diff -r 000000000000 -r bde4ae8d615e os/mm/devsound/sounddevbt/PlatSec/src/Server/AudioServer/MmfBtDevSoundSessionBody.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/mm/devsound/sounddevbt/PlatSec/src/Server/AudioServer/MmfBtDevSoundSessionBody.cpp Fri Jun 15 03:10:57 2012 +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 +#include "MmfBtDevSoundSessionBody.h" +#include "MmfBtDevSoundSessionXtnd.h" + +#include +#include +#include +#include +#include // 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& 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& 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 (&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(&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 * + ********************************************************************************/