sl@0: // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include sl@0: #ifdef SYMBIAN_MULTIMEDIA_CODEC_API sl@0: #include sl@0: #endif // SYMBIAN_MULTIMEDIA_CODEC_API sl@0: #include "MmfDevSoundSessionBody.h" sl@0: #include "MmfDevSoundSessionXtnd.h" sl@0: #include "MmfDevSoundServer.h" sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include // KUidRefDevSoundTaskConfig & KMmfUidEmptyBuffersCustomInterface sl@0: #include sl@0: sl@0: const TUid KEmptyBuffersCustomInterfaceTypeUid = {KMmfUidEmptyBuffersCustomInterface}; sl@0: sl@0: /* sl@0: * sl@0: * Default Constructor. sl@0: * sl@0: * No default implementation. CMMFDevSoundProxy implements 2-phase construction. sl@0: * sl@0: */ sl@0: CMMFDevSoundSvrImp::CMMFDevSoundSvrImp(CMMFDevSoundSessionXtnd* aParent) sl@0: : iParent(*aParent) sl@0: { sl@0: iMode= EMMFDevSoundStateIdle; sl@0: //Set reasonable default values for DTMF sl@0: iDTMFGen.SetToneDurations(250000,50000,250000); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Destructor. sl@0: * sl@0: * Deletes all objects and releases all resource owned by this sl@0: * instance. sl@0: * sl@0: */ sl@0: CMMFDevSoundSvrImp::~CMMFDevSoundSvrImp() sl@0: { sl@0: delete iToneBuffer1; sl@0: delete iToneBuffer2; sl@0: delete iDevSoundEventHandler; sl@0: if( iAudioPolicyProxy != NULL) sl@0: { sl@0: iAudioPolicyProxy->Close(); sl@0: delete iAudioPolicyProxy; sl@0: } sl@0: delete iDevSoundUtil; sl@0: delete iFixedSequences; sl@0: delete iCMMFHwDevice; sl@0: #ifdef SYMBIAN_MULTIMEDIA_CODEC_API sl@0: OMX_Deinit(); sl@0: #endif // SYMBIAN_MULTIMEDIA_CODEC_API sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Constructs, and returns a pointer to, a new CMMFDevSoundSvrImp object. sl@0: * sl@0: * Leaves on failure. sl@0: * sl@0: */ sl@0: CMMFDevSoundSvrImp* CMMFDevSoundSvrImp::NewL(CMMFDevSoundSessionXtnd* aParent) sl@0: { sl@0: CMMFDevSoundSvrImp* self = new (ELeave) CMMFDevSoundSvrImp(aParent); sl@0: return self; sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * 3rd phase constructor - assumes that iParent has already been set up properly sl@0: * (During ConstructL() it has yet to be sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::Construct3L(RServer2& aPolicyServerHandle) sl@0: { sl@0: // all these data properties should be NULL, but add ASSERTs to verity sl@0: ASSERT(iAudioPolicyProxy==NULL); sl@0: iAudioPolicyProxy = new (ELeave) RMMFAudioPolicyProxy(); sl@0: ASSERT(iDevSoundEventHandler==NULL); sl@0: iDevSoundEventHandler = CMMFDevSoundEventHandler::NewL(iAudioPolicyProxy); sl@0: User::LeaveIfError(iAudioPolicyProxy->Open(aPolicyServerHandle)); sl@0: iDevSoundEventHandler->SetDevSoundInfo(&iParent); sl@0: sl@0: iDevSoundUtil = CMMFDevSoundUtility::NewL(); sl@0: // Initialize Fixed sequence related sl@0: iDevSoundUtil->InitializeFixedSequenceL(&iFixedSequences); sl@0: sl@0: #ifdef SYMBIAN_MULTIMEDIA_CODEC_API sl@0: OMX_Init(); sl@0: #endif // SYMBIAN_MULTIMEDIA_CODEC_API sl@0: PreInitializeL(); sl@0: } sl@0: sl@0: /** sl@0: * internal procedure to perform all initialization prior to setting the sl@0: * data type 4CC code sl@0: */ sl@0: void CMMFDevSoundSvrImp::PreInitializeL() sl@0: { sl@0: // Set default values for priority settings: Note: Client must sl@0: // over ride default settings by calling SetPrioirtySettings sl@0: iAudioPolicyPrioritySettings.iState = EMMFStateStopped; sl@0: iAudioPolicyPrioritySettings.iPref = EMdaPriorityPreferenceNone; sl@0: iAudioPolicyPrioritySettings.iPriority = 0; sl@0: sl@0: // Get device capabilities and current settings from Audio Policy: sl@0: User::LeaveIfError(iAudioPolicyProxy->GetPlayFormatsSupported(iPlayFormatsSupported)); sl@0: User::LeaveIfError(iAudioPolicyProxy->GetPlayFormat(iPlayFormat)); sl@0: User::LeaveIfError(iAudioPolicyProxy->GetRecordFormatsSupported(iRecordFormatsSupported)); sl@0: User::LeaveIfError(iAudioPolicyProxy->GetRecordFormat(iRecordFormat)); sl@0: sl@0: //default to play until we know we are recording sl@0: User::LeaveIfError(InitializeFormat(iPlayFormatsSupported, iPlayFormat)); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Initializes CMMFDevSoundProxy object to play and record PCM16 raw audio data sl@0: * with sampling rate of 8 KHz. sl@0: * sl@0: * On completion of Initialization, calls InitializeComplete() on sl@0: * aDevSoundObserver. sl@0: * sl@0: * Leaves on failure. sl@0: * sl@0: * @param "MDevSoundObserver& aDevSoundObserver" sl@0: * A reference to DevSound Observer instance. sl@0: * sl@0: * @param "TMMFState aMode" sl@0: * Mode for which this object will be used. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::InitializeL(MDevSoundObserver& aDevSoundObserver, TMMFState aMode) sl@0: sl@0: { sl@0: // if no HwDevice id specified, load default null implementation sl@0: TUid rawUid = {KMmfUidHwDevicePCM16ToPCM16}; sl@0: InitializeL(aDevSoundObserver, rawUid, aMode); sl@0: __ASSERT_DEBUG(!(iHasPolicy&&(iMode == EMMFDevSoundStatePlaying)), Panic(TMMFDevSoundSessionPolicyNotInvalidated)); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Configure CMMFDevSoundProxy object for the settings in aConfig. sl@0: * sl@0: * Use this to set sampling rate, Encoding and Mono/Stereo. sl@0: * sl@0: * @param "TMMFCapabilities& aConfig" sl@0: * Attribute values to which CMMFDevSoundProxy object will be configured to. sl@0: * sl@0: * As part of defect 20796, the iRecordFormat has been set under the iPlayFormat, sl@0: * before it was not set at all. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::SetConfigL(const TMMFCapabilities& aConfig) sl@0: { sl@0: TUint attributeValue = aConfig.iRate; sl@0: // WINS supports from 8000 Hz to 96000 Hz sl@0: // The ToneGenerator currently supports sample rate of 8000Hz only. sl@0: if(iMode == EMMFDevSoundStateTonePlaying && (attributeValue != EMMFSampleRate8000Hz )) sl@0: { sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: if (attributeValue & EMMFSampleRate96000Hz) sl@0: { sl@0: iPlayFormat().iRate = 96000; sl@0: iRecordFormat().iRate = 96000; sl@0: iDeviceConfig.iRate = EMMFSampleRate96000Hz; sl@0: } sl@0: else if (attributeValue & EMMFSampleRate88200Hz) sl@0: { sl@0: iPlayFormat().iRate = 88200; sl@0: iRecordFormat().iRate = 88200; sl@0: iDeviceConfig.iRate = EMMFSampleRate88200Hz; sl@0: } sl@0: else if (attributeValue & EMMFSampleRate64000Hz) sl@0: { sl@0: iPlayFormat().iRate = 64000; sl@0: iRecordFormat().iRate = 64000; sl@0: iDeviceConfig.iRate = EMMFSampleRate64000Hz; sl@0: } sl@0: else if (attributeValue & EMMFSampleRate48000Hz) sl@0: { sl@0: iPlayFormat().iRate = 48000; sl@0: iRecordFormat().iRate = 48000; sl@0: iDeviceConfig.iRate = EMMFSampleRate48000Hz; sl@0: } sl@0: else if (attributeValue & EMMFSampleRate44100Hz) sl@0: { sl@0: iPlayFormat().iRate = 44100; sl@0: iRecordFormat().iRate = 44100; sl@0: iDeviceConfig.iRate = EMMFSampleRate44100Hz; sl@0: } sl@0: else if (attributeValue & EMMFSampleRate32000Hz) sl@0: { sl@0: iPlayFormat().iRate = 32000; sl@0: iRecordFormat().iRate = 32000; sl@0: iDeviceConfig.iRate = EMMFSampleRate32000Hz; sl@0: } sl@0: else if (attributeValue & EMMFSampleRate24000Hz) sl@0: { sl@0: iPlayFormat().iRate = sl@0: iRecordFormat().iRate = 24000; sl@0: iDeviceConfig.iRate = EMMFSampleRate24000Hz; sl@0: } sl@0: else if (attributeValue & EMMFSampleRate22050Hz) sl@0: { sl@0: iPlayFormat().iRate = 22050; sl@0: iRecordFormat().iRate = 22050; sl@0: iDeviceConfig.iRate = EMMFSampleRate22050Hz; sl@0: } sl@0: else if (attributeValue & EMMFSampleRate16000Hz) sl@0: { sl@0: iPlayFormat().iRate = 16000; sl@0: iRecordFormat().iRate = 16000; sl@0: iDeviceConfig.iRate = EMMFSampleRate16000Hz; sl@0: } sl@0: else if (attributeValue & EMMFSampleRate12000Hz) sl@0: { sl@0: iPlayFormat().iRate = sl@0: iRecordFormat().iRate = 12000; sl@0: iDeviceConfig.iRate = EMMFSampleRate12000Hz; sl@0: } sl@0: else if (attributeValue & EMMFSampleRate11025Hz) sl@0: { sl@0: iPlayFormat().iRate = 11025; sl@0: iRecordFormat().iRate = 11025; sl@0: iDeviceConfig.iRate = EMMFSampleRate11025Hz; sl@0: } sl@0: else if (attributeValue & EMMFSampleRate8000Hz) sl@0: { sl@0: iPlayFormat().iRate = 8000; sl@0: iRecordFormat().iRate = 8000; sl@0: iDeviceConfig.iRate = EMMFSampleRate8000Hz; sl@0: } sl@0: else if (attributeValue) sl@0: { //if no attribute value assume its not set sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: attributeValue = aConfig.iEncoding; sl@0: // Map from MMF Encoding enums to RMdaDevSound enum sl@0: if(attributeValue & EMMFSoundEncoding8BitPCM) sl@0: { sl@0: iPlayFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitPCM; sl@0: iRecordFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitPCM; sl@0: iDeviceConfig.iEncoding = EMMFSoundEncoding8BitPCM; sl@0: } sl@0: else if(attributeValue & EMMFSoundEncoding8BitALaw) sl@0: { sl@0: iPlayFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitALaw; sl@0: iRecordFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitALaw; sl@0: iDeviceConfig.iEncoding = EMMFSoundEncoding8BitALaw; sl@0: } sl@0: else if(attributeValue & EMMFSoundEncoding8BitMuLaw) sl@0: { sl@0: iPlayFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitMuLaw; sl@0: iRecordFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitMuLaw; sl@0: iDeviceConfig.iEncoding = EMMFSoundEncoding8BitMuLaw; sl@0: } sl@0: else if(attributeValue & EMMFSoundEncoding16BitPCM) sl@0: { sl@0: iPlayFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM; sl@0: iRecordFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM; sl@0: iDeviceConfig.iEncoding = EMMFSoundEncoding16BitPCM; sl@0: } sl@0: else if (attributeValue) sl@0: { //if no attribute value assume its not set sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: // Mono/Stereo settings sl@0: attributeValue = aConfig.iChannels; sl@0: if(iMode == EMMFDevSoundStateTonePlaying && (attributeValue != EMMFMono )) sl@0: { sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: if(attributeValue & EMMFStereo) sl@0: { sl@0: iPlayFormat().iChannels = 2; sl@0: iRecordFormat().iChannels = 2; sl@0: iDeviceConfig.iChannels = EMMFStereo; sl@0: } sl@0: else if(attributeValue & EMMFMono) sl@0: { sl@0: iPlayFormat().iChannels = 1; sl@0: iRecordFormat().iChannels = 1; sl@0: iDeviceConfig.iChannels = EMMFMono; sl@0: } sl@0: else if (attributeValue) sl@0: { //if no attribute value assume its not set sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Changes the current playback volume to a specified value. sl@0: * sl@0: * The volume can be changed before or during playback and is effective sl@0: * immediately. sl@0: * sl@0: * @param "TInt aVolume" sl@0: * The volume setting. This can be any value from zero to the value sl@0: * returned by a call to CMdaAudioPlayerUtility::MaxVolume(). If the sl@0: * volume is not within this range, the volume is automatically set to sl@0: * minimum or maximum value based on the value that is being passed. sl@0: * Setting a zero value mutes the sound. Setting the maximum value sl@0: * results in the loudest possible sound. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::SetVolume(TInt aVolume) sl@0: { sl@0: sl@0: // Check and make sure that the volume is in valid range sl@0: if (aVolume < 0) sl@0: aVolume = 0; sl@0: sl@0: if (aVolume > MaxVolume()) sl@0: aVolume = MaxVolume(); sl@0: sl@0: iVolume = aVolume; sl@0: sl@0: SetDeviceVolume(iVolume); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Changes the current recording gain to a specified value. sl@0: * sl@0: * The gain can be changed before or during recording and is effective sl@0: * immediately. sl@0: * sl@0: * @param "TInt aGain" sl@0: * The volume setting. This can be any value from zero to the value sl@0: * returned by a call to CMdaAudioPlayerUtility::MaxVolume(). If the sl@0: * volume is not within this range, the gain is automatically set to sl@0: * minimum or maximum value based on the value that is being passed. sl@0: * Setting a zero value mutes the sound. Setting the maximum value sl@0: * results in the loudest possible sound. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::SetGain(TInt aGain) sl@0: { sl@0: // make sure it falls with the correct range sl@0: TInt maxGain = iRecordFormatsSupported().iMaxVolume; sl@0: if (aGain > maxGain) sl@0: aGain = maxGain; sl@0: else if (aGain < 0) sl@0: aGain = 0; sl@0: iGain = aGain; sl@0: SetDeviceRecordLevel(iGain); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Sets the speaker balance for playing. sl@0: * sl@0: * The speaker balance can be changed before or during playback and is sl@0: * effective immediately. sl@0: * sl@0: * @param "TInt& aLeftPercentage" sl@0: * On return contains left speaker volume perecentage. This can be any sl@0: * value from zero to 100. Setting a zero value mutes the sound on left sl@0: * speaker. sl@0: * sl@0: * @param "TInt& aRightPercentage" sl@0: * On return contains right speaker volume perecentage. This can be any sl@0: * value from zero to 100. Setting a zero value mutes the sound on sl@0: * right speaker. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::SetPlayBalanceL(TInt aLeftPercentage, TInt aRightPercentage) sl@0: { sl@0: if (aLeftPercentage < 0) sl@0: aLeftPercentage = 0; sl@0: else if (aLeftPercentage > 100) sl@0: aLeftPercentage = 100; sl@0: if (aRightPercentage < 0) sl@0: aRightPercentage = 0; sl@0: else if (aRightPercentage > 100) sl@0: aRightPercentage = 100; sl@0: iLeftPlayBalance = aLeftPercentage; sl@0: iRightPlayBalance = aRightPercentage; sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Sets the microphone gain balance for recording. sl@0: * sl@0: * The microphone gain balance can be changed before or during recording and sl@0: * is effective immediately. sl@0: * sl@0: * @param "TInt aLeftPercentage" sl@0: * Left microphone gain precentage. This can be any value from zero to sl@0: * 100. Setting a zero value mutes the gain on left microphone. sl@0: * sl@0: * @param "TInt aRightPercentage" sl@0: * Right microphone gain precentage. This can be any value from zero to sl@0: * 100. Setting a zero value mutes the gain on right microphone. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::SetRecordBalanceL(TInt aLeftPercentage, TInt aRightPercentage) sl@0: { sl@0: if (aLeftPercentage < 0) sl@0: aLeftPercentage = 0; sl@0: else if (aLeftPercentage > 100) sl@0: aLeftPercentage = 100; sl@0: if (aRightPercentage < 0) sl@0: aRightPercentage = 0; sl@0: else if (aRightPercentage > 100) sl@0: aRightPercentage = 100; sl@0: iLeftRecordBalance = aLeftPercentage; sl@0: iRightRecordBalance = aRightPercentage; sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Initializes audio device and start play process. This method queries and sl@0: * acquires the audio policy before initializing audio device. If there was an sl@0: * error during policy initialization, PlayError() method will be called on sl@0: * the observer with error code KErrAccessDenied, otherwise BufferToBeFilled() sl@0: * method will be called with a buffer reference. After reading data into the sl@0: * buffer reference passed, the client should call PlayData() to play data. sl@0: * sl@0: * The amount of data that can be played is specified in sl@0: * CMMFBuffer::RequestSize(). Any data that is read into buffer beyond this sl@0: * size will be ignored. sl@0: * sl@0: * Leaves on failure. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::PlayInitL() sl@0: { sl@0: if (!iDevSoundObserver) sl@0: User::Leave(KErrNotReady); sl@0: sl@0: if (iAudioPolicyPrioritySettings.iState == EMMFStatePlayData) sl@0: { sl@0: // If policy has not been obtaing then ignore the request. sl@0: // If it has then do a stop and start action on HW device sl@0: // without informing policy. sl@0: sl@0: if (iHasPolicy) sl@0: { sl@0: if (iCMMFHwDevice) sl@0: { sl@0: TInt err = iCMMFHwDevice->Stop(); sl@0: if (err == KErrNone) sl@0: { sl@0: err = iCMMFHwDevice->Start(EDevDecode, EDevOutFlow); sl@0: } sl@0: sl@0: if (err != KErrNone) sl@0: { sl@0: Error(err); sl@0: } sl@0: } sl@0: } sl@0: return; sl@0: } sl@0: sl@0: // Get audio policy sl@0: iAudioPolicyPrioritySettings.iState = EMMFStatePlayData; sl@0: RequestPolicy(); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Initializes audio device and start record process. sl@0: * This method: sl@0: * 1. Queries and acquires the audio policy before initializing audio device. sl@0: * If there was an error during policy initialization, RecordError() method will sl@0: * be called on the observer with error code KErrAccessDenied, otherwise BufferToBeEmptied() sl@0: * method will be called with a buffer reference. This buffer contains recorded sl@0: * or encoded data. After processing data in the buffer reference passed, the sl@0: * client should call RecordData() to continue recording process. sl@0: * sl@0: * 2. Checks if the requesting client process has a UserEnvironment capability. sl@0: * If it does not, the audio device will not be initialized and an error sl@0: * code KErrAccessDenied will be sent to the client. sl@0: * sl@0: * The amount of data that is available is specified in sl@0: * CMMFBuffer::RequestSize(). sl@0: * sl@0: * Leaves on failure. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::RecordInitL(const RMmfIpcMessage& aMessage) sl@0: { sl@0: if (!iDevSoundObserver) sl@0: User::Leave(KErrNotReady); sl@0: sl@0: // Checkes if the client has the UserEnvironment capability sl@0: if (!aMessage.HasCapability(ECapabilityUserEnvironment)) sl@0: { sl@0: User::Leave(KErrPermissionDenied); sl@0: } sl@0: sl@0: if (iAudioPolicyPrioritySettings.iState == EMMFStateRecordData) sl@0: { sl@0: if (iHasPolicy) sl@0: { sl@0: if (iCMMFHwDevice) sl@0: { sl@0: TInt err = iCMMFHwDevice->Stop(); sl@0: if (err == KErrNone) sl@0: { sl@0: err = iCMMFHwDevice->Start(EDevDecode, EDevOutFlow); sl@0: } sl@0: sl@0: if (err != KErrNone) sl@0: { sl@0: Error(err); sl@0: } sl@0: sl@0: if (iHwDeviceBuffer) sl@0: { sl@0: iHwDeviceBuffer->SetLastBuffer(EFalse); sl@0: } sl@0: } sl@0: } sl@0: sl@0: return; sl@0: } sl@0: sl@0: // Get audio policy sl@0: iAudioPolicyPrioritySettings.iState = EMMFStateRecordData; sl@0: RequestPolicy(); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Plays data in the buffer at the current volume. The client should fill sl@0: * the buffer with audio data before calling this method. The Observer gets sl@0: * reference to buffer along with callback BufferToBeFilled(). When playing of sl@0: * the audio sample is complete, successfully or otherwise, the method sl@0: * PlayError() on observer is called. sl@0: * sl@0: */ sl@0: TBool CMMFDevSoundSvrImp::PlayData(const RMmfIpcMessage& aMessage) sl@0: { sl@0: ASSERT(iDevSoundObserver); sl@0: sl@0: if (iAudioPolicyPrioritySettings.iState == EMMFStateStopped) sl@0: { sl@0: // Initialisation has been successful but an error (possibly underflow) has occurred sl@0: // which the controller has yet to respond to and that has changed the state to stopped. sl@0: // Allow the call to complete and processing to continue... sl@0: return ETrue; sl@0: } sl@0: sl@0: if((iAudioPolicyPrioritySettings.iState != EMMFStatePlayData) && (iAudioPolicyPrioritySettings.iState != EMMFStatePaused)) sl@0: { sl@0: PanicClient(aMessage, EMMFDevSoundPlayDataWithoutInitialize); sl@0: return EFalse; sl@0: } sl@0: if (iMode== EMMFDevSoundStateIdle) sl@0: { sl@0: return ETrue; sl@0: } sl@0: TInt error = KErrNone; sl@0: if(iCMMFHwDevice) sl@0: { sl@0: if (iPaused) sl@0: { sl@0: iPaused = EFalse; sl@0: //note PlayData does not leave or return an error code so the Start() fails we cannot sl@0: //report the error back at this point sl@0: error = iCMMFHwDevice->Start(EDevDecode, EDevOutFlow);//restart hw device after pause sl@0: } sl@0: else if ((iMode == EMMFDevSoundStatePlaying) && iHasPolicy) sl@0: { sl@0: TInt len = iHwDeviceBuffer->Data().Length(); sl@0: if (iHwDeviceBuffer->LastBuffer()) sl@0: { sl@0: iLastBufferReceived = ETrue; sl@0: } sl@0: // Pass the data buffer to HwDevice sl@0: error = iCMMFHwDevice->ThisHwBufferFilled(*iHwDeviceBuffer); sl@0: } sl@0: } sl@0: if (error != KErrNone) sl@0: { sl@0: Error(error); sl@0: if(iCMMFHwDevice) sl@0: { sl@0: iCMMFHwDevice->Stop(); sl@0: } sl@0: sl@0: } sl@0: return ETrue; sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Stops the ongoing operation (Play, Record, TonePlay, Convert) sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::Stop() sl@0: { sl@0: iPaused = EFalse; sl@0: sl@0: if (!iHasPolicy) sl@0: { sl@0: UpdatePolicyState(EMMFStateStopped); sl@0: return; sl@0: } sl@0: sl@0: // Stop the hw device first - this unloads sound drivers sl@0: if (iCMMFHwDevice) sl@0: { sl@0: iCMMFHwDevice->Stop(); sl@0: } sl@0: sl@0: iDevSoundEventHandler->CancelReceiveEvents(); sl@0: sl@0: UpdatePolicyState(EMMFStateStopped); sl@0: __ASSERT_DEBUG(!(iHasPolicy&&(iMode == EMMFDevSoundStatePlaying)), Panic(TMMFDevSoundSessionPolicyNotInvalidated)); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Temporarily Stops the ongoing operation (Play, Record, TonePlay, Convert) sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::Pause() sl@0: { sl@0: iPaused = ETrue; sl@0: sl@0: if (!iHasPolicy) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: // Pause the HW device first sl@0: if (iCMMFHwDevice) sl@0: { sl@0: iCMMFHwDevice->Pause(); sl@0: } sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Returns the sample recorded so far. sl@0: * sl@0: * @return "TInt" sl@0: * Returns the samples recorded. sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::SamplesRecorded() sl@0: { sl@0: TInt samples = 0; sl@0: sl@0: if(iRecordCustomInterface) sl@0: { sl@0: samples = iRecordCustomInterface->BytesRecorded(); sl@0: if(NumberOfChannels() > 1) sl@0: { sl@0: samples /= NumberOfChannels(); sl@0: } sl@0: if(BytesPerAudioSample() > 1) sl@0: { sl@0: samples /= BytesPerAudioSample(); sl@0: } sl@0: } sl@0: sl@0: return samples; sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Returns the sample played so far. sl@0: * sl@0: * @return "TInt" sl@0: * Returns the samples recorded. sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::SamplesPlayed() sl@0: { sl@0: TInt samples = 0; sl@0: if(iPlayCustomInterface) sl@0: { sl@0: TUint bytesPlayed = iPlayCustomInterface->BytesPlayed(); sl@0: if (bytesPlayed) sl@0: iPlayedBytesCount = bytesPlayed; sl@0: sl@0: samples = iPlayedBytesCount; sl@0: if(NumberOfChannels() > 1) sl@0: samples /= NumberOfChannels(); sl@0: sl@0: if(BytesPerAudioSample() > 1) sl@0: samples /= BytesPerAudioSample(); sl@0: } sl@0: //note always pcm16 becuase the iPlayedBytesCount originates from sl@0: //RMdaDevSound which is always pcm16 sl@0: return samples; //each sample is 2 bytes sl@0: } sl@0: sl@0: sl@0: /* sl@0: * sl@0: * Initializes audio device and start playing tone. Tone is played with sl@0: * frequency and for duration specified. sl@0: * sl@0: * Leaves on failure. sl@0: * sl@0: * @param "TInt aFrequency" sl@0: * Frequency at with the tone will be played. sl@0: * sl@0: * @param "TTimeIntervalMicroSeconds& aDuration" sl@0: * The period over which the tone will be played. A zero value causes sl@0: * the no tone to be played (Verify this with test app). sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::PlayToneL(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration) sl@0: { sl@0: if (iMode != EMMFDevSoundStateTonePlaying) sl@0: { sl@0: User::Leave(KErrNotSupported); //tone playing only supported in tone play state sl@0: } sl@0: sl@0: // Check whether frequency and duration is valid or not sl@0: TInt64 zeroInt64(0); sl@0: if ((aFrequency<0) || (aDuration.Int64() < zeroInt64)) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: if (!iDevSoundObserver) sl@0: { sl@0: User::Leave(KErrNotReady); sl@0: } sl@0: sl@0: iToneGen.SetFrequencyAndDuration(aFrequency,aDuration); sl@0: sl@0: // Get audio policy sl@0: iAudioPolicyPrioritySettings.iState = EMMFStatePlayTone; sl@0: RequestPolicy(); sl@0: } sl@0: sl@0: /* sl@0: * Initializes audio device and start playing a dual tone. sl@0: * The tone consists of two sine waves of different frequencies summed together sl@0: * Dual Tone is played with specified frequencies and for specified duration. sl@0: * sl@0: * @param "aFrequencyOne" sl@0: * First frequency of dual tone sl@0: * sl@0: * @param "aFrequencyTwo" sl@0: * Second frequency of dual tone sl@0: * sl@0: * @param "aDuration" sl@0: * The period over which the tone will be played. A zero value causes sl@0: * the no tone to be played (Verify this with test app). sl@0: */ sl@0: void CMMFDevSoundSvrImp::PlayDualToneL(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration) sl@0: { sl@0: if (!iDevSoundObserver) sl@0: { sl@0: User::Leave(KErrNotReady); sl@0: } sl@0: sl@0: // Check whether frequencies and duration are valid or not sl@0: TInt64 zeroInt64(0); sl@0: if ((aFrequencyOne<0) || (aFrequencyTwo<0) || (aDuration.Int64() < zeroInt64)) sl@0: { sl@0: iDevSoundObserver->ToneFinished(KErrArgument); sl@0: return; sl@0: } sl@0: sl@0: sl@0: iDualToneGen.SetFrequencyAndDuration(aFrequencyOne, aFrequencyTwo, aDuration); sl@0: sl@0: // Get audio policy sl@0: iAudioPolicyPrioritySettings.iState = EMMFStatePlayDualTone; sl@0: RequestPolicy(); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Initializes audio device and start playing DTMF string aDTMFString. sl@0: * sl@0: * Leaves on failure. sl@0: * sl@0: * @param "TDesC& aDTMFString" sl@0: * DTMF sequence in a descriptor. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::PlayDTMFStringL(const TDesC& aDTMFString) sl@0: { sl@0: if (!iDevSoundObserver) sl@0: User::Leave(KErrNotReady); sl@0: sl@0: if (iMode!= EMMFDevSoundStateTonePlaying) sl@0: User::Leave(KErrNotSupported); //tone playing only supported in tone play state sl@0: sl@0: iDTMFGen.SetString(aDTMFString); sl@0: sl@0: // Get audio policy sl@0: iAudioPolicyPrioritySettings.iState = EMMFStatePlayDTMFString; sl@0: RequestPolicy(); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Initializes audio device and start playing tone sequence. sl@0: * sl@0: * Leaves on failure. sl@0: * sl@0: * @param "TDesC8& aData" sl@0: * Tone sequence in a descriptor. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::PlayToneSequenceL(const TDesC8& aData) sl@0: { sl@0: if (!iDevSoundObserver) sl@0: User::Leave(KErrNotReady); sl@0: sl@0: if (iMode!= EMMFDevSoundStateTonePlaying) sl@0: User::Leave(KErrNotSupported); //tone playing only supported in tone play state sl@0: sl@0: // Check whether the sequence is valid or not sl@0: if (!iDevSoundUtil->RecognizeSequence(aData)) sl@0: User::Leave(KErrCorrupt); sl@0: sl@0: iSequenceGen.SetSequenceData(aData); sl@0: sl@0: // Get audio policy sl@0: iAudioPolicyPrioritySettings.iState = EMMFStatePlayToneSequence; sl@0: RequestPolicy(); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Initializes audio device and start playing the specified pre-defined tone sl@0: * sequence. sl@0: * sl@0: * Leaves on failure. sl@0: * sl@0: * @param "TInt aSequenceNumber" sl@0: * The index identifying the specific pre-defined tone sequence. Index sl@0: * values are relative to zero. sl@0: * This can be any value from zero to the value returned by a call to sl@0: * FixedSequenceCount() - 1. sl@0: * The function raises a panic if sequence number is not within this sl@0: * range. sl@0: * sl@0: * @see FixesSequenceCount() sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::PlayFixedSequenceL(TInt aSequenceNumber) sl@0: { sl@0: if (!iDevSoundObserver) sl@0: User::Leave(KErrNotReady); sl@0: sl@0: if (iMode!= EMMFDevSoundStateTonePlaying) sl@0: User::Leave(KErrNotSupported); //tone playing only supported in tone play state sl@0: sl@0: ASSERT((aSequenceNumber >= 0)&&(aSequenceNumber < iFixedSequences->Count())); sl@0: sl@0: iFixedSequence.Set(iFixedSequences->MdcaPoint(aSequenceNumber)); sl@0: iSequenceGen.SetSequenceData(iFixedSequence); sl@0: sl@0: // Get audio policy sl@0: iAudioPolicyPrioritySettings.iState = EMMFStatePlayToneSequence; sl@0: RequestPolicy(); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Defines the duration of tone on, tone off and tone pause to be used during the sl@0: * DTMF tone playback operation. sl@0: * sl@0: * Supported only during tone playing. sl@0: * sl@0: * @param "TTimeIntervalMicroSeconds32& aToneOnLength" sl@0: * The period over which the tone will be played. If this is set to sl@0: * zero, then the tone is not played. sl@0: * sl@0: * @param "TTimeIntervalMicroSeconds32& aToneOffLength" sl@0: * The period over which the no tone will be played. sl@0: * sl@0: * @param "TTimeIntervalMicroSeconds32& aPauseLength" sl@0: * The period over which the tone playing will be paused. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::SetDTMFLengths(TTimeIntervalMicroSeconds32& aToneOnLength, sl@0: TTimeIntervalMicroSeconds32& aToneOffLength, sl@0: TTimeIntervalMicroSeconds32& aPauseLength) sl@0: { sl@0: sl@0: if(aToneOnLength.Int() < KMdaInfiniteDurationDTMFToneOnLength) sl@0: aToneOnLength = TTimeIntervalMicroSeconds32(0); sl@0: if(aToneOffLength.Int() < 0) sl@0: aToneOffLength = TTimeIntervalMicroSeconds32(0); sl@0: if(aPauseLength.Int() < 0) sl@0: aPauseLength = TTimeIntervalMicroSeconds32(0); sl@0: sl@0: iDTMFGen.SetToneDurations(aToneOnLength,aToneOffLength,aPauseLength); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Defines the period over which the volume level is to rise smoothly from sl@0: * nothing to the normal volume level. sl@0: * sl@0: * @param "TTimeIntervalMicroSeconds& aRampDuration" sl@0: * The period over which the volume is to rise. A zero value causes sl@0: * the tone sample to be played at the normal level for the full sl@0: * duration of the playback. A value, which is longer than the duration sl@0: * of the tone sample, that the sample never reaches its normal sl@0: * volume level. sl@0: * sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::SetVolumeRamp(const TTimeIntervalMicroSeconds& aRampDuration) sl@0: { sl@0: // save ramp duration for tone generator sl@0: iRampDuration = aRampDuration; sl@0: sl@0: SetDeviceVolumeRamp(iRampDuration); sl@0: } sl@0: sl@0: /** sl@0: * Sets volume ramp on HwDevice. sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::SetDeviceVolumeRamp(const TTimeIntervalMicroSeconds& aRampDuration) sl@0: { sl@0: TInt error = KErrNone; sl@0: if (iPlayCustomInterface) sl@0: iPlayCustomInterface->SetVolumeRamp(aRampDuration); sl@0: else sl@0: error = KErrNotReady; sl@0: return error; sl@0: } sl@0: sl@0: /** sl@0: * @see sounddevice.h sl@0: */ sl@0: void CMMFDevSoundSvrImp::GetSupportedInputDataTypesL(RArray& aSupportedDataTypes, const TMMFPrioritySettings& /*aPrioritySettings*/) const sl@0: { sl@0: //aPrioritySettings not used on ref DevSound sl@0: //search for playing datatypes sl@0: iDevSoundUtil->SeekHwDevicePluginsL(aSupportedDataTypes, EMMFStatePlaying); sl@0: #ifdef SYMBIAN_MULTIMEDIA_CODEC_API sl@0: // append list of codec plugins sl@0: iDevSoundUtil->SeekCodecPluginsL(aSupportedDataTypes, EMMFStatePlaying, ETrue); sl@0: #endif // SYMBIAN_MULTIMEDIA_CODEC_API sl@0: } sl@0: sl@0: /** sl@0: * @see sounddevice.h sl@0: */ sl@0: void CMMFDevSoundSvrImp::GetSupportedOutputDataTypesL(RArray& aSupportedDataTypes, const TMMFPrioritySettings& /*aPrioritySettings*/) const sl@0: { sl@0: //aPrioritySettings not used on ref DevSound sl@0: // search for recording datatypes sl@0: iDevSoundUtil->SeekHwDevicePluginsL(aSupportedDataTypes, EMMFStateRecording); sl@0: #ifdef SYMBIAN_MULTIMEDIA_CODEC_API sl@0: // append list of codec plugins sl@0: iDevSoundUtil->SeekCodecPluginsL(aSupportedDataTypes, EMMFStateRecording, ETrue); sl@0: #endif // SYMBIAN_MULTIMEDIA_CODEC_API sl@0: } sl@0: sl@0: TInt CMMFDevSoundSvrImp::RegisterAsClient(TUid aEventType, const TDesC8& aNotificationRegistrationData) sl@0: { sl@0: return iAudioPolicyProxy->RequestResourceNotification(aEventType,aNotificationRegistrationData); sl@0: } sl@0: sl@0: TInt CMMFDevSoundSvrImp::CancelRegisterAsClient(TUid aEventType) sl@0: { sl@0: return iAudioPolicyProxy->CancelRequestResourceNotification(aEventType); sl@0: } sl@0: sl@0: TInt CMMFDevSoundSvrImp::GetResourceNotificationData(TUid aEventType, TDes8& aNotificationData) sl@0: { sl@0: TInt err = KErrNone; sl@0: err = iAudioPolicyProxy->IsRegisteredResourceNotification(aEventType); sl@0: if(err == KErrNone) sl@0: { sl@0: TMMFTimeIntervalMicroSecondsPckg pckg = TTimeIntervalMicroSeconds(SamplesPlayed()); sl@0: aNotificationData.Copy(pckg); sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: TInt CMMFDevSoundSvrImp::WillResumePlay() sl@0: { sl@0: return iAudioPolicyProxy->StopNotification(); sl@0: } sl@0: sl@0: TInt CMMFDevSoundSvrImp::EmptyBuffers() sl@0: { sl@0: TInt err = KErrNone; sl@0: if (iMode != EMMFStatePlaying) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: if (!iCMMFHwDevice) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: MEmptyBuffersCustomInterface* emptybuffers = reinterpret_cast(iCMMFHwDevice->CustomInterface(KEmptyBuffersCustomInterfaceTypeUid)); sl@0: if (emptybuffers) sl@0: { sl@0: err = emptybuffers->EmptyBuffers(); sl@0: } sl@0: else sl@0: { sl@0: err = KErrNotSupported; sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: TInt CMMFDevSoundSvrImp::GetTimePlayed(TTimeIntervalMicroSeconds& aTime) sl@0: { sl@0: TInt err = KErrNone; sl@0: TTimeIntervalMicroSeconds time(0); sl@0: if(iCMMFHwDevice) sl@0: { sl@0: if(!iTimePlayedCustomInterface) sl@0: { sl@0: iTimePlayedCustomInterface = reinterpret_cast(iCMMFHwDevice->CustomInterface(KTimePlayedCustomInterfaceTypeUid)); sl@0: if(iTimePlayedCustomInterface == NULL) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: } sl@0: err = iTimePlayedCustomInterface->GetTimePlayed(time); sl@0: if(err == KErrNone && time.Int64() > 0) sl@0: { sl@0: iTimePlayed = time.Int64(); sl@0: } sl@0: } sl@0: aTime = iTimePlayed.Int64(); sl@0: return err; sl@0: } sl@0: sl@0: /******************************************************************************** sl@0: * Implementations of Non Exported public functions begins here * sl@0: ********************************************************************************/ sl@0: sl@0: // sl@0: // Audio Policy specific implementation begins here // sl@0: // sl@0: sl@0: /* sl@0: * sl@0: * Called by Audio Policy Server when a request to play is approved by the sl@0: * Audio Policy Server. sl@0: * sl@0: * Leaves on failure??. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::StartPlayDataL() sl@0: { sl@0: ASSERT(iMode== EMMFDevSoundStatePlaying); sl@0: if(iAudioPolicyPrioritySettings.iState == EMMFStateStopped) sl@0: { sl@0: return; sl@0: } sl@0: iHasPolicy = ETrue; sl@0: sl@0: TInt error = KErrNone; sl@0: sl@0: if(iCMMFHwDevice) sl@0: { sl@0: UpdatePolicyState(EMMFStatePlayData); sl@0: // Set volume and play format values sl@0: error = SetPlayFormat(iPlayFormat); sl@0: if (error == KErrNone) sl@0: error = SetDeviceVolume(iVolume); sl@0: if (error == KErrNone) sl@0: error = SetDeviceVolumeRamp(iRampDuration); sl@0: sl@0: // Initialize attribute values sl@0: iPlayedBytesCount = 0; sl@0: iTimePlayed = 0; sl@0: iLastBufferReceived = EFalse; sl@0: sl@0: // Start HwDevice sl@0: if (error == KErrNone) sl@0: error = iCMMFHwDevice->Start(EDevDecode, EDevOutFlow); sl@0: } sl@0: else sl@0: error = KErrNotReady; sl@0: sl@0: if (error != KErrNone) sl@0: { sl@0: Error(error); sl@0: sl@0: } sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Called by Audio Policy Server when a request to record is approved by the sl@0: * Audio Policy Server. sl@0: * sl@0: * Leaves on failure. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::StartRecordDataL() sl@0: { sl@0: ASSERT(iMode== EMMFDevSoundStateRecording); sl@0: if(iAudioPolicyPrioritySettings.iState == EMMFStateStopped) sl@0: { sl@0: return; sl@0: } sl@0: iHasPolicy = ETrue; sl@0: sl@0: if(iCMMFHwDevice) sl@0: { sl@0: UpdatePolicyState(EMMFStateRecordData); sl@0: TInt error = KErrNone; sl@0: error = SetRecordFormat(iRecordFormat); sl@0: if (error != KErrNone) sl@0: { sl@0: Error(error); sl@0: return; sl@0: sl@0: } sl@0: error = SetDeviceRecordLevel(iGain); sl@0: if (error != KErrNone) sl@0: { sl@0: Error(error); sl@0: return; sl@0: sl@0: } sl@0: error = iCMMFHwDevice->Start(EDevEncode, EDevInFlow); sl@0: if (iHwDeviceBuffer) sl@0: iHwDeviceBuffer->SetLastBuffer(EFalse); sl@0: sl@0: if (error != KErrNone) sl@0: { sl@0: Error(error); sl@0: return; sl@0: } sl@0: } sl@0: else sl@0: iDevSoundObserver->RecordError(KErrNotReady); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Called by Audio Policy Server when a request to play tone is approved by sl@0: * the Audio Policy Server. sl@0: * sl@0: * Leaves on failure. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::StartPlayToneL() sl@0: { sl@0: ASSERT(iMode == EMMFDevSoundStateTonePlaying); sl@0: if(iAudioPolicyPrioritySettings.iState == EMMFStateStopped) sl@0: { sl@0: return; sl@0: } sl@0: iHasPolicy = ETrue; sl@0: sl@0: if(iCMMFHwDevice) sl@0: { sl@0: UpdatePolicyState(EMMFStatePlayTone); sl@0: TInt error = KErrNone; sl@0: // Set volume and play format values sl@0: error = SetPlayFormat(iPlayFormat); sl@0: if (error != KErrNone) sl@0: { sl@0: Error(error); sl@0: return; sl@0: sl@0: } sl@0: if (iHwDeviceID.iUid == KMmfUidHwDevicePCM16ToPCM16) sl@0: error = SetDeviceVolume(iVolume); sl@0: else sl@0: error = KErrGeneral;//hw device should always be pcm16 for tone sl@0: sl@0: // turn off volume ramping - this is done in software below sl@0: if (error == KErrNone) sl@0: error = SetDeviceVolumeRamp(TTimeIntervalMicroSeconds(0)); sl@0: sl@0: if (error != KErrNone) sl@0: { sl@0: Error(error); sl@0: return; sl@0: sl@0: } sl@0: sl@0: // Initialize attribute values sl@0: iPlayedBytesCount = 0; sl@0: iTimePlayed = 0; sl@0: // Configure tone generator sl@0: iToneGen.Configure( sl@0: iPlayFormat().iRate, sl@0: iPlayFormat().iChannels, sl@0: iRepeatCount, sl@0: I64LOW((iRepeatTrailingSilence.Int64()*iPlayFormat().iRate)/1000000), sl@0: I64LOW((iRampDuration.Int64()*iPlayFormat().iRate)/1000000) sl@0: ); sl@0: sl@0: iCurrentGenerator = &iToneGen; sl@0: sl@0: // Start playback sl@0: DoPlayL(); sl@0: } sl@0: else sl@0: iDevSoundObserver->ToneFinished(KErrNotReady); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Called by Audio Policy Server when a request to play a dual tone is approved by sl@0: * the Audio Policy Server. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::StartPlayDualToneL() sl@0: { sl@0: ASSERT(iMode == EMMFDevSoundStateTonePlaying); sl@0: if(iAudioPolicyPrioritySettings.iState == EMMFStateStopped) sl@0: { sl@0: return; sl@0: } sl@0: iHasPolicy = ETrue; sl@0: sl@0: if(iCMMFHwDevice) sl@0: { sl@0: UpdatePolicyState(EMMFStatePlayDualTone); sl@0: TInt error = KErrNone; sl@0: // Set volume and play format values sl@0: error = SetPlayFormat(iPlayFormat); sl@0: if (error != KErrNone) sl@0: { sl@0: Error(error); sl@0: return; sl@0: } sl@0: if (iHwDeviceID.iUid == KMmfUidHwDevicePCM16ToPCM16) sl@0: error = SetDeviceVolume(iVolume); sl@0: else sl@0: error = KErrGeneral;//hw device should always be pcm16 for tone sl@0: sl@0: // turn off volume ramping - this is done in software below sl@0: if (error == KErrNone) sl@0: error = SetDeviceVolumeRamp(TTimeIntervalMicroSeconds(0)); sl@0: sl@0: if (error != KErrNone) sl@0: { sl@0: Error(error); sl@0: return; sl@0: sl@0: } sl@0: sl@0: // Initialize attribute values sl@0: iPlayedBytesCount = 0; sl@0: iTimePlayed = 0; sl@0: // Configure dual tone generator sl@0: iDualToneGen.Configure( sl@0: iPlayFormat().iRate, sl@0: iPlayFormat().iChannels, sl@0: iRepeatCount, sl@0: I64LOW((iRepeatTrailingSilence.Int64()*iPlayFormat().iRate)/KOneMillionMicroSeconds), sl@0: I64LOW((iRampDuration.Int64()*iPlayFormat().iRate)/KOneMillionMicroSeconds) sl@0: ); sl@0: sl@0: iCurrentGenerator = &iDualToneGen; sl@0: sl@0: // Start playback sl@0: DoPlayL(); sl@0: } sl@0: else sl@0: iDevSoundObserver->ToneFinished(KErrNotReady); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Called by Audio Policy Server when a request to play DTMF String is approved sl@0: * by the Audio Policy Server. sl@0: * sl@0: * Leaves on failure. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::StartPlayDTMFStringL() sl@0: { sl@0: ASSERT(iMode == EMMFDevSoundStateTonePlaying); sl@0: if(iAudioPolicyPrioritySettings.iState == EMMFStateStopped) sl@0: { sl@0: return; sl@0: } sl@0: iHasPolicy = ETrue; sl@0: sl@0: if(iCMMFHwDevice) sl@0: { sl@0: UpdatePolicyState(EMMFStatePlayDTMFString); sl@0: TInt error = KErrNone; sl@0: // Set volume and play format values sl@0: error = SetPlayFormat(iPlayFormat); sl@0: if (error != KErrNone) sl@0: { sl@0: Error(error); sl@0: return; sl@0: sl@0: } sl@0: error = SetDeviceVolume(iVolume); sl@0: sl@0: // turn off volume ramping - this is done in software below sl@0: if (error == KErrNone) sl@0: error = SetDeviceVolumeRamp(TTimeIntervalMicroSeconds(0)); sl@0: sl@0: if (error != KErrNone) sl@0: { sl@0: Error(error); sl@0: return; sl@0: } sl@0: sl@0: // Initialize attribute values sl@0: iPlayedBytesCount = 0; sl@0: iTimePlayed = 0; sl@0: iDTMFGen.Configure( sl@0: iPlayFormat().iRate, sl@0: iPlayFormat().iChannels, sl@0: iRepeatCount, sl@0: I64LOW((iRepeatTrailingSilence.Int64()*iPlayFormat().iRate)/1000000), sl@0: I64LOW((iRampDuration.Int64()*iPlayFormat().iRate)/1000000) sl@0: ); sl@0: sl@0: iCurrentGenerator = &iDTMFGen; sl@0: sl@0: // Start playback sl@0: //need to trap this as we can leave with KErrUnderflow sl@0: //if there was no data to play - the error has already sl@0: //been sent to the observer and we don't want to call RunError sl@0: TRAP(error,DoPlayL()); sl@0: if ((error != KErrUnderflow)&&(error != KErrNone)) sl@0: { sl@0: User::Leave(error); sl@0: } sl@0: } sl@0: else sl@0: iDevSoundObserver->ToneFinished(KErrNotReady); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Called by Audio Policy Server when a request to play tone sequence is sl@0: * approved by the Audio Policy Server. sl@0: * sl@0: * Leaves on failure. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::StartPlayToneSequenceL() sl@0: { sl@0: ASSERT(iMode == EMMFDevSoundStateTonePlaying); sl@0: if(iAudioPolicyPrioritySettings.iState == EMMFStateStopped) sl@0: { sl@0: return; sl@0: } sl@0: iHasPolicy = ETrue; sl@0: sl@0: if(iCMMFHwDevice) sl@0: { sl@0: UpdatePolicyState(EMMFStatePlayToneSequence); sl@0: TInt error = KErrNone; sl@0: // Set volume and play format values sl@0: if (iHwDeviceID.iUid == KMmfUidHwDevicePCM16ToPCM16) sl@0: error = SetPlayFormat(iPlayFormat); sl@0: else error = KErrGeneral;//hw device should always be pcm16 for tone sl@0: if (error != KErrNone) sl@0: { sl@0: Error(error); sl@0: return; sl@0: } sl@0: sl@0: if (iHwDeviceID.iUid == KMmfUidHwDevicePCM16ToPCM16) sl@0: error = SetDeviceVolume(iVolume); sl@0: else sl@0: error = KErrGeneral;//hw device should always be pcm16 for tone sl@0: sl@0: // turn off volume ramping - this is done in software below sl@0: if (error == KErrNone) sl@0: error = SetDeviceVolumeRamp(TTimeIntervalMicroSeconds(0)); sl@0: sl@0: if (error != KErrNone) sl@0: { sl@0: Error(error); sl@0: return; sl@0: } sl@0: sl@0: // Initialize attribute values sl@0: iPlayedBytesCount = 0; sl@0: iTimePlayed = 0; sl@0: iSequenceGen.Configure( sl@0: iPlayFormat().iRate, sl@0: iPlayFormat().iChannels, sl@0: iRepeatCount, sl@0: I64LOW((iRepeatTrailingSilence.Int64()*iPlayFormat().iRate)/1000000), sl@0: I64LOW((iRampDuration.Int64()*iPlayFormat().iRate)/1000000) sl@0: ); sl@0: sl@0: iCurrentGenerator = &iSequenceGen; sl@0: sl@0: // Start playback sl@0: DoPlayL(); sl@0: } sl@0: else sl@0: iDevSoundObserver->ToneFinished(KErrNotReady); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Called by Audio Policy Server when the current DevSound instance looses the sl@0: * policy because of another instance with a higher priority wants the device. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::SendEventToClient(const TMMFEvent& aEvent) sl@0: { sl@0: if (aEvent.iErrorCode != KErrNone) sl@0: { sl@0: iHasPolicy = EFalse; sl@0: if (iMode == EMMFDevSoundStatePlaying) sl@0: { sl@0: UpdateBytesPlayed(); sl@0: iDevSoundObserver->PlayError(aEvent.iErrorCode); sl@0: UpdatePolicyState(EMMFStateStopped); sl@0: } sl@0: else if (iMode == EMMFDevSoundStateRecording) sl@0: { sl@0: iDevSoundObserver->RecordError(aEvent.iErrorCode); sl@0: UpdatePolicyState(EMMFStateStopped); sl@0: } sl@0: else if (iMode == EMMFDevSoundStateTonePlaying) sl@0: { sl@0: iDevSoundObserver->ToneFinished(aEvent.iErrorCode); sl@0: } sl@0: iCMMFHwDevice->Stop();//unloads sound device sl@0: // Have audio Policy launch higher priority request sl@0: iAudioPolicyProxy->LaunchRequests(); sl@0: } sl@0: else sl@0: { sl@0: iHasPolicy = ETrue; sl@0: iDevSoundObserver->SendEventToClient(aEvent); sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: * sl@0: * Sets volume on HwDevice. sl@0: * sl@0: * @return "TInt" sl@0: * Error value returned by HwDevice. sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::SetDeviceVolume(TInt aVolume) sl@0: { sl@0: TInt error = KErrNone; sl@0: if (iPlayCustomInterface) sl@0: iPlayCustomInterface->SetVolume(aVolume); sl@0: else error = KErrNotReady; sl@0: return error; sl@0: } sl@0: sl@0: /** sl@0: * sl@0: * Sets PlayFormat on HwDevice. sl@0: * sl@0: * sl@0: * @return "TInt" sl@0: * Error value returned by HwDevice. sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::SetPlayFormat(RMdaDevSound::TCurrentSoundFormatBuf& aPlayFormat) sl@0: { sl@0: TInt error = KErrNone; sl@0: if (iCMMFHwDevice) sl@0: { sl@0: TTaskConfig taskConfig; sl@0: taskConfig.iUid = KUidRefDevSoundTaskConfig; sl@0: taskConfig.iRate = aPlayFormat().iRate; sl@0: sl@0: if (aPlayFormat().iChannels == 1) sl@0: { sl@0: taskConfig.iStereoMode = ETaskMono; sl@0: } sl@0: else if (aPlayFormat().iChannels == 2) sl@0: { sl@0: taskConfig.iStereoMode = ETaskInterleaved; sl@0: } sl@0: else sl@0: { sl@0: return KErrArgument; sl@0: } sl@0: sl@0: error = iCMMFHwDevice->SetConfig(taskConfig); sl@0: //note the iEncoding and iBufferSize are already determined by the sl@0: //CMMFHwDevice plugin and so are not set. sl@0: } sl@0: else sl@0: { sl@0: error = KErrNotReady; sl@0: } sl@0: return error; sl@0: } sl@0: sl@0: sl@0: /** sl@0: * sl@0: * Sets RecordFormat on HwDevice. sl@0: * sl@0: * sl@0: * @return "TInt" sl@0: * Error value returned by HwDevice. sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::SetRecordFormat(RMdaDevSound::TCurrentSoundFormatBuf& aRecordFormat) sl@0: { sl@0: TInt error = KErrNone; sl@0: if (iCMMFHwDevice) sl@0: { sl@0: TTaskConfig taskConfig; sl@0: taskConfig.iUid = KUidRefDevSoundTaskConfig; sl@0: taskConfig.iRate = aRecordFormat().iRate; sl@0: sl@0: if (aRecordFormat().iChannels == 1) sl@0: { sl@0: taskConfig.iStereoMode = ETaskMono; sl@0: } sl@0: else if (aRecordFormat().iChannels == 2) sl@0: { sl@0: taskConfig.iStereoMode = ETaskInterleaved; sl@0: } sl@0: else sl@0: { sl@0: return KErrArgument; sl@0: } sl@0: sl@0: error = iCMMFHwDevice->SetConfig(taskConfig); sl@0: //note the iEncoding and iBufferSize are already determined by the sl@0: //CMMFHwDevice plugin and so are not set. sl@0: } sl@0: else sl@0: { sl@0: error = KErrNotReady; sl@0: } sl@0: return error; sl@0: } sl@0: sl@0: sl@0: /** sl@0: * sl@0: * Sets record level on HwDevice. sl@0: * sl@0: * sl@0: * @return "TInt" sl@0: * Error value returned by HwDevice. sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::SetDeviceRecordLevel(TInt aGain) sl@0: { sl@0: TInt error = KErrNone; sl@0: if (iRecordCustomInterface) sl@0: iRecordCustomInterface->SetGain(aGain); sl@0: else error = KErrNotReady; sl@0: return error; sl@0: sl@0: } sl@0: sl@0: sl@0: /** sl@0: * sl@0: * MMMFHwDeviceObserver mixin implementation. sl@0: * sl@0: * The CMMFHwDevice implementation object calls this method during decoding sl@0: * (playing), when it needs the encoded data in the buffer sl@0: * aHwDataBuffer. sl@0: * sl@0: * @return "TInt" sl@0: * Error code. KErrNone if success. sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::FillThisHwBuffer(CMMFBuffer& aHwDataBuffer) sl@0: { sl@0: TInt err = KErrNone; sl@0: // Keep a reference to this Hw data Buffer. We need to send the sl@0: // reference back to HwDevice implementation sl@0: iHwDeviceBuffer = static_cast (&aHwDataBuffer); sl@0: // Set the request length, From HwDevice this comes with buffer sl@0: // length. sl@0: TInt len = iHwDeviceBuffer->Data().MaxLength(); sl@0: // Ignore error. since buffer size = Buffer Length sl@0: TRAP(err, iHwDeviceBuffer->SetRequestSizeL(len)); sl@0: sl@0: if (iMode== EMMFDevSoundStatePlaying) // Get Data from Observer sl@0: { sl@0: if (iLastBufferReceived) sl@0: { sl@0: iHwDeviceBuffer->Data().SetLength(0); sl@0: // Pass the buffer to the he device sl@0: err = iCMMFHwDevice->ThisHwBufferFilled(*iHwDeviceBuffer); sl@0: } sl@0: else sl@0: // Pass the buffer to the observer sl@0: iDevSoundObserver->BufferToBeFilled(&aHwDataBuffer); sl@0: } sl@0: else if (iMode == EMMFDevSoundStateTonePlaying) sl@0: { sl@0: // Hw device will call this method right after its Start was called. sl@0: // When it calls this for the first time it hasn't played one single sl@0: // buffer yet so check that. sl@0: // In this case there's no need to set the active buffer as it's already sl@0: // waiting to be played. sl@0: if (!iFirstCallFromHwDevice) sl@0: SetActiveToneBuffer(); sl@0: sl@0: // If there is no data in the active buffer, tone play is finished. sl@0: // DevSound just have to wait for completion event from audio device. sl@0: if (iActiveToneBuffer->Data().Length() > 0) sl@0: { sl@0: TInt tonelen = iActiveToneBuffer->Data().Length(); sl@0: sl@0: // don't enter more data than can be handled by the receiving buffer sl@0: if (len >= tonelen) len = tonelen; sl@0: sl@0: // Copy data from tone buffer to hw device buffer sl@0: Mem::Copy((TAny*)(iHwDeviceBuffer->Data().Ptr()), (TAny*)(iActiveToneBuffer->Data().Ptr()), len); sl@0: sl@0: iHwDeviceBuffer->Data().SetLength(len); sl@0: // Play data and try to generate next data block sl@0: err = iCMMFHwDevice->ThisHwBufferFilled(*iHwDeviceBuffer); sl@0: if (err != KErrNone) sl@0: return err; sl@0: // Check again whether this is the first call from Hw device. sl@0: // FillFreeToneBuffer assumes the iActiveToneBuffer has already sl@0: // been played. sl@0: if (!iFirstCallFromHwDevice) sl@0: err = FillFreeToneBuffer(); sl@0: else sl@0: iFirstCallFromHwDevice = EFalse; // Reset flag sl@0: sl@0: } sl@0: else if (iFirstCallFromHwDevice) sl@0: {//we have no data in the tone buffer and thus have no sl@0: //outstanding requests to play sl@0: err = KErrUnderflow; //simulate underrun sl@0: } sl@0: else sl@0: { sl@0: iHwDeviceBuffer->Data().SetLength(0); sl@0: iHwDeviceBuffer->SetLastBuffer(ETrue); sl@0: // Send an empty last buffer to HwDevice to get a play completion event with KErrUnderflow sl@0: err = iCMMFHwDevice->ThisHwBufferFilled(*iHwDeviceBuffer); sl@0: } sl@0: sl@0: // If there was an error filling the buffer could be corrupt data sl@0: // notify the client and stop playing.Set err to KErrNone. sl@0: if (err != KErrNone) sl@0: { sl@0: Error(err);//Updates Bytes played informs client sl@0: err = KErrNone; sl@0: iCMMFHwDevice->Stop();//unloads sound device sl@0: } sl@0: } sl@0: else sl@0: { sl@0: err = KErrGeneral; sl@0: Error(err); sl@0: iCMMFHwDevice->Stop();//unloads sound device sl@0: sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: * sl@0: * MMMFHwDeviceObserver mixin implementation. sl@0: * sl@0: * The CMMFHwDevice implementation object calls this method during encoding sl@0: * (recording), when it fills the buffer aHwDataBuffer with sl@0: * encoded data. sl@0: * sl@0: * @return "TInt" sl@0: * Error code. KErrNone if success. sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::EmptyThisHwBuffer(CMMFBuffer& aHwDataBuffer) sl@0: { sl@0: TInt err = KErrNone; sl@0: if(iMode== EMMFDevSoundStateRecording) sl@0: { sl@0: // Keep a reference to this Hw data Buffer. We need to send the sl@0: // reference back to HwDevice implementation sl@0: iHwDeviceBuffer = static_cast(&aHwDataBuffer); sl@0: sl@0: // Set the request length, From HwDevice this comes with buffer sl@0: // length. MMF will use RequestSize attribute of the buffer. sl@0: // We can avoid this by setting in HwDevice implemenation sl@0: TInt len = iHwDeviceBuffer->Data().Length(); sl@0: TRAP(err, iHwDeviceBuffer->SetRequestSizeL(len)); sl@0: sl@0: // if we're pausing (i.e. flushing) set the last buffer flag sl@0: // when we get an empty buffer from the logical driver sl@0: if(iPaused && iHwDeviceBuffer->Data().Length() == 0) sl@0: { sl@0: iPaused = EFalse; sl@0: sl@0: iHwDeviceBuffer->SetLastBuffer(ETrue); sl@0: sl@0: iDevSoundEventHandler->CancelReceiveEvents(); sl@0: sl@0: } sl@0: sl@0: // Send Data from Observer sl@0: iDevSoundObserver->BufferToBeEmptied(iHwDeviceBuffer); sl@0: } sl@0: else sl@0: { sl@0: err = KErrGeneral; sl@0: Error(err); sl@0: iCMMFHwDevice->Stop();//unloads sound device sl@0: sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: * sl@0: * MMMFHwDeviceObserver mixin implementation. sl@0: * sl@0: * The CMMFHwDevice implementation object calls this method when a message from sl@0: * the hardware device implementation is received. sl@0: * sl@0: * @return "TInt" sl@0: * Error code. KErrNone if success. sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::MsgFromHwDevice(TUid aMessageType, const TDesC8& /*aMsg*/) sl@0: { sl@0: TInt result = KErrNotSupported; sl@0: if (aMessageType.iUid == KMmfHwDeviceObserverUpdateBytesPlayed) sl@0: {//this is used by sw codec wrapper to request a bytes played update sl@0: //bytes played won't be updated in Stopped() or Error() on sw cdoec wrapper sl@0: //as the sound device is closed. Non swCodec wrapper Hw device plugins sl@0: //can get there bytes updated on Stopped() and/or Error() sl@0: UpdateBytesPlayed(); sl@0: result = KErrNone; sl@0: } sl@0: return result; sl@0: } sl@0: sl@0: /** sl@0: * sl@0: * MMMFHwDeviceObserver mixin implementation. sl@0: * sl@0: * The CMMFHwDevice implementation object calls this method when the current sl@0: * encode or decode task is finished or stopped. The policy state is updated sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::Stopped() sl@0: { sl@0: //for swcodec wrap hw devices bytes played updated in MsgFromHwDevice sl@0: //but non Swcodec wrappers hw devices may do it differently sl@0: //also don't know if non Swcodec wrap hw device will call Stopped or Error first sl@0: UpdateBytesPlayed(); sl@0: sl@0: iLastBufferReceived = EFalse; sl@0: UpdatePolicyState(EMMFStateCompleted); sl@0: } sl@0: sl@0: /** sl@0: * MMMFHwDeviceObserver mixin implementation sl@0: * Processes error from hw device sl@0: */ sl@0: void CMMFDevSoundSvrImp::Error(TInt aError) sl@0: { sl@0: if (iMode== EMMFDevSoundStatePlaying) sl@0: { sl@0: //for swcodec wrap hw devices bytes played updated in MsgFromHwDevice sl@0: //but non Swcodec wrappers hw devices may do it differently sl@0: //also don't know if non Swcodec wrap hw device will call Stopped or Error first sl@0: UpdateBytesPlayed(); sl@0: sl@0: iDevSoundObserver->PlayError(aError); sl@0: UpdatePolicyState(EMMFStateStopped); sl@0: } sl@0: else if (iMode== EMMFDevSoundStateRecording) sl@0: { sl@0: iDevSoundObserver->RecordError(aError); sl@0: UpdatePolicyState(EMMFStateStopped); sl@0: } sl@0: else if (iMode== EMMFDevSoundStateTonePlaying) sl@0: { sl@0: iDevSoundObserver->ToneFinished(aError); sl@0: UpdatePolicyState(EMMFStateStopped); sl@0: } sl@0: //else can't handle error sl@0: } sl@0: sl@0: sl@0: /******************************************************************************** sl@0: * Non Exported public functions ends here * sl@0: ********************************************************************************/ sl@0: sl@0: sl@0: /******************************************************************************** sl@0: * Private functions begins here * sl@0: ********************************************************************************/ sl@0: sl@0: TInt CMMFDevSoundSvrImp::InitializeFormat(RMdaDevSound::TSoundFormatsSupportedBuf& aSupportedFormat, sl@0: RMdaDevSound::TCurrentSoundFormatBuf& aFormat) sl@0: { sl@0: // Choose an encoding sl@0: TUint32 enc = aSupportedFormat().iEncodings; sl@0: // Always defaults to this sl@0: if (enc & RMdaDevSound::EMdaSoundEncoding16BitPCM) sl@0: aFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM; sl@0: else if (enc & RMdaDevSound::EMdaSoundEncoding8BitALaw) sl@0: aFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitALaw; sl@0: else if (enc & RMdaDevSound::EMdaSoundEncoding8BitMuLaw) sl@0: aFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitMuLaw; sl@0: else if (enc & RMdaDevSound::EMdaSoundEncoding8BitPCM) sl@0: aFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitPCM; sl@0: sl@0: // default to Monophonic playback: sl@0: aFormat().iChannels=1; sl@0: sl@0: // Store the device capabilities (WINS supports from 8000 Hz to 44100 Hz) sl@0: if ((aSupportedFormat().iMinRate <= 8000) && (8000 <= aSupportedFormat().iMaxRate)) sl@0: iDeviceCapabilities.iRate = EMMFSampleRate8000Hz; sl@0: if ((aSupportedFormat().iMinRate <= 11025) && (11025 <= aSupportedFormat().iMaxRate)) sl@0: iDeviceCapabilities.iRate |= EMMFSampleRate11025Hz; sl@0: if ((aSupportedFormat().iMinRate <= 12000) && (12000 <= aSupportedFormat().iMaxRate)) sl@0: iDeviceCapabilities.iRate |= EMMFSampleRate12000Hz; sl@0: if ((aSupportedFormat().iMinRate <= 16000) && (16000 <= aSupportedFormat().iMaxRate)) sl@0: iDeviceCapabilities.iRate |= EMMFSampleRate16000Hz; sl@0: if ((aSupportedFormat().iMinRate <= 22050) && (22050 <= aSupportedFormat().iMaxRate)) sl@0: iDeviceCapabilities.iRate |= EMMFSampleRate22050Hz; sl@0: if ((aSupportedFormat().iMinRate <= 24000) && (24000 <= aSupportedFormat().iMaxRate)) sl@0: iDeviceCapabilities.iRate |= EMMFSampleRate24000Hz; sl@0: if ((aSupportedFormat().iMinRate <= 32000) && (32000 <= aSupportedFormat().iMaxRate)) sl@0: iDeviceCapabilities.iRate |= EMMFSampleRate32000Hz; sl@0: if ((aSupportedFormat().iMinRate <= 44100) && (44100 <= aSupportedFormat().iMaxRate)) sl@0: iDeviceCapabilities.iRate |= EMMFSampleRate44100Hz; sl@0: if ((aSupportedFormat().iMinRate <= 48000) && (48000 <= aSupportedFormat().iMaxRate)) sl@0: iDeviceCapabilities.iRate |= EMMFSampleRate48000Hz; sl@0: if ((aSupportedFormat().iMinRate <= 64000) && (64000 <= aSupportedFormat().iMaxRate)) sl@0: iDeviceCapabilities.iRate |= EMMFSampleRate64000Hz; sl@0: if ((aSupportedFormat().iMinRate <= 88200) && (88200 <= aSupportedFormat().iMaxRate)) sl@0: iDeviceCapabilities.iRate |= EMMFSampleRate88200Hz; sl@0: if ((aSupportedFormat().iMinRate <= 96000) && (96000 <= aSupportedFormat().iMaxRate)) sl@0: iDeviceCapabilities.iRate |= EMMFSampleRate96000Hz; sl@0: sl@0: // Store the encodings supported sl@0: iDeviceCapabilities.iEncoding = 0; sl@0: if (enc & RMdaDevSound::EMdaSoundEncoding16BitPCM) sl@0: iDeviceCapabilities.iEncoding |= EMMFSoundEncoding16BitPCM; sl@0: if (enc & RMdaDevSound::EMdaSoundEncoding8BitALaw) sl@0: iDeviceCapabilities.iEncoding |= EMMFSoundEncoding8BitALaw; sl@0: if (enc & RMdaDevSound::EMdaSoundEncoding8BitMuLaw) sl@0: iDeviceCapabilities.iEncoding |= EMMFSoundEncoding8BitMuLaw; sl@0: if (enc & RMdaDevSound::EMdaSoundEncoding8BitPCM) sl@0: iDeviceCapabilities.iEncoding |= EMMFSoundEncoding8BitPCM; sl@0: sl@0: // Mono and Stereo support sl@0: if (aSupportedFormat().iChannels == 2) sl@0: iDeviceCapabilities.iChannels = EMMFStereo; sl@0: iDeviceCapabilities.iChannels |= EMMFMono; sl@0: sl@0: iDeviceCapabilities.iBufferSize = aSupportedFormat().iMaxBufferSize; sl@0: // Default sl@0: iDeviceConfig.iRate = EMMFSampleRate8000Hz; sl@0: iDeviceConfig.iEncoding = EMMFSoundEncoding16BitPCM; sl@0: iDeviceConfig.iChannels = EMMFMono; sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Makes request to Policy Server (asynchronous call) sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::RequestPolicy() sl@0: { sl@0: iDevSoundEventHandler->CancelReceiveEvents(); sl@0: iDevSoundEventHandler->ReceiveEvents(); sl@0: iAudioPolicyPrioritySettings.iCapabilities = iParent.CheckClientCapabilities(); sl@0: iAudioPolicyProxy->MakeRequest(iAudioPolicyPrioritySettings); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Creates buffer and begin playback using the specified tone generator. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::DoPlayL() sl@0: { sl@0: // Delete any buffer from previous call and try to create maximum buffer sl@0: // size. Double Buffer the Tone data. sl@0: if (iToneBuffer1) sl@0: { sl@0: delete iToneBuffer1; sl@0: iToneBuffer1 = NULL; sl@0: } sl@0: //note the tone buffer needs to be the same as the pcm16->pcm16 'null' sl@0: //hw device plugin sl@0: // Buffer size = (SampleRate * BytesPerSample * Channels) / 4 sl@0: TInt useBufferOfSize = ((SamplingFrequency() * 2 * NumberOfChannels())/KDevSoundFramesPerSecond + (KDevSoundDeltaFrameSize-1)) &~ (KDevSoundDeltaFrameSize-1); sl@0: //clamp buffer to desired limits sl@0: if(useBufferOfSize < KDevSoundMinFrameSize) sl@0: useBufferOfSize = KDevSoundMinFrameSize; sl@0: else if(useBufferOfSize > KDevSoundMaxFrameSize) sl@0: useBufferOfSize = KDevSoundMaxFrameSize; sl@0: sl@0: //clamp buffer to limits of hardware sl@0: if(useBufferOfSize < Max(iPlayFormatsSupported().iMinBufferSize, iRecordFormatsSupported().iMinBufferSize)) sl@0: useBufferOfSize = Max(iPlayFormatsSupported().iMinBufferSize, iRecordFormatsSupported().iMinBufferSize); sl@0: else if(useBufferOfSize > Min(iPlayFormatsSupported().iMaxBufferSize, iRecordFormatsSupported().iMaxBufferSize)) sl@0: useBufferOfSize = Min(iPlayFormatsSupported().iMaxBufferSize, iRecordFormatsSupported().iMaxBufferSize); sl@0: sl@0: iToneBuffer1 = CMMFDataBuffer::NewL(useBufferOfSize); sl@0: User::LeaveIfError(iCurrentGenerator->FillBuffer(iToneBuffer1->Data())); sl@0: sl@0: if (iToneBuffer2) sl@0: { sl@0: delete iToneBuffer2; sl@0: iToneBuffer2 = NULL; sl@0: } sl@0: iToneBuffer2 = CMMFDataBuffer::NewL(useBufferOfSize); sl@0: User::LeaveIfError(iCurrentGenerator->FillBuffer(iToneBuffer2->Data())); sl@0: sl@0: // Assign active buffer sl@0: iActiveToneBuffer = iToneBuffer1; sl@0: sl@0: // Hw device hasn't played anything yet so don't change sl@0: // active buffer. This is checked in FillThisHwBuffer. sl@0: iFirstCallFromHwDevice = ETrue; sl@0: sl@0: // Start HwDevice to play data sl@0: User::LeaveIfError(iCMMFHwDevice->Start(EDevDecode, EDevOutFlow)); sl@0: sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * This method assigns the other buffer as active buffer. The tone audio sl@0: * generator should fill data in the other buffer by now. sl@0: * sl@0: */ sl@0: void CMMFDevSoundSvrImp::SetActiveToneBuffer() sl@0: { sl@0: if (iActiveToneBuffer == iToneBuffer1) sl@0: iActiveToneBuffer = iToneBuffer2; sl@0: else if (iActiveToneBuffer == iToneBuffer2) sl@0: iActiveToneBuffer = iToneBuffer1; sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * This method fills data into the free buffer. sl@0: * sl@0: * @return "TInt" sl@0: * Error code. KErrNone if success. sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::FillFreeToneBuffer() sl@0: { sl@0: TInt err(KErrNone); sl@0: if (iActiveToneBuffer == iToneBuffer1) sl@0: err = iCurrentGenerator->FillBuffer(iToneBuffer2->Data()); sl@0: else if (iActiveToneBuffer == iToneBuffer2) sl@0: err = iCurrentGenerator->FillBuffer(iToneBuffer1->Data()); sl@0: return err; sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Updates the policy state based on Audio policy settings of this devsound instance sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::UpdatePolicyState(TMMFAudioPolicyState aNewState) sl@0: { sl@0: iAudioPolicyPrioritySettings.iState = aNewState; sl@0: TInt error = iAudioPolicyProxy->UpdateState(iAudioPolicyPrioritySettings); sl@0: if ((error == KErrNone) && (aNewState == EMMFStateStopped)) sl@0: { sl@0: iHasPolicy = EFalse; sl@0: } sl@0: sl@0: return error; sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Initializes audio device node by setting volume, and sampling rate. sl@0: * sl@0: * @return "TInt" sl@0: * Error Code. KErrNone if success. sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::InitTask() sl@0: { sl@0: // No Implementation sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: sl@0: /* sl@0: * sl@0: * Returns an integer representing Sampling Frequency the device is currently sl@0: * configured to. sl@0: * sl@0: * @return "TInt" sl@0: * Sampling Frequency. sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::SamplingFrequency() sl@0: { sl@0: if(iDeviceConfig.iRate == EMMFSampleRate8000Hz) sl@0: return 8000; sl@0: else if(iDeviceConfig.iRate == EMMFSampleRate11025Hz) sl@0: return 11025; sl@0: else if(iDeviceConfig.iRate == EMMFSampleRate12000Hz) sl@0: return 12000; sl@0: else if(iDeviceConfig.iRate == EMMFSampleRate16000Hz) sl@0: return 16000; sl@0: else if(iDeviceConfig.iRate == EMMFSampleRate22050Hz) sl@0: return 22050; sl@0: else if(iDeviceConfig.iRate == EMMFSampleRate24000Hz) sl@0: return 24000; sl@0: else if(iDeviceConfig.iRate == EMMFSampleRate32000Hz) sl@0: return 32000; sl@0: else if(iDeviceConfig.iRate == EMMFSampleRate44100Hz) sl@0: return 44100; sl@0: else if(iDeviceConfig.iRate == EMMFSampleRate48000Hz) sl@0: return 48000; sl@0: else if(iDeviceConfig.iRate == EMMFSampleRate88200Hz) sl@0: return 88200; sl@0: else if(iDeviceConfig.iRate == EMMFSampleRate96000Hz) sl@0: return 96000; sl@0: else sl@0: return 8000; //default sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Returns an integer representing number of channels the device is currently sl@0: * configured to. sl@0: * sl@0: * @return "TInt" sl@0: * Number of audio channels 1 if mono, 2 if stereo. sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::NumberOfChannels() sl@0: { sl@0: if(iDeviceConfig.iChannels == EMMFMono) sl@0: return 1; sl@0: else sl@0: return 2; sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Returns an integer representing number of bytes in each audio sample sl@0: * sl@0: * sl@0: * @return "TInt" sl@0: * Number of of bytes in each audio sample. sl@0: * sl@0: */ sl@0: TInt CMMFDevSoundSvrImp::BytesPerAudioSample() sl@0: { sl@0: TInt bytes=1; sl@0: switch (iDeviceConfig.iEncoding) sl@0: { sl@0: case EMMFSoundEncoding8BitPCM: sl@0: case EMMFSoundEncoding8BitALaw: sl@0: case EMMFSoundEncoding8BitMuLaw: sl@0: { sl@0: bytes=1; sl@0: } sl@0: break; sl@0: case EMMFSoundEncoding16BitPCM: sl@0: { sl@0: bytes=2; sl@0: } sl@0: break; sl@0: } sl@0: return bytes; sl@0: } sl@0: sl@0: sl@0: /******************************************************************************** sl@0: * Private functions ends here * sl@0: ********************************************************************************/ sl@0: sl@0: sl@0: // CustomCommand* implementation: sl@0: // The following come through from the parent object intact - currently it seems sl@0: // easier to pass this through with an RMessage, as the result parameter (at least) sl@0: // is easier to deal with that way. This might change in the future. sl@0: // [TODO - if we extended this to CMMFHwDevice, it might be easier to use some sort sl@0: // of TMMFCustomCommandParamBlock throughout, which as well as the uid, in params etc sl@0: // by value, also provided a virtual(?) function to set output param. Could then sl@0: // use in both plat sec and original code sl@0: sl@0: void CMMFDevSoundSvrImp::DoSyncCustomCommandL(const RMmfIpcMessage& aMessage) sl@0: { sl@0: TInt command = aMessage.Int0(); sl@0: sl@0: // we don't support any commands at the momment sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: void CMMFDevSoundSvrImp::DoSyncCustomCommandResultL(const RMmfIpcMessage& aMessage) sl@0: { sl@0: TInt command = aMessage.Int0(); sl@0: sl@0: // we don't support any commands at the momment sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: void CMMFDevSoundSvrImp::DoAsyncCustomCommandL(const RMmfIpcMessage& aMessage) sl@0: { sl@0: TInt command = aMessage.Int0(); sl@0: sl@0: // we don't support any commands at the momment sl@0: User::Leave(KErrNotSupported); // this will still complete for an async message sl@0: } sl@0: sl@0: void CMMFDevSoundSvrImp::DoAsyncCustomCommandResultL(const RMmfIpcMessage& aMessage) sl@0: { sl@0: TInt command = aMessage.Int0(); sl@0: sl@0: // we don't support any commands at the moment sl@0: User::Leave(KErrNotSupported); // this will still complete for an async message sl@0: } sl@0: