audiostubs/devsoundextensions_stubs/mmfdevsoundadaptation_stub/src/MmfDevSoundAdaptationBody.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 14 Jan 2010 07:14:53 +0200
changeset 0 0ce1b5ce9557
child 3 f935d51494d1
permissions -rw-r--r--
Revision: 201001

/*
* Copyright (c) 2006-2008 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: Audio Stubs -  DevSound adaptation stub body implementation.
*
*/


// INCLUDE FILES
#include <e32base.h>
#include <mdaaudiotoneplayer.h>

#include "G711DecoderIntfc.h"
#include "G729DecoderIntfc.h"
#include "IlbcDecoderIntfc.h"
#include "G711EncoderIntfc.h"
#include "G729EncoderIntfc.h"
#include "IlbcEncoderIntfc.h"
#include "ErrorConcealmentIntfc.h"
#include "SpeechEncoderConfig.h"

#include "AudioInputMessageTypes.h"
#include "AudioOutputMessageTypes.h"
//#include "AudioResourceMessageTypes.h"

#include "AudioInputCI.h"
#include "AudioOutputCI.h"
#include "G711DecoderIntfcCI.h"
#include "G729DecoderIntfcCI.h"
#include "IlbcDecoderIntfcCI.h"
#include "G711EncoderIntfcCI.h"
#include "G729EncoderIntfcCI.h"
#include "IlbcEncoderIntfcCI.h"
#include "ErrorConcealmentIntfcCI.h"
#include "SpeechEncoderConfigCI.h"

//#include <AudioResourceCIStub.h>
//#include <AudioEqualizerCI.h>
//#include <EnvironmentalReverbCI.h>
//#include <StereoWideningCI.h>
//#include <BassBoostCI.h>
//#include <SourceDopplerBase.h>
//#include <ListenerDopplerBase.h>
//#include <SourceDopplerCI.h>
//#include <ListenerDopplerCI.h>
//#include <ListenerLocationCI.h>
//#include <SourceLocationCI.h>
//#include <ListenerOrientationCI.h>
//#include <SourceOrientationCI.h>
//#include <DistanceAttenuationCI.h>
//#include <LoudnessCI.h>

//#include <AddedDevSoundControlCI.h>
//#include <AddedDevSoundControlCIStub.h>
//#include <RestrictedAudioOutputCI.h>

#include "MmfDevSoundAdaptationBody.h"
#include "MmfHwDeviceStub.h"
#include "TonePlayCompleteTimer.h"


// CONSTANTS
#ifdef _DEBUG
#include "e32debug.h"

#define DEBPRN0(str)                RDebug::Print(str, this)
#define DEBPRN1(str, val1)          RDebug::Print(str, this, val1)
#define DEBPRN2(str, val1, val2)    RDebug::Print(str, this, val1, val2)
#else
#define DEBPRN0(str)
#define DEBPRN1(str, val1)
#define DEBPRN2(str, val1, val2)
#endif //_DEBUG


const TUint KMaxVolume = 10;
const TUint KToneSamplingRate = 8000;
const TUint KToneChannels = 2;
// Time to play one note 1/10th of 1/2 a second
const TUint KToneNotePlayTime = 50000;

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

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::CBody
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CMMFDevSoundAdaptation::CBody::CBody()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CBody"));
    iMode= EMMFStateIdle;
    //Set reasonable default values for DTMF
    iDTMFGen.SetToneDurations(250000,50000,250000);
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::ConstructL
// Symbian 2nd phase constructor can leave.
// assumes that iParent has already been set up properly
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::ConstructL(
    RServer2& /*aPolicyServerHandle*/)
    {
    // Default
    // set the default capability
    iDeviceCapabilities.iRate = EMMFSampleRate8000Hz;
    iDeviceCapabilities.iEncoding = EMMFSoundEncoding16BitPCM;
    iDeviceCapabilities.iChannels = EMMFMono;
    iDeviceCapabilities.iBufferSize = KBufferLength;

    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::ConstructL:EXIT"));
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CMMFDevSoundAdaptation::CBody* CMMFDevSoundAdaptation::CBody::NewL()
    {
    CMMFDevSoundAdaptation::CBody* self = new (ELeave) CBody;
    return self;
    }


// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBodye::~CBody
// Destructor
// -----------------------------------------------------------------------------
//
CMMFDevSoundAdaptation::CBody::~CBody()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::~CBody:ENTER"));
    delete iToneBuffer1;
    delete iToneBuffer2;
    delete iDevSoundUtil;
    delete iFixedSequences;
    delete iCMMFHwDevice;
    delete iTonePlayCompleteTimer;
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::~CBody:EXIT"));
    }


// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::InitializeL
// Initializes CMMFDevSoundProxy object to play and record PCM16 raw audio data
// with sampling rate of 8 KHz.
//
// On completion of Initialization, calls InitializeComplete() on
// aDevSoundObserver.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::InitializeL(
    MDevSoundAdaptationObserver& aDevSoundObserver,
    TMMFState aMode)
    {
    // if no HwDevice id specified, load default null implementation
    TUid rawUid = {0};
    InitializeL(aDevSoundObserver, rawUid, aMode);
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::InitializeL
// Initializes DevSound object for the mode aMode for processing audio data
// with hardware device aHWDev.
//
// On completion of Initialization, the observer will be notified via call back
// InitializeComplete().
//
// Leaves on failure.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::InitializeL(
    MDevSoundAdaptationObserver& aDevSoundObserver,
    TUid aHWDev,
    TMMFState aMode)
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::InitializeL:ENTER"));
    TInt initError = KErrNone;
    iDevSoundObserver = &aDevSoundObserver;

    if (aMode == EMMFStateIdle)
        {
        User::Leave(KErrNotSupported);
        }
    iMode= aMode;


    iDevSoundObserver = &aDevSoundObserver;
    iHwDeviceID.iUid = aHWDev.iUid;
    if(iCMMFHwDevice)
        {
        delete iCMMFHwDevice;
        iHwDeviceBuffer = NULL; // buffer is deleted by HwDevice delete
        }

    iCMMFHwDevice = NULL;
    iCMMFHwDevice = CMMFHwDeviceStub::NewL();

    iDevInfo.iHwDeviceObserver = this;
    initError = iCMMFHwDevice->Init(iDevInfo);

    iDevSoundObserver->InitializeComplete(initError);

    if (initError)
        {
        User::Leave(initError);
        }
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::InitializeL:EXIT"));
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::InitializeL
// Initializes DevSound object for the mode aMode for processing audio data
// with hardware device supporting FourCC aDesiredFourCC.
//
// On completion of Initialization, the observer will be notified via call back
// InitializeComplete().
//
// Leaves on failure.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::InitializeL(
    MDevSoundAdaptationObserver& aDevSoundObserver,
    TFourCC /*aDesiredFourCC*/,
    TMMFState aMode)
    {
    TUid implUid = {0};
    InitializeL(aDevSoundObserver, implUid, aMode);
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::Capabilities
// Returns the supported Audio settings.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TMMFCapabilities CMMFDevSoundAdaptation::CBody::Capabilities()
    {
    return iDeviceCapabilities;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::Config
// Returns the current audio settings.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TMMFCapabilities CMMFDevSoundAdaptation::CBody::Config() const
    {
    return iDeviceConfig;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::SetConfigL
// Configure CMMFDevSoundProxy object for the settings in aConfig.
// Use this to set sampling rate, Encoding and Mono/Stereo.
// As part of defect 20796, the iRecordFormat has been set under the iPlayFormat,
//  before it was not set at all.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::SetConfigL(
    const TMMFCapabilities& aConfig)
    {
    iDeviceConfig = aConfig;

    // Fix to WAV recording problem.
    // A kludge to init channel number to 'something' in case the device returns 0.
    if (!iDeviceConfig.iChannels)
        {
        iDeviceConfig.iChannels = EMMFMono;
        }
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::MaxVolume
// Returns an integer representing the maximum volume.
// This is the maximum value which can be passed to CMMFDevSoundProxy::SetVolume.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::MaxVolume()
    {
    return KMaxVolume;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::Volume
// Returns an integer representing the current volume.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::Volume()
    {
    return iVolume;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::SetVolume
// Changes the current playback volume to a specified value.
// The volume can be changed before or during playback and is effective
// immediately.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::SetVolume(
    TInt aVolume)
    {
    // Check and make sure that the volume is in valid range
    if (aVolume < 0)
        {
        aVolume = 0;
        }
    if (aVolume > MaxVolume())
        {
        aVolume = MaxVolume();
        }
    iVolume = aVolume;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::MaxGain
// Returns an integer representing the maximum gain.
// This is the maximum value which can be passed to CMMFDevSoundProxy::SetGain.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::MaxGain()
    {
    return KMaxVolume;//uses iMaxVolume for iMaxGain
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::Gain
// Returns an integer representing the current gain.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::Gain()
    {
    return iGain;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::SetGain
// Changes the current recording gain to a specified value.
//
// The gain can be changed before or during recording and is effective
// immediately.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::SetGain(TInt aGain)
    {
    // make sure it falls with the correct range
    if (aGain > MaxGain())
        {
        aGain = MaxGain();
        }
    else if (aGain < 0)
        {
        aGain = 0;
        }
    iGain = aGain;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::GetPlayBalanceL
// Returns the speaker balance set for playing.
// Leaves on failure.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::GetPlayBalanceL(
    TInt& aLeftPercentage,
    TInt& aRightPercentage)
    {
    aLeftPercentage = iLeftPlayBalance;
    aRightPercentage = iRightPlayBalance;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::SetPlayBalanceL
// Sets the speaker balance for playing.
// The speaker balance can be changed before or during playback and is
// effective immediately.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::SetPlayBalanceL(
    TInt aLeftPercentage,
    TInt aRightPercentage)
    {
    if (aLeftPercentage < 0)
        {
        aLeftPercentage = 0;
        }
    else if (aLeftPercentage > 100)
        {
        aLeftPercentage = 100;
        }
    if (aRightPercentage < 0)
        {
        aRightPercentage = 0;
        }
    else if (aRightPercentage > 100)
        {
        aRightPercentage = 100;
        }
    iLeftPlayBalance = aLeftPercentage;
    iRightPlayBalance = aRightPercentage;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::GetRecordBalanceL
// Returns the microphone gain balance set for recording.
// Leaves on failure.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::GetRecordBalanceL(
    TInt& aLeftPercentage,
    TInt& aRightPercentage)
    {
    aLeftPercentage = iLeftRecordBalance;
    aRightPercentage = iRightRecordBalance;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::SetRecordBalanceL
// Sets the microphone gain balance for recording.
// The microphone gain balance can be changed before or during recording and
// is effective immediately.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::SetRecordBalanceL(
    TInt aLeftPercentage,
    TInt aRightPercentage)
    {
    if (aLeftPercentage < 0)
        {
        aLeftPercentage = 0;
        }
    else if (aLeftPercentage > 100)
        {
        aLeftPercentage = 100;
        }
    if (aRightPercentage < 0)
        {
        aRightPercentage = 0;
        }
    else if (aRightPercentage > 100)
        {
        aRightPercentage = 100;
        }
    iLeftRecordBalance = aLeftPercentage;
    iRightRecordBalance = aRightPercentage;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::PlayInitL
// Initializes audio device and start play process. This method queries and
// acquires the audio policy before initializing audio device. If there was an
// error during policy initialization, PlayError() method will be called on
// the observer with error code KErrAccessDenied, otherwise BufferToBeFilled()
// method will be called with a buffer reference. After reading data into the
// buffer reference passed, the client should call PlayData() to play data.
//
// The amount of data that can be played is specified in
// CMMFBuffer::RequestSize(). Any data that is read into buffer beyond this
// size will be ignored.
//
// Leaves on failure.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::PlayInitL()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::PlayInitL"));
    if (!iDevSoundObserver)
        {
        User::Leave(KErrNotReady);
        }

    StartPlayDataL();
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::RecordInitL
// Initializes audio device and start record process. This method queries and
// acquires the audio policy before initializing audio device. If there was an
// error during policy initialization, RecordError() method will be called on
// the observer with error code KErrAccessDenied, otherwise BufferToBeEmptied()
// method will be called with a buffer reference. This buffer contains recorded
// or encoded data. After processing data in the buffer reference passed, the
// client should call RecordData() to continue recording process.
//
// The amount of data that is available is specified in
// CMMFBuffer::RequestSize().
//
// Leaves on failure.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::RecordInitL()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::RecordInitL"));
    if (!iDevSoundObserver)
        {
        User::Leave(KErrNotReady);
        }

    StartRecordDataL();
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::PlayData
// Plays data in the buffer at the current volume. The client should fill
// the buffer with audio data before calling this method. The Observer gets
// reference to buffer along with callback BufferToBeFilled(). When playing of
// the audio sample is complete, successfully or otherwise, the method
// PlayError() on observer is called.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::PlayData()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::PlayData"));
    ASSERT(iDevSoundObserver);

    if (iMode== EMMFStateIdle)
        {
        return;
        }

    TInt error = KErrNone;

    if(iCMMFHwDevice)
        {
        if (iPaused)
            {
            iPaused = EFalse;
            //note PlayData does not leave or return an error code so the
            //Start() fails we cannot report the error back at this point
            if (iCMMFHwDevice->IsActive())
                {
                iCMMFHwDevice->Cancel();
                }
            //restart hw device after pause
            error = iCMMFHwDevice->Start(EDevDecode, EDevOutFlow);
            }
       else if(iMode== EMMFStatePlaying)
            {
            TInt len = iHwDeviceBuffer->Data().Length();
            iPlayedBytesCount += len;
            if (iHwDeviceBuffer->LastBuffer())
                {
                iLastBufferReceived = ETrue;
                }

            // Pass the data buffer to HwDevice
            if (iMode== EMMFStatePlaying)
                {
                error = iCMMFHwDevice->ThisHwBufferFilled(*iHwDeviceBuffer);
                }
            }
        }
    if (error != KErrNone)
        {
        iDevSoundObserver->PlayError(error);
        }
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::RecordData
// Contine the process of recording. Once the buffer is filled with recorded
// data, the Observer gets reference to buffer along with callback
// BufferToBeEmptied(). After processing the buffer (copying over to a
// different buffer or writing to file) the client should call this
// method to continue recording process.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::RecordData()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::RecordData"));
    ASSERT(iDevSoundObserver);
    if(iCMMFHwDevice)
        {
        if(iMode == EMMFStateRecording)
            {
            // Fix to WAV recording issue.
            // In case of real DevSound adaptation implementation, the
            // CMMFSwCodecRecordDataPath sets the last buffer parameter when no
            // more data is in the buffer to process. In case of the stub, this
            // never gets set as the s/w codec is not involved - we are simply
            // copying same fixed 4k block of data over and over again. So, on
            // pause or stop we need to indicate to the data path that we no
            // longer need processing of data by manually setting last buffer
            // parameter and resetting requested data size to 0.
            if (iPaused)
                {
                iHwDeviceBuffer->SetLastBuffer(ETrue);
                iHwDeviceBuffer->Data().SetLength(0);
                }
            else
                {
                iHwDeviceBuffer->Data().SetLength(iHwDeviceBuffer->RequestSize());
                }

            iCMMFHwDevice->ThisHwBufferEmptied(*iHwDeviceBuffer);
            }
        }
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::Stop
// Stops the ongoing operation (Play, Record, TonePlay, Convert)
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::Stop()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::Stop"));

    iPaused = EFalse;

    if (iMode== EMMFStateIdle)
        {
        return;
        }

    // For custom interface

     // Stop the hw device first - this unloads sound drivers
    if(iCMMFHwDevice)
        {
        iCMMFHwDevice->Stop();
        }

    if ((iMode== EMMFStateTonePlaying) && (iTonePlayCompleteTimer))
        {
        iTonePlayCompleteTimer->Cancel();
        }

    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::Pause
// Temporarily Stops the ongoing operation (Play, Record, TonePlay, Convert)
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::Pause()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::Pause"));
    iPaused = ETrue;

    if (iMode== EMMFStateIdle)
        {
        return;
        }

    // Pause the HW device first
    if(iCMMFHwDevice)
        {
        iCMMFHwDevice->Pause();
        }
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::SamplesRecorded
// Returns the sample recorded so far.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::SamplesRecorded()
    {
    TInt samples = 0;
    samples = iRecordedBytesCount;
    if(NumberOfChannels() > 1)
        {
        samples /= NumberOfChannels();
        }
    if(BytesPerAudioSample() > 1)
        {
        samples /= BytesPerAudioSample();
        }
    return samples;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::SamplesPlayed
// Returns the sample played so far.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::SamplesPlayed()
    {
    TInt samples = 0;
    samples = iPlayedBytesCount;
    if(NumberOfChannels() > 1)
        {
        samples /= NumberOfChannels();
        }

    if(BytesPerAudioSample() > 1)
        {
        samples /= BytesPerAudioSample();
        }
    return samples; //each sample is 2 bytes
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::PlayToneL
// Initializes audio device and start playing tone. Tone is played with
// frequency and for duration specified.
//
// Leaves on failure.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::PlayToneL(
    TInt aFrequency,
    const TTimeIntervalMicroSeconds& aDuration)
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::PlayToneL"));
    if (iMode!= EMMFStateTonePlaying)
        {
        //tone playing only supported in tone play state
        User::Leave(KErrNotSupported);
        }
    // Check whether frequency and duration is valid or not
    TInt64 zeroInt64(0);
    if ((aFrequency<0) || (aDuration.Int64() < zeroInt64))
        {
        User::Leave(KErrArgument);
        }
    if (!iDevSoundObserver)
        {
        User::Leave(KErrNotReady);
        }
    iToneGen.SetFrequencyAndDuration(aFrequency,aDuration);

    StartPlayToneL();
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::PlayDualToneL
// Initializes audio device and start playing a dual tone.
// The tone consists of two sine waves of different frequencies summed together
// Dual Tone is played with specified frequencies and for specified duration.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::PlayDualToneL(
    TInt aFrequencyOne,
    TInt aFrequencyTwo,
    const TTimeIntervalMicroSeconds& aDuration)
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::PlayDualToneL"));

    // Check whether frequencies and duration are valid or not
    TInt64 zeroInt64(0);
    if ((aFrequencyOne<0) || (aFrequencyTwo<0) ||
        (aDuration.Int64() < zeroInt64))
        {
        User::Leave(KErrArgument);
        }
    if (!iDevSoundObserver)
        {
        User::Leave(KErrNotReady);
        }
    iDualToneGen.SetFrequencyAndDuration(aFrequencyOne,
                                         aFrequencyTwo,
                                         aDuration);
    StartPlayDualToneL();
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::PlayDTMFStringL
// Initializes audio device and start playing DTMF string aDTMFString.
// Leaves on failure.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::PlayDTMFStringL(
    const TDesC& aDTMFString)
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::PlayDTMFStringL"));

    if (!iDevSoundObserver)
        {
        User::Leave(KErrNotReady);
        }
    if (iMode!= EMMFStateTonePlaying)
        {
        //tone playing only supported in tone play state
        User::Leave(KErrNotSupported);
        }
    iDTMFGen.SetString(aDTMFString);
    StartPlayDTMFStringL();
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::PlayToneSequenceL
// Initializes audio device and start playing tone sequence.
//
// Leaves on failure.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::PlayToneSequenceL(const TDesC8& aData)
    {
    DEBPRN1(
    _L("CMMFDevSoundAdaptationStub[0x%x]::CBody::PlayToneSequenceL:Length[%d]"),
    aData.Length());

    if (!iDevSoundObserver)
        {
        User::Leave(KErrNotReady);
        }
    if (iMode!= EMMFStateTonePlaying)
        {
        //tone playing only supported in tone play state
        User::Leave(KErrNotSupported);
        }

    InitializeDevSoundUtilL();
    // Check whether the sequence is valid or not
    if (!iDevSoundUtil->RecognizeSequence(aData))
        {
        User::Leave(KErrCorrupt);
        }

    // For playing Tone sequence, we don't use PCM generator.
    // We use a timer instead
    // iSequenceGen.SetSequenceData(aData);

    if (!iTonePlayCompleteTimer)
        {
        iTonePlayCompleteTimer =
            CTonePlayCompleteTimer::NewL(*iDevSoundObserver);
        }
    // Determine the time out based on iRepeatCount and number of notes
    // in the sequence
    TUint repeats = ((iRepeatCount > 0) ? iRepeatCount : 1);
    TTimeIntervalMicroSeconds32 time(KToneNotePlayTime*aData.Length()*repeats);
    iTonePlayCompleteTimer->SetTimeOut(time);

    StartPlayToneSequenceL();
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::PlayFixedSequenceL
// Initializes audio device and start playing the specified pre-defined tone
// sequence.
//
// Leaves on failure.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::PlayFixedSequenceL(TInt aSequenceNumber)
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::PlayFixedSequenceL"));

    if (!iDevSoundObserver)
        {
        User::Leave(KErrNotReady);
        }
    if (iMode!= EMMFStateTonePlaying)
        {
        //tone playing only supported in tone play state
        User::Leave(KErrNotSupported);
        }
    ASSERT((aSequenceNumber >= 0) &&
           (aSequenceNumber < iFixedSequences->Count()));

    iFixedSequence.Set(iFixedSequences->MdcaPoint(aSequenceNumber));
    iSequenceGen.SetSequenceData(iFixedSequence);

    StartPlayToneSequenceL();
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::SetToneRepeats
// Defines the number of times the audio is to be repeated during the tone
// playback operation. A period of silence can follow each playing of tone.
// The tone playing can be repeated indefinitely.
// Supported only during tone playing.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::SetToneRepeats(
    TInt aRepeatCount,
    const TTimeIntervalMicroSeconds& aRepeatTrailingSilence)
    {
    iRepeatCount = aRepeatCount;
    iRepeatTrailingSilence = aRepeatTrailingSilence;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::SetDTMFLengths
// Defines the duration of tone on, tone off and tone pause to be used during the
// DTMF tone playback operation.
// Supported only during tone playing.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::SetDTMFLengths(
    TTimeIntervalMicroSeconds32& aToneOnLength,
    TTimeIntervalMicroSeconds32& aToneOffLength,
    TTimeIntervalMicroSeconds32& aPauseLength)
    {

    if(aToneOnLength.Int() < KMdaInfiniteDurationDTMFToneOnLength)
        {
        aToneOnLength = TTimeIntervalMicroSeconds32(0);
        }
    if(aToneOffLength.Int() < 0)
        {
        aToneOffLength = TTimeIntervalMicroSeconds32(0);
        }
    if(aPauseLength.Int() < 0)
        {
        aPauseLength = TTimeIntervalMicroSeconds32(0);
        }

    iDTMFGen.SetToneDurations(aToneOnLength,aToneOffLength,aPauseLength);
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::SetVolumeRamp
// Defines the period over which the volume level is to rise smoothly from
// nothing to the normal volume level.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::SetVolumeRamp(
    const TTimeIntervalMicroSeconds& aRampDuration)
    {
    // save ramp duration for tone generator
    iRampDuration = aRampDuration;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::SetPrioritySettings
// Defines the priority settings that should be used for this instance.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::SetPrioritySettings(
    const TMMFPrioritySettings& /*aPrioritySettings*/)
    {
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::CustomInterface
// @see sounddevice.h
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TAny* CMMFDevSoundAdaptation::CBody::CustomInterface(TUid aInterfaceId)
    {
// Note: These can only be uncommented when supported by the
//       MessageHandlerFactory and CustomInterfaceProxyFactory stubs.
//       Will result in memory leak if re-enabled without updating of
//       the proxy and message factory stubs.
//
    DEBPRN1(
    _L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:InterfaceId[0x%x]"),
    aInterfaceId);

    if (aInterfaceId == KUidSpeechEncoderConfig)
        {
        TRAP_IGNORE(iSpeechEncoderConfigCI = CSpeechEncoderConfigCI::NewL());
        DEBPRN0(
        _L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CSpeechEncoderConfigCI..."));
        return iSpeechEncoderConfigCI;
        }
    else if (aInterfaceId == KUidErrorConcealmentIntfc)
        {
        TRAP_IGNORE(iErrorConcealmentIntfcCI = CErrorConcealmentIntfcCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CErrorConcealmentIntfcCI..."));
        return iErrorConcealmentIntfcCI;
        }
    else if (aInterfaceId == KUidG711DecoderIntfc)
        {
        TRAP_IGNORE(iG711DecoderIntfcCI = CG711DecoderIntfcCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CG711DecoderIntfcCI..."));
        return iG711DecoderIntfcCI;
        }
    else if (aInterfaceId == KUidG729DecoderIntfc)
        {
        TRAP_IGNORE(iG729DecoderIntfcCI = CG729DecoderIntfcCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CG729DecoderIntfcCI..."));
        return iG729DecoderIntfcCI;
        }
    else if (aInterfaceId == KUidIlbcDecoderIntfc)
        {
        TRAP_IGNORE(iIlbcDecoderIntfcCI = CIlbcDecoderIntfcCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CIlbcDecoderIntfcCI..."));
        return iIlbcDecoderIntfcCI;
        }
    else if (aInterfaceId == KUidG711EncoderIntfc)
        {
        TRAP_IGNORE(iG711EncoderIntfcCI = CG711EncoderIntfcCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CG711EncoderIntfcCI..."));
        return iG711EncoderIntfcCI;
        }
    else if (aInterfaceId == KUidG729EncoderIntfc)
        {
        TRAP_IGNORE(iG729EncoderIntfcCI = CG729EncoderIntfcCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CG729EncoderIntfcCI..."));
        return iG729EncoderIntfcCI;
        }
    else if (aInterfaceId == KUidIlbcEncoderIntfc)
        {
        TRAP_IGNORE(iIlbcEncoderIntfcCI = CIlbcEncoderIntfcCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CIlbcEncoderIntfcCI..."));
        return iIlbcEncoderIntfcCI;
        }
    else if (aInterfaceId == KUidAudioInput)
        {
        CAudioInputCI* retCI(NULL);
        TRAP_IGNORE(retCI = CAudioInputCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CAudioInputCI..."));
        return retCI;
        }
    else if(aInterfaceId == KUidAudioOutput)
        {
        CAudioOutputCI* retCI(NULL);
        TRAP_IGNORE(retCI = CAudioOutputCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CAudioOutputCI..."));
        return retCI;
        }/*
    else if (aInterfaceId == KUidSbcEncoderIntfc)
        {
        TRAP_IGNORE(iSbcEncoderIntfcCI = CSbcEncoderIntfcCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CSbcEncoderIntfcCI..."));
        return iSbcEncoderIntfcCI;
        }
    else if (aInterfaceId == KUidAudioVibraControl)
        {
        TRAP_IGNORE(iAudioVibraControlCI = CAudioVibraControlCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CAudioVibraControlCI..."));
        return iAudioVibraControlCI;
        }
    else if (aInterfaceId == KUidAudioResource)
        {
        CAudioResourceCIStub* retCI(NULL);
        TRAP_IGNORE(retCI = CAudioResourceCIStub::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CAudioResourceCIStub..."));
        return retCI;
        }
    else if (aInterfaceId == KUidAudioEqualizerEffect)
        {
        CAudioEqualizerCI* retCI(NULL);
        TRAP_IGNORE(retCI = CAudioEqualizerCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CAudioEqualizerCI..."));
        return retCI;
        }
    else if (aInterfaceId == KUidEnvironmentalReverbEffect)
        {
        CEnvironmentalReverbCI* retCI(NULL);
        TRAP_IGNORE(retCI = CEnvironmentalReverbCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CEnvironmentalReverbCI..."));
        return retCI;
        }
    else if (aInterfaceId == KUidStereoWideningEffect)
        {
        CStereoWideningCI* retCI(NULL);
        TRAP_IGNORE(retCI = CStereoWideningCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CStereoWideningCI..."));
        return retCI;
        }
    else if (aInterfaceId == KUidBassBoostEffect)
        {
        CBassBoostCI* retCI(NULL);
        TRAP_IGNORE(retCI = CBassBoostCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CBassBoostCI..."));
        return retCI;
        }
    else if (aInterfaceId == KUidSourceDopplerEffect)
        {
        CSourceDopplerCI* retCI(NULL);
        TRAP_IGNORE(retCI = CSourceDopplerCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CSourceDopplerCI..."));
        return retCI;
        }
    else if (aInterfaceId == KUidListenerDopplerEffect)
        {
        CListenerDopplerCI* retCI(NULL);
        TRAP_IGNORE(retCI = CListenerDopplerCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CListenerDopplerCI..."));
        return retCI;
        }
    else if (aInterfaceId == KUidListenerLocationEffect)
        {
        CListenerLocationCI* retCI(NULL);
        TRAP_IGNORE(retCI = CListenerLocationCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CListenerLocationCI..."));
        return retCI;
        }
    else if (aInterfaceId == KUidSourceLocationEffect)
        {
        CSourceLocationCI* retCI(NULL);
        TRAP_IGNORE(retCI = CSourceLocationCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CSourceLocationCI..."));
        return retCI;
        }
    else if (aInterfaceId == KUidListenerOrientationEffect)
        {
        CListenerOrientationCI* retCI(NULL);
        TRAP_IGNORE(retCI = CListenerOrientationCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CListenerOrientationCI..."));
        return retCI;
        }
    else if (aInterfaceId == KUidSourceOrientationEffect)
        {
        CSourceOrientationCI* retCI(NULL);
        TRAP_IGNORE(retCI = CSourceOrientationCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CSourceOrientationCI..."));
        return retCI;
        }
    else if (aInterfaceId == KUidDistanceAttenuationEffect)
        {
        CDistanceAttenuationCI* retCI(NULL);
        TRAP_IGNORE(retCI = CDistanceAttenuationCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CDistanceAttenuationCI..."));
        return retCI;
        }
    else if (aInterfaceId == KUidLoudnessEffect)
        {
        CLoudnessCI* retCI(NULL);
        TRAP_IGNORE(retCI = CLoudnessCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CLoudnessCI..."));
        return retCI;
        }
    else if (aInterfaceId == KUidAddedDevSoundControlInterface)
        {
        CAddedDevSoundControlCI* retCI(NULL);
        TRAP_IGNORE(retCI = CAddedDevSoundControlCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CAddedDevSoundControlCI..."));
        return (MAddedDevSoundControl*)retCI;
        }
    else if (aInterfaceId == KUidRestrictedAudioOutput)
        {
        CRestrictedAudioOutputCI* retCI(NULL);
        TRAP_IGNORE(retCI = CRestrictedAudioOutputCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CRestrictedAudioOutputCI..."));
        return retCI;
        }
    else if (aInterfaceId == KUidAacDecoderConfig)
        {
        TRAP_IGNORE(iAacDecoderConfigCI = CAacDecoderConfigCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CAacDecoderConfigCI..."));
        return iAacDecoderConfigCI;
        }
    else if (aInterfaceId == KUidEAacPlusDecoderIntfc)
        {
        TRAP_IGNORE(iEAacPlusDecoderConfigCI = CEAacPlusDecoderIntfcCI::NewL());
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning CEAacPlusDecoderIntfcCI..."));
        return iEAacPlusDecoderConfigCI;
        }*/
    else
        {
        DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::CustomInterface:returning NULL..."));
        return NULL;
        }
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::FixedSequenceCount
// Returns the number of available pre-defined tone sequences.
// This is the number of fixed sequence supported by DevSound by default.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::FixedSequenceCount()
    {
    return iFixedSequences->Count();
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::FixedSequenceName
// Returns the name assigned to a specific pre-defined tone sequence.
// This is the number of fixed sequence supported by DevSound by default.
// The function raises a panic if sequence number specified invalid.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
const TDesC& CMMFDevSoundAdaptation::CBody::FixedSequenceName(
    TInt aSequenceNumber)
    {
    ASSERT((aSequenceNumber >= 0) &&
           (aSequenceNumber < iFixedSequences->Count()));

    TRAPD(err, InitializeDevSoundUtilL());
    if (err == KErrNone)
        {
        return iDevSoundUtil->FixedSequenceName(aSequenceNumber);
        }
    else
        {
        return KNullDesC;
        }
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::GetSupportedInputDataTypesL
// @see sounddevice.h
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::GetSupportedInputDataTypesL(
    RArray<TFourCC>& aSupportedDataTypes,
    const TMMFPrioritySettings& /*aPrioritySettings*/) const
    {
    //aPrioritySettings not used on ref DevSound
    //search for playing datatypes
    InitializeDevSoundUtilL();
    iDevSoundUtil->SeekHwDevicePluginsL(aSupportedDataTypes, EMMFStatePlaying);
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::GetSupportedOutputDataTypesL
// @see sounddevice.h
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::GetSupportedOutputDataTypesL(
    RArray<TFourCC>& aSupportedDataTypes,
    const TMMFPrioritySettings& /*aPrioritySettings*/) const
    {
    //aPrioritySettings not used on ref DevSound
    // search for recording datatypes
    InitializeDevSoundUtilL();
    iDevSoundUtil->SeekHwDevicePluginsL(aSupportedDataTypes,
                                        EMMFStateRecording);
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::SetClientConfig
// Sets client capabilities for this instance of DevSound Adaptation.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::SetClientConfig(
    const TMMFClientConfig& aClientConfig)
    {
    iClientConfig = aClientConfig;
    }

// -----------------------------------------------------------------------------
// TMMFClientConfig& CMMFDevSoundAdaptation::CBody::ClientConfig
// Returns client capabilities of this instance of DevSound Adaptation.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
const TMMFClientConfig& CMMFDevSoundAdaptation::CBody::ClientConfig() const
    {
    return iClientConfig;
    }

/********************************************************************************
 *              Implementations of Non Exported public functions begins here    *
 ********************************************************************************/

//////////////////////////////////////////////////////////////////////////////////
//              Audio Policy specific implementation begins here                //
//////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::StartPlayDataL
// Called by Audio Policy Server when a request to play is approved by the
// Audio Policy Server.
//
// Leaves on failure??.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::StartPlayDataL()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::StartPlayDataL"));

    ASSERT(iMode== EMMFStatePlaying);

    TInt error = KErrNone;

    if(iCMMFHwDevice)
        {
        // Initialize attribute values
        iPlayedBytesCount = 0;
        iLastBufferReceived = EFalse;

        // Start HwDevice
        if (iCMMFHwDevice->IsActive())
            {
            iCMMFHwDevice->Cancel();
            }
        error = iCMMFHwDevice->Start(EDevDecode, EDevOutFlow);
        }
    else
        {
        error = KErrNotReady;
        }

    if (error != KErrNone)
        {
        iDevSoundObserver->PlayError(error);
        }
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::StartRecordDataL
// Called by Audio Policy Server when a request to record is approved by the
// Audio Policy Server.
//
// Leaves on failure.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::StartRecordDataL()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::StartRecordDataL"));

    ASSERT(iMode== EMMFStateRecording);

     if(iCMMFHwDevice)
        {
        TInt error = KErrNone;
        // Initialize attribute values
        iRecordedBytesCount = 0;

        if (iCMMFHwDevice->IsActive())
            {
            iCMMFHwDevice->Cancel();
            }
        error = iCMMFHwDevice->Start(EDevEncode, EDevInFlow);

        if (iHwDeviceBuffer)
            {
            iHwDeviceBuffer->SetLastBuffer(EFalse);
            }
        if (error != KErrNone)
            {
            iDevSoundObserver->RecordError(error);
            return;
            }
        }
    else
        {
        iDevSoundObserver->RecordError(KErrNotReady);
        }
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::StartPlayToneL
// Called by Audio Policy Server when a request to play tone is approved by
// the Audio Policy Server.
//
// Leaves on failure.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::StartPlayToneL()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::StartPlayToneL"));

    ASSERT(iMode== EMMFStateTonePlaying);

     if(iCMMFHwDevice)
        {
        // Initialize attribute values
        iPlayedBytesCount = 0;

        // Configure tone generator
        iToneGen.Configure(
            KToneSamplingRate,
            KToneChannels,
            iRepeatCount,
            I64LOW((iRepeatTrailingSilence.Int64()*KToneSamplingRate)/1000000),
            I64LOW((iRampDuration.Int64()*KToneSamplingRate)/1000000)
            );

        iCurrentGenerator = &iToneGen;

        // Start playback
        DoPlayL();

        }
    else
        {
        iDevSoundObserver->ToneFinished(KErrNotReady);
        }
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::StartPlayDualToneL
// Called by Audio Policy Server when a request to play a dual tone is approved
// by the Audio Policy Server.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::StartPlayDualToneL()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::StartPlayDualToneL"));

    ASSERT(iMode== EMMFStateTonePlaying);

     if(iCMMFHwDevice)
        {
        // Initialize attribute values
        iPlayedBytesCount = 0;

        // Configure dual tone generator
        iDualToneGen.Configure(
            KToneSamplingRate,
            KToneChannels,
            iRepeatCount,
            I64LOW((iRepeatTrailingSilence.Int64()
                    *KToneSamplingRate)/KOneMillionMicroSeconds),
            I64LOW((iRampDuration.Int64()
                    *KToneSamplingRate)/KOneMillionMicroSeconds)
            );

        iCurrentGenerator = &iDualToneGen;

        // Start playback
        DoPlayL();
        }
    else
        iDevSoundObserver->ToneFinished(KErrNotReady);
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::StartPlayDTMFStringL
// Called by Audio Policy Server when a request to play DTMF String is approved
// by the Audio Policy Server.
//
// Leaves on failure.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::StartPlayDTMFStringL()
    {
    DEBPRN0(
    _L("CMMFDevSoundAdaptationStub[0x%x]::CBody::StartPlayDTMFStringL"));

    ASSERT(iMode== EMMFStateTonePlaying);

    if(iCMMFHwDevice)
        {
        TInt error = KErrNone;
        // Initialize attribute values
        iPlayedBytesCount = 0;

        iDTMFGen.Configure(
            KToneSamplingRate,
            KToneChannels,
            iRepeatCount,
            I64LOW((iRepeatTrailingSilence.Int64()*KToneSamplingRate)/1000000),
            I64LOW((iRampDuration.Int64()*KToneSamplingRate)/1000000)
            );

        iCurrentGenerator = &iDTMFGen;

        // Start playback
        //need to trap this as we can leave with KErrUnderflow
        //if there was no data to play - the error has already
        //been sent to the observer and we don't want to call RunError
        TRAP(error,DoPlayL());
        if ((error != KErrUnderflow)&&(error != KErrNone))
            {
            User::Leave(error);
            }
        }
    else
        {
        iDevSoundObserver->ToneFinished(KErrNotReady);
        }
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::StartPlayToneSequenceL
// Called by Audio Policy Server when a request to play tone sequence is
// approved by the Audio Policy Server.
//
// Leaves on failure.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::StartPlayToneSequenceL()
    {
    DEBPRN0(
    _L("CMMFDevSoundAdaptationStub[0x%x]::CBody::StartPlayToneSequenceL"));

    ASSERT(iMode == EMMFStateTonePlaying);

    // For playing Tone sequence, we don't use PCM generator.
    // We use a timer instead
/*
    if(iCMMFHwDevice)
        {
        // Initialize attribute values
        iPlayedBytesCount = 0;

        iSequenceGen.Configure(
            KToneSamplingRate,
            KToneChannels,
            iRepeatCount,
            I64LOW((iRepeatTrailingSilence.Int64()*KToneSamplingRate)/1000000),
            I64LOW((iRampDuration.Int64()*KToneSamplingRate)/1000000)
            );

        iCurrentGenerator = &iSequenceGen;

        // Start playback
        DoPlayL();
        }
    else
        iDevSoundObserver->ToneFinished(KErrNotReady);
*/
    if (iTonePlayCompleteTimer->IsActive())
        {
        iTonePlayCompleteTimer->Cancel();
        }
    iTonePlayCompleteTimer->Start();
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::FillThisHwBuffer
// MMMFHwDeviceObserver mixin implementation.
// The CMMFHwDevice implementation object calls this method during decoding
// (playing), when it needs the encoded data in the buffer
// aHwDataBuffer.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::FillThisHwBuffer(
    CMMFBuffer& aHwDataBuffer)
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::FillThisHwBuffer"));

    TInt err = KErrNone;
    // Keep a reference to this Hw data Buffer. We need to send the
    // reference back to HwDevice implementation
    iHwDeviceBuffer = static_cast<CMMFDataBuffer*> (&aHwDataBuffer);
    // Set the request length, From HwDevice this comes with buffer
    // length.
    TInt len = iHwDeviceBuffer->Data().MaxLength();
    // Ignore error. since buffer size = Buffer Length
    TRAP(err, iHwDeviceBuffer->SetRequestSizeL(len));

    if (iMode== EMMFStatePlaying) // Get Data from Observer
        {
        if (iLastBufferReceived)
            {
            iHwDeviceBuffer->Data().SetLength(0);
            // Pass the buffer to the he device
            err = iCMMFHwDevice->ThisHwBufferFilled(*iHwDeviceBuffer);
            }
        else
            {
            // Pass the buffer to the observer
            iDevSoundObserver->BufferToBeFilled(&aHwDataBuffer);
            }
        }
    else if (iMode== EMMFStateTonePlaying)
        {
        // Hw device will call this method right after its Start was called.
        // When it calls this for the first time it hasn't played one single
        // buffer yet so check that.
        // In this case there's no need to set the active buffer as it's already
        // waiting to be played.
        if (!iFirstCallFromHwDevice)
            {
            SetActiveToneBuffer();
            }

        // If there is no data in the active buffer, tone play is finished.
        // DevSound just have to wait for completion event from audio device.
        if (iActiveToneBuffer->Data().Length() > 0)
            {
            len = iActiveToneBuffer->Data().Length();
            // Copy data from tone buffer to hw device buffer
            Mem::Copy((TAny*)(iHwDeviceBuffer->Data().Ptr()),
                      (TAny*)(iActiveToneBuffer->Data().Ptr()),
                      len);

            iHwDeviceBuffer->Data().SetLength(len);
            if (len < iHwDeviceBuffer->RequestSize())
                {
                iHwDeviceBuffer->SetLastBuffer(ETrue);
                }
            // Play data and try to generate next data block
            err = iCMMFHwDevice->ThisHwBufferFilled(*iHwDeviceBuffer);
            if (err != KErrNone)
                {
                return err;
                }

            // Check again whether this is the first call from Hw device.
            // FillFreeToneBuffer assumes the iActiveToneBuffer has already
            // been played.
            if (!iFirstCallFromHwDevice)
                {
                err = FillFreeToneBuffer();
                }
            else
                {
                iFirstCallFromHwDevice = EFalse;  // Reset flag
                }
            }
        else if (iFirstCallFromHwDevice)
            {
            //we have no data in the tone buffer and thus have no
            //outstanding requests to play
            err = KErrUnderflow; //simulate underrun
            iHwDeviceBuffer->SetLastBuffer(ETrue);
            // Play data and try to generate next data block
            err = iCMMFHwDevice->ThisHwBufferFilled(*iHwDeviceBuffer);
            if (err != KErrNone)
                {
                return err;
                }
            }

        // If there was an error filling the buffer could be corrupt data
        // notify the client and stop playing.Set err to KErrNone.
        if (err != KErrNone)
            {
            Error(err);//Updates Bytes played informs client
            err = KErrNone;
            iCMMFHwDevice->Stop();//unloads sound device
            Stopped();//Updates policy
            }
        }
    else
        {
        err = KErrGeneral;
        iDevSoundObserver->PlayError(KErrGeneral);
        }
    return err;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::EmptyThisHwBuffer
// MMMFHwDeviceObserver mixin implementation.
// The CMMFHwDevice implementation object calls this method during encoding
// (recording), when it fills the buffer aHwDataBuffer with
// encoded data.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::EmptyThisHwBuffer(
    CMMFBuffer& aHwDataBuffer)
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::EmptyThisHwBuffer"));

    TInt err = KErrNone;
    if(iMode== EMMFStateRecording)
        {
        // Keep a reference to this Hw data Buffer. We need to send the
        // reference back to HwDevice implementation
        iHwDeviceBuffer = static_cast<CMMFDataBuffer*>(&aHwDataBuffer);

        // Set the request length, From HwDevice this comes with buffer
        // length. MMF will use RequestSize attribute of the buffer.
        // We can avoid this by setting in HwDevice implemenation
        TInt len = iHwDeviceBuffer->Data().Length();
        iRecordedBytesCount += len;
        TRAP(err, iHwDeviceBuffer->SetRequestSizeL(len));

        // if we're pausing (i.e. flushing) set the last buffer flag
        // when we get an empty buffer from the logical driver
        if(iPaused  && iHwDeviceBuffer->Data().Length() == 0)
            {
            iPaused = EFalse;
            iHwDeviceBuffer->SetLastBuffer(ETrue);
            }

        // Send Data from Observer
        iDevSoundObserver->BufferToBeEmptied(iHwDeviceBuffer);
        }
    else
        {
        err = KErrGeneral;
        iDevSoundObserver->RecordError(KErrGeneral);
        }

    return err;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::MsgFromHwDevice
// MMMFHwDeviceObserver mixin implementation.
// The CMMFHwDevice implementation object calls this method when a message from
// the hardware device implementation is received.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::MsgFromHwDevice(
    TUid /*aMessageType*/,
    const TDesC8& /*aMsg*/)
    {
    return KErrNotSupported;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::Stopped
// MMMFHwDeviceObserver mixin implementation.
//
// The CMMFHwDevice implementation object calls this method when the current
// encode or decode task is finished or stopped.  The policy state is updated
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::Stopped()
    {
    //for swcodec wrap hw devices bytes played updated in MsgFromHwDevice
    //but non Swcodec wrappers hw devices may do it differently also don't
    //know if non Swcodec wrap hw device will call Stopped or Error first
    iLastBufferReceived = EFalse;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::Error
// MMMFHwDeviceObserver mixin implementation
//  Processes error from hw device
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::Error(
    TInt aError)
    {
    DEBPRN1(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::Error(%d)"), aError);

    if (iMode== EMMFStatePlaying)
        {
        iDevSoundObserver->PlayError(aError);
        }
    else if (iMode== EMMFStateRecording)
        {
        iDevSoundObserver->RecordError(aError);
        }
    else if (iMode== EMMFStateTonePlaying)
        {
        if (aError == KErrUnderflow)
            {
            iDevSoundObserver->ToneFinished(KErrNone);
            }
        else
            {
            iDevSoundObserver->ToneFinished(aError);
            }
        }
    //else can't handle error
    }

/********************************************************************************
 *              Non Exported public functions ends here                         *
 ********************************************************************************/


/********************************************************************************
 *              Private functions begins here                                   *
 ********************************************************************************/

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::DoPlayL
// Creates buffer and begin playback using the specified tone generator.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::DoPlayL()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::DoPlayL"));

    // Delete any buffer from previous call and try to create maximum buffer
    // size. Double Buffer the Tone data.
    if (iToneBuffer1)
        {
        delete iToneBuffer1;
        iToneBuffer1 = NULL;
        }

    iToneBuffer1 = CMMFDataBuffer::NewL(KDevSoundDefaultFrameSize);
    User::LeaveIfError(iCurrentGenerator->FillBuffer(iToneBuffer1->Data()));

    if (iToneBuffer2)
        {
        delete iToneBuffer2;
        iToneBuffer2 = NULL;
        }
    iToneBuffer2 = CMMFDataBuffer::NewL(KDevSoundDefaultFrameSize);
    User::LeaveIfError(iCurrentGenerator->FillBuffer(iToneBuffer2->Data()));

    // Assign active buffer
    iActiveToneBuffer = iToneBuffer1;

    // Hw device hasn't played anything yet so don't change
    // active buffer. This is checked in FillThisHwBuffer.
    iFirstCallFromHwDevice = ETrue;

    // Start HwDevice to play data
    if (iCMMFHwDevice->IsActive())
        {
        iCMMFHwDevice->Cancel();
        }
    User::LeaveIfError(iCMMFHwDevice->Start(EDevDecode, EDevOutFlow));
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::SetActiveToneBuffer
// This method assigns the other buffer as active buffer. The tone audio
//  generator should fill data in the other buffer by now.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::SetActiveToneBuffer()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::SetActiveToneBuffer"));

    if (iActiveToneBuffer == iToneBuffer1)
        {
        iActiveToneBuffer = iToneBuffer2;
        }
    else if (iActiveToneBuffer == iToneBuffer2)
        {
        iActiveToneBuffer = iToneBuffer1;
        }
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::FillFreeToneBuffer
// This method fills data into the free buffer.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::FillFreeToneBuffer()
    {
    DEBPRN0(_L("CMMFDevSoundAdaptationStub[0x%x]::CBody::FillFreeToneBuffer"));

    TInt err(KErrNone);
    if (iActiveToneBuffer == iToneBuffer1)
        {
        err = iCurrentGenerator->FillBuffer(iToneBuffer2->Data());
        }
    else if (iActiveToneBuffer == iToneBuffer2)
        {
        err = iCurrentGenerator->FillBuffer(iToneBuffer1->Data());
        }
    return err;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::InitTask
// Initializes audio device node by setting volume, and sampling rate.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::InitTask()
    {
    // No Implementation
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::SamplingFrequency
// Returns an integer representing Sampling Frequency the device is currently
//  configured to.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::SamplingFrequency()
    {
    if(iDeviceConfig.iRate == EMMFSampleRate8000Hz)
        {
        return 8000;
        }
    else if(iDeviceConfig.iRate == EMMFSampleRate11025Hz)
        {
        return 11025;
        }
    else if(iDeviceConfig.iRate == EMMFSampleRate12000Hz)
        {
        return 12000;
        }
    else if(iDeviceConfig.iRate == EMMFSampleRate16000Hz)
        {
        return 16000;
        }
    else if(iDeviceConfig.iRate == EMMFSampleRate22050Hz)
        {
        return 22050;
        }
    else if(iDeviceConfig.iRate == EMMFSampleRate24000Hz)
        {
        return 24000;
        }
    else if(iDeviceConfig.iRate == EMMFSampleRate32000Hz)
        {
        return 32000;
        }
    else if(iDeviceConfig.iRate == EMMFSampleRate44100Hz)
        {
        return 44100;
        }
    else if(iDeviceConfig.iRate == EMMFSampleRate48000Hz)
        {
        return 48000;
        }
    else if(iDeviceConfig.iRate == EMMFSampleRate88200Hz)
        {
        return 88200;
        }
    else if(iDeviceConfig.iRate == EMMFSampleRate96000Hz)
        {
        return 96000;
        }
    else
        {
        return 8000; //default
        }
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::NumberOfChannels
// Returns an integer representing number of channels the device is currently
//  configured to.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::NumberOfChannels()
    {
    if(iDeviceConfig.iChannels == EMMFMono)
        {
        return 1;
        }
    else
        {
        return 2;
        }
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::BytesPerAudioSample
// Returns an integer representing number of bytes in each audio sample
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMMFDevSoundAdaptation::CBody::BytesPerAudioSample()
    {
    TInt bytes=1;
    switch (iDeviceConfig.iEncoding)
        {
        case EMMFSoundEncoding8BitPCM:
        case EMMFSoundEncoding8BitALaw:
        case EMMFSoundEncoding8BitMuLaw:
            {
            bytes=1;
            }
        break;
        case EMMFSoundEncoding16BitPCM:
            {
            bytes=2;
            }
        break;
        }
    return bytes;
    }

// -----------------------------------------------------------------------------
// CMMFDevSoundAdaptation::CBody::InitializeDevSoundUtilL
// Initializes DevSoundUtil object.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CMMFDevSoundAdaptation::CBody::InitializeDevSoundUtilL() const
    {
    if (!iDevSoundUtil)
        {
        DEBPRN0(
        _L("CMMFDevSoundAdaptationStub[0x%x]::CBody::InitializeDevSoundUtilL:ENTER"));

        iDevSoundUtil = CMMFDevSoundUtility::NewL();

        // Initialize Fixed sequence related
        DEBPRN0(
        _L("CMMFDevSoundAdaptationStub[0x%x]::CBody::InitializeDevSoundUtilL"));
        iDevSoundUtil->InitializeFixedSequenceL(&iFixedSequences);

        DEBPRN0(
        _L("CMMFDevSoundAdaptationStub[0x%x]::CBody::InitializeDevSoundUtilL"));
        }

    }

//End of File