--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devsound/sounddevbt/PlatSec/src/Server/AudioServer/MmfBtDevSoundSessionBody.cpp Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,1958 @@
+// Copyright (c) 2001-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:
+//
+
+#include <e32base.h>
+#include "MmfBtDevSoundSessionBody.h"
+#include "MmfBtDevSoundSessionXtnd.h"
+
+#include <mdaaudiotoneplayer.h>
+#include <mmf/server/mmfdatabuffer.h>
+#include <mmffourcc.h>
+#include <mmfbthwdeviceimplementationuids.hrh>
+#include <mmfbtswcodecwrappercustominterfacesuids.hrh> // KUidBtRefDevSoundTaskConfig
+
+
+/*
+ * AO to handle RSD initialisation
+ *
+ */
+CRoutingSoundDeviceHandler* CRoutingSoundDeviceHandler::NewL(MDevSoundObserver* aObserver)
+ {
+ CRoutingSoundDeviceHandler* self = new(ELeave) CRoutingSoundDeviceHandler(aObserver);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CRoutingSoundDeviceHandler::~CRoutingSoundDeviceHandler()
+ {
+ Cancel();
+ }
+
+void CRoutingSoundDeviceHandler::RunL()
+ {
+ TInt err = iStatus.Int();
+ if (iObserver)
+ {
+ iObserver->InitializeComplete(err);
+ }
+ }
+
+void CRoutingSoundDeviceHandler::DoCancel()
+ {
+ if (iObserver)
+ {
+ iObserver->InitializeComplete(KErrCancel);
+ }
+ }
+
+CRoutingSoundDeviceHandler::CRoutingSoundDeviceHandler(MDevSoundObserver* aObserver) :
+ CActive(EPriorityStandard),
+ iObserver(aObserver)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void CRoutingSoundDeviceHandler::ConstructL()
+ {
+ }
+
+void CRoutingSoundDeviceHandler::Start()
+ {
+ if (!IsActive())
+ {
+ SetActive();
+ }
+ }
+
+/*
+ *
+ * Default Constructor.
+ *
+ * No default implementation. CMMFDevSoundProxy implements 2-phase construction.
+ *
+ */
+CMMFDevSoundSvrImp::CMMFDevSoundSvrImp(CMMFDevSoundSessionXtnd* aParent)
+: iParent(*aParent)
+ {
+ iMode= EMMFStateIdle;
+ //Set reasonable default values for DTMF
+ iDTMFGen.SetToneDurations(250000,50000,250000);
+ }
+
+/*
+ *
+ * Destructor.
+ *
+ * Deletes all objects and releases all resource owned by this
+ * instance.
+ *
+ */
+CMMFDevSoundSvrImp::~CMMFDevSoundSvrImp()
+ {
+ delete iRSDHandler;
+ delete iToneBuffer1;
+ delete iToneBuffer2;
+ delete iDevSoundEventHandler;
+ if( iAudioPolicyProxy != NULL)
+ {
+ iAudioPolicyProxy->Close();
+ delete iAudioPolicyProxy;
+ }
+ delete iDevSoundUtil;
+ delete iFixedSequences;
+ delete iCMMFHwDevice;
+ }
+
+/*
+ *
+ * Constructs, and returns a pointer to, a new CMMFDevSoundSvrImp object.
+ *
+ * Leaves on failure.
+ *
+ */
+CMMFDevSoundSvrImp* CMMFDevSoundSvrImp::NewL(CMMFDevSoundSessionXtnd* aParent)
+ {
+ CMMFDevSoundSvrImp* self = new (ELeave) CMMFDevSoundSvrImp(aParent);
+ return self;
+ }
+
+/*
+ *
+ * 3rd phase constructor - assumes that iParent has already been set up properly
+ * (During ConstructL() it has yet to be
+ *
+ */
+void CMMFDevSoundSvrImp::Construct3L(RServer2& aPolicyServerHandle)
+ {
+ // all these data properties should be NULL, but add ASSERTs to verity
+ ASSERT(iAudioPolicyProxy==NULL);
+ iAudioPolicyProxy = new (ELeave) RMMFAudioPolicyProxy();
+ ASSERT(iDevSoundEventHandler==NULL);
+ iDevSoundEventHandler = CMMFDevSoundEventHandler::NewL(iAudioPolicyProxy);
+ User::LeaveIfError(iAudioPolicyProxy->Open(aPolicyServerHandle));
+ iDevSoundEventHandler->SetDevSoundInfo(&iParent);
+
+ iDevSoundUtil = CMMFDevSoundUtility::NewL();
+ // Initialize Fixed sequence related
+ iDevSoundUtil->InitializeFixedSequenceL(&iFixedSequences);
+
+ // Add RSD handler construction here.
+ iRSDHandler = CRoutingSoundDeviceHandler::NewL(&iParent);
+
+ PreInitializeL();
+ }
+
+/**
+ * internal procedure to perform all initialization prior to setting the
+ * data type 4CC code
+ */
+void CMMFDevSoundSvrImp::PreInitializeL()
+ {
+ // Set default values for priority settings: Note: Client must
+ // over ride default settings by calling SetPrioirtySettings
+ iAudioPolicyPrioritySettings.iState = EMMFStateStopped;
+ iAudioPolicyPrioritySettings.iPref = EMdaPriorityPreferenceNone;
+ iAudioPolicyPrioritySettings.iPriority = 0;
+
+ // Get device capabilities and current settings from Audio Policy:
+ iAudioPolicyProxy->GetPlayFormatsSupported(iPlayFormatsSupported);
+ iAudioPolicyProxy->GetPlayFormat(iPlayFormat);
+ iAudioPolicyProxy->GetRecordFormatsSupported(iRecordFormatsSupported);
+ iAudioPolicyProxy->GetRecordFormat(iRecordFormat);
+
+ //default to play until we know we are recording
+ User::LeaveIfError(InitializeFormat(iPlayFormatsSupported, iPlayFormat));
+ }
+
+/*
+ *
+ * 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.
+ *
+ * Leaves on failure.
+ *
+ * @param "MDevSoundObserver& aDevSoundObserver"
+ * A reference to DevSound Observer instance.
+ *
+ * @param "TMMFState aMode"
+ * Mode for which this object will be used.
+ *
+ */
+void CMMFDevSoundSvrImp::InitializeL(MDevSoundObserver& aDevSoundObserver, TMMFState aMode)
+
+ {
+ // if no HwDevice id specified, load default null implementation
+ TUid rawUid = {KMmfUidBtHwDevicePCM16ToPCM16};
+ InitializeL(aDevSoundObserver, rawUid, aMode);
+ }
+
+/*
+ *
+ * Configure CMMFDevSoundProxy object for the settings in aConfig.
+ *
+ * Use this to set sampling rate, Encoding and Mono/Stereo.
+ *
+ * @param "TMMFCapabilities& aConfig"
+ * Attribute values to which CMMFDevSoundProxy object will be configured to.
+ *
+ * As part of defect 20796, the iRecordFormat has been set under the iPlayFormat,
+ * before it was not set at all.
+ *
+ */
+void CMMFDevSoundSvrImp::SetConfigL(const TMMFCapabilities& aConfig)
+ {
+ TUint attributeValue = aConfig.iRate;
+ // WINS supports from 8000 Hz to 96000 Hz
+ if (attributeValue & EMMFSampleRate96000Hz)
+ {
+ iPlayFormat().iRate = 96000;
+ iRecordFormat().iRate = 96000;
+ iDeviceConfig.iRate = EMMFSampleRate96000Hz;
+ }
+ else if (attributeValue & EMMFSampleRate88200Hz)
+ {
+ iPlayFormat().iRate = 88200;
+ iRecordFormat().iRate = 88200;
+ iDeviceConfig.iRate = EMMFSampleRate88200Hz;
+ }
+ else if (attributeValue & EMMFSampleRate64000Hz)
+ {
+ iPlayFormat().iRate = 64000;
+ iRecordFormat().iRate = 64000;
+ iDeviceConfig.iRate = EMMFSampleRate64000Hz;
+ }
+ else if (attributeValue & EMMFSampleRate48000Hz)
+ {
+ iPlayFormat().iRate = 48000;
+ iRecordFormat().iRate = 48000;
+ iDeviceConfig.iRate = EMMFSampleRate48000Hz;
+ }
+ else if (attributeValue & EMMFSampleRate44100Hz)
+ {
+ iPlayFormat().iRate = 44100;
+ iRecordFormat().iRate = 44100;
+ iDeviceConfig.iRate = EMMFSampleRate44100Hz;
+ }
+ else if (attributeValue & EMMFSampleRate32000Hz)
+ {
+ iPlayFormat().iRate = 32000;
+ iRecordFormat().iRate = 32000;
+ iDeviceConfig.iRate = EMMFSampleRate32000Hz;
+ }
+ else if (attributeValue & EMMFSampleRate24000Hz)
+ {
+ iPlayFormat().iRate =
+ iRecordFormat().iRate = 24000;
+ iDeviceConfig.iRate = EMMFSampleRate24000Hz;
+ }
+ else if (attributeValue & EMMFSampleRate22050Hz)
+ {
+ iPlayFormat().iRate = 22050;
+ iRecordFormat().iRate = 22050;
+ iDeviceConfig.iRate = EMMFSampleRate22050Hz;
+ }
+ else if (attributeValue & EMMFSampleRate16000Hz)
+ {
+ iPlayFormat().iRate = 16000;
+ iRecordFormat().iRate = 16000;
+ iDeviceConfig.iRate = EMMFSampleRate16000Hz;
+ }
+ else if (attributeValue & EMMFSampleRate12000Hz)
+ {
+ iPlayFormat().iRate =
+ iRecordFormat().iRate = 12000;
+ iDeviceConfig.iRate = EMMFSampleRate12000Hz;
+ }
+ else if (attributeValue & EMMFSampleRate11025Hz)
+ {
+ iPlayFormat().iRate = 11025;
+ iRecordFormat().iRate = 11025;
+ iDeviceConfig.iRate = EMMFSampleRate11025Hz;
+ }
+ else if (attributeValue & EMMFSampleRate8000Hz)
+ {
+ iPlayFormat().iRate = 8000;
+ iRecordFormat().iRate = 8000;
+ iDeviceConfig.iRate = EMMFSampleRate8000Hz;
+ }
+ else if (attributeValue)
+ { //if no attribute value assume its not set
+ User::Leave(KErrNotSupported);
+ }
+
+ attributeValue = aConfig.iEncoding;
+ // Map from MMF Encoding enums to RMdaDevSound enum
+ if(attributeValue & EMMFSoundEncoding8BitPCM)
+ {
+ iPlayFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitPCM;
+ iRecordFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitPCM;
+ iDeviceConfig.iEncoding = EMMFSoundEncoding8BitPCM;
+ }
+ else if(attributeValue & EMMFSoundEncoding8BitALaw)
+ {
+ iPlayFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitALaw;
+ iRecordFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitALaw;
+ iDeviceConfig.iEncoding = EMMFSoundEncoding8BitALaw;
+ }
+ else if(attributeValue & EMMFSoundEncoding8BitMuLaw)
+ {
+ iPlayFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitMuLaw;
+ iRecordFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitMuLaw;
+ iDeviceConfig.iEncoding = EMMFSoundEncoding8BitMuLaw;
+ }
+ else if(attributeValue & EMMFSoundEncoding16BitPCM)
+ {
+ iPlayFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM;
+ iRecordFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM;
+ iDeviceConfig.iEncoding = EMMFSoundEncoding16BitPCM;
+ }
+ else if (attributeValue)
+ { //if no attribute value assume its not set
+ User::Leave(KErrNotSupported);
+ }
+
+ // Mono/Stereo settings
+ attributeValue = aConfig.iChannels;
+ if(attributeValue & EMMFStereo)
+ {
+ iPlayFormat().iChannels = 2;
+ iRecordFormat().iChannels = 2;
+ iDeviceConfig.iChannels = EMMFStereo;
+ }
+ else if(attributeValue & EMMFMono)
+ {
+ iPlayFormat().iChannels = 1;
+ iRecordFormat().iChannels = 1;
+ iDeviceConfig.iChannels = EMMFMono;
+ }
+ else if (attributeValue)
+ { //if no attribute value assume its not set
+ User::Leave(KErrNotSupported);
+ }
+ }
+
+/*
+ *
+ * Changes the current playback volume to a specified value.
+ *
+ * The volume can be changed before or during playback and is effective
+ * immediately.
+ *
+ * @param "TInt aVolume"
+ * The volume setting. This can be any value from zero to the value
+ * returned by a call to CMdaAudioPlayerUtility::MaxVolume(). If the
+ * volume is not within this range, the volume is automatically set to
+ * minimum or maximum value based on the value that is being passed.
+ * Setting a zero value mutes the sound. Setting the maximum value
+ * results in the loudest possible sound.
+ *
+ */
+void CMMFDevSoundSvrImp::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;
+
+ SetDeviceVolume(iVolume);
+ }
+
+/*
+ *
+ * Changes the current recording gain to a specified value.
+ *
+ * The gain can be changed before or during recording and is effective
+ * immediately.
+ *
+ * @param "TInt aGain"
+ * The volume setting. This can be any value from zero to the value
+ * returned by a call to CMdaAudioPlayerUtility::MaxVolume(). If the
+ * volume is not within this range, the gain is automatically set to
+ * minimum or maximum value based on the value that is being passed.
+ * Setting a zero value mutes the sound. Setting the maximum value
+ * results in the loudest possible sound.
+ *
+ */
+void CMMFDevSoundSvrImp::SetGain(TInt aGain)
+ {
+ // make sure it falls with the correct range
+ TInt maxGain = iRecordFormatsSupported().iMaxVolume;
+ if (aGain > maxGain)
+ aGain = maxGain;
+ else if (aGain < 0)
+ aGain = 0;
+ iGain = aGain;
+ SetDeviceRecordLevel(iGain);
+ }
+
+/*
+ *
+ * Sets the speaker balance for playing.
+ *
+ * The speaker balance can be changed before or during playback and is
+ * effective immediately.
+ *
+ * @param "TInt& aLeftPercentage"
+ * On return contains left speaker volume perecentage. This can be any
+ * value from zero to 100. Setting a zero value mutes the sound on left
+ * speaker.
+ *
+ * @param "TInt& aRightPercentage"
+ * On return contains right speaker volume perecentage. This can be any
+ * value from zero to 100. Setting a zero value mutes the sound on
+ * right speaker.
+ *
+ */
+void CMMFDevSoundSvrImp::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;
+ }
+
+/*
+ *
+ * Sets the microphone gain balance for recording.
+ *
+ * The microphone gain balance can be changed before or during recording and
+ * is effective immediately.
+ *
+ * @param "TInt aLeftPercentage"
+ * Left microphone gain precentage. This can be any value from zero to
+ * 100. Setting a zero value mutes the gain on left microphone.
+ *
+ * @param "TInt aRightPercentage"
+ * Right microphone gain precentage. This can be any value from zero to
+ * 100. Setting a zero value mutes the gain on right microphone.
+ *
+ */
+void CMMFDevSoundSvrImp::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;
+ }
+
+/*
+ *
+ * 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.
+ *
+ */
+void CMMFDevSoundSvrImp::PlayInitL()
+ {
+ if (!iDevSoundObserver)
+ User::Leave(KErrNotReady);
+
+ // Get audio policy
+ iAudioPolicyPrioritySettings.iState = EMMFStatePlayData;
+ RequestPolicy();
+ }
+
+/*
+ *
+ * Initializes audio device and start record process.
+ * This method:
+ * 1. 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.
+ *
+ * 2. Checks if the requesting client process has a UserEnvironment capability.
+ * If it does not, the audio device will not be initialized and an error
+ * code KErrAccessDenied will be sent to the client.
+ *
+ * The amount of data that is available is specified in
+ * CMMFBuffer::RequestSize().
+ *
+ * Leaves on failure.
+ *
+ */
+void CMMFDevSoundSvrImp::RecordInitL(const RMmfIpcMessage& aMessage)
+ {
+ if (!iDevSoundObserver)
+ User::Leave(KErrNotReady);
+
+ // Checkes if the client has the UserEnvironment capability
+ if (!aMessage.HasCapability(ECapabilityUserEnvironment))
+ {
+ User::Leave(KErrPermissionDenied);
+ }
+
+ // Get audio policy
+ iAudioPolicyPrioritySettings.iState = EMMFStateRecordData;
+ RequestPolicy();
+ }
+
+/*
+ *
+ * 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.
+ *
+ */
+void CMMFDevSoundSvrImp::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
+ error = iCMMFHwDevice->Start(EDevDecode, EDevOutFlow);//restart hw device after pause
+ }
+ else if(iMode== EMMFStatePlaying)
+ {
+ TInt len = iHwDeviceBuffer->Data().Length();
+ iPlayedBytesCount += len;
+ if (iHwDeviceBuffer->LastBuffer())
+ iLastBufferReceived = ETrue;
+
+
+ if (iMode== EMMFStatePlaying)
+ // Pass the data buffer to HwDevice
+ error = iCMMFHwDevice->ThisHwBufferFilled(*iHwDeviceBuffer);
+ }
+ }
+ if (error != KErrNone)
+ iDevSoundObserver->PlayError(error);
+ }
+
+/*
+ *
+ * Stops the ongoing operation (Play, Record, TonePlay, Convert)
+ *
+ */
+void CMMFDevSoundSvrImp::Stop()
+ {
+ iPaused = EFalse;
+
+ if (iMode== EMMFStateIdle)
+ return;
+
+ // Stop the hw device first - this unloads sound drivers
+ if(iCMMFHwDevice)
+ iCMMFHwDevice->Stop();
+
+ iDevSoundEventHandler->CancelReceiveEvents();
+
+ iAudioPolicyPrioritySettings.iState = EMMFStateStopped;
+ UpdatePolicyState();
+ }
+
+/*
+ *
+ * Temporarily Stops the ongoing operation (Play, Record, TonePlay, Convert)
+ *
+ */
+void CMMFDevSoundSvrImp::Pause()
+ {
+ iPaused = ETrue;
+
+ if (iMode== EMMFStateIdle)
+ return;
+
+ // Pause the HW device first
+ if(iCMMFHwDevice)
+ iCMMFHwDevice->Pause();
+
+ // defer policy update until buffers have been flushed
+ if ((iMode == EMMFStatePlaying) || (iMode == EMMFStateTonePlaying))
+ {
+ iDevSoundEventHandler->CancelReceiveEvents();
+
+ iAudioPolicyPrioritySettings.iState = EMMFStatePaused;
+ UpdatePolicyState();
+ }
+ }
+
+/*
+ *
+ * Returns the sample recorded so far.
+ *
+ * @return "TInt"
+ * Returns the samples recorded.
+ *
+ */
+TInt CMMFDevSoundSvrImp::SamplesRecorded()
+ {
+ TInt samples = 0;
+
+ if(iRecordCustomInterface)
+ {
+ samples = iRecordCustomInterface->BytesRecorded();
+ if(NumberOfChannels() > 1)
+ {
+ samples /= NumberOfChannels();
+ }
+ if(BytesPerAudioSample() > 1)
+ {
+ samples /= BytesPerAudioSample();
+ }
+ }
+
+ return samples;
+ }
+
+/*
+ *
+ * Returns the sample played so far.
+ *
+ * @return "TInt"
+ * Returns the samples recorded.
+ *
+ */
+TInt CMMFDevSoundSvrImp::SamplesPlayed()
+ {
+ TInt samples = 0;
+ if(iPlayCustomInterface)
+ {
+ TUint bytesPlayed = iPlayCustomInterface->BytesPlayed();
+ if (bytesPlayed)
+ iPlayedBytesCount = bytesPlayed;
+
+ samples = iPlayedBytesCount;
+ if(NumberOfChannels() > 1)
+ samples /= NumberOfChannels();
+
+ if(BytesPerAudioSample() > 1)
+ samples /= BytesPerAudioSample();
+ }
+ //note always pcm16 becuase the iPlayedBytesCount originates from
+ //RMdaDevSound which is always pcm16
+ return samples; //each sample is 2 bytes
+ }
+
+
+/*
+ *
+ * Initializes audio device and start playing tone. Tone is played with
+ * frequency and for duration specified.
+ *
+ * Leaves on failure.
+ *
+ * @param "TInt aFrequency"
+ * Frequency at with the tone will be played.
+ *
+ * @param "TTimeIntervalMicroSeconds& aDuration"
+ * The period over which the tone will be played. A zero value causes
+ * the no tone to be played (Verify this with test app).
+ *
+ */
+void CMMFDevSoundSvrImp::PlayToneL(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration)
+ {
+ if (iMode!= EMMFStateTonePlaying)
+ User::Leave(KErrNotSupported); //tone playing only supported in tone play state
+
+ // 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);
+
+ // Get audio policy
+ iAudioPolicyPrioritySettings.iState = EMMFStatePlayTone;
+ RequestPolicy();
+ }
+
+/*
+ * 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.
+ *
+ * @param "aFrequencyOne"
+ * First frequency of dual tone
+ *
+ * @param "aFrequencyTwo"
+ * Second frequency of dual tone
+ *
+ * @param "aDuration"
+ * The period over which the tone will be played. A zero value causes
+ * the no tone to be played (Verify this with test app).
+ */
+void CMMFDevSoundSvrImp::PlayDualToneL(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration)
+ {
+
+ // 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);
+
+ // Get audio policy
+ iAudioPolicyPrioritySettings.iState = EMMFStatePlayDualTone;
+ RequestPolicy();
+ }
+
+/*
+ *
+ * Initializes audio device and start playing DTMF string aDTMFString.
+ *
+ * Leaves on failure.
+ *
+ * @param "TDesC& aDTMFString"
+ * DTMF sequence in a descriptor.
+ *
+ */
+void CMMFDevSoundSvrImp::PlayDTMFStringL(const TDesC& aDTMFString)
+ {
+ if (!iDevSoundObserver)
+ User::Leave(KErrNotReady);
+
+ if (iMode!= EMMFStateTonePlaying)
+ User::Leave(KErrNotSupported); //tone playing only supported in tone play state
+
+ iDTMFGen.SetString(aDTMFString);
+
+ // Get audio policy
+ iAudioPolicyPrioritySettings.iState = EMMFStatePlayDTMFString;
+ RequestPolicy();
+ }
+
+/*
+ *
+ * Initializes audio device and start playing tone sequence.
+ *
+ * Leaves on failure.
+ *
+ * @param "TDesC8& aData"
+ * Tone sequence in a descriptor.
+ *
+ */
+void CMMFDevSoundSvrImp::PlayToneSequenceL(const TDesC8& aData)
+ {
+ if (!iDevSoundObserver)
+ User::Leave(KErrNotReady);
+
+ if (iMode!= EMMFStateTonePlaying)
+ User::Leave(KErrNotSupported); //tone playing only supported in tone play state
+
+ // Check whether the sequence is valid or not
+ if (!iDevSoundUtil->RecognizeSequence(aData))
+ User::Leave(KErrCorrupt);
+
+ iSequenceGen.SetSequenceData(aData);
+
+ // Get audio policy
+ iAudioPolicyPrioritySettings.iState = EMMFStatePlayToneSequence;
+ RequestPolicy();
+ }
+
+/*
+ *
+ * Initializes audio device and start playing the specified pre-defined tone
+ * sequence.
+ *
+ * Leaves on failure.
+ *
+ * @param "TInt aSequenceNumber"
+ * The index identifying the specific pre-defined tone sequence. Index
+ * values are relative to zero.
+ * This can be any value from zero to the value returned by a call to
+ * CMdaAudioPlayerUtility::FixedSequenceCount() - 1.
+ * The function raises a panic if sequence number is not within this
+ * range.
+ *
+ */
+void CMMFDevSoundSvrImp::PlayFixedSequenceL(TInt aSequenceNumber)
+ {
+ if (!iDevSoundObserver)
+ User::Leave(KErrNotReady);
+
+ if (iMode!= EMMFStateTonePlaying)
+ User::Leave(KErrNotSupported); //tone playing only supported in tone play state
+
+ ASSERT((aSequenceNumber >= 0)&&(aSequenceNumber < iFixedSequences->Count()));
+
+ iFixedSequence.Set(iFixedSequences->MdcaPoint(aSequenceNumber));
+ iSequenceGen.SetSequenceData(iFixedSequence);
+
+ // Get audio policy
+ iAudioPolicyPrioritySettings.iState = EMMFStatePlayToneSequence;
+ RequestPolicy();
+ }
+
+/*
+ *
+ * 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.
+ *
+ * @param "TTimeIntervalMicroSeconds32& aToneOnLength"
+ * The period over which the tone will be played. If this is set to
+ * zero, then the tone is not played.
+ *
+ * @param "TTimeIntervalMicroSeconds32& aToneOffLength"
+ * The period over which the no tone will be played.
+ *
+ * @param "TTimeIntervalMicroSeconds32& aPauseLength"
+ * The period over which the tone playing will be paused.
+ *
+ */
+void CMMFDevSoundSvrImp::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);
+ }
+
+/*
+ *
+ * Defines the period over which the volume level is to rise smoothly from
+ * nothing to the normal volume level.
+ *
+ * @param "TTimeIntervalMicroSeconds& aRampDuration"
+ * The period over which the volume is to rise. A zero value causes
+ * the tone sample to be played at the normal level for the full
+ * duration of the playback. A value, which is longer than the duration
+ * of the tone sample, that the sample never reaches its normal
+ * volume level.
+ *
+ *
+ */
+void CMMFDevSoundSvrImp::SetVolumeRamp(const TTimeIntervalMicroSeconds& aRampDuration)
+ {
+ // save ramp duration for tone generator
+ iRampDuration = aRampDuration;
+
+ SetDeviceVolumeRamp(iRampDuration);
+ }
+
+/**
+ * Sets volume ramp on HwDevice.
+ */
+TInt CMMFDevSoundSvrImp::SetDeviceVolumeRamp(const TTimeIntervalMicroSeconds& aRampDuration)
+ {
+ TInt error = KErrNone;
+ if (iPlayCustomInterface)
+ iPlayCustomInterface->SetVolumeRamp(aRampDuration);
+ else
+ error = KErrNotReady;
+ return error;
+ }
+
+/**
+ * @see sounddevice.h
+ */
+void CMMFDevSoundSvrImp::GetSupportedInputDataTypesL(RArray<TFourCC>& aSupportedDataTypes, const TMMFPrioritySettings& /*aPrioritySettings*/) const
+ {
+ //aPrioritySettings not used on ref DevSound
+ //search for playing datatypes
+ iDevSoundUtil->SeekHwDevicePluginsL(aSupportedDataTypes, EMMFStatePlaying);
+ }
+
+/**
+ * @see sounddevice.h
+ */
+void CMMFDevSoundSvrImp::GetSupportedOutputDataTypesL(RArray<TFourCC>& aSupportedDataTypes, const TMMFPrioritySettings& /*aPrioritySettings*/) const
+ {
+ //aPrioritySettings not used on ref DevSound
+ // search for recording datatypes
+ iDevSoundUtil->SeekHwDevicePluginsL(aSupportedDataTypes, EMMFStateRecording);
+ }
+
+TInt CMMFDevSoundSvrImp::RegisterAsClient(TUid aEventType, const TDesC8& aNotificationRegistrationData)
+ {
+ return iAudioPolicyProxy->RequestResourceNotification(aEventType,aNotificationRegistrationData);
+ }
+
+TInt CMMFDevSoundSvrImp::CancelRegisterAsClient(TUid aEventType)
+ {
+ return iAudioPolicyProxy->CancelRequestResourceNotification(aEventType);
+ }
+
+TInt CMMFDevSoundSvrImp::GetResourceNotificationData(TUid aEventType, TDes8& aNotificationData)
+ {
+ TInt err = KErrNone;
+ err = iAudioPolicyProxy->IsRegisteredResourceNotification(aEventType);
+ if(err == KErrNone)
+ {
+ aNotificationData.Num(SamplesPlayed());
+ }
+ return err;
+ }
+
+TInt CMMFDevSoundSvrImp::WillResumePlay()
+ {
+ return iAudioPolicyProxy->StopNotification();
+ }
+
+/********************************************************************************
+ * Implementations of Non Exported public functions begins here *
+ ********************************************************************************/
+
+//
+// Audio Policy specific implementation begins here //
+//
+
+/*
+ *
+ * Called by Audio Policy Server when a request to play is approved by the
+ * Audio Policy Server.
+ *
+ * Leaves on failure??.
+ *
+ */
+void CMMFDevSoundSvrImp::StartPlayDataL()
+ {
+ ASSERT(iMode== EMMFStatePlaying);
+
+ TInt error = KErrNone;
+
+ if(iCMMFHwDevice)
+ {
+ // Set volume and play format values
+ error = SetPlayFormat(iPlayFormat);
+ if (error == KErrNone)
+ error = SetDeviceVolume(iVolume);
+ if (error == KErrNone)
+ error = SetDeviceVolumeRamp(iRampDuration);
+
+ // Initialize attribute values
+ iPlayedBytesCount = 0;
+ iLastBufferReceived = EFalse;
+
+ // Start HwDevice
+ if (error == KErrNone)
+ error = iCMMFHwDevice->Start(EDevDecode, EDevOutFlow);
+ }
+ else
+ error = KErrNotReady;
+
+ if (error != KErrNone)
+ iDevSoundObserver->PlayError(error);
+ }
+
+/*
+ *
+ * Called by Audio Policy Server when a request to record is approved by the
+ * Audio Policy Server.
+ *
+ * Leaves on failure.
+ *
+ */
+void CMMFDevSoundSvrImp::StartRecordDataL()
+ {
+ ASSERT(iMode== EMMFStateRecording);
+
+ if(iCMMFHwDevice)
+ {
+ TInt error = KErrNone;
+ error = SetRecordFormat(iRecordFormat);
+ if (error != KErrNone)
+ {
+ iDevSoundObserver->RecordError(error);
+ return;
+ }
+ error = SetDeviceRecordLevel(iGain);
+ if (error != KErrNone)
+ {
+ iDevSoundObserver->RecordError(error);
+ return;
+ }
+
+ // Initialize attribute values
+ iRecordedBytesCount = 0;
+
+ error = iCMMFHwDevice->Start(EDevEncode, EDevInFlow);
+ if (iHwDeviceBuffer)
+ iHwDeviceBuffer->SetLastBuffer(EFalse);
+
+ if (error != KErrNone)
+ {
+ iDevSoundObserver->RecordError(error);
+ return;
+ }
+ }
+ else
+ iDevSoundObserver->RecordError(KErrNotReady);
+ }
+
+/*
+ *
+ * Called by Audio Policy Server when a request to play tone is approved by
+ * the Audio Policy Server.
+ *
+ * Leaves on failure.
+ *
+ */
+void CMMFDevSoundSvrImp::StartPlayToneL()
+ {
+ ASSERT(iMode== EMMFStateTonePlaying);
+
+ if(iCMMFHwDevice)
+ {
+ TInt error = KErrNone;
+ // Set volume and play format values
+ error = SetPlayFormat(iPlayFormat);
+ if (error != KErrNone)
+ {
+ iDevSoundObserver->ToneFinished(error);
+ return;
+ }
+ if (iHwDeviceID.iUid == KMmfUidBtHwDevicePCM16ToPCM16)
+ error = SetDeviceVolume(iVolume);
+ else
+ error = KErrGeneral;//hw device should always be pcm16 for tone
+
+ // turn off volume ramping - this is done in software below
+ if (error == KErrNone)
+ error = SetDeviceVolumeRamp(TTimeIntervalMicroSeconds(0));
+
+ if (error != KErrNone)
+ {
+ iDevSoundObserver->ToneFinished(error);
+ return;
+ }
+
+ // Initialize attribute values
+ iPlayedBytesCount = 0;
+
+ // Configure tone generator
+ iToneGen.Configure(
+ iPlayFormat().iRate,
+ iPlayFormat().iChannels,
+ iRepeatCount,
+ I64LOW((iRepeatTrailingSilence.Int64()*iPlayFormat().iRate)/1000000),
+ I64LOW((iRampDuration.Int64()*iPlayFormat().iRate)/1000000)
+ );
+
+ iCurrentGenerator = &iToneGen;
+
+ // Start playback
+ DoPlayL();
+
+ }
+ else
+ iDevSoundObserver->ToneFinished(KErrNotReady);
+ }
+
+/*
+ *
+ * Called by Audio Policy Server when a request to play a dual tone is approved by
+ * the Audio Policy Server.
+ *
+ */
+void CMMFDevSoundSvrImp::StartPlayDualToneL()
+ {
+ ASSERT(iMode== EMMFStateTonePlaying);
+
+ if(iCMMFHwDevice)
+ {
+ TInt error = KErrNone;
+ // Set volume and play format values
+ error = SetPlayFormat(iPlayFormat);
+ if (error != KErrNone)
+ {
+ iDevSoundObserver->ToneFinished(error);
+ return;
+ }
+ if (iHwDeviceID.iUid == KMmfUidBtHwDevicePCM16ToPCM16)
+ error = SetDeviceVolume(iVolume);
+ else
+ error = KErrGeneral;//hw device should always be pcm16 for tone
+
+ // turn off volume ramping - this is done in software below
+ if (error == KErrNone)
+ error = SetDeviceVolumeRamp(TTimeIntervalMicroSeconds(0));
+
+ if (error != KErrNone)
+ {
+ iDevSoundObserver->ToneFinished(error);
+ return;
+ }
+
+ // Initialize attribute values
+ iPlayedBytesCount = 0;
+
+ // Configure dual tone generator
+ iDualToneGen.Configure(
+ iPlayFormat().iRate,
+ iPlayFormat().iChannels,
+ iRepeatCount,
+ I64LOW((iRepeatTrailingSilence.Int64()*iPlayFormat().iRate)/KOneMillionMicroSeconds),
+ I64LOW((iRampDuration.Int64()*iPlayFormat().iRate)/KOneMillionMicroSeconds)
+ );
+
+ iCurrentGenerator = &iDualToneGen;
+
+ // Start playback
+ DoPlayL();
+ }
+ else
+ iDevSoundObserver->ToneFinished(KErrNotReady);
+ }
+
+/*
+ *
+ * Called by Audio Policy Server when a request to play DTMF String is approved
+ * by the Audio Policy Server.
+ *
+ * Leaves on failure.
+ *
+ */
+void CMMFDevSoundSvrImp::StartPlayDTMFStringL()
+ {
+
+ ASSERT(iMode== EMMFStateTonePlaying);
+
+ if(iCMMFHwDevice)
+ {
+ TInt error = KErrNone;
+ // Set volume and play format values
+ error = SetPlayFormat(iPlayFormat);
+ if (error != KErrNone)
+ {
+ iDevSoundObserver->ToneFinished(error);
+ return;
+ }
+ error = SetDeviceVolume(iVolume);
+
+ // turn off volume ramping - this is done in software below
+ if (error == KErrNone)
+ error = SetDeviceVolumeRamp(TTimeIntervalMicroSeconds(0));
+
+ if (error != KErrNone)
+ {
+ iDevSoundObserver->ToneFinished(error);
+ return;
+ }
+
+ // Initialize attribute values
+ iPlayedBytesCount = 0;
+
+ iDTMFGen.Configure(
+ iPlayFormat().iRate,
+ iPlayFormat().iChannels,
+ iRepeatCount,
+ I64LOW((iRepeatTrailingSilence.Int64()*iPlayFormat().iRate)/1000000),
+ I64LOW((iRampDuration.Int64()*iPlayFormat().iRate)/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);
+ }
+
+/*
+ *
+ * Called by Audio Policy Server when a request to play tone sequence is
+ * approved by the Audio Policy Server.
+ *
+ * Leaves on failure.
+ *
+ */
+void CMMFDevSoundSvrImp::StartPlayToneSequenceL()
+ {
+ ASSERT(iMode== EMMFStateTonePlaying);
+
+ if(iCMMFHwDevice)
+ {
+ TInt error = KErrNone;
+ // Set volume and play format values
+ if (iHwDeviceID.iUid == KMmfUidBtHwDevicePCM16ToPCM16)
+ error = SetPlayFormat(iPlayFormat);
+ else error = KErrGeneral;//hw device should always be pcm16 for tone
+ if (error != KErrNone)
+ {
+ iDevSoundObserver->ToneFinished(error);
+ return;
+ }
+
+ if (iHwDeviceID.iUid == KMmfUidBtHwDevicePCM16ToPCM16)
+ error = SetDeviceVolume(iVolume);
+ else
+ error = KErrGeneral;//hw device should always be pcm16 for tone
+
+ // turn off volume ramping - this is done in software below
+ if (error == KErrNone)
+ error = SetDeviceVolumeRamp(TTimeIntervalMicroSeconds(0));
+
+ if (error != KErrNone)
+ {
+ iDevSoundObserver->ToneFinished(error);
+ return;
+ }
+
+ // Initialize attribute values
+ iPlayedBytesCount = 0;
+
+ iSequenceGen.Configure(
+ iPlayFormat().iRate,
+ iPlayFormat().iChannels,
+ iRepeatCount,
+ I64LOW((iRepeatTrailingSilence.Int64()*iPlayFormat().iRate)/1000000),
+ I64LOW((iRampDuration.Int64()*iPlayFormat().iRate)/1000000)
+ );
+
+ iCurrentGenerator = &iSequenceGen;
+
+ // Start playback
+ DoPlayL();
+ }
+ else
+ iDevSoundObserver->ToneFinished(KErrNotReady);
+ }
+
+/*
+ *
+ * Called by Audio Policy Server when the current DevSound instance looses the
+ * policy because of another instance with a higher priority wants the device.
+ *
+ */
+void CMMFDevSoundSvrImp::SendEventToClient(const TMMFEvent& aEvent)
+ {
+ switch (iMode)
+ {
+ case EMMFStatePlaying:
+ case EMMFStateTonePlaying:
+ case EMMFStatePlayToneSequence:
+ case EMMFStateRecording:
+ {
+ Error(aEvent.iErrorCode);//Updates Bytes played informs client
+ iCMMFHwDevice->Stop();//unloads sound device
+ Stopped();//Updates policy
+ iMode = EMMFStateIdle;
+ iAudioPolicyProxy->LaunchRequests();
+ break;
+ }
+ case EMMFStateIdle:
+ {
+ iMode = EMMFStatePlaying;
+ iDevSoundObserver->SendEventToClient(aEvent);
+ break;
+ }
+ default:
+ break;
+ }
+ // Have audio Policy launch higher priority request:
+ }
+
+
+/**
+ *
+ * Sets volume on HwDevice.
+ *
+ * @return "TInt"
+ * Error value returned by HwDevice.
+ *
+ */
+TInt CMMFDevSoundSvrImp::SetDeviceVolume(TInt aVolume)
+ {
+ TInt error = KErrNone;
+ if (iPlayCustomInterface)
+ iPlayCustomInterface->SetVolume(aVolume);
+ else error = KErrNotReady;
+ return error;
+ }
+
+/**
+ *
+ * Sets PlayFormat on HwDevice.
+ *
+ *
+ * @return "TInt"
+ * Error value returned by HwDevice.
+ *
+ */
+TInt CMMFDevSoundSvrImp::SetPlayFormat(RMdaDevSound::TCurrentSoundFormatBuf& aPlayFormat)
+ {
+ TInt error = KErrNone;
+ if (iCMMFHwDevice)
+ {
+ TTaskConfig taskConfig;
+ taskConfig.iUid = KUidBtRefDevSoundTaskConfig;
+ taskConfig.iRate = aPlayFormat().iRate;
+
+ if (aPlayFormat().iChannels == 1)
+ {
+ taskConfig.iStereoMode = ETaskMono;
+ }
+ else if (aPlayFormat().iChannels == 2)
+ {
+ taskConfig.iStereoMode = ETaskInterleaved;
+ }
+ else
+ {
+ return KErrArgument;
+ }
+
+ error = iCMMFHwDevice->SetConfig(taskConfig);
+ //note the iEncoding and iBufferSize are already determined by the
+ //CMMFHwDevice plugin and so are not set.
+ }
+ else
+ {
+ error = KErrNotReady;
+ }
+ return error;
+ }
+
+
+/**
+ *
+ * Sets RecordFormat on HwDevice.
+ *
+ *
+ * @return "TInt"
+ * Error value returned by HwDevice.
+ *
+ */
+TInt CMMFDevSoundSvrImp::SetRecordFormat(RMdaDevSound::TCurrentSoundFormatBuf& aRecordFormat)
+ {
+ TInt error = KErrNone;
+ if (iCMMFHwDevice)
+ {
+ TTaskConfig taskConfig;
+ taskConfig.iUid = KUidBtRefDevSoundTaskConfig;
+ taskConfig.iRate = aRecordFormat().iRate;
+
+ if (aRecordFormat().iChannels == 1)
+ {
+ taskConfig.iStereoMode = ETaskMono;
+ }
+ else if (aRecordFormat().iChannels == 2)
+ {
+ taskConfig.iStereoMode = ETaskInterleaved;
+ }
+ else
+ {
+ return KErrArgument;
+ }
+
+ error = iCMMFHwDevice->SetConfig(taskConfig);
+ //note the iEncoding and iBufferSize are already determined by the
+ //CMMFHwDevice plugin and so are not set.
+ }
+ else
+ {
+ error = KErrNotReady;
+ }
+ return error;
+ }
+
+
+/**
+ *
+ * Sets record level on HwDevice.
+ *
+ *
+ * @return "TInt"
+ * Error value returned by HwDevice.
+ *
+ */
+TInt CMMFDevSoundSvrImp::SetDeviceRecordLevel(TInt aGain)
+ {
+ TInt error = KErrNone;
+ if (iRecordCustomInterface)
+ iRecordCustomInterface->SetGain(aGain);
+ else error = KErrNotReady;
+ return error;
+
+ }
+
+
+/**
+ *
+ * MMMFHwDeviceObserver mixin implementation.
+ *
+ * The CMMFHwDevice implementation object calls this method during decoding
+ * (playing), when it needs the encoded data in the buffer
+ * aHwDataBuffer.
+ *
+ * @return "TInt"
+ * Error code. KErrNone if success.
+ *
+ */
+TInt CMMFDevSoundSvrImp::FillThisHwBuffer(CMMFBuffer& aHwDataBuffer)
+ {
+ 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)
+ {
+ TInt tonelen = iActiveToneBuffer->Data().Length();
+
+ // don't enter more data than can be handled by the receiving buffer
+ if (len >= tonelen) len = tonelen;
+
+ // Copy data from tone buffer to hw device buffer
+ Mem::Copy((TAny*)(iHwDeviceBuffer->Data().Ptr()), (TAny*)(iActiveToneBuffer->Data().Ptr()), len);
+
+ iHwDeviceBuffer->Data().SetLength(len);
+ // 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
+ }
+
+
+ // 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;
+ }
+
+
+/**
+ *
+ * MMMFHwDeviceObserver mixin implementation.
+ *
+ * The CMMFHwDevice implementation object calls this method during encoding
+ * (recording), when it fills the buffer aHwDataBuffer with
+ * encoded data.
+ *
+ * @return "TInt"
+ * Error code. KErrNone if success.
+ *
+ */
+TInt CMMFDevSoundSvrImp::EmptyThisHwBuffer(CMMFBuffer& aHwDataBuffer)
+ {
+ 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);
+
+ iDevSoundEventHandler->CancelReceiveEvents();
+
+ iAudioPolicyPrioritySettings.iState = EMMFStateStopped;
+ UpdatePolicyState();
+ }
+
+ // Send Data from Observer
+ iDevSoundObserver->BufferToBeEmptied(iHwDeviceBuffer);
+ }
+ else
+ {
+ err = KErrGeneral;
+ iDevSoundObserver->RecordError(KErrGeneral);
+ }
+
+ return err;
+ }
+
+
+/**
+ *
+ * MMMFHwDeviceObserver mixin implementation.
+ *
+ * The CMMFHwDevice implementation object calls this method when a message from
+ * the hardware device implementation is received.
+ *
+ * @return "TInt"
+ * Error code. KErrNone if success.
+ *
+ */
+TInt CMMFDevSoundSvrImp::MsgFromHwDevice(TUid aMessageType, const TDesC8& /*aMsg*/)
+ {
+ TInt result = KErrNotSupported;
+ if (aMessageType.iUid == KMmfHwDeviceObserverUpdateBytesPlayed)
+ {//this is used by sw codec wrapper to request a bytes played update
+ //bytes played won't be updated in Stopped() or Error() on sw cdoec wrapper
+ //as the sound device is closed. Non swCodec wrapper Hw device plugins
+ //can get there bytes updated on Stopped() and/or Error()
+ UpdateBytesPlayed();
+ result = KErrNone;
+ }
+ return result;
+ }
+
+/**
+ *
+ * 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
+ *
+ */
+void CMMFDevSoundSvrImp::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
+ UpdateBytesPlayed();
+
+ iLastBufferReceived = EFalse;
+ iAudioPolicyPrioritySettings.iState = EMMFStateCompleted;
+ UpdatePolicyState();
+ }
+
+/**
+ * MMMFHwDeviceObserver mixin implementation
+ * Processes error from hw device
+ */
+void CMMFDevSoundSvrImp::Error(TInt aError)
+ {
+ if (iMode== EMMFStatePlaying)
+ {
+ //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
+ UpdateBytesPlayed();
+
+ iDevSoundObserver->PlayError(aError);
+ iAudioPolicyPrioritySettings.iState = EMMFStateStopped;
+ UpdatePolicyState();
+ }
+ else if (iMode== EMMFStateRecording)
+ {
+ iDevSoundObserver->RecordError(aError);
+ }
+ else if (iMode== EMMFStateTonePlaying)
+ {
+ iDevSoundObserver->ToneFinished(aError);
+ }
+ //else can't handle error
+ }
+
+
+/********************************************************************************
+ * Non Exported public functions ends here *
+ ********************************************************************************/
+
+
+/********************************************************************************
+ * Private functions begins here *
+ ********************************************************************************/
+
+TInt CMMFDevSoundSvrImp::InitializeFormat(RMdaDevSound::TSoundFormatsSupportedBuf& aSupportedFormat,
+ RMdaDevSound::TCurrentSoundFormatBuf& aFormat)
+ {
+ // Choose an encoding
+ TUint32 enc = aSupportedFormat().iEncodings;
+ // Always defaults to this
+ if (enc & RMdaDevSound::EMdaSoundEncoding16BitPCM)
+ aFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM;
+ else if (enc & RMdaDevSound::EMdaSoundEncoding8BitALaw)
+ aFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitALaw;
+ else if (enc & RMdaDevSound::EMdaSoundEncoding8BitMuLaw)
+ aFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitMuLaw;
+ else if (enc & RMdaDevSound::EMdaSoundEncoding8BitPCM)
+ aFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitPCM;
+
+ // default to Monophonic playback:
+ aFormat().iChannels=1;
+
+ // Store the device capabilities (WINS supports from 8000 Hz to 44100 Hz)
+ if ((aSupportedFormat().iMinRate <= 8000) && (8000 <= aSupportedFormat().iMaxRate))
+ iDeviceCapabilities.iRate = EMMFSampleRate8000Hz;
+ if ((aSupportedFormat().iMinRate <= 11025) && (11025 <= aSupportedFormat().iMaxRate))
+ iDeviceCapabilities.iRate |= EMMFSampleRate11025Hz;
+ if ((aSupportedFormat().iMinRate <= 12000) && (12000 <= aSupportedFormat().iMaxRate))
+ iDeviceCapabilities.iRate |= EMMFSampleRate12000Hz;
+ if ((aSupportedFormat().iMinRate <= 16000) && (16000 <= aSupportedFormat().iMaxRate))
+ iDeviceCapabilities.iRate |= EMMFSampleRate16000Hz;
+ if ((aSupportedFormat().iMinRate <= 22050) && (22050 <= aSupportedFormat().iMaxRate))
+ iDeviceCapabilities.iRate |= EMMFSampleRate22050Hz;
+ if ((aSupportedFormat().iMinRate <= 24000) && (24000 <= aSupportedFormat().iMaxRate))
+ iDeviceCapabilities.iRate |= EMMFSampleRate24000Hz;
+ if ((aSupportedFormat().iMinRate <= 32000) && (32000 <= aSupportedFormat().iMaxRate))
+ iDeviceCapabilities.iRate |= EMMFSampleRate32000Hz;
+ if ((aSupportedFormat().iMinRate <= 44100) && (44100 <= aSupportedFormat().iMaxRate))
+ iDeviceCapabilities.iRate |= EMMFSampleRate44100Hz;
+ if ((aSupportedFormat().iMinRate <= 48000) && (48000 <= aSupportedFormat().iMaxRate))
+ iDeviceCapabilities.iRate |= EMMFSampleRate48000Hz;
+ if ((aSupportedFormat().iMinRate <= 64000) && (64000 <= aSupportedFormat().iMaxRate))
+ iDeviceCapabilities.iRate |= EMMFSampleRate64000Hz;
+ if ((aSupportedFormat().iMinRate <= 88200) && (88200 <= aSupportedFormat().iMaxRate))
+ iDeviceCapabilities.iRate |= EMMFSampleRate88200Hz;
+ if ((aSupportedFormat().iMinRate <= 96000) && (96000 <= aSupportedFormat().iMaxRate))
+ iDeviceCapabilities.iRate |= EMMFSampleRate96000Hz;
+
+ // Store the encodings supported
+ iDeviceCapabilities.iEncoding = 0;
+ if (enc & RMdaDevSound::EMdaSoundEncoding16BitPCM)
+ iDeviceCapabilities.iEncoding |= EMMFSoundEncoding16BitPCM;
+ if (enc & RMdaDevSound::EMdaSoundEncoding8BitALaw)
+ iDeviceCapabilities.iEncoding |= EMMFSoundEncoding8BitALaw;
+ if (enc & RMdaDevSound::EMdaSoundEncoding8BitMuLaw)
+ iDeviceCapabilities.iEncoding |= EMMFSoundEncoding8BitMuLaw;
+ if (enc & RMdaDevSound::EMdaSoundEncoding8BitPCM)
+ iDeviceCapabilities.iEncoding |= EMMFSoundEncoding8BitPCM;
+
+ // Mono and Stereo support
+ if (aSupportedFormat().iChannels == 2)
+ iDeviceCapabilities.iChannels = EMMFStereo;
+ iDeviceCapabilities.iChannels |= EMMFMono;
+
+ iDeviceCapabilities.iBufferSize = aSupportedFormat().iMaxBufferSize;
+ // Default
+ iDeviceConfig.iRate = EMMFSampleRate8000Hz;
+ iDeviceConfig.iEncoding = EMMFSoundEncoding16BitPCM;
+ iDeviceConfig.iChannels = EMMFMono;
+
+ return KErrNone;
+ }
+
+/*
+ *
+ * Makes request to Policy Server (asynchronous call)
+ *
+ */
+void CMMFDevSoundSvrImp::RequestPolicy()
+ {
+ iDevSoundEventHandler->CancelReceiveEvents();
+ iDevSoundEventHandler->ReceiveEvents();
+ iAudioPolicyPrioritySettings.iCapabilities = iParent.CheckClientCapabilities();
+ iAudioPolicyProxy->MakeRequest(iAudioPolicyPrioritySettings);
+ }
+
+/*
+ *
+ * Creates buffer and begin playback using the specified tone generator.
+ *
+ */
+void CMMFDevSoundSvrImp::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;
+ }
+ //note the tone buffer needs to be the same as the pcm16->pcm16 'null'
+ //hw device plugin
+ // Buffer size = (SampleRate * BytesPerSample * Channels) / 4
+ TInt useBufferOfSize = ((SamplingFrequency() * 2 * NumberOfChannels())/KDevSoundFramesPerSecond + (KDevSoundDeltaFrameSize-1)) &~ (KDevSoundDeltaFrameSize-1);
+ //clamp buffer to desired limits
+ if(useBufferOfSize < KDevSoundMinFrameSize)
+ useBufferOfSize = KDevSoundMinFrameSize;
+ else if(useBufferOfSize > KDevSoundMaxFrameSize)
+ useBufferOfSize = KDevSoundMaxFrameSize;
+
+ //clamp buffer to limits of hardware
+ if(useBufferOfSize < Max(iPlayFormatsSupported().iMinBufferSize, iRecordFormatsSupported().iMinBufferSize))
+ useBufferOfSize = Max(iPlayFormatsSupported().iMinBufferSize, iRecordFormatsSupported().iMinBufferSize);
+ else if(useBufferOfSize > Min(iPlayFormatsSupported().iMaxBufferSize, iRecordFormatsSupported().iMaxBufferSize))
+ useBufferOfSize = Min(iPlayFormatsSupported().iMaxBufferSize, iRecordFormatsSupported().iMaxBufferSize);
+
+ iToneBuffer1 = CMMFDataBuffer::NewL(useBufferOfSize);
+ User::LeaveIfError(iCurrentGenerator->FillBuffer(iToneBuffer1->Data()));
+
+ if (iToneBuffer2)
+ {
+ delete iToneBuffer2;
+ iToneBuffer2 = NULL;
+ }
+ iToneBuffer2 = CMMFDataBuffer::NewL(useBufferOfSize);
+ 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
+ User::LeaveIfError(iCMMFHwDevice->Start(EDevDecode, EDevOutFlow));
+
+ }
+
+/*
+ *
+ * This method assigns the other buffer as active buffer. The tone audio
+ * generator should fill data in the other buffer by now.
+ *
+ */
+void CMMFDevSoundSvrImp::SetActiveToneBuffer()
+ {
+ if (iActiveToneBuffer == iToneBuffer1)
+ iActiveToneBuffer = iToneBuffer2;
+ else if (iActiveToneBuffer == iToneBuffer2)
+ iActiveToneBuffer = iToneBuffer1;
+ }
+
+/*
+ *
+ * This method fills data into the free buffer.
+ *
+ * @return "TInt"
+ * Error code. KErrNone if success.
+ *
+ */
+TInt CMMFDevSoundSvrImp::FillFreeToneBuffer()
+ {
+ TInt err(KErrNone);
+ if (iActiveToneBuffer == iToneBuffer1)
+ err = iCurrentGenerator->FillBuffer(iToneBuffer2->Data());
+ else if (iActiveToneBuffer == iToneBuffer2)
+ err = iCurrentGenerator->FillBuffer(iToneBuffer1->Data());
+ return err;
+ }
+
+/*
+ *
+ * Updates the policy state based on Audio policy settings of this devsound instance
+ *
+ */
+TInt CMMFDevSoundSvrImp::UpdatePolicyState()
+ {
+ TInt error = iAudioPolicyProxy->UpdateState(iAudioPolicyPrioritySettings);
+ return error;
+ }
+
+/*
+ *
+ * Initializes audio device node by setting volume, and sampling rate.
+ *
+ * @return "TInt"
+ * Error Code. KErrNone if success.
+ *
+ */
+TInt CMMFDevSoundSvrImp::InitTask()
+ {
+ // No Implementation
+ return KErrNone;
+ }
+
+
+
+/*
+ *
+ * Returns an integer representing Sampling Frequency the device is currently
+ * configured to.
+ *
+ * @return "TInt"
+ * Sampling Frequency.
+ *
+ */
+TInt CMMFDevSoundSvrImp::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
+ }
+
+/*
+ *
+ * Returns an integer representing number of channels the device is currently
+ * configured to.
+ *
+ * @return "TInt"
+ * Number of audio channels 1 if mono, 2 if stereo.
+ *
+ */
+TInt CMMFDevSoundSvrImp::NumberOfChannels()
+ {
+ if(iDeviceConfig.iChannels == EMMFMono)
+ return 1;
+ else
+ return 2;
+ }
+
+/*
+ *
+ * Returns an integer representing number of bytes in each audio sample
+ *
+ *
+ * @return "TInt"
+ * Number of of bytes in each audio sample.
+ *
+ */
+TInt CMMFDevSoundSvrImp::BytesPerAudioSample()
+ {
+ TInt bytes=1;
+ switch (iDeviceConfig.iEncoding)
+ {
+ case EMMFSoundEncoding8BitPCM:
+ case EMMFSoundEncoding8BitALaw:
+ case EMMFSoundEncoding8BitMuLaw:
+ {
+ bytes=1;
+ }
+ break;
+ case EMMFSoundEncoding16BitPCM:
+ {
+ bytes=2;
+ }
+ break;
+ }
+ return bytes;
+ }
+
+
+/********************************************************************************
+ * Private functions ends here *
+ ********************************************************************************/