omxilcomp/omxilgeneric/filesource/src/omxilfilesourceprocessingfunction.cpp
changeset 0 58be5850fb6c
equal deleted inserted replaced
-1:000000000000 0:58be5850fb6c
       
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 
       
    17 
       
    18 /**
       
    19  * @file
       
    20  * @internalTechnology
       
    21  */
       
    22 
       
    23 #include <uri8.h>
       
    24 #include <openmax/il/common/omxilcallbacknotificationif.h>
       
    25 #include "omxilfilesourceprocessingfunction.h"
       
    26 
       
    27 const TInt KMaxMsgQueueEntries = 25;
       
    28 // This represents the number of times this component will respond to a client when the file handle is invalid
       
    29 // (e.g a URI is not specified) before sending a OMX_BUFFERFLAG_EOS notification flag. This is to prevent
       
    30 // the endless buffer passing. 250 is chosen as it is more than the number of buffers passed by Khronos conformance
       
    31 // suite during port communication test.
       
    32 const TInt KMaxBuffersWhenNoFileName =250; 
       
    33 const TInt KBufferSizeReturnedWhenNoFileName = 2;
       
    34 
       
    35 COmxILFileSourceProcessingFunction* COmxILFileSourceProcessingFunction::NewL(MOmxILCallbackNotificationIf& aCallbacks)
       
    36 	{
       
    37 	COmxILFileSourceProcessingFunction* self = new (ELeave) COmxILFileSourceProcessingFunction(aCallbacks);
       
    38 	CleanupStack::PushL(self);
       
    39 	self->ConstructL();
       
    40 	CleanupStack::Pop(self);
       
    41 	return self;
       
    42 	}
       
    43 
       
    44 COmxILFileSourceProcessingFunction::COmxILFileSourceProcessingFunction(MOmxILCallbackNotificationIf& aCallbacks)
       
    45 : COmxILProcessingFunction(aCallbacks)
       
    46 	{
       
    47 	}
       
    48 
       
    49 void COmxILFileSourceProcessingFunction::ConstructL()
       
    50 	{
       
    51 	iState = OMX_StateLoaded;
       
    52 	ipFileSourceAccess = CFileSourceAccess::NewL(*this);
       
    53 	ipBufferArrivalHandler = CBufferArrivalHandler::NewL(*this, *ipFileSourceAccess);
       
    54 	ipPFHelper = CPFHelper::NewL(*this, *ipFileSourceAccess, *ipBufferArrivalHandler);
       
    55 	}
       
    56 
       
    57 COmxILFileSourceProcessingFunction::~COmxILFileSourceProcessingFunction()
       
    58 	{
       
    59 	if(ipPFHelper &&
       
    60 	   (iState == OMX_StateInvalid  ||
       
    61 	    iState == OMX_StateExecuting ||
       
    62 	    iState == OMX_StatePause))
       
    63 		{
       
    64 		ipPFHelper->StopSync();
       
    65 		}
       
    66 
       
    67 	delete ipBufferArrivalHandler;
       
    68 	delete ipPFHelper;
       
    69 	delete ipFileSourceAccess;
       
    70 	delete ipUri;
       
    71 	delete ipFileName;
       
    72 
       
    73 	// Buffer headers are not owned by the processing function
       
    74     iBuffersToFill.Close();
       
    75 	}
       
    76 
       
    77 OMX_ERRORTYPE COmxILFileSourceProcessingFunction::StateTransitionIndication(TStateIndex aNewState)
       
    78 	{
       
    79 	OMX_ERRORTYPE err = OMX_ErrorNone;
       
    80 	switch(aNewState)
       
    81 		{
       
    82 		case EStateExecuting:
       
    83 			{
       
    84 			if (ipPFHelper->ExecuteAsync() != KErrNone)
       
    85 				{
       
    86 				err = OMX_ErrorInsufficientResources;
       
    87 				}
       
    88 			}
       
    89 			break;
       
    90 
       
    91 		case EStateInvalid:
       
    92 			{
       
    93             if (ipPFHelper && ipPFHelper->StopAsync() != KErrNone)
       
    94                 {
       
    95                 err = OMX_ErrorInsufficientResources;
       
    96                 }
       
    97 
       
    98 			}
       
    99 			break;
       
   100 
       
   101 		case EStatePause:
       
   102 			{
       
   103 			ipPFHelper->PauseAsync();
       
   104 			}
       
   105 			break;
       
   106 
       
   107 		case EStateIdle:
       
   108 			{
       
   109 			ipPFHelper->IdleAsync();
       
   110 			}
       
   111 			break;
       
   112 
       
   113 		case EStateLoaded:
       
   114 		case EStateWaitForResources:
       
   115 			{
       
   116 			if (ipPFHelper && ipPFHelper->StopAsync() != KErrNone)
       
   117 				{
       
   118 				err = OMX_ErrorInsufficientResources;
       
   119 				}
       
   120 			}
       
   121 			break;
       
   122 
       
   123 		case ESubStateExecutingToIdle:
       
   124 			{
       
   125 			ipPFHelper->StopAsync();
       
   126 			}
       
   127 			break;
       
   128 		case ESubStatePauseToIdle:
       
   129 	    case ESubStateLoadedToIdle:
       
   130 	    case ESubStateIdleToLoaded:
       
   131 			break;
       
   132 
       
   133 		default:
       
   134 			{
       
   135 			err = OMX_ErrorIncorrectStateTransition;
       
   136 			}
       
   137 		};
       
   138 
       
   139 	return err;
       
   140 	}
       
   141 
       
   142 OMX_ERRORTYPE COmxILFileSourceProcessingFunction::BufferFlushingIndication(TUint32 aPortIndex, OMX_DIRTYPE aDirection)
       
   143 	{
       
   144     OMX_ERRORTYPE err = OMX_ErrorNone;
       
   145     if ((aPortIndex == OMX_ALL && aDirection == OMX_DirMax) ||
       
   146         (aPortIndex == 0 && aDirection == OMX_DirOutput))
       
   147         {
       
   148         err = CPFHelper::ConvertSymbianErrorType(ipPFHelper->FlushIndication());
       
   149         }
       
   150     else
       
   151         {
       
   152         err = OMX_ErrorBadParameter;
       
   153         }
       
   154     return err;
       
   155     }
       
   156 
       
   157 OMX_ERRORTYPE COmxILFileSourceProcessingFunction::ParamIndication(OMX_INDEXTYPE aParamIndex, const TAny* apComponentParameterStructure)
       
   158 	{
       
   159 	OMX_ERRORTYPE err = OMX_ErrorNone;
       
   160 	switch(aParamIndex)
       
   161 		{
       
   162 		case OMX_IndexParamPortDefinition:
       
   163 			{
       
   164 			//const OMX_PARAM_PORTDEFINITIONTYPE* portDefinition = static_cast<const OMX_PARAM_PORTDEFINITIONTYPE*>(apComponentParameterStructure);
       
   165 			//nothing to do
       
   166 			//
       
   167 			//the number of buffers may change depending on capture mode (single shot vs burst mode)
       
   168 			//in that case, we need to do something for PF...
       
   169 			break;
       
   170 			}
       
   171 		case OMX_IndexParamContentURI:
       
   172 			{
       
   173 			const OMX_PARAM_CONTENTURITYPE* contentUriType = reinterpret_cast<const OMX_PARAM_CONTENTURITYPE*>(apComponentParameterStructure);
       
   174 			err = SetFileName(contentUriType);
       
   175 			break;
       
   176 			}
       
   177 		default:
       
   178 			{
       
   179 			err = OMX_ErrorUnsupportedIndex;
       
   180 			}
       
   181 		}
       
   182 	return err;
       
   183 	}
       
   184 
       
   185 OMX_ERRORTYPE COmxILFileSourceProcessingFunction::ConfigIndication(OMX_INDEXTYPE /*aConfigIndex*/, const TAny* /*apComponentConfigStructure*/)
       
   186 	{
       
   187 	return OMX_ErrorNone;
       
   188 	}
       
   189 
       
   190 OMX_ERRORTYPE COmxILFileSourceProcessingFunction::BufferIndication(OMX_BUFFERHEADERTYPE* apBufferHeader, OMX_DIRTYPE aDirection)
       
   191 	{
       
   192 	if (aDirection == OMX_DirOutput)
       
   193     	{
       
   194     	if (ipBufferArrivalHandler->BufferIndication(apBufferHeader) != KErrNone)
       
   195     		{
       
   196     		return OMX_ErrorInsufficientResources;
       
   197     		}
       
   198 		}
       
   199     else
       
   200     	{
       
   201     	return OMX_ErrorBadParameter;
       
   202     	}
       
   203 
       
   204     return OMX_ErrorNone;
       
   205 	}
       
   206 
       
   207 OMX_BOOL COmxILFileSourceProcessingFunction::BufferRemovalIndication(OMX_BUFFERHEADERTYPE* apBufferHeader, OMX_DIRTYPE /*aDirection*/)
       
   208 	{
       
   209 	return ipPFHelper->RemoveBufferIndication(apBufferHeader);
       
   210 	}
       
   211 
       
   212 MOmxILCallbackNotificationIf& COmxILFileSourceProcessingFunction::GetCallbacks()
       
   213 	{
       
   214 	return iCallbacks;
       
   215 	}
       
   216 
       
   217 OMX_ERRORTYPE COmxILFileSourceProcessingFunction::SetFileName(const OMX_PARAM_CONTENTURITYPE* aContentUriType)
       
   218 	{
       
   219 	ASSERT(aContentUriType);
       
   220 	delete ipFileName;
       
   221 	ipFileName = NULL;
       
   222 	delete ipUri;
       
   223 	ipUri = NULL;
       
   224 
       
   225 	TInt sizeOfUri = aContentUriType->nSize - _FOFF(OMX_PARAM_CONTENTURITYPE, contentURI); //Actual size of URI
       
   226 	if (sizeOfUri <= 0)
       
   227 		{
       
   228 		return OMX_ErrorBadParameter;
       
   229 		}
       
   230 
       
   231 	// Don't include the zero character at the end.
       
   232 	TPtrC8 uriDes(aContentUriType->contentURI,sizeOfUri);
       
   233 
       
   234 	TInt err = KErrNone;
       
   235 	do
       
   236 		{
       
   237 		TUriParser8 parser;
       
   238 		err = parser.Parse(uriDes);
       
   239 		if (err != KErrNone)
       
   240 			{
       
   241 			break;
       
   242 			}
       
   243 
       
   244 		TRAP(err, ipFileName = parser.GetFileNameL());
       
   245 		if (err != KErrNone)
       
   246 			{
       
   247 			break;
       
   248 			}
       
   249 
       
   250 		// Remove Null charcter '\0' if any.
       
   251 		TPtr filePtr(ipFileName->Des());
       
   252 		TInt index = filePtr.LocateReverse('\0');
       
   253 		if (index != KErrNotFound && index == filePtr.Length()-1)
       
   254 		    {
       
   255 		    filePtr.Delete(index,1);
       
   256 		    }
       
   257 
       
   258 		uriDes.Set(reinterpret_cast<const TUint8 *>(aContentUriType), aContentUriType->nSize );
       
   259         ipUri = uriDes.Alloc();
       
   260         if (!ipUri)
       
   261             {
       
   262             err = KErrNoMemory;
       
   263             break;
       
   264             }
       
   265 
       
   266 		return OMX_ErrorNone;
       
   267 		}
       
   268 	while (EFalse);
       
   269 
       
   270 	// Something failed.
       
   271 	__ASSERT_DEBUG( (err == KErrNone), User::Panic(_L("UriParsing"), err) );
       
   272 
       
   273 	delete ipFileName;
       
   274 	ipFileName = NULL;
       
   275 	delete ipUri;
       
   276 	ipUri = NULL;
       
   277 	return (err == KErrNoMemory ? OMX_ErrorInsufficientResources : OMX_ErrorBadParameter);
       
   278 	}
       
   279 
       
   280 
       
   281 const HBufC* COmxILFileSourceProcessingFunction::FileName() const
       
   282 	{
       
   283 	return ipFileName;
       
   284 	}
       
   285 
       
   286 const HBufC8* COmxILFileSourceProcessingFunction::Uri() const
       
   287 	{
       
   288 	return ipUri;
       
   289 	}
       
   290 
       
   291 COmxILFileSourceProcessingFunction::CFileSourceAccess* COmxILFileSourceProcessingFunction::CFileSourceAccess::NewL(COmxILFileSourceProcessingFunction& aParent)
       
   292 	{
       
   293 	CFileSourceAccess* self = new (ELeave) CFileSourceAccess(aParent);
       
   294 	CleanupStack::PushL(self);
       
   295 	self->ConstructL();
       
   296 	CleanupStack::Pop(self);
       
   297 	return self;
       
   298 	}
       
   299 
       
   300 COmxILFileSourceProcessingFunction::CFileSourceAccess::CFileSourceAccess(COmxILFileSourceProcessingFunction& aParent)
       
   301 	: CActive(EPriorityStandard),
       
   302 	iParent(aParent),
       
   303 	iBufferOffset(0),
       
   304 	iReadBuffer(0,0),
       
   305 	iEOSFlag(EFalse)
       
   306 	{
       
   307 	CActiveScheduler::Add(this);
       
   308 	}
       
   309 
       
   310 void COmxILFileSourceProcessingFunction::CFileSourceAccess::ConstructL()
       
   311 	{
       
   312 	User::LeaveIfError(iFs.Connect());
       
   313 	}
       
   314 
       
   315 COmxILFileSourceProcessingFunction::CFileSourceAccess::~CFileSourceAccess()
       
   316 	{
       
   317 	Cancel();
       
   318 
       
   319 	iFileHandle.Close();
       
   320 	iFs.Close();
       
   321 	}
       
   322 
       
   323 void COmxILFileSourceProcessingFunction::CFileSourceAccess::RunL()
       
   324 	{
       
   325 	// The buffer is not on the list implies that they have already been flushed/spotted
       
   326 	// via BufferFlushingIndication/BufferRemovalIndication
       
   327 	TInt index = iParent.iBuffersToFill.Find(iCurrentBuffer);
       
   328 	if (KErrNotFound != index)
       
   329 		{
       
   330 		switch(iStatus.Int())
       
   331 			{
       
   332 			case KErrNone:
       
   333 				{
       
   334 				if (iReadBuffer.Length()==0) //the end of the file
       
   335 				    {
       
   336 				    iFileHandle.Close();
       
   337 				    iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_EOS;
       
   338 				    iParent.GetCallbacks().EventNotification(OMX_EventBufferFlag, iCurrentBuffer->nOutputPortIndex, OMX_BUFFERFLAG_EOS, NULL);
       
   339 				    iEOSFlag = ETrue;
       
   340 				    }
       
   341 				iCurrentBuffer->nFilledLen=iReadBuffer.Length();
       
   342 				iCurrentBuffer->nOffset = 0;
       
   343 				break;
       
   344 				}
       
   345 			default:
       
   346 				{
       
   347 				User::Leave(iStatus.Int());
       
   348 				}
       
   349 			};
       
   350 
       
   351 		iParent.GetCallbacks().BufferDoneNotification(iCurrentBuffer,iCurrentBuffer->nOutputPortIndex,OMX_DirOutput);
       
   352 		iParent.iBuffersToFill.Remove(index);
       
   353 		iCurrentBuffer = NULL;
       
   354 		}
       
   355 	
       
   356     if(iFileHandle.SubSessionHandle() != 0)
       
   357         {
       
   358         ProcessNextBuffer();
       
   359         }
       
   360 	}
       
   361 
       
   362 TInt COmxILFileSourceProcessingFunction::CFileSourceAccess::ProcessNextBuffer()
       
   363 	{
       
   364 	TInt err = KErrNone;
       
   365 	if ((iParent.iBuffersToFill.Count() > 0) && !IsActive() && iParent.iState == OMX_StateExecuting)
       
   366 		{
       
   367 		iCurrentBuffer = iParent.iBuffersToFill[0];
       
   368 		iReadBuffer.Set(iCurrentBuffer->pBuffer, iCurrentBuffer->nAllocLen, iCurrentBuffer->nAllocLen);
       
   369         if (iFileHandle.SubSessionHandle() == 0)
       
   370             {
       
   371             if(iEOSFlag == EFalse)
       
   372                 {
       
   373                 // This condition caters for when an IL client does not set the URI before trasitioning to 
       
   374                 // executing state (like the Khronos conformance suite). The proposed way to deal with this is to keep
       
   375                 // sending BufferDone notification with blank buffers with size >0 for KMaxBuffersWhenNoFileName number
       
   376                 // of times before OMX_BUFFERFLAG_EOS flag is sent to client. This simulates a normal communication.
       
   377                 if( iEOSBufferNotificationCount <= KMaxBuffersWhenNoFileName )
       
   378                     {
       
   379                     TUint nBufferSize = 0;
       
   380                     if (iEOSBufferNotificationCount < KMaxBuffersWhenNoFileName)
       
   381                         {
       
   382                         nBufferSize = KBufferSizeReturnedWhenNoFileName;
       
   383                         }
       
   384                     iReadBuffer.Set(iCurrentBuffer->pBuffer, nBufferSize, iCurrentBuffer->nAllocLen);                  
       
   385                     iEOSBufferNotificationCount++;              
       
   386                     SetActive();
       
   387                     TRequestStatus* status(&iStatus);
       
   388                     User::RequestComplete(status, KErrNone);
       
   389                     }
       
   390                 }
       
   391             else
       
   392                 {
       
   393                 iReadBuffer.Set(iCurrentBuffer->pBuffer, iCurrentBuffer->nAllocLen, iCurrentBuffer->nAllocLen);
       
   394                 // do nothing. this menas that all operations have completed succesfully.
       
   395                 }
       
   396             
       
   397             }
       
   398         else
       
   399             {
       
   400             iFileHandle.Read(iReadBuffer, iCurrentBuffer->nAllocLen, iStatus);
       
   401             SetActive();
       
   402             }
       
   403 		}
       
   404 	return err;
       
   405 	}
       
   406 
       
   407 void COmxILFileSourceProcessingFunction::CFileSourceAccess::DoCancel()
       
   408 	{
       
   409 	if (iFileHandle.SubSessionHandle() != 0)
       
   410 	    {
       
   411 	    iFileHandle.Close();
       
   412 	    }
       
   413 	iEOSFlag = EFalse;
       
   414 	iEOSBufferNotificationCount = 0;
       
   415 	
       
   416 	iCurrentBuffer = NULL;
       
   417 	}
       
   418 
       
   419 TInt COmxILFileSourceProcessingFunction::CFileSourceAccess::Execute()
       
   420 	{
       
   421 	iEOSFlag = EFalse;
       
   422 	iEOSBufferNotificationCount = 0;
       
   423 	iParent.iState = OMX_StateExecuting;
       
   424 	return ProcessNextBuffer();
       
   425 	}
       
   426 
       
   427 void COmxILFileSourceProcessingFunction::CFileSourceAccess::Pause()
       
   428 	{
       
   429 	iParent.iState = OMX_StatePause;
       
   430 	}
       
   431 
       
   432 void COmxILFileSourceProcessingFunction::CFileSourceAccess::Idle()
       
   433     {
       
   434     iParent.iState = OMX_StateIdle;
       
   435     iParent.iBuffersToFill.Reset();
       
   436     }
       
   437 
       
   438 void COmxILFileSourceProcessingFunction::CFileSourceAccess::CancelDataTransfer()
       
   439     {
       
   440     if(iFileHandle.SubSessionHandle() != 0)
       
   441         {
       
   442         iFileHandle.ReadCancel();
       
   443         }
       
   444     }
       
   445 
       
   446 void COmxILFileSourceProcessingFunction::CFileSourceAccess::Stop()
       
   447 	{
       
   448 	if(iParent.iState == OMX_StateExecuting || iParent.iState == OMX_StatePause)
       
   449 		{
       
   450 		Cancel();
       
   451 		iParent.iState = OMX_StateIdle;
       
   452 		}
       
   453 	}
       
   454 
       
   455 COmxILFileSourceProcessingFunction::CPFHelper* COmxILFileSourceProcessingFunction::CPFHelper::NewL(COmxILFileSourceProcessingFunction& aParent, CFileSourceAccess& aFileSourceAccess, CBufferArrivalHandler& aBufferArrivalHandler)
       
   456 	{
       
   457 	CPFHelper* self = new (ELeave) CPFHelper(aParent, aFileSourceAccess, aBufferArrivalHandler);
       
   458 	CleanupStack::PushL(self);
       
   459 	self->ConstructL();
       
   460 	CleanupStack::Pop(self);
       
   461 	return self;
       
   462 	}
       
   463 
       
   464 COmxILFileSourceProcessingFunction::CPFHelper::CPFHelper(COmxILFileSourceProcessingFunction& aParent, CFileSourceAccess& aFileSourceAccess, CBufferArrivalHandler& aBufferArrivalHandler)
       
   465 : CActive(CActive::EPriorityUserInput),
       
   466   iParent(aParent),
       
   467   iFileSourceAccess(aFileSourceAccess),
       
   468   iBufferArrivalHandler(aBufferArrivalHandler)
       
   469 	{
       
   470 	CActiveScheduler::Add(this);
       
   471     iRunLContext = RThread();
       
   472 	}
       
   473 
       
   474 void COmxILFileSourceProcessingFunction::CPFHelper::ConstructL()
       
   475 	{
       
   476     User::LeaveIfError(iWaitSemaphore.CreateLocal(0));
       
   477 	User::LeaveIfError(iMsgQueue.CreateLocal(KMaxMsgQueueEntries));
       
   478 	SetActive();
       
   479 	iMsgQueue.NotifyDataAvailable(iStatus);
       
   480 	}
       
   481 
       
   482 COmxILFileSourceProcessingFunction::CPFHelper::~CPFHelper()
       
   483 	{
       
   484 	Cancel();
       
   485 	iMsgQueue.Close();
       
   486     iRunLContext.Close();
       
   487     iWaitSemaphore.Close();
       
   488 	}
       
   489 
       
   490 void COmxILFileSourceProcessingFunction::CPFHelper::RunL()
       
   491 	{
       
   492 	TInt err = ProcessQueue();
       
   493 	if (err != KErrNone)
       
   494 		{
       
   495 		iParent.GetCallbacks().ErrorEventNotification( ConvertSymbianErrorType(err) );
       
   496 		}
       
   497 
       
   498 	// setup for next callbacks
       
   499 	SetActive();
       
   500 	iMsgQueue.NotifyDataAvailable(iStatus);
       
   501 	}
       
   502 
       
   503 void COmxILFileSourceProcessingFunction::CPFHelper::DoCancel()
       
   504 	{
       
   505 	if (iMsgQueue.Handle())
       
   506 		{
       
   507 		ProcessQueue();
       
   508 		iMsgQueue.CancelDataAvailable();
       
   509 		}
       
   510 	}
       
   511 
       
   512 TInt COmxILFileSourceProcessingFunction::CPFHelper::ProcessQueue()
       
   513 	{
       
   514 	TProcMessage msg;
       
   515 	TInt err = KErrNone;
       
   516 
       
   517 	while (iMsgQueue.Receive(msg) == KErrNone)
       
   518 		{
       
   519 		switch (msg.iType)
       
   520 			{
       
   521 			case EExecuteCommand:
       
   522 				{
       
   523                 const HBufC* fileName = iParent.FileName();
       
   524 	            if (fileName && iFileSourceAccess.iFileHandle.SubSessionHandle() == 0)
       
   525                     {
       
   526                     err = iFileSourceAccess.iFileHandle.Open(iFileSourceAccess.iFs, *fileName, EFileRead | EFileShareReadersOnly);
       
   527                     }
       
   528 	            // Transition to execute only when opening the file succeeds or there is no file name at all
       
   529                 if ( err == KErrNone)
       
   530                     {
       
   531                     err = iFileSourceAccess.Execute();
       
   532                     }
       
   533 				break;
       
   534 				}
       
   535 
       
   536 			case EStopCommand:
       
   537 				{
       
   538 				iFileSourceAccess.Stop();
       
   539 				break;
       
   540 				}
       
   541 
       
   542 			case EPauseCommand:
       
   543 				{
       
   544 				iFileSourceAccess.Pause();
       
   545 				break;
       
   546 				}
       
   547 
       
   548 			case EIdleCommand:
       
   549 			    {
       
   550 			    iFileSourceAccess.Idle();
       
   551 			    break;
       
   552 			    }
       
   553 			    
       
   554 			case EFlushCommand:
       
   555 			    {
       
   556 			    // Carry out the flush and wake up the non-Active Scheduler client.
       
   557 			    PerformFlush();
       
   558 			    iWaitSemaphore.Signal();
       
   559 			    break;
       
   560 			    }
       
   561 			    
       
   562 			case ERemoveBufferCommand:
       
   563 			    {
       
   564 			    // Carry out the buffer removal and wake up the non-Active Scheduler client.
       
   565 			    TBufferRemovalArgs* args = reinterpret_cast<TBufferRemovalArgs*>(msg.iPtr);
       
   566 			    *(args->iHdrRemoved) = PerformBufferRemoval(args->ipHeader);
       
   567 			    iWaitSemaphore.Signal();
       
   568 			    break;
       
   569 			    }
       
   570 			    
       
   571 			default:
       
   572 				{
       
   573 				break;
       
   574 				}
       
   575 			}
       
   576 
       
   577 		if (err)
       
   578 			{
       
   579 			break;
       
   580 			}
       
   581 		}
       
   582 	return err;
       
   583 	}
       
   584 
       
   585 TInt COmxILFileSourceProcessingFunction::CPFHelper::ExecuteAsync()
       
   586 	{
       
   587 	TProcMessage message;
       
   588 	message.iType = EExecuteCommand;
       
   589 	return iMsgQueue.Send(message);
       
   590 	}
       
   591 
       
   592 TInt COmxILFileSourceProcessingFunction::CPFHelper::StopAsync()
       
   593 	{
       
   594 	TProcMessage message;
       
   595 	message.iType = EStopCommand;
       
   596 	return iMsgQueue.Send(message);
       
   597 	}
       
   598 
       
   599 TInt COmxILFileSourceProcessingFunction::CPFHelper::PauseAsync()
       
   600     {
       
   601     TProcMessage message;
       
   602     message.iType = EPauseCommand;
       
   603     return iMsgQueue.Send(message);
       
   604     }
       
   605 
       
   606 void COmxILFileSourceProcessingFunction::CPFHelper::StopSync()
       
   607     {
       
   608     // Cancel to process the existing queue before handling this command
       
   609     Cancel();
       
   610     iFileSourceAccess.Stop();
       
   611 
       
   612     // setup for next callbacks
       
   613     SetActive();
       
   614     iMsgQueue.NotifyDataAvailable(iStatus);
       
   615     }
       
   616 
       
   617 TInt COmxILFileSourceProcessingFunction::CPFHelper::IdleAsync()
       
   618     {
       
   619     TProcMessage message;
       
   620     message.iType = EIdleCommand;
       
   621     return iMsgQueue.Send(message);
       
   622     }
       
   623 
       
   624 TInt COmxILFileSourceProcessingFunction::CPFHelper::FlushIndication()
       
   625     {
       
   626     TInt error = KErrNone;    
       
   627     RThread currentThread = RThread();
       
   628     if (currentThread.Id() == iRunLContext.Id())
       
   629         {
       
   630         // Running in the same context as CFileSourceAccess::RunL() so 
       
   631         // sure of no concurrency issues.
       
   632         PerformFlush();
       
   633         }
       
   634     else
       
   635         {
       
   636         // Running in a different thread, meaning the client does
       
   637         // not have an active scheduler.  To avoid concurrency problems 
       
   638         // during the flush, switch to the thread in which the active objects'
       
   639         // execution is handled.
       
   640         TProcMessage message;
       
   641         message.iType = EFlushCommand;
       
   642         error =  iMsgQueue.Send(message);
       
   643         if (error == KErrNone)
       
   644             {
       
   645             iWaitSemaphore.Wait();
       
   646             }
       
   647         }
       
   648     currentThread.Close();
       
   649     return error;
       
   650     }
       
   651 
       
   652 void COmxILFileSourceProcessingFunction::CPFHelper::PerformFlush()
       
   653     {
       
   654     // Running in the same context as CFileSourceAccess::RunL() so 
       
   655     // sure of no concurrency issues.
       
   656     
       
   657     // So that we don't continue to write to the buffer once it's returned.
       
   658     iFileSourceAccess.CancelDataTransfer();
       
   659     
       
   660     while (iParent.iBuffersToFill.Count() > 0)
       
   661         {
       
   662         OMX_BUFFERHEADERTYPE* pBufferHeader = iParent.iBuffersToFill[0];
       
   663         iParent.iBuffersToFill.Remove(0);
       
   664         iParent.iCallbacks.BufferDoneNotification(pBufferHeader,
       
   665                                                 pBufferHeader->nOutputPortIndex,
       
   666                                                 OMX_DirOutput);
       
   667         }
       
   668     
       
   669     iBufferArrivalHandler.FlushIndication();    
       
   670     }
       
   671 
       
   672 OMX_BOOL COmxILFileSourceProcessingFunction::CPFHelper::RemoveBufferIndication(OMX_BUFFERHEADERTYPE* apBufferHeader)
       
   673     {
       
   674     TInt error = KErrNone;    
       
   675     RThread currentThread = RThread();
       
   676     if (currentThread.Id() == iRunLContext.Id())
       
   677         {
       
   678         currentThread.Close();
       
   679         // Running in the same context as CFileSourceAccess::RunL() so 
       
   680         // sure of no concurrency issues.
       
   681         return PerformBufferRemoval(apBufferHeader);
       
   682         }
       
   683     else
       
   684         {
       
   685         currentThread.Close();
       
   686         // Running in a different thread, meaning the client does
       
   687         // not have an active scheduler.  To avoid concurrency problems 
       
   688         // during the flush, switch to the thread in which the active objects'
       
   689         // execution is handled.
       
   690         TProcMessage message;
       
   691         OMX_BOOL bufferFound;
       
   692         TBufferRemovalArgs messageArgs;
       
   693         messageArgs.ipHeader = apBufferHeader;
       
   694         messageArgs.iHdrRemoved = &bufferFound;
       
   695         message.iType = ERemoveBufferCommand;
       
   696         message.iPtr = &messageArgs;
       
   697         error =  iMsgQueue.Send(message);
       
   698         if (error == KErrNone)
       
   699             {
       
   700             iWaitSemaphore.Wait();
       
   701             return bufferFound;
       
   702             }
       
   703         iParent.GetCallbacks().ErrorEventNotification(OMX_ErrorInsufficientResources);
       
   704         return OMX_FALSE;
       
   705         }
       
   706     }
       
   707 
       
   708 OMX_BOOL COmxILFileSourceProcessingFunction::CPFHelper::PerformBufferRemoval(OMX_BUFFERHEADERTYPE* apBufferHeader)
       
   709     {
       
   710     if (iParent.iBuffersToFill.Count() < 1)
       
   711         {
       
   712         return OMX_FALSE;
       
   713         }
       
   714     
       
   715     if (iParent.iBuffersToFill[0] == apBufferHeader)
       
   716         {
       
   717         iFileSourceAccess.CancelDataTransfer();
       
   718         iParent.iBuffersToFill.Remove(0);
       
   719         return OMX_TRUE;
       
   720         }
       
   721     
       
   722     TInt count = iParent.iBuffersToFill.Count();
       
   723     for (TInt index = 1; index < count; ++index)
       
   724         {
       
   725         if (iParent.iBuffersToFill[index] == apBufferHeader)
       
   726             {
       
   727             iParent.iBuffersToFill.Remove(index);
       
   728             return OMX_TRUE;
       
   729             }
       
   730         }
       
   731     
       
   732     return iBufferArrivalHandler.RemoveBufferIndication(apBufferHeader);
       
   733     }
       
   734 
       
   735 /**
       
   736  Converts a Symbian error code to an OpenMAX error code.
       
   737  @param     aError The Symbian error code.
       
   738  @return    The OpenMAX error code.
       
   739  */
       
   740 OMX_ERRORTYPE COmxILFileSourceProcessingFunction::CPFHelper::ConvertSymbianErrorType(TInt aError)
       
   741     {
       
   742     // In the current implementation this function is only used for the return code in the
       
   743     // callback methods. Currently the only expected errors KErrNone and KErrOverflow.
       
   744 
       
   745     OMX_ERRORTYPE err = OMX_ErrorNone;
       
   746     switch (aError)
       
   747         {
       
   748     case KErrNone:
       
   749         err = OMX_ErrorNone;
       
   750         break;
       
   751     case KErrOverflow:
       
   752     case KErrNoMemory:
       
   753         err = OMX_ErrorInsufficientResources;
       
   754         break;
       
   755     case KErrNotSupported:
       
   756         err = OMX_ErrorNotImplemented;
       
   757         break;
       
   758     case KErrNotReady:
       
   759         err = OMX_ErrorNotReady;
       
   760         break;
       
   761     case KErrGeneral:
       
   762     default:
       
   763         err = OMX_ErrorUndefined;
       
   764         }
       
   765     return err;
       
   766     }
       
   767 
       
   768 COmxILFileSourceProcessingFunction::CBufferArrivalHandler* COmxILFileSourceProcessingFunction::CBufferArrivalHandler::NewL(COmxILFileSourceProcessingFunction& aParent, CFileSourceAccess& aFileSourceAccess)
       
   769     {
       
   770     CBufferArrivalHandler* self = new (ELeave) CBufferArrivalHandler(aParent, aFileSourceAccess);
       
   771     CleanupStack::PushL(self);
       
   772     self->ConstructL();
       
   773     CleanupStack::Pop(self);
       
   774     return self;
       
   775     }
       
   776 
       
   777 COmxILFileSourceProcessingFunction::CBufferArrivalHandler::CBufferArrivalHandler(COmxILFileSourceProcessingFunction& aParent, CFileSourceAccess& aFileSourceAccess)
       
   778 : CActive(CActive::EPriorityStandard),
       
   779   iParent(aParent),
       
   780   iFileSourceAccess(aFileSourceAccess)
       
   781     { 
       
   782     CActiveScheduler::Add(this);
       
   783     }
       
   784 
       
   785 void COmxILFileSourceProcessingFunction::CBufferArrivalHandler::ConstructL()
       
   786     {
       
   787     User::LeaveIfError(iMsgQueue.CreateLocal(KMaxMsgQueueEntries));
       
   788     SetActive();
       
   789     iMsgQueue.NotifyDataAvailable(iStatus);
       
   790     }
       
   791 
       
   792 COmxILFileSourceProcessingFunction::CBufferArrivalHandler::~CBufferArrivalHandler()
       
   793     {
       
   794     Cancel();
       
   795     iMsgQueue.Close();  // Queue should be emptied by now
       
   796     }
       
   797         
       
   798 TInt COmxILFileSourceProcessingFunction::CBufferArrivalHandler::BufferIndication(OMX_BUFFERHEADERTYPE* apBufferHeader)
       
   799     {
       
   800     TBufferIndicationMessage msg;
       
   801     msg.iBufferHdr = apBufferHeader;
       
   802     return iMsgQueue.Send(msg);    
       
   803     }
       
   804 
       
   805 /*
       
   806  * Bear in mind that this results in BufferDoneNotifications and so should be called at the end of of the 
       
   807  * flush sequence to ensure headers are completed in the order they were received.
       
   808  */
       
   809 void COmxILFileSourceProcessingFunction::CBufferArrivalHandler::FlushIndication()
       
   810     {
       
   811     TBufferIndicationMessage msg;
       
   812     
       
   813     while (iMsgQueue.Receive(msg) == KErrNone)
       
   814         {
       
   815         iParent.GetCallbacks().BufferDoneNotification(msg.iBufferHdr, msg.iBufferHdr->nOutputPortIndex,OMX_DirOutput);
       
   816         }
       
   817     }
       
   818 
       
   819 OMX_BOOL COmxILFileSourceProcessingFunction::CBufferArrivalHandler::RemoveBufferIndication(OMX_BUFFERHEADERTYPE* apBufferHeader)
       
   820     {
       
   821     RArray<TBufferIndicationMessage> bufferedMsgs;
       
   822     TBufferIndicationMessage msg;
       
   823     
       
   824     OMX_BOOL hdrFound = OMX_FALSE;
       
   825     while (iMsgQueue.Receive(msg) == KErrNone)
       
   826         {
       
   827         if (msg.iBufferHdr == apBufferHeader)
       
   828             {
       
   829             hdrFound = OMX_TRUE;
       
   830             }
       
   831         else
       
   832             {
       
   833             TInt error = bufferedMsgs.Append(msg);
       
   834             if (error != KErrNone)
       
   835                 {
       
   836                 // to prevent potential buffer leakage if the Append operation fails
       
   837                 iParent.GetCallbacks().BufferDoneNotification(msg.iBufferHdr, msg.iBufferHdr->nOutputPortIndex,OMX_DirOutput);
       
   838                 }
       
   839             }
       
   840         }
       
   841     
       
   842     TInt count = bufferedMsgs.Count();
       
   843     for (TInt index = 0; index < count; ++index)
       
   844         {
       
   845         // There's the potential here, in an environment when 3+ threads
       
   846         // (which is possible in the case of a non-AS client and a multi-threaded
       
   847         // tunneled component, e.g. Bellagio) are manipulatng the component, for
       
   848         // a buffer to be inserted out of order if a FillThisBuffer() command comes
       
   849         // in during the move to Idle and with particular thread scheduling 
       
   850         // sequences.  However as we only have one port and this command is called as
       
   851         // part of a move to Idle or port disablement then we should get a 
       
   852         // BufferRemovalNotification() for every buffer so in this instance it shouldn't
       
   853         // be a problem.
       
   854         iMsgQueue.Send(bufferedMsgs[index]);
       
   855         }
       
   856     return hdrFound;
       
   857     }
       
   858 
       
   859 void COmxILFileSourceProcessingFunction::CBufferArrivalHandler::RunL()
       
   860     {
       
   861     TBufferIndicationMessage msg;
       
   862     TInt err = iMsgQueue.Receive(msg);
       
   863     
       
   864     if ((err == KErrNone) && (iParent.iState == OMX_StateExecuting ||
       
   865                                 iParent.iState == OMX_StatePause || 
       
   866                                 iParent.iState == OMX_StateIdle))
       
   867         {
       
   868         err = iParent.iBuffersToFill.Append(msg.iBufferHdr);
       
   869         
       
   870         if(err == KErrNone)
       
   871             {
       
   872             if(iParent.iState != OMX_StateIdle)
       
   873                 {
       
   874                 err = iFileSourceAccess.ProcessNextBuffer();
       
   875                 }
       
   876             }
       
   877         else
       
   878             {
       
   879             iParent.GetCallbacks().ErrorEventNotification(OMX_ErrorInsufficientResources);
       
   880             // to prevent potential buffer leakage if the Append operation fails
       
   881             iParent.GetCallbacks().BufferDoneNotification(msg.iBufferHdr, msg.iBufferHdr->nOutputPortIndex,OMX_DirOutput);
       
   882             }        
       
   883         }
       
   884             
       
   885     SetActive();
       
   886     iMsgQueue.NotifyDataAvailable(iStatus);  
       
   887     }
       
   888 
       
   889 void COmxILFileSourceProcessingFunction::CBufferArrivalHandler::DoCancel()
       
   890     {
       
   891     iMsgQueue.CancelDataAvailable();
       
   892     }