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