Update contrib.
1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // source\server\mmfdatapath.cpp
19 #include <mmf/common/mmffourcc.h>
20 #include <mmf/common/mmfpaniccodes.h>
21 #include <mmf/server/mmfaudiooutput.h>
22 #include <mmf/server/mmfaudioinput.h>
23 #include <mmf/server/mmfdatapath.h>
24 #include "mmfclientaudiostreamutils.h"
25 #include <mmf/common/mmfaudio.h>
26 #include <mmf/plugin/mmfcodecimplementationuids.hrh> // KUidMmfCodecAudioSettings
27 #include <mmf/server/devsoundstandardcustominterfaces.h>
29 const TUid KUidCodecAudioConfig = {KUidMmfCodecAudioSettings};
31 void Panic(TMMFDataPathPanicCode aPanicCode, TInt aSourceLineNumber)
33 _LIT(KMMFDataPathPanicCategory, "MMFDataPath");
34 User::Panic(KMMFDataPathPanicCategory, STATIC_CAST(TInt,aPanicCode) + aSourceLineNumber);
37 //all functions are exported form the DLL and are virtual to allow plugins to define there own CMMFDataPaths
40 Allocates and constructs a data path.
42 Use this function if the codec UID is not already known by CMMFController
43 and there is no data path ambiguity - ie only one data path is possible.
45 Will create codec via fourCC.
48 Installs an event handler to provide message passing between clients and sources/sinks.
50 @return Newly constructed data path object.
53 EXPORT_C CMMFDataPath* CMMFDataPath::NewL(MAsyncEventHandler& aEventHandler)
55 CMMFDataPath* self = new(ELeave) CMMFDataPath(TMediaId(), aEventHandler);
56 CleanupStack::PushL(self);
64 Allocates and constructs a data path according to the specified media ID.
66 Use this function if the codec UID is not already known by CMMFController
67 and there is ambiguity with the data path ie. there is more than one possible data path.
70 Optional media ID parameter when there are multiple media types.
72 Installs an event handler to provide message passing between clients and sources/sinks.
74 @return A newly constructed data path object.
77 EXPORT_C CMMFDataPath* CMMFDataPath::NewL(TMediaId aMediaId, MAsyncEventHandler& aEventHandler)
79 CMMFDataPath* self = new(ELeave) CMMFDataPath(aMediaId, aEventHandler);
80 CleanupStack::PushL(self);
87 Allocates and constructs a data path according to the specified codec UID.
89 Use this function if the codec UID is already known by CMMFController
90 and there is no data path ambiguity ie. only one data path is possible
91 will create codec explicitly using the supplied codec Uid
94 Optional mediaID parameter when there are multiple media types
96 Installs an event handler to provide message passing between clients and sources/sinks.
98 @return A newly constructed data path object.
101 EXPORT_C CMMFDataPath* CMMFDataPath::NewL(TUid aCodecUid, MAsyncEventHandler& aEventHandler)
103 CMMFDataPath* self = new(ELeave) CMMFDataPath(TMediaId(), aEventHandler);
104 CleanupStack::PushL(self);
105 self->ConstructL(aCodecUid);
112 Allocates and constructs a data path according to the specified codec UID.
114 Use this function if the codec UID is already known by CMMFController
115 and there is ambiguity ie. more than one possible data path.
116 TMediaId used to select the path.
121 Optional mediaID parameter when there are multiple media types.
123 Installs an event handler to provide message passing between clients and sources/sinks.
125 @return A newly constructed data path object.
127 EXPORT_C CMMFDataPath* CMMFDataPath::NewL(TUid aCodecUid, TMediaId aMediaId, MAsyncEventHandler& aEventHandler)
129 CMMFDataPath* self = new(ELeave) CMMFDataPath(aMediaId, aEventHandler);
130 CleanupStack::PushL(self);
131 self->ConstructL(aCodecUid);
140 EXPORT_C CMMFDataPath::~CMMFDataPath()
146 //log off the source and sink
148 iDataSource->SourceThreadLogoff();
150 iDataSink->SinkThreadLogoff();
152 if (iCompleteCallback)
154 iCompleteCallback->Cancel();
155 delete iCompleteCallback;
160 Deletes buffers if this datapath's sources and sinks own the buffers returned by PrimeL().
161 Typically if buffers are created asychronously, the datapath doesn't own the buffer
162 so leaves cleanup handling to the owner sources/sinks.
164 Called when source and sink needs to be de-referenced. Sets iDataPathCreated, iSinkCanReceive,
165 iSnkBufRef and iSrcBufRef to EFalse; sets iState to EStopped.
167 EXPORT_C void CMMFDataPath::ResetL()
171 DoCleanupBuffers(); // Delete buffers
172 //logoff and dereference source and sink
174 { iDataSource->SourceThreadLogoff(); iDataSource = NULL; }
176 { iDataSink->SinkThreadLogoff(); iDataSink = NULL; }
179 iDataPathCreated = EFalse;
183 iPauseCalled = EFalse;
185 delete iCompleteCallback; iCompleteCallback = NULL;
189 Delete source and/or sink buffers that are owned by DataPath.
191 Ownership indicated by iSrcBufRef and iSnkBufRef.
193 Ownership is assigned during buffer allocation within the datapath PrimeL().
195 void CMMFDataPath::DoCleanupBuffers()
197 // delete source and/or sink buffer that is owned by DataPath
198 if ( !iSrcBufRef && iSourceBuffer )
200 delete iSourceBuffer;
202 iSourceBuffer = NULL;
203 if ( !iSnkBufRef && iSinkBuffer )
212 Obtain source and/or sink buffer using the synchronous API CreateSourceBufferL() and CreateSinkBufferL().
214 void CMMFDataPath::ObtainSyncBuffersL()
216 //Try to create source and sink buffers. If we can't create them synchronously via
217 //CreateSourceBufferL and CreateSinkBufferL we will need to obtain them by
218 //asynchronous buffer creation when playing starts.
220 if (iBuffersToUse & ENeedSourceBuffer)
222 if (!iSourceBuffer) //we may already have a buffer from a previous initialization
224 TRAPD(err, iSourceBuffer = iDataSource->CreateSourceBufferL(iMediaId,*iSinkBuffer, iSrcBufRef));
225 if(err != KErrNone && err != KErrNotSupported)
228 RDebug::Print(_L("DP::ObtainSyncBuffersL - Leaving %d (this 0x%x)\n"),err, this);
236 if (iBuffersToUse & ENeedSinkBuffer)
238 if (!iSinkBuffer) //we may already have a buffer from a previous initialization
240 TRAPD(err, iSinkBuffer = iDataSink->CreateSinkBufferL(iMediaId, iSnkBufRef));
241 if(err != KErrNone && err != KErrNotSupported)
244 RDebug::Print(_L("DP::ObtainSyncBuffersL - Leaving %d (this 0x%x)\n"),err, this);
251 if (iSourceBuffer && !(iBuffersToUse & ENeedSinkBuffer))
252 {//only need one buffer, use source
253 iSinkBuffer =iSourceBuffer;
254 iSnkBufRef = ETrue; //the sink buffer is not to be deleted
256 else if (iSinkBuffer && !(iBuffersToUse & ENeedSourceBuffer))
257 {//only need one buffer, use sink
258 iSourceBuffer =iSinkBuffer;
259 iSrcBufRef = ETrue; //the sink buffer is not to be deleted
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);
274 The default implementation leaves with KErrNotSupported.
277 The initialisation data.
280 EXPORT_C void CMMFDataPath::ConstructSourceL( const TDesC8& /*aInitData*/ )
282 User::Leave(KErrNotSupported);
288 Overridable constuction specific to this datasource.
290 The default implementation leaves with KErrNotSupported.
293 The initialisation data.
295 EXPORT_C void CMMFDataPath::ConstructSinkL( const TDesC8& /*aInitData*/ )
297 User::Leave(KErrNotSupported);
301 Takes UID of codec on construction, and if not an NULL codec sets the datapath up for codec instantiation.
304 The UID of the codec.
307 EXPORT_C void CMMFDataPath::ConstructL(TUid aCodecUid)
309 iUseSuppliedCodecUid = EFalse; //initially assume no supplied codec uid
311 if (aCodecUid != KNullUid)
312 {//the data path NewL has specified a specific codec
313 //create CMMFCodec here
314 iCodec = CMMFCodec::NewL(aCodecUid);
316 iUseSuppliedCodecUid = ETrue;
321 iObtainingAsyncSourceBuffer = EFalse;
322 iObtainingAsyncSinkBuffer = EFalse;
323 iSourceBufferWithSource = EFalse;
324 iSinkBufferWithSink = EFalse;
329 Adds a data source to the datapath and, if the sink already exists, tries to establish a connection
330 between the source and sink.
333 The data source to add to the data path.
335 EXPORT_C void CMMFDataPath::AddDataSourceL(MDataSource* aSource)
337 if (!iDataSink) iDataSource=aSource; //can't create a data path without the MDataSink as well
338 else if (!iUseSuppliedCodecUid) //no supplied uid need to see if we can create codec to establish a data path
339 {//we have a data sink as well so check a data path can be established between source&sink
340 CreateDataPathL(aSource, iDataSink);
341 iDataSource = aSource;
343 else //the CMMFController specified the codec uid so must use existing codec
344 {//note we are assuming here that the CMMFController knows what it is doing ie the supplied codec uid
345 //can make the appropriate data conversion
346 iDataPathCreated = ETrue;
347 iDataSource = aSource;
350 User::LeaveIfError(iDataSource->SourceThreadLogon(*this));
355 Adds a data sink to the datapath and, if the source already exists, tries to establish a connection
356 between the source and sink.
359 The data sink to add to the data path.
362 EXPORT_C void CMMFDataPath::AddDataSinkL(MDataSink* aSink)
364 if (!iDataSource) iDataSink=aSink; //can't create a data path without the MDataSource as well
365 else if (!iUseSuppliedCodecUid) //no supplied uid need to see if we can create codec to establish a data path
366 {//we have a data source as well so check a media path can be established between source&sink
367 CreateDataPathL(iDataSource, aSink);
370 else //the CMMFController specified the codec uid so must use existing codec
371 {//note we are assuming here that the CMMFController knows what it is doing ie the supplied codec uid
372 //can make the appropriate data conversion
373 iDataPathCreated = ETrue;
377 iSourceFourCC = iDataSink->SinkDataTypeCode(iMediaId);//sink because CMMFDataPath is an MDataSink to its MDataSource!
378 iSinkFourCC = iDataSource->SourceDataTypeCode(iMediaId);//source because CMMFDataPath is an MDataSource to its MDataSink!
380 User::LeaveIfError(iDataSink->SinkThreadLogon(*this));
387 * internal function to establish a datapath between the source and sink
388 * the data supplied by the sink adn expected by the source are checked and
389 * a codec is instantiated if necessary
395 void CMMFDataPath::CreateDataPathL(MDataSource* aSource, MDataSink* aSink)
396 { //procedure to attempt to match the source to the sink creating a codec if necessary
397 // returns ETrue if the datapath could be constructed else false
398 //sets iCodec to the appropriate codec.& sets its own iSink/iSource FourCC datatype codes
399 iDataPathCreated = EFalse;
400 if (aSource && aSink) //have a source and sink
401 { //we have a data source & sink but no codec so try and find one - if required
402 TFourCC sourceFourCCCode = aSource->SourceDataTypeCode(iMediaId); //get MDataSource data type fourCC code
403 TFourCC sinkFourCCCode = aSink->SinkDataTypeCode(iMediaId); //get MDataSink data type fourCC code
404 if ((sourceFourCCCode != sinkFourCCCode) && //MDataSource & MDataSink datatypes are not compatible
405 (sourceFourCCCode != KMMFFourCCCodeNULL) && (sinkFourCCCode != KMMFFourCCCodeNULL))
406 {//we need a codec to make the conversion between the source and the sink
407 CMMFCodec* codec = CMMFCodec::NewL(sourceFourCCCode, sinkFourCCCode);
413 //data path created ie have source/sink and can match their datatypes
414 iDataPathCreated = ETrue;
416 //now we have an source attached we need to configure the codec for sample rate
417 //and number of channels
419 //prepare a package to send to a codec
420 TMMFAudioConfig audioSettings;
423 if (aSource->DataSourceType() == KUidMmfFormatDecode)
425 audioSettings.iSampleRate = static_cast<CMMFFormatDecode*>(aSource)->SampleRate();
426 audioSettings.iChannels = static_cast<CMMFFormatDecode*>(aSource)->NumChannels();
429 //package up to send to codec
430 TPckgBuf<TMMFAudioConfig> configPackage(audioSettings);
432 //we need to catch User::Leave(KErrNotSupported) as by default most codecs
433 //do not support the ConfigureL method.
434 TRAPD(err,iCodec->ConfigureL(KUidCodecAudioConfig, configPackage));
435 // need to check other error here
436 if (err != KErrNone && err != KErrNotSupported)
443 User::Leave( KErrNotSupported ) ; //couldn't find suitable codec
445 } //if (sourceFourCCCode != sinkFourCCCode)
447 { //source & sink fourCC datatypes are the same so no codec is required
448 __ASSERT_DEBUG(iCodec == NULL, Panic(EMMFDataPathPanicProgrammingError,__LINE__));
450 iDataPathCreated = ETrue;
452 //can assign FourCC codes for the CMMFDataPath
453 iSinkFourCC = sourceFourCCCode; //sink because CMMFDataPath is an MDataSink to its MDataSource!
454 iSourceFourCC = sinkFourCCCode; //source because CMMFDataPath is an MDataSource to its MDataSink!
455 //If sink & source need its own Prime() done in controller
460 Clears the specified buffer.
462 Pure virtual dummy implementation, not needed by datapath
463 comes from MDataSink - CMMFData path is a sink to its MDataSource.
465 This is only required for an active push MDataSource requesting a buffer empty.
470 The MDataSource supplying this buffer.
472 An optional mediaID parameter when there are multiple buffers arriving of different media types.
475 EXPORT_C void CMMFDataPath::EmptyBufferL(CMMFBuffer* /* aBuffer */, MDataSource* /*aSupplier*/, TMediaId /*aMediaId*/)
485 * Function to get data from the datapath's iDataSource
488 void CMMFDataPath::FillSourceBufferL()
491 RDebug::Print(_L("DP::FillSourceBufferL tick-%d (this 0x%x)\n"),User::TickCount(),this);
494 __ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__));
497 // clear the no-more-source flag here (as well as in PlayL()) because
498 // there may have been a re-position since the last call to BufferFilledL()
499 iNoMoreSourceData = EFalse;
501 if(!iObtainingAsyncSourceBuffer)
502 {//this is a normal request for data.
503 //If we are getting asynchronous buffers, then can't do this as iSourceBuffer == NULL
504 iSourceBuffer->SetFrameNumber(++iCurrentSourceFrameNumber); //so source knows which data to load buffer with
505 iSourceBuffer->SetStatus(EBeingFilled);
506 iSourceBuffer->SetLastBuffer(EFalse);
510 RDebug::Print(_L("DP asking for buffer %d - ptr=0x%x (this 0x%x)\n"), iCurrentSourceFrameNumber, iSourceBuffer,this);
513 iSourceBufferWithSource = ETrue;
515 // wait for BufferFilled callback from source. Do this here as some sources cause
516 //re-entrancy into data path via BufferFilledL
517 ChangeDataPathTransferState(EWaitSource);
519 iDataSource->FillBufferL(iSourceBuffer, this, iMediaId);
522 RDebug::Print(_L("DP::FillSourceBufferL - DONE tick-%d (this 0x%x)\n"),User::TickCount(),this);
528 Indicates the data source has filled the specified buffer.
530 Called by the CMMFDataPath's MDataSource when it has filled the buffer.
533 A pointer to the filled buffer.
535 EXPORT_C void CMMFDataPath::BufferFilledL(CMMFBuffer* aBuffer)
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);
541 //This assertion is commented because of PDEF117405
542 //state only used if we are passing data
543 //__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__));
545 __ASSERT_DEBUG((!iNoMoreSourceData), Panic(EMMFDataPathPanicBadState,__LINE__));
547 iSourceBufferWithSource = EFalse;
549 //Has the datapath stopped running, if so were not interested in any callbacks.
550 if(iState == EStopped || iState == EPrimed || (iPauseCalled && iState != ERecording))
553 RDebug::Print(_L("DP::BufferFilledL called while not expecting callback iState=%d iPauseCalled=%d (this 0x%x)\n"),iState, iPauseCalled,this);
558 #ifdef REPOSITION_SPEEDUP
559 // if the source has been re-positioned, then go & get some more source data now
560 if (!iObtainingAsyncSourceBuffer && iSourceBuffer->FrameNumber() != iCurrentSourceFrameNumber)
563 RDebug::Print(_L("DP::BufferFilledL source was re-positioned re-requesting source data (this 0x%x)\n"),this);
565 ChangeDataPathTransferState(ENeedSourceData);
568 #endif //REPOSITION_SPEEDUP
570 //bufer is NULL, indicating no more source data.
573 //If we only hold a reference to the source buffer, set that to NULL
575 iSourceBuffer = NULL;
578 iNoMoreSourceData = ETrue;
580 if(!iCodec || //there's only one buffer and that has been returned as NULL, so must be end of data
581 iSinkBufferWithSink) //buffer is with sink, we don't have any more data to put in it, so must be end of data
583 ChangeDataPathTransferState(EEndOfData);
585 else //sink buffer is with datapath, see if there is anything to send to sink
586 ChangeDataPathTransferState(ENeedToMatchSourceToSink);
589 RDebug::Print(_L("DP::BufferFilledL DONE aBuffer==NULL tick-%d (this 0x%x)\n"),User::TickCount(),this);
595 //We were waiting for a response from the source to get an asynchronous buffer.
596 //We now have it, and we proceed to transfer this data to the sink.
597 if (iObtainingAsyncSourceBuffer)
599 iObtainingAsyncSourceBuffer = EFalse;
603 aBuffer->SetStatus(EFull);
605 if(iSourceBuffer != aBuffer)
606 {//buffer has been changed by the source
607 iSourceBuffer = aBuffer;
608 if (!(iBuffersToUse & ENeedSinkBuffer))
609 {//we only need one buffer and use source
610 iSinkBuffer = iSourceBuffer;
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);
617 //Is this the last buffer from the source (0 length or LastBuffer flag set)
618 //or have reached the end of the play window; we only look at the play window here
619 //if we are converting. For conversion we look at the data we have read. This is then passed onto
621 if (!iSourceBuffer->BufferSize() || iSourceBuffer->LastBuffer() ||
622 (((iState == EConverting) || (iState == EPlaying)) && (iPlayWindowEndPosition < iCachedSourceDuration) && ( InputPosition() >= iPlayWindowEndPosition )))
625 RDebug::Print(_L("DP::BufferFilledL end of input data tick-%d (this 0x%x)\n"),User::TickCount(),this);
626 RDebug::Print(_L("iSourceBuffer->BufferSize()=%d\n"),iSourceBuffer->BufferSize());
627 RDebug::Print(_L("iSourceBuffer->LastBuffer()=%d\n"),iSourceBuffer->LastBuffer());
628 RDebug::Print(_L("InputPosition()=%d >= iPlayWindowEndPosition=%d\n"),I64INT(InputPosition().Int64()),I64INT(iPlayWindowEndPosition.Int64()));
630 iNoMoreSourceData = ETrue;
631 iSourceBuffer->SetLastBuffer(ETrue); //just in-case we are terminating on BufferSize == 0 or play window
636 ChangeDataPathTransferState(ESendDataToSink);
637 else if(!iSinkBufferWithSink) //sink buffer is with data path, can try to fill it
638 ChangeDataPathTransferState(ENeedToMatchSourceToSink);
639 //else wait for sink to return buffer BufferEmptied will send us into ENeedToMatchSourceToSink state
642 RDebug::Print(_L("DP::BufferFilledL - DONE tick-%d (this 0x%x)\n"),User::TickCount(),this);
652 * Function to take the data from an already full source buffer and by using
653 * a codec if necessary fills the sink buffer
656 void CMMFDataPath::FillSinkBufferL()
659 RDebug::Print(_L("DP::FillSinkBufferL tick-%d (this 0x%x)\n"),User::TickCount(),this);
662 //This state is only used if we are passing data
663 __ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__));
665 //This state is only used if we have a real codec
666 __ASSERT_DEBUG(iCodec, Panic(EMMFDataPathPanicBadState,__LINE__));
669 //The sink buffer is with the sink so we can't fill it.
670 //When it has been emptied, this state will be re-entered from BufferEmptiedL
671 if(iSinkBufferWithSink)
674 RDebug::Print(_L("DP::FillSinkBufferL buffer is in use by SINK - DONE (this 0x%x)\n"),this);
676 ChangeDataPathTransferState(EWaitSink); // wait for BufferEmptied callback from sink
680 //The source buffer is with the source so we can't take data from it.
681 //When it has been filled, this state will be re-entered from BufferFilledL
682 if(iSourceBufferWithSource)
685 RDebug::Print(_L("DP::FillSinkBufferL buffer is in use by SOURCE - DONE (this 0x%x)\n"),this);
687 ChangeDataPathTransferState(EWaitSource); // wait for BufferFilled callback from source
691 //source buffer is NULL, can't be any more data to send.
692 //iNoMoreSourceData is set and the source buffer is empty, can't be any more data to send.
693 if(!iSourceBuffer || (iNoMoreSourceData && !iSourceBuffer->BufferSize()))
695 if(iSinkBuffer->Status() == EBeingFilled)
696 {//if we have data in sink buffer, mark it as last buffer and send
697 iSinkBuffer->SetLastBuffer(ETrue);
698 ChangeDataPathTransferState(ESendDataToSink);
700 else //the sink buffer can't have anything in it
701 ChangeDataPathTransferState(EEndOfData);
704 #ifdef REPOSITION_SPEEDUP
705 // if the source has been re-positioned,
706 // speed things up by getting some more source data now
707 if(iSourceBuffer && iSourceBuffer->FrameNumber() != iCurrentSourceFrameNumber)
710 RDebug::Print(_L("DP::FillSinkBufferL() source was re-positioned re-requesting source data (this 0x%x)\n"),this);
712 ChangeDataPathTransferState(ENeedSourceData);
715 #endif //REPOSITION_SPEEDUP
717 iSinkBuffer->SetStatus(EBeingFilled);
718 iSinkBuffer->SetLastBuffer(EFalse);
720 //pass buffer to codec for processing
721 iCodecProcessResult = iCodec->ProcessL(*iSourceBuffer, *iSinkBuffer);
722 //the codec tries to fill the sink buffer to its max length
723 //TCodecProcessResult returns the status of the codec Process -
724 //this can result in result conditions such as:
725 //EProcessComplete - the codec processed all the source data into the sink buffer
726 //EProcessIncomplete - the codec filled sink buffer before all the source buffer was processed
727 //EDstNotFilled - the codec processed the source buffer but the sink buffer was not filled
728 //EEndOfData - the codec detected the end data - all source data in processed but sink may not be full
729 //EProcessError - the codec process error condition
732 switch (iCodecProcessResult.iStatus)
734 case TCodecProcessResult::EProcessComplete:
735 //finished procesing source data - all data in sink buffer
738 RDebug::Print(_L("CMMFDataPath::FillSinkBufferL codec EProcessComplete (this 0x%x)\n"),this);
740 iSourceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
741 iSinkBuffer->SetStatus(EFull); //sink buffer is full
742 if (iNoMoreSourceData)
743 iSinkBuffer->SetLastBuffer(ETrue);
744 ChangeDataPathTransferState(ESendDataToSink);// the full sink buffer needs to be sent to the sink
747 case TCodecProcessResult::EProcessIncomplete:
748 // the sink was filled before all the src was processed
749 // therefore still send everything to sink
750 //but datapath needs to carry on processing the source buffer before it gets more source data
751 //when sink has emptied data path needs to send rest of data
754 RDebug::Print(_L("CMMFDataPath::FillSinkBufferL codec EProcessIncomplete (this 0x%x)\n"),this);
756 TUint sourceBufferPosition = iCodecProcessResult.iSrcBytesProcessed + iSourceBuffer->Position();
757 iSourceBuffer->SetPosition(sourceBufferPosition);//update source buffer position
758 iSinkBuffer->SetStatus(EFull); //sink & source buffers are both full
759 ChangeDataPathTransferState(ESendDataToSink); // the full sink buffer needs to be sent to the sink
762 case TCodecProcessResult::EDstNotFilled:
763 // the destination is not full
766 RDebug::Print(_L("CMMFDataPath::FillSinkBufferL codec EDstNotFilled (this 0x%x)\n"),this);
768 iSourceBuffer->SetStatus(EAvailable); //source buffer is now available
769 TUint sinkBufferPosition = iCodecProcessResult.iDstBytesAdded + iSinkBuffer->Position();
770 iSinkBuffer->SetPosition(sinkBufferPosition);//update sink buffer position (still EBeingFilled)
771 // if this was the last source buffer, send what we've got (if anything)
772 // to the sink... EmptySinkBuffer() should then enter EEndOfData state
773 if (iNoMoreSourceData)
775 iSinkBuffer->SetLastBuffer(ETrue);
776 ChangeDataPathTransferState(ESendDataToSink);//send what we've got to the sink -
780 ChangeDataPathTransferState(ENeedSourceData); //need to get more source data to fill sink buffer
784 case TCodecProcessResult::EEndOfData:
785 //no more data - send what we've got to the sink
786 //note we can't always rely on this - in many cases the codec will not know when
787 //it has reached the end of data.
790 RDebug::Print(_L("CMMFDataPath::FillSinkBufferL codec EEndOfData (this 0x%x)\n"),this);
792 iSourceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
793 iSinkBuffer->SetStatus(EFull);//sink buffer may not really be 'full' but its as full as it going to get
795 //This only occurs where the codec can detect the end of data, but the source can't
796 iNoMoreSourceData=ETrue;
797 iSinkBuffer->SetLastBuffer(ETrue);
799 ChangeDataPathTransferState(ESendDataToSink);//send what we've got to the sink -
800 //doesn't matter if sink buffer is not full
803 case TCodecProcessResult::EProcessError:
805 RDebug::Print(_L("DP::FillSinkBufferL tick-%d DONE %d (this 0x%x)\n"),User::TickCount(), __LINE__,this);
807 User::Leave(KErrCorrupt); //codec process error
811 RDebug::Print(_L("DP::FillSinkBufferL tick-%d DONE %d (this 0x%x)\n"),User::TickCount(), __LINE__,this);
813 User::Leave(KErrCorrupt); //should never get here
816 RDebug::Print(_L("DP::FillSinkBufferL - done tick-%d (this 0x%x)\n"),User::TickCount(),this);
823 Tests whether the data path can create a sink buffer.
825 The default implementation returns false.
827 @return ETrue if the data path can create a sink buffer. EFalse if the data path cannot create a sink buffer.
829 EXPORT_C TBool CMMFDataPath::CanCreateSinkBuffer()
831 return NULL; //CMMFDataPath cannot create buffer
835 Creates a sink buffer according to the specifed media ID.
837 Intended for synchronous usage (buffers supplied by datapath for an MDataSink).
838 This method is essentially a dummy implementation of an MDataSink pure virtual.
840 The default implementation returns NULL.
843 An optional mediaID parameter when there are multiple buffers arriving of different media types.
845 @return Returns NULL in this instance as datapath can't create sink buffers
847 EXPORT_C CMMFBuffer* CMMFDataPath::CreateSinkBufferL(TMediaId /*aMediaId*/)
848 {//CMMFDataPath can't create buffers
853 Creates a sink buffer according to the specifed media ID and reference.
855 Intended for asynchronous usage (buffers supplied by Devsound device).
856 This method is essentially a dummy implementation of an MDataSink pure virtual.
858 The default implementation returns NULL.
861 An optional mediaID parameter when there are multiple buffers arriving for different media types.
863 A boolean indicating buffer ownership.
865 @return Returns NULL in this instance as datapath can't create sink buffers.
867 EXPORT_C CMMFBuffer* CMMFDataPath::CreateSinkBufferL(TMediaId /*aMediaId*/, TBool& /*aReference*/)
868 {//CMMFDataPath can't create buffers
873 Gets the sink's data type for the specified media ID.
876 An optional parameter to specifiy the specific stream when datasource contains more than one stream of data
877 @return The sink's data type.
879 EXPORT_C TFourCC CMMFDataPath::SinkDataTypeCode(TMediaId /*aMediaId*/)
885 Fills the specified buffer.
887 Pure virtual dummy implementation, not needed by datapath
888 comes from MDataSink - CMMFData path is a source to its MDataSink
890 Only required for an active pull MDataSink requesting a buffer fill. The default implementation is empty.
895 The MDataSink supplying this buffer.
897 An optional mediaID parameter when there are multiple buffers arriving of different media types
899 EXPORT_C void CMMFDataPath::FillBufferL(CMMFBuffer* /*aBuffer*/, MDataSink* /*aConsumer*/, TMediaId /*aMediaId*/)
904 void CMMFDataPath::SetBuffersAvailable()
906 // set source buffer to be available
908 iSourceBuffer->SetStatus(EAvailable);
909 // set sink buffer to be available
911 iSinkBuffer->SetStatus(EAvailable);
914 void CMMFDataPath::ResetRefBuffers()
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);
920 // Reset the buffer pointers to NULL if they are supplied by DevSound
921 // We do this because buffers that are not owned by the datapath may not be valid any more.
924 iSourceBuffer = NULL;
935 TInt CMMFDataPath::DetermineBuffersToUseL(void) const
937 TInt buffs = ENoBuffers;
939 {//Using a real Codec, need both sets of buffers
940 if(!iDataSink->CanCreateSinkBuffer() || ! iDataSource->CanCreateSourceBuffer())
941 User::Leave(KErrNotSupported);
943 buffs = CMMFDataPath::ENeedSinkBuffer | CMMFDataPath::ENeedSourceBuffer;
945 else //we are using a Null Codec, only need one buffer, but which one?
946 {//use buffer from DevSound, if no DevSound (ie, clip to clip), prefer source buffer.
947 //If preferring source but it can't create buffers, use sink.
948 if ((iDataSink->DataSinkType() == KUidMmfAudioOutput) && (iDataSink->CanCreateSinkBuffer()))
949 buffs = ENeedSinkBuffer;
950 else if(iDataSource->CanCreateSourceBuffer())
951 buffs = ENeedSourceBuffer;
952 else if(iDataSink->CanCreateSinkBuffer())
953 buffs = ENeedSinkBuffer;
955 User::Leave(KErrNotSupported);
965 * Function to initialize iDataSink before it can start sending data
966 * This is a one time prime. This will synchronize DataPath's data driving
967 * mechanism with HwDevice implementation.
969 * This initialisation method detects its attached sources and sinks and makes adjustments to the state machine
970 * This avoid the possibility of NULL buffers (not yet returned by an asychronous sink or source) being passed around the MMF
973 void CMMFDataPath::InitializeSinkL()
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);
979 //state only used if we are passing data
980 __ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__));
982 iObtainingAsyncSinkBuffer = EFalse;
984 if (iBuffersToUse & ENeedSinkBuffer)
986 //Buffers are initially created in the Prime method. But following a pause, we must re-create
987 //any referenced buffers, so try direct creation.
988 //NB: this does mean we are trying this twice, Prime and here
989 if (!iSinkBuffer) //we may already have a buffer from a previous initialization
991 TRAPD(err, iSinkBuffer = iDataSink->CreateSinkBufferL(iMediaId, iSnkBufRef));
992 if(err != KErrNone && err != KErrNotSupported)
997 //If buffer has not been supplied via CreateSinkBufferL,
998 //must use asynchronous buffer creation
1001 iObtainingAsyncSinkBuffer = ETrue;
1002 ChangeDataPathTransferState(EWaitSink); // wait for BufferEmptied callback from sink
1003 iDataSink->EmptyBufferL(iSinkBuffer, this, iMediaId);
1007 //we have a sink buffer from CreateSinkBufferL
1008 iSinkBuffer->SetStatus(EAvailable);
1010 if (iBuffersToUse & ENeedSourceBuffer)
1011 {//need a source buffer, go get it
1012 ChangeDataPathTransferState(EInitializeSource);
1015 {//only need one buffer, use sink
1016 iSourceBuffer = iSinkBuffer;
1017 iSrcBufRef = ETrue; //the src buffer is not to be deleted
1019 ChangeDataPathTransferState(ENeedSourceData); //got all buffers, start getting data
1024 {//don't need a sink buffer, but we need a source one
1025 ChangeDataPathTransferState(EInitializeSource);
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);
1037 * Function to initialize iDataSource before it can start sending data
1038 * This is a one time prime. This will synchronize DataPath's data driving
1039 * mechanism with HwDevice implementation.
1041 * This initialisation method detects its attached sources and sinks and makes adjustments to the state machine
1042 * This avoid the possibility of NULL buffers (not yet returned by an asychronous sink or source) being passed around the MMF
1045 void CMMFDataPath::InitializeSourceL()
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);
1051 //state only used if we are passing data
1052 __ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__));
1054 iObtainingAsyncSourceBuffer = EFalse;
1056 if (iBuffersToUse & ENeedSourceBuffer)
1058 //Buffers are initially created in the Prime method. But following a pause, we must re-create
1059 //any referenced buffers, so try direct creation.
1060 //NB: this does mean we are trying this twice, Prime and here.
1061 if (!iSourceBuffer) //we may already have a buffer from a previous initialization
1063 TRAPD(err, iSourceBuffer = iDataSource->CreateSourceBufferL(iMediaId,*iSinkBuffer, iSrcBufRef));
1064 if(err != KErrNone && err != KErrNotSupported)
1069 //If buffer has not been supplied via CreateSourceBufferL
1070 //must use asynchronous buffer creation
1073 iObtainingAsyncSourceBuffer = ETrue;
1074 ChangeDataPathTransferState(ENeedSourceData);
1077 {//we have a source buffer from CreateSourceBufferL
1078 iSourceBuffer->SetStatus(EAvailable);
1080 if (!(iBuffersToUse & ENeedSinkBuffer))
1081 {//only need one buffer, use sink
1082 iSinkBuffer = iSourceBuffer;
1086 ChangeDataPathTransferState(ENeedSourceData); //got all buffers, start getting data
1090 {//don't need a source buffer, use sinks
1093 iSourceBuffer = iSinkBuffer;
1094 iSrcBufRef = iSnkBufRef;
1095 SetBuffersAvailable();
1099 Panic(EMMFDataPathPanicProgrammingError,__LINE__);
1101 ChangeDataPathTransferState(ENeedSourceData); //got all buffers, start getting data
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);
1113 * Function to pass a full databuffer to the iDataSink
1115 void CMMFDataPath::EmptySinkBufferL()
1118 RDebug::Print(_L("DP::EmptySinkBufferL pass data to sink tick-%d (this 0x%x)\n"),User::TickCount(),this);
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);
1123 //Before emptying the sink buffer we need to check it has data to empty - this
1124 //may not be the case if there is no more data ie iNoMoreSourceData is true.
1125 //In this case we need to check to see if there is any data left in the sink
1126 //buffer, ie the sink buffer is either full or being filled. If there is not any
1127 //data in the sink buffer, ie it is not in the state of EBeingFilled or EFull
1128 //then there is nothing to empty so the datapath state is set to EEndOfData and
1129 //we return from the procedure.
1131 //state only used if we are passing data
1132 __ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording || (iState == EPrimed && iPauseCalled)), Panic(EMMFDataPathPanicBadState,__LINE__));
1133 __ASSERT_DEBUG(iSinkBuffer &&
1134 ((iSinkBuffer->Status()==EBeingFilled) || (iSinkBuffer->Status()==EFull)),
1135 Panic(EMMFDataPathPanicProgrammingError,__LINE__));
1137 __ASSERT_DEBUG(iSinkBufferWithSink == EFalse, Panic(EMMFDataPathPanicBadState,__LINE__));
1140 //Due to sinks that may call BuferEmptied directly (ie. re-entrancy onto DataPath) we
1141 //must work out next state here. If re-entrancy, the next state may validly get overwritten
1143 if(iObtainingAsyncSinkBuffer) //wait for buffer to be returned in BufferEmptied
1145 ChangeDataPathTransferState(EWaitSink); // wait for BufferEmptied callback from sink
1148 #ifdef REPOSITION_SPEEDUP
1149 // if the source has been re-positioned,
1150 // speed things up by getting some more source data now
1151 if(iSourceBuffer && iSourceBuffer->FrameNumber() != iCurrentSourceFrameNumber)
1154 RDebug::Print(_L("DP::EmptySinkBufferL() source was re-positioned re-requesting source data (this 0x%x)\n"),this);
1156 ChangeDataPathTransferState(ENeedSourceData);
1159 #endif //REPOSITION_SPEEDUP
1161 //We have sent data to sink, if we are using a real Codec, we can now get more data from source
1162 //if there is any more to get and the codec has emptied it.
1163 //NB: No need to check we own the source buffer as we will no be in this state
1164 //if we have asked for more source data and haven't received it.
1165 else if (iCodec && !iNoMoreSourceData && (iSourceBuffer->Status() == EAvailable))
1168 RDebug::Print(_L("ASKING for more source data iCodec = 0x%x iNoMoreSourceData=%d iSourceBufferWithSource = %d (this 0x%x)\n"), iCodec, iNoMoreSourceData, iSourceBufferWithSource,this);
1170 ChangeDataPathTransferState(ENeedSourceData);
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);
1178 //if this is the last buffer, set this flag so we can deal with KErrUnderflow
1179 //as a valid termination of playing
1180 if(iSinkBuffer->LastBuffer())
1181 iAllDataSentToSink=ETrue;
1183 ChangeDataPathTransferState(EWaitSink); // wait for BufferEmptied callback from sink
1187 if(!iObtainingAsyncSinkBuffer) //normal data transfer
1188 iSinkBuffer->SetFrameNumber(++iCurrentSinkFrameNumber);
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);
1194 iSinkBufferWithSink = ETrue;
1195 TRAPD(error, iDataSink->EmptyBufferL(iSinkBuffer, this, iMediaId));
1197 // Check that we haven't exceeded the maximum clip length - if so, go to the EndOfData state
1198 // so we perform necessary cleanup.
1199 if (error == KErrEof || error == KErrOverflow || error == KErrUnderflow)
1202 RDebug::Print(_L("DP::EmptySinkBufferL DONE %d error = %d tick-%d (this 0x%x)\n"),__LINE__, error, User::TickCount(),this);
1204 iDataPathCompletedErrorCode = error;
1205 ChangeDataPathTransferState(EEndOfData);
1208 User::LeaveIfError(error);
1211 RDebug::Print(_L("DP::EmptySinkBufferL - done tick-%d (this 0x%x)\n"),User::TickCount(),this);
1217 Indicates the data sink has emptied the buffer.
1219 Called by the CMMFDataPath's MDataSink when it has emptied the buffer
1224 EXPORT_C void CMMFDataPath::BufferEmptiedL(CMMFBuffer* aBuffer)
1229 bufNum = aBuffer->FrameNumber();
1231 RDebug::Print(_L("DP::BufferEmptiedL returned NULL (this 0x%x)\n"),this);
1233 RDebug::Print(_L("DP::BufferEmptiedL sink has taken buffer %d (ptr=0x%x) bytes %d eof= %d iNoMoreSourceData = %d tick-%d (this 0x%x)\n"),
1234 bufNum, aBuffer, aBuffer->BufferSize(),aBuffer->LastBuffer(), iNoMoreSourceData, User::TickCount(),this);
1237 iSinkBufferWithSink = EFalse;
1239 //Has the datapath stopped running, if so were not interested in any callbacks.
1240 if(iState == EStopped || (iState == EPrimed && !iPauseCalled))
1243 RDebug::Print(_L("DP::BufferEmptiedL called while not expecting callback iState=%d iPauseCalled=%d (this 0x%x)\n"),iState, iPauseCalled,this);
1249 // This will allow MDataSink to send dynamic buffer to DataPath with each BufferEmptiedL request.
1250 if (iSinkBuffer != aBuffer) //buffer has been updated
1252 iSinkBuffer = aBuffer;
1253 if (!(iBuffersToUse & ENeedSourceBuffer))
1254 { //can use a single buffer
1255 iSourceBuffer = iSinkBuffer;
1256 iSrcBufRef = iSnkBufRef;
1261 iSinkBuffer->SetStatus(EAvailable);
1263 if (iObtainingAsyncSinkBuffer) //we are creating an asynchronous sink buffer
1265 iObtainingAsyncSinkBuffer = EFalse;
1267 //we have a sink buffer, should this also be used by the source
1268 if (!(iBuffersToUse & ENeedSourceBuffer))
1269 {//using a single buffer, so start getting data
1270 iSourceBuffer = iSinkBuffer;
1271 iSrcBufRef = iSnkBufRef;
1273 ChangeDataPathTransferState(ENeedSourceData);
1275 else //obtain a separate source buffer
1276 ChangeDataPathTransferState(EInitializeSource);
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);
1284 if(!iCodec) //No Codec in use
1286 if(iNoMoreSourceData)
1287 ChangeDataPathTransferState(EEndOfData);//final buffer returned from sink
1289 ChangeDataPathTransferState(ENeedSourceData);//get more data from source
1293 //There is more source data and src buffer is being filled or we are about to go into
1294 // ENeedSourceData state to fill it, so wait for source data to arrive.
1295 //NB:if there was more source data and we are using a real codec and source buffer was empty,
1296 //more source data would have been requested in EmptySinkBuffer
1297 if(!iNoMoreSourceData && (iSourceBufferWithSource || iTransferState == ENeedSourceData))
1300 RDebug::Print(_L("DP::BufferEmptiedL - waiting for more source data - DONE tick-%d line %d (this 0x%x)\n"),User::TickCount(),__LINE__,this);
1305 //source has supplied a NULL buffer or it has been emptied; no more data to send.
1306 if(!iSourceBuffer || (iSourceBuffer->Status() == EAvailable))
1307 ChangeDataPathTransferState(EEndOfData);
1308 else if(iSourceBuffer->Status() == EFull) //there is data in the source buffer, go and get it
1309 ChangeDataPathTransferState(ENeedToMatchSourceToSink);
1313 Panic(EMMFDataPathPanicProgrammingError,__LINE__);
1319 RDebug::Print(_L("DP::BufferEmptiedL - DONE tick-%d (this 0x%x)\n"),User::TickCount(),this);
1326 Tests whether the data path can create a source buffer.
1328 Would expect datapath to always return NULL, so this is a default implementation of a pure virtual from MDataSink.
1330 The default implementation returns EFalse.
1332 @return ETrue if the data path can create a source buffer. EFalse if the data path cannot create a source buffer.
1334 EXPORT_C TBool CMMFDataPath::CanCreateSourceBuffer() //from both MDataSource & MDataSink?
1336 return EFalse; //CMMFDataPath cannot create buffer
1340 Creates a source buffer.
1342 Intended for synchronous usage (buffers supplied by datapath for a MDataSource)
1343 This method is essentially a dummy implementation of an MDataSource pure virtual.
1345 The default implementation leaves with KErrNotSupported and returns NULL.
1348 An optional mediaID parameter when there are multiple buffers arriving of different media types.
1349 @return A pointer to a newly created buffer. Returns NULL in this instance as datapath can't create source buffers
1351 EXPORT_C CMMFBuffer* CMMFDataPath::CreateSourceBufferL(TMediaId /*aMediaId*/) //CMMFDataPath can't create buffers
1353 User::Leave(KErrNotSupported);
1358 Creates a source buffer according to the specifed media ID and reference.
1360 Intended for asynchronous usage (buffers supplied by datapath for a MDataSource)
1361 This method is essentially a dummy implementation of an MDataSource pure virtual.
1363 The default implementation leaves with KErrNotSupported and returns NULL.
1366 An optional mediaID parameter when there are multiple buffers arriving of different media types.
1368 A boolean indicating buffer ownership. ETrue if the MDataSource owns the buffer, EFalse if the caller owns the buffer.
1370 @return A pointer to a newly created buffer. Returns NULL in this instance as datapath can't create source buffers.
1372 EXPORT_C CMMFBuffer* CMMFDataPath::CreateSourceBufferL(TMediaId /*aMediaId*/, TBool& /*aReference*/) //CMMFDataPath can't create buffers
1374 User::Leave(KErrNotSupported);
1380 Gets the source data type for the specified media ID.
1383 An optional parameter to specifiy specific stream when datasource contains more than one stream of data.
1385 @return The source data type.
1387 EXPORT_C TFourCC CMMFDataPath::SourceDataTypeCode(TMediaId /*aMediaId*/)
1389 return(iSourceFourCC);
1394 Allocates buffers in preparation to play.
1396 Must be called before calling PlayL().
1398 iSnkBufRef and iSrcBufRef contain ETrue if these buffers are created and owned by a MDataSource or MDataSink
1399 For clean-up purposes, datapath only cleans up buffers allocated directly by PrimeL().
1402 EXPORT_C void CMMFDataPath::PrimeL()
1405 RDebug::Print(_L("DP::PrimeL tick-%d (this 0x%x)\n"),User::TickCount(),this);
1408 //allocate resources ie buffers & prepare to play
1409 if (iDataPathCreated && (iState == EStopped))
1410 //luckily the client utility does this.
1411 {//can only prime from the stopped state
1413 //This will determine what buffers we need to run the datapath.
1414 //Can leave KERRNotSupported
1415 iBuffersToUse = DetermineBuffersToUseL();
1417 //Try to create source and sink buffers. If we can't create them in the Prime,
1418 //we will need to obtain them by asynchronous buffer creation when playing starts.
1419 ObtainSyncBuffersL();
1421 iDataSource->SourcePrimeL(); //propogate state change to source
1422 iDataSink->SinkPrimeL(); //propogate state change to sink
1425 //If Client has set these, they will be set following the prime
1426 iPlayWindowStartPosition = 0;
1427 iPlayWindowEndPosition = Duration();
1430 iPauseCalled = EFalse;
1432 if (iCompleteCallback)
1434 delete iCompleteCallback;
1435 iCompleteCallback = NULL;
1437 TBool waitForSink = (iDataSink->DataSinkType() == KUidMmfAudioOutput)?ETrue:EFalse;
1438 iCompleteCallback = new (ELeave) CCompleteCallback(*this,waitForSink);
1441 RDebug::Print(_L("DP::PrimeL Done tick-%d (this 0x%x)\n"),User::TickCount(),this);
1447 Starts an active scheduler 'play' loop.
1449 Can only play from the primed state.
1451 EXPORT_C void CMMFDataPath::PlayL()
1453 #if defined(__PROFILING)
1454 RDebug::ProfileEnd(1);
1455 #endif // defined(__PROFILING)
1458 RDebug::Print(_L("DP::PlayL, on src buff %d sink buf %d (this 0x%x)\n"), iCurrentSourceFrameNumber, iCurrentSinkFrameNumber,this);
1459 RDebug::Print(_L("iStartPosition = %d\n"), I64INT(iStartPosition.Int64()));
1462 if ((iDataPathCreated) && (iState == EPrimed))
1464 //can only play from the primed state
1466 TBool savedPauseCalled=EFalse;
1467 if(iPauseCalled) //sink and source will have been stopped, and we will not have been re-primed
1469 savedPauseCalled=ETrue;
1470 iDataSink->SinkPrimeL(); //propagate change down to sink
1471 iPauseCalled = EFalse;
1474 iCurrentSourceFrameNumber = 0; //reset to beginning
1475 iCurrentSinkFrameNumber = 0; //reset to beginning
1477 iSourceBufferWithSource = EFalse;
1478 iSinkBufferWithSink = EFalse;
1480 iNoMoreSourceData = EFalse;
1481 iAllDataSentToSink=EFalse;
1482 iDataPathCompletedErrorCode=KErrNone;
1484 SetPositionL( iStartPosition ) ;
1485 iReferenceAudioSamplesPlayed = 0;
1486 iReferenceAudioSamplesRecorded = 0;
1488 //complete a request on iStatus to invoke play code
1489 iDataSource->SourcePlayL(); //propagate state change to source
1490 if (!(savedPauseCalled && (iTransferState==EWaitSink || iTransferState==EInitializeSink)))
1492 iDataSink->SinkPlayL(); //propogate state change to sink
1495 if (iDataSink->DataSinkType() == KUidMmfAudioOutput)
1497 else if(iDataSource->DataSourceType() == KUidMmfAudioInput)
1498 iState = ERecording;
1500 iState = EConverting;
1502 //need to re-initialize any buffer(s) that we only own references to
1503 ChangeDataPathTransferState(EInitializeSink);
1506 RDebug::Print(_L("DP::Play - DONE\n"));
1514 Sends KMMFErrorCategoryDataPathGeneralError to the client if an error occurs.
1516 EXPORT_C void CMMFDataPath::Pause()
1519 RDebug::Print(_L("DP::Pause, on src buff %d sink buf %d (this 0x%x)\n"), iCurrentSourceFrameNumber, iCurrentSinkFrameNumber,this);
1520 RDebug::Print(_L("DP::Pause current state=%d tick-%d (this 0x%x)\n"),iTransferState, User::TickCount(),this);
1523 TRAPD(err, DoPauseL());
1527 DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
1530 RDebug::Print(_L("DP::Pause - DONE tick-%d (this 0x%x)\n"),User::TickCount(),this);
1537 Resets datapath position - currently does not clean up buffers. Sends KMMFErrorCategoryDataPathGeneralError
1538 to the client if an error occurs.
1540 EXPORT_C void CMMFDataPath::Stop()
1543 RDebug::Print(_L("DP::Stop current state=%d tick-%d (this 0x%x)\n"), iTransferState, User::TickCount(),this);
1546 if ((iDataPathCreated) && (iState != EStopped))
1548 TRAPD(err, DoStopL());
1551 DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
1555 Forces and end of data state on the datapath
1557 EXPORT_C void CMMFDataPath::EndOfData()
1559 TRAPD(err, DoEndOfDataL());
1563 DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
1570 TInt CMMFDataPath::AudioSamplesPlayed() const
1572 if (iDataSink->DataSinkType() != KUidMmfAudioOutput)
1575 CMMFAudioOutput* audioOutput = STATIC_CAST(CMMFAudioOutput*,iDataSink);
1579 if(iState == EPlaying)
1580 samples = audioOutput->SoundDevice().SamplesPlayed();
1583 RDebug::Print(_L("DP::AudioSamplesPlayed = %d\n"),samples);
1593 TInt CMMFDataPath::AudioSamplesRecorded() const
1595 if (iDataSource->DataSourceType() != KUidMmfAudioInput)
1598 CMMFAudioInput* audioInput = STATIC_CAST(CMMFAudioInput*,iDataSource);
1602 if(iState == ERecording)
1603 samples = audioInput->SoundDevice().SamplesRecorded();
1606 RDebug::Print(_L("DP::AudioSamplesRecorded = %d\n"),samples);
1616 TTimeIntervalMicroSeconds CMMFDataPath::CalculateAudioOutputPosition() const
1618 //This operation can only be carried out on an Audio Output
1619 __ASSERT_ALWAYS(iDataSink->DataSinkType() == KUidMmfAudioOutput, Panic(EMMFDataPathPanicProgrammingError,__LINE__));
1622 //If we are not playing, simply return where we will play from
1623 if(iState != EPlaying || iCurrentSinkFrameNumber == 0)
1624 return iStartPosition;
1627 RDebug::Print(_L("DP::CalculateAudioOutputDuration from %d\n"),iReferenceAudioSamplesPlayed);
1630 TReal samplesPlayed = AudioSamplesPlayed() - iReferenceAudioSamplesPlayed;
1632 CMMFAudioOutput* audioOutput = STATIC_CAST(CMMFAudioOutput*,iDataSink);
1633 CMMFDevSound& devSound = audioOutput->SoundDevice();
1635 TMMFCapabilities devSoundConfig = devSound.Config();
1637 TInt samplingFreq = StreamUtils::SampleRateAsValue(devSoundConfig);
1640 RDebug::Print(_L("samplingFreq %d\n"),samplingFreq);
1643 TReal timePlayedSeconds = 0;
1645 timePlayedSeconds = samplesPlayed/samplingFreq;
1647 TInt64 timePlayed(I64DOUBLECAST(timePlayedSeconds * 1000000));
1650 RDebug::Print(_L("timePlayed %d\n"), I64LOW(timePlayed));
1653 return TTimeIntervalMicroSeconds(timePlayed + iStartPosition.Int64());
1661 TTimeIntervalMicroSeconds CMMFDataPath::CalculateAudioInputPosition() const
1663 //This operation can only be carried out on an Audio Input
1664 __ASSERT_ALWAYS(iDataSource->DataSourceType() == KUidMmfAudioInput, Panic(EMMFDataPathPanicProgrammingError,__LINE__));
1667 //If we are not playing, simply return where we will play from
1668 if(iState != ERecording)
1669 return iStartPosition;
1672 RDebug::Print(_L("DP::CalculateAudioInputPosition from %d\n"),iReferenceAudioSamplesRecorded);
1675 TReal samplesRecorded = AudioSamplesRecorded() - iReferenceAudioSamplesRecorded;
1677 CMMFAudioInput* audioInput = STATIC_CAST(CMMFAudioInput*,iDataSource);
1678 CMMFDevSound& devSound = audioInput->SoundDevice();
1680 TMMFCapabilities devSoundConfig = devSound.Config();
1682 TInt samplingFreq = StreamUtils::SampleRateAsValue(devSoundConfig);
1685 RDebug::Print(_L("samplingFreq %d\n"),samplingFreq);
1688 TReal timeRecordedSeconds = 0;
1690 timeRecordedSeconds = samplesRecorded/samplingFreq;
1692 TInt64 timeRecorded(I64DOUBLECAST(timeRecordedSeconds * 1000000));
1695 RDebug::Print(_L("timeRecorded %d\n"), I64LOW(timeRecorded));
1697 return TTimeIntervalMicroSeconds(timeRecorded);
1704 TTimeIntervalMicroSeconds CMMFDataPath::OutputPosition() const
1706 TTimeIntervalMicroSeconds interval;
1707 TTimeIntervalMicroSeconds position;
1709 if (iDataSink->DataSinkType() == KUidMmfAudioOutput)
1711 position = CalculateAudioOutputPosition();
1713 RDebug::Print(_L("DP::OutputPosition from audio output= %d\n"),I64INT(position.Int64()));
1716 else if (iDataSink->DataSinkType() == KUidMmfFormatEncode)
1718 //note Encode format position takes priority if both source & sink are formats?
1719 // try to get the position directly from the format. If that fails, work it out here
1720 TRAPD(error, position = ((CMMFFormatEncode*)iDataSink)->PositionL());
1721 if (error)//getting the position from the format didn't work so calculate it here
1723 interval = ((CMMFFormatEncode*)iDataSink)->FrameTimeInterval(iMediaId);
1724 TInt64 position64 = interval.Int64() * iCurrentSinkFrameNumber;
1725 position = position64;
1728 TTimeIntervalMicroSeconds duration = CONST_CAST(CMMFDataPath*,this)->Duration(); //need this to check position doesn't exceed duration
1729 if (position > duration)//this can happen on last buffer
1730 position = duration;
1734 RDebug::Print(_L("DP::OutputPosition from format= %d\n"),I64INT(position.Int64()));
1738 {//can only read output position if sink is a format or an audio output
1739 return TTimeIntervalMicroSeconds(0);
1745 TTimeIntervalMicroSeconds CMMFDataPath::InputPosition() const
1747 TTimeIntervalMicroSeconds interval;
1748 TTimeIntervalMicroSeconds position;
1750 if (iDataSource->DataSourceType() == KUidMmfAudioInput)
1752 position = CalculateAudioInputPosition();
1754 RDebug::Print(_L("DP::InputPosition from audio input= %d\n"),I64INT(position.Int64()));
1757 else if (iDataSource->DataSourceType() == KUidMmfFormatDecode)
1758 {//note Decode format position takes priority if both source & sink are formats?
1759 // try to get the position directly from the format. If that fails, work it out here
1760 TRAPD(error, position = ((CMMFFormatDecode*)iDataSource)->PositionL());
1761 if (error)//getting the position from the format didn't work so calculate it here
1763 interval = ((CMMFFormatDecode*)iDataSource)->FrameTimeInterval(iMediaId);
1764 TInt64 position64 = interval.Int64() * iCurrentSourceFrameNumber;
1765 position = position64;
1768 TTimeIntervalMicroSeconds duration = CONST_CAST(CMMFDataPath*,this)->Duration(); //need this to check position doesn't exceed duration
1769 if (position > duration)//this can happen on last buffer
1770 position = duration;
1773 RDebug::Print(_L("DP::InputPosition from format = %d\n"),I64INT(position.Int64()));
1777 {//can only read input position if source is a format or an audio input
1778 return TTimeIntervalMicroSeconds(0);
1788 Gets the data path position.
1790 @return The data path position.
1792 EXPORT_C TTimeIntervalMicroSeconds CMMFDataPath::Position() const
1794 if ((iState == ERecording) || (iState == EConverting))
1795 return InputPosition();
1796 else if(iState == EPlaying)
1797 return OutputPosition();
1800 return iStartPosition;
1805 Sets the data path position.
1808 The data path position.
1810 EXPORT_C void CMMFDataPath::SetPositionL(const TTimeIntervalMicroSeconds& aPosition)
1811 {//need to map to source position to frame position
1813 RDebug::Print(_L("DP::SetPositionL = %d ticks-%d (this 0x%x)\n"),I64INT(aPosition.Int64()), User::TickCount(),this);
1816 if (iState == EStopped)
1817 User::Leave(KErrNotReady); //can only set position if primed
1819 //As this will affect the position, we need to know how many bytes were
1820 //played when position was updated. Future Position() requests will
1821 //then use this refernce to determine the current position.
1822 iReferenceAudioSamplesPlayed = AudioSamplesPlayed();
1824 // Force the new position to be inside the play window (also within the file duration)
1825 if ( aPosition < iPlayWindowStartPosition )
1826 iStartPosition = iPlayWindowStartPosition;
1827 else if ( aPosition > iPlayWindowEndPosition )
1828 iStartPosition = iPlayWindowEndPosition; //clearly this will cause nothing to be played
1830 iStartPosition = aPosition;
1832 TTimeIntervalMicroSeconds interval;
1834 //can only set the position on an MDataSource that is a format object
1835 //Note: position defaults to source if both source & sink are clips
1836 if (iDataSource->DataSourceType() == KUidMmfFormatDecode)
1838 //position is not beyond the end of file
1839 interval = ((CMMFFormatDecode*)iDataSource)->FrameTimeInterval(iMediaId);
1841 // for some reason this code won't compile without these intermediate steps
1842 TInt64 position = iStartPosition.Int64();
1843 TInt64 interval64 = interval.Int64();
1844 if (interval64 == 0)
1845 User::Leave(KErrDivideByZero);
1846 TInt64 datapos64 = position/interval64;
1847 iCurrentSourceFrameNumber = I64LOW(datapos64);
1850 // Try to set the position directly on the format
1851 TRAP_IGNORE(((CMMFFormatDecode*)iDataSource)->SetPositionL(iStartPosition));
1852 //NB: don't worry about error, since we'll reposition anyway when we get the next buffer
1854 else if (iDataSink->DataSinkType() == KUidMmfFormatEncode)
1856 //position is not beyond the end of file
1857 interval = ((CMMFFormatEncode*)iDataSink)->FrameTimeInterval(iMediaId);
1859 //convert to TUint - for some reason it won't compile without these intermediate steps
1860 TInt64 position = iStartPosition.Int64();
1861 TInt64 interval64 = interval.Int64();
1862 if (interval64 == 0)
1863 User::Leave(KErrDivideByZero);
1864 TInt64 datapos64 = position/interval64;
1865 iCurrentSinkFrameNumber = I64LOW(datapos64);
1868 // Try to set the position directly on the format
1869 TRAP_IGNORE(((CMMFFormatEncode*)iDataSink)->SetPositionL(iStartPosition));
1870 //NB: don't worry about error, since we'll reposition anyway when we get the next buffer
1873 {//can only set position if source or sink is a format
1874 //If both source and sink are formats position is relative to the source
1875 User::Leave(KErrNotSupported); //can't set position if neither source nor sink are clips
1878 if(iCodec) //we have a real codec, must reset it
1879 iCodec->ResetL(); // Need to preserve sync when resuming play
1881 // Once we've sent the last buffer to the sink it's too late to start
1882 // changing the state since we may get a RunError(KErrUnderflow) at any time.
1883 // Once this happens, the sound driver may have unloaded etc..and recovery
1884 // would be complicated.
1885 if (iAllDataSentToSink)
1889 RDebug::Print(_L("DP::SetPosition - Done iCurrentSourceFrameNumber=%d iStartPosition=%d ticks-%d (this 0x%x)\n"),iCurrentSourceFrameNumber, I64INT(iStartPosition.Int64()), User::TickCount(),this);
1897 Sets the play window absolutely (i.e. the parameters are relative to the start of the entire clip).
1900 The offset from the start of the Clip
1902 The offset from the end of the clip (if this is less than aStart, then the two will be inverted).
1904 EXPORT_C void CMMFDataPath::SetPlayWindowL( const TTimeIntervalMicroSeconds& aStart, const TTimeIntervalMicroSeconds& aEnd )
1906 // Clear the existing Play window
1907 ClearPlayWindowL() ;
1909 // Check that the parameters are legitimate. 0 <= startpos < endpos <= duration & update member variables
1910 TTimeIntervalMicroSeconds duration = Duration();
1912 if ( aStart < TTimeIntervalMicroSeconds(0) )
1913 iPlayWindowStartPosition = TTimeIntervalMicroSeconds(0);
1914 else if ( aStart > duration )
1915 iPlayWindowStartPosition = duration;
1916 else iPlayWindowStartPosition = aStart;
1918 if ( aEnd < TTimeIntervalMicroSeconds(0) )
1919 iPlayWindowEndPosition = TTimeIntervalMicroSeconds(0);
1920 else if ( aEnd > duration )
1921 iPlayWindowEndPosition = duration;
1922 else iPlayWindowEndPosition = aEnd;
1924 // ensure that the current position is inside the new play window
1925 if ( iPlayWindowEndPosition != TTimeIntervalMicroSeconds(0) )
1927 TTimeIntervalMicroSeconds currentPosition = Position() ;
1928 if ( currentPosition < iPlayWindowStartPosition )
1929 SetPositionL( iPlayWindowStartPosition ) ;
1930 else if ( currentPosition > iPlayWindowEndPosition )
1931 SetPositionL( iPlayWindowEndPosition ) ;
1934 ClearPlayWindowL() ;
1937 RDebug::Print(_L("DP::SetPlayWindowL iPlayWindowStartPosition=%d iPlayWindowEndPosition=%d\n"),I64INT(iPlayWindowStartPosition.Int64()),I64INT(iPlayWindowEndPosition.Int64()));
1943 Sets the play window to the full length of clip.
1945 EXPORT_C void CMMFDataPath::ClearPlayWindowL()
1947 iPlayWindowStartPosition = TTimeIntervalMicroSeconds(0) ;
1948 iPlayWindowEndPosition = Duration();
1951 if(iState == EStopped)
1952 iStartPosition = iPlayWindowStartPosition;
1956 Returns the current data path state.
1958 EXPORT_C TInt CMMFDataPath::State()
1965 Uses the AO mechanism to drive state changes between sources and sinks.
1967 RunL() moves and assigns buffers between its attached MDataSource/MDataSinks.
1969 void CMMFDataPath::ChangeDataPathTransferState(TTransferState aNewDataPathTransferState)
1972 switch (aNewDataPathTransferState)
1975 RDebug::Print(_L("Next State EWaitSink ticks-%d (this 0x%x)\n"),User::TickCount(),this);
1978 RDebug::Print(_L("Next State EWaitSource ticks-%d (this 0x%x)\n"),User::TickCount(),this);
1980 case EInitializeSink:
1981 RDebug::Print(_L("Next State EInitializeSink ticks-%d (this 0x%x)\n"),User::TickCount(),this);
1983 case EInitializeSource:
1984 RDebug::Print(_L("Next State EInitializeSource ticks-%d (this 0x%x)\n"),User::TickCount(),this);
1986 case ENeedSourceData:
1987 RDebug::Print(_L("Next State ENeedSourceData ticks-%d (this 0x%x)\n"),User::TickCount(),this);
1990 RDebug::Print(_L("Next State ENeedSinkData ticks-%d (this 0x%x)\n"),User::TickCount(),this);
1992 case ENeedToMatchSourceToSink:
1993 RDebug::Print(_L("Next State ENeedToMatchSourceToSink ticks-%d (this 0x%x)\n"),User::TickCount(),this);
1995 case ESendDataToSink:
1996 RDebug::Print(_L("Next State ESendDataToSink ticks-%d (this 0x%x)\n"),User::TickCount(),this);
1999 RDebug::Print(_L("Next State EEndOfData ticks-%d (this 0x%x)\n"),User::TickCount(),this);
2005 TRequestStatus* stat = &iStatus;
2007 iTransferState = aNewDataPathTransferState;
2008 if ((iTransferState != EWaitSink) && (iTransferState != EWaitSource) &&
2009 (iState == EPlaying || iState == ERecording || iState == EConverting || (iState == EPrimed && iPauseCalled)))
2010 {//can go ahead with transfer
2013 User::RequestComplete(stat, KErrNone);
2019 RDebug::Print(_L("Datapath is no longer active, not going to new state (this 0x%x)\n"),this);
2024 Runs the clip depending on the current data path and transfer state.
2026 For example, fills the sink buffer if TDataPathState is EPlaying and TTransferState is ENeedSinkData.
2028 EXPORT_C void CMMFDataPath::RunL()
2031 RDebug::Print(_L("DP::RunL tick-%d (this 0x%x)\n"),User::TickCount(),this);
2039 //paused with stored position
2044 switch (iTransferState)
2049 case EInitializeSink:
2052 case EInitializeSource:
2053 InitializeSourceL();
2055 case ENeedSourceData:
2056 FillSourceBufferL();
2061 case ENeedToMatchSourceToSink:
2064 case ESendDataToSink:
2076 RDebug::Print(_L("DP::RunL DONE\n"));
2083 The default implementation is empty.
2085 EXPORT_C void CMMFDataPath::DoCancel()
2087 //don't need to do anything as we don't have any async requests to other objects
2091 Handles errors coming from attached sources and passes them to the clients.
2094 Standard error code (KErrNone = No Error).
2096 @return The event code returned to the data path. KErrNone if end of file is encountered.
2098 EXPORT_C TInt CMMFDataPath::RunError(TInt aError)
2100 return DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, aError);
2105 Returns the duration of the clip.
2107 @return The length of clip in TTimeIntervalMicroSeconds.
2109 TTimeIntervalMicroSeconds CMMFDataPath::Duration() const
2111 TTimeIntervalMicroSeconds duration(0);
2113 if ( iDataSource && ( iDataSource->DataSourceType() == KUidMmfFormatDecode ) )
2115 //this updated version of datapath caches the duration of the
2116 //source clip for efficiency - since this meathod is const
2117 //we need to cast away the constness to set iCachedSourceDuration
2118 CMMFDataPath* thisNonConst = const_cast<CMMFDataPath*>(this);
2119 duration = STATIC_CAST(CMMFFormatDecode*, thisNonConst->iDataSource )->Duration( iMediaId ) ;
2120 thisNonConst->iCachedSourceDuration = duration;
2122 else if ( iDataSink && ( iDataSink->DataSinkType() == KUidMmfFormatEncode ) )
2123 duration = STATIC_CAST(CMMFFormatEncode*, iDataSink )->Duration( iMediaId ) ;
2129 This is a virtual function datapath (or derivations off) that can be implemented but may be left blank for default behaviour.
2131 Additional Stop() method specific to this datapath.
2133 void CMMFDataPath::DoStopL()
2135 // Note that the datapath needs to be paused first
2136 // before it can be stopped - this is important for audio play
2137 // for instance to effect an immediate stop rather than playing out
2138 // the current buffer.
2142 // Stop data source and sink
2143 iDataSource->SourceStopL(); // propagate state change to source
2144 iDataSink->SinkStopL(); // propagate change down to sink
2146 iSinkBufferWithSink = EFalse;
2147 iSourceBufferWithSource = EFalse;
2149 //Contains the completion code if the datapath completes as a result of an error
2150 iDataPathCompletedErrorCode = KErrNone;
2152 ResetRefBuffers(); // buffer references may not be valid any more
2154 SetPositionL(iPlayWindowStartPosition); // reset position
2156 iState = EStopped; // stop succeeded, set state to stopped
2160 This is a virtual function datapath (or derivations off) that can be implemented but may be left blank for default behaviour.
2162 Additional Pause method specific to this datapath.
2164 The DataPath implements pause by recording the current position and stopping the source and sink.
2165 When Play is called the DataPath uses the stored position as the starting point and resumes
2166 playing. The reason for this (rather than using the PauseL() API on sources and sinks) is that
2167 some implementations do not support a suitable pause, therefore the DataPath is implemented to
2168 support the lowest common denominator.
2171 A suitable pause implementation will retain any buffers in use. There will be no
2172 need to call PrimeL() prior to PlayL().
2174 void CMMFDataPath::DoPauseL()
2177 RDebug::Print(_L("DP::DoPauseL tick-%d (this 0x%x)\n"),User::TickCount(),this);
2181 if ((iDataPathCreated) && ((iState == EPlaying) || (iState == EConverting)))
2183 // try to pause source and sink
2184 iDataSource->SourcePauseL(); // propagate state change to source
2185 SetPositionL(Position());
2186 iDataSink->SinkStopL();
2188 iPauseCalled = ETrue; // indicate pause is called
2190 iState = EPrimed; // go back to primed state (we're not playing)
2192 iSinkBufferWithSink = EFalse;
2193 iSourceBufferWithSource = EFalse;
2195 ResetRefBuffers(); // buffer references may not be valid any more
2197 Cancel(); //Stop the state machine
2199 else if(iState == ERecording)
2201 iPauseCalled = ETrue;
2203 RDebug::Print(_L("DP::DoPauseL Recording, pause datasource\n"));
2205 iDataSource->SourcePauseL();
2208 RDebug::Print(_L("DP::DoPauseL - Done iReferenceAudioSamplesPlayed = %d\n"),iReferenceAudioSamplesPlayed);
2209 RDebug::Print(_L("DP::DoPauseL - Done restart at %d tick-%d (this 0x%x)\n"),I64INT(iStartPosition.Int64()), User::TickCount(),this);
2214 This is a virtual function datapath (or derivations off) that can be implemented or may be left blank for default behaviour.
2216 Additional Pause method specific to this datapath.
2218 void CMMFDataPath::DoEndOfDataL()
2221 RDebug::Print(_L("DP::DoEndOfDataL tick-%d (this 0x%x)\n"),User::TickCount(),this);
2223 SetPositionL(iPlayWindowStartPosition); // reset position
2225 ASSERT(iCompleteCallback);
2226 iCompleteCallback->SignalDataPathComplete(iDataPathCompletedErrorCode);
2232 RDebug::Print(_L("DP::DoEndOfDataL - Done tick-%d (this 0x%x)\n"),User::TickCount(),this);
2238 Passes error handling and general messages up to clients.
2241 Category code for the event. Category codes can be used as unique identifers.
2243 Standard error code.
2245 @return The event code sent to client.
2248 EXPORT_C TInt CMMFDataPath::DoSendEventToClient(TUid aEventType, TInt aErrorCode)
2250 TMMFEvent event(aEventType, aErrorCode);
2251 return iEventHandler.SendEventToClient(event);
2255 Passes error handling and general messages to clients.
2258 TMMFEvent supplied by callee (typically DoSendEventToClient)
2260 @return The Event Message sent to the datapath event handler
2262 EXPORT_C TInt CMMFDataPath::SendEventToClient(const TMMFEvent& aEvent)
2265 RDebug::Print(_L("CMMFDataPath::SendEventToClient CODE = %d ticks=%d (this 0x%x)\n"),aEvent.iErrorCode,User::TickCount(),this);
2266 RDebug::Print(_L("CMMFDataPath::SendEventToClient iEventType = %d == %d\n"),aEvent.iEventType, KMMFEventCategoryPlaybackComplete);
2269 //If we have sent all the data to the sink, it is legal for it to send KErrUnderFlow
2270 //to us and we can go through a clean shutdown, otherwise we pass the error to the
2271 //controller and it is responsible for determining what to do
2272 if(iAllDataSentToSink &&
2273 (aEvent.iEventType == KMMFEventCategoryPlaybackComplete) &&
2274 (aEvent.iErrorCode == KErrUnderflow))
2277 RDebug::Print(_L("CMMFDataPath::SendEventToClient Clean complete\n"));
2279 //sink may not return the final buffer once it has finished with it
2280 //force ourselves into the EndOfData state
2281 if(iTransferState != EEndOfData)
2283 iDataPathCompletedErrorCode = KErrNone;
2284 TRAP_IGNORE(DoEndOfDataL());
2287 iCompleteCallback->SignalSinkComplete(KErrNone);
2293 return iEventHandler.SendEventToClient(aEvent);
2296 CMMFDataPath::CCompleteCallback::CCompleteCallback(CMMFDataPath& aDataPath, TBool aWaitForSink)
2297 : CActive(EPriorityStandard),
2298 iDataPath(aDataPath),
2299 iWaitForSink(aWaitForSink)
2301 CActiveScheduler::Add(this);
2304 CMMFDataPath::CCompleteCallback::~CCompleteCallback()
2309 void CMMFDataPath::CCompleteCallback::SignalDataPathComplete(TInt aDataPathError)
2311 iDataPathComplete = ETrue;
2312 iDataPathError = aDataPathError;
2315 // Signal ourselves to run with the given completion code
2316 TRequestStatus* status = &ActiveStatus();
2317 User::RequestComplete(status, KErrNone);
2321 void CMMFDataPath::CCompleteCallback::SignalSinkComplete(TInt aSinkError)
2323 iSinkComplete = ETrue;
2324 iSinkError = aSinkError;
2327 // Signal ourselves to run with the given completion code
2328 TRequestStatus* status = &ActiveStatus();
2329 User::RequestComplete(status, KErrNone);
2334 TRequestStatus& CMMFDataPath::CCompleteCallback::ActiveStatus()
2340 void CMMFDataPath::CCompleteCallback::DoCancel()
2344 void CMMFDataPath::CCompleteCallback::RunL()
2348 if (iDataPathComplete && iSinkComplete)
2351 RDebug::Print(_L("CMMFDataPath::CCompleteCallback::RunL STOPPING src & sink ticks=%d (this 0x%x)\n"),User::TickCount(),this);
2354 TRAP_IGNORE(iDataPath.DoStopL())
2356 iDataPathComplete = EFalse;
2357 iSinkComplete = EFalse;
2359 // if we have to wait for the sink to complete, always use the sink error
2360 iDataPath.DoSendEventToClient(KMMFEventCategoryPlaybackComplete, iSinkError);
2363 else if (iDataPathComplete)
2366 RDebug::Print(_L("CMMFDataPath::CCompleteCallback::RunL STOPPING src & sink ticks=%d (this 0x%x)\n"),User::TickCount(),this);
2369 TRAP_IGNORE(iDataPath.DoStopL())
2371 iDataPathComplete = EFalse;
2372 iSinkComplete = EFalse;
2374 iDataPath.DoSendEventToClient(KMMFEventCategoryPlaybackComplete, iDataPathError);
2378 EXPORT_C TInt CMMFDataPath::SetBlockLength(TUint aBlockLength)
2380 MMMFDevSoundCustomInterfaceFileBlockLength* fileBlockLengthCI = NULL;
2381 TInt err = KErrNotSupported;
2384 err = iCodec->ExtensionInterface(KUidCustomInterfaceDevSoundFileBlockLength.iUid, (TAny*&)fileBlockLengthCI);
2387 if (err == KErrNone)
2389 fileBlockLengthCI->SetFileBlockLength(aBlockLength);