diff -r 000000000000 -r 8466d47a6819 emailservices/emailserver/cmailhandlerplugin/src/emailsoundstates.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emailservices/emailserver/cmailhandlerplugin/src/emailsoundstates.cpp Thu Dec 17 08:39:21 2009 +0200 @@ -0,0 +1,714 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Class to handle email sound playing. +* +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "emailtrace.h" +#include "memailsoundstatecontext.h" +#include "emailsoundstates.h" +#include "fsnotificationhandlertimer.h" +#include "cmailhandlerpluginpanic.h" + +// Local constants +static const TInt KToneMinVolume = 0; +static const TInt KToneMaxVolume = 10; +static const TInt KDelayTimerInterval = 60000000; // 60s + +// --------------------------------------------------------------------------- +// Initializes the state machine by setting initial state and creating +// failure state that can be entered at any time in error cases. +// --------------------------------------------------------------------------- +// +void CEmailSoundState::InitializeL( MEmailSoundStateContext* aContext ) + { + FUNC_LOG + TAny* tls = Dll::Tls(); + if ( !tls ) + { + // prepare failed state so its always available + CEmailSoundState* failedState = new ( ELeave ) CEmailSoundFailed( *aContext ); + Dll::SetTls( failedState ); + // now enter to initial state, use failed state for obtaining context + CEmailInitilisingTone::EnterL( failedState ); + } + } + +// --------------------------------------------------------------------------- +// Exits the state machine and frees memory allocated for states +// --------------------------------------------------------------------------- +// +void CEmailSoundState::Uninitialize( CEmailSoundState* aCurrentState ) + { + FUNC_LOG + + if ( aCurrentState ) + { + // Exit must be called before deleting failedState because it may + // also be current state. + aCurrentState->Exit(); + } + + TAny* tls = Dll::Tls(); + if ( tls ) + { + CEmailSoundState* failedState = + reinterpret_cast( tls ); + delete failedState; + Dll::SetTls( NULL ); + } + } + +// --------------------------------------------------------------------------- +// No-op in base class, also enough for some derived classes. +// --------------------------------------------------------------------------- +// +void CEmailSoundState::ProfileChanged() + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// Tone initialization failure always leads to failed state. +// --------------------------------------------------------------------------- +// +void CEmailSoundState::AudioInitFailed() + { + FUNC_LOG + // enter to failed state. + StateTransition( EFailed ); + } + +// --------------------------------------------------------------------------- +// Derived classes implement +// --------------------------------------------------------------------------- +// +void CEmailSoundState::AudioInitCompleted() + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// Derived classes implement +// --------------------------------------------------------------------------- +// +void CEmailSoundState::AudioPlayCompleted() + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// Handled in CEmailReadyToPlay state, in most other states ignored. +// --------------------------------------------------------------------------- +// +void CEmailSoundState::PlayTone() + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// Applicable only in playing state +// --------------------------------------------------------------------------- +// +void CEmailSoundState::StopTone() + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// Tries to create audio player or activas failed state if error occurs +// --------------------------------------------------------------------------- +// +TBool CEmailSoundState::TryStartToneInitialization() + { + FUNC_LOG + TRAPD( err, iContext.RecreateAudioPlayerL() ); + if ( err ) + { + StateTransition( EFailed ); + } + return ( err == KErrNone ); + } + +// --------------------------------------------------------------------------- +// Stores as current state in owner of the state machine. +// --------------------------------------------------------------------------- +// +void CEmailSoundState::BaseEnter() + { + FUNC_LOG + iContext.SetState( this ); + } + +// --------------------------------------------------------------------------- +// State transition to requested state or failed state if attempt doesn't +// succeed. +// --------------------------------------------------------------------------- +// +void CEmailSoundState::StateTransition( const TSoundState aState ) + { + FUNC_LOG + TRAPD( err, + { + switch ( aState ) + { + case EInit: + CEmailInitilisingTone::EnterL( this ); + break; + case EReady: + CEmailReadyToPlay::EnterL( this ); + break; + case EPlaying: + CEmailPlayingTone::EnterL( this ); + break; + case EPendingPlay: + CEmailPendingPlay::EnterL( this ); + break; + case EPendingInit: + CEmailPendingInit::EnterL( this ); + break; + case EDelay: + CEmailTimerDelay::EnterL( this ); + break; + case EFailed: + default: + // to failed state + /* CodeScanner warning ignored because CS does not regognize + * TRAP being used */ + User::Leave( KErrArgument ); // codescanner::leave + break; + } + } ); + if ( err != KErrNone ) + { + CEmailSoundFailed::Enter( this ); + } + // exit old state + Exit(); + } + +// --------------------------------------------------------------------------- +// For most states destructor call is fine. +// See also CEmailSoundFailed::Exit() +// --------------------------------------------------------------------------- +// +void CEmailSoundState::Exit() + { + FUNC_LOG + delete this; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +MEmailSoundStateContext& CEmailSoundState::Context() const + { + FUNC_LOG + return iContext; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +CEmailSoundState::~CEmailSoundState() + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// c++ constructor +// --------------------------------------------------------------------------- +// +CEmailSoundState::CEmailSoundState( + MEmailSoundStateContext& aContext ) : + iContext( aContext ) + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// c++ constructor +// --------------------------------------------------------------------------- +// +CEmailInitilisingTone::CEmailInitilisingTone( + MEmailSoundStateContext& aContext ) : + CEmailSoundState( aContext ) + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// Need to cancel and restart tone initialization +// --------------------------------------------------------------------------- +// +void CEmailInitilisingTone::ProfileChanged() + { + FUNC_LOG + TryStartToneInitialization(); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CEmailInitilisingTone::AudioInitCompleted() + { + FUNC_LOG + StateTransition( EReady ); + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CEmailInitilisingTone::PlayTone() + { + FUNC_LOG + // not ready yet, postpone playing + StateTransition( EPendingPlay ); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CEmailInitilisingTone::DoEnterL() + { + FUNC_LOG + iContext.RecreateAudioPlayerL(); + CEmailSoundState::BaseEnter(); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CEmailInitilisingTone::EnterL( CEmailSoundState* aPreviousState ) + { + FUNC_LOG + CEmailInitilisingTone* state = new ( ELeave ) + CEmailInitilisingTone( aPreviousState->Context() ); + CleanupStack::PushL( state ); + state->DoEnterL(); + CleanupStack::Pop(); + } + +// --------------------------------------------------------------------------- +// c++ constructor +// --------------------------------------------------------------------------- +// +CEmailReadyToPlay::CEmailReadyToPlay( MEmailSoundStateContext& aContext ) + : CEmailSoundState( aContext ) + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// New profile may have different tone, initialize it. +// --------------------------------------------------------------------------- +// +void CEmailReadyToPlay::ProfileChanged() + { + FUNC_LOG + StateTransition( EInit ); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CEmailReadyToPlay::PlayTone() + { + FUNC_LOG + StateTransition( EPlaying ); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void CEmailReadyToPlay::DoEnterL() + { + FUNC_LOG + CEmailSoundState::BaseEnter(); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void CEmailReadyToPlay::EnterL( + CEmailSoundState* aPreviousState ) + { + FUNC_LOG + CEmailReadyToPlay* state = new ( ELeave ) CEmailReadyToPlay( + aPreviousState->Context() ); + CleanupStack::PushL( state ); + state->DoEnterL(); + CleanupStack::Pop(); + } + +// --------------------------------------------------------------------------- +// c++ constructor +// --------------------------------------------------------------------------- +// +CEmailSoundFailed::CEmailSoundFailed( MEmailSoundStateContext& aContext ) + : CEmailSoundState( aContext ) + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// Something has gone wrong earlier, now try recovery (re-init). +// --------------------------------------------------------------------------- +// +void CEmailSoundFailed::ProfileChanged() + { + FUNC_LOG + // try re-initialization + StateTransition( EInit ); + } + +// --------------------------------------------------------------------------- +// Something has gone wrong earlier, now try recovery (re-init + play ). +// --------------------------------------------------------------------------- +// +void CEmailSoundFailed::PlayTone() + { + FUNC_LOG + // kick off tone re-creation again + if ( TryStartToneInitialization() ) + { + StateTransition( EPendingPlay ); + } + } + +// --------------------------------------------------------------------------- +// Set failed state as current state. +// --------------------------------------------------------------------------- +// +void CEmailSoundFailed::DoEnter() + { + FUNC_LOG + CEmailSoundState::BaseEnter(); + } + +// --------------------------------------------------------------------------- +// Failed state is preserved until plugin shutdown, therefore base class Exit() +// is overridden and explicit destruction for this class is done in +// CEmailSoundState::Uninitialize. +// --------------------------------------------------------------------------- +// +void CEmailSoundFailed::Exit() + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// Obtain failed state from TLS and set it as current state. +// --------------------------------------------------------------------------- +// +void CEmailSoundFailed::Enter( CEmailSoundState* /*aPreviousState*/ ) + { + FUNC_LOG + TAny* tls = Dll::Tls(); + __ASSERT_ALWAYS( tls, Panic( ECmailHandlerPluginPanicNoFailedState ) ); + CEmailSoundFailed* failedState = reinterpret_cast( tls ); + failedState->DoEnter(); + } + +// --------------------------------------------------------------------------- +// c++ constructor +// --------------------------------------------------------------------------- +// +CEmailPlayingTone::CEmailPlayingTone( MEmailSoundStateContext& aContext ) + : CEmailSoundState( aContext ) + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// When playing completes, recreate tone because new profile may have +// different one. +// --------------------------------------------------------------------------- +// +void CEmailPlayingTone::ProfileChanged() + { + FUNC_LOG + StateTransition( EPendingInit ); + } + +// --------------------------------------------------------------------------- +// Proceed to delay state. +// Existing player instance owned by context is preserved. +// --------------------------------------------------------------------------- +// +void CEmailPlayingTone::AudioPlayCompleted() + { + FUNC_LOG + + // Tell sysap that tone playing has stopped + RProperty::Set( KPSUidCoreApplicationUIs, KCoreAppUIsMessageToneQuit, ECoreAppUIsStopTonePlaying ); + + StateTransition( EDelay ); + } + +// --------------------------------------------------------------------------- +// Stop tone and proceed to delay state. +// --------------------------------------------------------------------------- +// +void CEmailPlayingTone::StopTone() + { + FUNC_LOG + CMdaAudioPlayerUtility* player = iContext.AudioPlayer(); + // should never be null in this state + __ASSERT_ALWAYS( player, Panic( ECmailHandlerPluginPanicNullAudioPlayer ) ); + player->Stop(); + + // Tell sysap that tone playing has stopped + RProperty::Set( KPSUidCoreApplicationUIs, KCoreAppUIsMessageToneQuit, ECoreAppUIsStopTonePlaying ); + + StateTransition( EDelay ); + } + +// --------------------------------------------------------------------------- +// Starts playing of already initialized tone. +// --------------------------------------------------------------------------- +// +void CEmailPlayingTone::EnterL( CEmailSoundState* aPreviousState ) + { + FUNC_LOG + CEmailPlayingTone* state = new ( ELeave ) CEmailPlayingTone( + aPreviousState->Context() ); + CleanupStack::PushL( state ); + state->DoEnterL(); + CleanupStack::Pop(); + } + +// --------------------------------------------------------------------------- +// Playes 'new email' tone. +// --------------------------------------------------------------------------- +// +void CEmailPlayingTone::DoEnterL() + { + FUNC_LOG + CMdaAudioPlayerUtility* player = iContext.AudioPlayer(); + // should never be null in this state + __ASSERT_ALWAYS( player, Panic( ECmailHandlerPluginPanicNullAudioPlayer ) ); + + MProfile* profile = iContext.ProfileEngine().ActiveProfileL(); // owned + + const TInt profileVolume = + profile->ProfileTones().ToneSettings().iRingingVolume; + TInt volume = Max( KToneMinVolume, Min( profileVolume, KToneMaxVolume ) ); + profile->Release(); + profile = NULL; + + // scale with player but only if volume is greater than zero + if ( volume > 0 ) + { + volume = volume * player->MaxVolume() / KToneMaxVolume ; + } + INFO_1( "email tone volume", volume ) + player->SetVolume( volume ); + + // Set time + TTimeIntervalMicroSeconds time = TTimeIntervalMicroSeconds( 0 ); + + // Tell sysap that there's a tone playing at the moment + RProperty::Set( KPSUidCoreApplicationUIs, KCoreAppUIsMessageToneQuit, ECoreAppUIsTonePlaying ); + + // Set repeats and start playing + player->SetRepeats( 0, time ); + player->Play(); + CEmailSoundState::BaseEnter(); + }; + +// --------------------------------------------------------------------------- +// c++ constructor +// --------------------------------------------------------------------------- +// +CEmailPendingPlay::CEmailPendingPlay( MEmailSoundStateContext& aContext ) + : CEmailSoundState( aContext ) + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// Currently initializing tone is outdated, need to re-init and play +// immediately. +// --------------------------------------------------------------------------- +// +void CEmailPendingPlay::ProfileChanged() + { + FUNC_LOG + TryStartToneInitialization(); + } + +// --------------------------------------------------------------------------- +// Play was requested while tone initialization was ongoing, no its ready +// and tone can be played. +// --------------------------------------------------------------------------- +// +void CEmailPendingPlay::AudioInitCompleted() + { + FUNC_LOG + StateTransition( EPlaying ); + } + +// --------------------------------------------------------------------------- +// Activates this state. +// --------------------------------------------------------------------------- +// +void CEmailPendingPlay::DoEnterL() + { + FUNC_LOG + CEmailSoundState::BaseEnter(); + } + +// --------------------------------------------------------------------------- +// Playing tone was requested during initialization. +// --------------------------------------------------------------------------- +// +void CEmailPendingPlay::EnterL( CEmailSoundState* aPreviousState ) + { + FUNC_LOG + CEmailPendingPlay* state = new ( ELeave ) CEmailPendingPlay( + aPreviousState->Context() ); + CleanupStack::PushL( state ); + state->DoEnterL(); + CleanupStack::Pop(); + } + +// --------------------------------------------------------------------------- +// c++ constructor +// --------------------------------------------------------------------------- +// +CEmailPendingInit::CEmailPendingInit( MEmailSoundStateContext& aContext ) + : CEmailSoundState( aContext ) + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// Playback finished and tone can be initialized. +// --------------------------------------------------------------------------- +// +void CEmailPendingInit::AudioPlayCompleted() + { + FUNC_LOG + // now we can re-init new tone + StateTransition( EInit ); + } + +// --------------------------------------------------------------------------- +// Activates this state. +// --------------------------------------------------------------------------- +// +void CEmailPendingInit::DoEnterL() + { + FUNC_LOG + CEmailSoundState::BaseEnter(); + } + +// --------------------------------------------------------------------------- +// Tone initialization was requested during playback. +// --------------------------------------------------------------------------- +// +void CEmailPendingInit::EnterL( CEmailSoundState* aPreviousState ) + { + FUNC_LOG + CEmailPendingInit* state = new ( ELeave ) CEmailPendingInit( + aPreviousState->Context() ); + CleanupStack::PushL( state ); + state->DoEnterL(); + CleanupStack::Pop(); + } + +// --------------------------------------------------------------------------- +// c++ constructor +// --------------------------------------------------------------------------- +// +CEmailTimerDelay::CEmailTimerDelay( MEmailSoundStateContext& aContext ) + : CEmailSoundState( aContext ) + { + FUNC_LOG + } + +// --------------------------------------------------------------------------- +// New profile may have different tone, try initialize it. +// --------------------------------------------------------------------------- +// +void CEmailTimerDelay::ProfileChanged() + { + FUNC_LOG + TryStartToneInitialization(); + } + +// --------------------------------------------------------------------------- +// Timer expired. Ready to play again. +// --------------------------------------------------------------------------- +// +void CEmailTimerDelay::TimerCallBackL( TInt /*aError*/ ) + { + FUNC_LOG + StateTransition( EReady ); + } + +// --------------------------------------------------------------------------- +// Destructor +// --------------------------------------------------------------------------- +// +CEmailTimerDelay::~CEmailTimerDelay() + { + FUNC_LOG + delete iTimer; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CEmailTimerDelay::DoEnterL() + { + FUNC_LOG + iTimer = CFSNotificationHandlerTimer::NewL( *this ); + iTimer->After( KDelayTimerInterval ); + CEmailSoundState::BaseEnter(); + } +// --------------------------------------------------------------------------- +// Starts delay timer +// --------------------------------------------------------------------------- +// +void CEmailTimerDelay::EnterL( CEmailSoundState* aPreviousState ) + { + FUNC_LOG + CEmailTimerDelay* state = new ( ELeave ) CEmailTimerDelay( + aPreviousState->Context() ); + CleanupStack::PushL( state ); + state->DoEnterL(); + CleanupStack::Pop( state ); + } + +// End of file