--- /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 <AudioPreference.h>
+#include <MProfileEngine.h>
+#include <MProfile.h>
+#include <MProfileTones.h>
+#include <MProfileExtraTones.h>
+#include <TProfileToneSettings.h>
+#include <CProfileChangeNotifyHandler.h>
+#include <coreapplicationuisdomainpskeys.h>
+
+#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<CEmailSoundState*>( 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<CEmailSoundFailed*>( 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