diff -r 000000000000 -r 40261b775718 omxil/omxilcomponentcommon/src/common/omxilfsm.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omxil/omxilcomponentcommon/src/common/omxilfsm.cpp Tue Feb 02 01:56:55 2010 +0200 @@ -0,0 +1,783 @@ +// Copyright (c) 2008-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: +// + + +/** + @file + @internalComponent +*/ + +#include "log.h" +#include "omxilfsm.h" +#include "omxilstate.h" +#include "omxilportmanager.h" +#include "omxilconfigmanager.h" +#include "omxilcallbackmanager.h" +#include "omxilprocessingfunction.h" + +#define RETURN_OMX_ERROR_AND_EVENT_IF_NEEDED(_a) \ + { \ + const OMX_ERRORTYPE _err = _a; \ + if (OMX_ErrorNone == _err) return _err; \ + else return SendOmxErrorEventIfNeeded(_err); \ + } + + +const TInt COmxILFsm::KMaxMsgQueueEntries; + +EXPORT_C COmxILFsm* +COmxILFsm::NewL(COmxILComponent& aComponent, + COmxILProcessingFunction& aProcFunction, + COmxILPortManager& aPortManager, + COmxILConfigManager& aConfigManager, + MOmxILCallbackManagerIf& aCallbacks) + { + DEBUG_PRINTF(_L8("COmxILFsm::NewLC")); + + COmxILFsm* self = new (ELeave) COmxILFsm(aComponent, + aProcFunction, + aPortManager, + aConfigManager, + aCallbacks); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return (self); + } + +void +COmxILFsm::ConstructL() + { + DEBUG_PRINTF(_L8("COmxILFsm::ConstructL")); + + // Create the FSM states + + // Init the array + for (TUint i=0; i < EStateMax; ++i) + { + iStates.AppendL(NULL); + } + + // Add the standard states... + iStates[EStateInvalid] = new (ELeave)COmxILStateInvalid; + iStates[EStateLoaded] = new (ELeave)COmxILStateLoaded; + iStates[EStateIdle] = new (ELeave)COmxILStateIdle; + iStates[EStateExecuting] = new (ELeave)COmxILStateExecuting; + iStates[EStatePause] = new (ELeave)COmxILStatePause; + iStates[EStateWaitForResources] = new (ELeave)COmxILStateWaitForResources; + + // Now add the substates + iStates[ESubStateLoadedToIdle] = new (ELeave)COmxILStateLoadedToIdle; + iStates[ESubStateIdleToLoaded] = new (ELeave)COmxILStateIdleToLoaded; + iStates[ESubStateExecutingToIdle] = new (ELeave)COmxILStateExecutingToIdle; + iStates[ESubStatePauseToIdle] = new (ELeave)COmxILStatePauseToIdle; + + iCallbacks.SetPortManager(iPortManager); + iCallbacks.SetFsm(*this); + + } + +COmxILFsm::COmxILFsm(COmxILComponent& aComponent, + COmxILProcessingFunction& aProcFunction, + COmxILPortManager& aPortManager, + COmxILConfigManager& aConfigManager, + MOmxILCallbackManagerIf& aCallbacks) + : + iComponent(aComponent), + iProcFunction(aProcFunction), + iPortManager(aPortManager), + iConfigManager(aConfigManager), + iCallbacks(aCallbacks), + iStates(), + iCurrentStateIndex(EStateMax), + ipCurrentState(0) + { + DEBUG_PRINTF(_L8("COmxILFsm::COmxILFsm")); + } + +COmxILFsm::~COmxILFsm() + { + DEBUG_PRINTF(_L8("COmxILFsm::~COmxILFsm")); + + iCurrentStateIndex = EStateMax; + ipCurrentState = 0; + iStates.ResetAndDestroy(); + + } + +OMX_ERRORTYPE +COmxILFsm::InitFsm() + { + DEBUG_PRINTF(_L8("COmxILFsm::InitFsm")); + + // Let's get ready to handle API calls... + iCurrentStateIndex = EStateLoaded; + ipCurrentState = iStates[iCurrentStateIndex]; + return OMX_ErrorNone; + + } + +COmxILComponent* +COmxILFsm::GetComponent() const + { + return &iComponent; + } + +OMX_ERRORTYPE +COmxILFsm::PopulateBuffer(OMX_BUFFERHEADERTYPE** appBufferHdr, + OMX_U32 aPortIndex, + OMX_PTR apAppPrivate, + OMX_U32 aSizeBytes, + OMX_U8* apBuffer) + { + DEBUG_PRINTF(_L8("COmxILFsm::PopulateBuffer")); + + TBool portPopulationCompleted = EFalse; + OMX_ERRORTYPE omxRetValue = + ipCurrentState->PopulateBuffer(*this, + appBufferHdr, + aPortIndex, + apAppPrivate, + aSizeBytes, + apBuffer, + portPopulationCompleted); + + if (OMX_ErrorNone == omxRetValue) + { + if (portPopulationCompleted && + ESubStateLoadedToIdle == iCurrentStateIndex && + iPortManager.AllPortsPopulated()) + { + // Complete here the transition to OMX_StateIdle + omxRetValue = FsmTransition(EStateIdle); + if (OMX_ErrorNone == omxRetValue) + { + // Notify the IL client that port population has + // completed sucessfully + omxRetValue = iCallbacks.TransitionCompleteNotification( + OMX_StateIdle); + + } + } + } + + if (OMX_ErrorNone == omxRetValue || + OMX_ErrorInsufficientResources == omxRetValue) + { + // OMX_ErrorInsufficientResources is allowed in OMX_EmptyThisBuffer and + // OMX_FillThisBuffer + return omxRetValue; + } + else + { + return SendOmxErrorEventIfNeeded(omxRetValue); + } + + } + +OMX_ERRORTYPE +COmxILFsm::FsmTransition(TStateIndex aNewState) + { + DEBUG_PRINTF2(_L8("COmxILFsm::FsmTransition : %d"), aNewState); + + __ASSERT_ALWAYS(aNewState < EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + if (aNewState != iCurrentStateIndex) + { + // We notify the processing function of all the state transitions, even + // if they are not to a final OpenMAX IL state. + OMX_ERRORTYPE omxRetValue; + if (OMX_ErrorNone != + (omxRetValue = + iProcFunction.StateTransitionIndication(aNewState))) + { + // No need of propagating further error codes if the component is + // transitioning to OMX_StateInvalid or if the PF itself is + // invalidating the component... + if (EStateInvalid != aNewState && + OMX_ErrorInvalidState != omxRetValue) + { + return omxRetValue; + } + } + + iCurrentStateIndex = aNewState; + ipCurrentState = iStates[iCurrentStateIndex]; + + } + + return OMX_ErrorNone; + + } + +OMX_ERRORTYPE +COmxILFsm::FsmTransition(TUint32 aNewState) + { + + return FsmTransition(static_cast(aNewState)); + + } + + +OMX_ERRORTYPE +COmxILFsm::GetComponentVersion(OMX_STRING aComponentName, + OMX_VERSIONTYPE* apComponentVersion, + OMX_VERSIONTYPE* apSpecVersion, + OMX_UUIDTYPE* apComponentUUID) const + { + DEBUG_PRINTF(_L8("COmxILFsm::GetComponentVersion")); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + // This api should not be allowed in OMX_StateInvalid + if (EStateInvalid == iCurrentStateIndex) + { + return SendOmxErrorEventIfNeeded(OMX_ErrorInvalidState); + } + + if (!aComponentName || + !apComponentVersion || + !apSpecVersion || + !apComponentUUID) + { + return OMX_ErrorBadParameter; + } + + // This API call is independent of the current state. Its handled by the + // the config manager + + RETURN_OMX_ERROR_AND_EVENT_IF_NEEDED( + iConfigManager.GetComponentVersion( + aComponentName, + apComponentVersion, + apSpecVersion, + apComponentUUID)); + } + + +OMX_ERRORTYPE +COmxILFsm::SendCommand(OMX_COMMANDTYPE aCommand, + TUint32 anParam1, + TAny* apCmdData) + { + DEBUG_PRINTF3(_L8("COmxILFsm::SendCommand : command [%d] Param1 [%d]"), aCommand, anParam1); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + // Do some very minor error checking here to try to save some time... + if (OMX_CommandStateSet == aCommand && + anParam1 > OMX_StateWaitForResources) + { + return OMX_ErrorBadParameter; + } + + TOmxILCommand command(aCommand, anParam1, apCmdData); + OMX_ERRORTYPE sendCommandError; + switch (aCommand) + { + case OMX_CommandStateSet: + { + sendCommandError = ipCurrentState->CommandStateSet(*this, command); + } + break; + case OMX_CommandFlush: + { + sendCommandError = ipCurrentState->CommandFlush(*this, command); + } + break; + case OMX_CommandPortDisable: + { + sendCommandError = ipCurrentState->CommandPortDisable(*this, command); + } + break; + case OMX_CommandPortEnable: + { + sendCommandError = ipCurrentState->CommandPortEnable(*this, command); + } + break; + case OMX_CommandMarkBuffer: + { + sendCommandError = ipCurrentState->CommandMarkBuffer(*this, command); + } + break; + default: + { + // This is an invalid command type + return OMX_ErrorBadParameter; + } + }; + + if (OMX_ErrorNone == sendCommandError || + OMX_ErrorInsufficientResources == sendCommandError) + { + // OMX_ErrorInsufficientResources is allowed in OMX_SendCommand + return sendCommandError; + } + else + { + return SendOmxErrorEventIfNeeded(sendCommandError); + } + + } + + +OMX_ERRORTYPE +COmxILFsm::GetParameter(OMX_INDEXTYPE aParamIndex, + TAny* apComponentParameterStructure) const + { + DEBUG_PRINTF(_L8("COmxILFsm::GetParameter")); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + if (!apComponentParameterStructure) + { + return OMX_ErrorBadParameter; + } + + RETURN_OMX_ERROR_AND_EVENT_IF_NEEDED( + ipCurrentState->GetParameter(*this, aParamIndex, + apComponentParameterStructure)); + } + + +OMX_ERRORTYPE +COmxILFsm::SetParameter(OMX_INDEXTYPE aParamIndex, + const TAny* apComponentParameterStructure) + { + DEBUG_PRINTF(_L8("COmxILFsm::SetParameter")); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + if (!apComponentParameterStructure) + { + return OMX_ErrorBadParameter; + } + + RETURN_OMX_ERROR_AND_EVENT_IF_NEEDED( + ipCurrentState->SetParameter(*this, aParamIndex, + apComponentParameterStructure)); + } + + +OMX_ERRORTYPE +COmxILFsm::GetConfig(OMX_INDEXTYPE aConfigIndex, + TAny* apComponentConfigStructure) const + { + DEBUG_PRINTF(_L8("COmxILFsm::GetConfig")); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + if (!apComponentConfigStructure) + { + return OMX_ErrorBadParameter; + } + + RETURN_OMX_ERROR_AND_EVENT_IF_NEEDED( + ipCurrentState->GetConfig(*this, + aConfigIndex, + apComponentConfigStructure)); + + } + + +OMX_ERRORTYPE +COmxILFsm::SetConfig(OMX_INDEXTYPE aIndex, + const TAny* apComponentConfigStructure) + { + DEBUG_PRINTF(_L8("COmxILFsm::SetConfig")); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + if (!apComponentConfigStructure) + { + return OMX_ErrorBadParameter; + } + + RETURN_OMX_ERROR_AND_EVENT_IF_NEEDED( + ipCurrentState->SetConfig(*this, aIndex, apComponentConfigStructure)); + + } + + +OMX_ERRORTYPE +COmxILFsm::GetExtensionIndex( + OMX_STRING aParameterName, + OMX_INDEXTYPE* apIndexType) const + { + DEBUG_PRINTF(_L8("COmxILFsm::GetExtensionIndex")); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + if (!apIndexType || !aParameterName) + { + return OMX_ErrorBadParameter; + } + + RETURN_OMX_ERROR_AND_EVENT_IF_NEEDED( + ipCurrentState->GetExtensionIndex(*this, + aParameterName, + apIndexType)); + } + + +OMX_ERRORTYPE +COmxILFsm::GetState(OMX_STATETYPE* apState) const + { + DEBUG_PRINTF(_L8("COmxILFsm::GetState")); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + if (!apState) + { + return OMX_ErrorBadParameter; + } + + *apState = ipCurrentState->GetState(); + + return OMX_ErrorNone; + + } + + +OMX_ERRORTYPE +COmxILFsm::ComponentTunnelRequest(OMX_U32 aPort, + OMX_HANDLETYPE aTunneledComp, + OMX_U32 aTunneledPort, + OMX_TUNNELSETUPTYPE* apTunnelSetup) + { + DEBUG_PRINTF(_L8("COmxILFsm::ComponentTunnelRequest")); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + // Here, since NULL is a valid parameter for aTunneledComp, checking of + // input parameters is completely done by the ports. + RETURN_OMX_ERROR_AND_EVENT_IF_NEEDED( + ipCurrentState->ComponentTunnelRequest(*this, + aPort, + aTunneledComp, + aTunneledPort, + apTunnelSetup)); + + } + + +OMX_ERRORTYPE +COmxILFsm::UseBuffer(OMX_BUFFERHEADERTYPE** appBufferHdr, + OMX_U32 aPortIndex, + OMX_PTR apAppPrivate, + OMX_U32 aSizeBytes, + OMX_U8* apBuffer) + { + DEBUG_PRINTF(_L8("COmxILFsm::UseBuffer")); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + if (!appBufferHdr || !aSizeBytes || !apBuffer) + { + return OMX_ErrorBadParameter; + } + + return PopulateBuffer(appBufferHdr, + aPortIndex, + apAppPrivate, + aSizeBytes, + apBuffer); + + } + + +OMX_ERRORTYPE +COmxILFsm::AllocateBuffer(OMX_BUFFERHEADERTYPE** appBufferHdr, + OMX_U32 aPortIndex, + OMX_PTR apAppPrivate, + OMX_U32 aSizeBytes) + { + DEBUG_PRINTF(_L8("COmxILFsm::AllocateBuffer")); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + if (!appBufferHdr || !aSizeBytes) + { + return OMX_ErrorBadParameter; + } + + + return PopulateBuffer(appBufferHdr, + aPortIndex, + apAppPrivate, + aSizeBytes, + 0); + + } + + +OMX_ERRORTYPE +COmxILFsm::FreeBuffer(OMX_U32 aPortIndex, + OMX_BUFFERHEADERTYPE* apBuffer) + { + DEBUG_PRINTF(_L8("COmxILFsm::FreeBuffer")); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + if (!apBuffer) + { + return OMX_ErrorBadParameter; + } + + TBool portDepopulationCompleted = EFalse; + OMX_ERRORTYPE omxRetValue = + ipCurrentState->FreeBuffer(*this, + aPortIndex, + apBuffer, + portDepopulationCompleted); + + if (OMX_ErrorNone == omxRetValue) + { + if (portDepopulationCompleted) + { + if (ESubStateIdleToLoaded == iCurrentStateIndex) + { + if (iPortManager.AllPortsDePopulated()) + { + // Complete here the transition to OMX_StateLoaded + omxRetValue = FsmTransition(EStateLoaded); + if (OMX_ErrorNone == omxRetValue) + { + // Notify the IL client that port depopulation has + // completed sucessfully + omxRetValue = + iCallbacks.TransitionCompleteNotification( + OMX_StateLoaded); + } + } + } + } + } + + if (OMX_ErrorNone == omxRetValue) + { + return OMX_ErrorNone; + } + else + { + return SendOmxErrorEventIfNeeded(omxRetValue); + } + + } + + +OMX_ERRORTYPE +COmxILFsm::EmptyThisBuffer(OMX_BUFFERHEADERTYPE* apBuffer) + { + DEBUG_PRINTF2(_L8("COmxILFsm::EmptyThisBuffer : BUFFER [%X]"), apBuffer); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + if (!apBuffer) + { + return OMX_ErrorBadParameter; + } + + RETURN_OMX_ERROR_AND_EVENT_IF_NEEDED( + ipCurrentState->EmptyThisBuffer(*this, apBuffer)); + + } + + +OMX_ERRORTYPE +COmxILFsm::FillThisBuffer(OMX_BUFFERHEADERTYPE* apBuffer) + { + DEBUG_PRINTF2(_L8("COmxILFsm::FillThisBuffer : BUFFER [%X]"), apBuffer); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + if (!apBuffer) + { + return OMX_ErrorBadParameter; + } + + RETURN_OMX_ERROR_AND_EVENT_IF_NEEDED( + ipCurrentState->FillThisBuffer(*this, apBuffer)); + + } + + +OMX_ERRORTYPE +COmxILFsm::SetCallbacks(const OMX_CALLBACKTYPE* apCallbacks, + const OMX_PTR apAppData) + { + DEBUG_PRINTF(_L8("COmxILFsm::SetCallbacks")); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + if (!apCallbacks) + { + return OMX_ErrorBadParameter; + } + + // This api should only be allowed in OMX_StateLoaded + if (EStateLoaded != iCurrentStateIndex) + { + return OMX_ErrorIncorrectStateOperation; + } + + RETURN_OMX_ERROR_AND_EVENT_IF_NEEDED( + iCallbacks.RegisterILClientCallbacks(apCallbacks, apAppData)); + + } + + +OMX_ERRORTYPE +COmxILFsm::UseEGLImage(OMX_BUFFERHEADERTYPE** /*appBufferHdr*/, + OMX_U32 /*aPortIndex*/, + OMX_PTR /*aAppPrivate*/, + void* /*eglImage*/) + { + DEBUG_PRINTF(_L8("COmxILFsm::UseEGLImage")); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + return OMX_ErrorNotImplemented; + } + +OMX_ERRORTYPE +COmxILFsm::ComponentRoleEnum(OMX_U8* aRole, + OMX_U32 aIndex) const + { + DEBUG_PRINTF(_L8("COmxILFsm::ComponentRoleEnum")); + + __ASSERT_DEBUG(iCurrentStateIndex != EStateMax, + User::Panic(KOmxILFsmPanicCategory, 1)); + + // This api should not be allowed in OMX_StateInvalid + if (EStateInvalid == iCurrentStateIndex) + { + return SendOmxErrorEventIfNeeded(OMX_ErrorInvalidState); + } + + if (!aRole) + { + return OMX_ErrorBadParameter; + } + + RETURN_OMX_ERROR_AND_EVENT_IF_NEEDED( + iConfigManager.ComponentRoleEnum(aRole, + aIndex)); + + } + +/** + This method is here to fullfill the following functionalities: + + -# It is used to make sure that the component error codes are returned to + the IL Client in a way that conforms with Table 3-9 of the OpenMAX IL + 1.1.1 spec. This table specifies which error codes must be sent with + EventHandler. If an error code is to be sent via EventHandler, the API + return code must be OMX_ErrorNone. + + -# This method is also used to invalidate the component whenever an internal + component action returns OMX_ErrorInvalidState. For example, this is + useful when code executed by a port or by the processing function cannot + recover from an internal error. Returning OMX_ErrorInvalidState in that + kind of situation will invalidate the component in + SendOmxErrorEventIfNeeded and the event will be conveyed to the IL Client + as mandated by the spec. + + @param aError An OpenMAX IL error code. + */ +OMX_ERRORTYPE +COmxILFsm::SendOmxErrorEventIfNeeded(OMX_ERRORTYPE aError) + { + DEBUG_PRINTF2(_L8("COmxILFsm::SendOmxErrorEventIfNeeded - aError = 0x%X"), aError); + + OMX_ERRORTYPE returnError = aError; + switch(aError) + { + case OMX_ErrorInsufficientResources: + { + DEBUG_PRINTF(_L8("COmxILFsm::SendOmxErrorEventIfNeeded aError[OMX_ErrorInsufficientResources]")); + iCallbacks.ErrorEventNotification(aError); + } + break; + case OMX_ErrorInvalidState: + { + DEBUG_PRINTF(_L8("COmxILFsm::SendOmxErrorEventIfNeeded aError[OMX_ErrorInvalidState]")); + iCallbacks.ErrorEventNotification(aError); + if (EStateInvalid != iCurrentStateIndex) + { + returnError = OMX_ErrorNone; + } + } + break; + case OMX_ErrorUnderflow: + case OMX_ErrorOverflow: + case OMX_ErrorHardware: + case OMX_ErrorStreamCorrupt: + case OMX_ErrorResourcesLost: + case OMX_ErrorSameState: + case OMX_ErrorResourcesPreempted: + case OMX_ErrorPortUnresponsiveDuringAllocation: + case OMX_ErrorPortUnresponsiveDuringDeallocation: + case OMX_ErrorPortUnresponsiveDuringStop: + case OMX_ErrorIncorrectStateTransition: + case OMX_ErrorPortUnpopulated: + case OMX_ErrorDynamicResourcesUnavailable: + case OMX_ErrorMbErrorsInFrame: + case OMX_ErrorFormatNotDetected: + { + DEBUG_PRINTF2(_L8("COmxILFsm::SendOmxErrorEventIfNeeded aError[%X]"), aError); + iCallbacks.ErrorEventNotification(aError); + returnError = OMX_ErrorNone; + } + break; + }; + + if(OMX_ErrorInvalidState == aError && + EStateInvalid != iCurrentStateIndex) + { + // Invalidate this component. This instance of the component should be + // destroyed by the IL Client after this. No need to check error code. + FsmTransition(EStateInvalid); + } + + return returnError; + + } + +OMX_ERRORTYPE +COmxILFsm::SendOmxErrorEventIfNeeded(OMX_ERRORTYPE aError) const + { + DEBUG_PRINTF(_L8("COmxILFsm::SendOmxErrorEventIfNeeded")); + + return const_cast(this)->SendOmxErrorEventIfNeeded(aError); + + }