srsf/ttsutility/src/ttsutilitybody.cpp
branchRCL_3
changeset 19 e36f3802f733
parent 0 bf1d17376201
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/srsf/ttsutility/src/ttsutilitybody.cpp	Wed Sep 01 12:29:17 2010 +0100
@@ -0,0 +1,1181 @@
+/*
+* Copyright (c) 2004-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:  Implementations for methods in CTtsUtilityBody
+*
+*/
+
+
+// INCLUDE FILES
+#include "ttsutilitybody.h"
+#include <mmf/server/mmffile.h>
+#include <mmf/server/mmfdes.h>
+#include <mmf/common/mmfcontrollerpluginresolver.h>
+#include <ecom/ecom.h>
+#include <AudioPreference.h>
+#include <utf.h>
+#include "rubydebug.h"
+
+// CONSTANTS
+
+// TTS media type equals to audio media type
+const TUid KUidMediaTypeTTS = { 0x101F5D07 };
+
+// Implementation UID of Tts Plugin
+const TUid KUidTtsPlugin = { 0x101FF934 };
+
+// Implementation UID of HQ-TTS Plugin
+const TUid KUidHqTtsPlugin = { 0x10201AF5 };
+
+// Header for TTS input
+_LIT8( KTtsDataHeader, "(tts)" );
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::CTtsUtilityBody
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CTtsUtilityBody::CTtsUtilityBody( MTtsClientUtilityObserver& aObserver ) : 
+                                  iAudioPlayDeviceCommands( iController ),
+                                  iAudioPlayControllerCommands( iController ),
+                                  iTtsCustomCommands( iController ),
+                                  iObserver( aObserver ),
+                                  iTime( 0 ),
+                                  iCurrentStyleID( 0 ),
+                                  iTrailingSilence( 0 ),
+                                  iOpenPlugin( KNullUid ),
+                                  iUidOfDataSink( KUidMmfAudioOutput )
+    {
+    // Nothing
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::ConstructL()
+    {
+    // Dummy priority settings
+    iPrioritySettings.iPriority = 0;
+    iPrioritySettings.iPref = ( TMdaPriorityPreference ) 0;
+    iPrioritySettings.iState = EMMFStateIdle; // idle
+    
+    // List plugins to make sure that at least one is found
+    RArray<TUid> temp;
+    ListPluginsL( temp );
+    temp.Close();
+
+    // Default audio priority
+    StorePriority( KAudioPriorityVoiceDial, 
+                   static_cast<TMdaPriorityPreference>( KAudioPrefVocosPlayback ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CTtsUtilityBody* CTtsUtilityBody::NewL( MTtsClientUtilityObserver& aObserver )
+    {
+    CTtsUtilityBody* self = new( ELeave ) CTtsUtilityBody( aObserver );
+    
+    CleanupStack::PushL( self );
+
+    self->ConstructL();
+    CleanupStack::Pop();
+    
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::~CTtsUtilityBody
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+CTtsUtilityBody::~CTtsUtilityBody()
+    {
+    // Cancel any pending requests
+    if ( iControllerEventMonitor != NULL )
+        {
+        iControllerEventMonitor->Cancel();
+        }
+
+    delete iControllerEventMonitor;
+    iController.Close();
+ 
+    iStyles.Close();
+    iInternalStyleIDs.Close();
+    iControllerStyleIDs.Close();
+    
+    delete iParsedText;
+    
+    REComSession::FinalClose();
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::HandleEvent
+// Handles events from plugin via MMF.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::HandleEvent( const TMMFEvent& aEvent )
+    {
+    TInt result = (TInt)aEvent.iErrorCode;
+
+#ifdef _DEBUG
+    TInt event = (TInt)aEvent.iEventType.iUid;
+    RUBY_DEBUG2( "CTtsUtilityBody::HandleEvent() - Event Type = %d, Event Result = %d", 
+                 event, result );
+#endif
+    
+    if ( aEvent.iEventType == KMMFEventCategoryPlaybackComplete )
+        {
+        if ( result == KErrNone )
+            {
+            iRepeats--;
+            
+            if ( iRepeats > 0 )
+                {
+                // @todo Not too good way to handle waiting, we're blocking
+                // the client thread here... Should be done in plugin side..
+                User::After( iTrailingSilence );
+                Play();
+                // Don't make the callback at this point
+                return;
+                }
+            }
+        else
+            {
+            iRepeats = 0;
+            }
+        
+        iUidOfDataSink = KUidMmfAudioOutput;
+
+        // Remove data sink - otherwise file handle stays open. 
+        // Return value ignored because there is nothing we can do. 
+        iController.RemoveDataSink( iSinkHandle );
+
+        iObserver.MapcPlayComplete( result );
+        
+        }
+    else if ( aEvent.iEventType == KMMFEventCategoryAudioLoadingComplete )
+        {
+        if ( result != KErrNone )
+            {
+            iUidOfDataSink = KUidMmfAudioOutput; 
+            iController.RemoveDataSink( iSinkHandle );
+            }
+            
+        iTime = Duration();
+        iObserver.MapcInitComplete( result, iTime );
+        if ( iPlayImmediately )
+            {
+            iPlayImmediately = EFalse;
+            if ( result == KErrNone )
+                {
+                Play();
+                }
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::AddStyleL
+// Adds style to collection, calls TTS custom commands.
+// -----------------------------------------------------------------------------
+//
+TTtsStyleID CTtsUtilityBody::AddStyleL( const TTtsStyle& aStyle )
+    {
+    TTtsStyleID controllerID( 0 );
+    
+    if ( IsPluginOpen() )
+        {
+        User::LeaveIfError( iTtsCustomCommands.AddStyle( aStyle, controllerID ) );
+        }
+
+    // Add style also to our own array
+    iStyles.Append( aStyle );
+    TTtsStyleID internalID( iCurrentStyleID ); 
+    iInternalStyleIDs.Append( internalID );
+
+    // This is zero if no open controller connection, will be updated later
+    iControllerStyleIDs.Append( controllerID ); 
+    iCurrentStyleID++;
+
+    return internalID;
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::DeleteStyle
+// Deletes style from collection, calls TTS custom commands.
+// -----------------------------------------------------------------------------
+//
+TInt CTtsUtilityBody::DeleteStyle( TTtsStyleID aID )
+    {
+    TTtsStyleID controllerStyleId( 0 );
+
+    // Delete from local storage
+    for ( TInt i = 0; i < iInternalStyleIDs.Count(); i++ )
+        {
+        if ( iInternalStyleIDs[i] == aID )
+            {
+            iInternalStyleIDs.Remove( i );
+            iStyles.Remove( i );
+            // Take note of the controller side style id before removing it
+            controllerStyleId = iControllerStyleIDs[i];
+            iControllerStyleIDs.Remove( i );
+            break;
+            }
+        }
+
+    // Reset style id counter if no styles registered anymore
+    if ( iInternalStyleIDs.Count() == 0 )
+        {
+        iCurrentStyleID = 0;
+        }
+
+    if ( IsPluginOpen() )
+        {
+        // Delete style from controller plugin
+        TInt error = iTtsCustomCommands.DeleteStyle( controllerStyleId );
+        if ( error != KErrNone )
+            {
+            return error;
+            }
+        }
+
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::NumberOfStyles
+// Returns number of registered styles.
+// -----------------------------------------------------------------------------
+//
+TUint16 CTtsUtilityBody::NumberOfStyles()
+    {
+    return ( TUint16 ) iStyles.Count();
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::StyleL
+// Returns reference to registered style based on style ID.
+// -----------------------------------------------------------------------------
+//
+TTtsStyle& CTtsUtilityBody::StyleL( TTtsStyleID aStyleID )
+    {
+    TInt i( 0 );
+    TInt count( iInternalStyleIDs.Count() );
+    
+    while ( i < count && iInternalStyleIDs[i] != aStyleID )
+        {
+        i++;
+        }
+    
+    if ( i == count )
+        {
+        User::Leave( KErrNotFound );
+        }
+
+    return iStyles[i];
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::StyleL
+// Returns reference to registered style based on style index.
+// -----------------------------------------------------------------------------
+//
+TTtsStyle& CTtsUtilityBody::StyleL( TUint16 aIndex )
+    {
+    if ( aIndex >= iStyles.Count() )
+        {
+        User::Leave( KErrNotFound );
+        }
+
+    return iStyles[aIndex];
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::Play
+// Starts playback.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::Play()
+    {
+    iController.Play();
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::Stop
+// Stops playback.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::Stop()
+    {
+    iRepeats = 0;
+    iController.Stop();
+    iUidOfDataSink = KUidMmfAudioOutput;
+    iController.RemoveDataSink( iSinkHandle );
+    iPlayImmediately = EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::SetVolume
+// Sets playback volume.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::SetVolume( TInt aVolume )
+    {
+    iAudioPlayDeviceCommands.SetVolume( aVolume );
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::SetRepeats
+// Sets number of repeats.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::SetRepeats( TInt aRepeatNumberOfTimes, 
+                                  const TTimeIntervalMicroSeconds& aTrailingSilence )
+    {
+    iTrailingSilence = TTimeIntervalMicroSeconds32( I64LOW( aTrailingSilence.Int64() ) );
+    iRepeats = aRepeatNumberOfTimes;
+    }
+        
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::Duration
+// Returns duration of TTS 'clip'.
+// -----------------------------------------------------------------------------
+//
+const TTimeIntervalMicroSeconds& CTtsUtilityBody::Duration()
+    {
+    iDuration = 0; 
+    iController.GetDuration( iDuration ); // Ignoring return value 
+    
+    return iDuration; 
+    } 
+    
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::MaxVolume
+// Returns maximum volume.
+// -----------------------------------------------------------------------------
+//
+TInt CTtsUtilityBody::MaxVolume()
+    {
+    TInt volume = 0;
+    if ( iAudioPlayDeviceCommands.GetMaxVolume( volume ) != KErrNone )
+        {
+        return 0;
+        }
+    return volume;
+    } 
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::OpenAndPlayDesL
+// Opens descriptor source and plays it immediately.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::OpenAndPlayDesL( const TDesC8& aDescriptor )
+    {
+    iPlayImmediately = ETrue;
+    
+    TRAPD( error, OpenDesL( aDescriptor ) );
+    if ( error != KErrNone )
+        {
+        iPlayImmediately = EFalse;
+        User::Leave( error );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::OpenAndPlayFileL
+// Opens file source and plays it immediately.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::OpenAndPlayFileL( const TDesC& aFileName )
+    {
+    iPlayImmediately = ETrue;
+    
+    TRAPD( error, OpenFileL( aFileName ) );
+    if ( error != KErrNone )
+        {
+        iPlayImmediately = EFalse;
+        User::Leave( error );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::OpenAndPlayParsedTextL
+// Opens parsed text source and plays it immediately.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::OpenAndPlayParsedTextL( CTtsParsedText& aText )
+    {
+    iPlayImmediately = ETrue;
+    
+    TRAPD( error, OpenParsedTextL( aText ) );
+    if ( error != KErrNone )
+        {
+        iPlayImmediately = EFalse;
+        User::Leave( error );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::OpenDesL
+// Opens descriptor source 
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::OpenDesL( const TDesC8& aDescriptor )
+    {
+    if ( !iPluginOpenedExplicitly )
+        {
+        CheckAndLoadCorrectPluginL( iDefaultStyle.iQuality, 
+                                    iDefaultStyle.iLanguage, 
+                                    iDefaultStyle.iVoice );
+        }
+
+    // Add data descriptor source
+    TMMFDescriptorConfig sourceCfg;
+    sourceCfg().iDes = (TAny*)&aDescriptor;
+    sourceCfg().iDesThreadId = RThread().Id();
+    User::LeaveIfError( iController.AddDataSource( KUidMmfDescriptorSource, 
+                                                   sourceCfg, iSourceHandle ) );
+
+    // Add data sink to file or audio output
+    AddDataSinkL();
+
+    // Prime controller
+    User::LeaveIfError( iController.Prime() );
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::OpenFileL
+// Opens file source
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::OpenFileL( const TDesC& aFileName )
+    {
+    if ( !iPluginOpenedExplicitly )
+        {
+        CheckAndLoadCorrectPluginL( iDefaultStyle.iQuality, 
+                                    iDefaultStyle.iLanguage, 
+                                    iDefaultStyle.iVoice );
+        }
+
+    // Add data file source
+    TMMFFileConfig sourceCfg;
+    sourceCfg().iPath = aFileName;
+    User::LeaveIfError( iController.AddDataSource( KUidMmfFileSource, sourceCfg, 
+                                                   iSourceHandle ) );
+    // Add data sink to file or audio output
+    AddDataSinkL();
+        
+    // Prime controller
+    User::LeaveIfError( iController.Prime() );
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::OpenParsedTextL
+// Opens parsed text source with the help of TTS custom commands.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::OpenParsedTextL( CTtsParsedText& aText )
+    {
+    if ( !iPluginOpenedExplicitly )
+        {
+        if ( aText.NumberOfSegments() > 0 )
+            {
+            // Take the first segment
+            const TTtsSegment& segment = aText.SegmentL( 0 );
+        
+            TTtsStyleID styleID = segment.StyleID();
+        
+            // Style should have been registered already
+            TTtsStyle& style = StyleL( styleID );
+        
+            CheckAndLoadCorrectPluginL( style.iQuality, style.iLanguage, 
+                                        style.iVoice );
+            }
+         else
+            {
+            User::Leave( KErrArgument );
+            }
+        }
+
+    // Data source is now parsed text
+    CopyParsedTextL( aText );
+    User::LeaveIfError( iTtsCustomCommands.OpenParsedText( *iParsedText ) );
+
+    // Add data sink to file or audio output
+    AddDataSinkL();
+
+    User::LeaveIfError( iController.Prime() );
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::Pause
+// Pauses playback.
+// -----------------------------------------------------------------------------
+//
+TInt CTtsUtilityBody::Pause()
+    {
+    return iController.Pause();
+    }   
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::OpenPluginL
+// Opens connection to plugin
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::OpenPluginL( TUid aUid )
+    {
+    OpenControllerConnectionL( aUid );
+    
+    iPluginOpenedExplicitly = ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::ListPluginsL
+// Lists available plugins
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::ListPluginsL( RArray<TUid>& aUids )
+    {
+    // Empty the list
+    aUids.Reset();
+    
+    RMMFControllerImplInfoArray controllers;
+    CleanupResetAndDestroyPushL( controllers );
+    
+    CMMFControllerPluginSelectionParameters* selectionParams = CMMFControllerPluginSelectionParameters::NewLC();
+    
+    // Select the media IDs to allow
+    RArray<TUid> mediaIds;
+    CleanupClosePushL( mediaIds );
+    User::LeaveIfError( mediaIds.Append( KUidMediaTypeTTS ) );
+
+    selectionParams->SetMediaIdsL( mediaIds, CMMFPluginSelectionParameters::EAllowOnlySuppliedMediaIds );
+    CleanupStack::PopAndDestroy( &mediaIds );
+    
+    // Check also the allowed data headers
+    // Should be "(tts)"
+    CMMFFormatSelectionParameters* formatSelectParams = CMMFFormatSelectionParameters::NewLC();
+    formatSelectParams->SetMatchToHeaderDataL( KTtsDataHeader );
+    
+    selectionParams->SetRequiredPlayFormatSupportL( *formatSelectParams );
+    
+    CleanupStack::PopAndDestroy( formatSelectParams );
+    
+    // Do the list of implementation
+    selectionParams->ListImplementationsL( controllers );    
+    
+    // Make sure at least one controller has been found
+    if( controllers.Count() == 0 )
+        {
+        RUBY_DEBUG1( "No controllers found using media type %x", KUidMediaTypeTTS );
+        User::Leave( KErrNotFound );
+        }
+
+    for ( TInt c = 0; c < controllers.Count(); c++ )
+        {
+        RUBY_DEBUG1( "UID = %x", controllers[c]->Uid() );
+        aUids.Append( controllers[c]->Uid() );
+        }
+
+    CleanupStack::PopAndDestroy( selectionParams );
+    CleanupStack::PopAndDestroy( &controllers ); 
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::SetDefaultStyleL
+// Sets deafault style 
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::SetDefaultStyleL( const TTtsStyle& aStyle )
+    {
+    User::LeaveIfError( iTtsCustomCommands.SetDefaultStyle( aStyle ) );
+    iDefaultStyle = aStyle;
+    }
+        
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::DefaultStyleL
+// Returns default style
+// -----------------------------------------------------------------------------
+//
+TTtsStyle& CTtsUtilityBody::DefaultStyleL()
+    {   
+    User::LeaveIfError( iTtsCustomCommands.GetDefaultStyle( iDefaultStyle ) );
+    return iDefaultStyle;
+    }
+        
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::SetSpeakingRateL
+// Sets speaking rate
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::SetSpeakingRateL( TInt aRate )
+    {
+    User::LeaveIfError( iTtsCustomCommands.SetSpeakingRate( aRate ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::SpeakingRateL
+// Returns speaking rate
+// -----------------------------------------------------------------------------
+//
+TInt CTtsUtilityBody::SpeakingRateL()
+    {
+    TInt rate( KErrGeneral );
+    User::LeaveIfError( iTtsCustomCommands.GetSpeakingRate( rate ) );
+    return rate;
+    }
+    
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::GetSupportedLanguagesL
+// Returns list of supported languages
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::GetSupportedLanguagesL( RArray<TLanguage>& aLanguages )
+    {
+    User::LeaveIfError( iTtsCustomCommands.GetSupportedLanguages( aLanguages ) );
+    }
+        
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::GetSupportedVoicesL
+// Returns list of supported voices
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::GetSupportedVoicesL( TLanguage aLanguage, 
+                                           RArray<TTtsStyle>& aVoices )
+    {
+    User::LeaveIfError( iTtsCustomCommands.GetSupportedVoices( aLanguage, aVoices ) );
+    }
+    
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::OpenDesL
+// Opens unicode descriptor
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::OpenDesL( const TDesC& aDescriptor )
+    {
+    HBufC8* utf8string = ConvertToUtf8LC( aDescriptor );
+    OpenDesL( utf8string->Des() );
+    CleanupStack::PopAndDestroy( utf8string );
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::GetSupportedVoicesL
+// Opens and plays unicode descriptor
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::OpenAndPlayDesL( const TDesC& aDescriptor )
+    {
+    HBufC8* utf8string = ConvertToUtf8LC( aDescriptor );
+    OpenAndPlayDesL( utf8string->Des() );
+    CleanupStack::PopAndDestroy( utf8string );        
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::SetOutputFileL
+// Sets output to be written to the file handle 
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::SetOutputFileL( const RFile& aFile )
+    {
+    iUidOfDataSink = KUidMmfFileSink; 
+
+    // iFile has to contain valid file handle when data sink 
+    // is marked to be file sink. 
+    iFile = aFile; 
+    }
+    
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::Close
+// Closes current TTS synthesis source.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::Close()
+    {
+    iRepeats = 0;
+    if ( iControllerEventMonitor != NULL )
+        {
+        iControllerEventMonitor->Cancel();
+        }
+    delete iControllerEventMonitor;
+    iControllerEventMonitor = NULL;
+    iController.Close();
+    iPluginOpenedExplicitly = EFalse;
+    iOpenPlugin = KNullUid;
+    iUidOfDataSink = KUidMmfAudioOutput;
+    }        
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::GetPosition
+// Returns position of synthesis in microseconds.
+// -----------------------------------------------------------------------------
+//
+TInt CTtsUtilityBody::GetPosition( TTimeIntervalMicroSeconds& aPosition )
+    {
+    return iController.GetPosition( aPosition );
+    }
+       
+ 
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::GetPosition
+// Returns position of synthesis in words.
+// -----------------------------------------------------------------------------
+//
+TInt CTtsUtilityBody::GetPosition( TInt& aWordIndex )
+    {
+    return iTtsCustomCommands.GetPosition( aWordIndex );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::SetPosition
+// Sets synthesis position in microseconds.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::SetPosition( const TTimeIntervalMicroSeconds& aPosition )
+    {
+    iController.SetPosition( aPosition );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::SetPosition
+// Sets synthesis position in words.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::SetPosition( TInt aWordIndex )
+    {
+    iTtsCustomCommands.SetPosition( aWordIndex );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::SetPriority
+// Sets playback priority.
+// -----------------------------------------------------------------------------
+//
+TInt CTtsUtilityBody::SetPriority( TInt aPriority, TMdaPriorityPreference aPref )
+    {
+    StorePriority( aPriority, aPref );
+
+    if ( IsPluginOpen() )
+        {
+        return iController.SetPrioritySettings( iPrioritySettings );
+        }
+    else
+        {
+        return KErrNone;
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::GetVolume
+// Returns volume value.
+// -----------------------------------------------------------------------------
+//
+TInt CTtsUtilityBody::GetVolume( TInt& aVolume )
+    {
+    return iAudioPlayDeviceCommands.GetVolume( aVolume );
+    }
+        
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::SetBalance
+// Sets balance.
+// -----------------------------------------------------------------------------
+//
+TInt CTtsUtilityBody::SetBalance( TInt aBalance )
+    {
+    return iAudioPlayDeviceCommands.SetBalance( aBalance );
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::GetBalance
+// Returns current balance setting.
+// -----------------------------------------------------------------------------
+//
+TInt CTtsUtilityBody::GetBalance( TInt& aBalance )
+    {
+    return iAudioPlayDeviceCommands.GetBalance( aBalance );
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::CustomCommandSync
+// Sends synchronous custom command via MMF.
+// -----------------------------------------------------------------------------
+//
+TInt CTtsUtilityBody::CustomCommandSync( const TMMFMessageDestinationPckg& aDestination, 
+                                         TInt aFunction, 
+                                         const TDesC8& aDataTo1, 
+                                         const TDesC8& aDataTo2, 
+                                         TDes8& aDataFrom )
+    {
+    return iController.CustomCommandSync( aDestination, aFunction, aDataTo1, aDataTo2, aDataFrom );
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::CustomCommandSync
+// Sends synchronous custom command via MMF.
+// -----------------------------------------------------------------------------
+//
+TInt CTtsUtilityBody::CustomCommandSync( const TMMFMessageDestinationPckg& aDestination, 
+                                         TInt aFunction, 
+                                         const TDesC8& aDataTo1, 
+                                         const TDesC8& aDataTo2 )
+    {
+    return iController.CustomCommandSync( aDestination, aFunction, aDataTo1, aDataTo2 );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::CustomCommandAsync
+// Sends asynchronous custom command via MMF.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::CustomCommandAsync( const TMMFMessageDestinationPckg& aDestination,  
+                                          TInt aFunction, 
+                                          const TDesC8& aDataTo1, 
+                                          const TDesC8& aDataTo2, 
+                                          TDes8& aDataFrom,
+                                          TRequestStatus& aStatus )
+    {
+    iController.CustomCommandAsync( aDestination, aFunction, aDataTo1, aDataTo2, aDataFrom, aStatus );
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::CustomCommandAsync
+// Sends asynchronous custom command via MMF.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::CustomCommandAsync( const TMMFMessageDestinationPckg& aDestination, 
+                                          TInt aFunction, 
+                                          const TDesC8& aDataTo1, 
+                                          const TDesC8& aDataTo2, 
+                                          TRequestStatus& aStatus )
+    {
+    iController.CustomCommandAsync( aDestination, aFunction, aDataTo1, aDataTo2, aStatus );
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::IsPluginOpen
+// Returns ETrue if connection is established with controller plugin
+// -----------------------------------------------------------------------------
+//
+TBool CTtsUtilityBody::IsPluginOpen()
+    {
+    if ( iOpenPlugin == KNullUid )
+        {
+        return EFalse;
+        }
+    else
+        {
+        return ETrue;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::OpenControllerConnectionL
+// Opens controller connection if it has been closed
+// Changes plugin if the one requested is not loaded currently
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::OpenControllerConnectionL( TUid aPluginUid )
+    {
+    RUBY_DEBUG_BLOCK( "CTtsUtilityBody::OpenControllerConnectionL(aPluginUid)" );
+    
+    if ( iOpenPlugin != aPluginUid )
+        {
+        // Clear previously loaded plugin if needed
+        if ( IsPluginOpen() )
+            {
+            Close();
+            }
+
+        TInt error = iController.Open( aPluginUid, iPrioritySettings );
+        if ( error ) 
+            {
+            RUBY_DEBUG2( "Unable to load controller plugin, error = %d, UID = %x", 
+                         error, aPluginUid );            
+            User::Leave( error );
+            }
+        else
+            {
+            if ( iControllerEventMonitor == NULL )
+                {
+                // Start the event monitor
+                iControllerEventMonitor = CMMFControllerEventMonitor::NewL( *this, iController );
+                iControllerEventMonitor->Start();
+                }
+            }
+      
+        iOpenPlugin = aPluginUid;
+
+        // Add already registered styles to controller plugin too         
+        for ( TInt i( 0 ); i < iStyles.Count(); i++ )
+            {
+            TTtsStyleID controllerStyleId( 0 );
+            User::LeaveIfError( iTtsCustomCommands.AddStyle( iStyles[i], controllerStyleId ) );
+            iControllerStyleIDs[i] = controllerStyleId;
+            } 
+        
+        // Set priority settings
+        User::LeaveIfError( SetPriority( iPrioritySettings.iPriority, 
+                                         (TMdaPriorityPreference) iPrioritySettings.iPref ) );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::CopyParsedTextL
+// Copies parsed text structure and substitutes style ids to corresponding plugin
+// ids.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::CopyParsedTextL( CTtsParsedText& aText )
+    {
+    RUBY_DEBUG_BLOCK( "CTtsUtilityBody::CopyParsedTextL" );
+
+    // Delete previous object if exists
+    delete iParsedText;
+    iParsedText = NULL;
+
+    // New instance
+    iParsedText = CTtsParsedText::NewL( aText.Text(), aText.PhonemeSequence(),
+                                        aText.PhonemeNotation() );
+
+    // Segments
+
+    // Indexes for starting points for segment's text and phoneme part in
+    // CTtsParsedText object's text and phoneme sequence    
+    TInt textIndex( 0 );
+    TInt phonemeIndex( 0 );
+
+    for ( TInt i = 0; i < aText.NumberOfSegments(); i++ )
+        {
+        TTtsSegment segment = aText.SegmentL( i );
+        
+        TInt styleIndex = iInternalStyleIDs.Find( aText.SegmentL( i ).StyleID() );
+        User::LeaveIfError( styleIndex );
+        segment.SetStyleID( iControllerStyleIDs[styleIndex] );
+        
+        TInt segTextLength = aText.SegmentL( i ).TextPtr().Length();
+        TInt segPhonemeSeqLength = aText.SegmentL( i )
+                                      .PhonemeSequencePtr().Length();
+        
+        // Text
+        if ( textIndex + segTextLength
+             <= iParsedText->Text().Length() )
+            {
+            segment.SetTextPtr( iParsedText->Text()
+                                .Mid( textIndex, segTextLength ) );
+            
+            textIndex += segTextLength;
+            }
+        // Segments are somehow constructed illegally. Copy the whole text.
+        else
+            {
+            segment.SetTextPtr( iParsedText->Text() );
+            }
+        
+        // Phoneme sequence
+        if ( phonemeIndex + segPhonemeSeqLength
+             <= iParsedText->PhonemeSequence().Length() )
+            {
+            segment.SetPhonemeSequencePtr(
+                iParsedText->PhonemeSequence().Mid( phonemeIndex, segPhonemeSeqLength ) );
+            
+            phonemeIndex += segPhonemeSeqLength;
+            }
+        else
+            {
+            segment.SetPhonemeSequencePtr(
+                iParsedText->PhonemeSequence() );
+            }
+
+        // Add segment to the new instance of CTtsParsedText
+        iParsedText->AddSegmentL( segment );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::StorePriority
+// Stores priority values locally to be sent to the plugin when connection is
+// opened.
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::StorePriority( TInt aPriority, TMdaPriorityPreference aPref )
+    {
+    iPrioritySettings.iPriority = aPriority;
+    iPrioritySettings.iPref = aPref;
+    iPrioritySettings.iState = EMMFStateIdle;
+    }    
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::ConvertToUtf8LC
+// Converts unicode descriptor to utf-8
+// -----------------------------------------------------------------------------
+//
+HBufC8* CTtsUtilityBody::ConvertToUtf8LC( const TDesC& aDes )
+    {
+    HBufC8* utf8 = CnvUtfConverter::ConvertFromUnicodeToUtf8L( aDes );
+    CleanupStack::PushL( utf8 );
+    return utf8;
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::AddDataSinkL
+// Adds data sink (file and audio supported)
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::AddDataSinkL()
+    {
+    RUBY_DEBUG_BLOCKL( "CTtsUtilityBody::AddDataSinkL" );
+    
+    if ( iUidOfDataSink == KUidMmfAudioOutput )
+        {
+        User::LeaveIfError( iController.AddDataSink( KUidMmfAudioOutput, 
+                                                     KNullDesC8, iSinkHandle ) ); 
+        }
+    else if ( iUidOfDataSink == KUidMmfFileSink )
+        {
+        TMMFFileHandleConfig destCfg( &iFile );
+
+        TInt error = iController.AddDataSink( KUidMmfFileSink,destCfg, iSinkHandle ); 
+        if ( error )
+            {
+            iUidOfDataSink = KUidMmfAudioOutput; 
+            User::Leave( error ); 
+            }
+        }
+    else
+        {
+        User::Leave( KErrNotSupported );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::CheckAndLoadCorrectPluginL
+// 
+// -----------------------------------------------------------------------------
+//
+void CTtsUtilityBody::CheckAndLoadCorrectPluginL( TTtsQuality aQuality, 
+                                                  TLanguage aLanguage, 
+                                                  const TTtsVoice& aVoice )
+    {
+    RUBY_DEBUG_BLOCKL( "CTtsUtilityBody::CheckAndLoadCorrectPluginL" );
+    
+    TInt error( KErrNone );
+    
+    switch ( aQuality )
+        {
+        case ETtsQualityHighOnly:
+
+            OpenControllerConnectionL( KUidHqTtsPlugin );
+            
+            break;
+            
+        case ETtsQualityLowOnly:
+        case ETtsQualityUndefined:
+        
+            OpenControllerConnectionL( KUidTtsPlugin );
+                
+            break;
+            
+        case ETtsQualityHighPreferred:
+
+            TRAP( error, OpenControllerConnectionL( KUidHqTtsPlugin ) );
+            if ( error || !IsSupportedSpeaker( aLanguage, aVoice ) )
+                {
+                // Try to use Klatt if Hqtts not found or specific language/speaker 
+                // not available
+                OpenControllerConnectionL( KUidTtsPlugin );
+                }
+                
+            break;
+            
+        case ETtsQualityLowPreferred:
+
+            TRAP( error, OpenControllerConnectionL( KUidTtsPlugin ) );
+            if ( error || !IsSupportedSpeaker( aLanguage, aVoice ) )
+                {
+                // Try to use Hqtts if Klatt not found or specific language/speaker 
+                // not available
+                OpenControllerConnectionL( KUidHqTtsPlugin );
+                }
+        
+            break;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CTtsUtilityBody::IsSupportedSpeaker
+// 
+// -----------------------------------------------------------------------------
+//
+TBool CTtsUtilityBody::IsSupportedSpeaker( TLanguage aLanguage, 
+                                           const TTtsVoice& aVoice )
+    {
+    TBool answer( EFalse );
+    
+    if ( aLanguage == KTtsUndefinedLanguage )
+        {
+        // Undefined language -> plugin can use default language and voice.
+        answer = ETrue;
+        }
+    else
+        {
+        RArray<TLanguage> languages;
+        iTtsCustomCommands.GetSupportedLanguages( languages );
+
+        if ( languages.Find( aLanguage ) != KErrNotFound )
+            {
+            if ( aVoice == KNullDesC )
+                {
+                // Language found and undefined voice
+                answer = ETrue;
+                }
+            else
+                {
+                RArray<TTtsStyle> voices;
+                iTtsCustomCommands.GetSupportedVoices( aLanguage, voices );
+                
+                TInt counter( 0 );
+
+                while ( answer == EFalse && counter < voices.Count() )
+                    {
+                    if ( voices[counter].iVoice == aVoice )
+                        {
+                        // Both language and voice are supported 
+                        // by currently loaded plugin.
+                        answer = ETrue;
+                        }
+                        
+                    counter++;
+                    }
+                        
+                voices.Close();
+                }
+            }
+            
+        languages.Close();
+        }
+        
+    return answer;
+    }
+    
+// End of File