mmlibs/mmfw/src/server/BaseClasses/mmfdatapath.cpp
changeset 0 b8ed18f6c07b
child 5 b220a9341636
equal deleted inserted replaced
-1:000000000000 0:b8ed18f6c07b
       
     1 // Copyright (c) 2002-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\mmfdatapath.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 <mmf/server/mmfdatapath.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 
       
    29 const TUid KUidCodecAudioConfig = {KUidMmfCodecAudioSettings};
       
    30 
       
    31 void Panic(TMMFDataPathPanicCode aPanicCode, TInt aSourceLineNumber)
       
    32 	{
       
    33 	_LIT(KMMFDataPathPanicCategory, "MMFDataPath");
       
    34 	User::Panic(KMMFDataPathPanicCategory, STATIC_CAST(TInt,aPanicCode) + aSourceLineNumber);
       
    35 	}
       
    36 
       
    37 //all functions are exported form the DLL and are virtual to allow plugins to define there own CMMFDataPaths
       
    38 
       
    39 /**
       
    40 Allocates and constructs a data path.
       
    41 
       
    42 Use this function if the codec UID is not already known by CMMFController
       
    43 and there is no data path ambiguity - ie only one data path is possible.
       
    44 
       
    45 Will create codec via fourCC.
       
    46 
       
    47 @param  aEventHandler
       
    48         Installs an event handler to provide message passing between clients and sources/sinks.
       
    49 
       
    50 @return Newly constructed data path object.
       
    51 */
       
    52 
       
    53 EXPORT_C CMMFDataPath* CMMFDataPath::NewL(MAsyncEventHandler& aEventHandler)
       
    54 	{
       
    55 	CMMFDataPath* self = new(ELeave) CMMFDataPath(TMediaId(), aEventHandler);
       
    56 	CleanupStack::PushL(self);
       
    57 	self->ConstructL();
       
    58 	CleanupStack::Pop();
       
    59 	return self;
       
    60 	}
       
    61 
       
    62 
       
    63 /**
       
    64 Allocates and constructs a data path according to the specified media ID.
       
    65 
       
    66 Use this function if the codec UID is not already known by CMMFController
       
    67 and there is ambiguity with the data path ie. there is more than one possible data path.
       
    68 
       
    69 @param  aMediaId
       
    70         Optional media ID parameter when there are multiple media types.
       
    71 @param  aEventHandler
       
    72         Installs an event handler to provide message passing between clients and sources/sinks.
       
    73 
       
    74 @return A newly constructed data path object.
       
    75 */
       
    76 
       
    77 EXPORT_C CMMFDataPath* CMMFDataPath::NewL(TMediaId aMediaId, MAsyncEventHandler& aEventHandler)
       
    78 	{
       
    79 	CMMFDataPath* self = new(ELeave) CMMFDataPath(aMediaId, aEventHandler);
       
    80 	CleanupStack::PushL(self);
       
    81 	self->ConstructL();
       
    82 	CleanupStack::Pop();
       
    83 	return self;
       
    84 	}
       
    85 
       
    86 /**
       
    87 Allocates and constructs a data path according to the specified codec UID.
       
    88 
       
    89 Use this function if the codec UID is already known by CMMFController
       
    90 and there is no data path ambiguity ie. only one data path is possible
       
    91 will create codec explicitly using the supplied codec Uid
       
    92 
       
    93 @param  aCodecUid
       
    94         Optional mediaID parameter when there are multiple media types
       
    95 @param  aEventHandler
       
    96         Installs an event handler to provide message passing between clients and sources/sinks.
       
    97 
       
    98 @return A newly constructed data path object.
       
    99 */
       
   100 
       
   101 EXPORT_C CMMFDataPath* CMMFDataPath::NewL(TUid aCodecUid, MAsyncEventHandler& aEventHandler)
       
   102 	{
       
   103 	CMMFDataPath* self = new(ELeave) CMMFDataPath(TMediaId(), aEventHandler);
       
   104 	CleanupStack::PushL(self);
       
   105 	self->ConstructL(aCodecUid);
       
   106 	CleanupStack::Pop();
       
   107 	return self;
       
   108 	}
       
   109 
       
   110 
       
   111 /**
       
   112 Allocates and constructs a data path according to the specified codec UID.
       
   113 
       
   114 Use this function if the codec UID is already known by CMMFController
       
   115 and there is ambiguity ie. more than one possible data path.
       
   116 TMediaId used to select the path.
       
   117 
       
   118 @param  aCodecUid
       
   119 		The codec UID.
       
   120 @param  aMediaId
       
   121         Optional mediaID parameter when there are multiple media types.
       
   122 @param  aEventHandler
       
   123         Installs an event handler to provide message passing between clients and sources/sinks.
       
   124 
       
   125 @return A newly constructed data path object.
       
   126 */
       
   127 EXPORT_C CMMFDataPath* CMMFDataPath::NewL(TUid aCodecUid, TMediaId aMediaId, MAsyncEventHandler& aEventHandler)
       
   128 	{
       
   129 	CMMFDataPath* self = new(ELeave) CMMFDataPath(aMediaId, aEventHandler);
       
   130 	CleanupStack::PushL(self);
       
   131 	self->ConstructL(aCodecUid);
       
   132 	CleanupStack::Pop();
       
   133 	return self;
       
   134 	}
       
   135 
       
   136 /**
       
   137 Standard destructor.
       
   138 */
       
   139 
       
   140 EXPORT_C CMMFDataPath::~CMMFDataPath()
       
   141 	{
       
   142 	Cancel();
       
   143 	delete iCodec;
       
   144  	DoCleanupBuffers();
       
   145 
       
   146 	//log off the source and sink
       
   147 	if (iDataSource)
       
   148 		iDataSource->SourceThreadLogoff();
       
   149 	if (iDataSink)
       
   150 		iDataSink->SinkThreadLogoff();
       
   151 
       
   152 	if (iCompleteCallback)
       
   153 		{
       
   154 		iCompleteCallback->Cancel();
       
   155 		delete iCompleteCallback;
       
   156 		}
       
   157 	}
       
   158 
       
   159 /**
       
   160 Deletes buffers if this datapath's sources and sinks own the buffers returned by PrimeL().
       
   161 Typically if buffers are created asychronously, the datapath doesn't own the buffer
       
   162 so leaves cleanup handling to the owner sources/sinks.
       
   163 
       
   164 Called when source and sink needs to be de-referenced. Sets iDataPathCreated, iSinkCanReceive, 
       
   165 iSnkBufRef and iSrcBufRef to EFalse; sets iState to EStopped.
       
   166 */
       
   167 EXPORT_C void CMMFDataPath::ResetL()
       
   168 	{
       
   169 	delete iCodec;
       
   170 	iCodec = NULL;
       
   171 	DoCleanupBuffers(); // Delete buffers
       
   172 	//logoff and dereference source and sink
       
   173 	if (iDataSource)
       
   174 		{ iDataSource->SourceThreadLogoff(); iDataSource = NULL; }
       
   175 	if (iDataSink)
       
   176 		{ iDataSink->SinkThreadLogoff(); iDataSink = NULL; }
       
   177 
       
   178 	// Reset states
       
   179 	iDataPathCreated = EFalse;
       
   180 	iState = EStopped;
       
   181 	iSrcBufRef = EFalse;
       
   182 	iSnkBufRef = EFalse;
       
   183 	iPauseCalled = EFalse;
       
   184 
       
   185 	delete iCompleteCallback; iCompleteCallback = NULL;
       
   186 	}
       
   187 
       
   188 /**
       
   189 Delete source and/or sink buffers that are owned by DataPath.
       
   190 
       
   191 Ownership indicated by iSrcBufRef and iSnkBufRef.
       
   192 
       
   193 Ownership is assigned during buffer allocation within the datapath PrimeL().
       
   194 */
       
   195 void CMMFDataPath::DoCleanupBuffers()
       
   196 	{
       
   197 	// delete source and/or sink buffer that is owned by DataPath
       
   198 	if ( !iSrcBufRef && iSourceBuffer )
       
   199 		{
       
   200 		delete iSourceBuffer;
       
   201 		}
       
   202 	iSourceBuffer = NULL;
       
   203 	if ( !iSnkBufRef && iSinkBuffer )
       
   204 		{
       
   205 		delete iSinkBuffer;
       
   206 		}
       
   207 	iSinkBuffer = NULL;
       
   208 	}
       
   209 
       
   210 
       
   211 /**
       
   212 Obtain source and/or sink buffer using the synchronous API CreateSourceBufferL() and CreateSinkBufferL().
       
   213 */
       
   214 void CMMFDataPath::ObtainSyncBuffersL()
       
   215 	{
       
   216 	//Try to create source and sink buffers. If we can't create them synchronously via
       
   217 	//CreateSourceBufferL and CreateSinkBufferL we will need to obtain them by 
       
   218 	//asynchronous buffer creation when playing starts.
       
   219 
       
   220 	if (iBuffersToUse & ENeedSourceBuffer)
       
   221 		{
       
   222 		if (!iSourceBuffer) //we may already have a buffer from a previous initialization
       
   223 			{
       
   224 			TRAPD(err, iSourceBuffer = iDataSource->CreateSourceBufferL(iMediaId,*iSinkBuffer, iSrcBufRef));
       
   225 			if(err != KErrNone && err != KErrNotSupported)
       
   226 				{
       
   227 #ifdef _DP_DEBUG
       
   228 	RDebug::Print(_L("DP::ObtainSyncBuffersL - Leaving %d  (this 0x%x)\n"),err, this);
       
   229 #endif
       
   230 				User::Leave(err);
       
   231 				}
       
   232 			}
       
   233 		}
       
   234 
       
   235 
       
   236 	if (iBuffersToUse & ENeedSinkBuffer)
       
   237 		{
       
   238 		if (!iSinkBuffer) //we may already have a buffer from a previous initialization
       
   239 			{
       
   240 			TRAPD(err, iSinkBuffer = iDataSink->CreateSinkBufferL(iMediaId, iSnkBufRef));
       
   241 			if(err != KErrNone && err != KErrNotSupported)
       
   242 				{
       
   243 #ifdef _DP_DEBUG
       
   244 	RDebug::Print(_L("DP::ObtainSyncBuffersL - Leaving %d  (this 0x%x)\n"),err, this);
       
   245 #endif
       
   246 				User::Leave(err);
       
   247 				}
       
   248 			}
       
   249 		}
       
   250 
       
   251 	if (iSourceBuffer && !(iBuffersToUse & ENeedSinkBuffer))
       
   252 		{//only need one buffer, use source
       
   253 		iSinkBuffer =iSourceBuffer;
       
   254 		iSnkBufRef = ETrue; //the sink buffer is not to be deleted
       
   255 		}
       
   256 	else if (iSinkBuffer && !(iBuffersToUse & ENeedSourceBuffer))
       
   257 		{//only need one buffer, use sink
       
   258 		iSourceBuffer =iSinkBuffer;
       
   259 		iSrcBufRef = ETrue; //the sink buffer is not to be deleted
       
   260 		}	
       
   261 
       
   262 #ifdef _DP_DEBUG
       
   263 	RDebug::Print(_L("DP::ObtainSyncBuffersL - DONE  iSourceBuffer=0x%x ref=%d   iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
       
   264 #endif
       
   265 	}
       
   266 
       
   267 
       
   268 
       
   269 
       
   270 
       
   271 /**
       
   272 Constructs a source.
       
   273 
       
   274 The default implementation leaves with KErrNotSupported.
       
   275 
       
   276 @param  aInitData
       
   277         The initialisation data.
       
   278 */
       
   279 
       
   280 EXPORT_C void CMMFDataPath::ConstructSourceL( const TDesC8& /*aInitData*/ )
       
   281 	{
       
   282 	User::Leave(KErrNotSupported);
       
   283 	}
       
   284 
       
   285 /**
       
   286 Constructs a sink.
       
   287 
       
   288 Overridable constuction specific to this datasource.
       
   289 
       
   290 The default implementation leaves with KErrNotSupported.
       
   291 
       
   292 @param  aInitData
       
   293         The initialisation data.
       
   294 */
       
   295 EXPORT_C void CMMFDataPath::ConstructSinkL( const TDesC8& /*aInitData*/ )
       
   296 	{
       
   297 	User::Leave(KErrNotSupported);
       
   298 	}
       
   299 
       
   300 /**
       
   301 Takes UID of codec on construction, and if not an NULL codec sets the datapath up for codec instantiation.
       
   302 
       
   303 @param  aCodecUid
       
   304         The UID of the codec.
       
   305 */
       
   306 
       
   307 EXPORT_C void CMMFDataPath::ConstructL(TUid aCodecUid)
       
   308 	{
       
   309 	iUseSuppliedCodecUid = EFalse; //initially assume no supplied codec uid
       
   310 
       
   311 	if (aCodecUid != KNullUid)
       
   312 		{//the data path NewL has specified a specific codec
       
   313 		//create CMMFCodec here
       
   314 		iCodec = CMMFCodec::NewL(aCodecUid);
       
   315 		if (iCodec)
       
   316 			iUseSuppliedCodecUid = ETrue;
       
   317 		}
       
   318 
       
   319 	iSrcBufRef = EFalse;
       
   320 	iSnkBufRef = EFalse;
       
   321 	iObtainingAsyncSourceBuffer = EFalse;
       
   322 	iObtainingAsyncSinkBuffer = EFalse;
       
   323 	iSourceBufferWithSource = EFalse;
       
   324 	iSinkBufferWithSink = EFalse;
       
   325 	}
       
   326 
       
   327 
       
   328 /** 
       
   329 Adds a data source to the datapath and, if the sink already exists, tries to establish a connection
       
   330 between the source and sink.
       
   331 
       
   332 @param  aSource
       
   333         The data source to add to the data path.
       
   334 */
       
   335 EXPORT_C void CMMFDataPath::AddDataSourceL(MDataSource* aSource)
       
   336 	{
       
   337 	if (!iDataSink) iDataSource=aSource; //can't create a data path without the MDataSink as well
       
   338 	else if (!iUseSuppliedCodecUid) //no supplied uid need to see if we can create codec to establish a data path
       
   339 		{//we have a data sink as well so check a data path can be established between source&sink
       
   340 		CreateDataPathL(aSource, iDataSink);
       
   341 		iDataSource = aSource;
       
   342 		}
       
   343 	else //the CMMFController specified the codec uid so must use existing codec
       
   344 		{//note we are assuming here that the CMMFController knows what it is doing ie the supplied codec uid 
       
   345 		//can make the appropriate data conversion
       
   346 		iDataPathCreated = ETrue;
       
   347 		iDataSource = aSource;
       
   348 		}
       
   349 	ClearPlayWindowL() ;
       
   350 	User::LeaveIfError(iDataSource->SourceThreadLogon(*this));
       
   351 	}
       
   352 
       
   353 
       
   354 /** 
       
   355 Adds a data sink to the datapath and, if the source already exists, tries to establish a connection
       
   356 between the source and sink.
       
   357 
       
   358 @param  aSink
       
   359         The data sink to add to the data path.
       
   360 */
       
   361 
       
   362 EXPORT_C void CMMFDataPath::AddDataSinkL(MDataSink* aSink)
       
   363 	{
       
   364 	if (!iDataSource) iDataSink=aSink; //can't create a data path without the MDataSource as well
       
   365 	else if (!iUseSuppliedCodecUid) //no supplied uid need to see if we can create codec to establish a data path
       
   366 		{//we have a data source as well so check a media path can be established between source&sink
       
   367 		CreateDataPathL(iDataSource, aSink);
       
   368 		iDataSink = aSink;
       
   369 		}
       
   370 	else //the CMMFController specified the codec uid so must use existing codec
       
   371 		{//note we are assuming here that the CMMFController knows what it is doing ie the supplied codec uid 
       
   372 		//can make the appropriate data conversion
       
   373 		iDataPathCreated = ETrue;
       
   374 		iDataSink = aSink;	
       
   375 		
       
   376 		//set 4CCs
       
   377 		iSourceFourCC  = iDataSink->SinkDataTypeCode(iMediaId);//sink because CMMFDataPath is an MDataSink to its MDataSource!
       
   378 		iSinkFourCC = iDataSource->SourceDataTypeCode(iMediaId);//source because CMMFDataPath is an MDataSource to its MDataSink!
       
   379 		}
       
   380 	User::LeaveIfError(iDataSink->SinkThreadLogon(*this));
       
   381 	}
       
   382 
       
   383 
       
   384 /* 
       
   385  *  CreateDataPathL 
       
   386  * 
       
   387  *  internal function to establish a datapath between the source and sink
       
   388  *	the data supplied by the sink adn expected by the source are checked and 
       
   389  *	a codec is instantiated if necessary
       
   390  *
       
   391  *	@param	aSource
       
   392  *	@param	aSink
       
   393  */
       
   394 
       
   395 void CMMFDataPath::CreateDataPathL(MDataSource* aSource, MDataSink* aSink)
       
   396 	{ //procedure to attempt to match the source to the sink creating a codec if necessary
       
   397 	// returns ETrue if the datapath could be constructed else false
       
   398 	//sets iCodec to the appropriate codec.& sets its own iSink/iSource FourCC datatype codes
       
   399 	iDataPathCreated = EFalse;
       
   400 	if (aSource && aSink) //have a source and sink
       
   401 		{ //we have a data source & sink but no codec so try and find one - if required
       
   402 		TFourCC sourceFourCCCode = aSource->SourceDataTypeCode(iMediaId); //get MDataSource data type fourCC code
       
   403 		TFourCC sinkFourCCCode = aSink->SinkDataTypeCode(iMediaId); //get MDataSink data type fourCC code
       
   404 		if ((sourceFourCCCode != sinkFourCCCode) && //MDataSource & MDataSink datatypes are not compatible
       
   405 			(sourceFourCCCode != KMMFFourCCCodeNULL) && (sinkFourCCCode != KMMFFourCCCodeNULL)) 
       
   406 			{//we need a codec to make the conversion between the source and the sink
       
   407 			CMMFCodec* codec = CMMFCodec::NewL(sourceFourCCCode, sinkFourCCCode);
       
   408 
       
   409 			if (codec)
       
   410 				{
       
   411 				delete iCodec;
       
   412 				iCodec = codec;
       
   413 				//data path created ie have source/sink and can match their datatypes
       
   414 				iDataPathCreated = ETrue;
       
   415 
       
   416 				//now we have an source attached we need to configure the codec for sample rate
       
   417 				//and number of channels
       
   418 
       
   419 				//prepare a package to send to a codec
       
   420 				TMMFAudioConfig audioSettings;
       
   421 				
       
   422 				//test for decoder
       
   423 				if (aSource->DataSourceType() == KUidMmfFormatDecode)
       
   424 					{
       
   425 					audioSettings.iSampleRate = static_cast<CMMFFormatDecode*>(aSource)->SampleRate();
       
   426 					audioSettings.iChannels = static_cast<CMMFFormatDecode*>(aSource)->NumChannels();
       
   427 					}
       
   428 
       
   429 				//package up to send to codec
       
   430 				TPckgBuf<TMMFAudioConfig> configPackage(audioSettings);
       
   431 
       
   432 				//we need to catch User::Leave(KErrNotSupported) as by default most codecs
       
   433 				//do not support the ConfigureL method.
       
   434 				TRAPD(err,iCodec->ConfigureL(KUidCodecAudioConfig, configPackage));
       
   435 				// need to check other error here
       
   436 				if (err != KErrNone && err != KErrNotSupported)
       
   437 					{
       
   438 					User::Leave(err);
       
   439 					}
       
   440 				}
       
   441 			else
       
   442 				{
       
   443 				User::Leave( KErrNotSupported ) ; //couldn't find suitable codec
       
   444 				}
       
   445 			} //if (sourceFourCCCode != sinkFourCCCode)
       
   446 		else 
       
   447 			{ //source & sink fourCC datatypes are the same so no codec is required
       
   448 			__ASSERT_DEBUG(iCodec == NULL,  Panic(EMMFDataPathPanicProgrammingError,__LINE__)); 			
       
   449 
       
   450 			iDataPathCreated = ETrue;
       
   451 			}
       
   452 		//can assign FourCC codes for the CMMFDataPath
       
   453 		iSinkFourCC = sourceFourCCCode; //sink because CMMFDataPath is an MDataSink to its MDataSource!
       
   454 		iSourceFourCC = sinkFourCCCode; //source because CMMFDataPath is an MDataSource to its MDataSink!
       
   455 		//If sink & source need its own Prime() done in controller	
       
   456 		} 
       
   457 	}
       
   458 
       
   459 /**
       
   460 Clears the specified buffer.
       
   461 
       
   462 Pure virtual dummy implementation, not needed by datapath
       
   463 comes from MDataSink - CMMFData path is a sink to its MDataSource.
       
   464 
       
   465 This is only required for an active push MDataSource requesting a buffer empty.
       
   466 
       
   467 @param  aBuffer
       
   468         The buffer to empty.
       
   469 @param  aSupplier
       
   470         The MDataSource supplying this buffer.
       
   471 @param  aMediaId
       
   472         An optional mediaID parameter when there are multiple buffers arriving of different media types.
       
   473 
       
   474 */
       
   475 EXPORT_C void CMMFDataPath::EmptyBufferL(CMMFBuffer* /* aBuffer */, MDataSource* /*aSupplier*/, TMediaId /*aMediaId*/)
       
   476 	{
       
   477 	//not implemented
       
   478 	}
       
   479 
       
   480 
       
   481 
       
   482 /* 
       
   483  *  FillSourceBufferL
       
   484  * 
       
   485  *	Function to get data from the datapath's iDataSource
       
   486  */
       
   487 
       
   488 void CMMFDataPath::FillSourceBufferL()
       
   489 	{
       
   490 #ifdef _DP_DEBUG
       
   491 	RDebug::Print(_L("DP::FillSourceBufferL tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
   492 #endif
       
   493 
       
   494 	__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__)); 
       
   495 
       
   496 
       
   497 	// clear the no-more-source flag here (as well as in PlayL()) because 
       
   498 	// there may have been a re-position since the last call to BufferFilledL()
       
   499 	iNoMoreSourceData = EFalse;
       
   500 
       
   501 	if(!iObtainingAsyncSourceBuffer) 
       
   502 		{//this is a normal request for data. 
       
   503 		//If we are getting asynchronous buffers, then can't do this as iSourceBuffer == NULL
       
   504 		iSourceBuffer->SetFrameNumber(++iCurrentSourceFrameNumber); //so source knows which data to load buffer with
       
   505 		iSourceBuffer->SetStatus(EBeingFilled);
       
   506 		iSourceBuffer->SetLastBuffer(EFalse);
       
   507 		}
       
   508 
       
   509 #ifdef _DP_DEBUG
       
   510 	RDebug::Print(_L("DP asking for buffer %d  - ptr=0x%x   (this 0x%x)\n"), iCurrentSourceFrameNumber, iSourceBuffer,this);	
       
   511 #endif
       
   512 
       
   513 	iSourceBufferWithSource = ETrue;
       
   514 
       
   515 	// wait for BufferFilled callback from source. Do this here as some sources cause
       
   516 	//re-entrancy into data path via BufferFilledL
       
   517 	ChangeDataPathTransferState(EWaitSource);  
       
   518 
       
   519 	iDataSource->FillBufferL(iSourceBuffer, this, iMediaId);
       
   520 
       
   521 #ifdef _DP_DEBUG
       
   522 	RDebug::Print(_L("DP::FillSourceBufferL - DONE tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
   523 #endif
       
   524 	}
       
   525 
       
   526 
       
   527 /** 
       
   528 Indicates the data source has filled the specified buffer.
       
   529 
       
   530 Called by the CMMFDataPath's MDataSource when it has filled the buffer.
       
   531 
       
   532 @param aBuffer
       
   533        A pointer to the filled buffer.
       
   534 */
       
   535 EXPORT_C void CMMFDataPath::BufferFilledL(CMMFBuffer* aBuffer)
       
   536 	{	
       
   537 #ifdef _DP_DEBUG
       
   538 	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);
       
   539 #endif
       
   540 	
       
   541 	//This assertion is commented because of PDEF117405
       
   542 	//state only used if we are passing data
       
   543 	//__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__));
       
   544 
       
   545 	__ASSERT_DEBUG((!iNoMoreSourceData), Panic(EMMFDataPathPanicBadState,__LINE__)); 
       
   546 		
       
   547 	iSourceBufferWithSource = EFalse;
       
   548 
       
   549 	//Has the datapath stopped running, if so were not interested in any callbacks.
       
   550 	if(iState == EStopped || iState == EPrimed || (iPauseCalled && iState != ERecording))
       
   551 		{
       
   552 #ifdef _DP_DEBUG
       
   553 		RDebug::Print(_L("DP::BufferFilledL called while not expecting callback iState=%d  iPauseCalled=%d  (this 0x%x)\n"),iState, iPauseCalled,this);
       
   554 #endif
       
   555 		return;
       
   556 		}
       
   557 
       
   558 #ifdef REPOSITION_SPEEDUP
       
   559 	// if the source has been re-positioned, then go & get some more source data now
       
   560 	if (!iObtainingAsyncSourceBuffer && iSourceBuffer->FrameNumber() != iCurrentSourceFrameNumber)
       
   561 		{
       
   562 #ifdef _DP_DEBUG
       
   563 		RDebug::Print(_L("DP::BufferFilledL source was re-positioned re-requesting source data (this 0x%x)\n"),this);
       
   564 #endif
       
   565 		ChangeDataPathTransferState(ENeedSourceData);
       
   566 		return;
       
   567 		}
       
   568 #endif //REPOSITION_SPEEDUP
       
   569 
       
   570 	//bufer is NULL, indicating no more source data.
       
   571 	if (!aBuffer)
       
   572 		{
       
   573 		//If we only hold a reference to the source buffer, set that to NULL
       
   574 		if(iSnkBufRef)
       
   575 			iSourceBuffer = NULL;
       
   576 
       
   577 
       
   578 		iNoMoreSourceData = ETrue;
       
   579 
       
   580 		if(!iCodec || //there's only one buffer and that has been returned as NULL, so must be end of data
       
   581 		  iSinkBufferWithSink) //buffer is with sink, we don't have any more data to put in it, so must be end of data
       
   582 			{
       
   583 			ChangeDataPathTransferState(EEndOfData);
       
   584 			}
       
   585 		else //sink buffer is with datapath, see if there is anything to send to sink
       
   586 			ChangeDataPathTransferState(ENeedToMatchSourceToSink);
       
   587 
       
   588 #ifdef _DP_DEBUG
       
   589 		RDebug::Print(_L("DP::BufferFilledL DONE aBuffer==NULL tick-%d (this 0x%x)\n"),User::TickCount(),this);
       
   590 #endif
       
   591 		return;
       
   592 		} 
       
   593 
       
   594 	
       
   595 	//We were waiting for a response from the source to get an asynchronous buffer.
       
   596 	//We now have it, and we proceed to transfer this data to the sink.
       
   597 	if	(iObtainingAsyncSourceBuffer)
       
   598 		{
       
   599 		iObtainingAsyncSourceBuffer = EFalse;
       
   600 		}
       
   601 	
       
   602 
       
   603 	aBuffer->SetStatus(EFull);
       
   604 
       
   605 	if(iSourceBuffer != aBuffer)
       
   606 		{//buffer has been changed by the source
       
   607 		iSourceBuffer = aBuffer;
       
   608 		if (!(iBuffersToUse & ENeedSinkBuffer))
       
   609 			{//we only need one buffer and use source
       
   610 			iSinkBuffer = iSourceBuffer;
       
   611 			iSnkBufRef = ETrue;
       
   612 			}
       
   613 #ifdef _DP_DEBUG
       
   614 	RDebug::Print(_L("DP::BufferFilledL - iSourceBuffer=0x%x ref=%d   iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
       
   615 #endif	
       
   616 		}
       
   617 	//Is this the last buffer from the source (0 length or LastBuffer flag set)
       
   618 	//or have reached the end of the play window; we only look at the play window here
       
   619 	//if we are converting. For conversion we look at the data we have read. This is then passed onto 
       
   620 	//the source
       
   621 	if (!iSourceBuffer->BufferSize() || iSourceBuffer->LastBuffer() ||
       
   622 		(((iState == EConverting) || (iState == EPlaying)) && (iPlayWindowEndPosition < iCachedSourceDuration) && ( InputPosition() >= iPlayWindowEndPosition ))) 
       
   623 		{
       
   624 #ifdef _DP_DEBUG
       
   625 		RDebug::Print(_L("DP::BufferFilledL end of input data  tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
   626 		RDebug::Print(_L("iSourceBuffer->BufferSize()=%d\n"),iSourceBuffer->BufferSize());
       
   627 		RDebug::Print(_L("iSourceBuffer->LastBuffer()=%d\n"),iSourceBuffer->LastBuffer());
       
   628 		RDebug::Print(_L("InputPosition()=%d  >= iPlayWindowEndPosition=%d\n"),I64INT(InputPosition().Int64()),I64INT(iPlayWindowEndPosition.Int64()));
       
   629 #endif
       
   630 		iNoMoreSourceData = ETrue;
       
   631 		iSourceBuffer->SetLastBuffer(ETrue); //just in-case we are terminating on BufferSize == 0 or play window
       
   632 		}
       
   633 
       
   634 
       
   635 	if (!iCodec)
       
   636 		ChangeDataPathTransferState(ESendDataToSink);
       
   637 	else if(!iSinkBufferWithSink) //sink buffer is with data path, can try to fill it
       
   638 		ChangeDataPathTransferState(ENeedToMatchSourceToSink);
       
   639 	//else wait for sink to return buffer BufferEmptied will send us into ENeedToMatchSourceToSink state
       
   640 
       
   641 #ifdef _DP_DEBUG
       
   642 	RDebug::Print(_L("DP::BufferFilledL - DONE tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
   643 #endif
       
   644 	}
       
   645 
       
   646 
       
   647 
       
   648 
       
   649 /* 
       
   650  *  FillSinkBufferL
       
   651  * 
       
   652  *	Function to take the data from an already full source buffer and by using
       
   653  *	a codec if necessary fills the sink buffer
       
   654  */
       
   655 
       
   656 void CMMFDataPath::FillSinkBufferL()
       
   657 	{
       
   658 #ifdef _DP_DEBUG
       
   659 	RDebug::Print(_L("DP::FillSinkBufferL tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
   660 #endif
       
   661 
       
   662 	//This state is only used if we are passing data
       
   663 	__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__)); 
       
   664 
       
   665 	//This state is only used if we have a real codec
       
   666 	__ASSERT_DEBUG(iCodec, Panic(EMMFDataPathPanicBadState,__LINE__)); 
       
   667 
       
   668 
       
   669 	//The sink buffer is with the sink so we can't fill it.
       
   670 	//When it has been emptied, this state will be re-entered from BufferEmptiedL
       
   671 	if(iSinkBufferWithSink)
       
   672 		{
       
   673 #ifdef _DP_DEBUG
       
   674 		RDebug::Print(_L("DP::FillSinkBufferL buffer is in use by SINK - DONE   (this 0x%x)\n"),this);
       
   675 #endif
       
   676 		ChangeDataPathTransferState(EWaitSink);  // wait for BufferEmptied callback from sink
       
   677 		return;
       
   678 		}
       
   679 
       
   680 	//The source buffer is with the source so we can't take data from it.
       
   681 	//When it has been filled, this state will be re-entered from BufferFilledL
       
   682 	if(iSourceBufferWithSource)
       
   683 		{
       
   684 #ifdef _DP_DEBUG
       
   685 		RDebug::Print(_L("DP::FillSinkBufferL buffer is in use by SOURCE - DONE   (this 0x%x)\n"),this);
       
   686 #endif
       
   687 		ChangeDataPathTransferState(EWaitSource);  // wait for BufferFilled callback from source
       
   688 		return;
       
   689 		}
       
   690 
       
   691 	//source buffer is NULL, can't be any more data to send.
       
   692 	//iNoMoreSourceData is set and the source buffer is empty, can't be any more data to send.
       
   693 	if(!iSourceBuffer || (iNoMoreSourceData && !iSourceBuffer->BufferSize()))
       
   694 		{
       
   695 		if(iSinkBuffer->Status() == EBeingFilled)
       
   696 			{//if we have data in sink buffer, mark it as last buffer and send
       
   697 			iSinkBuffer->SetLastBuffer(ETrue);
       
   698 			ChangeDataPathTransferState(ESendDataToSink);
       
   699 			}
       
   700 		else //the sink buffer can't have anything in it
       
   701 			ChangeDataPathTransferState(EEndOfData);
       
   702 		}
       
   703 
       
   704 #ifdef REPOSITION_SPEEDUP
       
   705 	// if the source has been re-positioned, 
       
   706 	// speed things up by getting some more source data now
       
   707 	if(iSourceBuffer && iSourceBuffer->FrameNumber() != iCurrentSourceFrameNumber)
       
   708 		{
       
   709 #ifdef _DP_DEBUG
       
   710 		RDebug::Print(_L("DP::FillSinkBufferL() source was re-positioned re-requesting source data (this 0x%x)\n"),this);
       
   711 #endif
       
   712 		ChangeDataPathTransferState(ENeedSourceData);
       
   713 		return;
       
   714 		}
       
   715 #endif //REPOSITION_SPEEDUP
       
   716 
       
   717 	iSinkBuffer->SetStatus(EBeingFilled);
       
   718 	iSinkBuffer->SetLastBuffer(EFalse);
       
   719 
       
   720 	//pass buffer to codec for processing
       
   721 	iCodecProcessResult = iCodec->ProcessL(*iSourceBuffer, *iSinkBuffer);
       
   722 	//the codec tries to fill the sink buffer to its max length
       
   723 	//TCodecProcessResult returns the status of the codec Process -
       
   724 	//this can result in result conditions such as:
       
   725 	//EProcessComplete - the codec processed all the source data into the sink buffer
       
   726 	//EProcessIncomplete - the codec filled sink buffer before all the source buffer was processed
       
   727 	//EDstNotFilled - the codec processed the source buffer but the sink buffer was not filled
       
   728 	//EEndOfData - the codec detected the end data - all source data in processed but sink may not be full
       
   729 	//EProcessError - the codec process error condition
       
   730 
       
   731 	
       
   732 	switch (iCodecProcessResult.iStatus)
       
   733 		{
       
   734 	case TCodecProcessResult::EProcessComplete:
       
   735 	//finished procesing source data - all data in sink buffer
       
   736 		{
       
   737 #ifdef _DP_DEBUG
       
   738 		RDebug::Print(_L("CMMFDataPath::FillSinkBufferL codec EProcessComplete   (this 0x%x)\n"),this);
       
   739 #endif
       
   740 		iSourceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
       
   741 		iSinkBuffer->SetStatus(EFull);	//sink buffer is full	
       
   742 		if (iNoMoreSourceData) 
       
   743 			iSinkBuffer->SetLastBuffer(ETrue);
       
   744 		ChangeDataPathTransferState(ESendDataToSink);// the full sink buffer needs to be sent to the sink 
       
   745 		}
       
   746 	break;
       
   747 	case TCodecProcessResult::EProcessIncomplete:
       
   748 		// the sink was filled before all the src was processed 
       
   749 		// therefore still send everything to sink 
       
   750 		//but datapath needs to carry on processing the source buffer before it gets more source data
       
   751 		//when sink has emptied data path needs to send rest of data
       
   752 		{
       
   753 #ifdef _DP_DEBUG
       
   754 		RDebug::Print(_L("CMMFDataPath::FillSinkBufferL codec EProcessIncomplete   (this 0x%x)\n"),this);
       
   755 #endif
       
   756 		TUint sourceBufferPosition = iCodecProcessResult.iSrcBytesProcessed + iSourceBuffer->Position();
       
   757 		iSourceBuffer->SetPosition(sourceBufferPosition);//update source buffer position
       
   758 		iSinkBuffer->SetStatus(EFull); //sink & source buffers are both full
       
   759 		ChangeDataPathTransferState(ESendDataToSink); // the full sink buffer needs to be sent to the sink 
       
   760 		}
       
   761 	break;
       
   762 	case TCodecProcessResult::EDstNotFilled:
       
   763 		// the destination is not full 
       
   764 		{
       
   765 #ifdef _DP_DEBUG
       
   766 		RDebug::Print(_L("CMMFDataPath::FillSinkBufferL codec EDstNotFilled   (this 0x%x)\n"),this);
       
   767 #endif
       
   768 		iSourceBuffer->SetStatus(EAvailable); //source buffer is now available
       
   769 		TUint sinkBufferPosition = iCodecProcessResult.iDstBytesAdded + iSinkBuffer->Position();
       
   770 		iSinkBuffer->SetPosition(sinkBufferPosition);//update sink  buffer position (still EBeingFilled)
       
   771 		// if this was the last source buffer, send what we've got (if anything) 
       
   772 		// to the sink... EmptySinkBuffer() should then enter EEndOfData state
       
   773 		if (iNoMoreSourceData)
       
   774 			{
       
   775 			iSinkBuffer->SetLastBuffer(ETrue);
       
   776 			ChangeDataPathTransferState(ESendDataToSink);//send what we've got to the sink - 
       
   777 			}
       
   778 		else
       
   779 			{
       
   780 			ChangeDataPathTransferState(ENeedSourceData); //need to get more source data to fill sink buffer
       
   781 			}
       
   782 		}
       
   783 	break;	
       
   784 	case TCodecProcessResult::EEndOfData:
       
   785 		//no more data - send what we've got to the sink
       
   786 		//note we can't always rely on this  - in many cases the codec will not know when
       
   787 		//it has reached the end of data.
       
   788 		{
       
   789 #ifdef _DP_DEBUG
       
   790 		RDebug::Print(_L("CMMFDataPath::FillSinkBufferL codec EEndOfData   (this 0x%x)\n"),this);
       
   791 #endif
       
   792 		iSourceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
       
   793 		iSinkBuffer->SetStatus(EFull);//sink buffer may not really be 'full' but its as full as it going to get
       
   794 
       
   795 		//This only occurs where the codec can detect the end of data, but the source can't
       
   796 		iNoMoreSourceData=ETrue;
       
   797 		iSinkBuffer->SetLastBuffer(ETrue); 
       
   798 
       
   799 		ChangeDataPathTransferState(ESendDataToSink);//send what we've got to the sink - 
       
   800 		//doesn't matter if sink buffer is not full
       
   801 		}
       
   802 	break;
       
   803 	case TCodecProcessResult::EProcessError:
       
   804 #ifdef _DP_DEBUG
       
   805 		RDebug::Print(_L("DP::FillSinkBufferL tick-%d  DONE %d   (this 0x%x)\n"),User::TickCount(), __LINE__,this);
       
   806 #endif
       
   807 		User::Leave(KErrCorrupt); //codec process error
       
   808 	break;
       
   809 	default:
       
   810 #ifdef _DP_DEBUG
       
   811 		RDebug::Print(_L("DP::FillSinkBufferL tick-%d  DONE %d   (this 0x%x)\n"),User::TickCount(), __LINE__,this);
       
   812 #endif
       
   813 		User::Leave(KErrCorrupt); //should never get here
       
   814 		}
       
   815 #ifdef _DP_DEBUG
       
   816 	RDebug::Print(_L("DP::FillSinkBufferL - done  tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
   817 #endif
       
   818 	}
       
   819 
       
   820 
       
   821 
       
   822 /**
       
   823 Tests whether the data path can create a sink buffer.
       
   824 
       
   825 The default implementation returns false.
       
   826 
       
   827 @return ETrue if the data path can create a sink buffer. EFalse if the data path cannot create a sink buffer.
       
   828 */
       
   829 EXPORT_C TBool CMMFDataPath::CanCreateSinkBuffer()
       
   830 	{
       
   831 	return NULL; //CMMFDataPath cannot create buffer
       
   832 	}
       
   833 
       
   834 /**
       
   835 Creates a sink buffer according to the specifed media ID.
       
   836 
       
   837 Intended for synchronous usage (buffers supplied by datapath for an MDataSink).
       
   838 This method is essentially a dummy implementation of an MDataSink pure virtual.
       
   839 
       
   840 The default implementation returns NULL.
       
   841 
       
   842 @param  aMediaId
       
   843         An optional mediaID parameter when there are multiple buffers arriving of different media types.
       
   844 
       
   845 @return Returns NULL in this instance as datapath can't create sink buffers
       
   846 */
       
   847 EXPORT_C CMMFBuffer* CMMFDataPath::CreateSinkBufferL(TMediaId /*aMediaId*/)
       
   848 	{//CMMFDataPath can't create buffers
       
   849 	return NULL;
       
   850 	}
       
   851 
       
   852 /**
       
   853 Creates a sink buffer according to the specifed media ID and reference.
       
   854 
       
   855 Intended for asynchronous usage (buffers supplied by Devsound device).
       
   856 This method is essentially a dummy implementation of an MDataSink pure virtual.
       
   857 
       
   858 The default implementation returns NULL.
       
   859 
       
   860 @param  aMediaId
       
   861         An optional mediaID parameter when there are multiple buffers arriving for different media types.
       
   862 @param  aReference
       
   863         A boolean indicating buffer ownership.
       
   864 
       
   865 @return	Returns NULL in this instance as datapath can't create sink buffers.
       
   866 */
       
   867 EXPORT_C CMMFBuffer* CMMFDataPath::CreateSinkBufferL(TMediaId /*aMediaId*/, TBool& /*aReference*/)
       
   868 	{//CMMFDataPath can't create buffers
       
   869 	return NULL;
       
   870 	}
       
   871 
       
   872 /**
       
   873 Gets the sink's data type for the specified media ID.
       
   874 
       
   875 @param  aMediaId
       
   876         An optional parameter to specifiy the specific stream when datasource contains more than one stream of data
       
   877 @return The sink's data type.
       
   878 */
       
   879 EXPORT_C TFourCC CMMFDataPath::SinkDataTypeCode(TMediaId /*aMediaId*/)
       
   880 	{
       
   881 	return(iSinkFourCC);
       
   882 	}
       
   883 
       
   884 /**
       
   885 Fills the specified buffer.
       
   886 
       
   887 Pure virtual dummy implementation, not needed by datapath
       
   888 comes from MDataSink - CMMFData path is a source to its MDataSink
       
   889 
       
   890 Only required for an active pull MDataSink requesting a buffer fill. The default implementation is empty.
       
   891 
       
   892 @param  aBuffer
       
   893         The buffer to fill.
       
   894 @param  aConsumer
       
   895         The MDataSink supplying this buffer.
       
   896 @param  aMediaId
       
   897         An optional mediaID parameter when there are multiple buffers arriving of different media types
       
   898 */
       
   899 EXPORT_C void CMMFDataPath::FillBufferL(CMMFBuffer* /*aBuffer*/, MDataSink* /*aConsumer*/, TMediaId /*aMediaId*/)
       
   900 	{
       
   901 	//not implementated
       
   902 	}
       
   903 
       
   904 void CMMFDataPath::SetBuffersAvailable()
       
   905 	{
       
   906 	// set source buffer to be available
       
   907   	if (iSourceBuffer)
       
   908   		iSourceBuffer->SetStatus(EAvailable);
       
   909 	// set sink buffer to be available
       
   910   	if (iSinkBuffer)
       
   911   		iSinkBuffer->SetStatus(EAvailable);
       
   912 	}
       
   913 
       
   914 void CMMFDataPath::ResetRefBuffers()
       
   915 	{
       
   916 #ifdef _DP_DEBUG
       
   917 	RDebug::Print(_L("DP::ResetRefBuffers iSourceBuffer=0x%x ref=%d   iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
       
   918 #endif
       
   919 
       
   920 	// Reset the buffer pointers to NULL if they are supplied by DevSound
       
   921 	// We do this because buffers that are not owned by the datapath may not be valid any more.
       
   922 	if (iSrcBufRef)
       
   923 		{
       
   924 		iSourceBuffer = NULL;
       
   925 		}
       
   926 	if (iSnkBufRef)
       
   927 		{
       
   928 		iSinkBuffer = NULL;
       
   929 		}
       
   930 	}
       
   931 
       
   932 
       
   933 
       
   934 
       
   935 TInt CMMFDataPath::DetermineBuffersToUseL(void) const
       
   936 	{
       
   937 	TInt buffs = ENoBuffers;
       
   938 	if(iCodec)
       
   939 		{//Using a real Codec, need both sets of buffers
       
   940 		if(!iDataSink->CanCreateSinkBuffer() || ! iDataSource->CanCreateSourceBuffer())
       
   941 			User::Leave(KErrNotSupported);
       
   942 
       
   943 		buffs = CMMFDataPath::ENeedSinkBuffer | CMMFDataPath::ENeedSourceBuffer;	
       
   944 		}
       
   945 	else //we are using a Null Codec, only need one buffer, but which one?
       
   946 		{//use buffer from DevSound, if no DevSound (ie, clip to clip), prefer source buffer.
       
   947 		//If preferring source but it can't create buffers, use sink.
       
   948 		if ((iDataSink->DataSinkType() == KUidMmfAudioOutput) && (iDataSink->CanCreateSinkBuffer()))
       
   949 			buffs = ENeedSinkBuffer;
       
   950 		else if(iDataSource->CanCreateSourceBuffer())
       
   951 			buffs = ENeedSourceBuffer;
       
   952 		else if(iDataSink->CanCreateSinkBuffer())
       
   953 			buffs = ENeedSinkBuffer;
       
   954 		else
       
   955 			User::Leave(KErrNotSupported);
       
   956 		}
       
   957 	return buffs;
       
   958 	}
       
   959 
       
   960 
       
   961 
       
   962 /*
       
   963  *  InitializeSinkL
       
   964  *
       
   965  *	Function to initialize iDataSink before it can start sending data
       
   966  *	This is a one time prime. This will synchronize DataPath's data driving
       
   967  *	mechanism with HwDevice implementation.
       
   968  *
       
   969  *  This initialisation method detects its attached sources and sinks and makes adjustments to the state machine
       
   970  *  This avoid the possibility of NULL buffers (not yet returned by an asychronous sink or source) being passed around the MMF
       
   971  */
       
   972 
       
   973 void CMMFDataPath::InitializeSinkL()
       
   974 	{
       
   975 #ifdef _DP_DEBUG
       
   976 	RDebug::Print(_L("DP::InitializeSinkL  iSourceBuffer=0x%x ref=%d   iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
       
   977 #endif
       
   978 
       
   979 	//state only used if we are passing data
       
   980 	__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__));
       
   981 
       
   982 	iObtainingAsyncSinkBuffer = EFalse;
       
   983 
       
   984 	if (iBuffersToUse & ENeedSinkBuffer)
       
   985 		{
       
   986 		//Buffers are initially created in the Prime method. But following a pause, we must re-create 
       
   987 		//any referenced buffers, so try direct creation.
       
   988 		//NB: this does mean we are trying this twice, Prime and here
       
   989 		if (!iSinkBuffer) //we may already have a buffer from a previous initialization
       
   990 			{
       
   991 			TRAPD(err, iSinkBuffer = iDataSink->CreateSinkBufferL(iMediaId, iSnkBufRef));
       
   992 			if(err != KErrNone && err != KErrNotSupported)
       
   993 				User::Leave(err);
       
   994 			}
       
   995 
       
   996 
       
   997 		//If buffer has not been supplied via CreateSinkBufferL, 
       
   998 		//must use asynchronous buffer creation		
       
   999 		if (!iSinkBuffer) 
       
  1000 			{
       
  1001 			iObtainingAsyncSinkBuffer = ETrue;
       
  1002 			ChangeDataPathTransferState(EWaitSink);  // wait for BufferEmptied callback from sink
       
  1003 			iDataSink->EmptyBufferL(iSinkBuffer, this, iMediaId);
       
  1004 			}
       
  1005 		else
       
  1006 			{
       
  1007 			//we have a sink buffer from CreateSinkBufferL
       
  1008 			iSinkBuffer->SetStatus(EAvailable);
       
  1009 			
       
  1010 			if (iBuffersToUse & ENeedSourceBuffer)
       
  1011 				{//need a source buffer, go get it
       
  1012 				ChangeDataPathTransferState(EInitializeSource);
       
  1013 				}
       
  1014 			else
       
  1015 				{//only need one buffer, use sink
       
  1016 				iSourceBuffer = iSinkBuffer;
       
  1017 				iSrcBufRef = ETrue; //the src buffer is not to be deleted
       
  1018 
       
  1019 				ChangeDataPathTransferState(ENeedSourceData); //got all buffers, start getting data
       
  1020 				}
       
  1021 			}
       
  1022 		}
       
  1023 	else
       
  1024 		{//don't need a sink buffer, but we need a source one
       
  1025 		ChangeDataPathTransferState(EInitializeSource);
       
  1026 		}
       
  1027 
       
  1028 #ifdef _DP_DEBUG
       
  1029 	RDebug::Print(_L("DP::InitializeSinkL - DONE  iSourceBuffer=0x%x ref=%d   iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
       
  1030 #endif	
       
  1031 	}
       
  1032 
       
  1033 
       
  1034 /*
       
  1035  *  InitializeSourceL
       
  1036  *
       
  1037  *	Function to initialize iDataSource before it can start sending data
       
  1038  *	This is a one time prime. This will synchronize DataPath's data driving
       
  1039  *	mechanism with HwDevice implementation.
       
  1040  *
       
  1041  *  This initialisation method detects its attached sources and sinks and makes adjustments to the state machine
       
  1042  *  This avoid the possibility of NULL buffers (not yet returned by an asychronous sink or source) being passed around the MMF
       
  1043  */
       
  1044 
       
  1045 void CMMFDataPath::InitializeSourceL()
       
  1046 	{
       
  1047 #ifdef _DP_DEBUG
       
  1048 	RDebug::Print(_L("DP::InitializeSourceL -  iSourceBuffer=0x%x ref=%d   iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
       
  1049 #endif	
       
  1050 
       
  1051 	//state only used if we are passing data
       
  1052 	__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__));
       
  1053 
       
  1054 	iObtainingAsyncSourceBuffer = EFalse;
       
  1055 
       
  1056 	if (iBuffersToUse & ENeedSourceBuffer)
       
  1057 		{
       
  1058 		//Buffers are initially created in the Prime method. But following a pause, we must re-create 
       
  1059 		//any referenced buffers, so try direct creation.
       
  1060 		//NB: this does mean we are trying this twice, Prime and here.
       
  1061 		if (!iSourceBuffer) //we may already have a buffer from a previous initialization
       
  1062 			{
       
  1063 			TRAPD(err, iSourceBuffer = iDataSource->CreateSourceBufferL(iMediaId,*iSinkBuffer, iSrcBufRef));
       
  1064 			if(err != KErrNone && err != KErrNotSupported)
       
  1065 				User::Leave(err);
       
  1066 			}
       
  1067 
       
  1068 
       
  1069 		//If buffer has not been supplied via CreateSourceBufferL
       
  1070 		//must use asynchronous buffer creation
       
  1071 		if (!iSourceBuffer) 
       
  1072 			{
       
  1073 			iObtainingAsyncSourceBuffer = ETrue;
       
  1074 			ChangeDataPathTransferState(ENeedSourceData);			
       
  1075 			}
       
  1076 		else
       
  1077 			{//we have a source buffer from CreateSourceBufferL
       
  1078 			iSourceBuffer->SetStatus(EAvailable);
       
  1079 
       
  1080 			if (!(iBuffersToUse & ENeedSinkBuffer))
       
  1081 				{//only need one buffer, use sink
       
  1082 				iSinkBuffer = iSourceBuffer;
       
  1083 				iSnkBufRef = ETrue;
       
  1084 				}
       
  1085 
       
  1086 			ChangeDataPathTransferState(ENeedSourceData); //got all buffers, start getting data			
       
  1087 			}
       
  1088 		}
       
  1089 	else
       
  1090 		{//don't need a source buffer, use sinks
       
  1091 		if(iSinkBuffer)
       
  1092 			{
       
  1093 			iSourceBuffer = iSinkBuffer;
       
  1094 			iSrcBufRef = iSnkBufRef;
       
  1095 			SetBuffersAvailable();
       
  1096 			}
       
  1097 #ifdef _DP_DEBUG
       
  1098 		else
       
  1099 			Panic(EMMFDataPathPanicProgrammingError,__LINE__);
       
  1100 #endif
       
  1101 		ChangeDataPathTransferState(ENeedSourceData); //got all buffers, start getting data
       
  1102 
       
  1103 		
       
  1104 #ifdef _DP_DEBUG
       
  1105 	RDebug::Print(_L("DP::InitializeSourceL -  iSourceBuffer=0x%x ref=%d   iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
       
  1106 #endif			
       
  1107 		}
       
  1108 	}
       
  1109 
       
  1110 /*
       
  1111  *  EmptySinkBufferL
       
  1112  * 
       
  1113  *	Function to pass a full databuffer to the iDataSink
       
  1114  */
       
  1115 void CMMFDataPath::EmptySinkBufferL()
       
  1116 	{
       
  1117 #ifdef _DP_DEBUG
       
  1118 	RDebug::Print(_L("DP::EmptySinkBufferL pass data to sink  tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  1119 	if(iSinkBuffer)
       
  1120 		RDebug::Print(_L("iSinkBuffer %d contains %d bytes  eof = %d line %d   (this 0x%x)\n"),iSinkBuffer->FrameNumber(), iSinkBuffer->BufferSize(),iSinkBuffer->LastBuffer(),__LINE__,this);		
       
  1121 #endif
       
  1122 
       
  1123 	//Before emptying the sink buffer we need to check it has data to empty - this
       
  1124 	//may not be the case if there is no more data ie iNoMoreSourceData is true.
       
  1125 	//In this case we need to check to see if there is any data left in the sink 
       
  1126 	//buffer, ie the sink buffer is either full or being filled. If there is not any
       
  1127 	//data in the sink buffer, ie it is not in the state of EBeingFilled or EFull
       
  1128 	//then there is nothing to empty so the datapath state is set to EEndOfData and
       
  1129 	//we return from the procedure.
       
  1130 
       
  1131 	//state only used if we are passing data
       
  1132 	__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording || (iState == EPrimed && iPauseCalled)), Panic(EMMFDataPathPanicBadState,__LINE__)); 
       
  1133 	__ASSERT_DEBUG(iSinkBuffer &&
       
  1134 				   ((iSinkBuffer->Status()==EBeingFilled) || (iSinkBuffer->Status()==EFull)),
       
  1135 				   Panic(EMMFDataPathPanicProgrammingError,__LINE__)); 
       
  1136 
       
  1137 	__ASSERT_DEBUG(iSinkBufferWithSink == EFalse, Panic(EMMFDataPathPanicBadState,__LINE__)); 
       
  1138 
       
  1139 
       
  1140 	//Due to sinks that may call BuferEmptied directly (ie. re-entrancy onto DataPath) we
       
  1141 	//must work out next state here. If re-entrancy, the next state may validly get overwritten 
       
  1142 	// in BuferEmptied.
       
  1143 	if(iObtainingAsyncSinkBuffer) //wait for buffer to be returned in BufferEmptied
       
  1144 		{
       
  1145 		ChangeDataPathTransferState(EWaitSink);  // wait for BufferEmptied callback from sink
       
  1146 		}
       
  1147 
       
  1148 #ifdef REPOSITION_SPEEDUP
       
  1149 	// if the source has been re-positioned, 
       
  1150 	// speed things up by getting some more source data now
       
  1151 	if(iSourceBuffer && iSourceBuffer->FrameNumber() != iCurrentSourceFrameNumber)
       
  1152 		{
       
  1153 #ifdef _DP_DEBUG
       
  1154 		RDebug::Print(_L("DP::EmptySinkBufferL() source was re-positioned re-requesting source data (this 0x%x)\n"),this);
       
  1155 #endif
       
  1156 		ChangeDataPathTransferState(ENeedSourceData);
       
  1157 		return;
       
  1158 		}
       
  1159 #endif //REPOSITION_SPEEDUP
       
  1160 
       
  1161 	//We have sent data to sink, if we are using a real Codec, we can now get more data from source
       
  1162 	//if there is any more to get and the codec has emptied it.
       
  1163 	//NB: No need to check we own the source buffer as we will no be in this state
       
  1164 	//if we have asked for more source data and haven't received it.
       
  1165 	else if (iCodec && !iNoMoreSourceData && (iSourceBuffer->Status() == EAvailable))
       
  1166 		{
       
  1167 #ifdef _DP_DEBUG
       
  1168 		RDebug::Print(_L("ASKING for more source data iCodec = 0x%x  iNoMoreSourceData=%d  iSourceBufferWithSource = %d   (this 0x%x)\n"), iCodec, iNoMoreSourceData, iSourceBufferWithSource,this);
       
  1169 #endif
       
  1170 		ChangeDataPathTransferState(ENeedSourceData);
       
  1171 		}
       
  1172 	else
       
  1173 		{
       
  1174 #ifdef _DP_DEBUG
       
  1175 		RDebug::Print(_L("Not asking for any more source data iCodec = 0x%x  iNoMoreSourceData=%d  iSourceBufferWithSource = %d   iSourceBuffer->Status=%d   (this 0x%x)\n"), iCodec, iNoMoreSourceData, iSourceBufferWithSource ,iSourceBuffer->Status(), this);
       
  1176 #endif
       
  1177 
       
  1178 		//if this is the last buffer, set this flag so we can deal with KErrUnderflow 
       
  1179 		//as a valid termination of playing
       
  1180 		if(iSinkBuffer->LastBuffer())
       
  1181 			iAllDataSentToSink=ETrue;
       
  1182 
       
  1183 		ChangeDataPathTransferState(EWaitSink);  // wait for BufferEmptied callback from sink
       
  1184 		}
       
  1185 
       
  1186 
       
  1187 	if(!iObtainingAsyncSinkBuffer) //normal data transfer
       
  1188 		iSinkBuffer->SetFrameNumber(++iCurrentSinkFrameNumber);
       
  1189 
       
  1190 #ifdef _DP_DEBUG
       
  1191 	RDebug::Print(_L("DP sending buffer %d ptr=0x%x of %d bytes to sink   (this 0x%x)\n"), iSinkBuffer->FrameNumber(),iSinkBuffer,iSinkBuffer->BufferSize(),this);
       
  1192 #endif
       
  1193 	
       
  1194 	iSinkBufferWithSink = ETrue;
       
  1195 	TRAPD(error, iDataSink->EmptyBufferL(iSinkBuffer, this, iMediaId));
       
  1196 
       
  1197 	// Check that we haven't exceeded the maximum clip length - if so, go to the EndOfData state
       
  1198 	// so we perform necessary cleanup.
       
  1199 	if (error == KErrEof || error == KErrOverflow || error == KErrUnderflow)
       
  1200 		{
       
  1201 #ifdef _DP_DEBUG
       
  1202 		RDebug::Print(_L("DP::EmptySinkBufferL DONE %d error = %d  tick-%d   (this 0x%x)\n"),__LINE__, error, User::TickCount(),this);
       
  1203 #endif
       
  1204 		iDataPathCompletedErrorCode = error;
       
  1205 		ChangeDataPathTransferState(EEndOfData);
       
  1206 		return;
       
  1207 		}
       
  1208 	User::LeaveIfError(error);
       
  1209 
       
  1210 #ifdef _DP_DEBUG
       
  1211 	RDebug::Print(_L("DP::EmptySinkBufferL - done  tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  1212 #endif
       
  1213 	}
       
  1214 
       
  1215 
       
  1216 /** 
       
  1217 Indicates the data sink has emptied the buffer.
       
  1218 
       
  1219 Called by the CMMFDataPath's MDataSink when it has emptied the buffer
       
  1220 
       
  1221 @param  aBuffer
       
  1222 		The emptied buffer.
       
  1223 */
       
  1224 EXPORT_C void CMMFDataPath::BufferEmptiedL(CMMFBuffer* aBuffer)
       
  1225 	{
       
  1226 #ifdef _DP_DEBUG
       
  1227 	TInt bufNum = 9999;
       
  1228 	if(aBuffer)
       
  1229 		bufNum = aBuffer->FrameNumber();
       
  1230 	else
       
  1231 		RDebug::Print(_L("DP::BufferEmptiedL returned NULL   (this 0x%x)\n"),this);
       
  1232 
       
  1233 	RDebug::Print(_L("DP::BufferEmptiedL sink has taken buffer %d (ptr=0x%x) bytes %d eof= %d   iNoMoreSourceData = %d tick-%d   (this 0x%x)\n"),
       
  1234 		bufNum, aBuffer, aBuffer->BufferSize(),aBuffer->LastBuffer(), iNoMoreSourceData, User::TickCount(),this);
       
  1235 #endif
       
  1236 
       
  1237 	iSinkBufferWithSink = EFalse;
       
  1238 
       
  1239     //Has the datapath stopped running, if so were not interested in any callbacks.
       
  1240     if(iState == EStopped || (iState == EPrimed && !iPauseCalled))
       
  1241         {
       
  1242 #ifdef _DP_DEBUG
       
  1243 		RDebug::Print(_L("DP::BufferEmptiedL called while not expecting callback iState=%d  iPauseCalled=%d  (this 0x%x)\n"),iState, iPauseCalled,this);
       
  1244 #endif
       
  1245 		return;
       
  1246 		}
       
  1247 
       
  1248 
       
  1249 	// This will allow MDataSink to send dynamic buffer to DataPath with each BufferEmptiedL request.
       
  1250 	if (iSinkBuffer != aBuffer) //buffer has been updated
       
  1251 		{
       
  1252 		iSinkBuffer = aBuffer;
       
  1253 		if (!(iBuffersToUse & ENeedSourceBuffer))
       
  1254 			{ //can use a single buffer
       
  1255 			iSourceBuffer = iSinkBuffer;
       
  1256 			iSrcBufRef = iSnkBufRef;
       
  1257 			}
       
  1258 
       
  1259 		}
       
  1260 
       
  1261 	iSinkBuffer->SetStatus(EAvailable);
       
  1262 	
       
  1263 	if (iObtainingAsyncSinkBuffer) //we are creating an asynchronous sink buffer
       
  1264 		{
       
  1265 		iObtainingAsyncSinkBuffer = EFalse;
       
  1266 
       
  1267 		//we have a sink buffer, should this also be used by the source
       
  1268 		if (!(iBuffersToUse & ENeedSourceBuffer))
       
  1269 			{//using a single buffer, so start getting data
       
  1270 			iSourceBuffer = iSinkBuffer;
       
  1271 			iSrcBufRef = iSnkBufRef;
       
  1272 
       
  1273 			ChangeDataPathTransferState(ENeedSourceData);
       
  1274 			}
       
  1275 		else //obtain a separate source buffer
       
  1276 			ChangeDataPathTransferState(EInitializeSource);
       
  1277 
       
  1278 #ifdef _DP_DEBUG
       
  1279 	RDebug::Print(_L("DP::BufferEmptiedL - DONE iSourceBuffer=0x%x ref=%d   iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
       
  1280 #endif	
       
  1281 		return;
       
  1282 		}
       
  1283 
       
  1284 	if(!iCodec) //No Codec in use
       
  1285 		{
       
  1286 		if(iNoMoreSourceData)
       
  1287 			ChangeDataPathTransferState(EEndOfData);//final buffer returned from sink
       
  1288 		else
       
  1289 			ChangeDataPathTransferState(ENeedSourceData);//get more data from source
       
  1290 		}
       
  1291 	else //real codecs
       
  1292 		{
       
  1293 		//There is more source data and src buffer is being filled or we are about to go into 
       
  1294 		// ENeedSourceData state to fill it, so wait for source data to arrive.
       
  1295 		//NB:if there was more source data and we are using a real codec and source buffer was empty,
       
  1296 		//more source data would have been requested in EmptySinkBuffer
       
  1297 		if(!iNoMoreSourceData && (iSourceBufferWithSource || iTransferState == ENeedSourceData))
       
  1298 			{
       
  1299 #ifdef _DP_DEBUG
       
  1300 			RDebug::Print(_L("DP::BufferEmptiedL - waiting for more source data - DONE tick-%d line %d   (this 0x%x)\n"),User::TickCount(),__LINE__,this);
       
  1301 #endif
       
  1302 			return;
       
  1303 			}
       
  1304 
       
  1305 		//source has supplied a NULL buffer or it has been emptied; no more data to send.
       
  1306 		if(!iSourceBuffer || (iSourceBuffer->Status() == EAvailable))
       
  1307 			ChangeDataPathTransferState(EEndOfData);
       
  1308 		else if(iSourceBuffer->Status() == EFull) //there is data in the source buffer, go and get it
       
  1309 			ChangeDataPathTransferState(ENeedToMatchSourceToSink);
       
  1310 
       
  1311 #ifdef _DP_DEBUG
       
  1312 		else
       
  1313 			Panic(EMMFDataPathPanicProgrammingError,__LINE__);
       
  1314 #endif
       
  1315 		}
       
  1316 
       
  1317 
       
  1318 #ifdef _DP_DEBUG
       
  1319 	RDebug::Print(_L("DP::BufferEmptiedL - DONE  tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  1320 #endif
       
  1321 	}
       
  1322 
       
  1323 
       
  1324 
       
  1325 /**
       
  1326 Tests whether the data path can create a source buffer.
       
  1327 
       
  1328 Would expect datapath to always return NULL, so this is a default implementation of a pure virtual from MDataSink.
       
  1329 
       
  1330 The default implementation returns EFalse.
       
  1331 
       
  1332 @return ETrue if the data path can create a source buffer. EFalse if the data path cannot create a source buffer.
       
  1333 */
       
  1334 EXPORT_C TBool CMMFDataPath::CanCreateSourceBuffer() //from both MDataSource & MDataSink?
       
  1335 	{
       
  1336 	return EFalse; //CMMFDataPath cannot create buffer
       
  1337 	}
       
  1338 
       
  1339 /**
       
  1340 Creates a source buffer.
       
  1341 
       
  1342 Intended for synchronous usage (buffers supplied by datapath for a MDataSource)
       
  1343 This method is essentially a dummy implementation of an MDataSource pure virtual.
       
  1344 
       
  1345 The default implementation leaves with KErrNotSupported and returns NULL.
       
  1346 
       
  1347 @param  aMediaId
       
  1348         An optional mediaID parameter when there are multiple buffers arriving of different media types.
       
  1349 @return A pointer to a newly created buffer. Returns NULL in this instance as datapath can't create source buffers
       
  1350 */
       
  1351 EXPORT_C CMMFBuffer* CMMFDataPath::CreateSourceBufferL(TMediaId /*aMediaId*/) //CMMFDataPath can't create buffers
       
  1352 	{
       
  1353 	User::Leave(KErrNotSupported);
       
  1354 	return NULL;
       
  1355 	}
       
  1356 
       
  1357 /**
       
  1358 Creates a source buffer according to the specifed media ID and reference.
       
  1359 
       
  1360 Intended for asynchronous usage (buffers supplied by datapath for a MDataSource)
       
  1361 This method is essentially a dummy implementation of an MDataSource pure virtual.
       
  1362 
       
  1363 The default implementation leaves with KErrNotSupported and returns NULL.
       
  1364 
       
  1365 @param  aMediaId
       
  1366         An optional mediaID parameter when there are multiple buffers arriving of different media types.
       
  1367 @param  aReference
       
  1368         A boolean indicating buffer ownership. ETrue if the MDataSource owns the buffer, EFalse if the caller owns the buffer.
       
  1369 
       
  1370 @return A pointer to a newly created buffer. Returns NULL in this instance as datapath can't create source buffers.
       
  1371 */
       
  1372 EXPORT_C CMMFBuffer* CMMFDataPath::CreateSourceBufferL(TMediaId /*aMediaId*/, TBool& /*aReference*/) //CMMFDataPath can't create buffers
       
  1373 	{
       
  1374 	User::Leave(KErrNotSupported);
       
  1375 	return NULL;
       
  1376 	}
       
  1377 
       
  1378 
       
  1379 /**
       
  1380 Gets the source data type for the specified media ID.
       
  1381 
       
  1382 @param  aMediaId
       
  1383         An optional parameter to specifiy specific stream when datasource contains more than one stream of data.
       
  1384 
       
  1385 @return The source data type.
       
  1386 */
       
  1387 EXPORT_C TFourCC CMMFDataPath::SourceDataTypeCode(TMediaId /*aMediaId*/)
       
  1388 	{
       
  1389 	return(iSourceFourCC);
       
  1390 	}
       
  1391 
       
  1392 
       
  1393 /**
       
  1394 Allocates buffers in preparation to play.
       
  1395 
       
  1396 Must be called before calling PlayL().
       
  1397 
       
  1398 iSnkBufRef and iSrcBufRef contain ETrue if these buffers are created and owned by a MDataSource or MDataSink
       
  1399 For clean-up purposes, datapath only cleans up buffers allocated directly by PrimeL().
       
  1400 */
       
  1401 
       
  1402 EXPORT_C void CMMFDataPath::PrimeL()
       
  1403 	{
       
  1404 #ifdef _DP_DEBUG
       
  1405 	RDebug::Print(_L("DP::PrimeL  tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  1406 #endif
       
  1407 	
       
  1408 	//allocate resources ie buffers & prepare to play
       
  1409 	if (iDataPathCreated && (iState == EStopped))
       
  1410 		//luckily the client utility does this.
       
  1411 		{//can only prime from the stopped state
       
  1412 		
       
  1413 		//This will determine what buffers we need to run the datapath.
       
  1414 		//Can leave KERRNotSupported
       
  1415 		iBuffersToUse = DetermineBuffersToUseL();
       
  1416 
       
  1417 		//Try to create source and sink buffers. If we can't create them in the Prime, 
       
  1418 		//we will need to obtain them by asynchronous buffer creation when playing starts.
       
  1419 		ObtainSyncBuffersL();
       
  1420 
       
  1421 		iDataSource->SourcePrimeL(); //propogate state change to source
       
  1422 		iDataSink->SinkPrimeL(); //propogate state change to sink
       
  1423 
       
  1424 
       
  1425 		//If Client has set these, they will be set following the prime
       
  1426 		iPlayWindowStartPosition = 0;
       
  1427 		iPlayWindowEndPosition = Duration();
       
  1428 
       
  1429 		iState = EPrimed;	
       
  1430 		iPauseCalled = EFalse;
       
  1431 
       
  1432 		if (iCompleteCallback)
       
  1433 			{
       
  1434 			delete iCompleteCallback;
       
  1435 			iCompleteCallback = NULL;
       
  1436 			}
       
  1437 		TBool waitForSink = (iDataSink->DataSinkType() == KUidMmfAudioOutput)?ETrue:EFalse;
       
  1438 		iCompleteCallback = new (ELeave) CCompleteCallback(*this,waitForSink);
       
  1439 		}		
       
  1440 #ifdef _DP_DEBUG
       
  1441 	RDebug::Print(_L("DP::PrimeL  Done  tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  1442 #endif
       
  1443 	}
       
  1444 
       
  1445 
       
  1446 /**
       
  1447 Starts an active scheduler 'play' loop.
       
  1448 
       
  1449 Can only play from the primed state.
       
  1450 */
       
  1451 EXPORT_C void CMMFDataPath::PlayL()
       
  1452 	{
       
  1453 #if defined(__PROFILING)
       
  1454 	RDebug::ProfileEnd(1);
       
  1455 #endif  // defined(__PROFILING)
       
  1456 
       
  1457 #ifdef _DP_DEBUG
       
  1458 	RDebug::Print(_L("DP::PlayL, on src buff %d  sink buf %d (this 0x%x)\n"), iCurrentSourceFrameNumber, iCurrentSinkFrameNumber,this);		
       
  1459 	RDebug::Print(_L("iStartPosition = %d\n"), I64INT(iStartPosition.Int64()));		
       
  1460 #endif
       
  1461 
       
  1462 	if ((iDataPathCreated) && (iState == EPrimed))
       
  1463 		{
       
  1464 		//can only play from the primed state
       
  1465 
       
  1466 		TBool savedPauseCalled=EFalse;
       
  1467 		if(iPauseCalled) //sink and source will have been stopped, and we will not have been re-primed
       
  1468 			{
       
  1469 			savedPauseCalled=ETrue;
       
  1470 			iDataSink->SinkPrimeL(); //propagate change down to sink
       
  1471 			iPauseCalled = EFalse;
       
  1472 			}
       
  1473 
       
  1474 		iCurrentSourceFrameNumber = 0; //reset to beginning
       
  1475 		iCurrentSinkFrameNumber = 0; //reset to beginning
       
  1476 
       
  1477 		iSourceBufferWithSource = EFalse;
       
  1478 		iSinkBufferWithSink = EFalse;
       
  1479 
       
  1480 		iNoMoreSourceData = EFalse;
       
  1481 		iAllDataSentToSink=EFalse;
       
  1482 		iDataPathCompletedErrorCode=KErrNone;
       
  1483 
       
  1484 		SetPositionL( iStartPosition ) ;
       
  1485 		iReferenceAudioSamplesPlayed = 0;
       
  1486 		iReferenceAudioSamplesRecorded = 0;
       
  1487 
       
  1488 		//complete a request on iStatus to invoke play code
       
  1489 		iDataSource->SourcePlayL(); //propagate state change to source
       
  1490 		if (!(savedPauseCalled && (iTransferState==EWaitSink || iTransferState==EInitializeSink)))
       
  1491 			{
       
  1492 			iDataSink->SinkPlayL(); //propogate state change to sink
       
  1493 			}
       
  1494 
       
  1495 		if (iDataSink->DataSinkType() == KUidMmfAudioOutput)
       
  1496 			iState = EPlaying;
       
  1497 		else if(iDataSource->DataSourceType() == KUidMmfAudioInput)
       
  1498 			iState = ERecording;
       
  1499 		else
       
  1500 			iState = EConverting;
       
  1501 
       
  1502 		//need to re-initialize any buffer(s) that we only own references to
       
  1503 		ChangeDataPathTransferState(EInitializeSink);
       
  1504 		}
       
  1505 #ifdef _DP_DEBUG
       
  1506 	RDebug::Print(_L("DP::Play - DONE\n"));		
       
  1507 #endif
       
  1508 	}
       
  1509 
       
  1510 
       
  1511 /** 
       
  1512 Pauses playing.
       
  1513 
       
  1514 Sends KMMFErrorCategoryDataPathGeneralError to the client if an error occurs.
       
  1515 */
       
  1516 EXPORT_C void CMMFDataPath::Pause()
       
  1517 	{
       
  1518 #ifdef _DP_DEBUG
       
  1519 	RDebug::Print(_L("DP::Pause, on src buff %d  sink buf %d   (this 0x%x)\n"), iCurrentSourceFrameNumber, iCurrentSinkFrameNumber,this);			
       
  1520 	RDebug::Print(_L("DP::Pause current state=%d  tick-%d    (this 0x%x)\n"),iTransferState, User::TickCount(),this);
       
  1521 #endif
       
  1522 
       
  1523 	TRAPD(err, DoPauseL());
       
  1524 	
       
  1525 	if (err)
       
  1526 		{
       
  1527 		DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
       
  1528 		}
       
  1529 #ifdef _DP_DEBUG
       
  1530 	RDebug::Print(_L("DP::Pause - DONE tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  1531 #endif
       
  1532 	}
       
  1533 
       
  1534 /** 
       
  1535 Stops playing.
       
  1536 
       
  1537 Resets datapath position - currently does not clean up buffers. Sends KMMFErrorCategoryDataPathGeneralError 
       
  1538 to the client if an error occurs.
       
  1539 */
       
  1540 EXPORT_C void CMMFDataPath::Stop()
       
  1541 	{ 
       
  1542 #ifdef _DP_DEBUG
       
  1543 	RDebug::Print(_L("DP::Stop current state=%d  tick-%d   (this 0x%x)\n"), iTransferState, User::TickCount(),this);
       
  1544 #endif
       
  1545 
       
  1546 	if ((iDataPathCreated)  && (iState != EStopped))
       
  1547 		{ 
       
  1548 		TRAPD(err, DoStopL());
       
  1549 		
       
  1550 		if (err)
       
  1551 			DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
       
  1552 		}
       
  1553 	}
       
  1554 /**
       
  1555 Forces and end of data state on the datapath
       
  1556 */
       
  1557 EXPORT_C void CMMFDataPath::EndOfData()
       
  1558 	{
       
  1559 	TRAPD(err, DoEndOfDataL());
       
  1560 	
       
  1561 	if (err)
       
  1562 		{
       
  1563 		DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
       
  1564 		}
       
  1565 	}
       
  1566 
       
  1567 /**
       
  1568 
       
  1569 */
       
  1570 TInt CMMFDataPath::AudioSamplesPlayed() const
       
  1571 	{
       
  1572 	if (iDataSink->DataSinkType() != KUidMmfAudioOutput)
       
  1573 		return 0;
       
  1574 
       
  1575 	CMMFAudioOutput* audioOutput = STATIC_CAST(CMMFAudioOutput*,iDataSink);
       
  1576 
       
  1577 	TInt samples = 0;
       
  1578 
       
  1579 	if(iState == EPlaying)
       
  1580 		samples = audioOutput->SoundDevice().SamplesPlayed();
       
  1581 
       
  1582 #ifdef _DP_DEBUG
       
  1583 	RDebug::Print(_L("DP::AudioSamplesPlayed = %d\n"),samples);
       
  1584 #endif
       
  1585 
       
  1586 	return samples;
       
  1587 	}
       
  1588 
       
  1589 
       
  1590 /** 
       
  1591 
       
  1592 */
       
  1593 TInt CMMFDataPath::AudioSamplesRecorded() const
       
  1594 	{
       
  1595 	if (iDataSource->DataSourceType() != KUidMmfAudioInput)
       
  1596 		return 0;
       
  1597 
       
  1598 	CMMFAudioInput* audioInput = STATIC_CAST(CMMFAudioInput*,iDataSource);
       
  1599 
       
  1600 	TInt samples = 0;
       
  1601 
       
  1602 	if(iState == ERecording)
       
  1603 		samples = audioInput->SoundDevice().SamplesRecorded();
       
  1604 
       
  1605 #ifdef _DP_DEBUG
       
  1606 	RDebug::Print(_L("DP::AudioSamplesRecorded = %d\n"),samples);
       
  1607 #endif
       
  1608 
       
  1609 	return samples;
       
  1610 	}
       
  1611 
       
  1612 
       
  1613 /**
       
  1614 
       
  1615 */
       
  1616 TTimeIntervalMicroSeconds CMMFDataPath::CalculateAudioOutputPosition() const
       
  1617     {
       
  1618 	//This operation can only be carried out on an Audio Output
       
  1619 	__ASSERT_ALWAYS(iDataSink->DataSinkType() == KUidMmfAudioOutput, Panic(EMMFDataPathPanicProgrammingError,__LINE__));
       
  1620 
       
  1621 
       
  1622 	//If we are not playing, simply return where we will play from
       
  1623 	if(iState != EPlaying || iCurrentSinkFrameNumber == 0)
       
  1624 		return iStartPosition;
       
  1625 
       
  1626 #ifdef _DP_DEBUG
       
  1627 	RDebug::Print(_L("DP::CalculateAudioOutputDuration from %d\n"),iReferenceAudioSamplesPlayed);
       
  1628 #endif
       
  1629 
       
  1630 	TReal samplesPlayed = AudioSamplesPlayed() - iReferenceAudioSamplesPlayed;
       
  1631 
       
  1632 	CMMFAudioOutput* audioOutput = STATIC_CAST(CMMFAudioOutput*,iDataSink);
       
  1633 	CMMFDevSound& devSound = audioOutput->SoundDevice();
       
  1634 
       
  1635 	TMMFCapabilities devSoundConfig = devSound.Config();
       
  1636 		
       
  1637 	TInt samplingFreq = StreamUtils::SampleRateAsValue(devSoundConfig);
       
  1638 
       
  1639 #ifdef _DP_DEBUG
       
  1640 	RDebug::Print(_L("samplingFreq %d\n"),samplingFreq);
       
  1641 #endif
       
  1642 
       
  1643 	TReal timePlayedSeconds = 0;
       
  1644 	if(samplesPlayed)
       
  1645 		timePlayedSeconds = samplesPlayed/samplingFreq;
       
  1646 
       
  1647 	TInt64 timePlayed(I64DOUBLECAST(timePlayedSeconds * 1000000));
       
  1648 
       
  1649 #ifdef _DP_DEBUG
       
  1650 	RDebug::Print(_L("timePlayed %d\n"), I64LOW(timePlayed));
       
  1651 #endif
       
  1652 
       
  1653 	return TTimeIntervalMicroSeconds(timePlayed + iStartPosition.Int64());
       
  1654     }
       
  1655 
       
  1656 
       
  1657 
       
  1658 /**
       
  1659 
       
  1660 */
       
  1661 TTimeIntervalMicroSeconds CMMFDataPath::CalculateAudioInputPosition() const
       
  1662     {
       
  1663 	//This operation can only be carried out on an Audio Input
       
  1664 	__ASSERT_ALWAYS(iDataSource->DataSourceType() == KUidMmfAudioInput, Panic(EMMFDataPathPanicProgrammingError,__LINE__));
       
  1665 
       
  1666 
       
  1667 	//If we are not playing, simply return where we will play from
       
  1668 	if(iState != ERecording)
       
  1669 		return iStartPosition;
       
  1670 
       
  1671 #ifdef _DP_DEBUG
       
  1672 	RDebug::Print(_L("DP::CalculateAudioInputPosition from %d\n"),iReferenceAudioSamplesRecorded);
       
  1673 #endif
       
  1674 
       
  1675 	TReal samplesRecorded = AudioSamplesRecorded() - iReferenceAudioSamplesRecorded;
       
  1676 
       
  1677 	CMMFAudioInput* audioInput = STATIC_CAST(CMMFAudioInput*,iDataSource);
       
  1678 	CMMFDevSound& devSound = audioInput->SoundDevice();
       
  1679 
       
  1680 	TMMFCapabilities devSoundConfig = devSound.Config();
       
  1681 		
       
  1682 	TInt samplingFreq = StreamUtils::SampleRateAsValue(devSoundConfig);
       
  1683 
       
  1684 #ifdef _DP_DEBUG
       
  1685 	RDebug::Print(_L("samplingFreq %d\n"),samplingFreq);
       
  1686 #endif
       
  1687 
       
  1688 	TReal timeRecordedSeconds = 0;
       
  1689 	if(samplesRecorded)
       
  1690 		timeRecordedSeconds = samplesRecorded/samplingFreq;
       
  1691 
       
  1692 	TInt64 timeRecorded(I64DOUBLECAST(timeRecordedSeconds * 1000000));
       
  1693 
       
  1694 #ifdef _DP_DEBUG
       
  1695 	RDebug::Print(_L("timeRecorded %d\n"), I64LOW(timeRecorded));
       
  1696 #endif
       
  1697 	return TTimeIntervalMicroSeconds(timeRecorded);
       
  1698     }
       
  1699 
       
  1700 
       
  1701 
       
  1702 
       
  1703 
       
  1704 TTimeIntervalMicroSeconds CMMFDataPath::OutputPosition() const
       
  1705 	{
       
  1706 	TTimeIntervalMicroSeconds interval;
       
  1707 	TTimeIntervalMicroSeconds position;
       
  1708 
       
  1709     if (iDataSink->DataSinkType() == KUidMmfAudioOutput)
       
  1710         {
       
  1711 		position = CalculateAudioOutputPosition();
       
  1712 #ifdef _DP_DEBUG
       
  1713 		RDebug::Print(_L("DP::OutputPosition from audio output= %d\n"),I64INT(position.Int64()));
       
  1714 #endif
       
  1715         }
       
  1716 	else if (iDataSink->DataSinkType() == KUidMmfFormatEncode)
       
  1717 		{
       
  1718 		//note Encode format position takes priority if both source & sink are formats?
       
  1719         // try to get the position directly from the format. If that fails, work it out here
       
  1720         TRAPD(error, position = ((CMMFFormatEncode*)iDataSink)->PositionL());
       
  1721         if (error)//getting the position from the format didn't work so calculate it here
       
  1722             {
       
  1723 		    interval = ((CMMFFormatEncode*)iDataSink)->FrameTimeInterval(iMediaId);
       
  1724 			TInt64 position64 = interval.Int64() * iCurrentSinkFrameNumber;
       
  1725 			position = position64;
       
  1726             }
       
  1727 
       
  1728 		TTimeIntervalMicroSeconds duration = CONST_CAST(CMMFDataPath*,this)->Duration(); //need this to check position doesn't exceed duration
       
  1729 		if (position > duration)//this can happen on last buffer 
       
  1730 			position = duration;
       
  1731 
       
  1732 
       
  1733 #ifdef _DP_DEBUG
       
  1734 		RDebug::Print(_L("DP::OutputPosition  from format= %d\n"),I64INT(position.Int64()));
       
  1735 #endif
       
  1736 		}
       
  1737 	else
       
  1738 		{//can only read output position if sink is a format or an audio output
       
  1739 		return TTimeIntervalMicroSeconds(0);
       
  1740 		}
       
  1741 
       
  1742 	return position;
       
  1743 	}
       
  1744 
       
  1745 TTimeIntervalMicroSeconds CMMFDataPath::InputPosition() const
       
  1746 	{
       
  1747 	TTimeIntervalMicroSeconds interval;
       
  1748 	TTimeIntervalMicroSeconds position;
       
  1749 
       
  1750     if (iDataSource->DataSourceType() == KUidMmfAudioInput)
       
  1751         {
       
  1752 		position = CalculateAudioInputPosition();
       
  1753 #ifdef _DP_DEBUG
       
  1754 		RDebug::Print(_L("DP::InputPosition from audio input= %d\n"),I64INT(position.Int64()));
       
  1755 #endif
       
  1756         }
       
  1757 	else if (iDataSource->DataSourceType() == KUidMmfFormatDecode)
       
  1758 		{//note Decode format position takes priority if both source & sink are formats?
       
  1759         // try to get the position directly from the format. If that fails, work it out here
       
  1760         TRAPD(error, position = ((CMMFFormatDecode*)iDataSource)->PositionL());
       
  1761         if (error)//getting the position from the format didn't work so calculate it here
       
  1762             {
       
  1763 		    interval = ((CMMFFormatDecode*)iDataSource)->FrameTimeInterval(iMediaId);
       
  1764 		    TInt64 position64 = interval.Int64() * iCurrentSourceFrameNumber;
       
  1765 		    position = position64;
       
  1766             }
       
  1767 
       
  1768 		TTimeIntervalMicroSeconds duration = CONST_CAST(CMMFDataPath*,this)->Duration(); //need this to check position doesn't exceed duration
       
  1769 		if (position > duration)//this can happen on last buffer 
       
  1770 			position = duration;
       
  1771 
       
  1772 #ifdef _DP_DEBUG
       
  1773 		RDebug::Print(_L("DP::InputPosition from format = %d\n"),I64INT(position.Int64()));
       
  1774 #endif
       
  1775 		}
       
  1776 	else
       
  1777 		{//can only read input position if source is a format or an audio input
       
  1778 		return TTimeIntervalMicroSeconds(0);
       
  1779 		}
       
  1780 
       
  1781 	return position;	
       
  1782 	}
       
  1783 
       
  1784 
       
  1785 
       
  1786 
       
  1787 /** 
       
  1788 Gets the data path position.
       
  1789 
       
  1790 @return The data path position.
       
  1791 */
       
  1792 EXPORT_C  TTimeIntervalMicroSeconds CMMFDataPath::Position() const
       
  1793 	{
       
  1794 	if ((iState == ERecording) || (iState == EConverting))
       
  1795 		return InputPosition();
       
  1796 	else if(iState == EPlaying)
       
  1797 		return OutputPosition();
       
  1798 	else
       
  1799 		{
       
  1800 		return iStartPosition;
       
  1801 		}
       
  1802 	}
       
  1803 
       
  1804 /** 
       
  1805 Sets the data path position.
       
  1806 
       
  1807 @param  aPosition
       
  1808 		The data path position.
       
  1809 */
       
  1810 EXPORT_C void CMMFDataPath::SetPositionL(const TTimeIntervalMicroSeconds& aPosition)
       
  1811 	{//need to map to source position to frame position 
       
  1812 #ifdef _DP_DEBUG
       
  1813 	RDebug::Print(_L("DP::SetPositionL = %d  ticks-%d   (this 0x%x)\n"),I64INT(aPosition.Int64()), User::TickCount(),this);
       
  1814 #endif
       
  1815 
       
  1816 	if (iState == EStopped)
       
  1817 		User::Leave(KErrNotReady); //can only set position if primed
       
  1818 
       
  1819 	//As this will affect the position, we need to know how many bytes were 
       
  1820 	//played when position was updated. Future Position() requests will
       
  1821 	//then use this refernce to determine the current position.
       
  1822 	iReferenceAudioSamplesPlayed = AudioSamplesPlayed();
       
  1823 
       
  1824 	// Force the new position to be inside the play window (also within the file duration)
       
  1825 	if ( aPosition < iPlayWindowStartPosition )
       
  1826 		iStartPosition = iPlayWindowStartPosition;
       
  1827 	else if ( aPosition > iPlayWindowEndPosition )
       
  1828 		iStartPosition = iPlayWindowEndPosition; //clearly this will cause nothing to be played
       
  1829 	else
       
  1830 		iStartPosition = aPosition;
       
  1831 
       
  1832 	TTimeIntervalMicroSeconds interval;
       
  1833 
       
  1834 	//can only set the position on an MDataSource that is a format object
       
  1835 	//Note: position defaults to source if both source & sink are clips
       
  1836 	if (iDataSource->DataSourceType() == KUidMmfFormatDecode)
       
  1837 		{
       
  1838 		//position is not beyond the end of file
       
  1839 		interval = ((CMMFFormatDecode*)iDataSource)->FrameTimeInterval(iMediaId);
       
  1840 
       
  1841 		// for some reason this code won't compile without these intermediate steps
       
  1842 		TInt64 position = iStartPosition.Int64();
       
  1843 		TInt64 interval64 = interval.Int64();
       
  1844 		if (interval64 == 0)
       
  1845 			User::Leave(KErrDivideByZero); 
       
  1846 		TInt64 datapos64 = position/interval64; 
       
  1847 		iCurrentSourceFrameNumber = I64LOW(datapos64);
       
  1848 
       
  1849 
       
  1850         // Try to set the position directly on the format
       
  1851         TRAP_IGNORE(((CMMFFormatDecode*)iDataSource)->SetPositionL(iStartPosition));
       
  1852         //NB: don't worry about error, since we'll reposition anyway when we get the next buffer
       
  1853 		}
       
  1854 	else if (iDataSink->DataSinkType() == KUidMmfFormatEncode)
       
  1855 		{			
       
  1856 		//position is not beyond the end of file
       
  1857 		interval = ((CMMFFormatEncode*)iDataSink)->FrameTimeInterval(iMediaId);
       
  1858 
       
  1859 		//convert to TUint - for some reason it won't compile without these intermediate steps
       
  1860 		TInt64 position = iStartPosition.Int64();
       
  1861 		TInt64 interval64 = interval.Int64();
       
  1862 		if (interval64 == 0)
       
  1863 			User::Leave(KErrDivideByZero); 
       
  1864 		TInt64 datapos64 = position/interval64; 
       
  1865 		iCurrentSinkFrameNumber = I64LOW(datapos64);
       
  1866 
       
  1867 
       
  1868         // Try to set the position directly on the format
       
  1869         TRAP_IGNORE(((CMMFFormatEncode*)iDataSink)->SetPositionL(iStartPosition));
       
  1870         //NB: don't worry about error, since we'll reposition anyway when we get the next buffer
       
  1871 		}
       
  1872 	else
       
  1873 		{//can only set position if source or sink is a format
       
  1874 		//If both source and sink are formats position is relative to the source
       
  1875 		User::Leave(KErrNotSupported); //can't set position if neither source nor sink are clips
       
  1876 		}
       
  1877 
       
  1878 	if(iCodec) //we have a real codec, must reset it
       
  1879 		iCodec->ResetL(); // Need to preserve sync when resuming play
       
  1880 
       
  1881 	// Once we've sent the last buffer to the sink it's too late to start
       
  1882 	// changing the state since we may get a RunError(KErrUnderflow) at any time.
       
  1883 	// Once this happens, the sound driver may have unloaded etc..and recovery
       
  1884 	// would be complicated.
       
  1885 	if (iAllDataSentToSink)
       
  1886 		return;
       
  1887 
       
  1888 #ifdef _DP_DEBUG
       
  1889 	RDebug::Print(_L("DP::SetPosition - Done iCurrentSourceFrameNumber=%d  iStartPosition=%d  ticks-%d   (this 0x%x)\n"),iCurrentSourceFrameNumber, I64INT(iStartPosition.Int64()), User::TickCount(),this);	
       
  1890 #endif
       
  1891 	}
       
  1892 
       
  1893 
       
  1894 
       
  1895 
       
  1896 /** 
       
  1897 Sets the play window absolutely (i.e. the parameters are relative to the start of the entire clip).
       
  1898 
       
  1899 @param  aStart
       
  1900         The offset from the start of the Clip
       
  1901 @param  aEnd
       
  1902         The offset from the end of the clip (if this is less than aStart, then the two will be inverted).
       
  1903 */
       
  1904 EXPORT_C void CMMFDataPath::SetPlayWindowL( const TTimeIntervalMicroSeconds& aStart, const TTimeIntervalMicroSeconds& aEnd ) 
       
  1905 	{
       
  1906 	// Clear the existing Play window
       
  1907 	ClearPlayWindowL() ;
       
  1908 	
       
  1909 	// Check that the parameters are legitimate.  0 <= startpos < endpos <= duration & update member variables
       
  1910 	TTimeIntervalMicroSeconds duration = Duration();
       
  1911 		
       
  1912 	if ( aStart < TTimeIntervalMicroSeconds(0) ) 
       
  1913 		iPlayWindowStartPosition = TTimeIntervalMicroSeconds(0);
       
  1914 	else if ( aStart > duration )
       
  1915 		iPlayWindowStartPosition = duration;
       
  1916 	else iPlayWindowStartPosition = aStart;
       
  1917 
       
  1918 	if ( aEnd < TTimeIntervalMicroSeconds(0) )
       
  1919 		iPlayWindowEndPosition = TTimeIntervalMicroSeconds(0);
       
  1920 	else if ( aEnd > duration )
       
  1921 		iPlayWindowEndPosition = duration;
       
  1922 	else iPlayWindowEndPosition = aEnd;
       
  1923 
       
  1924 	// ensure that the current position is inside the new play window
       
  1925 	if ( iPlayWindowEndPosition != TTimeIntervalMicroSeconds(0) )
       
  1926 		{
       
  1927 		TTimeIntervalMicroSeconds currentPosition = Position() ;
       
  1928 		if ( currentPosition < iPlayWindowStartPosition )
       
  1929 			SetPositionL( iPlayWindowStartPosition ) ;
       
  1930 		else if ( currentPosition > iPlayWindowEndPosition )
       
  1931 			SetPositionL( iPlayWindowEndPosition ) ;
       
  1932 		}
       
  1933 	else
       
  1934 		ClearPlayWindowL() ;
       
  1935 
       
  1936 #ifdef _DP_DEBUG
       
  1937 	RDebug::Print(_L("DP::SetPlayWindowL iPlayWindowStartPosition=%d iPlayWindowEndPosition=%d\n"),I64INT(iPlayWindowStartPosition.Int64()),I64INT(iPlayWindowEndPosition.Int64()));
       
  1938 #endif
       
  1939 	}
       
  1940 
       
  1941 
       
  1942 /**
       
  1943 Sets the play window to the full length of clip.
       
  1944 */
       
  1945 EXPORT_C void CMMFDataPath::ClearPlayWindowL() 
       
  1946 	{
       
  1947 	iPlayWindowStartPosition = TTimeIntervalMicroSeconds(0) ;
       
  1948 	iPlayWindowEndPosition = Duration();
       
  1949 
       
  1950 
       
  1951 	if(iState == EStopped)
       
  1952 		iStartPosition = iPlayWindowStartPosition;
       
  1953 	}
       
  1954 
       
  1955 /**
       
  1956 Returns the current data path state.
       
  1957 */
       
  1958 EXPORT_C  TInt CMMFDataPath::State()
       
  1959 	{
       
  1960 	return iState ;
       
  1961 	}
       
  1962 
       
  1963 
       
  1964 /**
       
  1965 Uses the AO mechanism to drive state changes between sources and sinks.
       
  1966 
       
  1967 RunL() moves and assigns buffers between its attached MDataSource/MDataSinks.
       
  1968 */
       
  1969 void CMMFDataPath::ChangeDataPathTransferState(TTransferState aNewDataPathTransferState)
       
  1970 	{
       
  1971 #ifdef _DP_DEBUG
       
  1972 		switch (aNewDataPathTransferState)
       
  1973 			{
       
  1974 		case EWaitSink:
       
  1975 	RDebug::Print(_L("Next State EWaitSink ticks-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  1976 			break;
       
  1977 		case EWaitSource:
       
  1978 	RDebug::Print(_L("Next State EWaitSource ticks-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  1979 			break;
       
  1980 		case EInitializeSink:
       
  1981 	RDebug::Print(_L("Next State EInitializeSink ticks-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  1982 			break;
       
  1983 		case EInitializeSource:
       
  1984 	RDebug::Print(_L("Next State EInitializeSource ticks-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  1985 			break;
       
  1986 		case ENeedSourceData:
       
  1987 	RDebug::Print(_L("Next State ENeedSourceData ticks-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  1988 			break;
       
  1989 		case ENeedSinkData:
       
  1990 	RDebug::Print(_L("Next State ENeedSinkData ticks-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  1991 			break;
       
  1992 		case ENeedToMatchSourceToSink:
       
  1993 	RDebug::Print(_L("Next State ENeedToMatchSourceToSink ticks-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  1994 			break;
       
  1995 		case ESendDataToSink:
       
  1996 	RDebug::Print(_L("Next State ESendDataToSink ticks-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  1997 			break;
       
  1998 		case EEndOfData:
       
  1999 	RDebug::Print(_L("Next State EEndOfData ticks-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  2000 			break;
       
  2001 			}
       
  2002 #endif
       
  2003 
       
  2004 
       
  2005 	TRequestStatus* stat = &iStatus;
       
  2006 	//change state
       
  2007 	iTransferState = aNewDataPathTransferState;
       
  2008 	if ((iTransferState != EWaitSink) && (iTransferState != EWaitSource) && 
       
  2009 		(iState == EPlaying || iState == ERecording || iState == EConverting || (iState == EPrimed && iPauseCalled)))
       
  2010 		{//can go ahead with transfer
       
  2011 		if (!IsActive())
       
  2012 			{
       
  2013 			User::RequestComplete(stat, KErrNone);
       
  2014 			SetActive();
       
  2015 			}
       
  2016 		}
       
  2017 #ifdef _DP_DEBUG
       
  2018 	else
       
  2019 		RDebug::Print(_L("Datapath is no longer active, not going to new state (this 0x%x)\n"),this);
       
  2020 #endif
       
  2021 	}
       
  2022 
       
  2023 /**
       
  2024 Runs the clip depending on the current data path and transfer state.
       
  2025 
       
  2026 For example, fills the sink buffer if TDataPathState is EPlaying and TTransferState is ENeedSinkData.
       
  2027 */
       
  2028 EXPORT_C void CMMFDataPath::RunL()
       
  2029 	{
       
  2030 #ifdef _DP_DEBUG
       
  2031 	RDebug::Print(_L("DP::RunL tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  2032 #endif
       
  2033 	
       
  2034 	switch (iState)
       
  2035 		{
       
  2036 	case EStopped:
       
  2037 		break;
       
  2038 	case EPrimed:
       
  2039 		//paused with stored position
       
  2040 		break;
       
  2041 	case EPlaying:
       
  2042 	case ERecording:
       
  2043 	case EConverting:
       
  2044 		switch (iTransferState)
       
  2045 			{
       
  2046 		case EWaitSink:
       
  2047 		case EWaitSource:
       
  2048 			break;
       
  2049 		case EInitializeSink:
       
  2050 			InitializeSinkL();
       
  2051 			break;
       
  2052 		case EInitializeSource:
       
  2053 			InitializeSourceL();
       
  2054 			break;
       
  2055 		case ENeedSourceData:
       
  2056 			FillSourceBufferL();
       
  2057 			break;
       
  2058 		case ENeedSinkData:
       
  2059 			FillSinkBufferL();
       
  2060 			break;
       
  2061 		case ENeedToMatchSourceToSink:
       
  2062 			FillSinkBufferL();
       
  2063 			break;
       
  2064 		case ESendDataToSink:
       
  2065 			EmptySinkBufferL();
       
  2066 			break;
       
  2067 		case EEndOfData:
       
  2068 			EndOfData();
       
  2069 			break;
       
  2070 			}
       
  2071 		break;
       
  2072 	default:
       
  2073 		break;
       
  2074 		}
       
  2075 #ifdef _DP_DEBUG
       
  2076 	RDebug::Print(_L("DP::RunL DONE\n"));
       
  2077 #endif
       
  2078 	}
       
  2079 
       
  2080 /**
       
  2081 Cancels the clip.
       
  2082 
       
  2083 The default implementation is empty.
       
  2084 */
       
  2085 EXPORT_C void CMMFDataPath::DoCancel()
       
  2086 	{
       
  2087 	//don't need to do anything as we don't have any async requests to other objects
       
  2088 	}
       
  2089 
       
  2090 /**
       
  2091 Handles errors coming from attached sources and passes them to the clients.
       
  2092 
       
  2093 @param  aError
       
  2094         Standard error code (KErrNone = No Error).
       
  2095 
       
  2096 @return The event code returned to the data path. KErrNone if end of file is encountered.
       
  2097 */
       
  2098 EXPORT_C TInt CMMFDataPath::RunError(TInt aError)
       
  2099 	{
       
  2100 	return DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, aError);
       
  2101 	}
       
  2102 
       
  2103 
       
  2104 /**
       
  2105 Returns the duration of the clip.
       
  2106 
       
  2107 @return The length of clip in TTimeIntervalMicroSeconds.
       
  2108 */
       
  2109 TTimeIntervalMicroSeconds CMMFDataPath::Duration() const
       
  2110 	{
       
  2111 	TTimeIntervalMicroSeconds duration(0);
       
  2112 
       
  2113 	if ( iDataSource &&  ( iDataSource->DataSourceType() == KUidMmfFormatDecode ) )
       
  2114 		{
       
  2115 		//this updated version of datapath caches the duration of the
       
  2116 		//source clip for efficiency - since this meathod is const
       
  2117 		//we need to cast away the constness to set iCachedSourceDuration
       
  2118 		CMMFDataPath* thisNonConst = const_cast<CMMFDataPath*>(this);
       
  2119 		duration = STATIC_CAST(CMMFFormatDecode*, thisNonConst->iDataSource )->Duration( iMediaId ) ;
       
  2120 		thisNonConst->iCachedSourceDuration = duration;
       
  2121 		}
       
  2122 	else if ( iDataSink && ( iDataSink->DataSinkType() == KUidMmfFormatEncode ) )
       
  2123 		duration = STATIC_CAST(CMMFFormatEncode*, iDataSink )->Duration( iMediaId ) ;
       
  2124 
       
  2125 	return duration ;
       
  2126 	}
       
  2127 
       
  2128 /**
       
  2129 This is a virtual function datapath (or derivations off) that can be implemented but may be left blank for default behaviour.
       
  2130 
       
  2131 Additional Stop() method specific to this datapath.
       
  2132 */
       
  2133 void CMMFDataPath::DoStopL()
       
  2134 	{
       
  2135 	// Note that the datapath needs to be paused first
       
  2136 	// before it can be stopped - this is important for audio play
       
  2137 	// for instance to effect an immediate stop rather than playing out
       
  2138 	// the current buffer.
       
  2139 
       
  2140 
       
  2141 
       
  2142 	// Stop data source and sink
       
  2143 	iDataSource->SourceStopL();					// propagate state change to source
       
  2144 	iDataSink->SinkStopL();						// propagate change down to sink
       
  2145 
       
  2146 	iSinkBufferWithSink = EFalse;
       
  2147 	iSourceBufferWithSource = EFalse;
       
  2148 
       
  2149 	//Contains the completion code if the datapath completes as a result of an error
       
  2150 	iDataPathCompletedErrorCode = KErrNone;
       
  2151 
       
  2152 	ResetRefBuffers();							// buffer references may not be valid any more
       
  2153 
       
  2154 	SetPositionL(iPlayWindowStartPosition);		// reset position
       
  2155 
       
  2156 	iState = EStopped;							// stop succeeded, set state to stopped
       
  2157 	}
       
  2158 
       
  2159 /**
       
  2160 This is a virtual function datapath (or derivations off) that can be implemented but may be left blank for default behaviour.
       
  2161 
       
  2162 Additional Pause method specific to this datapath.
       
  2163 
       
  2164 The DataPath implements pause by recording the current position and stopping the source and sink.
       
  2165 When Play is called the DataPath uses the stored position as the starting point and resumes
       
  2166 playing. The reason for this (rather than using the PauseL() API on sources and sinks) is that
       
  2167 some implementations do not support a suitable pause, therefore the DataPath is implemented to
       
  2168 support the lowest common denominator.
       
  2169 
       
  2170 Note:
       
  2171 A suitable pause implementation will retain any buffers in use. There will be no
       
  2172 need to call PrimeL() prior to PlayL().
       
  2173 */
       
  2174 void CMMFDataPath::DoPauseL()
       
  2175 	{
       
  2176 #ifdef _DP_DEBUG
       
  2177 	RDebug::Print(_L("DP::DoPauseL tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  2178 #endif
       
  2179 
       
  2180 
       
  2181 	if ((iDataPathCreated) && ((iState == EPlaying) || (iState == EConverting)))
       
  2182 		{
       
  2183 		// try to pause source and sink
       
  2184 		iDataSource->SourcePauseL();		// propagate state change to source
       
  2185 		SetPositionL(Position());
       
  2186 		iDataSink->SinkStopL();
       
  2187 
       
  2188 		iPauseCalled = ETrue;				// indicate pause is called
       
  2189 		
       
  2190 		iState = EPrimed;					// go back to primed state (we're not playing)
       
  2191 
       
  2192 		iSinkBufferWithSink = EFalse;
       
  2193 		iSourceBufferWithSource = EFalse;
       
  2194 
       
  2195 		ResetRefBuffers();					// buffer references may not be valid any more
       
  2196 
       
  2197 		Cancel(); //Stop the state machine
       
  2198 		}
       
  2199 	else if(iState == ERecording)
       
  2200 		{
       
  2201 		iPauseCalled = ETrue;
       
  2202 #ifdef _DP_DEBUG
       
  2203 		RDebug::Print(_L("DP::DoPauseL Recording, pause datasource\n"));
       
  2204 #endif
       
  2205 		iDataSource->SourcePauseL();
       
  2206 		}
       
  2207 #ifdef _DP_DEBUG
       
  2208 	RDebug::Print(_L("DP::DoPauseL - Done iReferenceAudioSamplesPlayed = %d\n"),iReferenceAudioSamplesPlayed);
       
  2209 	RDebug::Print(_L("DP::DoPauseL - Done restart at %d tick-%d   (this 0x%x)\n"),I64INT(iStartPosition.Int64()), User::TickCount(),this);
       
  2210 #endif
       
  2211 	}
       
  2212 
       
  2213 /**
       
  2214 This is a virtual function datapath (or derivations off) that can be implemented or may be left blank for default behaviour.
       
  2215 
       
  2216 Additional Pause method specific to this datapath.
       
  2217 */
       
  2218 void CMMFDataPath::DoEndOfDataL()
       
  2219 	{
       
  2220 #ifdef _DP_DEBUG
       
  2221 	RDebug::Print(_L("DP::DoEndOfDataL tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  2222 #endif
       
  2223 	SetPositionL(iPlayWindowStartPosition);	// reset position
       
  2224 
       
  2225 	ASSERT(iCompleteCallback);
       
  2226 	iCompleteCallback->SignalDataPathComplete(iDataPathCompletedErrorCode);
       
  2227 
       
  2228 	ResetRefBuffers();
       
  2229 	iState = EStopped;
       
  2230 
       
  2231 #ifdef _DP_DEBUG
       
  2232 	RDebug::Print(_L("DP::DoEndOfDataL - Done  tick-%d   (this 0x%x)\n"),User::TickCount(),this);
       
  2233 #endif
       
  2234 	}
       
  2235 
       
  2236 
       
  2237 /**
       
  2238 Passes error handling and general messages up to clients.
       
  2239 
       
  2240 @param  aEventType
       
  2241         Category code for the event. Category codes can be used as unique identifers.
       
  2242 @param  aErrorCode
       
  2243         Standard error code.
       
  2244 
       
  2245 @return The event code sent to client.
       
  2246 */
       
  2247 //error handling
       
  2248 EXPORT_C TInt CMMFDataPath::DoSendEventToClient(TUid aEventType, TInt aErrorCode)
       
  2249 	{
       
  2250 	TMMFEvent event(aEventType, aErrorCode);
       
  2251 	return iEventHandler.SendEventToClient(event);
       
  2252 	}
       
  2253 
       
  2254 /**
       
  2255 Passes error handling and general messages to clients.
       
  2256 
       
  2257 @param  aEvent
       
  2258         TMMFEvent supplied by callee (typically DoSendEventToClient)
       
  2259 
       
  2260 @return The Event Message sent to the datapath event handler
       
  2261 */
       
  2262 EXPORT_C TInt CMMFDataPath::SendEventToClient(const TMMFEvent& aEvent)
       
  2263 	{
       
  2264 #ifdef _DP_DEBUG
       
  2265 	RDebug::Print(_L("CMMFDataPath::SendEventToClient CODE = %d  ticks=%d   (this 0x%x)\n"),aEvent.iErrorCode,User::TickCount(),this);
       
  2266 	RDebug::Print(_L("CMMFDataPath::SendEventToClient iEventType = %d  == %d\n"),aEvent.iEventType, KMMFEventCategoryPlaybackComplete);
       
  2267 #endif
       
  2268 
       
  2269 		//If we have sent all the data to the sink, it is legal for it to send KErrUnderFlow
       
  2270 		//to us and we can go through a clean shutdown, otherwise we pass the error to the 
       
  2271 		//controller and it is responsible for determining what to do
       
  2272 		if(iAllDataSentToSink &&
       
  2273 			(aEvent.iEventType == KMMFEventCategoryPlaybackComplete) &&
       
  2274 			(aEvent.iErrorCode == KErrUnderflow))
       
  2275 			{
       
  2276 #ifdef _DP_DEBUG
       
  2277 			RDebug::Print(_L("CMMFDataPath::SendEventToClient Clean complete\n"));
       
  2278 #endif
       
  2279 			//sink may not return the final buffer once it has finished with it
       
  2280 			//force ourselves into the EndOfData state
       
  2281 			if(iTransferState != EEndOfData)
       
  2282 				{
       
  2283 				iDataPathCompletedErrorCode = KErrNone;
       
  2284 				TRAP_IGNORE(DoEndOfDataL());
       
  2285 				}
       
  2286 
       
  2287 			iCompleteCallback->SignalSinkComplete(KErrNone);
       
  2288 			return KErrNone;
       
  2289 			}
       
  2290 
       
  2291 
       
  2292 
       
  2293 	return iEventHandler.SendEventToClient(aEvent);	
       
  2294 	}
       
  2295 
       
  2296 CMMFDataPath::CCompleteCallback::CCompleteCallback(CMMFDataPath& aDataPath, TBool aWaitForSink)
       
  2297 	: CActive(EPriorityStandard), 
       
  2298 	iDataPath(aDataPath),
       
  2299 	iWaitForSink(aWaitForSink)
       
  2300 	{
       
  2301 	CActiveScheduler::Add(this);
       
  2302 	}
       
  2303 
       
  2304 CMMFDataPath::CCompleteCallback::~CCompleteCallback()
       
  2305 	{
       
  2306 	Cancel();
       
  2307 	}
       
  2308 
       
  2309 void CMMFDataPath::CCompleteCallback::SignalDataPathComplete(TInt aDataPathError)
       
  2310 	{
       
  2311 	iDataPathComplete = ETrue;
       
  2312 	iDataPathError = aDataPathError;
       
  2313 	if (!IsActive()) 
       
  2314 		{
       
  2315 		// Signal ourselves to run with the given completion code
       
  2316 		TRequestStatus* status = &ActiveStatus();
       
  2317 		User::RequestComplete(status, KErrNone);
       
  2318 		}
       
  2319 	}
       
  2320 
       
  2321 void CMMFDataPath::CCompleteCallback::SignalSinkComplete(TInt aSinkError)
       
  2322 	{
       
  2323 	iSinkComplete = ETrue;
       
  2324 	iSinkError = aSinkError;
       
  2325 	if (!IsActive()) 
       
  2326 		{
       
  2327 		// Signal ourselves to run with the given completion code
       
  2328 		TRequestStatus* status = &ActiveStatus();
       
  2329 		User::RequestComplete(status, KErrNone);
       
  2330 		}
       
  2331 	}
       
  2332 
       
  2333 
       
  2334 TRequestStatus& CMMFDataPath::CCompleteCallback::ActiveStatus()
       
  2335 	{
       
  2336 	SetActive();
       
  2337 	return iStatus;
       
  2338 	}
       
  2339 
       
  2340 void CMMFDataPath::CCompleteCallback::DoCancel()
       
  2341 	{
       
  2342 	}
       
  2343 
       
  2344 void CMMFDataPath::CCompleteCallback::RunL()
       
  2345 	{			
       
  2346 	if (iWaitForSink)
       
  2347 		{
       
  2348 		if (iDataPathComplete && iSinkComplete)
       
  2349 			{
       
  2350 #ifdef _DP_DEBUG
       
  2351 			RDebug::Print(_L("CMMFDataPath::CCompleteCallback::RunL STOPPING src & sink ticks=%d   (this 0x%x)\n"),User::TickCount(),this);
       
  2352 #endif
       
  2353 
       
  2354 			TRAP_IGNORE(iDataPath.DoStopL())
       
  2355 
       
  2356 			iDataPathComplete = EFalse;
       
  2357 			iSinkComplete = EFalse;
       
  2358 
       
  2359 			// if we have to wait for the sink to complete, always use the sink error
       
  2360 			iDataPath.DoSendEventToClient(KMMFEventCategoryPlaybackComplete, iSinkError);
       
  2361 			}
       
  2362 		}
       
  2363 	else if (iDataPathComplete)
       
  2364 		{
       
  2365 #ifdef _DP_DEBUG
       
  2366 		RDebug::Print(_L("CMMFDataPath::CCompleteCallback::RunL STOPPING src & sink ticks=%d   (this 0x%x)\n"),User::TickCount(),this);
       
  2367 #endif
       
  2368 
       
  2369 		TRAP_IGNORE(iDataPath.DoStopL())
       
  2370 
       
  2371 		iDataPathComplete = EFalse;
       
  2372 		iSinkComplete = EFalse;
       
  2373 
       
  2374 		iDataPath.DoSendEventToClient(KMMFEventCategoryPlaybackComplete, iDataPathError);
       
  2375 		}
       
  2376 	}
       
  2377 	
       
  2378 EXPORT_C TInt CMMFDataPath::SetBlockLength(TUint aBlockLength)
       
  2379 	{
       
  2380 	MMMFDevSoundCustomInterfaceFileBlockLength* fileBlockLengthCI = NULL;
       
  2381 	TInt err = KErrNotSupported;
       
  2382 	if (iCodec)
       
  2383 		{
       
  2384 		err = iCodec->ExtensionInterface(KUidCustomInterfaceDevSoundFileBlockLength.iUid, (TAny*&)fileBlockLengthCI); 
       
  2385 		}
       
  2386 
       
  2387 	if (err == KErrNone)
       
  2388 		{
       
  2389 		fileBlockLengthCI->SetFileBlockLength(aBlockLength);
       
  2390 		}
       
  2391 
       
  2392 	return err;
       
  2393 	}
       
  2394