srsf/ttsutility/src/ttsutilitybody.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:29:17 +0100
branchRCL_3
changeset 19 e36f3802f733
parent 0 bf1d17376201
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* 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