--- /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 <mmf/server/mmfswcodecwrapper.h>
+#include "mmfSwCodecPlayDataPath.h"
+#include "mmfSwCodecRecordDataPath.h"
+#include "mmfSwCodecConvertDataPath.h"
+#include <mmf/server/mmfswcodecwrappercustominterfacesuids.hrh>
+#include "mmfswcodecwrapperCustomInterfaces.h"
+#include <mmf/common/mmfpaniccodes.h>
+
+
+
+/**
+ * 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<CMMFSwCodecPlayDataPath*>(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<TPlayCustomInterface*>(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<TRecordCustomInterface*>(iRecordCustomInterface)->SetDataPath(static_cast<CMMFSwCodecRecordDataPath*>(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<MSwSetParamInterface*>(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<TAny*>(iPlayCustomInterface);
+ }
+ else if (aInterface.iUid == KMmfRecordSettingsCustomInterface)
+ {
+ if (!iRecordCustomInterface)
+ TRAP(err,iRecordCustomInterface = new(ELeave)TRecordCustomInterface());
+ if (err)
+ ret = NULL;
+ else
+ ret = static_cast<TAny*>(iRecordCustomInterface);
+ }
+
+ else if (aInterface.iUid == KMmfUidEmptyBuffersCustomInterface || aInterface == KTimePlayedCustomInterfaceTypeUid || aInterface == KIgnoreUnderflowCustomInterfaceTypeUid)
+ {
+ if (!iDataPath)
+ {
+ ret = NULL;
+ }
+ else
+ {
+ ret = static_cast<CMMFSwCodecDataPath*>(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);
+ }
+ }
+
+