1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/mm/mmlibs/mmfw/src/server/BaseClasses/mmfdatapath2.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1122 @@
1.4 +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// source\server\mmfdatapath2.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#include <e32math.h>
1.22 +#include <mmf/common/mmffourcc.h>
1.23 +#include <mmf/common/mmfpaniccodes.h>
1.24 +#include <mmf/server/mmfaudiooutput.h>
1.25 +#include <mmf/server/mmfaudioinput.h>
1.26 +#include "mmfdatapath2.h"
1.27 +#include "mmfclientaudiostreamutils.h"
1.28 +#include <mmf/common/mmfaudio.h>
1.29 +#include <mmf/plugin/mmfcodecimplementationuids.hrh> // KUidMmfCodecAudioSettings
1.30 +#include <mmf/server/devsoundstandardcustominterfaces.h>
1.31 +#include <mmf/server/mmffile.h>
1.32 +#include <mda/client/resource.h>
1.33 +
1.34 +static void Panic(TMMFDataPathPanicCode aPanicCode, TInt aSourceLineNumber)
1.35 + {
1.36 + _LIT(KMMFDataPathPanicCategory, "MMFDataPath2");
1.37 + User::Panic(KMMFDataPathPanicCategory, STATIC_CAST(TInt,aPanicCode) + aSourceLineNumber);
1.38 + }
1.39 +
1.40 +/**
1.41 +Allocates and constructs a data path.
1.42 +
1.43 +Use this function if the codec UID is not already known by CMMFController
1.44 +and there is no data path ambiguity - ie only one data path is possible.
1.45 +
1.46 +Will create codec via fourCC.
1.47 +
1.48 +@param aEventHandler
1.49 + Installs an event handler to provide message passing between clients and sources/sinks.
1.50 +
1.51 +@return Newly constructed data path object.
1.52 +*/
1.53 +
1.54 +EXPORT_C CMMFDataPath2* CMMFDataPath2::NewL(MAsyncEventHandler& aEventHandler)
1.55 + {
1.56 + CMMFDataPath2* self = new(ELeave) CMMFDataPath2(TMediaId(), aEventHandler);
1.57 + CleanupStack::PushL(self);
1.58 + self->ConstructL();
1.59 + CleanupStack::Pop();
1.60 + return self;
1.61 + }
1.62 +
1.63 +
1.64 +/**
1.65 +Allocates and constructs a data path according to the specified media ID.
1.66 +
1.67 +Use this function if the codec UID is not already known by CMMFController
1.68 +and there is ambiguity with the data path ie. there is more than one possible data path.
1.69 +
1.70 +@param aMediaId
1.71 + Optional media ID parameter when there are multiple media types.
1.72 +@param aEventHandler
1.73 + Installs an event handler to provide message passing between clients and sources/sinks.
1.74 +
1.75 +@return A newly constructed data path object.
1.76 +*/
1.77 +
1.78 +EXPORT_C CMMFDataPath2* CMMFDataPath2::NewL(TMediaId aMediaId, MAsyncEventHandler& aEventHandler)
1.79 + {
1.80 + CMMFDataPath2* self = new(ELeave) CMMFDataPath2(aMediaId, aEventHandler);
1.81 + CleanupStack::PushL(self);
1.82 + self->ConstructL();
1.83 + CleanupStack::Pop();
1.84 + return self;
1.85 + }
1.86 +
1.87 +/**
1.88 +Allocates and constructs a data path according to the specified codec UID.
1.89 +
1.90 +Use this function if the codec UID is already known by CMMFController
1.91 +and there is no data path ambiguity ie. only one data path is possible
1.92 +will create codec explicitly using the supplied codec Uid
1.93 +
1.94 +@param aCodecUid
1.95 + Optional mediaID parameter when there are multiple media types
1.96 +@param aEventHandler
1.97 + Installs an event handler to provide message passing between clients and sources/sinks.
1.98 +
1.99 +@return A newly constructed data path object.
1.100 +*/
1.101 +
1.102 +EXPORT_C CMMFDataPath2* CMMFDataPath2::NewL(TUid aCodecUid, MAsyncEventHandler& aEventHandler)
1.103 + {
1.104 + CMMFDataPath2* self = new(ELeave) CMMFDataPath2(TMediaId(), aEventHandler);
1.105 + CleanupStack::PushL(self);
1.106 + self->ConstructL(aCodecUid);
1.107 + CleanupStack::Pop();
1.108 + return self;
1.109 + }
1.110 +
1.111 +
1.112 +/**
1.113 +Allocates and constructs a data path according to the specified codec UID.
1.114 +
1.115 +Use this function if the codec UID is already known by CMMFController
1.116 +and there is ambiguity ie. more than one possible data path.
1.117 +TMediaId used to select the path.
1.118 +
1.119 +@param aCodecUid
1.120 + The codec UID.
1.121 +@param aMediaId
1.122 + Optional mediaID parameter when there are multiple media types.
1.123 +@param aEventHandler
1.124 + Installs an event handler to provide message passing between clients and sources/sinks.
1.125 +
1.126 +@return A newly constructed data path object.
1.127 +*/
1.128 +EXPORT_C CMMFDataPath2* CMMFDataPath2::NewL(TUid aCodecUid, TMediaId aMediaId, MAsyncEventHandler& aEventHandler)
1.129 + {
1.130 + CMMFDataPath2* self = new(ELeave) CMMFDataPath2(aMediaId, aEventHandler);
1.131 + CleanupStack::PushL(self);
1.132 + self->ConstructL(aCodecUid);
1.133 + CleanupStack::Pop();
1.134 + return self;
1.135 + }
1.136 +
1.137 +CMMFDataPath2::CMMFDataPath2(TMediaId aMediaId, MAsyncEventHandler& aEventHandler)
1.138 + : CMMFDataPath(aMediaId, aEventHandler), iTimeLeftToPlayComplete(-1)
1.139 + {
1.140 + }
1.141 +
1.142 +void CMMFDataPath2::ConstructL(TUid aCodecUid)
1.143 + {
1.144 + CMMFDataPath::ConstructL(aCodecUid);
1.145 + iRepeatTrailingSilenceTimer = CPeriodic::NewL(CActive::EPriorityStandard);
1.146 + }
1.147 +
1.148 +/**
1.149 +Standard destructor.
1.150 +*/
1.151 +
1.152 +CMMFDataPath2::~CMMFDataPath2()
1.153 + {
1.154 + if(iRepeatTrailingSilenceTimer)
1.155 + {
1.156 + iRepeatTrailingSilenceTimer->Cancel();
1.157 + delete iRepeatTrailingSilenceTimer;
1.158 + }
1.159 + }
1.160 +
1.161 +TInt CMMFDataPath2::RepeatTrailingSilenceTimerComplete(TAny* aDataPath)
1.162 + {
1.163 + CMMFDataPath2* dataPath = static_cast<CMMFDataPath2*>(aDataPath);
1.164 +
1.165 + TRAPD(err, dataPath->DoRepeatTrailingSilenceTimerCompleteL());
1.166 + if (err != KErrNone)
1.167 + {
1.168 + dataPath->DoSendEventToClient(KMMFEventCategoryPlaybackComplete, err);
1.169 + }
1.170 + return KErrNone;
1.171 + }
1.172 +
1.173 +TInt CMMFDataPath2::DoRepeatTrailingSilenceTimerCompleteL()
1.174 + {
1.175 + //cancel this periodic timer
1.176 + iRepeatTrailingSilenceTimer->Cancel();
1.177 + if(iTimeLeftToPlayComplete.Int64()>0)
1.178 + {
1.179 + iTimeLeftToPlayComplete=0;
1.180 + }
1.181 +
1.182 + if (iTrailingSilenceLeftToPlay.Int64() > 0)
1.183 + {
1.184 + PlaySilence();
1.185 + }
1.186 + else
1.187 + {
1.188 + SetPositionL(iPlayWindowStartPosition);
1.189 + iTimeLeftToPlayComplete=-1;
1.190 + FillSourceBufferL();
1.191 + }
1.192 + return KErrNone;
1.193 + }
1.194 +
1.195 +void CMMFDataPath2::PlaySilence()
1.196 + {
1.197 + // iRepeatTrailingSilenceTimer->After() takes a TTimeIntervalMicroSeconds32
1.198 + // so for longer periods of silence call it repeatedly with KMaxTInt lengths
1.199 + TTimeIntervalMicroSeconds32 silence;
1.200 + if(iTimeLeftToPlayComplete.Int64() > 0)
1.201 + {
1.202 + silence = I64INT(iTimeLeftToPlayComplete.Int64());
1.203 + }
1.204 + else if (iTrailingSilenceLeftToPlay.Int64() > KMaxTInt)
1.205 + {
1.206 + silence = KMaxTInt;
1.207 + iTrailingSilenceLeftToPlay = iTrailingSilenceLeftToPlay.Int64() - KMaxTInt;
1.208 + }
1.209 + else
1.210 + {
1.211 + silence = I64INT(iTrailingSilenceLeftToPlay.Int64());
1.212 + iTrailingSilenceLeftToPlay = 0;
1.213 + }
1.214 + iRepeatTrailingSilenceTimer->Start(silence, silence , TCallBack(RepeatTrailingSilenceTimerComplete, this));
1.215 + }
1.216 +
1.217 +/*
1.218 + * FillSourceBufferL
1.219 + *
1.220 + * Function to get data from the datapath's iDataSource
1.221 + */
1.222 +
1.223 +void CMMFDataPath2::DoFillSourceBufferL()
1.224 + {
1.225 +#ifdef _DP_DEBUG
1.226 + RDebug::Print(_L("DP::FillSourceBufferL tick-%d (this 0x%x)\n"),User::TickCount(),this);
1.227 +#endif
1.228 +
1.229 + __ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording || (iState == EPrimed && iPauseCalled && iIsUsingResumeSupport)), Panic(EMMFDataPathPanicBadState,__LINE__));
1.230 +
1.231 + // clear the no-more-source flag here (as well as in PlayL()) because
1.232 + // there may have been a re-position since the last call to BufferFilledL()
1.233 + iNoMoreSourceData = EFalse;
1.234 +
1.235 + if(!iObtainingAsyncSourceBuffer)
1.236 + {//this is a normal request for data.
1.237 + //If we are getting asynchronous buffers, then can't do this as iSourceBuffer == NULL
1.238 + iSourceBuffer->SetFrameNumber(++iCurrentSourceFrameNumber); //so source knows which data to load buffer with
1.239 + iSourceBuffer->SetStatus(EBeingFilled);
1.240 + iSourceBuffer->SetLastBuffer(EFalse);
1.241 + }
1.242 +
1.243 +#ifdef _DP_DEBUG
1.244 + RDebug::Print(_L("DP asking for buffer %d - ptr=0x%x (this 0x%x)\n"), iCurrentSourceFrameNumber, iSourceBuffer,this);
1.245 +#endif
1.246 +
1.247 + iSourceBufferWithSource = ETrue;
1.248 +
1.249 + // wait for BufferFilled callback from source. Do this here as some sources cause
1.250 + //re-entrancy into data path via BufferFilledL
1.251 + ChangeDataPathTransferState(EWaitSource);
1.252 +
1.253 + iDataSource->FillBufferL(iSourceBuffer, this, iMediaId);
1.254 +
1.255 +#ifdef _DP_DEBUG
1.256 + RDebug::Print(_L("DP::FillSourceBufferL - DONE tick-%d (this 0x%x)\n"),User::TickCount(),this);
1.257 +#endif
1.258 + }
1.259 +
1.260 +/**
1.261 +Runs the clip depending on the current data path and transfer state.
1.262 +
1.263 +For example, fills the sink buffer if TDataPathState is EPlaying and TTransferState is ENeedSinkData.
1.264 +*/
1.265 +void CMMFDataPath2::RunL()
1.266 + {
1.267 +#ifdef _DP_DEBUG
1.268 + RDebug::Print(_L("DP::RunL transfer state %d, iPausedCalled %d, tick-%d (this 0x%x)\n"),iTransferState, iPauseCalled, User::TickCount(),this);
1.269 +#endif
1.270 +
1.271 + switch (iState)
1.272 + {
1.273 + case EStopped:
1.274 + break;
1.275 + case EPrimed: // In the paused state we still continue to feed buffers to the sink. The sink (DevSound) handles the logic of whether the buffers should be emptied
1.276 + {
1.277 + if (!iPauseCalled || !iIsUsingResumeSupport)
1.278 + break;
1.279 + }
1.280 + // fall-through
1.281 + case EPlaying:
1.282 + case ERecording:
1.283 + case EConverting:
1.284 + switch (iTransferState)
1.285 + {
1.286 + case EWaitSink:
1.287 + case EWaitSource:
1.288 + break;
1.289 + case EInitializeSink:
1.290 + InitializeSinkL();
1.291 + break;
1.292 + case EInitializeSource:
1.293 + InitializeSourceL();
1.294 + break;
1.295 + case ENeedSourceData:
1.296 + FillSourceBufferL();
1.297 + break;
1.298 + case ENeedSinkData:
1.299 + FillSinkBufferL();
1.300 + break;
1.301 + case ENeedToMatchSourceToSink:
1.302 + FillSinkBufferL();
1.303 + break;
1.304 + case ESendDataToSink:
1.305 + EmptySinkBufferL();
1.306 + break;
1.307 + case EEndOfData:
1.308 + EndOfData();
1.309 + break;
1.310 + }
1.311 + break;
1.312 + default:
1.313 + break;
1.314 + }
1.315 +#ifdef _DP_DEBUG
1.316 + RDebug::Print(_L("DP::RunL DONE\n"));
1.317 +#endif
1.318 + }
1.319 +
1.320 +/*
1.321 + * FillSourceBufferL
1.322 + *
1.323 + * Function to get data from the datapath's iDataSource
1.324 + */
1.325 +
1.326 +void CMMFDataPath2::FillSourceBufferL()
1.327 + {
1.328 + __ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording || (iState == EPrimed && iPauseCalled && iIsUsingResumeSupport) ), Panic(EMMFDataPathPanicBadState,__LINE__));
1.329 +
1.330 + //if the silence timer is active then dont propagate the request
1.331 + if(iRepeatTrailingSilenceTimer->IsActive())
1.332 + {
1.333 + return;
1.334 + }
1.335 +
1.336 + //play the silence period and dont propagate the request
1.337 + if(iTrailingSilenceLeftToPlay>0 || iVerifyPlayComplete)
1.338 + {
1.339 + if(iVerifyPlayComplete)//case when the trailing silence is zero
1.340 + {
1.341 + if (!*iDisableAutoIntent && iDrmSource)
1.342 + {
1.343 + CMMFFile* file = static_cast<CMMFFile*>(iDrmSource);
1.344 + TInt err = file->ExecuteIntent(ContentAccess::EPlay);
1.345 + if (err != KErrNone)
1.346 + {
1.347 + DoSendEventToClient(KMMFEventCategoryPlaybackComplete, err);
1.348 + return;
1.349 + }
1.350 + }
1.351 +
1.352 + //Retrieve the current play time and add "duration-currentplaytime" to the silence period
1.353 + //This is to ensure that silence timer is not started before the previous play is actually completed by the devsound
1.354 + TTimeIntervalMicroSeconds currentTime = CalculateAudioOutputPosition();
1.355 + if(currentTime.Int64()>iPlayWindowStartPosition.Int64())
1.356 + {
1.357 + iTimeLeftToPlayComplete = iPlayWindowEndPosition.Int64()-currentTime.Int64();
1.358 + }
1.359 + else
1.360 + {
1.361 + iTimeLeftToPlayComplete = 0;
1.362 + }
1.363 +
1.364 + iVerifyPlayComplete = EFalse;
1.365 + }
1.366 + if(iTrailingSilenceLeftToPlay==0 && iTimeLeftToPlayComplete==0)
1.367 + {
1.368 + SetPositionL(iPlayWindowStartPosition);
1.369 + iTimeLeftToPlayComplete=-1;
1.370 + }
1.371 + else
1.372 + {
1.373 + PlaySilence();
1.374 + return;
1.375 + }
1.376 + }
1.377 +
1.378 + DoFillSourceBufferL();
1.379 + }
1.380 +
1.381 +
1.382 +/**
1.383 +Indicates the data source has filled the specified buffer.
1.384 +
1.385 +Called by the CMMFDataPath2's MDataSource when it has filled the buffer.
1.386 +
1.387 +@param aBuffer
1.388 + A pointer to the filled buffer.
1.389 +*/
1.390 +void CMMFDataPath2::BufferFilledL(CMMFBuffer* aBuffer)
1.391 + {
1.392 +#ifdef _DP_DEBUG
1.393 + 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);
1.394 +#endif
1.395 +
1.396 + TBool isInTruePause = (iState == EPrimed && iPauseCalled && iIsUsingResumeSupport);
1.397 + //state only used if we are passing data
1.398 + __ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording || isInTruePause), Panic(EMMFDataPathPanicBadState,__LINE__));
1.399 +
1.400 + __ASSERT_DEBUG((!iNoMoreSourceData), Panic(EMMFDataPathPanicBadState,__LINE__));
1.401 +
1.402 + //if we have been asked to repeat and this is the last buffer, reset last buffer flag and send to the device
1.403 + if(aBuffer!= NULL && aBuffer->LastBuffer())
1.404 + {
1.405 + iNumberOfTimesPlayed++;
1.406 + if ((iNumberOfTimesPlayed <= iNumberOfTimesToRepeat) || iNumberOfTimesToRepeat == KMdaRepeatForever)
1.407 + {
1.408 + aBuffer->SetLastBuffer(EFalse);
1.409 +
1.410 + //this will trigger the trailing silence timer next time a buffer is requested.
1.411 + iTrailingSilenceLeftToPlay = iTrailingSilence;
1.412 + iVerifyPlayComplete = ETrue;
1.413 + }
1.414 + }
1.415 +
1.416 + iSourceBufferWithSource = EFalse;
1.417 +
1.418 + //Has the datapath stopped running, if so were not interested in any callbacks.
1.419 + if(iState == EStopped || (iState == EPrimed && !isInTruePause))
1.420 + {
1.421 +#ifdef _DP_DEBUG
1.422 + RDebug::Print(_L("DP::BufferFilledL called while not expecting callback iState=%d iPauseCalled=%d (this 0x%x)\n"),iState, iPauseCalled,this);
1.423 +#endif
1.424 + return;
1.425 + }
1.426 +
1.427 +#ifdef REPOSITION_SPEEDUP
1.428 + // if the source has been re-positioned, then go & get some more source data now
1.429 + if (!iObtainingAsyncSourceBuffer && iSourceBuffer->FrameNumber() != iCurrentSourceFrameNumber)
1.430 + {
1.431 +#ifdef _DP_DEBUG
1.432 + RDebug::Print(_L("DP::BufferFilledL source was re-positioned re-requesting source data (this 0x%x)\n"),this);
1.433 +#endif
1.434 + ChangeDataPathTransferState(ENeedSourceData);
1.435 + return;
1.436 + }
1.437 +#endif //REPOSITION_SPEEDUP
1.438 +
1.439 + //bufer is NULL, indicating no more source data.
1.440 + if (!aBuffer)
1.441 + {
1.442 + //If we only hold a reference to the source buffer, set that to NULL
1.443 + if(iSnkBufRef)
1.444 + {
1.445 + iSourceBuffer = NULL;
1.446 + }
1.447 +
1.448 + iNoMoreSourceData = ETrue;
1.449 +
1.450 + if(!iCodec || //there's only one buffer and that has been returned as NULL, so must be end of data
1.451 + iSinkBufferWithSink) //buffer is with sink, we don't have any more data to put in it, so must be end of data
1.452 + {
1.453 + ChangeDataPathTransferState(EEndOfData);
1.454 + }
1.455 + else //sink buffer is with datapath, see if there is anything to send to sink
1.456 + {
1.457 + ChangeDataPathTransferState(ENeedToMatchSourceToSink);
1.458 + }
1.459 +
1.460 +#ifdef _DP_DEBUG
1.461 + RDebug::Print(_L("DP::BufferFilledL DONE aBuffer==NULL tick-%d (this 0x%x)\n"),User::TickCount(),this);
1.462 +#endif
1.463 + return;
1.464 + }
1.465 +
1.466 +
1.467 + //We were waiting for a response from the source to get an asynchronous buffer.
1.468 + //We now have it, and we proceed to transfer this data to the sink.
1.469 + if (iObtainingAsyncSourceBuffer)
1.470 + {
1.471 + iObtainingAsyncSourceBuffer = EFalse;
1.472 + }
1.473 +
1.474 +
1.475 + aBuffer->SetStatus(EFull);
1.476 +
1.477 + if(iSourceBuffer != aBuffer)
1.478 + {//buffer has been changed by the source
1.479 + iSourceBuffer = aBuffer;
1.480 + if (!(iBuffersToUse & ENeedSinkBuffer))
1.481 + {//we only need one buffer and use source
1.482 + iSinkBuffer = iSourceBuffer;
1.483 + iSnkBufRef = ETrue;
1.484 + }
1.485 +#ifdef _DP_DEBUG
1.486 + RDebug::Print(_L("DP::BufferFilledL - iSourceBuffer=0x%x ref=%d iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
1.487 +#endif
1.488 + }
1.489 + //Is this the last buffer from the source (0 length or LastBuffer flag set)
1.490 + //or have reached the end of the play window; we only look at the play window here
1.491 + //if we are converting. For conversion we look at the data we have read. This is then passed onto
1.492 + //the source
1.493 + if (!iSourceBuffer->BufferSize() || iSourceBuffer->LastBuffer() ||
1.494 + (((iState == EConverting) || (iState == EPlaying)) && (iPlayWindowEndPosition < iCachedSourceDuration) && ( InputPosition() >= iPlayWindowEndPosition )))
1.495 + {
1.496 + //When it resumes in silence , position of the buffer is in end so we need to skip the increament.
1.497 + if(!iPauseCalledInsilence)
1.498 + {
1.499 + iNumberOfTimesPlayed++;
1.500 + }else
1.501 + {
1.502 + iPauseCalledInsilence=EFalse;
1.503 + }
1.504 + if ((iNumberOfTimesPlayed <= iNumberOfTimesToRepeat) || iNumberOfTimesToRepeat == KMdaRepeatForever)
1.505 + {
1.506 + iSourceBuffer->SetLastBuffer(EFalse);
1.507 + //this will trigger the trailing silence timer next time a buffer is requested.
1.508 + iTrailingSilenceLeftToPlay = iTrailingSilence;
1.509 + iVerifyPlayComplete = ETrue;
1.510 + }
1.511 + else
1.512 + {
1.513 + #ifdef _DP_DEBUG
1.514 + RDebug::Print(_L("DP::BufferFilledL end of input data tick-%d (this 0x%x)\n"),User::TickCount(),this);
1.515 + RDebug::Print(_L("iSourceBuffer->BufferSize()=%d\n"),iSourceBuffer->BufferSize());
1.516 + RDebug::Print(_L("iSourceBuffer->LastBuffer()=%d\n"),iSourceBuffer->LastBuffer());
1.517 + RDebug::Print(_L("InputPosition()=%d >= iPlayWindowEndPosition=%d\n"),I64INT(InputPosition().Int64()),I64INT(iPlayWindowEndPosition.Int64()));
1.518 + #endif
1.519 + iNoMoreSourceData = ETrue;
1.520 + iSourceBuffer->SetLastBuffer(ETrue); //just in-case we are terminating on BufferSize == 0 or play window
1.521 + }
1.522 + }
1.523 +
1.524 +
1.525 + if (!iCodec)
1.526 + {
1.527 + ChangeDataPathTransferState(ESendDataToSink);
1.528 + }
1.529 + else if(!iSinkBufferWithSink) //sink buffer is with data path, can try to fill it
1.530 + {
1.531 + ChangeDataPathTransferState(ENeedToMatchSourceToSink);
1.532 + }
1.533 + //else wait for sink to return buffer BufferEmptied will send us into ENeedToMatchSourceToSink state
1.534 +
1.535 +#ifdef _DP_DEBUG
1.536 + RDebug::Print(_L("DP::BufferFilledL - DONE tick-%d (this 0x%x)\n"),User::TickCount(),this);
1.537 +#endif
1.538 + }
1.539 +
1.540 +/**
1.541 +Sets the data path position.
1.542 +
1.543 +@param aPosition
1.544 + The data path position.
1.545 +*/
1.546 +void CMMFDataPath2::SetPositionL(const TTimeIntervalMicroSeconds& aPosition)
1.547 + {//need to map to source position to frame position
1.548 +#ifdef _DP_DEBUG
1.549 + RDebug::Print(_L("DP::SetPositionL = %d ticks-%d (this 0x%x)\n"),I64INT(aPosition.Int64()), User::TickCount(),this);
1.550 +#endif
1.551 +
1.552 + if (iState == EStopped)
1.553 + {
1.554 + User::Leave(KErrNotReady); //can only set position if primed
1.555 + }
1.556 +
1.557 + if(iGetTimePlayedSupported)
1.558 + {
1.559 + TTimeIntervalMicroSeconds timePlayed(0);
1.560 + if(iState == EPlaying && iDataSink->DataSinkType() == KUidMmfAudioOutput)
1.561 + {
1.562 + CMMFAudioOutput* audioOutput = STATIC_CAST(CMMFAudioOutput*,iDataSink);
1.563 + CMMFDevSound& devSound = audioOutput->SoundDevice();
1.564 + TInt err= devSound.GetTimePlayed(timePlayed);
1.565 + if(err == KErrNone)
1.566 + {
1.567 + iDevSoundRepositionTime = timePlayed.Int64();
1.568 + }
1.569 + }
1.570 + else
1.571 + {
1.572 + iDevSoundRepositionTime = 0;
1.573 + }
1.574 + }
1.575 + else //roll back to samplesplayed
1.576 + {
1.577 + //As this will affect the position, we need to know how many bytes were
1.578 + //played when position was updated. Future Position() requests will
1.579 + //then use this refernce to determine the current position.
1.580 + iReferenceAudioSamplesPlayed = AudioSamplesPlayed();
1.581 + }
1.582 +
1.583 + // Force the new position to be inside the play window (also within the file duration)
1.584 + if ( aPosition < iPlayWindowStartPosition )
1.585 + {
1.586 + iStartPosition = iPlayWindowStartPosition;
1.587 + }
1.588 + else if ( aPosition > iPlayWindowEndPosition )
1.589 + {
1.590 + iStartPosition = iPlayWindowEndPosition; //clearly this will cause nothing to be played
1.591 + }
1.592 + else
1.593 + {
1.594 + iStartPosition = aPosition;
1.595 + }
1.596 +
1.597 + TTimeIntervalMicroSeconds interval;
1.598 +
1.599 + //can only set the position on an MDataSource that is a format object
1.600 + //Note: position defaults to source if both source & sink are clips
1.601 + if (iDataSource->DataSourceType() == KUidMmfFormatDecode)
1.602 + {
1.603 + //position is not beyond the end of file
1.604 + interval = ((CMMFFormatDecode*)iDataSource)->FrameTimeInterval(iMediaId);
1.605 +
1.606 + // for some reason this code won't compile without these intermediate steps
1.607 + TInt64 position = iStartPosition.Int64();
1.608 + TInt64 interval64 = interval.Int64();
1.609 + if (interval64 == 0)
1.610 + User::Leave(KErrDivideByZero);
1.611 + TInt64 datapos64 = position/interval64;
1.612 + iCurrentSourceFrameNumber = I64LOW(datapos64);
1.613 +
1.614 +
1.615 + // Try to set the position directly on the format
1.616 + TRAP_IGNORE(((CMMFFormatDecode*)iDataSource)->SetPositionL(iStartPosition));
1.617 + //NB: don't worry about error, since we'll reposition anyway when we get the next buffer
1.618 + }
1.619 + else if (iDataSink->DataSinkType() == KUidMmfFormatEncode)
1.620 + {
1.621 + //position is not beyond the end of file
1.622 + interval = ((CMMFFormatEncode*)iDataSink)->FrameTimeInterval(iMediaId);
1.623 +
1.624 + //convert to TUint - for some reason it won't compile without these intermediate steps
1.625 + TInt64 position = iStartPosition.Int64();
1.626 + TInt64 interval64 = interval.Int64();
1.627 + if (interval64 == 0)
1.628 + User::Leave(KErrDivideByZero);
1.629 + TInt64 datapos64 = position/interval64;
1.630 + iCurrentSinkFrameNumber = I64LOW(datapos64);
1.631 +
1.632 +
1.633 + // Try to set the position directly on the format
1.634 + TRAP_IGNORE(((CMMFFormatEncode*)iDataSink)->SetPositionL(iStartPosition));
1.635 + //NB: don't worry about error, since we'll reposition anyway when we get the next buffer
1.636 + }
1.637 + else
1.638 + {//can only set position if source or sink is a format
1.639 + //If both source and sink are formats position is relative to the source
1.640 + User::Leave(KErrNotSupported); //can't set position if neither source nor sink are clips
1.641 + }
1.642 +
1.643 + if(iCodec) //we have a real codec, must reset it
1.644 + {
1.645 + iCodec->ResetL(); // Need to preserve sync when resuming play
1.646 + }
1.647 +
1.648 + // Once we've sent the last buffer to the sink it's too late to start
1.649 + // changing the state since we may get a RunError(KErrUnderflow) at any time.
1.650 + // Once this happens, the sound driver may have unloaded etc..and recovery
1.651 + // would be complicated.
1.652 + if (iAllDataSentToSink)
1.653 + {
1.654 + return;
1.655 + }
1.656 +#ifdef _DP_DEBUG
1.657 + RDebug::Print(_L("DP::SetPosition - Done iCurrentSourceFrameNumber=%d iStartPosition=%d ticks-%d (this 0x%x)\n"),iCurrentSourceFrameNumber, I64INT(iStartPosition.Int64()), User::TickCount(),this);
1.658 +#endif
1.659 + }
1.660 +
1.661 +/**
1.662 +Gets the data path position.
1.663 +
1.664 +@return The data path position.
1.665 +*/
1.666 +TTimeIntervalMicroSeconds CMMFDataPath2::Position() const
1.667 + {
1.668 + if ((iState == ERecording) || (iState == EConverting))
1.669 + {
1.670 + return InputPosition();
1.671 + }
1.672 + else if(iState == EPlaying)
1.673 + {
1.674 + return OutputPosition();
1.675 + }
1.676 + else
1.677 + {
1.678 + return iStartPosition;
1.679 + }
1.680 + }
1.681 +
1.682 +TTimeIntervalMicroSeconds CMMFDataPath2::OutputPosition() const
1.683 + {
1.684 + TTimeIntervalMicroSeconds interval;
1.685 + TTimeIntervalMicroSeconds position;
1.686 +
1.687 + if (iDataSink->DataSinkType() == KUidMmfAudioOutput)
1.688 + {
1.689 + position = CalculateAudioOutputPosition();
1.690 +#ifdef _DP_DEBUG
1.691 + RDebug::Print(_L("DP::OutputPosition from audio output= %d\n"),I64INT(position.Int64()));
1.692 +#endif
1.693 + }
1.694 + else if (iDataSink->DataSinkType() == KUidMmfFormatEncode)
1.695 + {
1.696 + //note Encode format position takes priority if both source & sink are formats?
1.697 + // try to get the position directly from the format. If that fails, work it out here
1.698 + TRAPD(error, position = ((CMMFFormatEncode*)iDataSink)->PositionL());
1.699 + if (error)//getting the position from the format didn't work so calculate it here
1.700 + {
1.701 + interval = ((CMMFFormatEncode*)iDataSink)->FrameTimeInterval(iMediaId);
1.702 + TInt64 position64 = interval.Int64() * iCurrentSinkFrameNumber;
1.703 + position = position64;
1.704 + }
1.705 +
1.706 + TTimeIntervalMicroSeconds duration = CONST_CAST(CMMFDataPath2*,this)->Duration(); //need this to check position doesn't exceed duration
1.707 + if (position > duration)//this can happen on last buffer
1.708 + {
1.709 + position = duration;
1.710 + }
1.711 +#ifdef _DP_DEBUG
1.712 + RDebug::Print(_L("DP::OutputPosition from format= %d\n"),I64INT(position.Int64()));
1.713 +#endif
1.714 + }
1.715 + else
1.716 + {//can only read output position if sink is a format or an audio output
1.717 + return TTimeIntervalMicroSeconds(0);
1.718 + }
1.719 +
1.720 + return position;
1.721 + }
1.722 +
1.723 +TTimeIntervalMicroSeconds CMMFDataPath2::CalculateAudioOutputPosition() const
1.724 + {
1.725 + //This operation can only be carried out on an Audio Output
1.726 + __ASSERT_ALWAYS(iDataSink->DataSinkType() == KUidMmfAudioOutput, Panic(EMMFDataPathPanicProgrammingError,__LINE__));
1.727 +
1.728 +
1.729 + //If we are not playing, simply return where we will play from
1.730 + if(iState != EPlaying || iCurrentSinkFrameNumber == 0 || iStartPosition == iPlayWindowEndPosition )
1.731 + {
1.732 + return iStartPosition;
1.733 + }
1.734 +#ifdef _DP_DEBUG
1.735 + RDebug::Print(_L("DP::CalculateAudioOutputDuration from %d\n"),iReferenceAudioSamplesPlayed);
1.736 +#endif
1.737 +
1.738 + CMMFAudioOutput* audioOutput = STATIC_CAST(CMMFAudioOutput*,iDataSink);
1.739 + CMMFDevSound& devSound = audioOutput->SoundDevice();
1.740 +
1.741 + TTimeIntervalMicroSeconds devSoundTimePlayed(0);
1.742 + TInt64 timePlayed(0);
1.743 + TInt err = KErrNone;
1.744 + if(iGetTimePlayedSupported)
1.745 + {
1.746 + err= devSound.GetTimePlayed(devSoundTimePlayed);
1.747 + if(err == KErrNone)
1.748 + {
1.749 + timePlayed = devSoundTimePlayed.Int64()-iDevSoundRepositionTime.Int64();
1.750 + }
1.751 + }
1.752 + else //Roll back to SamplesPlayed
1.753 + {
1.754 + TReal samplesPlayed = AudioSamplesPlayed() - iReferenceAudioSamplesPlayed;
1.755 + TMMFCapabilities devSoundConfig = devSound.Config();
1.756 + TInt samplingFreq = StreamUtils::SampleRateAsValue(devSoundConfig);
1.757 + #ifdef _DP_DEBUG
1.758 + RDebug::Print(_L("samplingFreq %d\n"),samplingFreq);
1.759 + #endif
1.760 +
1.761 + TReal timePlayedSeconds = 0;
1.762 + if(samplesPlayed)
1.763 + {
1.764 + timePlayedSeconds = samplesPlayed/samplingFreq;
1.765 + }
1.766 + timePlayed = I64DOUBLECAST(timePlayedSeconds * 1000000);
1.767 +
1.768 + #ifdef _DP_DEBUG
1.769 + RDebug::Print(_L("timePlayed %d\n"), I64LOW(timePlayed));
1.770 + #endif
1.771 + }
1.772 + if(err == KErrNone)
1.773 + {
1.774 + // When Resume is not supported. Datapath simulates Pause() through DevSound's Stop
1.775 + // the time played is lost. So we need to saved the last position
1.776 + // On the opposite, when Resume is supported the time played returned by DevSound
1.777 + // reflects the real position, so there is no needed to recalculate at least playwindow is being used
1.778 + // Finally, if Resume is supported but is not used the position also need to be saved
1.779 + if(!iIsUsingResumeSupport || iPlayWindowStartPosition.Int64() > 0)
1.780 + {
1.781 + timePlayed = timePlayed + iStartPosition.Int64();
1.782 + }
1.783 +
1.784 + //During repeats. we need to reset the positin manually to playstart once playend is reached
1.785 + //this is because the bytes returned by devsound are not accurate in all the cases
1.786 + if(iRepeatTrailingSilenceTimer->IsActive() || iTimeLeftToPlayComplete==0)//loop play
1.787 + {
1.788 + if(iTimeLeftToPlayComplete==0)
1.789 + {
1.790 + timePlayed = iPlayWindowStartPosition.Int64();
1.791 + }
1.792 + }
1.793 + else if(timePlayed>=(iPlayWindowEndPosition.Int64()+1))
1.794 + {
1.795 + timePlayed = iPlayWindowStartPosition.Int64();
1.796 + }
1.797 + }
1.798 +
1.799 + return TTimeIntervalMicroSeconds(timePlayed);
1.800 + }
1.801 +
1.802 +/**
1.803 +Stops playing.
1.804 +
1.805 +Resets datapath position - currently does not clean up buffers. Sends KMMFErrorCategoryDataPathGeneralError
1.806 +to the client if an error occurs.
1.807 +*/
1.808 +void CMMFDataPath2::Stop()
1.809 + {
1.810 +#ifdef _DP_DEBUG
1.811 + RDebug::Print(_L("DP::Stop current state=%d tick-%d (this 0x%x)\n"), iTransferState, User::TickCount(),this);
1.812 +#endif
1.813 + if ((iDataPathCreated) && (iState != EStopped))
1.814 + {
1.815 + TRAPD(err, DoStopL());
1.816 + if (err)
1.817 + {
1.818 + DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
1.819 + }
1.820 + }
1.821 + }
1.822 +
1.823 +void CMMFDataPath2::DoStopL()
1.824 + {
1.825 + CMMFDataPath::DoStopL();
1.826 + iRepeatTrailingSilenceTimer->Cancel();
1.827 + iIsUsingResumeSupport = EFalse;
1.828 + }
1.829 +
1.830 +/**
1.831 +Pauses playing.
1.832 +
1.833 +Sends KMMFErrorCategoryDataPathGeneralError to the client if an error occurs.
1.834 +*/
1.835 +void CMMFDataPath2::Pause()
1.836 + {
1.837 +#ifdef _DP_DEBUG
1.838 + RDebug::Print(_L("DP::Pause, on src buff %d sink buf %d (this 0x%x)\n"), iCurrentSourceFrameNumber, iCurrentSinkFrameNumber,this);
1.839 + RDebug::Print(_L("DP::Pause current state=%d tick-%d (this 0x%x)\n"),iTransferState, User::TickCount(),this);
1.840 +#endif
1.841 +
1.842 + TRAPD(err, DoPauseL());
1.843 +
1.844 + if (err)
1.845 + {
1.846 + DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
1.847 + }
1.848 +#ifdef _DP_DEBUG
1.849 + RDebug::Print(_L("DP::Pause - DONE tick-%d (this 0x%x)\n"),User::TickCount(),this);
1.850 +#endif
1.851 + }
1.852 +
1.853 +EXPORT_C void CMMFDataPath2::PreEmptionPause()
1.854 + {
1.855 + TRAPD(err, DoPreEmptionPauseL());
1.856 +
1.857 + if (err)
1.858 + {
1.859 + DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
1.860 + }
1.861 + }
1.862 +
1.863 +/**
1.864 +Pauses playing.
1.865 +
1.866 +Sends KMMFErrorCategoryDataPathGeneralError to the client if an error occurs.
1.867 +*/
1.868 +void CMMFDataPath2::DoPreEmptionPauseL()
1.869 + {
1.870 +
1.871 + if ((iDataPathCreated) && ((iState == EPlaying) || (iState == EConverting) && ( iDataSink->DataSinkType() == KUidMmfAudioOutput )))
1.872 + {
1.873 + iDataSource->SourcePauseL(); // propagate state change to source
1.874 + SetPositionL(Position());
1.875 + iIsUsingResumeSupport = EFalse;
1.876 +
1.877 + iDataSink->SinkStopL();
1.878 + iPauseCalled = ETrue; // indicate pause is called
1.879 +
1.880 + iState = EPrimed; // go back to primed state (we're not playing)
1.881 +
1.882 + iSinkBufferWithSink = EFalse;
1.883 + iSourceBufferWithSource = EFalse;
1.884 +
1.885 + ResetRefBuffers(); // buffer references may not be valid any more
1.886 +
1.887 + Cancel(); //Stop the state machine
1.888 + }
1.889 + if(iState == ERecording)
1.890 + {
1.891 + User::Leave(KErrNotSupported);
1.892 + }
1.893 + iRepeatTrailingSilenceTimer->Cancel();
1.894 + }
1.895 +
1.896 +void CMMFDataPath2::DoPauseL()
1.897 + {
1.898 +#ifdef _DP_DEBUG
1.899 + RDebug::Print(_L("DP::DoPauseL tick-%d (this 0x%x)\n"),User::TickCount(),this);
1.900 +#endif
1.901 +
1.902 +
1.903 + if ((iDataPathCreated) && ((iState == EPlaying) || (iState == EConverting)))
1.904 + {
1.905 + if (iDataSink->DataSinkType() == KUidMmfAudioOutput && iIsResumeSupported)
1.906 + {
1.907 + iDataSink->SinkPauseL();
1.908 + // When true pause is supported only the datapath's position
1.909 + // should be updated, MDataSource position should be changed
1.910 + iStartPosition = Position();
1.911 + iIsUsingResumeSupport = ETrue;
1.912 + if(iRepeatTrailingSilenceTimer->IsActive())
1.913 + {
1.914 + iPauseCalledInsilence=ETrue;
1.915 + }
1.916 + // If we wait for the sink to complete play, then we do not proceed with supplying the buffers to the sink
1.917 + // In this case we need to reset the buffers so that InitializeSinkL won't attempt bringing in new ones
1.918 + if (iTransferState == EWaitSink)
1.919 + {
1.920 + ResetRefBuffers();
1.921 + }
1.922 + }
1.923 + else
1.924 + {
1.925 + // If we use resume support, then there is no need to pause source as we would continue to supply buffers to the sink
1.926 + // Here we are not using resume support, thus we're pausing the source
1.927 + iDataSource->SourcePauseL();
1.928 + SetPositionL(Position());
1.929 + iDataSink->SinkStopL();
1.930 + ResetRefBuffers(); // buffer references may not be valid any more
1.931 +
1.932 + Cancel(); //Stop the state machine
1.933 + }
1.934 + iPauseCalled = ETrue; // indicate pause is called
1.935 +
1.936 + iState = EPrimed; // go back to primed state (we're not playing)
1.937 + }
1.938 + else if(iState == ERecording)
1.939 + {
1.940 + iPauseCalled = ETrue;
1.941 +#ifdef _DP_DEBUG
1.942 + RDebug::Print(_L("DP::DoPauseL Recording, pause datasource\n"));
1.943 +#endif
1.944 + iDataSource->SourcePauseL();
1.945 + }
1.946 + iRepeatTrailingSilenceTimer->Cancel();
1.947 +#ifdef _DP_DEBUG
1.948 + RDebug::Print(_L("DP::DoPauseL - Done iReferenceAudioSamplesPlayed = %d\n"),iReferenceAudioSamplesPlayed);
1.949 + RDebug::Print(_L("DP::DoPauseL - Done restart at %d tick-%d (this 0x%x)\n"),I64INT(iStartPosition.Int64()), User::TickCount(),this);
1.950 +#endif
1.951 + }
1.952 +
1.953 +/**
1.954 +Cancels the silence timer.
1.955 +*/
1.956 +void CMMFDataPath2::DoCancel()
1.957 + {
1.958 + //cancel repeats
1.959 + iRepeatTrailingSilenceTimer->Cancel();
1.960 + iNumberOfTimesToRepeat=0;
1.961 + }
1.962 +
1.963 +/**
1.964 +Allocates buffers in preparation to play.
1.965 +
1.966 +Must be called before calling PlayL().
1.967 +
1.968 +iSnkBufRef and iSrcBufRef contain ETrue if these buffers are created and owned by a MDataSource or MDataSink
1.969 +For clean-up purposes, datapath only cleans up buffers allocated directly by PrimeL().
1.970 +*/
1.971 +void CMMFDataPath2::PrimeL()
1.972 + {
1.973 + CMMFDataPath::PrimeL();
1.974 + if(iDataSink->DataSinkType() == KUidMmfAudioOutput)
1.975 + {
1.976 + CMMFAudioOutput* audioOutput = STATIC_CAST(CMMFAudioOutput*,iDataSink);
1.977 + CMMFDevSound& devSound = audioOutput->SoundDevice();
1.978 + iGetTimePlayedSupported = devSound.IsGetTimePlayedSupported();
1.979 + iIsResumeSupported = devSound.IsResumeSupported();
1.980 + iIsUsingResumeSupport = EFalse;
1.981 + iPauseCalledInsilence = EFalse;
1.982 + }
1.983 + }
1.984 +
1.985 +/**
1.986 +Starts an active scheduler 'play' loop.
1.987 +
1.988 +Can only play from the primed state.
1.989 +*/
1.990 +void CMMFDataPath2::PlayL()
1.991 + {
1.992 +
1.993 +#if defined(__PROFILING)
1.994 + RDebug::ProfileEnd(1);
1.995 +#endif // defined(__PROFILING)
1.996 +
1.997 +#ifdef _DP_DEBUG
1.998 + RDebug::Print(_L("DP::PlayL, on src buff %d sink buf %d (this 0x%x)\n"), iCurrentSourceFrameNumber, iCurrentSinkFrameNumber,this);
1.999 + RDebug::Print(_L("iStartPosition = %d\n"), I64INT(iStartPosition.Int64()));
1.1000 +#endif
1.1001 +
1.1002 + if ((iDataPathCreated) && (iState == EPrimed))
1.1003 + {
1.1004 + //can only play from the primed state
1.1005 +
1.1006 + if(iPauseCalled) //sink and source will have been stopped, and we will not have been re-primed
1.1007 + {
1.1008 + //When pause is called silence,we need to send the buffer while resume so icansendbuffer should enabled
1.1009 + if(!iPauseCalledInsilence)
1.1010 + {
1.1011 + iDataSink->SinkPrimeL(); //propagate change down to sink
1.1012 + }
1.1013 + iPauseCalled = EFalse;
1.1014 + }
1.1015 +
1.1016 + iCurrentSourceFrameNumber = 0; //reset to beginning
1.1017 + iCurrentSinkFrameNumber = 0; //reset to beginning
1.1018 +
1.1019 + iSourceBufferWithSource = EFalse;
1.1020 + iSinkBufferWithSink = EFalse;
1.1021 +
1.1022 + iNoMoreSourceData = EFalse;
1.1023 + iAllDataSentToSink=EFalse;
1.1024 + iDataPathCompletedErrorCode=KErrNone;
1.1025 +
1.1026 + if(!iIsResumeSupported || !iIsUsingResumeSupport)
1.1027 + {
1.1028 + SetPositionL( iStartPosition );
1.1029 + }
1.1030 + iReferenceAudioSamplesPlayed = 0;
1.1031 + iReferenceAudioSamplesRecorded = 0;
1.1032 +
1.1033 + //complete a request on iStatus to invoke play code
1.1034 + iDataSource->SourcePlayL(); //propagate state change to source
1.1035 +
1.1036 + // This need to be done always since CMMFAudioOutput::EmptyBuffer
1.1037 + // doesn't start playback anymore
1.1038 + iDataSink->SinkPlayL(); //propogate state change to sink
1.1039 +
1.1040 + if (iDataSink->DataSinkType() == KUidMmfAudioOutput)
1.1041 + iState = EPlaying;
1.1042 + else if(iDataSource->DataSourceType() == KUidMmfAudioInput)
1.1043 + iState = ERecording;
1.1044 + else
1.1045 + iState = EConverting;
1.1046 +
1.1047 + //need to re-initialize any buffer(s) that we only own references to
1.1048 + ChangeDataPathTransferState(EInitializeSink);
1.1049 + }
1.1050 + iDevSoundRepositionTime = 0;
1.1051 + if(!iRetainRepeatInfo)
1.1052 + {
1.1053 + iNumberOfTimesPlayed = 0;
1.1054 + iTimeLeftToPlayComplete = -1;
1.1055 + iVerifyPlayComplete = EFalse;
1.1056 + }
1.1057 + iRetainRepeatInfo = EFalse;
1.1058 +#ifdef _DP_DEBUG
1.1059 + RDebug::Print(_L("DP::Play - DONE\n"));
1.1060 +#endif
1.1061 + }
1.1062 +
1.1063 +/**
1.1064 +Deletes buffers if this datapath's sources and sinks own the buffers returned by PrimeL().
1.1065 +Typically if buffers are created asychronously, the datapath doesn't own the buffer
1.1066 +so leaves cleanup handling to the owner sources/sinks.
1.1067 +
1.1068 +Called when source and sink needs to be de-referenced. Sets iDataPathCreated, iSinkCanReceive,
1.1069 +iSnkBufRef and iSrcBufRef to EFalse; sets iState to EStopped.
1.1070 +*/
1.1071 +void CMMFDataPath2::ResetL()
1.1072 + {
1.1073 + CMMFDataPath::ResetL();
1.1074 + iDrmSource = NULL;
1.1075 + }
1.1076 +
1.1077 +/**
1.1078 +Sets the number of times the audio sample is to be repeated during the
1.1079 +playback operation.
1.1080 +
1.1081 +A period of silence can follow each playing of the sample. The audio
1.1082 +sample can be repeated indefinitely.
1.1083 +
1.1084 +@param aRepeatNumberOfTimes
1.1085 + The number of times the audio sample, together with
1.1086 + the trailing silence, is to be repeated. If this is
1.1087 + set to KMdaRepeatForever, then the audio
1.1088 + sample, together with the trailing silence, is
1.1089 + repeated indefinitely or until Stop() is
1.1090 + called. If this is set to zero, then the audio sample
1.1091 + is not repeated.
1.1092 +@param aTrailingSilence
1.1093 + The time interval of the trailing silence in microseconds.
1.1094 +
1.1095 +*/
1.1096 +EXPORT_C void CMMFDataPath2::SetRepeats(TInt aRepeatNumberOfTimes, const TTimeIntervalMicroSeconds& aTrailingSilence)
1.1097 + {
1.1098 + iNumberOfTimesToRepeat=aRepeatNumberOfTimes;
1.1099 + iTrailingSilence=aTrailingSilence;
1.1100 + }
1.1101 +
1.1102 +/**
1.1103 +Sets the Drm file source and the automatic execute intent flag. This method is used by the controller plugin
1.1104 +to pass these to the datapath in order to execute the play intent during loop play.
1.1105 +
1.1106 +@param aSource
1.1107 + Data Source on which the play intent needs to be executed. This is usually the CMMFFile source
1.1108 +@param aDisableAutoIntent
1.1109 + Boolean variable which states whether the controller plugin or the datapath needs to execute play intent
1.1110 + automatically or not.
1.1111 +*/
1.1112 +EXPORT_C void CMMFDataPath2::SetDrmProperties(MDataSource* aSource, TBool *aDisableAutoIntent)
1.1113 + {
1.1114 + iDrmSource = aSource;
1.1115 + iDisableAutoIntent = aDisableAutoIntent;
1.1116 + }
1.1117 +
1.1118 +/**
1.1119 +This call indicates PlayL not to reset the iNumberOfTimesPlayed property. This method is used by the controller plugin
1.1120 +during repositioning. PlayL call during seeking should not reset the iNumberOfTimesPlayed property.
1.1121 +*/
1.1122 +EXPORT_C void CMMFDataPath2::RetainRepeatInfo()
1.1123 + {
1.1124 + iRetainRepeatInfo = ETrue;
1.1125 + }