diff -r 000000000000 -r 40261b775718 devsound/sounddevbt/src/swcodecwrapper/mmfBtSwCodecWrapper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/devsound/sounddevbt/src/swcodecwrapper/mmfBtSwCodecWrapper.cpp Tue Feb 02 01:56:55 2010 +0200 @@ -0,0 +1,893 @@ +// Copyright (c) 2005-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 "mmfbtswcodecwrapper.h" +#include "mmfBtSwCodecPlayDataPath.h" +#include "mmfBtSwCodecRecordDataPath.h" +#include "mmfBtSwCodecConvertDataPath.h" +#include +#include "mmfBtswcodecwrapperCustomInterfaces.h" +#include "MMFBtRoutingSoundDevice.h" +#include + + +/* + * AO to handle RSD initialisation + * + */ +CRoutingSoundDeviceOpenHandler* CRoutingSoundDeviceOpenHandler::NewL(CMMFSwCodecWrapper* aObserver) + { + CRoutingSoundDeviceOpenHandler* self = new(ELeave) CRoutingSoundDeviceOpenHandler(aObserver); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CRoutingSoundDeviceOpenHandler::~CRoutingSoundDeviceOpenHandler() + { + Cancel(); + } + +void CRoutingSoundDeviceOpenHandler::RunL() + { + TInt err = iStatus.Int(); + if (iObserver) + { + iObserver->OpenComplete(err); + } + } + +void CRoutingSoundDeviceOpenHandler::DoCancel() + { + if (iObserver) + { + iObserver->OpenComplete(KErrCancel); + } + } + +CRoutingSoundDeviceOpenHandler::CRoutingSoundDeviceOpenHandler(CMMFSwCodecWrapper* aObserver) : + CActive(EPriorityStandard), + iObserver(aObserver) + + { + CActiveScheduler::Add(this); + } + +void CRoutingSoundDeviceOpenHandler::ConstructL() + { + } + +void CRoutingSoundDeviceOpenHandler::Start() + { + if (!IsActive()) + { + SetActive(); + } + } + + +/** + * Internal panic + * @internalComponent + */ +void Panic(TInt aPanicCode) + { + _LIT(KMMFSwCodecWrapperPanicCategory, "MMFSwCodecWrapper"); + User::Panic(KMMFSwCodecWrapperPanicCategory, aPanicCode); + } + + +/** + * This method is not be exported as it is only + * intended to be called within this DLL. + * It's purpose is to assign an CRoutingSoundPlayDevice to the play + * custom interface + * @internalComponent + */ +void TPlayCustomInterface::SetDevice(CRoutingSoundPlayDevice* aDevice) + { + iDevice = aDevice; + } + +void TPlayCustomInterface::SetVolume(TUint aVolume) + { + iVolume = aVolume; + if (iDevice && iDevice->Handle()) + { + iDevice->SetVolume(iVolume); + } + } + +/** + * Procedure to get the number of bytes played by the device driver + * If there is no handle available to the device driver then the + * procedure returns the last known value + * @prototype + * @return number of bytes played + */ +TUint TPlayCustomInterface::BytesPlayed() + { + if(iDevice) + { + if (iDevice->Handle()) + { + iBytesPlayed = iDevice->BytesPlayed(); + } + } + return iBytesPlayed; + } + +TTaskConfig TPlayCustomInterface::Caps() + { + TTaskConfig taskConfig; + taskConfig.iRate = 0; + taskConfig.iStereoMode = 0; + taskConfig.iUid = KUidRefDevSoundTaskConfig; + + if (iDevice && iDevice->Handle()) + { + RArray supportedSampleRates; + RArraysupportedRateRanges; + iDevice->GetSupportedSampleRates(supportedSampleRates,supportedRateRanges); + for (TUint i=0; i supportedChannels; + TMMFStereoSupport stereoSupport; + iDevice->GetSupportedChannels(supportedChannels,stereoSupport); + for (TUint i=0; iHandle()) + return taskConfig; + } + +/** + * Procedure to get the number of bytes recorded by the device + * @prototype + * @return number of bytes recorded + */ +TUint TRecordCustomInterface::BytesRecorded() + { + if(iDataPath) + { + iBytesRecorded = iDataPath->RecordedBytesCount(); + } + return iBytesRecorded; + } + +/** +Constructor. +*/ +EXPORT_C CMMFSwCodecWrapper::CMMFSwCodecWrapper() + { + } + +/** +Destructor. + +The destructor is called by ECom framework allowing derived classes +to clean up implementation specific resources. The sound +device drivers are freed. +*/ +EXPORT_C CMMFSwCodecWrapper::~CMMFSwCodecWrapper() + { + // AO to handle OpenDevice call + if (iOpenHandler && iOpenHandler->IsActive()) + { + iOpenHandler->Cancel(); + } + delete iOpenHandler; + delete iRecordDevice; + delete iPlayDevice; + delete iDataPath; + delete iCodec; + delete iPlayCustomInterface; + delete iRecordCustomInterface; + } + +/** +Initializes the hardware device tasks - in the case of a +sw codec wrapper 'hardware device' this consists of loading the +sound device drivers and creating the CMMFSwCodec. + +@param aDevInfo + Device initialization parameters. + Only the iHwDeviceObserver is used for CMFSwCodecWrapper + derived CMMFHwDevices. +@return An error code indicating if the function call was successful. KErrNone on success, otherwise + another of the system-wide error codes. +*/ +EXPORT_C TInt CMMFSwCodecWrapper::Init(THwDeviceInitParams& aDevInfo) + { + TRequestStatus status; + Init(aDevInfo,status); + User::WaitForRequest(status); + return status.Int(); + } + + +/** +Initializes the hardware device tasks - in the case of a +sw codec wrapper 'hardware device' this consists of loading the +sound device drivers and creating the CMMFSwCodec. + +@param aDevInfo + Device initialization parameters. + Only the iHwDeviceObserver is used for CMFSwCodecWrapper + derived CMMFHwDevices. +@param aStatus + Status flag belonging to an Active Object that will have its + RunL() called when this function completes +*/ +EXPORT_C void CMMFSwCodecWrapper::Init( THwDeviceInitParams &aDevInfo, + TRequestStatus& aStatus) + { + aStatus = KRequestPending; + TRequestStatus* status = &aStatus; + if (!aDevInfo.iHwDeviceObserver) + { + User::RequestComplete(status, KErrArgument); + return; + } + iHwDeviceObserver = aDevInfo.iHwDeviceObserver; + + TInt err = KErrNone; + if (aDevInfo.iOutStream.iConnection.iId) + { + iDeviceUid = TUid::Uid(aDevInfo.iOutStream.iConnection.iId); + // Play device + delete iPlayDevice; + iPlayDevice = NULL; + TRAP(err, iPlayDevice = CRoutingSoundPlayDevice::NewL()); + if (err == KErrNone) + { + iPlayDevice->Initialize(iDeviceUid, + aDevInfo.iOutStream.iDeviceName, *status); + if (!iPlayCustomInterface) + { + TRAP(err,iPlayCustomInterface = new(ELeave)TPlayCustomInterface()); + if (err) + { + delete iPlayDevice; + iPlayDevice = NULL; + User::RequestComplete(status, err); + return; + } + } + static_cast(iPlayCustomInterface)->SetDevice(iPlayDevice); + } + } + if (aDevInfo.iInStream.iConnection.iId) + { + iDeviceUid = TUid::Uid(aDevInfo.iInStream.iConnection.iId); + // Record device + TRAP(err, iRecordDevice = CRoutingSoundRecordDevice::NewL()); + if (err == KErrNone) + { + iRecordDevice->Initialize(iDeviceUid, KNullDesC8, *status); + if (!iRecordCustomInterface) + { + TRAP(err,iRecordCustomInterface = new(ELeave)TRecordCustomInterface()); + if (err) + { + delete iRecordDevice; + iRecordDevice = NULL; + User::RequestComplete(status, err); + return; + } + } + } + } + + iCodec = &(Codec()); //create codec + + //[ assert the post condition ] + if (!iCodec) + { + err = KErrNotSupported; + } + + if (err != KErrNone) + { + User::RequestComplete(status, err); + // Cancel initialisation too + if (aDevInfo.iOutStream.iConnection.iId) + { + iPlayDevice->CancelInitialize(iDeviceUid); + } + if (aDevInfo.iInStream.iConnection.iId) + { + iRecordDevice->CancelInitialize(iDeviceUid); + } + } + else if ((!aDevInfo.iOutStream.iConnection.iId)&& (!aDevInfo.iInStream.iConnection.iId)) + { + //could be used for conversion so complete the request status + User::RequestComplete(status, KErrNone); + } + + } + +/** +Starts Encoding or Decoding task(s) based on the parameter specified. + +@param aFuncCmd + The device function specifying the requested service i.e. decode or encode + where EDevEncode = Record, EDevDecode = Play and EDevNullFunc = Convert. +@param aFlowCmd + The device flow directions for requested service. + This parameter is ignored for CMMFSwCodecWrapper CMMFHwDevicePlugins +@return An error code indicating if the function call was successful. KErrNone on success, otherwise + another of the system-wide error codes. +*/ +EXPORT_C TInt CMMFSwCodecWrapper::Start(TDeviceFunc aFuncCmd, TDeviceFlow /*aFlowCmd*/) + { + TInt error = KErrNone; + + // [ precondition that aFuncCmd is valid] + if (!((aFuncCmd == EDevEncode)|(aFuncCmd == EDevDecode)|(aFuncCmd == EDevNullFunc))) + { + return KErrArgument; + } + + // [ precondition that iCodec is present] + if (!iCodec) + { + return KErrNotReady; //make sure the codec has been added + } + + switch (aFuncCmd) + { + case EDevEncode: // Audio record + { + error = StartEncode(); + } + break; + case EDevDecode: // Audio play + { + error = StartDecode(); + } + break; + case EDevNullFunc: //Audio Convert + { + error = StartConvert(); + } + break; + default: + error = KErrNotSupported; + break; + } + + //[ assert the post conditions ] +#ifdef DEBUG + if (!error) + {//only assert if no error otherwise post consitions not valid + __ASSERT_DEBUG(iDataPath, Panic(EMMFSwCodecWrapperNoDataPath)); + if ((aFuncCmd == EDevEncode)||(aFuncCmd == EDevDecode)) + { + __ASSERT_DEBUG(iDataPath->Device().Handle(), Panic(EMMFSwCodecWrapperNoDevice)); + } + } +#endif + + return error; + } + +// Use AO to OpenDevice +TInt CMMFSwCodecWrapper::StartDecode() + { + TInt error = KErrNone; + + //[ assert precondition that play custom interface is present] + //if there is no play custom interface then the user of the CMMFSwCodecWrapper + //cannot have set any of the custom settings such as sample rate. + if (!iPlayCustomInterface) + { + return KErrNotReady; + } + + //play + if (!iDataPath) + {//create a datapath + TRAP(error,iDataPath = CMMFSwCodecPlayDataPath::NewL(iPlayDevice, iDeviceUid)); + if ((iDataPath) && (error == KErrNone)) + { + iDataPath->SetObserver(*iHwDeviceObserver); + error = iDataPath->AddCodec(*iCodec); + iDeviceBufferSize = iCodec->SinkBufferSize(); + static_cast(iDataPath)->SetPlayCustomInterface(*iPlayCustomInterface); + static_cast(iDataPath)->SetConfigForAudioRamp(iSampleRate, iChannels); + } + } + + if ((error == KErrNone) && + (iDataPath->State() != CMMFSwCodecDataPath::EPlaying)) + { + TBool asynchOpen = EFalse; // Ensure we only call OpenPlayComplete once + //datapath was created ok and we are not playing + if (iDataPath->State() == CMMFSwCodecDataPath::EStopped) + { + //starting from 'fresh so set sound device settings + + // Create the AO OpenDevice handler + if (!iOpenHandler) + { + TRAP(error, iOpenHandler = CRoutingSoundDeviceOpenHandler::NewL(this)); + } + if (!error) + { + asynchOpen = ETrue; + iPlayDevice->SetBufferSize(iDeviceBufferSize); + iOpenHandler->Start(); + static_cast(iDataPath)->Device()-> + OpenDevice(iDeviceUid, iOpenHandler->iStatus); + } + } + if (!asynchOpen) + { + error = OpenPlayComplete(error); + } + + }//status == KErrNone + + return error; + } + +TInt CMMFSwCodecWrapper::StartEncode() + {//record + + //[ assert precondition that record custom interface is present] + //if there is no record custom interface then the user of the CMMFSwCodecWrapper + //cannot have set any of the custom settings such as sample rate. + if (!iRecordCustomInterface) + { + return KErrNotReady; + } + + TInt error = KErrNone; + if (!iDataPath) + { + TRAP(error,iDataPath = CMMFSwCodecRecordDataPath::NewL(iRecordDevice)); + if ((iDataPath)&&(error == KErrNone)) + { + iDataPath->SetObserver(*iHwDeviceObserver); + error = iDataPath->AddCodec(*iCodec); + iDeviceBufferSize = (iCodec->SourceBufferSize()); + static_cast(iRecordCustomInterface)->SetDataPath(static_cast(iDataPath)); + } + } + if ((error == KErrNone)&& + (iDataPath->State() != CMMFSwCodecDataPath::EPlaying)) + { + TBool asynchOpen = EFalse; // Ensure we only call OpenPlayComplete once + if (!(static_cast(iDataPath))->Device()->Handle()) + { + // Create the AO OpenDevice handler + if (!iOpenHandler) + { + TRAP(error, iOpenHandler = CRoutingSoundDeviceOpenHandler::NewL(this)); + } + if (!error) + { + asynchOpen = ETrue; + iRecordDevice->SetBufferSize(iDeviceBufferSize); + iOpenHandler->Start(); + static_cast(iDataPath)->Device()-> + OpenDevice(iDeviceUid, iOpenHandler->iStatus); + } + } + + if (!asynchOpen) + { + error = OpenRecordComplete(error); + } + } + + return error; + } + +TInt CMMFSwCodecWrapper::StartConvert() + {//convert + + TInt error = KErrNone; + if (!iDataPath) + { + TRAP(error,iDataPath = CMMFSwCodecConvertDataPath::NewL()); + if ((iDataPath)&&(error == KErrNone)) + { + iDataPath->SetObserver(*iHwDeviceObserver); + error = iDataPath->AddCodec(*iCodec); + } + } + if (error == KErrNone) + { + error = iDataPath->Start(); + } + return error; + } + +/** +Temporarily suspends the current task of decoding or encoding. + +@return An error code indicating if the function call was successful. KErrNone on success, otherwise + another of the system-wide error codes. +*/ +EXPORT_C TInt CMMFSwCodecWrapper::Pause() + { + // [ precondition that datapath exists ] + if (!iDataPath) + { + return KErrNotReady; + } + + iDataPath->Pause(); + return KErrNone; + } + +/** +Stops the current on-going task. + +@return An error code indicating if the function call was successful. KErrNone on success, otherwise + another of the system-wide error codes. +*/ +EXPORT_C TInt CMMFSwCodecWrapper::Stop() + { + // [ precondition that datapath exists ] + if (!iDataPath) + { + return KErrNotReady; + } + iDataPath->Stop(); + return KErrNone; + } + + +/** +Stops and deletes the codec. + +This default implementation simply calls DeleteCodec() and then Stop() +but real hardware devices might use this method to free up resources. + +@return An error code indicating if the function call was successful. KErrNone on success, otherwise + another of the system-wide error codes. +*/ +EXPORT_C TInt CMMFSwCodecWrapper::StopAndDeleteCodec() + { + TInt stopError = Stop(); + TInt deleteError = DeleteCodec(); + + if (stopError != KErrNone) + { + return stopError; + } + else + { + return deleteError; + } + } + +/** +Deletes the codec +This default implementation does nothing +but real hardware devices might use this method to free up resources. +@return Error code. KErrNone if successful +*/ +EXPORT_C TInt CMMFSwCodecWrapper::DeleteCodec() + { + return KErrNone; + } + +/** +Call this function to notify hardware device implementation that +data is available in aFillBufferPtr for decoding. + +@param aFillBufferPtr + The data buffer filled by the observer. + +@return An error code indicating if the function call was successful. KErrNone on success, otherwise + another of the system-wide error codes. +*/ +EXPORT_C TInt CMMFSwCodecWrapper::ThisHwBufferFilled(CMMFBuffer& aFillBufferPtr) + { + TRAPD(err,iDataPath->BufferFilledL(STATIC_CAST(CMMFDataBuffer&, aFillBufferPtr))); + return err; + } + +/** +Call this function to notify hardware device implementation that +data in aEmptyBufferPtr from encoding is processed. + +@param aBuffer + The data buffer processed by observer. + +@return An error code indicating if the function call was successful. KErrNone on success, otherwise + another of the system-wide error codes. +*/ +EXPORT_C TInt CMMFSwCodecWrapper::ThisHwBufferEmptied(CMMFBuffer& aBuffer) + { + TRAPD(err,iDataPath->BufferEmptiedL(STATIC_CAST(CMMFDataBuffer&, aBuffer))); + return err; + } + + +/** +Retrieves a custom interface to the device. +The reference CMMFSwCodecWrapper supports two standard custom interfaces, +TPlayCustomInterface and TRecordCustomInterface. + +@param aInterface + Interface UID, defined with the custom interface. + aInterface = KMmfPlayCustomInterface for TPlayCustomInterface, + aInterface = KMmfRecordCustomInterface for TRecordCustomInterface. + Actual device implementations of CMMFSwCodecWrapper may do this differently however. +@return A pointer to the interface implementation, or NULL if the device can not + implement the interface requested. The return value must be cast to the + correct type by the user. +*/ +EXPORT_C TAny* CMMFSwCodecWrapper::CustomInterface(TUid aInterface) + { + TAny* ret = NULL; + TInt err = KErrNone; + if (aInterface.iUid == KMmfPlaySettingsCustomInterface) + { + if (!iPlayCustomInterface) + { + TRAP(err,iPlayCustomInterface = new(ELeave)TPlayCustomInterface()); + } + if (err) + { + ret = NULL; + } + else + { + ret = static_cast(iPlayCustomInterface); + } + } + else if (aInterface.iUid == KMmfRecordSettingsCustomInterface) + { + if (!iRecordCustomInterface) + { + TRAP(err,iRecordCustomInterface = new(ELeave)TRecordCustomInterface()); + } + if (err) + { + ret = NULL; + } + else + { + ret = static_cast(iRecordCustomInterface); + } + } + + return ret; + } + + +/** +Used to configure the sample rate and stereo mode of a CMMFHwDevice plugin. + +The configuration of HwDevices is device specific and is not used in any of the reference +devices that return KErrNotSupported. + +@param aConfig + The device configuration. +*/ +EXPORT_C TInt CMMFSwCodecWrapper::SetConfig(TTaskConfig& aConfig) + { + TInt err = KErrNone; + if (aConfig.iUid != KUidRefDevSoundTaskConfig) + return KErrArgument; + iSampleRate = aConfig.iRate;//note we're cheating a bit + //iRate is actually a bit map enum but an actual value + //is more useful here + TMMFStereoSupport stereoSupport = EMMFNone; + if (aConfig.iStereoMode == ETaskMono) + { + iChannels = 1; + } + else if (aConfig.iStereoMode == ETaskInterleaved) + { + iChannels = 2; + stereoSupport = EMMFInterleavedOnly; + } + else //don't support non interleaved + { + return KErrNotSupported; + } + + //set values on routing sound device + if (iPlayDevice) + { + err = iPlayDevice->SetChannels(iChannels, stereoSupport); + if (!err) + { + err = iPlayDevice->SetSampleRate(iSampleRate); + } + if (!err) + {//we'll set the data type while were at it for now pcm16 only + TFourCC fourCC = KMMFFourCCCodePCM16; + err = iPlayDevice->SetDataType(fourCC); + } + } + if ((iRecordDevice) && (!err)) + { + err = iRecordDevice->SetChannels(iChannels, stereoSupport); + if (!err) + { + err = iRecordDevice->SetSampleRate(iSampleRate); + } + } + + return err; + } + +/** +Callback once CRoutingSoundPlayDevice or CRoutingSoundRecordDevice::Open has completed or continuation from +call to StartDecode / StartEncode, depending on the state. + +@internalTechnology +@param aError + The status of the device. +@return A standard Symbian wide error code. + */ +TInt CMMFSwCodecWrapper::OpenComplete(TInt aError) + { + TInt err = KErrNotSupported; // + if (iPlayDevice) + { + err = OpenPlayComplete(aError); + } + else if (iRecordDevice) + { + err = OpenRecordComplete(aError); + } + return err; + } + +/** +Callback once CRoutingSoundPlayDevice::Open has completed or continuation from +call to StartDecode, depending on the state. + +@param aError + The status of the device. +@return A standard Symbian wide error code. + */ +TInt CMMFSwCodecWrapper::OpenPlayComplete(TInt aError) + { + TInt error = aError; + + //datapath was created ok and we are not playing + if (error == KErrNone && iDataPath->State() == CMMFSwCodecDataPath::EStopped) + { + //starting from fresh so set sound device settings +// static_cast(iPlayCustomInterface)->SetDevice( +// static_cast(iDataPath)->Device() ); + static_cast(iDataPath)->Device()->SetVolume(iPlayCustomInterface->Volume()); + } + + // resuming from pause or ready to play + if ((error == KErrNone) || (error == KErrInUse)) + { + error = iDataPath->Start(); + } + + return error; + } + +/** +Callback once CRoutingSoundRecordDevice::Open has completed or continuation from +call to StartDecode, depending on the state. + +@param aError + The status of the device. +@return A standard Symbian wide error code. + */ +TInt CMMFSwCodecWrapper::OpenRecordComplete(TInt aError) + { + TInt error = aError; + + //datapath was created ok and we are not playing + if (error == KErrNone && iDataPath->State() == CMMFSwCodecDataPath::EStopped) + { + //set sound driver settings + static_cast(iDataPath)->Device() + ->SetGain(iRecordCustomInterface->Gain()); + /* + // Sample rate + (static_cast(iDataPath))->Device()->SetSampleRate(iSampleRate); + // Channels + TMMFStereoSupport stereoSupport = EMMFNone; // assume mono + if (iChannels == 2) + { + // Assume interleaved only + stereoSupport = EMMFInterleavedOnly; + } + error = (static_cast(iDataPath))->Device()->SetChannels(iChannels, stereoSupport); + */ + } + + // resuming from pause or ready to play + if ((error == KErrNone) || (error == KErrInUse)) + { + error = iDataPath->Start(); + } + + return error; + }