htiui/HtiServicePlugins/HtiAudioServicePlugin/src/HtiAudioServicePlugin.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 19 Feb 2010 22:51:38 +0200
branchRCL_3
changeset 3 2703485a934c
parent 0 d6fe6244b863
permissions -rw-r--r--
Revision: 201003 Kit: 201007

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Implements the ECom plugin for HTI audio playback control
*                service.
*
*/



// INCLUDE FILES
#include <apgcli.h>
#include <AudioPreference.h>
#include <bautils.h>
#include <e32std.h>
#include <HtiDispatcherInterface.h>
#include <HtiLogging.h>
#include <pathinfo.h>

#include "HtiAudioServicePlugin.h"

// EXTERNAL DATA STRUCTURES

// EXTERNAL FUNCTION PROTOTYPES

// CONSTANTS
const static TInt KPlayToneCmdLength    = 13;
const static TInt KStopCmdLength        = 1;
const static TInt KSetVolCmdLength      = 2;
const static TInt KListCmdMinLength     = 4;
const static TInt KPlayDtmfCmdMinLength = 17;
const static TInt KPlayFileCmdMinLength = 21;
const static TInt KDurationCmdMinLength = 6;
const static TInt KMaxVolCmdMinLength   = 6;

const static TInt KTUintSize = sizeof( TUint );

// MACROS

// LOCAL CONSTANTS AND MACROS
const static TUid KAudioServiceUid = { 0x10210CCB };

_LIT( KBackslash, "\\" );
_LIT( KRngMimeType, "application/vnd.nokia.ringing-tone" );
_LIT( KAudioMimeType, "audio/*" );

// NOTE: Max length for error description is defined
// in HtiDispatcherInterface.h (currently 118).
_LIT8( KErrorNoCmd, "ERROR: No command given" );
_LIT8( KErrorUnknownCmd, "ERROR: Unknown Audio Service command" );
_LIT8( KErrorInvalidParameters,
    "ERROR: Invalid parameter data for this command" );
_LIT8( KErrorInvalidPath, "ERROR: Invalid path" );
_LIT8( KErrorToneInitFailed, "ERROR: Tone initialization failed" );
_LIT8( KErrorTonePlayFailed, "ERROR: Tone playing failed" );
_LIT8( KErrorFileInitFailed, "ERROR: File playing initialization failed" );
_LIT8( KErrorFilePlayFailed, "ERROR: File playing failed" );
_LIT8( KErrorBusyPlaying, "ERROR: Currently busy playing" );
_LIT8( KErrorNothingPlaying, "ERROR: Nothing playing" );
_LIT8( KErrorDurationFailed, "ERROR: Duration query failed" );
_LIT8( KErrorMaxVolFailed, "ERROR: Max volume query failed" );
_LIT8( KErrorPosition, "ERROR: Invalid start or end position value" );

// MODULE DATA STRUCTURES

// LOCAL FUNCTION PROTOTYPES

// FORWARD DECLARATIONS

// ============================= LOCAL FUNCTIONS ===============================

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::CHtiAudioServicePlugin
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
//
CHtiAudioServicePlugin::CHtiAudioServicePlugin():iIsBusy( EFalse ),
                                                 iIsPlaying( EFalse ),
                                                 iCommandId( 0 ),
                                                 iPlayCommandId( 0 ),
                                                 iMessage( NULL ),
                                                 iErrorCode( 0 ),
                                                 iVolume( 0 ),
                                                 iRepeats( 0 ),
                                                 iTrailingSilence( 0 ),
                                                 iDtmfLength( 0 ),
                                                 iDtmfGapLength( 0 ),
                                                 iStartPos( 0 ),
                                                 iEndPos( 0 )
    {
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::ConstructL()
    {
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CHtiAudioServicePlugin* CHtiAudioServicePlugin::NewL()
    {
    CHtiAudioServicePlugin* self = new (ELeave) CHtiAudioServicePlugin;
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop();
    return self;
    }


// Destructor
CHtiAudioServicePlugin::~CHtiAudioServicePlugin()
    {
    delete iMessage;
    iMessage = NULL;
    delete iAudioPlayer;
    iAudioPlayer = NULL;
    delete iTonePlayer;
    iTonePlayer = NULL;
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::ProcessMessageL
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::ProcessMessageL( const TDesC8& aMessage,
                                        THtiMessagePriority /*aPriority*/ )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::ProcessMessageL" );
    HTI_LOG_FORMAT( "Message length = %d", aMessage.Length() );

    if ( iIsBusy )
        {
        HTI_LOG_TEXT( "Plugin is busy - leaving" );
        User::Leave( KErrInUse );
        }

    // Will be set to EFalse in the SendResponseMsg or SendErrorResponseMsg
    // methods when the response has been successfully sent and the plugin is
    // ready for next message.
    iIsBusy = ETrue;

    if ( aMessage.Length() < 1 )
        {
        User::LeaveIfError(
            SendErrorResponseMsg( KErrArgument, KErrorNoCmd ) );
        return;
        }

    iCommandId = aMessage[0];
    HTI_LOG_FORMAT( "Command = %d", iCommandId );
    TInt err = KErrNone;

    if ( iCommandId == ECmdListAudioFiles )
        {
        TRAP( err, HandleListAudioFilesCmdL( aMessage ) );
        }

    else if ( iCommandId == ECmdPlayFile )
        {
        TRAP( err, HandlePlayFileCmdL( aMessage ) );
        }

    else if ( iCommandId == ECmdPlayTone )
        {
        TRAP( err, HandlePlayToneCmdL( aMessage ) );
        }

    else if ( iCommandId == ECmdPlayDtmf )
        {
        TRAP( err, HandlePlayDtmfCmdL( aMessage ) );
        }

    else if ( iCommandId == ECmdStop )
        {
        TRAP( err, HandleStopCmdL( aMessage ) );
        }

    else if ( iCommandId == ECmdGetDuration )
        {
        TRAP( err, HandleGetDurationCmdL( aMessage ) );
        }

    else if ( iCommandId == ECmdGetMaxVol )
        {
        TRAP( err, HandleGetMaxVolCmdL( aMessage ) );
        }

    else if ( iCommandId == ECmdSetVol )
        {
        TRAP( err, HandleSetVolCmdL( aMessage ) );
        }

    else
        {
        User::LeaveIfError(
            SendErrorResponseMsg( KErrArgument, KErrorUnknownCmd ) );
        }

    if ( err != KErrNone )
        {
        User::LeaveIfError(
                SendErrorResponseMsg( err, KNullDesC8, iCommandId ) );
        }

    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::ProcessMessageL" );
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::HandleListAudioFilesCmdL()
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::HandleListAudioFilesCmdL( const TDesC8& aMessage )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::HandleListAudioFilesCmdL" );

    RFs fsSession;
    User::LeaveIfError( fsSession.Connect() );
    CleanupClosePushL( fsSession );

    // Build a list of directories to scan
    CDesCArraySeg* directories = new (ELeave) CDesCArraySeg( 5 );
    CleanupStack::PushL( directories );

    if ( aMessage.Length() == 1 )  // Add default sound directories
        {
        TFileName directory;

        // ROM
        directory.Append( PathInfo::RomRootPath() );
        directory.Append( PathInfo::SoundsPath() );
        if ( BaflUtils::PathExists( fsSession, directory ) )
            {
            directories->AppendL( directory );
            AddSubdirsRecursivelyL( directories->MdcaPoint(
                directories->Count() - 1 ), *directories, fsSession );
            }

        // Phone memory
        directory.Zero();
        directory.Append( PathInfo::PhoneMemoryRootPath() );
        directory.Append( PathInfo::SoundsPath() );
        if ( BaflUtils::PathExists( fsSession, directory ) )
            {
            directories->AppendL( directory );
            AddSubdirsRecursivelyL( directories->MdcaPoint(
                directories->Count() - 1 ), *directories, fsSession );
            }

        // Memory card
        directory.Zero();
        directory.Append( PathInfo::MemoryCardRootPath() );
        directory.Append( PathInfo::SoundsPath() );
        if ( BaflUtils::PathExists( fsSession, directory ) )
            {
            directories->AppendL( directory );
            AddSubdirsRecursivelyL( directories->MdcaPoint(
                directories->Count() - 1 ), *directories, fsSession );
            }
        }

    else  // Add given directory
        {
        if ( aMessage.Length() < KListCmdMinLength )
            {
            User::LeaveIfError( SendErrorResponseMsg(
                                    KErrArgument, KErrorInvalidParameters ) );
            CleanupStack::PopAndDestroy( 2 ); // directories, fsSession
            return;
            }

        TInt pathLength = aMessage[1];
        if ( ( aMessage.Length() - pathLength ) != KListCmdMinLength - 2 )
            {
            User::LeaveIfError( SendErrorResponseMsg(
                                    KErrArgument, KErrorInvalidParameters ) );
            CleanupStack::PopAndDestroy( 2 ); // directories, fsSession
            return;
            }

        TFileName directory;
        TInt nextOffset = ParseString( aMessage, 1, directory );
        TInt dirLength = directory.Length();
        if ( dirLength < 2 || nextOffset < 0 )
            {
            User::LeaveIfError( SendErrorResponseMsg(
                                    KErrArgument, KErrorInvalidParameters ) );
            CleanupStack::PopAndDestroy( 2 ); // directories, fsSession
            return;
            }

        HTI_LOG_DES( directory );

        if ( directory[dirLength - 1] != '\\' )
            {
            HTI_LOG_TEXT( "Adding backslash to the end" );
            directory.Append( KBackslash );
            HTI_LOG_DES( directory );
            }

        if ( BaflUtils::PathExists( fsSession, directory ) )
            {
            HTI_LOG_TEXT( "Given path exists" );
            directories->AppendL( directory );
            AddSubdirsRecursivelyL( directories->MdcaPoint(
                directories->Count() - 1 ), *directories, fsSession );
            }
        }

    // Buffer for the file list that is returned
    CBufFlat* fileListBuf = CBufFlat::NewL( 256 );
    CleanupStack::PushL( fileListBuf );
    TInt bufPos = 0;

    TInt audioFileCount = 0;
    TInt dirCount( directories->Count() );
    HTI_LOG_FORMAT( "Total directory count = %d", dirCount );

    if ( dirCount == 0 )
        {
        HTI_LOG_TEXT( "The given directory did not exist" );
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidPath ) );
        CleanupStack::PopAndDestroy( 3 ); // fileListBuf, directories, fsSession
        return;
        }

    // Loop all the directories
    for ( TInt i = 0; i < dirCount; i++ )
        {
        HTI_LOG_TEXT( "Reading dir:" );
        HTI_LOG_DES( directories->MdcaPoint( i ) );
        CDir* dir;
        TInt err = fsSession.GetDir( directories->MdcaPoint( i ),
            KEntryAttNormal, ESortNone, dir );
        if ( err )
            {
            delete dir;
            dir = NULL;
            continue; // This dir is skipped
            }
        CleanupStack::PushL( dir );

        // Loop all the entries in this directory
        TInt fileCount( dir->Count() );
        for ( TInt j = 0; j < fileCount; j++ )
            {
            TFileName filePath;
            filePath.Copy( directories->MdcaPoint( i ) );
            filePath.Append( ( *dir )[j].iName );

            // Check MIME type match
            if ( MatchMimeTypeL( filePath, KAudioMimeType ) ||
                 MatchMimeTypeL( filePath, KRngMimeType ) )
                {
                HBufC8* filePathBuf8 = HBufC8::NewLC( KMaxFileName );
                filePathBuf8->Des().Copy( filePath );
                TInt pathLength = filePathBuf8->Length();
                HTI_LOG_DES( *filePathBuf8 );
                fileListBuf->ExpandL( bufPos, pathLength + 1 );
                TBuf8<1> lengthBuf;
                lengthBuf.Append( pathLength );
                fileListBuf->Write( bufPos, lengthBuf, 1 );
                bufPos++;
                fileListBuf->Write( bufPos, filePathBuf8->Ptr(), pathLength );
                bufPos += pathLength;
                CleanupStack::PopAndDestroy(); // filePathBuf8
                audioFileCount++;
                }

            } // files loop
        CleanupStack::PopAndDestroy(); // dir
        } // directories loop

    HTI_LOG_FORMAT( "Total audio file count = %d", audioFileCount );

    // All files added - write number of files to the beginning of buffer...
    TBuf8<2> countBuf;
    countBuf.Append( (TUint8*)(&audioFileCount), 2 );
    fileListBuf->InsertL( 0, countBuf, 2 );

    // ...and send it away
    TPtr8 ptr = fileListBuf->Ptr( 0 );
    User::LeaveIfError( SendResponseMsg( ptr ) );

    CleanupStack::PopAndDestroy( 3 ); // fileListBuf, directories, fsSession

    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::HandleListAudioFilesCmdL" );
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::HandlePlayFileCmdL()
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::HandlePlayFileCmdL( const TDesC8&aMessage )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::HandlePlayFileCmdL" );

    if ( iIsPlaying )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrInUse, KErrorBusyPlaying ) );
        return;
        }

    iPlayCommandId = ECmdPlayFile;

    /*
    Message bytes:
             0 = command code
             1 = path length
         2 - n = full path to file
        next 1 = volume
        next 4 = start position
        next 4 = end position
        next 1 = repeats
        next 4 = silence between repeats
        next 1 = audio setting
    */

    if ( aMessage.Length() < KPlayFileCmdMinLength )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidParameters ) );
        return;
        }

    // Parse parameter values from the message
    const TUint8* ptr = aMessage.Ptr();
    TInt pathLength = aMessage[1];

    if ( ( aMessage.Length() - pathLength ) !=
         ( KPlayFileCmdMinLength - 4 ) )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidParameters ) );
        return;
        }

    TFileName filePath;
    TInt nextOffset = ParseString( aMessage, 1, filePath );
    if ( filePath.Length() < 2 || nextOffset < 0 )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidParameters ) );
        return;
        }
    HTI_LOG_TEXT( "Full file path:" );
    HTI_LOG_DES( filePath );
    iVolume = aMessage[nextOffset];
    nextOffset++;
    HTI_LOG_FORMAT( "Volume = %d", iVolume );
    iStartPos = ParseUint32( ptr + nextOffset );
    HTI_LOG_FORMAT( "Start position = %d", iStartPos );
    nextOffset += 4;
    iEndPos = ParseUint32( ptr + nextOffset );
    HTI_LOG_FORMAT( "End position = %d", iEndPos );
    nextOffset += 4;
    iRepeats = aMessage[nextOffset];
    nextOffset++;
    HTI_LOG_FORMAT( "Repeats = %d", iRepeats );
    iTrailingSilence = ParseUint32( ptr + nextOffset );
    HTI_LOG_FORMAT( "Trailing silence = %d", iTrailingSilence );
    nextOffset += 4;
    TInt audioSetting = aMessage[nextOffset];
    HTI_LOG_FORMAT( "Audio setting = %d", audioSetting );

    // Set audio settings
    if ( audioSetting > ERingTonePreview ) audioSetting = EDefault;
    SetAudioSettings( ( TAudioSetting ) audioSetting );

    // Check if file is rng ringtone, it has to be played using tone player -
    // other formats are played with audio player.

    TInt err = KErrNone;
    TBool isRng = EFalse;
    TRAP( err, isRng = MatchMimeTypeL( filePath, KRngMimeType ) );

    if ( err )
        {
        User::LeaveIfError( SendErrorResponseMsg( err, KErrorFileInitFailed ) );
        return;
        }

    if ( isRng )
        {
        HTI_LOG_TEXT( "File is RNG - creating tone player" );
        TRAP( err, iTonePlayer = CMdaAudioToneUtility::NewL(
                *this, NULL, iAudioPriority, iAudioPriorityPreference ) );
        }

    else
        {
        HTI_LOG_TEXT( "File is not RNG - creating audio player" );
        TRAP( err, iAudioPlayer = CMdaAudioPlayerUtility::NewFilePlayerL(
                filePath, *this, iAudioPriority, iAudioPriorityPreference ) );
        // MapcInitComplete callback function will be called
        }

    if ( err )
        {
        delete iAudioPlayer;
        iAudioPlayer = NULL;
        delete iTonePlayer;
        iTonePlayer = NULL;
        User::LeaveIfError( SendErrorResponseMsg(
                                err, KErrorFileInitFailed ) );
        }

    if ( iTonePlayer )
        {
        iTonePlayer->PrepareToPlayFileSequence( filePath );
        // MatoPrepareComplete callback function will be called
        }

    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::HandlePlayFileCmdL" );
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::HandlePlayToneCmdL()
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::HandlePlayToneCmdL( const TDesC8& aMessage )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::HandlePlayToneCmdL" );

    if ( iIsPlaying )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrInUse, KErrorBusyPlaying ) );
        return;
        }

    iPlayCommandId = ECmdPlayTone;

    /*
    Message bytes:
            0  = command code
        1 - 2  = frequency value
        3 - 6  = duration value
            7  = volume value
            8  = repeat value
        9 - 12 = silence between repeats
    */

    if ( aMessage.Length() != KPlayToneCmdLength )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidParameters ) );
        return;
        }

    // Parse parameter values from the message
    const TUint8* ptr = aMessage.Ptr();
    TInt frequency = ParseUint16( ptr + 1 );
    HTI_LOG_FORMAT( "Freq = %d", frequency );
    TUint duration = ParseUint32( ptr + 3 );
    HTI_LOG_FORMAT( "Duration = %d", duration );
    iVolume = aMessage[7];
    HTI_LOG_FORMAT( "Volume = %d", iVolume );
    iRepeats = aMessage[8];
    HTI_LOG_FORMAT( "Repeats = %d", iRepeats );
    iTrailingSilence = ParseUint32( ptr + 9 );
    HTI_LOG_FORMAT( "Silence = %d", iTrailingSilence );

    TRAPD( err, iTonePlayer = CMdaAudioToneUtility::NewL( *this ) );

    if ( err )
        {
        delete iTonePlayer;
        iTonePlayer = NULL;
        User::LeaveIfError( SendErrorResponseMsg(
                                err, KErrorToneInitFailed ) );
        }

    iTonePlayer->PrepareToPlayTone( frequency,
                              TTimeIntervalMicroSeconds( duration ) );
    // MatoPrepareComplete callback function will be called when ready to play
    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::HandlePlayToneCmdL" );
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::HandlePlayDtmfCmdL()
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::HandlePlayDtmfCmdL( const TDesC8& aMessage )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::HandlePlayDtmfCmdL" );

    if ( iIsPlaying )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrInUse, KErrorBusyPlaying ) );
        return;
        }

    iPlayCommandId = ECmdPlayDtmf;

    /*
    Message bytes:
             0 = command code
             1 = DTMF string length
         2 - n = dtmf string
        next 4 = tone length
        next 4 = tone gap length
        next 1 = volume
        next 1 = repeats
        next 4 = silence between repeats
    */

    if ( aMessage.Length() < KPlayDtmfCmdMinLength )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidParameters ) );
        return;
        }

    // Parse parameter values from the message
    const TUint8* ptr = aMessage.Ptr();
    TInt stringLength = aMessage[1];

    if ( ( aMessage.Length() - stringLength ) !=
         ( KPlayDtmfCmdMinLength - 1 ) )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidParameters ) );
        return;
        }

    TBuf<255> dtmfString;
    TInt nextOffset = ParseString( aMessage, 1, dtmfString );
    if ( dtmfString.Length() < 1 || nextOffset < 0 )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidParameters ) );
        return;
        }
    HTI_LOG_TEXT( "DTMF string:" );
    HTI_LOG_DES( dtmfString );
    iDtmfLength = ParseUint32( ptr + nextOffset );
    nextOffset += 4;
    HTI_LOG_FORMAT( "DTMF length = %d", iDtmfLength );
    iDtmfGapLength = ParseUint32( ptr + nextOffset );
    nextOffset += 4;
    HTI_LOG_FORMAT( "DTMF gap length = %d", iDtmfGapLength );
    iVolume = aMessage[nextOffset];
    nextOffset++;
    HTI_LOG_FORMAT( "Volume = %d", iVolume );
    iRepeats = aMessage[nextOffset];
    nextOffset++;
    HTI_LOG_FORMAT( "Repeats = %d", iRepeats );
    iTrailingSilence = ParseUint32( ptr + nextOffset );
    HTI_LOG_FORMAT( "Trailing silence = %d", iTrailingSilence );

    SetAudioSettings( EDtmfString );

    TRAPD( err, iTonePlayer = CMdaAudioToneUtility::NewL(
            *this, NULL, iAudioPriority, iAudioPriorityPreference ) );

    if ( err )
        {
        delete iTonePlayer;
        iTonePlayer = NULL;
        User::LeaveIfError( SendErrorResponseMsg( err, KErrorToneInitFailed ) );
        }

    iTonePlayer->PrepareToPlayDTMFString( dtmfString );
    // MatoPrepareComplete callback function will be called when ready to play
    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::HandlePlayDtmfCmdL" );
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::HandleStopCmdL()
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::HandleStopCmdL( const TDesC8& aMessage )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::HandleStopCmdL" );

    if ( aMessage.Length() != KStopCmdLength )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidParameters ) );
        return;
        }

    if ( !iIsPlaying )
        {
        HTI_LOG_TEXT( "Not playing - nothing to stop" );
        // Just send "OK" reply if nothing is currently playing
        User::LeaveIfError( SendResponseMsg( _L8( "OK" ) ) );
        }

    else
        {
        if ( iAudioPlayer )
            {
            HTI_LOG_TEXT( "Stopping audio player" );
            iAudioPlayer->Stop();
            iIsPlaying = EFalse;
            delete iAudioPlayer;
            iAudioPlayer = NULL;
            // According to documentation should call MapcPlayComplete callback
            // method but it doesn't, so sending reply here.
            User::LeaveIfError( SendResponseMsg( _L8( "OK" ) ) );
            }

        else if ( iTonePlayer )
            {
            HTI_LOG_TEXT( "Stopping tone player" );
            iTonePlayer->CancelPlay();
            iIsPlaying = EFalse;
            delete iTonePlayer;
            iTonePlayer = NULL;
            // Callback method MatoPlayComplete is not called -
            // sending reply here.
            User::LeaveIfError( SendResponseMsg( _L8( "OK" ) ) );
            }
        }
    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::HandleStopCmdL" );
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::HandleGetDurationCmdL()
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::HandleGetDurationCmdL( const TDesC8& aMessage )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::HandleGetDurationCmdL" );

    if ( iIsPlaying )
        {
         // If currently playing, no parameters allowed. Returns the duration
         // of currently playing sound.
        if ( aMessage.Length() != 1 )
            {
            User::LeaveIfError( SendErrorResponseMsg(
                                    KErrInUse, KErrorBusyPlaying ) );
            return;
            }

        if ( iAudioPlayer )
            {
            TTimeIntervalMicroSeconds durationValue =
                                iAudioPlayer->Duration();

            if ( I64HIGH( durationValue.Int64() ) > 0 )
                {
                User::LeaveIfError( SendErrorResponseMsg(
                                        KErrOverflow, KErrorDurationFailed ) );
                return;
                }
            else
                {
                TUint duration = I64LOW( durationValue.Int64() );
                TBuf8<KTUintSize> durationBuf;
                durationBuf.Append( (TUint8*)(&duration), KTUintSize );
                User::LeaveIfError( SendResponseMsg( durationBuf ) );
                return;
                }
            }

        else  // Duration supported only for audio player
            {
            User::LeaveIfError( SendErrorResponseMsg(
                                    KErrNotSupported, KErrorDurationFailed ) );
            return;
            }
        }

    /* Command must have file path parameter if not currently playing.
    Message bytes:
             0 = command code
             1 = path length
         2 - n = full path to file
    */

    if ( aMessage.Length() < KDurationCmdMinLength )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidParameters ) );
        return;
        }

    TInt pathLength = aMessage[1];
    if ( ( aMessage.Length() - pathLength ) !=
         ( KDurationCmdMinLength - 4 ) )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidParameters ) );
        return;
        }

    // Parse parameter values from the message
    TFileName filePath;
    TInt nextOffset = ParseString( aMessage, 1, filePath );
    if ( filePath.Length() < 2 || nextOffset < 0 )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidParameters ) );
        return;
        }
    HTI_LOG_TEXT( "Full file path:" );
    HTI_LOG_DES( filePath );

    TRAPD( err, iAudioPlayer = CMdaAudioPlayerUtility::NewFilePlayerL(
                                                        filePath, *this ) );
    if ( err )
        {
        delete iAudioPlayer;
        iAudioPlayer = NULL;
        User::LeaveIfError( SendErrorResponseMsg( err, KErrorDurationFailed ) );
        }

    // MapcInitComplete callback function will be called
    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::HandleGetDurationCmdL" );
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::HandleGetMaxVolCmdL()
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::HandleGetMaxVolCmdL( const TDesC8& aMessage )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::HandleGetMaxVolCmdL" );

    if ( iIsPlaying )
        {
         // If currently playing, no parameters allowed. Returns the max volume
         // of currently playing sound.
        if ( aMessage.Length() != 1 )
            {
            User::LeaveIfError( SendErrorResponseMsg(
                                    KErrInUse, KErrorBusyPlaying ) );
            return;
            }

        TInt maxVol = -1;

        if ( iAudioPlayer )
            {
            maxVol = iAudioPlayer->MaxVolume();
            }

        else if ( iTonePlayer )
            {
            maxVol = iTonePlayer->MaxVolume();
            }

        HTI_LOG_FORMAT( "Max volume = %d", maxVol );

        if ( maxVol < 0 )
            {
            // Should not happen
            User::LeaveIfError( SendErrorResponseMsg(
                                    KErrGeneral, KErrorMaxVolFailed ) );
            return;
            }

        if ( maxVol > 255 ) maxVol = 255;
        TBuf8<1> maxVolBuf;
        maxVolBuf.Append( maxVol );
        User::LeaveIfError( SendResponseMsg( maxVolBuf ) );
        return;
        }

    /*
    Message bytes:
             0 = command code
             1 = path length
         2 - n = full path to file
    */

    if ( aMessage.Length() < KMaxVolCmdMinLength )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidParameters ) );
        return;
        }

    TInt pathLength = aMessage[1];
    if ( ( aMessage.Length() - pathLength ) != ( KMaxVolCmdMinLength - 4 ) )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidParameters ) );
        return;
        }

    // Parse parameter values from the message
    TFileName filePath;
    TInt nextOffset = ParseString( aMessage, 1, filePath );
    if ( filePath.Length() < 2 || nextOffset < 0 )
        {
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrArgument, KErrorInvalidParameters ) );
        return;
        }
    HTI_LOG_TEXT( "Full file path:" );
    HTI_LOG_DES( filePath );

    TInt err = KErrNone;
    TBool isRng = EFalse;
    TRAP( err, isRng = MatchMimeTypeL( filePath, KRngMimeType ) );

    if ( err )
        {
        User::LeaveIfError( SendErrorResponseMsg( err, KErrorMaxVolFailed ) );
        return;
        }

    if ( isRng )
        {
        HTI_LOG_TEXT( "File is RNG - creating tone player" );
        TRAP( err, iTonePlayer = CMdaAudioToneUtility::NewL( *this ) );
        }

    else
        {
        HTI_LOG_TEXT( "File is not RNG - creating audio player" );
        TRAP( err, iAudioPlayer = CMdaAudioPlayerUtility::NewFilePlayerL(
                                                        filePath, *this ) );
        // MapcInitComplete callback function will be called
        }

    if ( err )
        {
        delete iAudioPlayer;
        iAudioPlayer = NULL;
        delete iTonePlayer;
        iTonePlayer = NULL;
        User::LeaveIfError( SendErrorResponseMsg( err, KErrorMaxVolFailed ) );
        }

    if ( iTonePlayer )
        {
        iTonePlayer->PrepareToPlayFileSequence( filePath );
        // MatoPrepareComplete callback function will be called
        }

    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::HandleGetMaxVolCmdL" );
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::HandleSetVolCmdL()
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::HandleSetVolCmdL( const TDesC8& aMessage )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::HandleSetVolCmdL" );

    if ( aMessage.Length() != KSetVolCmdLength )
        {
        User::LeaveIfError( SendErrorResponseMsg( KErrArgument,
                                                  KErrorInvalidParameters ) );
        }

    if ( !iIsPlaying )
        {
        HTI_LOG_TEXT( "Nothing playing - not setting volume" );
        User::LeaveIfError( SendErrorResponseMsg(
                                KErrNotReady, KErrorNothingPlaying ) );
        }

    else
        {
        TInt volume = aMessage[1]; // [0] = command code, [1] = volume value
        HTI_LOG_FORMAT( "requested volume = %d", volume );

        if ( iAudioPlayer )
            {
            HTI_LOG_TEXT( "Setting audio player volume" );
            TInt maxVol = iAudioPlayer->MaxVolume();
            HTI_LOG_FORMAT( "max volume = %d", maxVol );
            if ( volume > maxVol ) volume = maxVol;
            iAudioPlayer->SetVolume( volume );
            TBuf8<1> volBuf;
            volBuf.Append( volume );
            User::LeaveIfError( SendResponseMsg( volBuf ) );
            }
        else if ( iTonePlayer )
            {
            HTI_LOG_TEXT( "Setting tone player volume" );
            TInt maxVol = iTonePlayer->MaxVolume();
            HTI_LOG_FORMAT( "max volume = %d", maxVol );
            if ( volume > maxVol ) volume = maxVol;
            iTonePlayer->SetVolume( volume );
            TBuf8<1> volBuf;
            volBuf.Append( volume );
            User::LeaveIfError( SendResponseMsg( volBuf ) );
            }
        }
    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::HandleSetVolCmdL" );
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::MatoPrepareComplete()
// Tone player prepare complete
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::MatoPrepareComplete( TInt aError )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::MatoPrepareComplete" );

    if ( iCommandId == ECmdGetMaxVol )
        {
        if ( aError )
            {
            SendErrorResponseMsg( aError, KErrorMaxVolFailed );
            }

        else
            {
            TInt maxVol = iTonePlayer->MaxVolume();
            HTI_LOG_FORMAT( "Max volume = %d", maxVol );
            if ( maxVol > 255 ) maxVol = 255;
            TBuf8<1> maxVolBuf;
            maxVolBuf.Append( maxVol );
            SendResponseMsg( maxVolBuf );
            }

        delete iTonePlayer;
        iTonePlayer = NULL;
        return;
        }

    if ( aError )
        {
        SendErrorResponseMsg( aError, KErrorToneInitFailed );
        delete iTonePlayer;
        iTonePlayer = NULL;
        }

    else
        {
        if ( iCommandId == ECmdPlayDtmf )
            {
            iTonePlayer->SetDTMFLengths(
                TTimeIntervalMicroSeconds32( iDtmfLength ),
                TTimeIntervalMicroSeconds32( iDtmfGapLength ),
                TTimeIntervalMicroSeconds32( 0 ) );
            }

        if ( iVolume > iTonePlayer->MaxVolume() )
            {
            iVolume = iTonePlayer->MaxVolume();
            }

        iTonePlayer->SetVolume( iVolume );
        iTonePlayer->SetRepeats( iRepeats + 1,
                        TTimeIntervalMicroSeconds( iTrailingSilence ) );
        iIsPlaying = ETrue;
        iTonePlayer->Play();
        iIsBusy = EFalse;
        // MatoPlayComplete callback function will be called when playing ends.
        }

    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::MatoPrepareComplete" );
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::MatoPlayComplete()
// Tone play complete
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::MatoPlayComplete( TInt aError )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::MatoPlayComplete" );

    iIsPlaying = EFalse;
    iIsBusy = ETrue; // Busy dispatching the play complete message

    if ( aError )
        {
        SendErrorResponseMsg( aError, KErrorTonePlayFailed, iPlayCommandId );
        }

    else
        {
        SendResponseMsg( _L8( "OK" ), iPlayCommandId );
        }

    delete iTonePlayer;
    iTonePlayer = NULL;

    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::MatoPlayComplete" );
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::MapcInitComplete()
// Audio player init complete
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::MapcInitComplete( TInt aError,
                                 const TTimeIntervalMicroSeconds& aDuration )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::MapcInitComplete" );

    if ( iCommandId == ECmdPlayFile )
        {
        if ( aError )
            {
            SendErrorResponseMsg( aError, KErrorFileInitFailed );
            delete iAudioPlayer;
            iAudioPlayer = NULL;
            }

        else
            {
            if ( iEndPos < iStartPos ||
                        TTimeIntervalMicroSeconds( iStartPos ) > aDuration )
                {
                SendErrorResponseMsg( KErrArgument, KErrorPosition );
                delete iAudioPlayer;
                iAudioPlayer = NULL;
                return;
                }

            if ( iEndPos > 0 )
                {
                iAudioPlayer->SetPlayWindow(
                    TTimeIntervalMicroSeconds( iStartPos ),
                    TTimeIntervalMicroSeconds( iEndPos ) );
                }

            HTI_LOG_FORMAT( "Max volume = %d", iAudioPlayer->MaxVolume() );
            HTI_LOG_FORMAT( "Setting volume = %d", iVolume );
            if ( iVolume > iAudioPlayer->MaxVolume() )
                {
                iVolume = iAudioPlayer->MaxVolume();
                }

            iAudioPlayer->SetVolume( iVolume );
            iAudioPlayer->SetRepeats( iRepeats,
                            TTimeIntervalMicroSeconds( iTrailingSilence ) );
            iIsPlaying = ETrue;
            iAudioPlayer->Play();

            // Have to do this after play command because
            // volume setting before play seems to have no effect.
            iAudioPlayer->SetVolume( 0 );
            iAudioPlayer->SetVolume( iVolume );

            iIsBusy = EFalse;
            // MapcPlayComplete callback function is called when playing ends
            }
        }

    else if ( iCommandId == ECmdGetDuration )
        {
        if ( aError )
            {
            SendErrorResponseMsg( aError, KErrorDurationFailed );
            }

        else
            {
            if ( I64HIGH( aDuration.Int64() ) > 0 )
                {
                SendErrorResponseMsg( KErrOverflow, KErrorDurationFailed );
                }
            else
                {
                TUint duration = I64LOW( aDuration.Int64() );
                TBuf8<KTUintSize> durationBuf;
                durationBuf.Append( (TUint8*)(&duration), KTUintSize );
                SendResponseMsg( durationBuf );
                }
            }
        delete iAudioPlayer;
        iAudioPlayer = NULL;
        }

    else if ( iCommandId == ECmdGetMaxVol )
        {
        if ( aError )
            {
            SendErrorResponseMsg( aError, KErrorMaxVolFailed );
            }

        else
            {
            TInt maxVol = iAudioPlayer->MaxVolume();
            HTI_LOG_FORMAT( "Max volume = %d", maxVol );
            if ( maxVol > 255 ) maxVol = 255;
            TBuf8<1> maxVolBuf;
            maxVolBuf.Append( maxVol );
            SendResponseMsg( maxVolBuf );
            }
        delete iAudioPlayer;
        iAudioPlayer = NULL;
        }

    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::MapcInitComplete" );
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::MapcPlayComplete()
// Audio play complete
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::MapcPlayComplete( TInt aError )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::MapcPlayComplete" );

    iIsPlaying = EFalse;
    iIsBusy = ETrue; // Busy dispatching the play complete message

    if ( aError )
        {
        SendErrorResponseMsg( aError, KErrorFilePlayFailed, ECmdPlayFile );
        }

    else
        {
        SendResponseMsg( _L8( "OK" ), iPlayCommandId );
        }

    delete iAudioPlayer;
    iAudioPlayer = NULL;

    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::MapcPlayComplete" );
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::NotifyMemoryChange
// Called when HTI Framework has dispatched a message forward and the amount
// of free memory in the message queue has changed.
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::NotifyMemoryChange( TInt aAvailableMemory )
    {
    if ( iIsBusy && iMessage )
        {
        if ( aAvailableMemory >= iMessage->Size() )
            {
            if ( iErrorCode == 0 )
                {
                TInt err = iDispatcher->DispatchOutgoingMessage(
                    iMessage, KAudioServiceUid );

                if ( err == KErrNone )
                    {
                    // Ownership of iMessage has been transferred
                    iMessage = NULL;
                    iIsBusy = EFalse;
                    iDispatcher->RemoveMemoryObserver( this );
                    }

                else if ( err == KErrNoMemory )
                    {
                    // Keep retrying.
                    }

                else // Give up on sending
                    {
                    delete iMessage;
                    iMessage = NULL;
                    iIsBusy = EFalse;
                    iDispatcher->RemoveMemoryObserver( this );
                    }
                }

            else
                {
                TInt err = iDispatcher->DispatchOutgoingErrorMessage(
                    iErrorCode, *iMessage, KAudioServiceUid );

                // If it was success or some other error than KErrNoMemory
                // we are done sending or trying to send this message.
                if ( err != KErrNoMemory )
                    {
                    delete iMessage;
                    iMessage = NULL;
                    iIsBusy = EFalse;
                    iDispatcher->RemoveMemoryObserver( this );
                    }

                else
                    {
                    // Keep retrying.
                    }
                }
            }
        }
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::IsBusy
// -----------------------------------------------------------------------------
//
TBool CHtiAudioServicePlugin::IsBusy()
    {
    return iIsBusy;
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::SendResponseMsg
// Sends a message out to the message dispatcher.
// -----------------------------------------------------------------------------
//
TInt CHtiAudioServicePlugin::SendResponseMsg( const TDesC8& aMsg,
                                              const TUint8 aCommandId )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::SendResponseMsg" );

    iErrorCode = 0;

    if ( iDispatcher == NULL )
        {
        iIsBusy = EFalse;
        return KErrGeneral;
        }

    iDispatcher->RemoveMemoryObserver( this );

    delete iMessage;
    iMessage = NULL;
    iMessage = HBufC8::New( aMsg.Length() + 1 );

    if ( iMessage == NULL )
        {
        iIsBusy = EFalse;
        return KErrNoMemory;
        }

    TPtr8 ptr8 = iMessage->Des();
    if ( aCommandId != 0 )
        {
        ptr8.Append( aCommandId );
        }
    else
        {
        ptr8.Append( iCommandId );
        }

    ptr8.Append( aMsg );

    TInt err = KErrNone;

    err = iDispatcher->DispatchOutgoingMessage( iMessage, KAudioServiceUid );

    if ( err == KErrNoMemory )
        {
        HTI_LOG_TEXT( "Message queue memory full - waiting" );
        iIsBusy = ETrue; // Should already be true, but just in case
        iDispatcher->AddMemoryObserver( this );
        // For the caller of this method all is OK, sending is just delayed
        err = KErrNone;
        }

    else if ( err == KErrNone )
        {
        HTI_LOG_TEXT( "Message sent to dispatcher" );
        iMessage = NULL; // Ownership of iMessage has been transferred
        iIsBusy = EFalse;
        }

    else // give up on sending
        {
        HTI_LOG_FORMAT( "Other dispatcher error %d", err );
        delete iMessage;
        iMessage = NULL;
        iIsBusy = EFalse;
        }

    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::SendResponseMsg" );
    return err;
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::SendErrorResponseMsg
// Sends an error message out to the message dispatcher.
// -----------------------------------------------------------------------------
//
TInt CHtiAudioServicePlugin::SendErrorResponseMsg( TInt aErrorCode,
                        const TDesC8& aErrorDescription,
                        const TUint8 aCommandId )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::SendErrorResponseMsg" );

    iErrorCode = aErrorCode;

    if ( iDispatcher == NULL )
        {
        iIsBusy = EFalse;
        return KErrGeneral;
        }

    iDispatcher->RemoveMemoryObserver( this );

    delete iMessage;
    iMessage = NULL;
    iMessage = HBufC8::New( aErrorDescription.Length() + 1 );

    if ( iMessage == NULL )
        {
        iIsBusy = EFalse;
        return KErrNoMemory;
        }

    TPtr8 ptr8 = iMessage->Des();
    if ( aCommandId != 0 )
        {
        ptr8.Append( aCommandId );
        }
    else
        {
        ptr8.Append( iCommandId );
        }

    ptr8.Append( aErrorDescription );

    TInt err = KErrNone;

    err = iDispatcher->DispatchOutgoingErrorMessage(
        aErrorCode, *iMessage, KAudioServiceUid );

    if ( err == KErrNoMemory )
        {
        HTI_LOG_TEXT( "Message queue memory full - waiting" );
        iIsBusy = ETrue; // Should already be true, but just in case
        iDispatcher->AddMemoryObserver( this );
        // For the caller of this method all is OK, sending is just delayed
        err = KErrNone;
        }

    else if ( err == KErrNone )
        {
        HTI_LOG_TEXT( "Error message sent to dispatcher" );
        delete iMessage;
        iMessage = NULL;
        iIsBusy = EFalse;
        }

    else // give up on sending
        {
        HTI_LOG_FORMAT( "Other dispatcher error %d", err );
        delete iMessage;
        iMessage = NULL;
        iIsBusy = EFalse;
        }

    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::SendErrorResponseMsg" );
    return err;
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::ParseString()
// -----------------------------------------------------------------------------
//
TInt CHtiAudioServicePlugin::ParseString( const TDesC8& aRequest,
                                          TInt aOffset,
                                          TDes& aResult )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::ParseString" );

    // If offset outside the string return empty string
    if ( aOffset >= aRequest.Size() )
        {
        return aOffset;
        }

    TInt length = aRequest[aOffset];
    HTI_LOG_FORMAT( "String length = %d", length );

    // If length is zero return empty string
    if ( length < 1 )
        {
        return aOffset + 1;
        }

    if ( length > aResult.MaxLength() )
        {
        return KErrBadDescriptor;
        }

    TInt nextOffset = length + aOffset + 1;
    HTI_LOG_FORMAT( "Next offset = %d", nextOffset );
    HTI_LOG_FORMAT( "Request size = %d", aRequest.Size() );

    if ( nextOffset > aRequest.Size() )
        {
        return KErrArgument;
        }

    aResult.Copy( aRequest.Mid( aOffset + 1, length ) );

    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::ParseString" );
    return nextOffset;
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::AddSubdirsRecursivelyL
// Scan all subdirectories from the given path and add them to the aArray.
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::AddSubdirsRecursivelyL( const TDesC& aPath,
                                                     CDesCArraySeg& aArray,
                                                     RFs& aFs )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::AddSubdirsRecursivelyL" );

    CDirScan* dirScan = CDirScan::NewL( aFs );
    CleanupStack::PushL( dirScan );

    TFileName* path = new (ELeave) TFileName;
    CleanupStack::PushL( path );

    CDir* directory = NULL;
    TPtrC currentPath;

    dirScan->SetScanDataL( aPath, KEntryAttMatchExclusive | KEntryAttDir, ESortNone );
    dirScan->NextL( directory );

    while ( directory )
        {
        CleanupStack::PushL( directory );
        currentPath.Set( dirScan->FullPath() );

        TInt dirCount( directory->Count() );
        for ( TInt i = 0; i < dirCount ; ++i )
            {
            path->Copy( currentPath );
            path->Append( ( *directory )[ i ].iName );
            path->Append( KBackslash );
            aArray.AppendL( *path );
            }

        CleanupStack::PopAndDestroy( directory );
        directory = NULL;

        dirScan->NextL( directory );
        }

    CleanupStack::PopAndDestroy( 2 ); // path, dirScan

    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::AddSubdirsRecursivelyL" );
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::MatchMimeTypeL
// Check if the MIME type of the given file matches to the given pattern.
// -----------------------------------------------------------------------------
//
TBool CHtiAudioServicePlugin::MatchMimeTypeL( const TDesC& aFilePath,
                      const TDesC& aMimeTypeMatchPattern )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::MatchMimeTypeL" );

    RApaLsSession apaSession;
    User::LeaveIfError( apaSession.Connect() );
    CleanupClosePushL( apaSession );

    TUid dummyUid( KNullUid );
    TDataType dataType;
    User::LeaveIfError( apaSession.AppForDocument( aFilePath,
                                                   dummyUid,
                                                   dataType ) );
    CleanupStack::PopAndDestroy(); // apaSession

    if ( dataType.Des().MatchF( aMimeTypeMatchPattern ) >= 0 )
        {
        HTI_LOG_TEXT( "Match" );
        return ETrue;
        }

    HTI_LOG_TEXT( "Not match" );
    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::MatchMimeTypeL" );
    return EFalse;
    }


// -----------------------------------------------------------------------------
// CHtiAudioServicePlugin::SetAudioSettings
// Set the audio priority and priority preference values.
// -----------------------------------------------------------------------------
//
void CHtiAudioServicePlugin::SetAudioSettings( TAudioSetting aSetting )
    {
    HTI_LOG_FUNC_IN( "CHtiAudioServicePlugin::SetAudioSettings" );
    HTI_LOG_FORMAT( "Setting values for audio setting %d", aSetting );

    switch ( aSetting )
        {
        case EGeneralMusic:
            {
            iAudioPriority = KAudioPriorityRealOnePlayer;
            iAudioPriorityPreference =
                ( TMdaPriorityPreference ) KAudioPrefRealOneLocalPlayback;
            break;
            }

        case ERingTonePreview:
            {
            iAudioPriority = KAudioPriorityRingingTonePreview;
            iAudioPriorityPreference =
                ( TMdaPriorityPreference ) KAudioPrefRingFilePreview;
            break;
            }
/*
        case EIncomingCall:
            {
            iAudioPriority = KAudioPriorityPhoneCall;
            iAudioPriorityPreference =
                ( TMdaPriorityPreference ) KAudioPrefIncomingCall;
            break;
            }
*/
        case EDtmfString:
            {

            iAudioPriority = KAudioPriorityDTMFString;
            iAudioPriorityPreference =
                ( TMdaPriorityPreference ) KAudioDTMFString;
            break;
            }

        default:
            {
            iAudioPriority = EMdaPriorityNormal;
            iAudioPriorityPreference = EMdaPriorityPreferenceTimeAndQuality;
            break;
            }
        }

    HTI_LOG_FUNC_OUT( "CHtiAudioServicePlugin::SetAudioSettings" );
    }


// ========================== OTHER EXPORTED FUNCTIONS =========================

//  End of File