omxilcomp/omxilaudioemulator/pcmrenderer/src/omxilpcmrendererprocessingfunction.cpp
changeset 0 58be5850fb6c
child 1 e0d606d6e3b1
equal deleted inserted replaced
-1:000000000000 0:58be5850fb6c
       
     1 /*
       
     2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 /**
       
    20  @file
       
    21  @internalComponent
       
    22 */
       
    23 
       
    24 #include <openmax/il/khronos/v1_x/OMX_Audio.h>
       
    25 
       
    26 #include <d32soundsc.h>
       
    27 
       
    28 #include "log.h"
       
    29 #include <openmax/il/common/omxilcallbacknotificationif.h>
       
    30 #include <openmax/il/common/omxilclockcomponentcmdsif.h>
       
    31 #include <openmax/il/extensions/omxilsymbianaudiopcmextensions.h>
       
    32 #include "omxilpcmrendererprocessingfunction.h"
       
    33 
       
    34 const TInt COmxILPcmRendererProcessingFunction::CPFHelper::KMaxMsgQueueEntries;
       
    35 
       
    36 COmxILPcmRendererProcessingFunction*
       
    37 COmxILPcmRendererProcessingFunction::NewL(MOmxILCallbackNotificationIf& aCallbacks, 
       
    38 										MOmxILClockComponentCmdsIf& aClientClockPort)
       
    39 	{
       
    40     DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::NewL"));
       
    41 
       
    42 	COmxILPcmRendererProcessingFunction* self =
       
    43 		new (ELeave)COmxILPcmRendererProcessingFunction(aCallbacks, aClientClockPort);
       
    44 	CleanupStack::PushL(self);
       
    45 	self->ConstructL();
       
    46 	CleanupStack::Pop(self);
       
    47 	return self;
       
    48 
       
    49 	}
       
    50 
       
    51 void
       
    52 COmxILPcmRendererProcessingFunction::ConstructL()
       
    53 	{
       
    54     DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::ConstructL"));
       
    55 
       
    56     iAudioDevice = CAudioDevice::NewL(*this);
       
    57     iPFHelper = CPFHelper::NewL(*iAudioDevice);
       
    58 	}
       
    59 
       
    60 COmxILPcmRendererProcessingFunction::COmxILPcmRendererProcessingFunction(
       
    61 	MOmxILCallbackNotificationIf& aCallbacks, 
       
    62 	MOmxILClockComponentCmdsIf& aClientClockPort)
       
    63 	:
       
    64 	COmxILProcessingFunction(aCallbacks),
       
    65 	iClientClockPortPtr(&aClientClockPort)
       
    66 	{
       
    67     DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::COmxILPcmRendererProcessingFunction"));
       
    68 
       
    69 	}
       
    70 
       
    71 COmxILPcmRendererProcessingFunction::~COmxILPcmRendererProcessingFunction()
       
    72 	{
       
    73     DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::~COmxILPcmRendererProcessingFunction"));
       
    74 
       
    75 	// Check in case the Sound Device has not been closed. That would happen in
       
    76 	// an scenario where the component is not being deleted in an orderer way.
       
    77 	if(iAudioDevice && iPFHelper &&
       
    78 	   (iState == OMX_StateInvalid   ||
       
    79 	    iState == OMX_StateExecuting ||
       
    80 	    iState == OMX_StatePause))
       
    81 		{
       
    82 		// Ignore error if the following call fails
       
    83 		iPFHelper->CloseDeviceOnError();
       
    84 		}
       
    85 
       
    86 	// Buffer headers are not owned by the processing function
       
    87     iBuffersToEmpty.Close();
       
    88     iBuffersEmptied.Close();
       
    89     delete iAudioDevice;
       
    90     delete iPFHelper;
       
    91 	}
       
    92 
       
    93 
       
    94 OMX_ERRORTYPE
       
    95 COmxILPcmRendererProcessingFunction::StateTransitionIndication(TStateIndex aNewState)
       
    96 	{
       
    97     DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::StateTransitionIndication"));
       
    98 
       
    99     OMX_ERRORTYPE err = OMX_ErrorNone;
       
   100 	switch(aNewState)
       
   101 		{
       
   102 	case EStateExecuting:
       
   103 		{
       
   104 		DEBUG_PRINTF(_L8("StateTransitionIndication : OMX_StateExecuting"));
       
   105 		if (iPFHelper->Execute() != KErrNone)
       
   106 			{
       
   107 			return OMX_ErrorInsufficientResources;
       
   108 			}
       
   109 		}
       
   110 		break;
       
   111 	case EStateInvalid:
       
   112 		{
       
   113 		DEBUG_PRINTF(_L8("StateTransitionIndication : OMX_StateInvalid"));
       
   114 		if (iPFHelper->Stop() != KErrNone)
       
   115 			{ // InsufficientResources to stop???
       
   116 			return OMX_ErrorInsufficientResources;
       
   117 			}
       
   118 		}
       
   119 		break;
       
   120 	case EStatePause:
       
   121 		{
       
   122 		DEBUG_PRINTF(_L8("StateTransitionIndication : OMX_StatePause"));
       
   123 		err = iAudioDevice->MoveToPausedState();
       
   124 		}
       
   125 		break;
       
   126 	case EStateIdle:
       
   127 		{
       
   128 		DEBUG_PRINTF(_L8("StateTransitionIndication : OMX_StateIdle"));
       
   129 		iBuffersToEmpty.Reset();
       
   130 		if (iPFHelper->Stop() != KErrNone)
       
   131 			{ // InsufficientResources to stop???
       
   132 			return OMX_ErrorInsufficientResources;
       
   133 			}
       
   134 		}
       
   135 		break;
       
   136 	case EStateLoaded:
       
   137 	case EStateWaitForResources:
       
   138 		{
       
   139 		DEBUG_PRINTF(_L8("StateTransitionIndication : OMX_StateLoaded, OMX_StateWaitForResources"));
       
   140 		if (iPFHelper->Stop() != KErrNone)
       
   141 			{ // InsufficientResources to stop???
       
   142 			return OMX_ErrorInsufficientResources;
       
   143 			}
       
   144 		}
       
   145 		break;
       
   146 	case ESubStateLoadedToIdle:
       
   147 		{
       
   148 		DEBUG_PRINTF(_L8("StateTransitionIndication : ESubStateLoadedToIdle"));
       
   149 		if (iPFHelper->OpenDevice() != KErrNone)
       
   150 			{
       
   151 			return OMX_ErrorInsufficientResources;
       
   152 			}
       
   153 		}
       
   154 		break;
       
   155 	case ESubStateIdleToLoaded:
       
   156 		{
       
   157 		DEBUG_PRINTF(_L8("StateTransitionIndication : ESubStateIdleToLoaded"));
       
   158 		if (iPFHelper->CloseDevice() != KErrNone)
       
   159 			{ // InsufficientResources to close???
       
   160 			return OMX_ErrorInsufficientResources;
       
   161 			}
       
   162 		}
       
   163 		break;
       
   164 	case ESubStateExecutingToIdle:
       
   165 	case ESubStatePauseToIdle:
       
   166 		{
       
   167 		// Ignore these transitions...
       
   168 		return OMX_ErrorNone;
       
   169 		}
       
   170 	default:
       
   171 		{
       
   172 		// Always ASSERT; This would be a problem in the framework.
       
   173 		ASSERT(0);
       
   174 		return OMX_ErrorIncorrectStateTransition;
       
   175 		}
       
   176 		};
       
   177 
       
   178 	return err;
       
   179 
       
   180 	}
       
   181 
       
   182 
       
   183 OMX_ERRORTYPE
       
   184 COmxILPcmRendererProcessingFunction::BufferFlushingIndication(
       
   185 	TUint32 aPortIndex,
       
   186 	OMX_DIRTYPE aDirection)
       
   187 	{
       
   188     DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::BufferFlushingIndication : aPortIndex[%d]"), aPortIndex);
       
   189 
       
   190     if ((aPortIndex == OMX_ALL && aDirection == OMX_DirMax) ||
       
   191 		(aPortIndex == KPCMRENDERER_APB0PORT_INDEX && aDirection == OMX_DirInput))
       
   192 		{
       
   193 		// If we are currently processing a buffer then cancel
       
   194 		if (iPFHelper->CancelDevice() != KErrNone)
       
   195 			{
       
   196 			return OMX_ErrorInsufficientResources;
       
   197 			}
       
   198 
       
   199 		// Send BufferDone notifications for each emptied buffer...
       
   200 		FlushBufferList(iBuffersEmptied);
       
   201 
       
   202 	    // Send BufferDone notifications for each pending buffer...
       
   203 		FlushBufferList(iBuffersToEmpty);
       
   204 		
       
   205 		return OMX_ErrorNone;
       
   206 		}
       
   207 	else if (aPortIndex == KPCMRENDERER_OPB0PORT_INDEX && aDirection == OMX_DirInput)
       
   208 		{
       
   209 		// Since the clock port buffers are returned immediately, 
       
   210 		// there's nothing to flush for the port
       
   211 		return OMX_ErrorNone;
       
   212 		}
       
   213 	else
       
   214 		{
       
   215 		// Always ASSERT; This would be a problem in the framework.
       
   216 		ASSERT(0);
       
   217 		return OMX_ErrorBadParameter;
       
   218 		}
       
   219 	}
       
   220 
       
   221 void
       
   222 COmxILPcmRendererProcessingFunction::FlushBufferList(
       
   223 	RPointerArray<OMX_BUFFERHEADERTYPE>& aBufferList)
       
   224 	{
       
   225     DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::FlushBufferList : [%s]"),
       
   226 				  &aBufferList == &iBuffersToEmpty ? "iBuffersToEmpty" : "iBuffersEmptied");
       
   227 
       
   228 	const TUint bufferCount = aBufferList.Count();
       
   229 	OMX_BUFFERHEADERTYPE* pBufferHeader = 0;
       
   230 	// We know there is only one input port...
       
   231 	OMX_DIRTYPE portDirection = OMX_DirInput;
       
   232 
       
   233 	for (TUint i=0; i<bufferCount; ++i)
       
   234 		{
       
   235 		pBufferHeader = aBufferList[i];
       
   236 		pBufferHeader->nFilledLen = 0;
       
   237 		iCallbacks.
       
   238 			BufferDoneNotification(
       
   239 				pBufferHeader,
       
   240 				pBufferHeader->nInputPortIndex,
       
   241 				portDirection
       
   242 				);
       
   243 		}
       
   244 
       
   245 	// Empty buffer list...
       
   246 	aBufferList.Reset();
       
   247 
       
   248 	}
       
   249 
       
   250 
       
   251 OMX_ERRORTYPE
       
   252 COmxILPcmRendererProcessingFunction::ParamIndication(
       
   253 	OMX_INDEXTYPE aParamIndex,
       
   254 	const TAny* apComponentParameterStructure)
       
   255 	{
       
   256     DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::ParamIndication"));
       
   257 
       
   258     OMX_ERRORTYPE err = OMX_ErrorNone;
       
   259     switch(aParamIndex)
       
   260 	{
       
   261 	case OMX_IndexParamAudioPcm:
       
   262 		{
       
   263 		const OMX_AUDIO_PARAM_PCMMODETYPE* pPcmProfile
       
   264 			= static_cast<const OMX_AUDIO_PARAM_PCMMODETYPE*>(
       
   265 				apComponentParameterStructure);
       
   266 
       
   267 		if((pPcmProfile->nChannels == 1 || pPcmProfile->nChannels == 2) &&
       
   268 		  (pPcmProfile->eNumData == OMX_NumericalDataSigned) &&
       
   269 		  (pPcmProfile->eEndian == OMX_EndianBig) &&
       
   270 		  (pPcmProfile->bInterleaved == OMX_TRUE) &&
       
   271 		  (pPcmProfile->nBitPerSample == 16) &&
       
   272 		  ((pPcmProfile->nSamplingRate == 8000)  ||
       
   273 		   (pPcmProfile->nSamplingRate == 11025) ||
       
   274 		   (pPcmProfile->nSamplingRate == 12000) ||
       
   275 		   (pPcmProfile->nSamplingRate == 16000) ||
       
   276 		   (pPcmProfile->nSamplingRate == 22050) ||
       
   277 		   (pPcmProfile->nSamplingRate == 24000) ||
       
   278 		   (pPcmProfile->nSamplingRate == 32000) ||
       
   279 		   (pPcmProfile->nSamplingRate == 44100) ||
       
   280 		   (pPcmProfile->nSamplingRate == 48000)) &&
       
   281 		  (pPcmProfile->ePCMMode == OMX_AUDIO_PCMModeLinear) &&
       
   282 		  (pPcmProfile->eChannelMapping[0] == OMX_AUDIO_ChannelLF) &&
       
   283 		  (pPcmProfile->eChannelMapping[1] == OMX_AUDIO_ChannelRF))
       
   284 			{
       
   285 			if (iPFHelper->ParamIndication(pPcmProfile) != KErrNone)
       
   286 				{
       
   287 				err = OMX_ErrorInsufficientResources;
       
   288 				}
       
   289 			}
       
   290 		else
       
   291 			{
       
   292 			err = OMX_ErrorBadParameter;
       
   293 			}
       
   294 		}
       
   295 		break;
       
   296 	default:
       
   297 		{
       
   298 		// Ignore other port param changes...
       
   299 		}
       
   300 	};
       
   301 
       
   302 	return err;
       
   303 
       
   304 	}
       
   305 
       
   306 OMX_ERRORTYPE
       
   307 COmxILPcmRendererProcessingFunction::ConfigIndication(OMX_INDEXTYPE aConfigIndex,
       
   308 													  const TAny* apComponentConfigStructure)
       
   309 	{
       
   310     DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::ConfigIndication %X"), aConfigIndex);
       
   311 
       
   312     OMX_ERRORTYPE err = OMX_ErrorNone;
       
   313     switch(aConfigIndex)
       
   314 	{
       
   315 	case OMX_SymbianIndexConfigAudioPcmVolumeRamp:
       
   316 		{
       
   317 		const OMX_SYMBIAN_AUDIO_CONFIG_PCM_VOLUMERAMP*
       
   318 			pPcmVolumeRamp
       
   319 			= static_cast<
       
   320 			const OMX_SYMBIAN_AUDIO_CONFIG_PCM_VOLUMERAMP*>(
       
   321 					apComponentConfigStructure);
       
   322 
       
   323 		if (iPFHelper->SetVolumeRamp(pPcmVolumeRamp->nRampDuration) != KErrNone)
       
   324 			{
       
   325 			err = OMX_ErrorInsufficientResources;
       
   326 			}
       
   327 		}
       
   328 		break;
       
   329 
       
   330 	case OMX_IndexConfigAudioVolume:
       
   331 		{
       
   332 		const OMX_AUDIO_CONFIG_VOLUMETYPE* pVolumeType
       
   333 			= static_cast<const OMX_AUDIO_CONFIG_VOLUMETYPE*>(
       
   334 					apComponentConfigStructure);
       
   335 
       
   336         if (pVolumeType->bLinear == OMX_TRUE)
       
   337             {
       
   338             // Some configuration structures contain read-only fields. The 
       
   339             // OMX_SetConfig method will preserve read-only fields in configuration
       
   340             // structures that contain them, and shall not generate an error when 
       
   341             // the caller attempts to change the value of a read-only field.
       
   342             err = OMX_ErrorNone;
       
   343             break;
       
   344             }
       
   345 			
       
   346 		if ((pVolumeType->sVolume.nValue <= pVolumeType->sVolume.nMax) &&
       
   347 		   (pVolumeType->sVolume.nValue >= pVolumeType->sVolume.nMin))
       
   348 			{
       
   349 			if (iPFHelper->SetVolume(pVolumeType->sVolume.nValue) != KErrNone)
       
   350 				{
       
   351 				err = OMX_ErrorInsufficientResources;
       
   352 				}
       
   353 			}
       
   354 		else
       
   355 			{
       
   356 			err = OMX_ErrorBadParameter;
       
   357 			}
       
   358 		}
       
   359 		break;
       
   360 
       
   361 	case OMX_IndexConfigAudioMute:
       
   362 		{
       
   363 		const OMX_AUDIO_CONFIG_MUTETYPE* pVolumeType
       
   364 		= static_cast<const OMX_AUDIO_CONFIG_MUTETYPE*>(
       
   365 				apComponentConfigStructure);
       
   366 
       
   367 		if (iPFHelper->SetMuted(pVolumeType->bMute) != KErrNone)
       
   368 			{
       
   369 			err = OMX_ErrorInsufficientResources;
       
   370 			}
       
   371 		}
       
   372 		break;
       
   373 
       
   374 	default:
       
   375 		{
       
   376 		// Ignore other port config changes...
       
   377 		}
       
   378 	};
       
   379 
       
   380 	return err;
       
   381 
       
   382 	}
       
   383 
       
   384 OMX_ERRORTYPE
       
   385 COmxILPcmRendererProcessingFunction::BufferIndication(
       
   386 	OMX_BUFFERHEADERTYPE* apBufferHeader,
       
   387 	OMX_DIRTYPE aDirection)
       
   388 	{
       
   389     DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::BufferIndication : [%X]"), apBufferHeader);
       
   390 
       
   391 	if (aDirection != OMX_DirInput)
       
   392 		{
       
   393 		return OMX_ErrorBadParameter;
       
   394 		}
       
   395     
       
   396 	if (iBuffersToEmpty.Append(apBufferHeader) != KErrNone)
       
   397 		{
       
   398 		return OMX_ErrorInsufficientResources;
       
   399 		}
       
   400 
       
   401 	// If we are not in an executing state or if the audio device is busy, delay playing back the buffer
       
   402 	if (iState != OMX_StateExecuting || iAudioDevice->IsActive())
       
   403 		{
       
   404 		return OMX_ErrorNone;
       
   405 		}
       
   406 				
       
   407 	if (iPFHelper->BufferIndication() != KErrNone)
       
   408 		{
       
   409 		return OMX_ErrorInsufficientResources;
       
   410 		}
       
   411 
       
   412 	return OMX_ErrorNone;
       
   413 	}
       
   414 
       
   415 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::MediaTimeIndication(const OMX_TIME_MEDIATIMETYPE& aMediaTimeType)
       
   416 	{
       
   417 	// Received a requested media time notification.
       
   418 	DEBUG_PRINTF5(_L8("MediaTimeIndication : eUpdateType = %d eState = %d xScale = %d nMediaTimestamp = %d "), 
       
   419 						aMediaTimeType.eUpdateType, aMediaTimeType.eState, aMediaTimeType.xScale, aMediaTimeType.nMediaTimestamp);
       
   420 	
       
   421 	iPFHelper->MediaTimeIndication(aMediaTimeType);
       
   422 	return OMX_ErrorNone;
       
   423 	}
       
   424 
       
   425 OMX_BOOL
       
   426 COmxILPcmRendererProcessingFunction::BufferRemovalIndication(
       
   427 	OMX_BUFFERHEADERTYPE* apBufferHeader,
       
   428 	OMX_DIRTYPE /* aDirection */)
       
   429 	{
       
   430     DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::BufferRemovalIndication : BUFFER [%X]"), apBufferHeader);
       
   431 
       
   432     TBool headerDeletionResult = ETrue;
       
   433     // Check if the buffer we want to remove is the one is being currently processed
       
   434     if (iAudioDevice->IsActive() && iAudioDevice->GetCurrentBuffer() == apBufferHeader)
       
   435 		{
       
   436 		if (iPFHelper->CancelDevice() != KErrNone)
       
   437 			{
       
   438 			return OMX_FALSE;
       
   439 			}
       
   440 
       
   441 		// if you cancel the audio device then you send the buffer to the other end of the tunnel
       
   442 		// so you shouldn't say that you had the buffer in the processing function in this situation.
       
   443 		headerDeletionResult = EFalse;
       
   444 		}
       
   445     else
       
   446 		{
       
   447 		TInt headerIndexInArray = KErrNotFound;
       
   448 		if (KErrNotFound !=
       
   449 			(headerIndexInArray =
       
   450 			 iBuffersToEmpty.Find(apBufferHeader)))
       
   451 			{
       
   452 			iBuffersToEmpty.Remove(headerIndexInArray);
       
   453 			}
       
   454 		else if(KErrNotFound !=
       
   455 				(headerIndexInArray =
       
   456 				 iBuffersEmptied.Find(apBufferHeader)))
       
   457 			{
       
   458 			iBuffersEmptied.Remove(headerIndexInArray);
       
   459 			}
       
   460 		else
       
   461 			{
       
   462 			headerDeletionResult = EFalse;
       
   463 			}
       
   464 		}
       
   465 
       
   466     DEBUG_PRINTF2(_L8("BufferRemovalIndication : Removal result [%s]"), (headerDeletionResult ? "YES" : "NO"));
       
   467     return (headerDeletionResult ? OMX_TRUE : OMX_FALSE);
       
   468 	}
       
   469 
       
   470 TInt
       
   471 COmxILPcmRendererProcessingFunction::GetBytesPlayed() const
       
   472 	{
       
   473 	return iAudioDevice->GetBytesPlayed();
       
   474 	}
       
   475 
       
   476 
       
   477 COmxILPcmRendererProcessingFunction::CAudioDevice* COmxILPcmRendererProcessingFunction::CAudioDevice::NewL(COmxILPcmRendererProcessingFunction& aParent)
       
   478 	{
       
   479 	CAudioDevice* self = new (ELeave) CAudioDevice(aParent);
       
   480 	CleanupStack::PushL(self);
       
   481 	self->ConstructL();
       
   482 	CleanupStack::Pop(self);
       
   483 	return self;
       
   484 	}
       
   485 
       
   486 COmxILPcmRendererProcessingFunction::CAudioDevice::CAudioDevice(COmxILPcmRendererProcessingFunction& aParent)
       
   487 : CActive(EPriorityUserInput),
       
   488   iParent(aParent),
       
   489   iSampleRate(KDefaultSampleRate),
       
   490   iChannels(KDefaultNumberChannels),
       
   491   iEncoding(KDefaultEncoding),
       
   492   iVolume(KDefaultVolume),
       
   493   iMuted(KDefaultMuted),
       
   494   iBufferSize(KBufferSize),
       
   495   iClockStateRunning(EFalse),
       
   496   iPausedClockViaScale(EFalse),
       
   497   iIsStartTimeFlagSet(EFalse)
       
   498 	{
       
   499 	CActiveScheduler::Add(this);
       
   500 	}
       
   501 
       
   502 
       
   503 void COmxILPcmRendererProcessingFunction::CAudioDevice::ConstructL()
       
   504     {
       
   505 	iCachedPlayBuffer.CreateL(0);
       
   506 	}
       
   507 
       
   508 COmxILPcmRendererProcessingFunction::CAudioDevice::~CAudioDevice()
       
   509 	{
       
   510 	delete iPeriodic;
       
   511 	Cancel();
       
   512 	iCachedPlayBuffer.Close();
       
   513 	}
       
   514 
       
   515 void COmxILPcmRendererProcessingFunction::CAudioDevice::RunL()
       
   516 	{
       
   517 	DEBUG_PRINTF(_L8("CAudioDevice::RunL : "));
       
   518 	if (iStatus != KErrNone)
       
   519 		{
       
   520 		switch(iStatus.Int())
       
   521 			{
       
   522 		case KErrUnderflow:
       
   523 			DEBUG_PRINTF(_L8("CAudioDevice::RunL : KErrUnderflow"));
       
   524 			iParent.iCallbacks.ErrorEventNotification(OMX_ErrorUnderflow);
       
   525 			break;
       
   526 
       
   527 		case KErrOverflow:
       
   528 			DEBUG_PRINTF(_L8("CAudioDevice::RunL : KErrOverflow"));
       
   529 			iParent.iCallbacks.ErrorEventNotification(OMX_ErrorOverflow);
       
   530 			break;
       
   531 
       
   532 		default:
       
   533 			DEBUG_PRINTF2(_L8("CAudioDevice::RunL : [%d] -> OMX_ErrorHardware"), iStatus.Int());
       
   534 			iParent.iCallbacks.ErrorEventNotification(OMX_ErrorHardware);
       
   535 			};
       
   536 		}
       
   537 
       
   538 	ASSERT(iCurrentBuffer);
       
   539 	// Update the last value of bytes played...
       
   540 	iLastBytesPlayedValue = iSoundDevice.BytesPlayed();
       
   541 
       
   542 	// Return the emptied buffer to the IL Client or the tunnelled
       
   543 	// component..
       
   544 	SignalBufferCompletion(iCurrentBuffer);
       
   545 	iCurrentBuffer = 0;
       
   546 		
       
   547 	// Make sure to clear the aggregated cache buffer, if it was used
       
   548 	iCachedPlayBuffer.Zero();
       
   549 	}
       
   550 
       
   551 void COmxILPcmRendererProcessingFunction::CAudioDevice::SignalBufferCompletion(
       
   552 	OMX_BUFFERHEADERTYPE* apCurrentBuffer)
       
   553 	{
       
   554 	DEBUG_PRINTF2(_L8("CAudioDevice::SignalBufferCompletion : BUFFER = [%X]"), apCurrentBuffer);
       
   555 
       
   556 	iParent.iBuffersEmptied.Append(apCurrentBuffer);
       
   557 
       
   558 	// Process the queue only if in executing state...
       
   559 	if (iParent.iState == OMX_StateExecuting)
       
   560 		{
       
   561 		const TUint bufferCount = iParent.iBuffersEmptied.Count();
       
   562 		OMX_BUFFERHEADERTYPE* pBufferHeader = 0;
       
   563 		for (TUint i=0; i<bufferCount; ++i)
       
   564 			{
       
   565 			pBufferHeader = iParent.iBuffersEmptied[i];
       
   566 			TBool lastBuffer = EFalse;
       
   567 			if (pBufferHeader->nFlags & OMX_BUFFERFLAG_EOS)
       
   568 				{
       
   569 				lastBuffer = ETrue;
       
   570 				}
       
   571 
       
   572 			pBufferHeader->nFilledLen = 0;
       
   573 			iParent.iCallbacks.BufferDoneNotification(pBufferHeader,
       
   574 													  pBufferHeader->nInputPortIndex,
       
   575 													  OMX_DirInput);
       
   576 			if (lastBuffer)
       
   577 				{
       
   578 				pBufferHeader->nFlags |= OMX_BUFFERFLAG_EOS;
       
   579 				// propagate the EOS flag
       
   580 				iParent.iCallbacks.EventNotification(
       
   581 					OMX_EventBufferFlag,
       
   582 					KPCMRENDERER_APB0PORT_INDEX,
       
   583 					pBufferHeader->nFlags,
       
   584 					NULL);
       
   585 				}
       
   586 			}
       
   587 
       
   588 		// Empty list...
       
   589 		iParent.iBuffersEmptied.Reset();
       
   590 		}
       
   591 
       
   592 	if (iParent.iBuffersToEmpty.Count() > 0)
       
   593 		{
       
   594 		DEBUG_PRINTF2(_L8("CAudioDevice::RunL : iBuffersToEmpty.Count = [%d]"),
       
   595 					  iParent.iBuffersToEmpty.Count());
       
   596 		iParent.iPFHelper->BufferIndication();
       
   597 		}		
       
   598 		
       
   599 	}
       
   600 
       
   601 
       
   602 TBool COmxILPcmRendererProcessingFunction::CAudioDevice::ConstructAndStartUpdateTimer()
       
   603     {
       
   604     // Need this check if:
       
   605     // - The component state transitions from Execution-Idle-Execution
       
   606     // - The Clock's state transitions from Running-Stop-Running
       
   607     if (iPeriodic == NULL)
       
   608         {
       
   609         iPeriodic = CPeriodic::New(EPriorityStandard);
       
   610         
       
   611         if (iPeriodic == NULL)
       
   612             {
       
   613             iParent.iCallbacks.ErrorEventNotification(OMX_ErrorInsufficientResources);
       
   614             return EFalse;
       
   615             }
       
   616         }
       
   617     
       
   618     StartUpdateTimer();
       
   619     
       
   620     return ETrue;
       
   621     }
       
   622 
       
   623 
       
   624 void COmxILPcmRendererProcessingFunction::CAudioDevice::ProcessNextBuffer()
       
   625 	{
       
   626 	if (iParent.iBuffersToEmpty.Count() == 0)
       
   627 		return;
       
   628 
       
   629 	// To implement A/V Sync, we should start playing only once the clock component gives the appopriate command
       
   630 	// If the clock component is not available, we start playing immediately
       
   631 	// Since the PCM Renderer supplies the reference clock, we make sure to initialise the clock component with
       
   632 	// the reference when we receive the first buffer
       
   633 	
       
   634 	if (!iParent.iClientClockPortPtr->IsClockComponentAvailable())
       
   635 		{
       
   636 		PlayData();
       
   637 		return;
       
   638 		}
       
   639 
       
   640 	OMX_BUFFERHEADERTYPE* bufferPtr = iParent.iBuffersToEmpty[0];
       
   641 	
       
   642 	TBool bufferHasStartTime = bufferPtr->nFlags & OMX_BUFFERFLAG_STARTTIME;
       
   643 	
       
   644     if (!iClockStateRunning)
       
   645         {
       
   646         if (!bufferHasStartTime)
       
   647             {
       
   648             // Connected with the Clock but OMX_BUFFERFLAG_STARTTIME isn't set; simply queue the buffer
       
   649             return;
       
   650             }
       
   651         else
       
   652             {
       
   653             OMX_ERRORTYPE err = iParent.iClientClockPortPtr->SetStartTime(static_cast<OMX_TICKS>(bufferPtr->nTimeStamp));
       
   654             
       
   655             if (err == OMX_ErrorNone)
       
   656                 {
       
   657                 // Clear the returning buffer's flag
       
   658                 bufferPtr->nFlags &= ~OMX_BUFFERFLAG_STARTTIME;
       
   659                 }
       
   660             else
       
   661                 {
       
   662                 // NOTE: If the Clock is not in OMX_TIME_ClockStateWaitingForStartTime,
       
   663                 //       currently SetStartTime will return OMX_ErrorIncorrectStateOperation
       
   664                 
       
   665                 // It is not the PCM renderer to flag a Clock component error;
       
   666                 // therefore, ignore the error.
       
   667                 // 
       
   668                 // As the Clock is not in OMX_TIME_ClockStateRunning state, the Renderer needs  
       
   669                 // to keep the OMX_BUFFERFLAG_STARTTIME in the first buffer until the Clock 
       
   670                 // moves into OMX_TIME_ClockStateWaitingForStartTime or OMX_TIME_ClockStateRunning
       
   671                 // state
       
   672                 DEBUG_PRINTF2(_L8("CAudioDevice::ProcessNextBuffer SetStartTime() return %d"), err);
       
   673                 }
       
   674             
       
   675             // Update the iStartMediaTime
       
   676             iParent.iStartMediaTime = static_cast<OMX_TICKS>(bufferPtr->nTimeStamp);
       
   677             iIsStartTimeFlagSet = ETrue;
       
   678             }
       
   679         } // (!iClockStateRunning)
       
   680     else
       
   681 		{
       
   682         if (bufferHasStartTime)
       
   683             {
       
   684             // The Clock moves straight into OMX_TIME_ClockStateRunning state,
       
   685             // clear the returning buffer's flag.
       
   686             bufferPtr->nFlags &= ~OMX_BUFFERFLAG_STARTTIME;
       
   687             }
       
   688         
       
   689         if (!iPlayData)
       
   690             {
       
   691             // Not allowed to render audio. This could be due to:
       
   692             //  - The renderer is waiting for a time completion notification from the Clock;
       
   693             return;
       
   694             }
       
   695 		
       
   696 		if (!iIsStartTimeFlagSet)
       
   697 		    {
       
   698 		    // As the StartTimeFlag is not mandatory; therefore it might be missing from the first audio buffer
       
   699 		    // In such a case, we use the first buffer's timestamp as the StartMediaTime.
       
   700 		    //
       
   701 		    // NOTE: Since the Clock is running, calling SetStartTime() to the Clock is meaningless
       
   702 		    
       
   703 		    // Update the iStartMediaTime
       
   704 		    iParent.iStartMediaTime = static_cast<OMX_TICKS>(bufferPtr->nTimeStamp);
       
   705 		    iIsStartTimeFlagSet = ETrue;
       
   706 		    
       
   707             // Cross checking the Clock's media timestamp with iStartMediaTime to see 
       
   708             // data can be rendered straight away 
       
   709             if (!CanPlayNow())
       
   710                 {
       
   711                 return;
       
   712                 }
       
   713             
       
   714             if (!ConstructAndStartUpdateTimer())
       
   715                 {
       
   716                 return;
       
   717                 }
       
   718 		    }
       
   719 		
       
   720 		DEBUG_PRINTF3(_L8("ProcessNextBuffer : iStartMediaTime = %d nTimeStamp = %d"), 
       
   721 	            I64LOW(iParent.iStartMediaTime), I64LOW(bufferPtr->nTimeStamp));
       
   722 		
       
   723 		if (!iPausedClockViaScale)	//if clock scale is zero then we are effectively paused
       
   724 			{
       
   725 			PlayData();
       
   726 			}
       
   727 		} // else
       
   728 	}
       
   729 
       
   730 
       
   731 void COmxILPcmRendererProcessingFunction::CAudioDevice::PlayData()
       
   732 	{
       
   733 	DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::CAudioDevice::PlayData()++"));
       
   734 	if (iParent.iBuffersToEmpty.Count() == 0 || iSoundDevice.Handle() == 0 || IsActive())
       
   735 		{
       
   736 		DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::CAudioDevice::PlayData() nothing to play, or there is an outstanding request"));
       
   737 		return;
       
   738 		}
       
   739 
       
   740 	iCurrentBuffer = iParent.iBuffersToEmpty[0];
       
   741 
       
   742 	iParent.iBuffersToEmpty.Remove(0);
       
   743 
       
   744 	CMMFDataBuffer* mmfSrcBuffer = static_cast<CMMFDataBuffer*>(iCurrentBuffer->pInputPortPrivate);
       
   745 	mmfSrcBuffer->Data().SetLength(iCurrentBuffer->nFilledLen);
       
   746 
       
   747 	// Attenuate the amplitude of the samples if volume ramping has been changed
       
   748 	if (iRampAudioSample)
       
   749 		{
       
   750 		iRampAudioSample = RampAudio(mmfSrcBuffer);
       
   751 		}
       
   752 
       
   753 	// First, check whether the buffer length is sufficient not to cause underflows in the device driver
       
   754 	TBool isFilledLengthSufficient = IsBufferLengthSufficient(iCurrentBuffer->nFilledLen);
       
   755 	// This variable defines whether we should send the data to the driver directly, or append it to an aggregated buffer
       
   756 	// We append the buffer instead of sending it directly, if (i) the buffer is too small, or (ii)  we have already aggregated something.
       
   757 	TBool appendBuffer = (!isFilledLengthSufficient || iCachedPlayBuffer.Length() > 0) ? ETrue : EFalse;
       
   758 	if (!appendBuffer)
       
   759 		{
       
   760 		SendBufferToSoundDevice(mmfSrcBuffer->Data());
       
   761 		}
       
   762 	else
       
   763 		{
       
   764 		// Check if we need to allocate the cached buffer
       
   765 		if (iCachedPlayBuffer.MaxLength() == 0)
       
   766 			{
       
   767 			// The RMdaDevSound shim allocates the shared chunk according to the maxLength of the descriptor it receives
       
   768 			// For this reason, we must allocate our buffer conservatively, otherwise the chunk may be insufficient and the RMdaDevSound shim will panic			
       
   769 			TInt err = iCachedPlayBuffer.ReAlloc(GetMinBufferLength() + iCurrentBuffer->nAllocLen);
       
   770 			if  (err != KErrNone)
       
   771 				{
       
   772 				iParent.iCallbacks.ErrorEventNotification(OMX_ErrorInsufficientResources);
       
   773 				return;
       
   774 				}
       
   775 			}
       
   776 		
       
   777 		iCachedPlayBuffer.Append(mmfSrcBuffer->Data());
       
   778 				
       
   779 		// If we have sufficient length aggregated, play the cached buffer
       
   780 		// Also if this is the last buffer, we have to play it now, there's nothing left to cache
       
   781 		if (IsBufferLengthSufficient(iCachedPlayBuffer.Length()) || iCurrentBuffer->nFlags & OMX_BUFFERFLAG_EOS)
       
   782 			{
       
   783 			SendBufferToSoundDevice(iCachedPlayBuffer);
       
   784 			}
       
   785 		// If not, make sure to notify that we notify that the buffer is done for the OMX tunnnel, so that the port will be able to reuse it
       
   786 		else
       
   787 			{
       
   788 			SignalBufferCompletion(iCurrentBuffer);
       
   789 			iCurrentBuffer = NULL;
       
   790 			}
       
   791 		}
       
   792 	}
       
   793 
       
   794 void COmxILPcmRendererProcessingFunction::CAudioDevice::SendBufferToSoundDevice(TDes8& aBuffer) 
       
   795 	{
       
   796 	ASSERT(!IsActive());
       
   797 	iStatus = KRequestPending;
       
   798 	DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::CAudioDevice::SendBufferToSoundDevice() PlayData [%d]"), aBuffer.Length());
       
   799 	iSoundDevice.PlayData(iStatus, aBuffer);
       
   800 	if (iResumeAfterNextPlay)
       
   801 		{
       
   802 		iResumeAfterNextPlay = EFalse;
       
   803 		iSoundDevice.ResumePlaying();
       
   804 		}
       
   805 	SetActive();				
       
   806 	}
       
   807 	
       
   808 TInt COmxILPcmRendererProcessingFunction::CAudioDevice::GetMinBufferLength() const
       
   809 	{
       
   810 	TInt minBufSize = KMinBufferMilliseconds * iSampleRate * iChannels / 1000;
       
   811 	if (iEncoding == RMdaDevSound::EMdaSoundEncoding16BitPCM)
       
   812 		{
       
   813 		minBufSize *= 2; // All other encodings use 1 byte per sample
       
   814 		}
       
   815 	return minBufSize;
       
   816 	}
       
   817 	
       
   818 TBool COmxILPcmRendererProcessingFunction::CAudioDevice::IsBufferLengthSufficient(TInt aBufferLength) const
       
   819 	{
       
   820 	return aBufferLength >= GetMinBufferLength() ? ETrue : EFalse;
       
   821 	}
       
   822 
       
   823 
       
   824 void COmxILPcmRendererProcessingFunction::CAudioDevice::ProcessMediaTimeIndication(OMX_TIME_MEDIATIMETYPE& aMediaTimeType)
       
   825 	{
       
   826 	switch (aMediaTimeType.eUpdateType)
       
   827 		{
       
   828 		case OMX_TIME_UpdateClockStateChanged:
       
   829 			{
       
   830 			HandleClockStateChanged(aMediaTimeType);
       
   831 			}
       
   832 			break;
       
   833 			
       
   834 		case OMX_TIME_UpdateRequestFulfillment:
       
   835 			{
       
   836 			// As the Clock was using another earlier start time;
       
   837 			// it is time for the PCM renderer to start playing the audio.
       
   838 			iPlayData = ETrue;
       
   839 			PlayData();
       
   840 			
       
   841 			if (!ConstructAndStartUpdateTimer())
       
   842 			    {
       
   843 			    return;
       
   844 			    }
       
   845 			}
       
   846 			break;
       
   847 			
       
   848 		case OMX_TIME_UpdateScaleChanged:
       
   849 			{
       
   850 			HandleClockScaleChanged(aMediaTimeType);
       
   851 			}
       
   852 			break;
       
   853 			
       
   854 		default:
       
   855 			{
       
   856 			// Do nothing here
       
   857 			}
       
   858 		}
       
   859 	}
       
   860 
       
   861 
       
   862 void COmxILPcmRendererProcessingFunction::CAudioDevice::StartUpdateTimer()
       
   863 	{
       
   864 	if (!iIsStartTimeFlagSet)
       
   865 		{
       
   866 		DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::CAudioDevice::StartUpdateTimer() iIsStartTimeFlagSet == EFalse!!"));
       
   867 		return;
       
   868 		}
       
   869 	
       
   870 	// In case the timer already started
       
   871 	ASSERT(iPeriodic);
       
   872 	iPeriodic->Cancel();
       
   873 	
       
   874 	TCallBack callback(UpdateClockMediaTime, this);
       
   875 	
       
   876 	// Start updating the Clock comp. every KPcmRendererTimePlayedDelay
       
   877 	iPeriodic->Start(KPcmRendererTimePlayedDelay, KPcmRendererTimePlayedDelay, callback);
       
   878 	}
       
   879 
       
   880 
       
   881 TBool COmxILPcmRendererProcessingFunction::CAudioDevice::CanPlayNow()
       
   882     {
       
   883     if (iParent.iState != OMX_StateExecuting)
       
   884         {
       
   885         return EFalse;
       
   886         }
       
   887     
       
   888     if (iClockMediaTime < iParent.iStartMediaTime)
       
   889         {
       
   890         // Once all required Clock's clients have responded, the clock component starts 
       
   891         // the media clock using the earliest client start time.
       
   892         // Therefore, start playing the audio only when such time comes; send a time
       
   893         // completion request to the Clock component
       
   894         OMX_ERRORTYPE err = iParent.iClientClockPortPtr->MediaTimeRequest(NULL, iParent.iStartMediaTime, 0);
       
   895         
       
   896         if (err != OMX_ErrorNone)
       
   897             {
       
   898             DEBUG_PRINTF2(_L8("CAudioDevice::CanPlayNow() MediaTimeRequest() return %d"), err);
       
   899             }
       
   900         
       
   901         // Indicate that processing a new buffer should not trigger a false start on playback.
       
   902         iPlayData = EFalse;
       
   903         return EFalse;
       
   904         }
       
   905     else if (iClockMediaTime > iParent.iStartMediaTime)
       
   906         {
       
   907         // NOTE: The spec. states that the clock should use the minimum of the received start times
       
   908         //       Therefore the Clock should NOT jump forwards with timestamp greater than the PCM
       
   909         //       Renderer iStartMediaTime 
       
   910         DEBUG_PRINTF3(_L8("CanPlayNow() nMediaTimestamp(%d) > iStartMediaTime(%d) IGNORE this use case"), 
       
   911                 I64LOW(iClockMediaTime), I64LOW(iParent.iStartMediaTime));
       
   912         
       
   913         // However if the Clock sends out a timestamp greater than the buffer's timestamp
       
   914         // drop the buffers that fall outside the Clock specified MediaTimestamp;
       
   915         
       
   916         OMX_BUFFERHEADERTYPE* bufferPtr = iParent.iBuffersToEmpty[0];
       
   917         iParent.iBuffersToEmpty.Remove(0);
       
   918         SignalBufferCompletion(bufferPtr);
       
   919         bufferPtr = NULL;
       
   920         
       
   921         // Since the iStartMediaTime doesn't make sense anymore, reset iIsStartTimeFlagSet until the buffer's timestamp 
       
   922         // is within the the Clock's Media timestamp
       
   923         iIsStartTimeFlagSet = EFalse;
       
   924         return EFalse;
       
   925         }
       
   926     
       
   927     return ETrue;
       
   928     }
       
   929 
       
   930 
       
   931 void COmxILPcmRendererProcessingFunction::CAudioDevice::HandleClockStateChanged(const OMX_TIME_MEDIATIMETYPE& aMediaTimeType)
       
   932 	{	
       
   933 	switch (aMediaTimeType.eState)
       
   934 	    {
       
   935 	    case OMX_TIME_ClockStateRunning:
       
   936 	        {
       
   937 	        iClockMediaTime = aMediaTimeType.nMediaTimestamp;
       
   938 	        
       
   939 	        // There are two possibilities:
       
   940 	        // case 1 - The clock goes straight into running and the PCM renderer processes the  
       
   941 	        //          StateChanged notification prior the audio buffer
       
   942 	         
       
   943 	        if (iIsStartTimeFlagSet)
       
   944 	            {
       
   945 	            // OR
       
   946 	            // case 2 - The PCM recieves the audio buffer, and the clock StateChanged notification
       
   947 	            // comes later
       
   948 	            
       
   949 	            // Clear the returning buffer's flag.
       
   950 	            iParent.iBuffersToEmpty[0]->nFlags &= ~OMX_BUFFERFLAG_STARTTIME;
       
   951 	            
       
   952 	            // Cross checking the Clock's media timestamp with iStartMediaTime to see 
       
   953 	            // data can be rendered straight away
       
   954 	            if (!CanPlayNow())
       
   955 	                {
       
   956 	                break;
       
   957 	                }
       
   958 	            
       
   959 	            // Start playing the audio and start updating the Clock media time regularly 
       
   960 	            PlayData();
       
   961 
       
   962 	            if (!ConstructAndStartUpdateTimer())
       
   963 	                {
       
   964 	                return;
       
   965 	                }
       
   966 	            }
       
   967 			else if ((!iClockStateRunning) && (iParent.iState == OMX_StateExecuting))
       
   968 				{
       
   969 				// The clock has gone to running but no start time flag was received. This would
       
   970 				// indicate that the client moved it straight from stopped to running. As we may
       
   971 				// have received buffers while in stopped state, we need to start processing
       
   972 				// them now.
       
   973                 DEBUG_PRINTF(_L8("HandleClockStateChanged() Gone to running without start time flag set"));
       
   974 				iClockStateRunning = ETrue;
       
   975 				ProcessNextBuffer();
       
   976 				}
       
   977 	        
       
   978 	        // Otherwise, the queue is empty;
       
   979 	        //
       
   980 	        // NOTE: When !iIsStartTimeFlagSet && !iClockStateRunning would drop the incoming buffers;
       
   981 	        //       if the first buffer does not have the OMX_BUFFERFLAG_STARTTIME set
       
   982 	        }
       
   983 	        break;
       
   984 	    
       
   985         case OMX_TIME_ClockStateWaitingForStartTime:
       
   986             {
       
   987             if (iClockStateRunning)
       
   988                 {
       
   989                 DEBUG_PRINTF(_L8("HandleClockStateChanged() OMX_TIME_ClockStateRunning -> OMX_TIME_ClockStateWaitingForStartTime IGNORED!!"));
       
   990                 }
       
   991             else
       
   992                 {
       
   993                 // Let's try to process buffers (if any).
       
   994                 ProcessNextBuffer();
       
   995                 }
       
   996             }
       
   997             break;
       
   998 
       
   999         case OMX_TIME_ClockStateStopped:
       
  1000             {
       
  1001             if (iClockStateRunning)
       
  1002                 {
       
  1003                 // The Clock was in "Running" state but not anymore; stop the audio
       
  1004                 if (IsActive())
       
  1005                     {
       
  1006                     Cancel();
       
  1007                     }
       
  1008                 else
       
  1009                     {
       
  1010                     DoCancel();
       
  1011                     }
       
  1012 
       
  1013                 iPlayData = ETrue;
       
  1014                 if (iIsStartTimeFlagSet)
       
  1015                     {
       
  1016                     iIsStartTimeFlagSet = EFalse;
       
  1017                     iPeriodic->Cancel();
       
  1018                     }
       
  1019                 }
       
  1020             
       
  1021             // Otherwise, ignore other possibilities
       
  1022             }
       
  1023             
       
  1024             break;
       
  1025          
       
  1026         default:
       
  1027             {
       
  1028             DEBUG_PRINTF2(_L8("HandleClockStateChanged() aMediaTimeType.eState = %d IGNORED!!"), aMediaTimeType.eState);
       
  1029             }
       
  1030          break;
       
  1031 	    }
       
  1032    
       
  1033 	iClockStateRunning = (aMediaTimeType.eState == OMX_TIME_ClockStateRunning) ? ETrue : EFalse;
       
  1034 	}	
       
  1035 
       
  1036 
       
  1037 void COmxILPcmRendererProcessingFunction::CAudioDevice::HandleClockScaleChanged(const OMX_TIME_MEDIATIMETYPE& aMediaTimeType)
       
  1038 	{
       
  1039 	if (aMediaTimeType.xScale == 0)
       
  1040 		{
       
  1041 		PauseAudio();
       
  1042 		iPausedClockViaScale = ETrue;
       
  1043         DEBUG_PRINTF2(_L8("HandleClockScaleChanged() pausing iPausedClockViaScale = %d"), iPausedClockViaScale);
       
  1044  		}
       
  1045 	else if (aMediaTimeType.xScale == 0x10000)
       
  1046 		{
       
  1047 		// The scale is a Q16 value
       
  1048 		iPausedClockViaScale = EFalse;
       
  1049 		DEBUG_PRINTF2(_L8("HandleClockScaleChanged() resuming iPausedClockViaScale = %d"), iPausedClockViaScale);
       
  1050 
       
  1051 		// If we are active then there is an outstanding PlayData() request so we need to call ResumePlaying().
       
  1052 		// However calling ResumePlaying() without an outstanding PlayData() request can cause the TimePLayed() API
       
  1053 		// to go awry, so we should defer calling ResumePlaying() until the next PlayData() call.
       
  1054 		if (IsActive())
       
  1055 			{
       
  1056 			iSoundDevice.ResumePlaying();
       
  1057 			}
       
  1058 		else
       
  1059 			{
       
  1060 			iResumeAfterNextPlay = ETrue;
       
  1061 			}
       
  1062 		iParent.iPFHelper->BufferIndication();	//handles the race condition where both 1) iSoundDevice was paused after the last PlayData() completed and before it was passed any data & 2) BufferIndication()s came in for all the IL buffers while in this paused state
       
  1063 		StartUpdateTimer();
       
  1064 		}
       
  1065 
       
  1066 	// TODO: Handle the rest of the scale values
       
  1067 
       
  1068 	}
       
  1069 
       
  1070 
       
  1071 void COmxILPcmRendererProcessingFunction::CAudioDevice::DoCancel()
       
  1072 	{
       
  1073 	if (iSoundDevice.Handle() != 0)
       
  1074 		{
       
  1075 		iSoundDevice.CancelPlayData();
       
  1076 		iSoundDevice.FlushPlayBuffer();
       
  1077 		}
       
  1078 	
       
  1079 	if (iCurrentBuffer)
       
  1080 	    {
       
  1081 		iCurrentBuffer->nFilledLen = 0;
       
  1082 		
       
  1083 		iParent.iCallbacks.BufferDoneNotification(iCurrentBuffer,
       
  1084 		        iCurrentBuffer->nInputPortIndex,
       
  1085 		        OMX_DirInput);
       
  1086 		
       
  1087 		iCachedPlayBuffer.Zero();
       
  1088 		iCurrentBuffer = NULL;
       
  1089 		}
       
  1090 	}
       
  1091 
       
  1092 
       
  1093 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::OpenDevice()
       
  1094 	{
       
  1095 	OMX_ERRORTYPE err = OMX_ErrorNone;
       
  1096 	if(!iSoundDevice.Handle())
       
  1097 		{
       
  1098 		if(KErrNone != iSoundDevice.Open(KSoundScTxUnit0))
       
  1099 			{
       
  1100 			err = OMX_ErrorHardware;
       
  1101 			}
       
  1102 		}
       
  1103 	return err;
       
  1104 	}
       
  1105 
       
  1106 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::CloseDevice()
       
  1107 	{
       
  1108 	OMX_ERRORTYPE err = OMX_ErrorNone;
       
  1109 	if(iSoundDevice.Handle())
       
  1110 		{
       
  1111 		iSoundDevice.Close();
       
  1112 		iResumeAfterNextPlay = EFalse;
       
  1113 		}
       
  1114 	return err;
       
  1115 	}
       
  1116 
       
  1117 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::Execute()
       
  1118 	{
       
  1119 	if(!iSoundDevice.Handle())
       
  1120 		{
       
  1121 		if(KErrNone != iSoundDevice.Open())
       
  1122 			{
       
  1123 			return OMX_ErrorHardware;
       
  1124 			}
       
  1125 		}
       
  1126 
       
  1127 	if(iParent.iState == OMX_StatePause)
       
  1128 		{
       
  1129 		// Now we can send BufferDone notifications for each emptied
       
  1130 		// buffer...
       
  1131 		iParent.FlushBufferList(iParent.iBuffersEmptied);
       
  1132 		// If we are active then there is an outstanding PlayData() request so we need to call ResumePlaying().
       
  1133 		// However calling ResumePlaying() without an outstanding PlayData() request can cause the TimePLayed() API
       
  1134 		// to go awry, so we should defer calling ResumePlaying() until the next PlayData() call.
       
  1135 		if (IsActive())
       
  1136 			{
       
  1137 			iSoundDevice.ResumePlaying();
       
  1138 			}
       
  1139 		else
       
  1140 			{
       
  1141 			iResumeAfterNextPlay = ETrue;
       
  1142 			}
       
  1143 		StartUpdateTimer();
       
  1144 		}
       
  1145 	else
       
  1146 		{
       
  1147 		// Set play format
       
  1148 		RMdaDevSound::TCurrentSoundFormatBuf buf;
       
  1149 		iSoundDevice.GetPlayFormat(buf);
       
  1150 		buf().iRate = iSampleRate;
       
  1151 		buf().iChannels = iChannels;
       
  1152 		buf().iBufferSize = iBufferSize;
       
  1153 		buf().iEncoding = iEncoding;
       
  1154 		if(KErrNone != iSoundDevice.SetPlayFormat(buf))
       
  1155 			{
       
  1156 			return OMX_ErrorHardware;
       
  1157 			}
       
  1158 		
       
  1159 		if (iMuted)
       
  1160 		    {
       
  1161 		    iSoundDevice.SetVolume(0);
       
  1162 		    }
       
  1163 		else
       
  1164 		    {
       
  1165 		    iSoundDevice.SetVolume(iVolume);
       
  1166 		    }
       
  1167 		}
       
  1168 
       
  1169 	iParent.iState = OMX_StateExecuting;		
       
  1170 		
       
  1171 	// Make sure to start processing of queued up buffers (if any)
       
  1172 	if (!IsActive() && iParent.iBuffersToEmpty.Count() > 0)
       
  1173 		{
       
  1174 		ProcessNextBuffer();
       
  1175 		}
       
  1176 
       
  1177 	return OMX_ErrorNone;
       
  1178 	}
       
  1179 
       
  1180 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::MoveToPausedState()
       
  1181 	{
       
  1182 	iParent.iState = OMX_StatePause;
       
  1183 	PauseAudio();
       
  1184 
       
  1185 	return OMX_ErrorNone;
       
  1186 	}
       
  1187 
       
  1188 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::Stop()
       
  1189 	{
       
  1190 	if(iParent.iState == OMX_StateExecuting || iParent.iState == OMX_StatePause)
       
  1191 		{
       
  1192 		// Cancel and flush the device driver
       
  1193 		Cancel();
       
  1194 
       
  1195 		// Cancel timer to stop calling RSoundSc::TimePlayed()
       
  1196 		if (iIsStartTimeFlagSet)
       
  1197 			{
       
  1198 			ASSERT(iPeriodic);
       
  1199 			iPeriodic->Cancel();
       
  1200 			}
       
  1201 		
       
  1202 		iParent.iState = OMX_StateIdle;
       
  1203 
       
  1204 		// If the audio device is still open, store the last value of bytes
       
  1205 		// played before closing the audio device...
       
  1206 		if(iSoundDevice.Handle() != 0)
       
  1207 			{
       
  1208 			iLastBytesPlayedValue = iSoundDevice.BytesPlayed();
       
  1209 			// Close the sound device
       
  1210 			iSoundDevice.Close();
       
  1211 			iResumeAfterNextPlay = EFalse;
       
  1212 			}
       
  1213 		}
       
  1214 	
       
  1215 	iClockStateRunning = EFalse;
       
  1216 	iIsStartTimeFlagSet = EFalse;
       
  1217 	iPlayData = ETrue;
       
  1218 
       
  1219 	return OMX_ErrorNone;
       
  1220 	}
       
  1221 
       
  1222 
       
  1223 void COmxILPcmRendererProcessingFunction::CAudioDevice::PauseAudio()
       
  1224 	{
       
  1225 	// Cancel timer to stop calling RSoundSc::TimePlayed()
       
  1226 	if (iIsStartTimeFlagSet)
       
  1227 		{
       
  1228 		ASSERT(iPeriodic);
       
  1229 		iPeriodic->Cancel();
       
  1230 		}
       
  1231 	
       
  1232 	if (iSoundDevice.Handle())
       
  1233 		{
       
  1234 		iSoundDevice.PausePlayBuffer();
       
  1235 		}
       
  1236 	}
       
  1237 
       
  1238 
       
  1239 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::SetChannels(TUint aChannels)
       
  1240 	{
       
  1241 	iChannels = aChannels;
       
  1242 	return SetPlayFormat();
       
  1243 	}
       
  1244 
       
  1245 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::SetSampleRate(TUint aSampleRate)
       
  1246 	{
       
  1247 	iSampleRate = aSampleRate;
       
  1248 	return SetPlayFormat();
       
  1249 	}
       
  1250 
       
  1251 TInt ConvertOmxToSymbianVolume(TInt aVolume)
       
  1252 	{
       
  1253 	// OpenMax volume is in millibels while Symbian volume is in 0.5 db increments in the [0..255] range
       
  1254 	// We divide by 50 as 0.5 dB = 50 millibells
       
  1255 	TInt res = KMedianVolume + aVolume / 50;
       
  1256 	if (res < 0)
       
  1257 		return 0;
       
  1258 	if (res > KMaxVolume)
       
  1259 		return KMaxVolume;
       
  1260 	return res;
       
  1261 	}
       
  1262 	
       
  1263 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::SetVolume(TInt aVolume)
       
  1264 	{
       
  1265 	iVolume = ConvertOmxToSymbianVolume(aVolume);
       
  1266 	if ((!iMuted) && (iSoundDevice.Handle() != 0))
       
  1267 		{
       
  1268 		iSoundDevice.SetVolume(iVolume);
       
  1269 		}
       
  1270 	return OMX_ErrorNone;
       
  1271 	}
       
  1272 
       
  1273 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::SetVolumeRamp(const TTimeIntervalMicroSeconds& aRampDuration)
       
  1274 	{
       
  1275 	iVolumeRamp = aRampDuration;
       
  1276 	if(iVolumeRamp.Int64() != 0)
       
  1277 		{
       
  1278 		iRampAudioSample = ETrue;
       
  1279 		ConfigAudioRamper(
       
  1280 			iVolumeRamp.Int64());
       
  1281 		}
       
  1282 	else
       
  1283 		{
       
  1284 		iRampAudioSample = EFalse;
       
  1285 		}
       
  1286 	return OMX_ErrorNone;
       
  1287 	}
       
  1288 
       
  1289 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::SetMuted(TBool aMuted)
       
  1290 	{
       
  1291 	iMuted = aMuted;
       
  1292 	
       
  1293 	if (iSoundDevice.Handle() == 0)
       
  1294 	    {
       
  1295 		// Just cache the value; the value will be set once the the device is opened
       
  1296 	    return OMX_ErrorNone;
       
  1297 	    }
       
  1298 	
       
  1299 	if (iMuted)
       
  1300 		{
       
  1301 		iSoundDevice.SetVolume(0);
       
  1302 		}
       
  1303 	else
       
  1304 		{
       
  1305 		iSoundDevice.SetVolume(iVolume);
       
  1306 		}
       
  1307 	return OMX_ErrorNone;
       
  1308 	}
       
  1309 
       
  1310 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::SetPlayFormat()
       
  1311 	{
       
  1312 	if (iParent.iState == OMX_StateExecuting)
       
  1313 		{
       
  1314 		RMdaDevSound::TCurrentSoundFormatBuf buf;
       
  1315 		iSoundDevice.GetPlayFormat(buf);
       
  1316 		buf().iRate = iSampleRate;
       
  1317 		buf().iChannels = iChannels;
       
  1318 		buf().iBufferSize = iBufferSize;
       
  1319 		buf().iEncoding = iEncoding;
       
  1320 		if(KErrNone != iSoundDevice.SetPlayFormat(buf))
       
  1321 			{
       
  1322 			return OMX_ErrorHardware;
       
  1323 			}
       
  1324 		}
       
  1325 	return OMX_ErrorNone;
       
  1326 	}
       
  1327 
       
  1328 OMX_BUFFERHEADERTYPE* COmxILPcmRendererProcessingFunction::CAudioDevice::GetCurrentBuffer()
       
  1329 	{
       
  1330 	return iCurrentBuffer;
       
  1331 	}
       
  1332 
       
  1333 TInt COmxILPcmRendererProcessingFunction::CAudioDevice::GetBytesPlayed()
       
  1334 	{
       
  1335 	if(iSoundDevice.Handle() != 0)
       
  1336 		{
       
  1337 		return iSoundDevice.BytesPlayed();
       
  1338 		}
       
  1339 
       
  1340 	return iLastBytesPlayedValue;
       
  1341 	}
       
  1342 
       
  1343 void COmxILPcmRendererProcessingFunction::CAudioDevice::ConfigAudioRamper(TInt64 aRampTime)
       
  1344 	{
       
  1345 	iRampSamples = I64LOW(((TInt64(iSampleRate) * aRampTime) /1000000 )); // Add this
       
  1346 	iRampSamplesLeft = iRampSamples;
       
  1347 	iRampIncr = 0;
       
  1348 	iSkip = ETrue;
       
  1349 	}
       
  1350 
       
  1351 TBool COmxILPcmRendererProcessingFunction::CAudioDevice::RampAudio(CMMFDataBuffer* aBuffer)
       
  1352 	{
       
  1353 	TInt i=0;
       
  1354 	TInt length = aBuffer->Data().Length()>>1;
       
  1355 	if (length == 0)
       
  1356 		{
       
  1357 		return EFalse;
       
  1358 		}
       
  1359 		
       
  1360 	TInt16* sample = REINTERPRET_CAST(TInt16*,&aBuffer->Data()[0]);
       
  1361 	TInt64 theResult(0);
       
  1362 	while ((i < length) && (iRampIncr < iRampSamples))
       
  1363 		{
       
  1364 		theResult = sample[i];
       
  1365 		theResult *= iRampIncr;
       
  1366 		theResult /= iRampSamples;
       
  1367 		sample[i] = STATIC_CAST(TInt16, I64LOW(theResult) );
       
  1368 
       
  1369 		if ((iChannels == 1) || (!iSkip))
       
  1370 			{
       
  1371 			iRampIncr++;
       
  1372 			}
       
  1373 		iSkip = !iSkip;
       
  1374 		i++;
       
  1375 		}
       
  1376 
       
  1377 	if (iRampIncr < iRampSamples)
       
  1378 		return ETrue;
       
  1379 	else
       
  1380 		return EFalse;
       
  1381 	}
       
  1382 
       
  1383 
       
  1384 TInt COmxILPcmRendererProcessingFunction::CAudioDevice::UpdateClockMediaTime(TAny* aPtr)
       
  1385 	{
       
  1386 	CAudioDevice* ptr = (CAudioDevice*)aPtr;
       
  1387 	TTimeIntervalMicroSeconds playedTime(0);
       
  1388   	
       
  1389 	if (ptr->iSoundDevice.GetTimePlayed(playedTime) != KErrNone)
       
  1390 		{
       
  1391 		ptr->iParent.iCallbacks.ErrorEventNotification(OMX_ErrorHardware);
       
  1392 		return EFalse;
       
  1393 		}
       
  1394 	
       
  1395   	OMX_ERRORTYPE err;
       
  1396   	
       
  1397 	// Update the clock component audio reference clock
       
  1398   	err = ptr->iParent.iClientClockPortPtr->SetAudioReference(ptr->iParent.iStartMediaTime + playedTime.Int64());
       
  1399 
       
  1400 	if (err != OMX_ErrorNone)
       
  1401 		{
       
  1402 		ptr->iParent.iCallbacks.ErrorEventNotification(err);
       
  1403 		return EFalse;
       
  1404 		}
       
  1405 	
       
  1406 	DEBUG_PRINTF2(_L8("CAudioDevice::UpdateClockMediaTime : playedTime = %d"), 
       
  1407 					I64LOW(playedTime.Int64()));
       
  1408 
       
  1409 	return ETrue;
       
  1410 	}
       
  1411 
       
  1412 
       
  1413 void COmxILPcmRendererProcessingFunction::CAudioDevice::ProcessParamIndication(const OMX_AUDIO_PARAM_PCMMODETYPE& aPcmModeType)
       
  1414 	{
       
  1415 	if(SetChannels(aPcmModeType.nChannels) != OMX_ErrorNone)
       
  1416 		{
       
  1417 		iParent.iCallbacks.ErrorEventNotification(OMX_ErrorHardware);
       
  1418 		return;
       
  1419 		}
       
  1420 	
       
  1421 	if (SetSampleRate(aPcmModeType.nSamplingRate) != OMX_ErrorNone)
       
  1422 		{
       
  1423 		iParent.iCallbacks.ErrorEventNotification(OMX_ErrorHardware);
       
  1424 		return;
       
  1425 		}
       
  1426 	}
       
  1427 
       
  1428 COmxILPcmRendererProcessingFunction::CPFHelper* COmxILPcmRendererProcessingFunction::CPFHelper::NewL(CAudioDevice& aAudioDevice)
       
  1429 	{
       
  1430 	CPFHelper* self = new (ELeave) CPFHelper(aAudioDevice);
       
  1431 	CleanupStack::PushL(self);
       
  1432 	self->ConstructL();
       
  1433 	CleanupStack::Pop(self);
       
  1434 	return self;
       
  1435 	}
       
  1436 
       
  1437 COmxILPcmRendererProcessingFunction::CPFHelper::CPFHelper(CAudioDevice& aAudioDevice)
       
  1438 : CActive(EPriorityUserInput),
       
  1439   iAudioDevice(aAudioDevice)
       
  1440 	{
       
  1441 	}
       
  1442 	
       
  1443 void COmxILPcmRendererProcessingFunction::CPFHelper::ConstructL()
       
  1444 	{
       
  1445 	CActiveScheduler::Add(this);
       
  1446 	User::LeaveIfError(iCallerSemaphore.CreateGlobal(KNullDesC, 0));
       
  1447 	User::LeaveIfError(iMsgQueue.CreateLocal(KMaxMsgQueueEntries));
       
  1448 	iMsgQueue.NotifyDataAvailable(iStatus);
       
  1449 	RThread thisThread;
       
  1450 	iHelperThreadId = thisThread.Id();
       
  1451 	thisThread.Close();
       
  1452 	SetActive();
       
  1453 	}
       
  1454 	
       
  1455 COmxILPcmRendererProcessingFunction::CPFHelper::~CPFHelper()
       
  1456 	{
       
  1457 	Cancel(); 
       
  1458 	iMsgQueue.Close();
       
  1459 	iCallerSemaphore.Close();
       
  1460 	}
       
  1461 
       
  1462 void COmxILPcmRendererProcessingFunction::CPFHelper::RunL()
       
  1463 	{
       
  1464 
       
  1465 	TProcMessage msg;
       
  1466 	while (iMsgQueue.Receive(msg)==KErrNone)
       
  1467 		{
       
  1468 		switch (msg.iType)
       
  1469 			{
       
  1470 			case EOpenDevice:
       
  1471 				{
       
  1472 				iAudioDevice.OpenDevice();
       
  1473 				break;
       
  1474 				}
       
  1475 			case ECloseDevice:
       
  1476 				{
       
  1477 				iAudioDevice.CloseDevice();
       
  1478 				break;
       
  1479 				}
       
  1480 			case ECloseDeviceOnError:
       
  1481 				{
       
  1482 				iAudioDevice.Cancel();
       
  1483 				iAudioDevice.CloseDevice();
       
  1484 				iCallerSemaphore.Signal();
       
  1485 				break;
       
  1486 				}
       
  1487 			case EExecuteCommand:
       
  1488 				{
       
  1489 				iAudioDevice.Execute();	
       
  1490 				break;
       
  1491 				}				
       
  1492 
       
  1493 			case EStopCommand:
       
  1494 				{
       
  1495 				iAudioDevice.Stop();	
       
  1496 				break;
       
  1497 				}
       
  1498 				
       
  1499 			case ECancelCommand:
       
  1500 				{
       
  1501 				iAudioDevice.Cancel();	
       
  1502 				break;
       
  1503 				}
       
  1504 				
       
  1505 			case EBufferIndication:
       
  1506 				{
       
  1507 				iAudioDevice.ProcessNextBuffer();	
       
  1508 				break;
       
  1509 				}
       
  1510 			case EMediaTimeIndication:
       
  1511 				{
       
  1512 				iAudioDevice.ProcessMediaTimeIndication(msg.iMediaTimeType);	
       
  1513 				break;
       
  1514 				}
       
  1515 			case EParamIndication:
       
  1516 				{
       
  1517 				iAudioDevice.ProcessParamIndication(msg.iPcmModeType);
       
  1518 				break;
       
  1519 				}
       
  1520 			case ESetVolumeRamp:
       
  1521 				{
       
  1522 				iAudioDevice.SetVolumeRamp(TTimeIntervalMicroSeconds(msg.iRampDuration));
       
  1523 				break;
       
  1524 				}
       
  1525 			case ESetVolume:
       
  1526 				{
       
  1527 				iAudioDevice.SetVolume(msg.iVolumeValue);
       
  1528 				break;
       
  1529 				}
       
  1530 			case ESetMuted:
       
  1531 				{
       
  1532 				iAudioDevice.SetMuted(msg.iMuted);
       
  1533 				break;
       
  1534 				}
       
  1535 			default:
       
  1536 				{
       
  1537 				break;
       
  1538 				}					
       
  1539 			}
       
  1540 		}
       
  1541 	DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::CPFHelper::RunL : msg.iType[%d]"), msg.iType);		
       
  1542 	// setup for next callbacks		
       
  1543 	iMsgQueue.NotifyDataAvailable(iStatus);
       
  1544 	SetActive();
       
  1545 	}
       
  1546 
       
  1547 void COmxILPcmRendererProcessingFunction::CPFHelper::DoCancel()
       
  1548 	{
       
  1549 	if (iMsgQueue.Handle()!=NULL)
       
  1550 		{
       
  1551 		iMsgQueue.CancelDataAvailable();
       
  1552 		}
       
  1553 	}
       
  1554 
       
  1555 TInt COmxILPcmRendererProcessingFunction::CPFHelper::OpenDevice()
       
  1556 	{
       
  1557 	TProcMessage message;
       
  1558 	message.iType = EOpenDevice;
       
  1559 	return iMsgQueue.Send(message);
       
  1560 	}
       
  1561 
       
  1562 TInt COmxILPcmRendererProcessingFunction::CPFHelper::CloseDevice()
       
  1563 	{
       
  1564 	DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::CPFHelper::CloseDevice : IsActive[%s]"),
       
  1565 				  (IsActive() ? "YES" : "NO"));
       
  1566 	TProcMessage message;
       
  1567 	message.iType = ECloseDevice;
       
  1568 	return iMsgQueue.Send(message);
       
  1569 	}
       
  1570 
       
  1571 TInt COmxILPcmRendererProcessingFunction::CPFHelper::CloseDeviceOnError()
       
  1572 	{
       
  1573 	DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::CPFHelper::CloseDeviceOnError : IsActive[%d]"), (IsActive() ? 1 : 0));
       
  1574 
       
  1575 	RThread thisThread;
       
  1576 	if (thisThread.Id() == iHelperThreadId)
       
  1577 		{
       
  1578 		// Just do it...
       
  1579 		iAudioDevice.Cancel();
       
  1580 		iAudioDevice.CloseDevice();
       
  1581 		}
       
  1582 	else
       
  1583 		{
       
  1584 
       
  1585 		TProcMessage message;
       
  1586 		message.iType = ECloseDeviceOnError;
       
  1587 		TInt error = iMsgQueue.Send(message);
       
  1588 		if (KErrNone != error)
       
  1589 			{
       
  1590 			// only wait if the message was sent into the queue...
       
  1591 			iCallerSemaphore.Wait();
       
  1592 			}
       
  1593 		}
       
  1594 
       
  1595 	thisThread.Close();
       
  1596 
       
  1597 	return KErrNone;
       
  1598 
       
  1599 	}
       
  1600 
       
  1601 TInt COmxILPcmRendererProcessingFunction::CPFHelper::Execute()
       
  1602 	{
       
  1603 	DEBUG_PRINTF2(_L8("CPFHelper::Execute : IsActive[%s]"), (IsActive() ? "YES" : "NO"));
       
  1604 	TProcMessage message;
       
  1605 	message.iType = EExecuteCommand;
       
  1606 	return iMsgQueue.Send(message);
       
  1607 	}
       
  1608 		
       
  1609 TInt COmxILPcmRendererProcessingFunction::CPFHelper::Stop()
       
  1610 	{
       
  1611 	DEBUG_PRINTF2(_L8("CPFHelper::Stop : IsActive[%s]"), (IsActive() ? "YES" : "NO"));
       
  1612 	TProcMessage message;
       
  1613 	message.iType = EStopCommand;
       
  1614 	return iMsgQueue.Send(message);
       
  1615 	}
       
  1616 	
       
  1617 TInt COmxILPcmRendererProcessingFunction::CPFHelper::CancelDevice()
       
  1618 	{
       
  1619 	DEBUG_PRINTF2(_L8("CPFHelper::CancelDevice : IsActive[%s]"), (IsActive() ? "YES" : "NO"));
       
  1620 	TProcMessage message;
       
  1621 	message.iType = ECancelCommand;
       
  1622 	return iMsgQueue.Send(message);
       
  1623 	}
       
  1624 	
       
  1625 TInt COmxILPcmRendererProcessingFunction::CPFHelper::BufferIndication()
       
  1626 	{
       
  1627 	DEBUG_PRINTF2(_L8("CPFHelper::BufferIndication : IsActive[%s]"), (IsActive() ? "YES" : "NO"));
       
  1628 	TProcMessage message;
       
  1629 	message.iType = EBufferIndication;
       
  1630 	return iMsgQueue.Send(message);
       
  1631 	}
       
  1632 
       
  1633 TInt COmxILPcmRendererProcessingFunction::CPFHelper::MediaTimeIndication(const OMX_TIME_MEDIATIMETYPE& aMediaTimeType)
       
  1634 	{
       
  1635 	DEBUG_PRINTF2(_L8("CPFHelper::MediaTimeIndication : IsActive[%s]"), (IsActive() ? "YES" : "NO"));
       
  1636 	TProcMessage message;
       
  1637 	message.iType = EMediaTimeIndication;
       
  1638 	message.iMediaTimeType.eUpdateType = aMediaTimeType.eUpdateType;
       
  1639 	message.iMediaTimeType.eState = aMediaTimeType.eState;
       
  1640 	message.iMediaTimeType.xScale = aMediaTimeType.xScale;	
       
  1641 	message.iMediaTimeType.nMediaTimestamp = aMediaTimeType.nMediaTimestamp;
       
  1642 	
       
  1643 	return iMsgQueue.Send(message);
       
  1644 	}
       
  1645 
       
  1646 TInt COmxILPcmRendererProcessingFunction::CPFHelper::ParamIndication(const OMX_AUDIO_PARAM_PCMMODETYPE* aPcmModeType)
       
  1647 	{
       
  1648 	DEBUG_PRINTF2(_L8("CPFHelper::ParamIndication : IsActive[%s]"), (IsActive() ? "YES" : "NO"));
       
  1649 	TProcMessage message;
       
  1650 	message.iType = EParamIndication;
       
  1651 	message.iPcmModeType.nChannels =  aPcmModeType->nChannels;
       
  1652 	message.iPcmModeType.nSamplingRate =  aPcmModeType->nSamplingRate;
       
  1653 	
       
  1654 	return iMsgQueue.Send(message);
       
  1655 	}
       
  1656 
       
  1657 TInt COmxILPcmRendererProcessingFunction::CPFHelper::SetVolumeRamp(const OMX_U64 aRampDuration)
       
  1658 	{
       
  1659 	DEBUG_PRINTF2(_L8("CPFHelper::SetVolumeRamp : IsActive[%s]"), (IsActive() ? "YES" : "NO"));
       
  1660 	TProcMessage message;
       
  1661 	message.iType = ESetVolumeRamp;
       
  1662 	message.iRampDuration = aRampDuration;
       
  1663 	
       
  1664 	return iMsgQueue.Send(message);
       
  1665 	}
       
  1666 
       
  1667 TInt COmxILPcmRendererProcessingFunction::CPFHelper::SetVolume(const OMX_S32 aVolumeValue)
       
  1668 	{
       
  1669 	DEBUG_PRINTF2(_L8("CPFHelper::SetVolume : IsActive[%s]"), (IsActive() ? "YES" : "NO"));
       
  1670 	TProcMessage message;
       
  1671 	message.iType = ESetVolume;
       
  1672 	message.iVolumeValue = aVolumeValue;
       
  1673 	
       
  1674 	return iMsgQueue.Send(message);	
       
  1675 	}
       
  1676 
       
  1677 TInt COmxILPcmRendererProcessingFunction::CPFHelper::SetMuted(const OMX_BOOL aMuted)
       
  1678 	{
       
  1679 	DEBUG_PRINTF2(_L8("CPFHelper::SetMuted : IsActive[%s]"), (IsActive() ? "YES" : "NO"));
       
  1680 	TProcMessage message;
       
  1681 	message.iType = ESetMuted;
       
  1682 	message.iMuted = aMuted;
       
  1683 	
       
  1684 	return iMsgQueue.Send(message);
       
  1685 	}