omxilcomp/omxilgeneric/filesource/src/omxilfilesourceprocessingfunction.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 02 Sep 2010 20:13:57 +0300
changeset 0 58be5850fb6c
permissions -rw-r--r--
Revision: 2010wk32 Kit: 201035

// 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
 * @internalTechnology
 */

#include <uri8.h>
#include <openmax/il/common/omxilcallbacknotificationif.h>
#include "omxilfilesourceprocessingfunction.h"

const TInt KMaxMsgQueueEntries = 25;
// This represents the number of times this component will respond to a client when the file handle is invalid
// (e.g a URI is not specified) before sending a OMX_BUFFERFLAG_EOS notification flag. This is to prevent
// the endless buffer passing. 250 is chosen as it is more than the number of buffers passed by Khronos conformance
// suite during port communication test.
const TInt KMaxBuffersWhenNoFileName =250; 
const TInt KBufferSizeReturnedWhenNoFileName = 2;

COmxILFileSourceProcessingFunction* COmxILFileSourceProcessingFunction::NewL(MOmxILCallbackNotificationIf& aCallbacks)
	{
	COmxILFileSourceProcessingFunction* self = new (ELeave) COmxILFileSourceProcessingFunction(aCallbacks);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

COmxILFileSourceProcessingFunction::COmxILFileSourceProcessingFunction(MOmxILCallbackNotificationIf& aCallbacks)
: COmxILProcessingFunction(aCallbacks)
	{
	}

void COmxILFileSourceProcessingFunction::ConstructL()
	{
	iState = OMX_StateLoaded;
	ipFileSourceAccess = CFileSourceAccess::NewL(*this);
	ipBufferArrivalHandler = CBufferArrivalHandler::NewL(*this, *ipFileSourceAccess);
	ipPFHelper = CPFHelper::NewL(*this, *ipFileSourceAccess, *ipBufferArrivalHandler);
	}

COmxILFileSourceProcessingFunction::~COmxILFileSourceProcessingFunction()
	{
	if(ipPFHelper &&
	   (iState == OMX_StateInvalid  ||
	    iState == OMX_StateExecuting ||
	    iState == OMX_StatePause))
		{
		ipPFHelper->StopSync();
		}

	delete ipBufferArrivalHandler;
	delete ipPFHelper;
	delete ipFileSourceAccess;
	delete ipUri;
	delete ipFileName;

	// Buffer headers are not owned by the processing function
    iBuffersToFill.Close();
	}

OMX_ERRORTYPE COmxILFileSourceProcessingFunction::StateTransitionIndication(TStateIndex aNewState)
	{
	OMX_ERRORTYPE err = OMX_ErrorNone;
	switch(aNewState)
		{
		case EStateExecuting:
			{
			if (ipPFHelper->ExecuteAsync() != KErrNone)
				{
				err = OMX_ErrorInsufficientResources;
				}
			}
			break;

		case EStateInvalid:
			{
            if (ipPFHelper && ipPFHelper->StopAsync() != KErrNone)
                {
                err = OMX_ErrorInsufficientResources;
                }

			}
			break;

		case EStatePause:
			{
			ipPFHelper->PauseAsync();
			}
			break;

		case EStateIdle:
			{
			ipPFHelper->IdleAsync();
			}
			break;

		case EStateLoaded:
		case EStateWaitForResources:
			{
			if (ipPFHelper && ipPFHelper->StopAsync() != KErrNone)
				{
				err = OMX_ErrorInsufficientResources;
				}
			}
			break;

		case ESubStateExecutingToIdle:
			{
			ipPFHelper->StopAsync();
			}
			break;
		case ESubStatePauseToIdle:
	    case ESubStateLoadedToIdle:
	    case ESubStateIdleToLoaded:
			break;

		default:
			{
			err = OMX_ErrorIncorrectStateTransition;
			}
		};

	return err;
	}

OMX_ERRORTYPE COmxILFileSourceProcessingFunction::BufferFlushingIndication(TUint32 aPortIndex, OMX_DIRTYPE aDirection)
	{
    OMX_ERRORTYPE err = OMX_ErrorNone;
    if ((aPortIndex == OMX_ALL && aDirection == OMX_DirMax) ||
        (aPortIndex == 0 && aDirection == OMX_DirOutput))
        {
        err = CPFHelper::ConvertSymbianErrorType(ipPFHelper->FlushIndication());
        }
    else
        {
        err = OMX_ErrorBadParameter;
        }
    return err;
    }

OMX_ERRORTYPE COmxILFileSourceProcessingFunction::ParamIndication(OMX_INDEXTYPE aParamIndex, const TAny* apComponentParameterStructure)
	{
	OMX_ERRORTYPE err = OMX_ErrorNone;
	switch(aParamIndex)
		{
		case OMX_IndexParamPortDefinition:
			{
			//const OMX_PARAM_PORTDEFINITIONTYPE* portDefinition = static_cast<const OMX_PARAM_PORTDEFINITIONTYPE*>(apComponentParameterStructure);
			//nothing to do
			//
			//the number of buffers may change depending on capture mode (single shot vs burst mode)
			//in that case, we need to do something for PF...
			break;
			}
		case OMX_IndexParamContentURI:
			{
			const OMX_PARAM_CONTENTURITYPE* contentUriType = reinterpret_cast<const OMX_PARAM_CONTENTURITYPE*>(apComponentParameterStructure);
			err = SetFileName(contentUriType);
			break;
			}
		default:
			{
			err = OMX_ErrorUnsupportedIndex;
			}
		}
	return err;
	}

OMX_ERRORTYPE COmxILFileSourceProcessingFunction::ConfigIndication(OMX_INDEXTYPE /*aConfigIndex*/, const TAny* /*apComponentConfigStructure*/)
	{
	return OMX_ErrorNone;
	}

OMX_ERRORTYPE COmxILFileSourceProcessingFunction::BufferIndication(OMX_BUFFERHEADERTYPE* apBufferHeader, OMX_DIRTYPE aDirection)
	{
	if (aDirection == OMX_DirOutput)
    	{
    	if (ipBufferArrivalHandler->BufferIndication(apBufferHeader) != KErrNone)
    		{
    		return OMX_ErrorInsufficientResources;
    		}
		}
    else
    	{
    	return OMX_ErrorBadParameter;
    	}

    return OMX_ErrorNone;
	}

OMX_BOOL COmxILFileSourceProcessingFunction::BufferRemovalIndication(OMX_BUFFERHEADERTYPE* apBufferHeader, OMX_DIRTYPE /*aDirection*/)
	{
	return ipPFHelper->RemoveBufferIndication(apBufferHeader);
	}

MOmxILCallbackNotificationIf& COmxILFileSourceProcessingFunction::GetCallbacks()
	{
	return iCallbacks;
	}

OMX_ERRORTYPE COmxILFileSourceProcessingFunction::SetFileName(const OMX_PARAM_CONTENTURITYPE* aContentUriType)
	{
	ASSERT(aContentUriType);
	delete ipFileName;
	ipFileName = NULL;
	delete ipUri;
	ipUri = NULL;

	TInt sizeOfUri = aContentUriType->nSize - _FOFF(OMX_PARAM_CONTENTURITYPE, contentURI); //Actual size of URI
	if (sizeOfUri <= 0)
		{
		return OMX_ErrorBadParameter;
		}

	// Don't include the zero character at the end.
	TPtrC8 uriDes(aContentUriType->contentURI,sizeOfUri);

	TInt err = KErrNone;
	do
		{
		TUriParser8 parser;
		err = parser.Parse(uriDes);
		if (err != KErrNone)
			{
			break;
			}

		TRAP(err, ipFileName = parser.GetFileNameL());
		if (err != KErrNone)
			{
			break;
			}

		// Remove Null charcter '\0' if any.
		TPtr filePtr(ipFileName->Des());
		TInt index = filePtr.LocateReverse('\0');
		if (index != KErrNotFound && index == filePtr.Length()-1)
		    {
		    filePtr.Delete(index,1);
		    }

		uriDes.Set(reinterpret_cast<const TUint8 *>(aContentUriType), aContentUriType->nSize );
        ipUri = uriDes.Alloc();
        if (!ipUri)
            {
            err = KErrNoMemory;
            break;
            }

		return OMX_ErrorNone;
		}
	while (EFalse);

	// Something failed.
	__ASSERT_DEBUG( (err == KErrNone), User::Panic(_L("UriParsing"), err) );

	delete ipFileName;
	ipFileName = NULL;
	delete ipUri;
	ipUri = NULL;
	return (err == KErrNoMemory ? OMX_ErrorInsufficientResources : OMX_ErrorBadParameter);
	}


const HBufC* COmxILFileSourceProcessingFunction::FileName() const
	{
	return ipFileName;
	}

const HBufC8* COmxILFileSourceProcessingFunction::Uri() const
	{
	return ipUri;
	}

COmxILFileSourceProcessingFunction::CFileSourceAccess* COmxILFileSourceProcessingFunction::CFileSourceAccess::NewL(COmxILFileSourceProcessingFunction& aParent)
	{
	CFileSourceAccess* self = new (ELeave) CFileSourceAccess(aParent);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

COmxILFileSourceProcessingFunction::CFileSourceAccess::CFileSourceAccess(COmxILFileSourceProcessingFunction& aParent)
	: CActive(EPriorityStandard),
	iParent(aParent),
	iBufferOffset(0),
	iReadBuffer(0,0),
	iEOSFlag(EFalse)
	{
	CActiveScheduler::Add(this);
	}

void COmxILFileSourceProcessingFunction::CFileSourceAccess::ConstructL()
	{
	User::LeaveIfError(iFs.Connect());
	}

COmxILFileSourceProcessingFunction::CFileSourceAccess::~CFileSourceAccess()
	{
	Cancel();

	iFileHandle.Close();
	iFs.Close();
	}

void COmxILFileSourceProcessingFunction::CFileSourceAccess::RunL()
	{
	// The buffer is not on the list implies that they have already been flushed/spotted
	// via BufferFlushingIndication/BufferRemovalIndication
	TInt index = iParent.iBuffersToFill.Find(iCurrentBuffer);
	if (KErrNotFound != index)
		{
		switch(iStatus.Int())
			{
			case KErrNone:
				{
				if (iReadBuffer.Length()==0) //the end of the file
				    {
				    iFileHandle.Close();
				    iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
				    iParent.GetCallbacks().EventNotification(OMX_EventBufferFlag, iCurrentBuffer->nOutputPortIndex, OMX_BUFFERFLAG_EOS, NULL);
				    iEOSFlag = ETrue;
				    }
				iCurrentBuffer->nFilledLen=iReadBuffer.Length();
				iCurrentBuffer->nOffset = 0;
				break;
				}
			default:
				{
				User::Leave(iStatus.Int());
				}
			};

		iParent.GetCallbacks().BufferDoneNotification(iCurrentBuffer,iCurrentBuffer->nOutputPortIndex,OMX_DirOutput);
		iParent.iBuffersToFill.Remove(index);
		iCurrentBuffer = NULL;
		}
	
    if(iFileHandle.SubSessionHandle() != 0)
        {
        ProcessNextBuffer();
        }
	}

TInt COmxILFileSourceProcessingFunction::CFileSourceAccess::ProcessNextBuffer()
	{
	TInt err = KErrNone;
	if ((iParent.iBuffersToFill.Count() > 0) && !IsActive() && iParent.iState == OMX_StateExecuting)
		{
		iCurrentBuffer = iParent.iBuffersToFill[0];
		iReadBuffer.Set(iCurrentBuffer->pBuffer, iCurrentBuffer->nAllocLen, iCurrentBuffer->nAllocLen);
        if (iFileHandle.SubSessionHandle() == 0)
            {
            if(iEOSFlag == EFalse)
                {
                // This condition caters for when an IL client does not set the URI before trasitioning to 
                // executing state (like the Khronos conformance suite). The proposed way to deal with this is to keep
                // sending BufferDone notification with blank buffers with size >0 for KMaxBuffersWhenNoFileName number
                // of times before OMX_BUFFERFLAG_EOS flag is sent to client. This simulates a normal communication.
                if( iEOSBufferNotificationCount <= KMaxBuffersWhenNoFileName )
                    {
                    TUint nBufferSize = 0;
                    if (iEOSBufferNotificationCount < KMaxBuffersWhenNoFileName)
                        {
                        nBufferSize = KBufferSizeReturnedWhenNoFileName;
                        }
                    iReadBuffer.Set(iCurrentBuffer->pBuffer, nBufferSize, iCurrentBuffer->nAllocLen);                  
                    iEOSBufferNotificationCount++;              
                    SetActive();
                    TRequestStatus* status(&iStatus);
                    User::RequestComplete(status, KErrNone);
                    }
                }
            else
                {
                iReadBuffer.Set(iCurrentBuffer->pBuffer, iCurrentBuffer->nAllocLen, iCurrentBuffer->nAllocLen);
                // do nothing. this menas that all operations have completed succesfully.
                }
            
            }
        else
            {
            iFileHandle.Read(iReadBuffer, iCurrentBuffer->nAllocLen, iStatus);
            SetActive();
            }
		}
	return err;
	}

void COmxILFileSourceProcessingFunction::CFileSourceAccess::DoCancel()
	{
	if (iFileHandle.SubSessionHandle() != 0)
	    {
	    iFileHandle.Close();
	    }
	iEOSFlag = EFalse;
	iEOSBufferNotificationCount = 0;
	
	iCurrentBuffer = NULL;
	}

TInt COmxILFileSourceProcessingFunction::CFileSourceAccess::Execute()
	{
	iEOSFlag = EFalse;
	iEOSBufferNotificationCount = 0;
	iParent.iState = OMX_StateExecuting;
	return ProcessNextBuffer();
	}

void COmxILFileSourceProcessingFunction::CFileSourceAccess::Pause()
	{
	iParent.iState = OMX_StatePause;
	}

void COmxILFileSourceProcessingFunction::CFileSourceAccess::Idle()
    {
    iParent.iState = OMX_StateIdle;
    iParent.iBuffersToFill.Reset();
    }

void COmxILFileSourceProcessingFunction::CFileSourceAccess::CancelDataTransfer()
    {
    if(iFileHandle.SubSessionHandle() != 0)
        {
        iFileHandle.ReadCancel();
        }
    }

void COmxILFileSourceProcessingFunction::CFileSourceAccess::Stop()
	{
	if(iParent.iState == OMX_StateExecuting || iParent.iState == OMX_StatePause)
		{
		Cancel();
		iParent.iState = OMX_StateIdle;
		}
	}

COmxILFileSourceProcessingFunction::CPFHelper* COmxILFileSourceProcessingFunction::CPFHelper::NewL(COmxILFileSourceProcessingFunction& aParent, CFileSourceAccess& aFileSourceAccess, CBufferArrivalHandler& aBufferArrivalHandler)
	{
	CPFHelper* self = new (ELeave) CPFHelper(aParent, aFileSourceAccess, aBufferArrivalHandler);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

COmxILFileSourceProcessingFunction::CPFHelper::CPFHelper(COmxILFileSourceProcessingFunction& aParent, CFileSourceAccess& aFileSourceAccess, CBufferArrivalHandler& aBufferArrivalHandler)
: CActive(CActive::EPriorityUserInput),
  iParent(aParent),
  iFileSourceAccess(aFileSourceAccess),
  iBufferArrivalHandler(aBufferArrivalHandler)
	{
	CActiveScheduler::Add(this);
    iRunLContext = RThread();
	}

void COmxILFileSourceProcessingFunction::CPFHelper::ConstructL()
	{
    User::LeaveIfError(iWaitSemaphore.CreateLocal(0));
	User::LeaveIfError(iMsgQueue.CreateLocal(KMaxMsgQueueEntries));
	SetActive();
	iMsgQueue.NotifyDataAvailable(iStatus);
	}

COmxILFileSourceProcessingFunction::CPFHelper::~CPFHelper()
	{
	Cancel();
	iMsgQueue.Close();
    iRunLContext.Close();
    iWaitSemaphore.Close();
	}

void COmxILFileSourceProcessingFunction::CPFHelper::RunL()
	{
	TInt err = ProcessQueue();
	if (err != KErrNone)
		{
		iParent.GetCallbacks().ErrorEventNotification( ConvertSymbianErrorType(err) );
		}

	// setup for next callbacks
	SetActive();
	iMsgQueue.NotifyDataAvailable(iStatus);
	}

void COmxILFileSourceProcessingFunction::CPFHelper::DoCancel()
	{
	if (iMsgQueue.Handle())
		{
		ProcessQueue();
		iMsgQueue.CancelDataAvailable();
		}
	}

TInt COmxILFileSourceProcessingFunction::CPFHelper::ProcessQueue()
	{
	TProcMessage msg;
	TInt err = KErrNone;

	while (iMsgQueue.Receive(msg) == KErrNone)
		{
		switch (msg.iType)
			{
			case EExecuteCommand:
				{
                const HBufC* fileName = iParent.FileName();
	            if (fileName && iFileSourceAccess.iFileHandle.SubSessionHandle() == 0)
                    {
                    err = iFileSourceAccess.iFileHandle.Open(iFileSourceAccess.iFs, *fileName, EFileRead | EFileShareReadersOnly);
                    }
	            // Transition to execute only when opening the file succeeds or there is no file name at all
                if ( err == KErrNone)
                    {
                    err = iFileSourceAccess.Execute();
                    }
				break;
				}

			case EStopCommand:
				{
				iFileSourceAccess.Stop();
				break;
				}

			case EPauseCommand:
				{
				iFileSourceAccess.Pause();
				break;
				}

			case EIdleCommand:
			    {
			    iFileSourceAccess.Idle();
			    break;
			    }
			    
			case EFlushCommand:
			    {
			    // Carry out the flush and wake up the non-Active Scheduler client.
			    PerformFlush();
			    iWaitSemaphore.Signal();
			    break;
			    }
			    
			case ERemoveBufferCommand:
			    {
			    // Carry out the buffer removal and wake up the non-Active Scheduler client.
			    TBufferRemovalArgs* args = reinterpret_cast<TBufferRemovalArgs*>(msg.iPtr);
			    *(args->iHdrRemoved) = PerformBufferRemoval(args->ipHeader);
			    iWaitSemaphore.Signal();
			    break;
			    }
			    
			default:
				{
				break;
				}
			}

		if (err)
			{
			break;
			}
		}
	return err;
	}

TInt COmxILFileSourceProcessingFunction::CPFHelper::ExecuteAsync()
	{
	TProcMessage message;
	message.iType = EExecuteCommand;
	return iMsgQueue.Send(message);
	}

TInt COmxILFileSourceProcessingFunction::CPFHelper::StopAsync()
	{
	TProcMessage message;
	message.iType = EStopCommand;
	return iMsgQueue.Send(message);
	}

TInt COmxILFileSourceProcessingFunction::CPFHelper::PauseAsync()
    {
    TProcMessage message;
    message.iType = EPauseCommand;
    return iMsgQueue.Send(message);
    }

void COmxILFileSourceProcessingFunction::CPFHelper::StopSync()
    {
    // Cancel to process the existing queue before handling this command
    Cancel();
    iFileSourceAccess.Stop();

    // setup for next callbacks
    SetActive();
    iMsgQueue.NotifyDataAvailable(iStatus);
    }

TInt COmxILFileSourceProcessingFunction::CPFHelper::IdleAsync()
    {
    TProcMessage message;
    message.iType = EIdleCommand;
    return iMsgQueue.Send(message);
    }

TInt COmxILFileSourceProcessingFunction::CPFHelper::FlushIndication()
    {
    TInt error = KErrNone;    
    RThread currentThread = RThread();
    if (currentThread.Id() == iRunLContext.Id())
        {
        // Running in the same context as CFileSourceAccess::RunL() so 
        // sure of no concurrency issues.
        PerformFlush();
        }
    else
        {
        // Running in a different thread, meaning the client does
        // not have an active scheduler.  To avoid concurrency problems 
        // during the flush, switch to the thread in which the active objects'
        // execution is handled.
        TProcMessage message;
        message.iType = EFlushCommand;
        error =  iMsgQueue.Send(message);
        if (error == KErrNone)
            {
            iWaitSemaphore.Wait();
            }
        }
    currentThread.Close();
    return error;
    }

void COmxILFileSourceProcessingFunction::CPFHelper::PerformFlush()
    {
    // Running in the same context as CFileSourceAccess::RunL() so 
    // sure of no concurrency issues.
    
    // So that we don't continue to write to the buffer once it's returned.
    iFileSourceAccess.CancelDataTransfer();
    
    while (iParent.iBuffersToFill.Count() > 0)
        {
        OMX_BUFFERHEADERTYPE* pBufferHeader = iParent.iBuffersToFill[0];
        iParent.iBuffersToFill.Remove(0);
        iParent.iCallbacks.BufferDoneNotification(pBufferHeader,
                                                pBufferHeader->nOutputPortIndex,
                                                OMX_DirOutput);
        }
    
    iBufferArrivalHandler.FlushIndication();    
    }

OMX_BOOL COmxILFileSourceProcessingFunction::CPFHelper::RemoveBufferIndication(OMX_BUFFERHEADERTYPE* apBufferHeader)
    {
    TInt error = KErrNone;    
    RThread currentThread = RThread();
    if (currentThread.Id() == iRunLContext.Id())
        {
        currentThread.Close();
        // Running in the same context as CFileSourceAccess::RunL() so 
        // sure of no concurrency issues.
        return PerformBufferRemoval(apBufferHeader);
        }
    else
        {
        currentThread.Close();
        // Running in a different thread, meaning the client does
        // not have an active scheduler.  To avoid concurrency problems 
        // during the flush, switch to the thread in which the active objects'
        // execution is handled.
        TProcMessage message;
        OMX_BOOL bufferFound;
        TBufferRemovalArgs messageArgs;
        messageArgs.ipHeader = apBufferHeader;
        messageArgs.iHdrRemoved = &bufferFound;
        message.iType = ERemoveBufferCommand;
        message.iPtr = &messageArgs;
        error =  iMsgQueue.Send(message);
        if (error == KErrNone)
            {
            iWaitSemaphore.Wait();
            return bufferFound;
            }
        iParent.GetCallbacks().ErrorEventNotification(OMX_ErrorInsufficientResources);
        return OMX_FALSE;
        }
    }

OMX_BOOL COmxILFileSourceProcessingFunction::CPFHelper::PerformBufferRemoval(OMX_BUFFERHEADERTYPE* apBufferHeader)
    {
    if (iParent.iBuffersToFill.Count() < 1)
        {
        return OMX_FALSE;
        }
    
    if (iParent.iBuffersToFill[0] == apBufferHeader)
        {
        iFileSourceAccess.CancelDataTransfer();
        iParent.iBuffersToFill.Remove(0);
        return OMX_TRUE;
        }
    
    TInt count = iParent.iBuffersToFill.Count();
    for (TInt index = 1; index < count; ++index)
        {
        if (iParent.iBuffersToFill[index] == apBufferHeader)
            {
            iParent.iBuffersToFill.Remove(index);
            return OMX_TRUE;
            }
        }
    
    return iBufferArrivalHandler.RemoveBufferIndication(apBufferHeader);
    }

/**
 Converts a Symbian error code to an OpenMAX error code.
 @param     aError The Symbian error code.
 @return    The OpenMAX error code.
 */
OMX_ERRORTYPE COmxILFileSourceProcessingFunction::CPFHelper::ConvertSymbianErrorType(TInt aError)
    {
    // In the current implementation this function is only used for the return code in the
    // callback methods. Currently the only expected errors KErrNone and KErrOverflow.

    OMX_ERRORTYPE err = OMX_ErrorNone;
    switch (aError)
        {
    case KErrNone:
        err = OMX_ErrorNone;
        break;
    case KErrOverflow:
    case KErrNoMemory:
        err = OMX_ErrorInsufficientResources;
        break;
    case KErrNotSupported:
        err = OMX_ErrorNotImplemented;
        break;
    case KErrNotReady:
        err = OMX_ErrorNotReady;
        break;
    case KErrGeneral:
    default:
        err = OMX_ErrorUndefined;
        }
    return err;
    }

COmxILFileSourceProcessingFunction::CBufferArrivalHandler* COmxILFileSourceProcessingFunction::CBufferArrivalHandler::NewL(COmxILFileSourceProcessingFunction& aParent, CFileSourceAccess& aFileSourceAccess)
    {
    CBufferArrivalHandler* self = new (ELeave) CBufferArrivalHandler(aParent, aFileSourceAccess);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

COmxILFileSourceProcessingFunction::CBufferArrivalHandler::CBufferArrivalHandler(COmxILFileSourceProcessingFunction& aParent, CFileSourceAccess& aFileSourceAccess)
: CActive(CActive::EPriorityStandard),
  iParent(aParent),
  iFileSourceAccess(aFileSourceAccess)
    { 
    CActiveScheduler::Add(this);
    }

void COmxILFileSourceProcessingFunction::CBufferArrivalHandler::ConstructL()
    {
    User::LeaveIfError(iMsgQueue.CreateLocal(KMaxMsgQueueEntries));
    SetActive();
    iMsgQueue.NotifyDataAvailable(iStatus);
    }

COmxILFileSourceProcessingFunction::CBufferArrivalHandler::~CBufferArrivalHandler()
    {
    Cancel();
    iMsgQueue.Close();  // Queue should be emptied by now
    }
        
TInt COmxILFileSourceProcessingFunction::CBufferArrivalHandler::BufferIndication(OMX_BUFFERHEADERTYPE* apBufferHeader)
    {
    TBufferIndicationMessage msg;
    msg.iBufferHdr = apBufferHeader;
    return iMsgQueue.Send(msg);    
    }

/*
 * Bear in mind that this results in BufferDoneNotifications and so should be called at the end of of the 
 * flush sequence to ensure headers are completed in the order they were received.
 */
void COmxILFileSourceProcessingFunction::CBufferArrivalHandler::FlushIndication()
    {
    TBufferIndicationMessage msg;
    
    while (iMsgQueue.Receive(msg) == KErrNone)
        {
        iParent.GetCallbacks().BufferDoneNotification(msg.iBufferHdr, msg.iBufferHdr->nOutputPortIndex,OMX_DirOutput);
        }
    }

OMX_BOOL COmxILFileSourceProcessingFunction::CBufferArrivalHandler::RemoveBufferIndication(OMX_BUFFERHEADERTYPE* apBufferHeader)
    {
    RArray<TBufferIndicationMessage> bufferedMsgs;
    TBufferIndicationMessage msg;
    
    OMX_BOOL hdrFound = OMX_FALSE;
    while (iMsgQueue.Receive(msg) == KErrNone)
        {
        if (msg.iBufferHdr == apBufferHeader)
            {
            hdrFound = OMX_TRUE;
            }
        else
            {
            TInt error = bufferedMsgs.Append(msg);
            if (error != KErrNone)
                {
                // to prevent potential buffer leakage if the Append operation fails
                iParent.GetCallbacks().BufferDoneNotification(msg.iBufferHdr, msg.iBufferHdr->nOutputPortIndex,OMX_DirOutput);
                }
            }
        }
    
    TInt count = bufferedMsgs.Count();
    for (TInt index = 0; index < count; ++index)
        {
        // There's the potential here, in an environment when 3+ threads
        // (which is possible in the case of a non-AS client and a multi-threaded
        // tunneled component, e.g. Bellagio) are manipulatng the component, for
        // a buffer to be inserted out of order if a FillThisBuffer() command comes
        // in during the move to Idle and with particular thread scheduling 
        // sequences.  However as we only have one port and this command is called as
        // part of a move to Idle or port disablement then we should get a 
        // BufferRemovalNotification() for every buffer so in this instance it shouldn't
        // be a problem.
        iMsgQueue.Send(bufferedMsgs[index]);
        }
    return hdrFound;
    }

void COmxILFileSourceProcessingFunction::CBufferArrivalHandler::RunL()
    {
    TBufferIndicationMessage msg;
    TInt err = iMsgQueue.Receive(msg);
    
    if ((err == KErrNone) && (iParent.iState == OMX_StateExecuting ||
                                iParent.iState == OMX_StatePause || 
                                iParent.iState == OMX_StateIdle))
        {
        err = iParent.iBuffersToFill.Append(msg.iBufferHdr);
        
        if(err == KErrNone)
            {
            if(iParent.iState != OMX_StateIdle)
                {
                err = iFileSourceAccess.ProcessNextBuffer();
                }
            }
        else
            {
            iParent.GetCallbacks().ErrorEventNotification(OMX_ErrorInsufficientResources);
            // to prevent potential buffer leakage if the Append operation fails
            iParent.GetCallbacks().BufferDoneNotification(msg.iBufferHdr, msg.iBufferHdr->nOutputPortIndex,OMX_DirOutput);
            }        
        }
            
    SetActive();
    iMsgQueue.NotifyDataAvailable(iStatus);  
    }

void COmxILFileSourceProcessingFunction::CBufferArrivalHandler::DoCancel()
    {
    iMsgQueue.CancelDataAvailable();
    }