diff -r cad71a31b7fc -r e36f3802f733 srsf/speechsynthesis/server/src/speechsynthesissession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/srsf/speechsynthesis/server/src/speechsynthesissession.cpp Wed Sep 01 12:29:17 2010 +0100 @@ -0,0 +1,859 @@ +/* +* Copyright (c) 2006-2007 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: Speech synthesis session +* +*/ + + +// INCLUDES + +#include "speechsynthesissession.h" +#include "speechsynthesisserver.h" +#include "speechsynthesisclientserver.h" +#include "rubydebug.h" + + +// CONSTANTS + +const TInt KMinVolume = 0; +const TInt KMinSpeakingRate = 1; + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::CSpeechSynthesisSession +// Constructor +// ---------------------------------------------------------------------------- +// +CSpeechSynthesisSession::CSpeechSynthesisSession(): + iSessionState( ESessionIdle ) + { + RUBY_DEBUG0( "CSpeechSynthesisSession::CSpeechSynthesisSession" ); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::CreateL +// 2nd phase construct for sessions - called by the CServer framework +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::CreateL() + { + RUBY_DEBUG_BLOCK( "CSpeechSynthesisSession::CreateL" ); + + Server().GetDefaultSettingsL( iCurrentVoice, + iSpeakingRate, iMaxSpeakingRate, + iVolume, iMaxVolume, + iAudioPriority, iAudioPreference, + iAudioOutput ); + + iTmpAudioOutput = iAudioOutput; + iTmpVolume = iVolume; + + Server().AddSession(); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::~CSpeechSynthesisSession +// Destructor +// ---------------------------------------------------------------------------- +// +CSpeechSynthesisSession::~CSpeechSynthesisSession() + { + RUBY_DEBUG0( "CSpeechSynthesisSession::~CSpeechSynthesisSession" ); + + iLanguages.Close(); + iVoices.Close(); + iCustomCommands.Close(); + + Server().Release( this ); + Server().DropSession(); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::MsssInitComplete +// Callback from server +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::MsssInitComplete( TInt aError, + const TTimeIntervalMicroSeconds& aDuration ) + { + RUBY_DEBUG1( "CSpeechSynthesisSession::MsssInitComplete [%d]", aError ); + + if ( aError ) + { + iSessionState = ESessionIdle; + iFileOutputActivated = EFalse; + + iDuration = 0; + iFile.Close(); + + Server().Release( this ); + } + else + { + iSessionState = ESessionPrimed; + + iDuration = aDuration; + } + + if ( iStoredMessage.IsNull() ) + { + RUBY_ERROR0( "iStoredMessage.IsNull() == ETrue" ); + } + else + { + iStoredMessage.Complete( aError ); + RUBY_DEBUG0( "Message completed" ); + } + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::MsssPlayComplete +// Callback from server +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::MsssPlayComplete( TInt aError ) + { + RUBY_DEBUG1( "CSpeechSynthesisSession::MsssPlayComplete [%d]", aError ); + + iSessionState = ESessionIdle; + iFileOutputActivated = EFalse; + + iDuration = 0; + iFile.Close(); + + Server().Release( this ); + + if ( iStoredMessage.IsNull() ) + { + RUBY_ERROR0( "iStoredMessage.IsNull() == ETrue" ); + } + else + { + iStoredMessage.Complete( aError ); + RUBY_DEBUG0( "Message completed" ); + } + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::MsssOperationAborted +// Callback from server +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::MsssOperationAborted() + { + RUBY_DEBUG0( "CSpeechSynthesisSession::MsssOperationAborted" ); + + iSessionState = ESessionIdle; + iFileOutputActivated = EFalse; + + iDuration = 0; + iFile.Close(); + + if ( !iStoredMessage.IsNull() ) + { + RUBY_DEBUG0( "Completing message with KErrDied" ); + iStoredMessage.Complete( KErrDied ); + } + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::Server +// +// ---------------------------------------------------------------------------- +// +inline CSpeechSynthesisServer& CSpeechSynthesisSession::Server() + { + return *static_cast( + const_cast( CSession2::Server() ) ); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::ServiceL +// Handle a client request. +// Leaving is handled by CSpeechSynthesisSession::ServiceError() which reports +// the error code to the client +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::ServiceL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "CSpeechSynthesisSession::ServiceL" ); + RUBY_DEBUG1( "aMessage.Function(): %d", aMessage.Function() ); + + TInt message( aMessage.Function() ); + + if ( message == EPrime || message == EPrimeFileOutput || + message == EPrimeStreamOutput || message == ESynthesise ) + { + Server().ReserveL( this, iAudioPriority ); + + TRAPD( error, DoAsyncServiceL( aMessage ) ); + if( error ) + { + Server().Release( this ); + User::Leave( error ); + } + } + else + { + DoSyncServiceL( aMessage ); + } + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoAsyncServiceL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoAsyncServiceL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "CSpeechSynthesisSession::DoAsyncServiceL" ); + + TInt function( aMessage.Function() ); + + if ( function == ESynthesise ) + { + if ( iSessionState == ESessionPrimed ) + { + if ( !iFileOutputActivated ) + { // Values may be changed when synthesis is paused. + if ( iTmpVolume != iVolume ) + { + Server().SetVolume( iVolume ); + iTmpVolume = iVolume; + } + + if ( iTmpAudioOutput != iAudioOutput ) + { + Server().SetAudioOutputL( iAudioOutput ); + iTmpAudioOutput = iAudioOutput; + } + } + + Server().Synthesize(); + } + else + { + User::Leave( KErrNotReady ); + } + } + else if ( function == EPrimeStreamOutput ) + { + User::Leave( KErrNotSupported ); + } + else // Prime or EPrimeFileOutput + { + iSessionState = ESessionIdle; + Server().Stop(); + + if ( iClosePlugin || Server().PreviousSession() != this ) + { + iClosePlugin = EFalse; + + Server().ClosePlugin(); + Server().SetVoiceL( iCurrentVoice, iSpeakingRate ); + + // Set custom commands, plugin ingnores commands if the state + // is incorrect for some command + for ( TInt i( 0 ); i < iCustomCommands.Count(); i++ ) + { + Server().CustomCommand( iCustomCommands[i].iCommand, iCustomCommands[i].iValue ); + } + } + else + { + Server().SetVoiceL( iCurrentVoice, iSpeakingRate ); + } + + // Fetch text to be synthesised + HBufC* text = HBufC::NewLC( aMessage.GetDesLengthL( 0 ) ); + TPtr ptr = text->Des(); + aMessage.ReadL( 0, ptr ); + + if ( function == EPrime ) + { + Server().SetAudioPriorityL( iAudioPriority, iAudioPreference ); + + Server().SetVolume( iVolume ); + iTmpVolume = iVolume; + + Server().SetAudioOutputL( iAudioOutput ); + iTmpAudioOutput = iAudioOutput; + + Server().PrimeL( ptr ); + + // Set custom commands, plugin ingnores commands if the state + // is incorrect for some command + for ( TInt i( 0 ); i < iCustomCommands.Count(); i++ ) + { + Server().CustomCommand( iCustomCommands[i].iCommand, iCustomCommands[i].iValue ); + } + + iFileOutputActivated = EFalse; + } + else + { + Server().PrimeL( ptr, iFile ); + + iFileOutputActivated = ETrue; + } + + CleanupStack::PopAndDestroy( text ); + } + + iStoredMessage = aMessage; + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoSyncServiceL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoSyncServiceL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "CSpeechSynthesisSession::DoSyncServiceL" ); + + switch ( aMessage.Function() ) + { + case ETransferFileHandle: + + User::LeaveIfError( iFile.AdoptFromClient( aMessage, + KFsHandleIndex, + KFileHandleIndex ) ); + + break; + + case EStopSynthesis: + + DoStopSynthesisL(); + + break; + + case EPauseSynthesis: + + DoPauseSynthesisL(); + + break; + + case EGetDuration: + + DoGetDurationL( aMessage ); + + break; + + case EGetLanguages: + + DoGetLanguagesL( aMessage ); + + break; + + case EGetLanguageCount: + + DoGetLanguageCountL( aMessage ); + + break; + + case EGetVoices: + + DoGetVoicesL( aMessage ); + + break; + + case EGetVoiceCount: + + DoGetVoiceCountL( aMessage ); + + break; + + case EVoice: + + DoVoiceL( aMessage ); + + break; + + case ESetVoice: + + DoSetVoiceL( aMessage ); + + break; + + case EMaxSpeakingRate: + + DoMaxSpeakingRateL( aMessage ); + + break; + + case ESpeakingRate: + + DoSpeakingRateL( aMessage ); + + break; + + case ESetSpeakingRate: + + DoSetSpeakingRateL( aMessage ); + + break; + + case EMaxVolume: + + DoMaxVolumeL( aMessage ); + + break; + + case EVolume: + + DoVolumeL( aMessage ); + + break; + + case ESetVolume: + + DoSetVolumeL( aMessage ); + + break; + + case ESetAudioPriority: + + DoSetAudioPriority( aMessage ); + + break; + + case ESetAudioOutput: + + DoSetAudioOutputL( aMessage ); + + break; + + case ECustomCommand: + + DoCustomCommandL( aMessage ); + + break; + + default: + + RUBY_ERROR1( "CSpeechSynthesisSession::ServiceL - %d", + aMessage.Function() ); + + PanicClient( aMessage, EPanicIllegalFunction ); + + break; + } + + aMessage.Complete( KErrNone ); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoStopSynthesisL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoStopSynthesisL() + { + RUBY_DEBUG_BLOCK( "" ); + + // Check we have permission to use server. + Server().ReserveL( this ); + + // Synthesis is ongoing + Server().Stop(); + + iSessionState = ESessionIdle; + + iDuration = 0; + iFile.Close(); + + // Release server and complete the previous message + Server().Release( this ); + + if ( !iStoredMessage.IsNull() ) + { + iStoredMessage.Complete( KErrAbort ); + } + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoPauseSynthesisL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoPauseSynthesisL() + { + RUBY_DEBUG_BLOCK( "" ); + + if ( iSessionState == ESessionPrimed && !iStoredMessage.IsNull() ) + { + if ( iFileOutputActivated ) + { + User::Leave( KErrNotSupported ); + } + + // Check we have permission to use server. + Server().ReserveL( this ); + + // Synthesis is ongoing + Server().Pause(); + + iStoredMessage.Complete( KErrCancel ); + } + else + { + User::Leave( KErrNotReady ); + } + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoGetDurationL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoGetDurationL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + if ( iSessionState != ESessionPrimed ) + { + User::Leave( KErrNotReady ); + } + else if ( iDuration.Int64() == 0 ) + { + User::Leave( KErrNotSupported ); + } + + TPckgBuf pkg( iDuration ); + aMessage.WriteL( 0, pkg ); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoGetLanguagesL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoGetLanguagesL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + // DoGetLanguagesL is called immediately after EGetLanguageCount + if ( iLanguages.Count() > 0 ) + { + const TInt dataSize( iLanguages.Count() * sizeof(TLanguage) ); + + HBufC8* tmp = HBufC8::NewLC( dataSize ); + TPtr8 tmp_ptr( tmp->Des() ); + + tmp_ptr.Append( (TUint8*)&iLanguages[0], dataSize ); + + aMessage.WriteL( 0, tmp_ptr ); + + CleanupStack::PopAndDestroy( tmp ); + } + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoGetLanguageCountL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoGetLanguageCountL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + iLanguages.Reset(); + + Server().GetSupportedLanguagesL( iLanguages ); + + TPckgBuf pkg_int( iLanguages.Count() ); + aMessage.WriteL( 0, pkg_int ); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoGetVoicesL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoGetVoicesL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + // DoGetVoicesL is called immediately after EGetVoiceCount + if ( iVoices.Count() > 0 ) + { + TInt dataSize( iVoices.Count() * sizeof(TVoice) ); + + HBufC8* tmp = HBufC8::NewLC( dataSize ); + TPtr8 tmp_ptr( tmp->Des() ); + + tmp_ptr.Append( (TUint8*)&iVoices[0], dataSize ); + + aMessage.WriteL( 0, tmp_ptr ); + + CleanupStack::PopAndDestroy( tmp ); + } + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoGetVoiceCountL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoGetVoiceCountL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + iVoices.Reset(); + TLanguage language( static_cast ( aMessage.Int1() ) ); + + Server().GetSupportedVoicesL( language, iVoices ); + + TPckgBuf pkg_int( iVoices.Count() ); + aMessage.WriteL( 0, pkg_int ); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoVoiceL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoVoiceL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + if ( !Server().IsVoiceValidL( iCurrentVoice ) ) + { + Server().GetDefaultVoiceL( iCurrentVoice ); + } + + TPckgBuf pkg_voice( iCurrentVoice ); + aMessage.WriteL( 0, pkg_voice ); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoSetVoiceL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoSetVoiceL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + TPckgBuf pkg_voice; + aMessage.ReadL( 0, pkg_voice ); + + TVoice voice( pkg_voice() ); + + if ( Server().IsVoiceValidL( voice ) ) + { + iCurrentVoice = voice; + + // Custom commands are valid until new voice is set + iCustomCommands.Close(); + } + else + { + User::Leave( KErrArgument ); + } + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoMaxSpeakingRateL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoMaxSpeakingRateL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + TPckgBuf pkg_int( iMaxSpeakingRate ); + aMessage.WriteL( 0, pkg_int ); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoSpeakingRateL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoSpeakingRateL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + TPckgBuf pkg_int( iSpeakingRate ); + aMessage.WriteL( 0, pkg_int ); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoSetSpeakingRateL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoSetSpeakingRateL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + TInt newValue( aMessage.Int0() ); + + if ( newValue < KMinSpeakingRate || newValue > iMaxSpeakingRate ) + { + User::Leave( KErrArgument ); + } + else + { + iSpeakingRate = newValue; + } + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoMaxVolumeL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoMaxVolumeL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + TPckgBuf pkg_int( iMaxVolume ); + aMessage.WriteL( 0, pkg_int ); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoVolumeL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoVolumeL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + TPckgBuf pkg_int( iVolume ); + aMessage.WriteL( 0, pkg_int ); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoSetVolumeL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoSetVolumeL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + TInt newValue( aMessage.Int0() ); + + if ( newValue < KMinVolume || newValue > iMaxVolume ) + { + User::Leave( KErrArgument ); + } + else + { + iVolume = newValue; + + if ( !iStoredMessage.IsNull() ) + { + // Check first we have permission to use server. + TRAP_IGNORE( + Server().ReserveL( this ); + Server().SetVolume( iVolume ); + iTmpVolume = iVolume; + ); + } + } + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoSetAudioPriority +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoSetAudioPriority( const RMessage2& aMessage ) + { + RUBY_DEBUG0( "" ); + + iAudioPriority = aMessage.Int0(); + iAudioPreference = aMessage.Int1(); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoSetAudioOutputL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoSetAudioOutputL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + iAudioOutput = aMessage.Int0(); + + if ( !iStoredMessage.IsNull() ) + { + // Check first we have permission to use server. + TRAPD( error, Server().ReserveL( this ) ); + if ( error == KErrNone ) + { + Server().SetAudioOutputL( iAudioOutput ); + iTmpAudioOutput = iAudioOutput; + } + } + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::DoCustomCommandL +// +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::DoCustomCommandL( const RMessage2& aMessage ) + { + RUBY_DEBUG_BLOCK( "" ); + + iClosePlugin = ETrue; + + TInt command( aMessage.Int0() ); + TInt value( aMessage.Int1() ); + + TBool found( EFalse ); + TInt count( iCustomCommands.Count() ); + + for ( TInt i( 0 ); i < count; i++ ) + { + if ( iCustomCommands[i].iCommand == command ) + { + iCustomCommands[i].iValue = value; + found = ETrue; + break; + } + } + + if ( !found ) + { + TCustomCommand newItem; + newItem.iCommand = command; + newItem.iValue = value; + + iCustomCommands.AppendL( newItem ); + } + + Server().CustomCommand( command, value ); + } + +// ---------------------------------------------------------------------------- +// CSpeechSynthesisSession::ServiceError +// Handle an error from CSpeechSynthesisSession::ServiceL() +// ---------------------------------------------------------------------------- +// +void CSpeechSynthesisSession::ServiceError( const RMessage2& aMessage, + TInt aError ) + { + RUBY_DEBUG1( "CSpeechSynthesisSession::ServiceError %d", aError ); + + CSession2::ServiceError( aMessage, aError ); + } + +// End of file