diff -r 000000000000 -r 40261b775718 devsound/devsoundrefplugin/src/swcodecwrapper/mmfSwCodecWrapper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/devsound/devsoundrefplugin/src/swcodecwrapper/mmfSwCodecWrapper.cpp Tue Feb 02 01:56:55 2010 +0200 @@ -0,0 +1,569 @@ +// Copyright (c) 2003-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 "mmfSwCodecPlayDataPath.h" +#include "mmfSwCodecRecordDataPath.h" +#include "mmfSwCodecConvertDataPath.h" +#include +#include "mmfswcodecwrapperCustomInterfaces.h" +#include + + + +/** + * 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 RMdaDevSound to the play + * custom interface + * @internalComponent + */ +void TPlayCustomInterface::SetDevice(RMdaDevSound* aDevice) + { + iDevice = aDevice; + } + +void TPlayCustomInterface::SetVolume(TUint aVolume) + { + iVolume = aVolume; + if (iDevice && iDevice->Handle()) + iDevice->SetPlayVolume(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 + * @released + * @return number of bytes played + */ +TUint TPlayCustomInterface::BytesPlayed() + { + if(iDevice) + { + if (iDevice->Handle()) + iBytesPlayed = iDevice->BytesPlayed(); + } + return iBytesPlayed; + } + +/** + * Procedure to get the number of bytes recorded by the device + * @released + * @return The number of bytes recorded by an existing datapath. If there + * is no datapath, then the last known number of bytes recorded will be returned. + */ +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() + { + delete iDataPath; + delete iCodec; + delete iPlayCustomInterface; + delete iRecordCustomInterface; + } + +/** +Initializes the hardware device tasks - in the case of a +sw codec wrapper 'hardware device' this consits 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) + { + + // [ precondition that aDevInfo has a valid observer ] + if (!aDevInfo.iHwDeviceObserver) + return KErrArgument; + + iHwDeviceObserver = aDevInfo.iHwDeviceObserver; +#ifndef SYMBIAN_MDF_SHAREDCHUNK_SOUNDDRIVER //Adapter loads the drivers + // Try to load the audio physical driver + TInt ret = User::LoadPhysicalDevice(KPddFileName); + if ((ret!=KErrNone) && (ret!=KErrAlreadyExists)) + return ret; + + // Try to load the audio logical driver + ret = User::LoadLogicalDevice(KLddFileName); + if ((ret!=KErrNone) && (ret!=KErrAlreadyExists)) + return ret; +#endif + iCodec = &(Codec()); //create codec + + //[ assert the post condition ] + if (!iCodec) + return KErrNotSupported; + + return 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 + if(error != KErrNone && iDataPath && aFuncCmd!=EDevEncode) + {//if error happens after opening LDD close it + if (iDataPath->Device().Handle()!= KNullHandle) + { + iDataPath->Device().Close(); + } + } + + return error; + } + + +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()); + //if datapath could not be created, return error code + if (error != KErrNone) + { + return error; + } + + //here we are sure iDataPath has been correctly allocated + iDataPath->SetObserver(*iHwDeviceObserver); + error = iDataPath->AddCodec(*iCodec); + if (error == KErrNone) + { + iDeviceBufferSize = (iCodec->SinkBufferSize()); + static_cast(iDataPath)->SetPlayCustomInterface(*iPlayCustomInterface); + } + else + { + // if could not add codec to datapath, return error code + return error; + } + } + + //Here we know that error is KerrNone, now we can check the state of the datapath + if (iDataPath->State() != CMMFSwCodecDataPath::EPlaying) + {//datapath was created ok and we are not playing + if (iDataPath->State() == CMMFSwCodecDataPath::EStopped) + {//starting from 'fresh so set sound device settings + if (!iDataPath->Device().Handle()) + {//if Device() is called then we need a valid sound device handle + error = iDataPath->Device().Open(); + if (error != KErrNone) + return error; + } + static_cast(iPlayCustomInterface)->SetDevice(&(iDataPath->Device())); + iDataPath->Device().SetPlayVolume(iPlayCustomInterface->Volume()); + RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings; + soundDeviceSettings().iRate = iSampleRate; + //this would normally be pcm16 + soundDeviceSettings().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM; + //1 = mono 2 = stereo + soundDeviceSettings().iChannels = iChannels; + //tell sound driver what buffer size to expect + //it is up the the implementor to make use the device can support + //the required buffer size + soundDeviceSettings().iBufferSize = iDeviceBufferSize; + error = iDataPath->Device().SetPlayFormat(soundDeviceSettings); + }//iDataPath->State() == CMMFSwCodecDataPath::EStopped + //else resuming from pause + if ((error == KErrNone)||(error == KErrInUse)) + error = iDataPath->Start(); + }//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()); + //if datapath could not be created, return error code + if (error != KErrNone) + { + return error; + } + + //here we are sure iDataPath has been correctly allocated + iDataPath->SetObserver(*iHwDeviceObserver); + error = iDataPath->AddCodec(*iCodec); + if (error == KErrNone) + { + iDeviceBufferSize = (iCodec->SourceBufferSize()); + static_cast(iRecordCustomInterface)->SetDataPath(static_cast(iDataPath)); + } + else + { + // if could not add codec to datapath, return error code + return error; + } + } + + //Here we know that error is KerrNone, now we can check the state of the datapath + if (iDataPath->State() != CMMFSwCodecDataPath::EPlaying) + { + if (iDataPath->State() == CMMFSwCodecDataPath::EStopped) + { + MSwSetParamInterface* setParams = + static_cast(iDataPath->CustomInterface(KUidSwSetParamInterface)); + ASSERT(!error); // should not get here if error set + error = setParams->SetGain(iRecordCustomInterface->Gain()); + if (!error) + { + error = setParams->SetNumChannels(iChannels); + } + if (!error) + { + error = setParams->SetSampleRate(iSampleRate); + } + } + if (error == KErrNone) + { + error = iDataPath->Start(); + } + } + return error; + } + + +TInt CMMFSwCodecWrapper::StartConvert() + {//convert + + TInt error = KErrNone; + if (!iDataPath) + { + TRAP(error,iDataPath = CMMFSwCodecConvertDataPath::NewL()); + if (error != KErrNone) + { + return error; + } + } + + //Here we know we are not dereferencing a null pointer as iDataPath has been correctly initialised + 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, +MPlayCustomInterface and MRecordCustomInterface. + +@param aInterface + Interface UID, defined with the custom interface. + aInterface = KMmfPlaySettingsCustomInterface for MPlayCustomInterface, + aInterface = KMmfRecordSettingsCustomInterface for MRecordCustomInterface. + aInterface = KMmfUidEmptyBuffersCustomInterface for MEmptyBuffersCustomInterface + 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); + } + + else if (aInterface.iUid == KMmfUidEmptyBuffersCustomInterface || aInterface == KTimePlayedCustomInterfaceTypeUid || aInterface == KIgnoreUnderflowCustomInterfaceTypeUid) + { + if (!iDataPath) + { + ret = NULL; + } + else + { + ret = static_cast(iDataPath)->CustomInterface(aInterface); + } + } + + 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) + { + if (aConfig.iUid != KUidRefDevSoundTaskConfig) + return KErrArgument; + iSampleRate = aConfig.iRate; + + if (aConfig.iStereoMode == ETaskMono) + { + iChannels = 1; + } + else if (aConfig.iStereoMode == ETaskInterleaved || aConfig.iStereoMode == ETaskNonInterleaved) + { + iChannels = 2; + } + else + { + return KErrArgument; + } + return KErrNone; + } + +/** +Used to set iVbrFlag on the datapath. + +This method is used to set the iVbrFlag in datapath. This flag is added to datapath to avail the +alternative dataflow wherein datapath makes sure that destinationbuffer is filled to its maximum length +before sending it to the sound driver. Sending the buffer directly to the device causes underflow incase of VBR codecs. +*/ +EXPORT_C void CMMFSwCodecWrapper::SetVbrFlag() + { + if(iDataPath) + { + TUid cUid = TUid::Uid(KSetVbrFlagCustomInterfaceTypeUid); + iDataPath->CustomInterface(cUid); + } + } + +