mmlibs/mmfw/src/server/BaseClasses/mmfdatapath2.cpp
changeset 0 40261b775718
child 54 b68f3e90dca1
child 67 b35006be8823
equal deleted inserted replaced
-1:000000000000 0:40261b775718
       
     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 // source\server\mmfdatapath2.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <e32math.h>
       
    19 #include <mmf/common/mmffourcc.h>
       
    20 #include <mmf/common/mmfpaniccodes.h>
       
    21 #include <mmf/server/mmfaudiooutput.h>
       
    22 #include <mmf/server/mmfaudioinput.h>
       
    23 #include "mmfdatapath2.h"
       
    24 #include "mmfclientaudiostreamutils.h"
       
    25 #include <mmf/common/mmfaudio.h>
       
    26 #include <mmf/plugin/mmfcodecimplementationuids.hrh> // KUidMmfCodecAudioSettings
       
    27 #include <mmf/server/devsoundstandardcustominterfaces.h>
       
    28 #include <mmf/server/mmffile.h>
       
    29 #include <mda/client/resource.h>
       
    30 
       
    31 static void Panic(TMMFDataPathPanicCode aPanicCode, TInt aSourceLineNumber)
       
    32 	{
       
    33 	_LIT(KMMFDataPathPanicCategory, "MMFDataPath2");
       
    34 	User::Panic(KMMFDataPathPanicCategory, STATIC_CAST(TInt,aPanicCode) + aSourceLineNumber);
       
    35 	}
       
    36 
       
    37 /**
       
    38 Allocates and constructs a data path.
       
    39 
       
    40 Use this function if the codec UID is not already known by CMMFController
       
    41 and there is no data path ambiguity - ie only one data path is possible.
       
    42 
       
    43 Will create codec via fourCC.
       
    44 
       
    45 @param  aEventHandler
       
    46         Installs an event handler to provide message passing between clients and sources/sinks.
       
    47 
       
    48 @return Newly constructed data path object.
       
    49 */
       
    50 
       
    51 EXPORT_C CMMFDataPath2* CMMFDataPath2::NewL(MAsyncEventHandler& aEventHandler)
       
    52 	{
       
    53 	CMMFDataPath2* self = new(ELeave) CMMFDataPath2(TMediaId(), aEventHandler);
       
    54 	CleanupStack::PushL(self);
       
    55 	self->ConstructL();
       
    56 	CleanupStack::Pop();
       
    57 	return self;
       
    58 	}
       
    59 
       
    60 
       
    61 /**
       
    62 Allocates and constructs a data path according to the specified media ID.
       
    63 
       
    64 Use this function if the codec UID is not already known by CMMFController
       
    65 and there is ambiguity with the data path ie. there is more than one possible data path.
       
    66 
       
    67 @param  aMediaId
       
    68         Optional media ID parameter when there are multiple media types.
       
    69 @param  aEventHandler
       
    70         Installs an event handler to provide message passing between clients and sources/sinks.
       
    71 
       
    72 @return A newly constructed data path object.
       
    73 */
       
    74 
       
    75 EXPORT_C CMMFDataPath2* CMMFDataPath2::NewL(TMediaId aMediaId, MAsyncEventHandler& aEventHandler)
       
    76 	{
       
    77 	CMMFDataPath2* self = new(ELeave) CMMFDataPath2(aMediaId, aEventHandler);
       
    78 	CleanupStack::PushL(self);
       
    79 	self->ConstructL();
       
    80 	CleanupStack::Pop();
       
    81 	return self;
       
    82 	}
       
    83 
       
    84 /**
       
    85 Allocates and constructs a data path according to the specified codec UID.
       
    86 
       
    87 Use this function if the codec UID is already known by CMMFController
       
    88 and there is no data path ambiguity ie. only one data path is possible
       
    89 will create codec explicitly using the supplied codec Uid
       
    90 
       
    91 @param  aCodecUid
       
    92         Optional mediaID parameter when there are multiple media types
       
    93 @param  aEventHandler
       
    94         Installs an event handler to provide message passing between clients and sources/sinks.
       
    95 
       
    96 @return A newly constructed data path object.
       
    97 */
       
    98 
       
    99 EXPORT_C CMMFDataPath2* CMMFDataPath2::NewL(TUid aCodecUid, MAsyncEventHandler& aEventHandler)
       
   100 	{
       
   101 	CMMFDataPath2* self = new(ELeave) CMMFDataPath2(TMediaId(), aEventHandler);
       
   102 	CleanupStack::PushL(self);
       
   103 	self->ConstructL(aCodecUid);
       
   104 	CleanupStack::Pop();
       
   105 	return self;
       
   106 	}
       
   107 
       
   108 
       
   109 /**
       
   110 Allocates and constructs a data path according to the specified codec UID.
       
   111 
       
   112 Use this function if the codec UID is already known by CMMFController
       
   113 and there is ambiguity ie. more than one possible data path.
       
   114 TMediaId used to select the path.
       
   115 
       
   116 @param  aCodecUid
       
   117 		The codec UID.
       
   118 @param  aMediaId
       
   119         Optional mediaID parameter when there are multiple media types.
       
   120 @param  aEventHandler
       
   121         Installs an event handler to provide message passing between clients and sources/sinks.
       
   122 
       
   123 @return A newly constructed data path object.
       
   124 */
       
   125 EXPORT_C CMMFDataPath2* CMMFDataPath2::NewL(TUid aCodecUid, TMediaId aMediaId, MAsyncEventHandler& aEventHandler)
       
   126 	{
       
   127 	CMMFDataPath2* self = new(ELeave) CMMFDataPath2(aMediaId, aEventHandler);
       
   128 	CleanupStack::PushL(self);
       
   129 	self->ConstructL(aCodecUid);
       
   130 	CleanupStack::Pop();
       
   131 	return self;
       
   132 	}
       
   133 
       
   134 CMMFDataPath2::CMMFDataPath2(TMediaId aMediaId, MAsyncEventHandler& aEventHandler) 
       
   135 	: CMMFDataPath(aMediaId, aEventHandler), iTimeLeftToPlayComplete(-1)
       
   136 	{
       
   137 	}
       
   138 		
       
   139 void CMMFDataPath2::ConstructL(TUid aCodecUid)
       
   140 	{
       
   141 	CMMFDataPath::ConstructL(aCodecUid);
       
   142 	iRepeatTrailingSilenceTimer = CPeriodic::NewL(CActive::EPriorityStandard); 
       
   143 	}
       
   144 	
       
   145 /**
       
   146 Standard destructor.
       
   147 */
       
   148 
       
   149 CMMFDataPath2::~CMMFDataPath2()
       
   150 	{
       
   151 	if(iRepeatTrailingSilenceTimer)
       
   152 		{
       
   153 		iRepeatTrailingSilenceTimer->Cancel();
       
   154 		delete iRepeatTrailingSilenceTimer;
       
   155 		}
       
   156 	}
       
   157 
       
   158 TInt CMMFDataPath2::RepeatTrailingSilenceTimerComplete(TAny* aDataPath)
       
   159 	{
       
   160 	CMMFDataPath2* dataPath = static_cast<CMMFDataPath2*>(aDataPath);
       
   161 	
       
   162 	TRAPD(err, dataPath->DoRepeatTrailingSilenceTimerCompleteL());
       
   163 	if (err != KErrNone)
       
   164 		{
       
   165 		dataPath->DoSendEventToClient(KMMFEventCategoryPlaybackComplete, err);
       
   166 		}	
       
   167 	return KErrNone;
       
   168 	}
       
   169 	
       
   170 TInt CMMFDataPath2::DoRepeatTrailingSilenceTimerCompleteL()
       
   171 	{
       
   172 	//cancel this periodic timer
       
   173 	iRepeatTrailingSilenceTimer->Cancel();
       
   174 	if(iTimeLeftToPlayComplete.Int64()>0)
       
   175 		{
       
   176 		iTimeLeftToPlayComplete=0;
       
   177 		}
       
   178 		
       
   179 	if (iTrailingSilenceLeftToPlay.Int64() > 0)
       
   180 		{
       
   181 		PlaySilence();
       
   182 		}
       
   183 	else
       
   184 		{
       
   185 		SetPositionL(iPlayWindowStartPosition);
       
   186 		iTimeLeftToPlayComplete=-1;
       
   187 		FillSourceBufferL();		
       
   188 		}
       
   189 	return KErrNone;
       
   190 	}
       
   191 	
       
   192 void CMMFDataPath2::PlaySilence()
       
   193 	{		
       
   194 	// iRepeatTrailingSilenceTimer->After() takes a TTimeIntervalMicroSeconds32
       
   195 	// so for longer periods of silence call it repeatedly with KMaxTInt lengths
       
   196 	TTimeIntervalMicroSeconds32 silence;
       
   197 	if(iTimeLeftToPlayComplete.Int64() > 0)
       
   198 		{
       
   199 		silence = I64INT(iTimeLeftToPlayComplete.Int64());
       
   200 		}
       
   201 	else if (iTrailingSilenceLeftToPlay.Int64() > KMaxTInt)
       
   202 		{
       
   203 		silence = KMaxTInt;
       
   204 		iTrailingSilenceLeftToPlay = iTrailingSilenceLeftToPlay.Int64() - KMaxTInt;
       
   205 		}
       
   206 	else
       
   207 		{
       
   208 		silence = I64INT(iTrailingSilenceLeftToPlay.Int64());
       
   209 		iTrailingSilenceLeftToPlay = 0;
       
   210 		}
       
   211 	iRepeatTrailingSilenceTimer->Start(silence, silence , TCallBack(RepeatTrailingSilenceTimerComplete, this));
       
   212 	}
       
   213 
       
   214 /* 
       
   215  *  FillSourceBufferL
       
   216  * 
       
   217  *	Function to get data from the datapath's iDataSource
       
   218  */
       
   219 
       
   220 void CMMFDataPath2::DoFillSourceBufferL()
       
   221 	{
       
   222 #ifdef _DP_DEBUG
       
   223 	RDebug::Print(_L("DP::FillSourceBufferL tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
   224 #endif
       
   225 
       
   226 	__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording || (iState == EPrimed && iPauseCalled && iIsUsingResumeSupport)), Panic(EMMFDataPathPanicBadState,__LINE__)); 
       
   227 
       
   228 	// clear the no-more-source flag here (as well as in PlayL()) because 
       
   229 	// there may have been a re-position since the last call to BufferFilledL()
       
   230 	iNoMoreSourceData = EFalse;
       
   231 
       
   232 	if(!iObtainingAsyncSourceBuffer) 
       
   233 		{//this is a normal request for data. 
       
   234 		//If we are getting asynchronous buffers, then can't do this as iSourceBuffer == NULL
       
   235 		iSourceBuffer->SetFrameNumber(++iCurrentSourceFrameNumber); //so source knows which data to load buffer with
       
   236 		iSourceBuffer->SetStatus(EBeingFilled);
       
   237 		iSourceBuffer->SetLastBuffer(EFalse);
       
   238 		}
       
   239 
       
   240 #ifdef _DP_DEBUG
       
   241 	RDebug::Print(_L("DP asking for buffer %d  - ptr=0x%x   (this 0x%x)\n"), iCurrentSourceFrameNumber, iSourceBuffer,this);	
       
   242 #endif
       
   243 
       
   244 	iSourceBufferWithSource = ETrue;
       
   245 
       
   246 	// wait for BufferFilled callback from source. Do this here as some sources cause
       
   247 	//re-entrancy into data path via BufferFilledL
       
   248 	ChangeDataPathTransferState(EWaitSource);  
       
   249 
       
   250 	iDataSource->FillBufferL(iSourceBuffer, this, iMediaId);
       
   251 
       
   252 #ifdef _DP_DEBUG
       
   253 	RDebug::Print(_L("DP::FillSourceBufferL - DONE tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
   254 #endif
       
   255 	}
       
   256 
       
   257 /**
       
   258 Runs the clip depending on the current data path and transfer state.
       
   259 
       
   260 For example, fills the sink buffer if TDataPathState is EPlaying and TTransferState is ENeedSinkData.
       
   261 */
       
   262 void CMMFDataPath2::RunL()
       
   263 	{
       
   264 #ifdef _DP_DEBUG 
       
   265 	RDebug::Print(_L("DP::RunL transfer state %d, iPausedCalled %d, tick-%d   (this 0x%x)\n"),iTransferState, iPauseCalled, User::TickCount(),this);
       
   266 #endif
       
   267 	
       
   268 	switch (iState)
       
   269 		{
       
   270 	case EStopped:
       
   271 		break;
       
   272 	case EPrimed: // In the paused state we still continue to feed buffers to the sink. The sink (DevSound) handles the logic of whether the buffers should be emptied
       
   273 	    {
       
   274 	    if (!iPauseCalled || !iIsUsingResumeSupport)
       
   275 	        break;
       
   276 	    }	    
       
   277 	    // fall-through
       
   278 	case EPlaying:
       
   279 	case ERecording:
       
   280 	case EConverting:
       
   281 		switch (iTransferState)
       
   282 			{
       
   283 		case EWaitSink:
       
   284 		case EWaitSource:
       
   285 			break;
       
   286 		case EInitializeSink:
       
   287 			InitializeSinkL();
       
   288 			break;
       
   289 		case EInitializeSource:
       
   290 			InitializeSourceL();
       
   291 			break;
       
   292 		case ENeedSourceData:
       
   293 			FillSourceBufferL();
       
   294 			break;
       
   295 		case ENeedSinkData:
       
   296 			FillSinkBufferL();
       
   297 			break;
       
   298 		case ENeedToMatchSourceToSink:
       
   299 			FillSinkBufferL();
       
   300 			break;
       
   301 		case ESendDataToSink:
       
   302 			EmptySinkBufferL();
       
   303 			break;
       
   304 		case EEndOfData:
       
   305 			EndOfData();
       
   306 			break;
       
   307 			}
       
   308 		break;
       
   309 	default:
       
   310 		break;
       
   311 		}
       
   312 #ifdef _DP_DEBUG
       
   313 	RDebug::Print(_L("DP::RunL DONE\n"));
       
   314 #endif
       
   315 	}
       
   316 	
       
   317 /* 
       
   318  *  FillSourceBufferL
       
   319  * 
       
   320  *	Function to get data from the datapath's iDataSource
       
   321  */
       
   322 
       
   323 void CMMFDataPath2::FillSourceBufferL()
       
   324 	{
       
   325 	__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording || (iState == EPrimed && iPauseCalled && iIsUsingResumeSupport) ), Panic(EMMFDataPathPanicBadState,__LINE__)); 
       
   326 
       
   327 	//if the silence timer is active then dont propagate the request
       
   328 	if(iRepeatTrailingSilenceTimer->IsActive())
       
   329 		{
       
   330 		return;
       
   331 		}
       
   332 	
       
   333 	//play the silence period and dont propagate the request
       
   334 	if(iTrailingSilenceLeftToPlay>0 || iVerifyPlayComplete)
       
   335 		{
       
   336 		if(iVerifyPlayComplete)//case when the trailing silence is zero
       
   337 			{
       
   338 			if (!*iDisableAutoIntent && iDrmSource)
       
   339 				{
       
   340 				CMMFFile* file = static_cast<CMMFFile*>(iDrmSource);
       
   341 				TInt err = file->ExecuteIntent(ContentAccess::EPlay);
       
   342 				if (err != KErrNone)
       
   343 					{
       
   344 					DoSendEventToClient(KMMFEventCategoryPlaybackComplete, err);
       
   345 					return;
       
   346 					}
       
   347 				}
       
   348 			
       
   349 			//Retrieve the current play time and add "duration-currentplaytime" to the silence period
       
   350 			//This is to ensure that silence timer is not started before the previous play is actually completed by the devsound
       
   351 			TTimeIntervalMicroSeconds currentTime = CalculateAudioOutputPosition();
       
   352 			if(currentTime.Int64()>iPlayWindowStartPosition.Int64())
       
   353 				{
       
   354 				iTimeLeftToPlayComplete = iPlayWindowEndPosition.Int64()-currentTime.Int64();
       
   355 				}
       
   356 			else
       
   357 				{
       
   358 				iTimeLeftToPlayComplete = 0;
       
   359 				}
       
   360 
       
   361 			iVerifyPlayComplete = EFalse;
       
   362 			}
       
   363 		if(iTrailingSilenceLeftToPlay==0 && iTimeLeftToPlayComplete==0)
       
   364 			{
       
   365 			SetPositionL(iPlayWindowStartPosition);
       
   366 			iTimeLeftToPlayComplete=-1;
       
   367 			}
       
   368 		else
       
   369 			{
       
   370 			PlaySilence();
       
   371 			return;
       
   372 			}
       
   373 		}
       
   374 	
       
   375 	DoFillSourceBufferL();
       
   376 	}
       
   377 
       
   378 
       
   379 /** 
       
   380 Indicates the data source has filled the specified buffer.
       
   381 
       
   382 Called by the CMMFDataPath2's MDataSource when it has filled the buffer.
       
   383 
       
   384 @param aBuffer
       
   385        A pointer to the filled buffer.
       
   386 */
       
   387 void CMMFDataPath2::BufferFilledL(CMMFBuffer* aBuffer)
       
   388 	{	
       
   389 #ifdef _DP_DEBUG
       
   390 	RDebug::Print(_L("DP::BufferFilledL src has filled buffer %d (ptr=0x%x) with %d bytes EoF = %d  tick-%d    (this 0x%x)\n"),aBuffer->FrameNumber(),aBuffer, aBuffer->BufferSize(),aBuffer->LastBuffer(), User::TickCount(),this);
       
   391 #endif
       
   392 	
       
   393 	TBool isInTruePause = (iState == EPrimed  && iPauseCalled && iIsUsingResumeSupport);
       
   394 	//state only used if we are passing data
       
   395 	__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording || isInTruePause), Panic(EMMFDataPathPanicBadState,__LINE__));
       
   396 
       
   397 	__ASSERT_DEBUG((!iNoMoreSourceData), Panic(EMMFDataPathPanicBadState,__LINE__)); 
       
   398 	
       
   399 	//if we have been asked to repeat and this is the last buffer, reset last buffer flag and send to the device
       
   400 	if(aBuffer!= NULL && aBuffer->LastBuffer())
       
   401 		{
       
   402 		iNumberOfTimesPlayed++;
       
   403 		if ((iNumberOfTimesPlayed <= iNumberOfTimesToRepeat) || iNumberOfTimesToRepeat == KMdaRepeatForever)
       
   404 			{
       
   405 			aBuffer->SetLastBuffer(EFalse);
       
   406 			
       
   407 			//this will trigger the trailing silence timer next time a buffer is requested.
       
   408 			iTrailingSilenceLeftToPlay = iTrailingSilence;
       
   409 			iVerifyPlayComplete = ETrue;
       
   410 			}
       
   411 		}		
       
   412 		
       
   413 	iSourceBufferWithSource = EFalse;
       
   414 
       
   415 	//Has the datapath stopped running, if so were not interested in any callbacks.
       
   416 	if(iState == EStopped || (iState == EPrimed  && !isInTruePause))
       
   417 		{
       
   418 #ifdef _DP_DEBUG
       
   419 		RDebug::Print(_L("DP::BufferFilledL called while not expecting callback iState=%d  iPauseCalled=%d  (this 0x%x)\n"),iState, iPauseCalled,this);
       
   420 #endif
       
   421 		return;
       
   422 		}
       
   423 
       
   424 #ifdef REPOSITION_SPEEDUP
       
   425 	// if the source has been re-positioned, then go & get some more source data now
       
   426 	if (!iObtainingAsyncSourceBuffer && iSourceBuffer->FrameNumber() != iCurrentSourceFrameNumber)
       
   427 		{
       
   428 #ifdef _DP_DEBUG
       
   429 		RDebug::Print(_L("DP::BufferFilledL source was re-positioned re-requesting source data (this 0x%x)\n"),this);
       
   430 #endif
       
   431 		ChangeDataPathTransferState(ENeedSourceData);
       
   432 		return;
       
   433 		}
       
   434 #endif //REPOSITION_SPEEDUP
       
   435 
       
   436 	//bufer is NULL, indicating no more source data.
       
   437 	if (!aBuffer)
       
   438 		{
       
   439 		//If we only hold a reference to the source buffer, set that to NULL
       
   440 		if(iSnkBufRef)
       
   441 			{
       
   442 			iSourceBuffer = NULL;
       
   443 			}
       
   444 		
       
   445 		iNoMoreSourceData = ETrue;
       
   446 
       
   447 		if(!iCodec || //there's only one buffer and that has been returned as NULL, so must be end of data
       
   448 		  iSinkBufferWithSink) //buffer is with sink, we don't have any more data to put in it, so must be end of data
       
   449 			{
       
   450 			ChangeDataPathTransferState(EEndOfData);
       
   451 			}
       
   452 		else //sink buffer is with datapath, see if there is anything to send to sink
       
   453 			{
       
   454 			ChangeDataPathTransferState(ENeedToMatchSourceToSink);
       
   455 			}
       
   456 		
       
   457 #ifdef _DP_DEBUG
       
   458 		RDebug::Print(_L("DP::BufferFilledL DONE aBuffer==NULL tick-%d (this 0x%x)\n"),User::TickCount(),this);
       
   459 #endif
       
   460 		return;
       
   461 		} 
       
   462 
       
   463 	
       
   464 	//We were waiting for a response from the source to get an asynchronous buffer.
       
   465 	//We now have it, and we proceed to transfer this data to the sink.
       
   466 	if	(iObtainingAsyncSourceBuffer)
       
   467 		{
       
   468 		iObtainingAsyncSourceBuffer = EFalse;
       
   469 		}
       
   470 	
       
   471 
       
   472 	aBuffer->SetStatus(EFull);
       
   473 
       
   474 	if(iSourceBuffer != aBuffer)
       
   475 		{//buffer has been changed by the source
       
   476 		iSourceBuffer = aBuffer;
       
   477 		if (!(iBuffersToUse & ENeedSinkBuffer))
       
   478 			{//we only need one buffer and use source
       
   479 			iSinkBuffer = iSourceBuffer;
       
   480 			iSnkBufRef = ETrue;
       
   481 			}
       
   482 #ifdef _DP_DEBUG
       
   483 	RDebug::Print(_L("DP::BufferFilledL - iSourceBuffer=0x%x ref=%d   iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
       
   484 #endif	
       
   485 		}
       
   486 	//Is this the last buffer from the source (0 length or LastBuffer flag set)
       
   487 	//or have reached the end of the play window; we only look at the play window here
       
   488 	//if we are converting. For conversion we look at the data we have read. This is then passed onto 
       
   489 	//the source
       
   490 	if (!iSourceBuffer->BufferSize() || iSourceBuffer->LastBuffer() ||
       
   491 		(((iState == EConverting) || (iState == EPlaying)) && (iPlayWindowEndPosition < iCachedSourceDuration) && ( InputPosition() >= iPlayWindowEndPosition ))) 
       
   492 		{
       
   493 		iNumberOfTimesPlayed++;
       
   494 		if ((iNumberOfTimesPlayed <= iNumberOfTimesToRepeat) || iNumberOfTimesToRepeat == KMdaRepeatForever)
       
   495 			{
       
   496 			iSourceBuffer->SetLastBuffer(EFalse);
       
   497 			//this will trigger the trailing silence timer next time a buffer is requested.
       
   498 			iTrailingSilenceLeftToPlay = iTrailingSilence;
       
   499 			iVerifyPlayComplete = ETrue;
       
   500 			}
       
   501 		else
       
   502 			{		
       
   503 	#ifdef _DP_DEBUG
       
   504 			RDebug::Print(_L("DP::BufferFilledL end of input data  tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
   505 			RDebug::Print(_L("iSourceBuffer->BufferSize()=%d\n"),iSourceBuffer->BufferSize());
       
   506 			RDebug::Print(_L("iSourceBuffer->LastBuffer()=%d\n"),iSourceBuffer->LastBuffer());
       
   507 			RDebug::Print(_L("InputPosition()=%d  >= iPlayWindowEndPosition=%d\n"),I64INT(InputPosition().Int64()),I64INT(iPlayWindowEndPosition.Int64()));
       
   508 	#endif
       
   509 			iNoMoreSourceData = ETrue;
       
   510 			iSourceBuffer->SetLastBuffer(ETrue); //just in-case we are terminating on BufferSize == 0 or play window
       
   511 			}
       
   512 		}
       
   513 
       
   514 
       
   515 	if (!iCodec)
       
   516 		{
       
   517 		ChangeDataPathTransferState(ESendDataToSink);
       
   518 		}
       
   519 	else if(!iSinkBufferWithSink) //sink buffer is with data path, can try to fill it
       
   520 		{
       
   521 		ChangeDataPathTransferState(ENeedToMatchSourceToSink);	
       
   522 		}
       
   523 	//else wait for sink to return buffer BufferEmptied will send us into ENeedToMatchSourceToSink state
       
   524 
       
   525 #ifdef _DP_DEBUG
       
   526 	RDebug::Print(_L("DP::BufferFilledL - DONE tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
   527 #endif
       
   528 	}
       
   529 	
       
   530 /** 
       
   531 Sets the data path position.
       
   532 
       
   533 @param  aPosition
       
   534 		The data path position.
       
   535 */
       
   536 void CMMFDataPath2::SetPositionL(const TTimeIntervalMicroSeconds& aPosition)
       
   537 	{//need to map to source position to frame position 
       
   538 #ifdef _DP_DEBUG
       
   539 	RDebug::Print(_L("DP::SetPositionL = %d  ticks-%d   (this 0x%x)\n"),I64INT(aPosition.Int64()), User::TickCount(),this);
       
   540 #endif
       
   541 
       
   542 	if (iState == EStopped)
       
   543 		{
       
   544 		User::Leave(KErrNotReady); //can only set position if primed
       
   545 		}
       
   546 	
       
   547 	if(iGetTimePlayedSupported)
       
   548 		{
       
   549 		TTimeIntervalMicroSeconds timePlayed(0);
       
   550 		if(iState == EPlaying && iDataSink->DataSinkType() == KUidMmfAudioOutput)
       
   551 			{
       
   552 			CMMFAudioOutput* audioOutput = STATIC_CAST(CMMFAudioOutput*,iDataSink);
       
   553 			CMMFDevSound& devSound = audioOutput->SoundDevice();
       
   554 			TInt err= devSound.GetTimePlayed(timePlayed);
       
   555 			if(err == KErrNone)
       
   556 				{
       
   557 				iDevSoundRepositionTime = timePlayed.Int64();
       
   558 				}
       
   559 			}
       
   560 		else
       
   561 			{
       
   562 			iDevSoundRepositionTime = 0;
       
   563 			}
       
   564 		}
       
   565 	else //roll back to samplesplayed
       
   566 		{
       
   567 		//As this will affect the position, we need to know how many bytes were 
       
   568 		//played when position was updated. Future Position() requests will
       
   569 		//then use this refernce to determine the current position.
       
   570 		iReferenceAudioSamplesPlayed = AudioSamplesPlayed();
       
   571 		}
       
   572 	
       
   573 	// Force the new position to be inside the play window (also within the file duration)
       
   574 	if ( aPosition < iPlayWindowStartPosition )
       
   575 		{
       
   576 		iStartPosition = iPlayWindowStartPosition;
       
   577 		}
       
   578 	else if ( aPosition > iPlayWindowEndPosition )
       
   579 		{
       
   580 		iStartPosition = iPlayWindowEndPosition; //clearly this will cause nothing to be played
       
   581 		}
       
   582 	else
       
   583 		{
       
   584 		iStartPosition = aPosition;
       
   585 		}
       
   586 	
       
   587 	TTimeIntervalMicroSeconds interval;
       
   588 
       
   589 	//can only set the position on an MDataSource that is a format object
       
   590 	//Note: position defaults to source if both source & sink are clips
       
   591 	if (iDataSource->DataSourceType() == KUidMmfFormatDecode)
       
   592 		{
       
   593 		//position is not beyond the end of file
       
   594 		interval = ((CMMFFormatDecode*)iDataSource)->FrameTimeInterval(iMediaId);
       
   595 
       
   596 		// for some reason this code won't compile without these intermediate steps
       
   597 		TInt64 position = iStartPosition.Int64();
       
   598 		TInt64 interval64 = interval.Int64();
       
   599 		if (interval64 == 0)
       
   600 			User::Leave(KErrDivideByZero); 
       
   601 		TInt64 datapos64 = position/interval64; 
       
   602 		iCurrentSourceFrameNumber = I64LOW(datapos64);
       
   603 
       
   604 
       
   605         // Try to set the position directly on the format
       
   606         TRAP_IGNORE(((CMMFFormatDecode*)iDataSource)->SetPositionL(iStartPosition));
       
   607         //NB: don't worry about error, since we'll reposition anyway when we get the next buffer
       
   608 		}
       
   609 	else if (iDataSink->DataSinkType() == KUidMmfFormatEncode)
       
   610 		{			
       
   611 		//position is not beyond the end of file
       
   612 		interval = ((CMMFFormatEncode*)iDataSink)->FrameTimeInterval(iMediaId);
       
   613 
       
   614 		//convert to TUint - for some reason it won't compile without these intermediate steps
       
   615 		TInt64 position = iStartPosition.Int64();
       
   616 		TInt64 interval64 = interval.Int64();
       
   617 		if (interval64 == 0)
       
   618 			User::Leave(KErrDivideByZero); 
       
   619 		TInt64 datapos64 = position/interval64; 
       
   620 		iCurrentSinkFrameNumber = I64LOW(datapos64);
       
   621 
       
   622 
       
   623         // Try to set the position directly on the format
       
   624         TRAP_IGNORE(((CMMFFormatEncode*)iDataSink)->SetPositionL(iStartPosition));
       
   625         //NB: don't worry about error, since we'll reposition anyway when we get the next buffer
       
   626 		}
       
   627 	else
       
   628 		{//can only set position if source or sink is a format
       
   629 		//If both source and sink are formats position is relative to the source
       
   630 		User::Leave(KErrNotSupported); //can't set position if neither source nor sink are clips
       
   631 		}
       
   632 
       
   633 	if(iCodec) //we have a real codec, must reset it
       
   634 		{
       
   635 		iCodec->ResetL(); // Need to preserve sync when resuming play
       
   636 		}
       
   637 		
       
   638 	// Once we've sent the last buffer to the sink it's too late to start
       
   639 	// changing the state since we may get a RunError(KErrUnderflow) at any time.
       
   640 	// Once this happens, the sound driver may have unloaded etc..and recovery
       
   641 	// would be complicated.
       
   642 	if (iAllDataSentToSink)
       
   643 		{
       
   644 		return;
       
   645 		}
       
   646 #ifdef _DP_DEBUG
       
   647 	RDebug::Print(_L("DP::SetPosition - Done iCurrentSourceFrameNumber=%d  iStartPosition=%d  ticks-%d   (this 0x%x)\n"),iCurrentSourceFrameNumber, I64INT(iStartPosition.Int64()), User::TickCount(),this);	
       
   648 #endif
       
   649 	}
       
   650 
       
   651 /** 
       
   652 Gets the data path position.
       
   653 
       
   654 @return The data path position.
       
   655 */
       
   656 TTimeIntervalMicroSeconds CMMFDataPath2::Position() const
       
   657 	{
       
   658 	if ((iState == ERecording) || (iState == EConverting))
       
   659 		{
       
   660 		return InputPosition();
       
   661 		}
       
   662 	else if(iState == EPlaying)
       
   663 		{
       
   664 		return OutputPosition();
       
   665 		}
       
   666 	else
       
   667 		{
       
   668 		return iStartPosition;
       
   669 		}
       
   670 	}
       
   671 
       
   672 TTimeIntervalMicroSeconds CMMFDataPath2::OutputPosition() const
       
   673 	{
       
   674 	TTimeIntervalMicroSeconds interval;
       
   675 	TTimeIntervalMicroSeconds position;
       
   676 
       
   677     if (iDataSink->DataSinkType() == KUidMmfAudioOutput)
       
   678         {
       
   679 		position = CalculateAudioOutputPosition();
       
   680 #ifdef _DP_DEBUG
       
   681 		RDebug::Print(_L("DP::OutputPosition from audio output= %d\n"),I64INT(position.Int64()));
       
   682 #endif
       
   683         }
       
   684 	else if (iDataSink->DataSinkType() == KUidMmfFormatEncode)
       
   685 		{
       
   686 		//note Encode format position takes priority if both source & sink are formats?
       
   687         // try to get the position directly from the format. If that fails, work it out here
       
   688         TRAPD(error, position = ((CMMFFormatEncode*)iDataSink)->PositionL());
       
   689         if (error)//getting the position from the format didn't work so calculate it here
       
   690             {
       
   691 		    interval = ((CMMFFormatEncode*)iDataSink)->FrameTimeInterval(iMediaId);
       
   692 			TInt64 position64 = interval.Int64() * iCurrentSinkFrameNumber;
       
   693 			position = position64;
       
   694             }
       
   695 
       
   696 		TTimeIntervalMicroSeconds duration = CONST_CAST(CMMFDataPath2*,this)->Duration(); //need this to check position doesn't exceed duration
       
   697 		if (position > duration)//this can happen on last buffer 
       
   698 			{
       
   699 			position = duration;
       
   700 			}
       
   701 #ifdef _DP_DEBUG
       
   702 		RDebug::Print(_L("DP::OutputPosition  from format= %d\n"),I64INT(position.Int64()));
       
   703 #endif
       
   704 		}
       
   705 	else
       
   706 		{//can only read output position if sink is a format or an audio output
       
   707 		return TTimeIntervalMicroSeconds(0);
       
   708 		}
       
   709 
       
   710 	return position;
       
   711 	}
       
   712 			
       
   713 TTimeIntervalMicroSeconds CMMFDataPath2::CalculateAudioOutputPosition() const
       
   714     {
       
   715 	//This operation can only be carried out on an Audio Output
       
   716 	__ASSERT_ALWAYS(iDataSink->DataSinkType() == KUidMmfAudioOutput, Panic(EMMFDataPathPanicProgrammingError,__LINE__));
       
   717 
       
   718 
       
   719 	//If we are not playing, simply return where we will play from
       
   720 	if(iState != EPlaying || iCurrentSinkFrameNumber == 0 || iStartPosition == iPlayWindowEndPosition )
       
   721 		{
       
   722 		return iStartPosition;
       
   723 		}
       
   724 #ifdef _DP_DEBUG
       
   725 	RDebug::Print(_L("DP::CalculateAudioOutputDuration from %d\n"),iReferenceAudioSamplesPlayed);
       
   726 #endif
       
   727 
       
   728 	CMMFAudioOutput* audioOutput = STATIC_CAST(CMMFAudioOutput*,iDataSink);
       
   729 	CMMFDevSound& devSound = audioOutput->SoundDevice();
       
   730 	
       
   731 	TTimeIntervalMicroSeconds devSoundTimePlayed(0);
       
   732 	TInt64 timePlayed(0);
       
   733 	TInt err = KErrNone;
       
   734 	if(iGetTimePlayedSupported)
       
   735 		{
       
   736 		err= devSound.GetTimePlayed(devSoundTimePlayed);
       
   737 		if(err == KErrNone)
       
   738 			{
       
   739 			timePlayed = devSoundTimePlayed.Int64()-iDevSoundRepositionTime.Int64();
       
   740 			}
       
   741 		}
       
   742 	else //Roll back to SamplesPlayed
       
   743 		{
       
   744 		TReal samplesPlayed = AudioSamplesPlayed() - iReferenceAudioSamplesPlayed;
       
   745 		TMMFCapabilities devSoundConfig = devSound.Config();
       
   746 		TInt samplingFreq = StreamUtils::SampleRateAsValue(devSoundConfig);
       
   747 	#ifdef _DP_DEBUG
       
   748 		RDebug::Print(_L("samplingFreq %d\n"),samplingFreq);
       
   749 	#endif
       
   750 		
       
   751 		TReal timePlayedSeconds = 0;
       
   752 		if(samplesPlayed)
       
   753 			{
       
   754 			timePlayedSeconds = samplesPlayed/samplingFreq;
       
   755 			}
       
   756 		timePlayed = I64DOUBLECAST(timePlayedSeconds * 1000000);
       
   757 
       
   758 	#ifdef _DP_DEBUG
       
   759 		RDebug::Print(_L("timePlayed %d\n"), I64LOW(timePlayed));
       
   760 	#endif
       
   761 		}
       
   762 	if(err == KErrNone)
       
   763 		{
       
   764 		// When Resume is not supported. Datapath simulates Pause() through DevSound's Stop
       
   765 		// the time played is lost. So we need to saved the last position
       
   766 		// On the opposite, when Resume is supported the time played returned by DevSound 
       
   767 		// reflects the real position, so there is no needed to recalculate at least playwindow is being used
       
   768 		// Finally, if Resume is supported but is not used the position also need to be saved
       
   769 		if(!iIsUsingResumeSupport || iPlayWindowStartPosition.Int64() > 0)
       
   770 			{
       
   771 			timePlayed = timePlayed + iStartPosition.Int64();	
       
   772 			}
       
   773 		
       
   774 		//During repeats. we need to reset the positin manually to playstart once playend is reached
       
   775 		//this is because the bytes returned by devsound are not accurate in all the cases
       
   776 		if(iRepeatTrailingSilenceTimer->IsActive() || iTimeLeftToPlayComplete==0)//loop play
       
   777 			{
       
   778 			if(iTimeLeftToPlayComplete==0)
       
   779 				{
       
   780 				timePlayed = iPlayWindowStartPosition.Int64();
       
   781 				}
       
   782 			}
       
   783 		else if(timePlayed>=(iPlayWindowEndPosition.Int64()+1))
       
   784 			{
       
   785 			timePlayed = iPlayWindowStartPosition.Int64();
       
   786 			}
       
   787 		}
       
   788 	
       
   789 	return TTimeIntervalMicroSeconds(timePlayed);
       
   790     }
       
   791    
       
   792 /** 
       
   793 Stops playing.
       
   794 
       
   795 Resets datapath position - currently does not clean up buffers. Sends KMMFErrorCategoryDataPathGeneralError 
       
   796 to the client if an error occurs.
       
   797 */
       
   798 void CMMFDataPath2::Stop()
       
   799 	{ 
       
   800 #ifdef _DP_DEBUG
       
   801 	RDebug::Print(_L("DP::Stop current state=%d  tick-%d   (this 0x%x)\n"), iTransferState, User::TickCount(),this);
       
   802 #endif
       
   803 	if ((iDataPathCreated)  && (iState != EStopped))
       
   804 		{ 
       
   805 		TRAPD(err, DoStopL());
       
   806 		if (err)
       
   807 			{
       
   808 			DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
       
   809 			}
       
   810 		}
       
   811 	}
       
   812 
       
   813 void CMMFDataPath2::DoStopL()
       
   814 	{
       
   815 	CMMFDataPath::DoStopL();
       
   816 	iRepeatTrailingSilenceTimer->Cancel();
       
   817 	iIsUsingResumeSupport = EFalse;
       
   818 	}
       
   819 	
       
   820 /** 
       
   821 Pauses playing.
       
   822 
       
   823 Sends KMMFErrorCategoryDataPathGeneralError to the client if an error occurs.
       
   824 */
       
   825 void CMMFDataPath2::Pause()
       
   826 	{
       
   827 #ifdef _DP_DEBUG
       
   828 	RDebug::Print(_L("DP::Pause, on src buff %d  sink buf %d   (this 0x%x)\n"), iCurrentSourceFrameNumber, iCurrentSinkFrameNumber,this);			
       
   829 	RDebug::Print(_L("DP::Pause current state=%d  tick-%d    (this 0x%x)\n"),iTransferState, User::TickCount(),this);
       
   830 #endif
       
   831 
       
   832 	TRAPD(err, DoPauseL());
       
   833 	
       
   834 	if (err)
       
   835 		{
       
   836 		DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
       
   837 		}
       
   838 #ifdef _DP_DEBUG
       
   839 	RDebug::Print(_L("DP::Pause - DONE tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
   840 #endif
       
   841 	}
       
   842 
       
   843 EXPORT_C void CMMFDataPath2::PreEmptionPause()
       
   844     {
       
   845     TRAPD(err, DoPreEmptionPauseL());
       
   846     
       
   847     if (err)
       
   848         {
       
   849         DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
       
   850         }
       
   851     }
       
   852 
       
   853 /** 
       
   854 Pauses playing.
       
   855 
       
   856 Sends KMMFErrorCategoryDataPathGeneralError to the client if an error occurs.
       
   857 */
       
   858 void CMMFDataPath2::DoPreEmptionPauseL()
       
   859 	{
       
   860 
       
   861     if ((iDataPathCreated) && ((iState == EPlaying) || (iState == EConverting) && ( iDataSink->DataSinkType() == KUidMmfAudioOutput )))
       
   862         {
       
   863         iDataSource->SourcePauseL();        // propagate state change to source
       
   864         SetPositionL(Position());
       
   865         iIsUsingResumeSupport = EFalse;
       
   866 
       
   867         iDataSink->SinkStopL();
       
   868 	    iPauseCalled = ETrue;               // indicate pause is called
       
   869      
       
   870 	    iState = EPrimed;                   // go back to primed state (we're not playing)
       
   871 		
       
   872 		iSinkBufferWithSink = EFalse;
       
   873 		iSourceBufferWithSource = EFalse;
       
   874   
       
   875 		ResetRefBuffers();                  // buffer references may not be valid any more
       
   876   
       
   877 		Cancel(); //Stop the state machine		
       
   878 	    }
       
   879 	if(iState == ERecording)
       
   880 	     {
       
   881 	     User::Leave(KErrNotSupported);
       
   882 	     }
       
   883 	 iRepeatTrailingSilenceTimer->Cancel();
       
   884 	}
       
   885 	
       
   886 void CMMFDataPath2::DoPauseL()
       
   887 	{
       
   888 #ifdef _DP_DEBUG
       
   889 	RDebug::Print(_L("DP::DoPauseL tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
   890 #endif
       
   891 
       
   892 
       
   893 	if ((iDataPathCreated) && ((iState == EPlaying) || (iState == EConverting)))
       
   894 		{
       
   895 		if (iDataSink->DataSinkType() == KUidMmfAudioOutput && iIsResumeSupported)
       
   896 			{
       
   897 			iDataSink->SinkPauseL();
       
   898 			// When true pause is supported only the datapath's position 
       
   899 			// should be updated, MDataSource position should be changed
       
   900 			iStartPosition = Position();
       
   901 			iIsUsingResumeSupport = ETrue;
       
   902 			// If we wait for the sink to complete play, then we do not proceed with supplying the buffers to the sink
       
   903 			// In this case we need to reset the buffers so that InitializeSinkL won't attempt bringing in new ones
       
   904 			if (iTransferState == EWaitSink)
       
   905 				{
       
   906 				ResetRefBuffers();
       
   907 				}
       
   908 			}
       
   909 		else
       
   910 			{
       
   911 			// If we use resume support, then there is no need to pause source as we would continue to supply buffers to the sink
       
   912 			// Here we are not using resume support, thus we're pausing the source
       
   913 			iDataSource->SourcePauseL();		
       
   914 			SetPositionL(Position());
       
   915 			iDataSink->SinkStopL();
       
   916 			ResetRefBuffers();                  // buffer references may not be valid any more
       
   917   
       
   918 			Cancel(); //Stop the state machine					
       
   919 			}
       
   920 		iPauseCalled = ETrue;				// indicate pause is called
       
   921 		
       
   922 		iState = EPrimed;					// go back to primed state (we're not playing)
       
   923 		}
       
   924 	else if(iState == ERecording)
       
   925 		{
       
   926 		iPauseCalled = ETrue;
       
   927 #ifdef _DP_DEBUG
       
   928 		RDebug::Print(_L("DP::DoPauseL Recording, pause datasource\n"));
       
   929 #endif
       
   930 		iDataSource->SourcePauseL();
       
   931 		}
       
   932 	iRepeatTrailingSilenceTimer->Cancel();
       
   933 #ifdef _DP_DEBUG
       
   934 	RDebug::Print(_L("DP::DoPauseL - Done iReferenceAudioSamplesPlayed = %d\n"),iReferenceAudioSamplesPlayed);
       
   935 	RDebug::Print(_L("DP::DoPauseL - Done restart at %d tick-%d   (this 0x%x)\n"),I64INT(iStartPosition.Int64()), User::TickCount(),this);
       
   936 #endif
       
   937 	}
       
   938 
       
   939 /**
       
   940 Cancels the silence timer.
       
   941 */
       
   942 void CMMFDataPath2::DoCancel()
       
   943 	{
       
   944 	//cancel repeats
       
   945 	iRepeatTrailingSilenceTimer->Cancel();
       
   946 	iNumberOfTimesToRepeat=0;
       
   947 	}
       
   948 
       
   949 /**
       
   950 Allocates buffers in preparation to play.
       
   951 
       
   952 Must be called before calling PlayL().
       
   953 
       
   954 iSnkBufRef and iSrcBufRef contain ETrue if these buffers are created and owned by a MDataSource or MDataSink
       
   955 For clean-up purposes, datapath only cleans up buffers allocated directly by PrimeL().
       
   956 */
       
   957 void CMMFDataPath2::PrimeL()
       
   958 	{
       
   959 	CMMFDataPath::PrimeL();
       
   960 	if(iDataSink->DataSinkType() == KUidMmfAudioOutput)
       
   961 		{
       
   962 		CMMFAudioOutput* audioOutput = STATIC_CAST(CMMFAudioOutput*,iDataSink);
       
   963 		CMMFDevSound& devSound = audioOutput->SoundDevice();
       
   964 		iGetTimePlayedSupported = devSound.IsGetTimePlayedSupported();
       
   965 		iIsResumeSupported = devSound.IsResumeSupported();
       
   966 		iIsUsingResumeSupport = EFalse;
       
   967 		}
       
   968 	}
       
   969 
       
   970 /**
       
   971 Starts an active scheduler 'play' loop.
       
   972 
       
   973 Can only play from the primed state.
       
   974 */
       
   975 void CMMFDataPath2::PlayL()
       
   976 	{
       
   977 
       
   978 #if defined(__PROFILING)
       
   979 	RDebug::ProfileEnd(1);
       
   980 #endif  // defined(__PROFILING)
       
   981 
       
   982 #ifdef _DP_DEBUG
       
   983 	RDebug::Print(_L("DP::PlayL, on src buff %d  sink buf %d (this 0x%x)\n"), iCurrentSourceFrameNumber, iCurrentSinkFrameNumber,this);		
       
   984 	RDebug::Print(_L("iStartPosition = %d\n"), I64INT(iStartPosition.Int64()));		
       
   985 #endif
       
   986 
       
   987 	if ((iDataPathCreated) && (iState == EPrimed))
       
   988 		{
       
   989 		//can only play from the primed state
       
   990 
       
   991 		if(iPauseCalled) //sink and source will have been stopped, and we will not have been re-primed
       
   992 			{
       
   993 			iDataSink->SinkPrimeL(); //propagate change down to sink
       
   994 			iPauseCalled = EFalse;
       
   995 			}
       
   996 
       
   997 		iCurrentSourceFrameNumber = 0; //reset to beginning
       
   998 		iCurrentSinkFrameNumber = 0; //reset to beginning
       
   999 
       
  1000 		iSourceBufferWithSource = EFalse;
       
  1001 		iSinkBufferWithSink = EFalse;
       
  1002 
       
  1003 		iNoMoreSourceData = EFalse;
       
  1004 		iAllDataSentToSink=EFalse;
       
  1005 		iDataPathCompletedErrorCode=KErrNone;
       
  1006 
       
  1007 		if(!iIsResumeSupported || !iIsUsingResumeSupport)
       
  1008 			{
       
  1009 			SetPositionL( iStartPosition );
       
  1010 			}
       
  1011 		iReferenceAudioSamplesPlayed = 0;
       
  1012 		iReferenceAudioSamplesRecorded = 0;
       
  1013 		
       
  1014 		//complete a request on iStatus to invoke play code
       
  1015 		iDataSource->SourcePlayL(); //propagate state change to source
       
  1016 
       
  1017 		// This need to be done always since CMMFAudioOutput::EmptyBuffer
       
  1018 		// doesn't start playback anymore
       
  1019 		iDataSink->SinkPlayL(); //propogate state change to sink
       
  1020 
       
  1021 		if (iDataSink->DataSinkType() == KUidMmfAudioOutput)
       
  1022 			iState = EPlaying;
       
  1023 		else if(iDataSource->DataSourceType() == KUidMmfAudioInput)
       
  1024 			iState = ERecording;
       
  1025 		else
       
  1026 			iState = EConverting;
       
  1027 
       
  1028 		//need to re-initialize any buffer(s) that we only own references to
       
  1029 		ChangeDataPathTransferState(EInitializeSink);
       
  1030 		}
       
  1031 	iDevSoundRepositionTime = 0;
       
  1032 	if(!iRetainRepeatInfo)
       
  1033 		{
       
  1034 		iNumberOfTimesPlayed = 0;
       
  1035 		iTimeLeftToPlayComplete = -1;
       
  1036 		iVerifyPlayComplete = EFalse;
       
  1037 		}
       
  1038 	iRetainRepeatInfo = EFalse;
       
  1039 #ifdef _DP_DEBUG
       
  1040 	RDebug::Print(_L("DP::Play - DONE\n"));		
       
  1041 #endif
       
  1042 	}
       
  1043 
       
  1044 /**
       
  1045 Deletes buffers if this datapath's sources and sinks own the buffers returned by PrimeL().
       
  1046 Typically if buffers are created asychronously, the datapath doesn't own the buffer
       
  1047 so leaves cleanup handling to the owner sources/sinks.
       
  1048 
       
  1049 Called when source and sink needs to be de-referenced. Sets iDataPathCreated, iSinkCanReceive, 
       
  1050 iSnkBufRef and iSrcBufRef to EFalse; sets iState to EStopped.
       
  1051 */
       
  1052 void CMMFDataPath2::ResetL()
       
  1053 	{
       
  1054 	CMMFDataPath::ResetL();
       
  1055 	iDrmSource = NULL;
       
  1056 	}
       
  1057 
       
  1058 /**
       
  1059 Sets the number of times the audio sample is to be repeated during the
       
  1060 playback operation.
       
  1061 
       
  1062 A period of silence can follow each playing of the sample. The audio
       
  1063 sample can be repeated indefinitely.
       
  1064 
       
  1065 @param   aRepeatNumberOfTimes
       
  1066          The number of times the audio sample, together with
       
  1067          the trailing silence, is to be repeated. If this is
       
  1068          set to KMdaRepeatForever, then the audio
       
  1069          sample, together with the trailing silence, is
       
  1070          repeated indefinitely or until Stop() is
       
  1071          called. If this is set to zero, then the audio sample
       
  1072          is not repeated.
       
  1073 @param   aTrailingSilence
       
  1074          The time interval of the trailing silence in microseconds.
       
  1075 
       
  1076 */
       
  1077 EXPORT_C void CMMFDataPath2::SetRepeats(TInt aRepeatNumberOfTimes, const TTimeIntervalMicroSeconds& aTrailingSilence)
       
  1078 	{
       
  1079 	iNumberOfTimesToRepeat=aRepeatNumberOfTimes;
       
  1080 	iTrailingSilence=aTrailingSilence;
       
  1081 	}
       
  1082 	
       
  1083 /**
       
  1084 Sets the Drm file source and the automatic execute intent flag. This method is used by the controller plugin
       
  1085 to pass these to the datapath in order to execute the play intent during loop play.
       
  1086 
       
  1087 @param  aSource
       
  1088         Data Source on which the play intent needs to be executed. This is usually the CMMFFile source
       
  1089 @param  aDisableAutoIntent
       
  1090 		Boolean variable which states whether the controller plugin or the datapath needs to execute play intent
       
  1091 		automatically or not.
       
  1092 */	
       
  1093 EXPORT_C void CMMFDataPath2::SetDrmProperties(MDataSource* aSource, TBool *aDisableAutoIntent)
       
  1094 	{
       
  1095 	iDrmSource = aSource;
       
  1096 	iDisableAutoIntent = aDisableAutoIntent;
       
  1097 	}
       
  1098 
       
  1099 /**
       
  1100 This call indicates PlayL not to reset the iNumberOfTimesPlayed property. This method is used by the controller plugin
       
  1101 during repositioning. PlayL call during seeking should not reset the iNumberOfTimesPlayed property.
       
  1102 */
       
  1103 EXPORT_C void CMMFDataPath2::RetainRepeatInfo()
       
  1104 	{
       
  1105 	iRetainRepeatInfo = ETrue;
       
  1106 	}