diff -r 000000000000 -r 79dd3e2336a0 mmdevicefw/mdf/src/audio/HwDeviceAdapter/mdfhwdeviceadapter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmdevicefw/mdf/src/audio/HwDeviceAdapter/mdfhwdeviceadapter.cpp Fri Oct 08 19:40:43 2010 +0100 @@ -0,0 +1,905 @@ +// 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 "HwDeviceAdapter/mdfhwdeviceadapter.h" +#include +#include +#include + +// Interface UID for the Sink Processing Unit +const TUid KUidSourceSinkPu = {0x102730BB}; +const TInt KZerothPort = 0; + +/* +The destructor. Unloads the Processing Units, deletes the +Processing Unit Loader and frees any owned buffers. +@see CMMFHwDevice::~CMMFHwDevice() +*/ +CMdfHwDeviceAdapter::~CMdfHwDeviceAdapter() + { + Stop(); + // Unload the PUs + if (iCodecPU) + { + iPuLoader->UnloadProcessingUnit(iCodecPU); + } + if (iAudioDevicePU) + { + iPuLoader->UnloadProcessingUnit(iAudioDevicePU); + } + + delete iInputBuffer; + delete iOutputBuffer; + delete iActiveWait; + delete iPuLoader; + REComSession::DestroyedImplementation(iPuLoaderDtorKey); + } + +/* +Creates a new CMdfHwDeviceAdapter object. The Processing Unit Loader plugin +is also loaded, and so the CMdfHwDeviceAdapter state is set to EProcessingUnitLoaderLoaded. +Will leave with KErrNotFound if it, or the Processing Unit Loader plugin is not found. +@see THwDevAdapterState +*/ +CMdfHwDeviceAdapter* CMdfHwDeviceAdapter::NewL() + { + CMdfHwDeviceAdapter* self = new (ELeave) CMdfHwDeviceAdapter; + CleanupStack::PushL (self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +/* +Default constructor. +*/ +CMdfHwDeviceAdapter::CMdfHwDeviceAdapter() + { + } + +/* +Loads the Processing Unit Loader plugin. +*/ +void CMdfHwDeviceAdapter::ConstructL() + { + // Load the PU Loader plugin + iPuLoader = static_cast + (REComSession::CreateImplementationL(TUid::Uid(KUidPuLoaderImplementation), iPuLoaderDtorKey)); + iActiveWait = new (ELeave) CActiveSchedulerWait; + iState = EProcessingUnitLoaderLoaded; + } + +/* +@see CMMFHwDevice::Start() +@see TDeviceFunc +*/ +TInt CMdfHwDeviceAdapter::Start(TDeviceFunc aFuncCmd, TDeviceFlow /*aFlowCmd*/) + { + if (!((aFuncCmd == EDevEncode)|(aFuncCmd == EDevDecode)|(aFuncCmd == EDevNullFunc))) + { + return KErrArgument; + } + + iFuncCmd = aFuncCmd; + + TInt err = KErrNone; + switch(aFuncCmd) + { + case EDevEncode: + { + err = StartEncode(); + } + break; + case EDevDecode: + { + err = StartDecode(); + } + break; + case EDevNullFunc: + { + // nothing at the moment, so fall through + } + //break; + default: + { + err = KErrNotSupported; + } + break; + } + + + return err; + } + +/* +Initialises the encode operation, and set the state of the CMdfHwDeviceAdapter +to EProcessingUnitInitializing. +@return An error code indicating if the function call was successful. +KErrNone on success, otherwise another of the system-wide error codes. +*/ +TInt CMdfHwDeviceAdapter::InitializeEncode() + { + ASSERT(iCodecOutputPort && iSourceOutputPort); + // Create input buffer that passes data from Source -> Codec PU + TRAPD(err, iInputBuffer = CMMFDescriptorBuffer::NewL(iSourceOutputPort->MopBufferSize())); + if(err != KErrNone) + { + return err; + } + + // Create output buffer that passes decoded data from Codec PU -> Out to file + TRAP(err, iOutputBuffer = CMMFDescriptorBuffer::NewL(iCodecOutputPort->MopBufferSize())); + if(err != KErrNone) + { + return err; + } + + err = iSourceOutputPort->MopUseBuffer(*iInputBuffer); + if(err != KErrNone) + { + return err; + } + err = iCodecInputPort->MipUseBuffer(*iInputBuffer); + if(err != KErrNone) + { + return err; + } + err = iCodecOutputPort->MopUseBuffer(*iOutputBuffer); + if(err != KErrNone) + { + return err; + } + + // async calls, that callback to InitializeComplete() + iCodecPU->Initialize(); + iAudioDevicePU->Initialize(); + if (iState == EProcessingUnitLoaded) + { + // only wait for the callbacks if we haven't already received them + iState = EProcessingUnitInitializing; + iActiveWait->Start(); + } + return iInitError; + } + +/* +Starts the encode operation, providing that the intial state of the +CMdfHwDeviceAdapter is EProcessingUnitLoaded. +@return An error code indicating if the function call was successful. +KErrNone on success, otherwise another of the system-wide error codes. +*/ +TInt CMdfHwDeviceAdapter::StartEncode() + { + TInt err = KErrNone; + if (iState == EProcessingUnitLoaded) + { + err = InitializeEncode(); + } + if (err != KErrNone) + { + return err; + } + if (iState == EProcessingUnitPaused) + { + // Ensure that the LastBuffer flags are reset. + iInputBuffer->SetLastBuffer(EFalse); + iOutputBuffer->SetLastBuffer(EFalse); + } + + return StartExecuting(); + } + +/* +Starts the execution of the encode or decode operation, and sets the state +of the CMdfHwDeviceAdapter to EProcessingUnitExecuting. +@return An error code indicating if the function call was successful. +KErrNone on success, otherwise another of the system-wide error codes. +*/ +TInt CMdfHwDeviceAdapter::StartExecuting() + { + TInt err = KErrNone; + if(iFuncCmd == EDevDecode) + { + iCodecOutputPort->MopReadData(*iOutputBuffer); + err = iHwDeviceObserver->FillThisHwBuffer(*iInputBuffer); + if(err != KErrNone) + { + return err; + } + } + else // encode + { + iSourceOutputPort->MopReadData(*iInputBuffer); + iCodecOutputPort->MopReadData(*iOutputBuffer); + } + + iState = EProcessingUnitExecuting; + + iCodecPU->Execute(); + iAudioDevicePU->Execute(); + + return err; + } + +/* +Initialises the decode operation, and set the state of the CMdfHwDeviceAdapter +to EProcessingUnitInitializing. +@return An error code indicating if the function call was successful. +KErrNone on success, otherwise another of the system-wide error codes. +*/ +TInt CMdfHwDeviceAdapter::InitializeDecode() + { + ASSERT(iCodecOutputPort && iSinkInputPort); + + TRAPD(err, iInputBuffer = CMMFDescriptorBuffer::NewL(iCodecInputPort->MipBufferSize())); + if(err != KErrNone) + { + return err; + } + + iCodecInputPort->MipUseBuffer(*iInputBuffer); + TRAP(err, iOutputBuffer = CMMFDescriptorBuffer::NewL(iCodecOutputPort->MopBufferSize())); + if(err != KErrNone) + { + return err; + } + + // Try to set up a tunnelbetween the output port of the PCM Pu + // and the input port of the Sink Pu + if (iPuLoader->TunnelSetup(*iCodecOutputPort, *iSinkInputPort) != KErrNone) + { + iSinkInputPort->MipUseBuffer(*iOutputBuffer); + } + iCodecOutputPort->MopUseBuffer(*iOutputBuffer); + + // async calls, that callback to InitializeComplete() + iCodecPU->Initialize(); + iAudioDevicePU->Initialize(); + iState = EProcessingUnitInitializing; + iActiveWait->Start(); + return KErrNone; + } + +/* +Starts the decode operation, providing that the intial state of the +CMdfHwDeviceAdapter is EProcessingUnitLoaded. +@return An error code indicating if the function call was successful. +KErrNone on success, otherwise another of the system-wide error codes. +*/ +TInt CMdfHwDeviceAdapter::StartDecode() + { + TInt err = KErrNone; + if (iState == EProcessingUnitLoaded) + { + err = InitializeDecode(); + } + if (err != KErrNone) + { + return err; + } + if (iState == EProcessingUnitIdle) + { + // Ensure that the LastBuffer flags are reset. + iInputBuffer->SetLastBuffer(EFalse); + iOutputBuffer->SetLastBuffer(EFalse); + } + return StartExecuting(); + } + +/* +@see CMMFHwDevice::Stop() +*/ +TInt CMdfHwDeviceAdapter::Stop() + { + if(iState == EProcessingUnitExecuting || iState == EProcessingUnitPaused) + { + iStopping = ETrue; // is used as a guard in ExecuteComplete + if(iAudioDevicePU) + { + iAudioDevicePU->Stop(); + } + if(iCodecPU) + { + iCodecPU->Stop(); + } + + iPCMPUCallbackComplete = EFalse; + iSourceSinkPUCallbackComplete = EFalse; + + iState = EProcessingUnitIdle; + iStopping = EFalse; + } + return KErrNone; + } + +/* +@see CMMFHwDevice::Pause() +*/ +TInt CMdfHwDeviceAdapter::Pause() + { + TInt err = KErrNone; + if(iState != EProcessingUnitPaused) + { + if(iAudioDevicePU) + { + err = iAudioDevicePU->Pause(); + } + iState = EProcessingUnitPaused; + } + return err; + } + +/* +@see CMMFHwDevice::Init() +*/ +TInt CMdfHwDeviceAdapter::Init(THwDeviceInitParams& aDevInfo) + { + if(!iCodecPU) + { + return KErrNotSupported; + } + + // Not currently using any other members of aDevInfo, except the Observer + // Set observer + if(!aDevInfo.iHwDeviceObserver) + { + return KErrArgument; + } + iHwDeviceObserver = aDevInfo.iHwDeviceObserver; + + RPointerArray inputPorts; + // Get ports and set observers + TInt err = iCodecPU->GetInputPorts(inputPorts); + if (err == KErrNone && inputPorts.Count() > 0) + { + iCodecInputPort = inputPorts[KZerothPort]; + iCodecInputPort->MipSetObserver(*this); + } + inputPorts.Close(); + if (err != KErrNone) + { + return err; + } + if (!iCodecInputPort) + { + return KErrNotFound; + } + + RPointerArray outputPorts; + // Get ports and set observers + err = iCodecPU->GetOutputPorts(outputPorts); + if (err == KErrNone && outputPorts.Count() > 0) + { + iCodecOutputPort = outputPorts[KZerothPort]; + iCodecOutputPort->MopSetObserver(*this); + } + outputPorts.Close(); + if (err != KErrNone) + { + return err; + } + if (!iCodecOutputPort) + { + return KErrNotFound; + } + + // Load SourceSink Pu + TRAP(err, iAudioDevicePU = iPuLoader->LoadProcessingUnitL(*this, KUidSourceSinkPu)); + if(err!=KErrNone) + { + return err; + } + + err = iAudioDevicePU->GetInputPorts(inputPorts); + if (err == KErrNone && inputPorts.Count() > 0) + { + iSinkInputPort = inputPorts[KZerothPort]; + iSinkInputPort->MipSetObserver(*this); + } + inputPorts.Close(); + if (err != KErrNone) + { + return err; + } + if (!iSinkInputPort) + { + return KErrNotFound; + } + + + err = iAudioDevicePU->GetOutputPorts(outputPorts); + if (err == KErrNone && outputPorts.Count() > 0) + { + iSourceOutputPort = outputPorts[KZerothPort]; + iSourceOutputPort->MopSetObserver(*this); + } + outputPorts.Close(); + if (err != KErrNone) + { + return err; + } + if (!iCodecOutputPort) + { + return KErrNotFound; + } + + iState = EProcessingUnitLoaded; + return KErrNone; + } + +/* +@see CMMFHwDevice::CustomInterface() +*/ +TAny* CMdfHwDeviceAdapter::CustomInterface(TUid aInterfaceId) + { + if (aInterfaceId == KUidHwDeviceSetupInterface) + { + MMdfHwDeviceSetup* hwDeviceSetup = this; + return hwDeviceSetup; + } + else if (aInterfaceId.iUid == KMmfPlaySettingsCustomInterface) + { + return iSinkInputPort->MipCustomInterface(aInterfaceId); + } + else if (aInterfaceId.iUid == KMmfRecordSettingsCustomInterface) + { + return iSourceOutputPort->MopCustomInterface(aInterfaceId); + } + else if (aInterfaceId == KUidCustomInterfaceDevSoundBitRate) + { + return iCodecPU->CustomInterface(aInterfaceId); + } + else + { + return NULL; + } + } + +/* +@see CMMFHwDevice::ThisHwBufferFilled() +*/ +TInt CMdfHwDeviceAdapter::ThisHwBufferFilled(CMMFBuffer& aFillBufferPtr) + { + aFillBufferPtr.SetStatus(EFull); + iCodecInputPort->MipWriteData(aFillBufferPtr); + return KErrNone; + } + +/* +@see CMMFHwDevice::ThisHwBufferEmptied() +*/ +TInt CMdfHwDeviceAdapter::ThisHwBufferEmptied(CMMFBuffer& /*aEmptyBufferPtr*/) + { + if (iOutputBuffer->LastBuffer()) + { + CMMFDataBuffer* buffer = static_cast (iOutputBuffer); + buffer->Data().SetLength(0); + iHwDeviceObserver->EmptyThisHwBuffer(*iOutputBuffer); + } + else + { + iCodecOutputPort->MopReadData(*iOutputBuffer); + } + return KErrNone; + } + +/* +@see CMMFHwDevice::SetConfig() +*/ +TInt CMdfHwDeviceAdapter::SetConfig(TTaskConfig& aConfig) + { + TInt err = KErrNone; + // Call to Configure the Codec PU + TPuTaskConfig config(aConfig); + err = iCodecInputPort->MipConfigure(config); + if(err != KErrNone) + { + return err; + } + err = iCodecOutputPort->MopConfigure(config); + if(err != KErrNone) + { + return err; + } + + // configure the audio device + err = iSinkInputPort->MipConfigure(config); + if(err != KErrNone) + { + return err; + } + err = iSourceOutputPort->MopConfigure(config); + if(err != KErrNone) + { + return err; + } + + return KErrNone; + } + +/* +@see CMMFHwDevice::StopAndDeleteCodec() +*/ +TInt CMdfHwDeviceAdapter::StopAndDeleteCodec() + { + TInt stopError = Stop(); + TInt deleteError = DeleteCodec(); + + if (stopError != KErrNone) + { + return stopError; + } + else + { + return deleteError; + } + } + +/* +Unloads all Processing Units, and deletes any locally owned buffers. +State is set to EProcessingUnitLoaderLoaded. + +@see CMMFHwDevice::DeleteCodec() +*/ +TInt CMdfHwDeviceAdapter::DeleteCodec() + { + Stop(); + if (iCodecPU) + { + iPuLoader->UnloadProcessingUnit(iCodecPU); + } + if (iAudioDevicePU) + { + iPuLoader->UnloadProcessingUnit(iAudioDevicePU); + } + + // CMdfHwDeviceAdapter does not own the I/O ports, which + // have been deleted at this point by UnloadProcessingUnit() + iCodecInputPort = NULL; + iCodecOutputPort = NULL; + iSinkInputPort = NULL; + iSourceOutputPort = NULL; + + delete iInputBuffer; + iInputBuffer = NULL; + delete iOutputBuffer; + iOutputBuffer = NULL; + + iState = EProcessingUnitLoaderLoaded; + + return KErrNone; + } + +/* +@see MMdfInputPortObserver::MipoWriteDataComplete() +*/ +void CMdfHwDeviceAdapter::MipoWriteDataComplete(const MMdfInputPort* aInputPort, + CMMFBuffer* aBuffer, TInt aErrorCode) + { + if(aErrorCode != KErrNone) + { + StopHwDevice(aErrorCode); + } + else + { + switch(iFuncCmd) + { + case EDevEncode: + { + if(aInputPort == iCodecInputPort) + { + if(aBuffer->LastBuffer()) + { + iCodecPU->Stop(); + } + else + { + // if not the last buffer, then pass buffer back to source to get more data + iSourceOutputPort->MopReadData(*iInputBuffer); + } + } + } + break; + case EDevDecode: + { + if(aInputPort == iCodecInputPort) + { + if (!aBuffer->LastBuffer()) + { + // JW 22-05-06 + // if the PU is idle (having been Stopped) then + // FillThisHwBuffer will cause a kern-exec, + // as the DevSoundSession no longer has a buffer + if(iState == EProcessingUnitExecuting) + { + TInt err = iHwDeviceObserver->FillThisHwBuffer(*aBuffer); + if(err != KErrNone) + { + StopHwDevice(err); + } + } + } + } + else // aInputPort == iSinkInputPort + { + if (!aBuffer->LastBuffer()) + { + if(iSinkInputPort->MipIsTunnelled()) + { + // This callback shouldn't occur since it should be tunnelled with the sink input port + StopHwDevice(KErrArgument); + } + else + { + iCodecOutputPort->MopReadData(*iOutputBuffer); + } + } + } + } + break; + case EDevNullFunc: + // nothing at the moment, so fall through + default: + StopHwDevice(KErrNotSupported); + } + } + } + +/* +@see MMdfInputPortObserver::MipoDisconnectTunnelComplete() +*/ +void CMdfHwDeviceAdapter::MipoDisconnectTunnelComplete(const MMdfInputPort* aInputPort, + TInt aErrorCode) + { + // The Inputport of the PcmCodecPu will no longer receive data. + if(aErrorCode == KErrNone) + { + if(aInputPort == iCodecInputPort) + { + iPCMPuMipoStopCompleted = ETrue; + } + else if(aInputPort == iSinkInputPort) + { + // This shouldn't be called! + iHwDeviceObserver->Error(KErrNotFound); + } + } + else + { + iHwDeviceObserver->Error(aErrorCode); + } + } + +/* +@see MMdfInputPortObserver::MipoRestartTunnelComplete() +*/ +void CMdfHwDeviceAdapter::MipoRestartTunnelComplete(const MMdfInputPort* /*aInputPort*/, + TInt /*aErrorCode*/) + { + + } + +/* +@see MMdfOutputPortObserver::MopoReadDataComplete() +*/ +void CMdfHwDeviceAdapter::MopoReadDataComplete(const MMdfOutputPort* aOutputPort, + CMMFBuffer* aBuffer, TInt aErrorCode) + { + if(aErrorCode != KErrNone) + { + StopHwDevice(aErrorCode); + } + else + { + switch(iFuncCmd) + { + case EDevEncode: + { + if(aOutputPort == iSourceOutputPort) + { + iCodecInputPort->MipWriteData(*aBuffer); + } + else // aPu == iCodecPU + { + TInt err = iHwDeviceObserver->EmptyThisHwBuffer(*aBuffer); + if(err !=KErrNone) + { + StopHwDevice(err); + } + } + } + break; + case EDevDecode: + { + if(aOutputPort == iCodecOutputPort) + { + if(iCodecOutputPort->MopIsTunnelled()) + { + // This callback shouldn't occur since it should be tunnelled with the sink input port + StopHwDevice(KErrArgument); + } + else + { + iSinkInputPort->MipWriteData(*aBuffer); + } + } + } + break; + case EDevNullFunc: + // nothing at the moment, so fall through + default: + StopHwDevice(KErrNotSupported); + } + } + } + +/* +@see MMdfOutputPortObserver::MopoDisconnectTunnelComplete() +*/ +void CMdfHwDeviceAdapter::MopoDisconnectTunnelComplete(const MMdfOutputPort* aOutputPort, + TInt aErrorCode) + { + if(!aOutputPort) + { + iHwDeviceObserver->Error(KErrArgument); + return; + } + + // The last buffer has been set, and called back to MopoReadDataComplete + if(aErrorCode != KErrNone) + { + iHwDeviceObserver->Error(aErrorCode); + return; + } + + if(aOutputPort == iCodecOutputPort) + { + iPCMPuMopoStopCompleted = ETrue; + } + else if(aOutputPort == iSourceOutputPort) + { + iSourceSinkPuMopoStopCompleted = ETrue; + } + else + { + iHwDeviceObserver->Error(KErrArgument); + return; + } + + if(iPCMPuMipoStopCompleted && iPCMPuMopoStopCompleted && iSourceSinkPuMopoStopCompleted) + { + iHwDeviceObserver->Error(KErrNone); + iState = EProcessingUnitIdle; + } + } + +/* +@see MMdfOutputPortObserver::MopoRestartTunnelComplete() +*/ +void CMdfHwDeviceAdapter::MopoRestartTunnelComplete(const MMdfOutputPort* /*aOutputPort*/, + TInt /*aErrorCode*/) + { + + } + +/* +@see MMdfProcessingUnitObserver::InitializeComplete() +*/ +void CMdfHwDeviceAdapter::InitializeComplete(const CMdfProcessingUnit* aPu, TInt aErrorCode) + { + iInitError = aErrorCode; + if(aErrorCode != KErrNone) + { + // stop waiting on the active scheduler if we were doing so + if (iState == EProcessingUnitInitializing) + { + // change state back to processing unit loaded + iState = EProcessingUnitLoaded; + iActiveWait->AsyncStop(); + } + return; + } + + if(aPu == iCodecPU) + { + iPCMPUCallbackComplete = ETrue; + } + else if(aPu == iAudioDevicePU) + { + iSourceSinkPUCallbackComplete = ETrue; + } + + if(iPCMPUCallbackComplete && iSourceSinkPUCallbackComplete) + { + // reset the flags + iPCMPUCallbackComplete = EFalse; + iSourceSinkPUCallbackComplete = EFalse; + + // Both PUs initialised OK + if (iState == EProcessingUnitInitializing) + { + iActiveWait->AsyncStop(); + } + iState = EProcessingUnitIdle; + } + } + +/* +@see MMdfProcessingUnitObserver::ExecuteComplete() +*/ +void CMdfHwDeviceAdapter::ExecuteComplete(const CMdfProcessingUnit* aPu, TInt aErrorCode) + { + if(iStopping) + { + return; + } + + if (iExecuteError == KErrNone) + { + iExecuteError = aErrorCode; + } + + if(aPu == iCodecPU) + { + iPCMPUCallbackComplete = ETrue; + } + else if(aPu == iAudioDevicePU) + { + iSourceSinkPUCallbackComplete = ETrue; + } + + if(iExecuteError != KErrNone || (iPCMPUCallbackComplete && iSourceSinkPUCallbackComplete)) + { + if (iState == EProcessingUnitExecuting) + { + // stop the hardware device if we are still executing + StopHwDevice(iExecuteError); + iState = EProcessingUnitIdle; + } + // reset the flags + iPCMPUCallbackComplete = EFalse; + iSourceSinkPUCallbackComplete = EFalse; + } + } + +/* +@see MMdfHwDeviceSetup::::SetDataTypesL() +*/ +void CMdfHwDeviceAdapter::SetDataTypesL(TFourCC aSrcType, TFourCC aDestType) + { + // Find and load an appropriate Codec + iCodecPU = iPuLoader->LoadProcessingUnitL(*this, aSrcType, aDestType); + } + +/* +Called to indicate that the Hardware Device has been stopped, leading +to callbacks to the observer. +@see MMMFHwDeviceObserver::Stopped() +@see MMMFHwDeviceObserver::Error() +*/ +void CMdfHwDeviceAdapter::StopHwDevice(TInt error) + { + iHwDeviceObserver->Stopped(); + iHwDeviceObserver->Error(error); + } + +/* +Returns the state of the Hardware Device Adapter object. +*/ +void CMdfHwDeviceAdapter::GetState(THwDevAdapterState& aState) const + { + aState = iState; + } +