|
1 /* |
|
2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: This file contains the base class from which specific audio |
|
15 * play controllers are derived. This class encapsulates common |
|
16 * behavior for all audio play controllers. |
|
17 * |
|
18 */ |
|
19 |
|
20 |
|
21 // INCLUDE FILES |
|
22 #include "AdvancedAudioPlayController.h" |
|
23 #include "AdvancedAudioResource.h" |
|
24 #include "DebugMacros.h" |
|
25 #include <AudioOutput.h> |
|
26 #include <MetaDataFieldContainer.h> |
|
27 #include <MetaDataUtility.h> |
|
28 #include <mmfformatimplementationuids.hrh> |
|
29 #include <mmfmeta.h> |
|
30 #include <MultimediaDataSourceEvents.h> |
|
31 #include <MultimediaDataSourceFactory.h> |
|
32 #include <oma2dcf.h> |
|
33 |
|
34 // KMdaRepeatForever constant is defined in this file |
|
35 #include <mda/common/resource.h> |
|
36 // CONSTANTS |
|
37 const TInt KOneThousandMilliSecond = 1000; // 1 sec |
|
38 |
|
39 // ============================= LOCAL FUNCTIONS =============================== |
|
40 |
|
41 // ============================ MEMBER FUNCTIONS =============================== |
|
42 |
|
43 // ----------------------------------------------------------------------------- |
|
44 // CAdvancedAudioPlayController::CAdvancedAudioPlayController |
|
45 // C++ default constructor can NOT contain any code, that might leave. |
|
46 // ----------------------------------------------------------------------------- |
|
47 // |
|
48 EXPORT_C CAdvancedAudioPlayController::CAdvancedAudioPlayController() |
|
49 : iState(EStopped), |
|
50 iAudioOutput(NULL), |
|
51 iAudioResource(NULL), |
|
52 iAudioUtility(NULL), |
|
53 iDisableAutoIntent (EFalse), |
|
54 iDecoderExists(EFalse), |
|
55 iRepeatCount(-1), |
|
56 iCurrentRepeatCount(0), |
|
57 iLoopPlayEnabled(EFalse), |
|
58 iRepeatForever(EFalse), |
|
59 iTrailingSilenceMs(0), |
|
60 iSavedTimePositionInMicroSecs(0) //, |
|
61 { |
|
62 iEventsEnabled = EFalse; |
|
63 |
|
64 RThread().SetPriority(EPriorityRealTime); |
|
65 } |
|
66 |
|
67 EXPORT_C void CAdvancedAudioPlayController::ConstructL() |
|
68 { |
|
69 DP1(_L("CAdvancedAudioPlayController::ConstructL this[%x]"), this); |
|
70 CAdvancedAudioController::ConstructL(); |
|
71 |
|
72 // Construct custom command parsers |
|
73 CMMFAudioPlayDeviceCustomCommandParser* audPlayDevParser = |
|
74 CMMFAudioPlayDeviceCustomCommandParser::NewL(*this); |
|
75 CleanupStack::PushL(audPlayDevParser); |
|
76 AddCustomCommandParserL(*audPlayDevParser); |
|
77 CleanupStack::Pop(audPlayDevParser); |
|
78 |
|
79 CMMFAudioPlayControllerCustomCommandParser* audPlayConParser = |
|
80 CMMFAudioPlayControllerCustomCommandParser::NewL(*this); |
|
81 CleanupStack::PushL(audPlayConParser); |
|
82 AddCustomCommandParserL(*audPlayConParser); |
|
83 CleanupStack::Pop(audPlayConParser); |
|
84 |
|
85 CMMFDRMCustomCommandParser* drmParser = CMMFDRMCustomCommandParser::NewL(*this); |
|
86 CleanupStack::PushL(drmParser); |
|
87 AddCustomCommandParserL(*drmParser); |
|
88 CleanupStack::Pop(drmParser); |
|
89 |
|
90 CStreamControlCustomCommandParser* scCCParser = CStreamControlCustomCommandParser::NewL(*this); |
|
91 CleanupStack::PushL(scCCParser); |
|
92 AddCustomCommandParserL(*scCCParser); |
|
93 CleanupStack::Pop(scCCParser); |
|
94 |
|
95 // new custom command parser to implement the MapcSetRepeats custom command from the client |
|
96 CMMFAudioPlayControllerSetRepeatsCustomCommandParser* audPlayConSetRepeatsParser = |
|
97 CMMFAudioPlayControllerSetRepeatsCustomCommandParser::NewL(*this); |
|
98 CleanupStack::PushL(audPlayConSetRepeatsParser); |
|
99 AddCustomCommandParserL(*audPlayConSetRepeatsParser); |
|
100 CleanupStack::Pop(audPlayConSetRepeatsParser); |
|
101 } |
|
102 |
|
103 // Destructor |
|
104 EXPORT_C CAdvancedAudioPlayController::~CAdvancedAudioPlayController() |
|
105 { |
|
106 DP1(_L("CAdvancedAudioPlayController::~CAdvancedAudioPlayController start this[%x]"), this); |
|
107 DP4(_L("CAdvancedAudioPlayController::~CAdvancedAudioPlayController iState[%d] iWait[%d] iBlockSetPos[%d] iSharedBuffers.Count[%d]"), |
|
108 iState, iWait, iBlockSetPos, iSharedBuffers.Count()); |
|
109 RThread().SetPriority(EPriorityNormal); |
|
110 |
|
111 if (iMetaDataEntries.Count()) |
|
112 { |
|
113 iMetaDataEntries.ResetAndDestroy(); |
|
114 iMetaDataEntries.Close(); |
|
115 } |
|
116 |
|
117 if (iTrailingSilenceTimer) |
|
118 { |
|
119 delete iTrailingSilenceTimer; |
|
120 iTrailingSilenceTimer = NULL; |
|
121 } |
|
122 |
|
123 delete iDataSourceAdapter; |
|
124 delete iWait; |
|
125 delete iBlockSetPos; |
|
126 iSharedBuffers.ResetAndDestroy(); |
|
127 iSharedBuffers.Close(); |
|
128 DP0(_L("CAdvancedAudioPlayController::~CAdvancedAudioPlayController end")); |
|
129 } |
|
130 |
|
131 |
|
132 // ----------------------------------------------------------------------------- |
|
133 // CAdvancedAudioPlayController::DoReadHeaderL |
|
134 // ----------------------------------------------------------------------------- |
|
135 // |
|
136 EXPORT_C void CAdvancedAudioPlayController::DoReadHeaderL(CMMFDataBuffer* /*aBuffer*/) |
|
137 { |
|
138 // do nothing |
|
139 } |
|
140 |
|
141 // ----------------------------------------------------------------------------- |
|
142 // CAdvancedAudioPlayController::DoSetPositionL |
|
143 // ----------------------------------------------------------------------------- |
|
144 // |
|
145 EXPORT_C void CAdvancedAudioPlayController::DoSetPositionL(const TTimeIntervalMicroSeconds& aTimePos) |
|
146 { |
|
147 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL start -----------")); |
|
148 TInt err = KErrNone; |
|
149 TInt foundPosition; |
|
150 TInt foundTimeMs; |
|
151 TBool seekFwd = EFalse; |
|
152 TUint timeMs = aTimePos.Int64()/1000; |
|
153 DP2(_L("CAdvancedAudioPlayController::DoSetPositionL timeMs[%u] pre[%d]"), timeMs, (iPreSeekTime.Int64()/1000)); |
|
154 // Fix for the error ou1cimx1#151598 - ESLM-7T5GJH |
|
155 // unregisters any old position entries from the FrameTable before setting any new play seek positions |
|
156 iAudioUtility->SeekToTimeMs(KMaxTUint); |
|
157 |
|
158 if (aTimePos < 0) |
|
159 { |
|
160 timeMs = 0; |
|
161 } |
|
162 |
|
163 // get current position in time |
|
164 // if we need to play to seek forward (not in table), the time will be advanced immediately |
|
165 // if we pause before we get there, pause will set pos to that time - which is what we want. |
|
166 // but we need to remember that we are not there yet so we can still seek forward. So we use pre-seek time. |
|
167 if (!iPlaySeeking) |
|
168 { |
|
169 iPreSeekTime = PositionL(); |
|
170 DP1(_L("CAdvancedAudioPlayController::DoSetPositionL save pre-seek time[%d]"), iPreSeekTime.Int64()/1000); |
|
171 } |
|
172 if (aTimePos > iPreSeekTime) |
|
173 { |
|
174 seekFwd = ETrue; |
|
175 } |
|
176 DP1(_L("CAdvancedAudioPlayController::DoSetPositionL seekFwd[%d]"), seekFwd); |
|
177 |
|
178 TUint const seekTime = timeMs; |
|
179 TUint position = 0; |
|
180 TBool posFoundInTable = EFalse; |
|
181 |
|
182 // look in current buffers first |
|
183 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL not time seekable")); |
|
184 err = SetPositionInSharedBuffers(timeMs, foundPosition, foundTimeMs); |
|
185 if (!iSourceIsTimeSeekable && !iSourceIsPosSeekable) |
|
186 { |
|
187 if (err == KErrNone) |
|
188 { // found exact position |
|
189 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL found exact position")); |
|
190 iCurrentPosition = foundPosition; // absolute position into file or content |
|
191 iTimePositionInMicroSecs = foundTimeMs; |
|
192 iTimePositionInMicroSecs *=1000; |
|
193 DP1(_L("CAdvancedAudioPlayController::DoSetPositionL iTimePositionInMicroSecs[%d]"),foundTimeMs); |
|
194 iAudioUtility->SetSourceReference(iTimePositionInMicroSecs/1000, iCurrentPosition-iHeaderOffset-iSyncOffset); |
|
195 RefillPreceedingBuffersL(); |
|
196 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL end -----------")); |
|
197 return; |
|
198 } |
|
199 // err means it just found something close |
|
200 ASSERT(err != KErrGeneral); |
|
201 if (err == KErrGeneral) |
|
202 { // KErrGeneral means it did not find anything and we have to stop. |
|
203 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL abort -------")); |
|
204 TMMFEvent event(KMMFEventCategoryPlaybackComplete,KErrGeneral); |
|
205 SendEvent(event); |
|
206 return; |
|
207 } |
|
208 // source is not seekable so use buffered data |
|
209 // use closest time and position found above |
|
210 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL using closest position")); |
|
211 iCurrentPosition = foundPosition; |
|
212 iTimePositionInMicroSecs = foundTimeMs; |
|
213 iTimePositionInMicroSecs *=1000; |
|
214 DP1(_L("CAdvancedAudioPlayController::DoSetPositionL iTimePositionInMicroSecs[%d]"),foundTimeMs); |
|
215 iAudioUtility->SetSourceReference(iTimePositionInMicroSecs/1000, iCurrentPosition-iHeaderOffset-iSyncOffset); |
|
216 RefillPreceedingBuffersL(); |
|
217 } |
|
218 if (iSourceIsTimeSeekable) |
|
219 { // time seekable source won't have accurate table positions |
|
220 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL is time seekable")); |
|
221 iPreSeekTime = 0; |
|
222 iDataSourceAdapter->SourceStopL(); // clear the buffers in the source before seeking and priming it |
|
223 iDataSourceAdapter->SourcePrimeL(); |
|
224 err = iDataSourceAdapter->SeekToTime(seekTime, timeMs); |
|
225 iAudioUtility->ResetTable(); |
|
226 iDataSourceAdapter->SourcePlayL(); |
|
227 iTimePositionInMicroSecs = timeMs; |
|
228 iTimePositionInMicroSecs *=1000; |
|
229 DP1(_L("CAdvancedAudioPlayController::DoSetPositionL iTimePositionInMicroSecs[%d]"),timeMs); |
|
230 iSourceReadPosition = 0; // we don't know the position - source doesn't give us that |
|
231 // iCurrentPosition = iSourceReadPosition; |
|
232 iCurrentPosition = KMaxTUint; |
|
233 iAudioUtility->SetSourceReference(iTimePositionInMicroSecs/1000, 0); |
|
234 TRAP(err, RefillSharedBuffersL()); |
|
235 } |
|
236 else if (iSourceIsPosSeekable) |
|
237 { |
|
238 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL is position seekable")); |
|
239 TInt err = iAudioUtility->FindFramePosFromTime(timeMs, position); |
|
240 if (err == KErrNone) |
|
241 { |
|
242 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL pos found in table")); |
|
243 posFoundInTable = ETrue; |
|
244 } |
|
245 TBool tryForAccuracy = EFalse; |
|
246 if (posFoundInTable) |
|
247 { // seek in source is taken care of below |
|
248 // The position was found in the table, and assuming it was found in the low res table |
|
249 // lets try to seek fwd to the exact position. |
|
250 // The reason for this is that the record utility does a stop play instead of a pause play |
|
251 // The inaccuracy in the resume position is then visible, using the low res table. |
|
252 tryForAccuracy = ETrue; |
|
253 } |
|
254 else |
|
255 { // then we must be going forward or just starting |
|
256 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL pos not found in table")); |
|
257 err = iAudioUtility->LastFramePos(position); |
|
258 if (err) // use KErrDoesNotExist or something |
|
259 { // do this a little better, maybe return something different from LastFramePos |
|
260 position = 0; |
|
261 timeMs = 0; |
|
262 } |
|
263 else |
|
264 { |
|
265 err = iAudioUtility->FindFrameTimeFromPos(timeMs, position); |
|
266 } |
|
267 } |
|
268 // seek in source |
|
269 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL seek in the source")); |
|
270 iSourceReadPosition = position+iHeaderOffset+iSyncOffset; |
|
271 iDataSourceAdapter->SourceStopL(); // clear the buffers in the source before seeking and priming it |
|
272 iDataSourceAdapter->SourcePrimeL(); |
|
273 iDataSourceAdapter->SeekToPosition(iSourceReadPosition); |
|
274 iAudioUtility->ResetTable(); |
|
275 iDataSourceAdapter->SourcePlayL(); |
|
276 iCurrentPosition = iSourceReadPosition; |
|
277 iTimePositionInMicroSecs = timeMs; |
|
278 iTimePositionInMicroSecs *=1000; // bh 21Mar08 // need this time to correlate to the position found |
|
279 DP1(_L("CAdvancedAudioPlayController::DoSetPositionL iTimePositionInMicroSecs[%d]"),timeMs); |
|
280 iAudioUtility->SetSourceReference(iTimePositionInMicroSecs/1000, iCurrentPosition-iHeaderOffset-iSyncOffset); |
|
281 TRAP(err, RefillSharedBuffersL()); |
|
282 DP1(_L("CAdvancedAudioPlayController::DoSetPositionL RefillSharedBuffersL[%d]"),err); |
|
283 if (seekFwd && (!posFoundInTable || tryForAccuracy)) |
|
284 { |
|
285 // seeking forward past entries available in table |
|
286 // will scan buffers for frame lengths without rendering |
|
287 // which will add table entries and notify when pos is reached |
|
288 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL do non-render seek fwd")); |
|
289 SeekToTimeMsL(seekTime); // this will set iTimePositionInMicroSecs to the seek fwd time |
|
290 } |
|
291 else |
|
292 { |
|
293 iPreSeekTime = 0; |
|
294 } |
|
295 } |
|
296 else |
|
297 { // continue from closest position and render once the time is reached |
|
298 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL src not seekable continue")); |
|
299 if (seekFwd) |
|
300 { |
|
301 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL src not seekable do non-render seek fwd")); |
|
302 SeekToTimeMsL(seekTime); |
|
303 } |
|
304 } |
|
305 DP0(_L("CAdvancedAudioPlayController::DoSetPositionL end -----------")); |
|
306 } |
|
307 |
|
308 void CAdvancedAudioPlayController::SeekToTimeMsL(TUint aTimeMs) |
|
309 { // used when seeking forward without rendering |
|
310 DP1(_L("CAdvancedAudioPlayController::SeekToTimeMs[%d]"),aTimeMs); |
|
311 |
|
312 iAudioUtility->SeekToTimeMs(aTimeMs); |
|
313 iPlaySeeking = ETrue; |
|
314 // ok to set the time forward because during this seek, devsound won't be getting |
|
315 // any data - so it's samples played would stay 0 and not keep incrementing if position is called |
|
316 iTimePositionInMicroSecs = aTimeMs; |
|
317 iTimePositionInMicroSecs *=1000; |
|
318 DP1(_L("CAdvancedAudioPlayController::SeekToTimeMs iTimePositionInMicroSecs[%d]"),iTimePositionInMicroSecs); |
|
319 if (iState == EPaused) |
|
320 { |
|
321 PlayForPauseSeekL(); |
|
322 } |
|
323 else if (iState == EInitialized) |
|
324 { |
|
325 PlayForInitPositionL(); |
|
326 } |
|
327 } |
|
328 |
|
329 void CAdvancedAudioPlayController::GoToInitPositionL() |
|
330 { |
|
331 DP1(_L("CAdvancedAudioPlayController::GoToInitPositionL[%d]"),iInitPosition.Int64()); |
|
332 if (iInitPosition >= 0) |
|
333 { // -1 is inactive, >=0 will seek |
|
334 TTimeIntervalMicroSeconds position = iInitPosition; |
|
335 DP0(_L("CAdvancedAudioPlayController::GoToInitPositionL clearing iInitPosition and seeking")); |
|
336 iInitPosition = -1; |
|
337 DoSetPositionL(position); |
|
338 } |
|
339 // Register for the Playwindow end position, if PlayWindow is created |
|
340 if (iPlayWindowEndPosition > 0) |
|
341 { |
|
342 iAudioUtility->SetPlayWindowEndTimeMs(iPlayWindowEndPosition.Int64()/1000); |
|
343 } |
|
344 } |
|
345 |
|
346 // ----------------------------------------------------------------------------- |
|
347 // CAdvancedAudioPlayController::RefillSharedBuffersL |
|
348 // ----------------------------------------------------------------------------- |
|
349 // |
|
350 void CAdvancedAudioPlayController::RefillSharedBuffersL() |
|
351 { |
|
352 DP0(_L("CAdvancedAudioPlayController::RefillSharedBuffersL")); |
|
353 TInt i; |
|
354 ClearSharedBuffersL(); |
|
355 for (i=0; i < iSharedBufferMaxNum; i++) |
|
356 { |
|
357 FillSharedBufferL(iSharedBuffers[i]); |
|
358 } |
|
359 } |
|
360 |
|
361 // ----------------------------------------------------------------------------- |
|
362 // CAdvancedAudioPlayController::ReinitSharedBuffersL |
|
363 // ----------------------------------------------------------------------------- |
|
364 // |
|
365 void CAdvancedAudioPlayController::ClearSharedBuffersL() |
|
366 { |
|
367 DP0(_L("CAdvancedAudioPlayController::ClearSharedBuffersL")); |
|
368 for (TInt i=0; i < iSharedBufferMaxNum; i++) |
|
369 { |
|
370 static_cast<CMMFDataBuffer*>(iSharedBuffers[i])->Data().SetLength(0); |
|
371 iSharedBuffers[i]->SetLastBuffer(EFalse); |
|
372 iSharedBuffers[i]->SetStatus(EAvailable); |
|
373 } |
|
374 } |
|
375 |
|
376 // ----------------------------------------------------------------------------- |
|
377 // CAdvancedAudioPlayController::InitSharedBuffersL |
|
378 // ----------------------------------------------------------------------------- |
|
379 // |
|
380 EXPORT_C void CAdvancedAudioPlayController::InitSharedBuffersL() |
|
381 { |
|
382 DP0(_L("CAdvancedAudioPlayController::InitSharedBuffersL")); |
|
383 TInt i; |
|
384 ResetSharedBuffersL(iSharedBufferMaxNum, iSharedBufferMaxSize); |
|
385 for (i=0; i < iSharedBufferMaxNum; i++) |
|
386 { |
|
387 FillSharedBufferL(iSharedBuffers[i]); |
|
388 } |
|
389 } |
|
390 |
|
391 EXPORT_C void CAdvancedAudioPlayController::RefillPreceedingBuffersL() |
|
392 { |
|
393 DP0(_L("CAdvancedAudioPlayController::RefillPreceedingBuffersL")); |
|
394 TInt curIndex = iSharedBufferIndex; |
|
395 TInt curPos = iSharedBuffers[curIndex]->FrameNumber(); |
|
396 TInt maxNum = iSharedBufferMaxNum; |
|
397 // buffers are filled in increasing order |
|
398 TInt index = iSharedBufferIndex; |
|
399 TInt pos; |
|
400 TInt stat; |
|
401 for (TInt i=0; i< maxNum-1; i++) |
|
402 { |
|
403 index++; |
|
404 if (index >= maxNum) |
|
405 { |
|
406 index = 0; |
|
407 } |
|
408 stat = iSharedBuffers[index]->Status(); |
|
409 pos = iSharedBuffers[index]->FrameNumber(); |
|
410 DP4(_L("CAdvancedAudioPlayController::RefillPreceedingBuffersL index[%d] stat[%d] pos[%d] bufpos[%d]"), |
|
411 index, stat, pos, iSharedBuffers[index]->Position()); |
|
412 if ((pos < curPos) && (stat == EFull)) |
|
413 { |
|
414 DP1(_L("CAdvancedAudioPlayController::RefillPreceedingBuffersL index[%d]"),index); |
|
415 FillSharedBufferL(iSharedBuffers[index]); |
|
416 } |
|
417 } |
|
418 } |
|
419 |
|
420 // ----------------------------------------------------------------------------- |
|
421 // CAdvancedAudioPlayController::SourceSinkStopL |
|
422 // ----------------------------------------------------------------------------- |
|
423 // |
|
424 EXPORT_C void CAdvancedAudioPlayController::SourceSinkStopL() |
|
425 { |
|
426 iDataSourceAdapter->SourceStopL(); |
|
427 |
|
428 if (iDataSink->DataSinkType() == KUidMmfFileSink) |
|
429 { |
|
430 iDataSink->SinkStopL(); |
|
431 } |
|
432 } |
|
433 |
|
434 // ----------------------------------------------------------------------------- |
|
435 // CAdvancedAudioPlayController::FillSharedBufferL |
|
436 // Read the next block of data from source into the given buffer. |
|
437 // ----------------------------------------------------------------------------- |
|
438 // |
|
439 EXPORT_C void CAdvancedAudioPlayController::FillSharedBufferL( |
|
440 CMMFBuffer* aBuffer) |
|
441 { |
|
442 DP2(_L("CAdvancedAudioPlayController::FillSharedBufferL ptr[%x], iState[%d]"), |
|
443 static_cast<CMMFDataBuffer*>(aBuffer)->Data().Ptr(), iState); |
|
444 |
|
445 aBuffer->SetLastBuffer(EFalse); |
|
446 aBuffer->SetStatus(EBeingFilled); |
|
447 aBuffer->SetPosition(0); |
|
448 static_cast<CMMFDataBuffer*>(aBuffer)->Data().SetLength(0); |
|
449 |
|
450 TMediaId mediaId(KUidMediaTypeAudio); |
|
451 iDataSourceAdapter->FillBufferL(aBuffer, this, mediaId); |
|
452 } |
|
453 |
|
454 // ----------------------------------------------------------------------------- |
|
455 // CAdvancedAudioPlayController::FindBufferFromPos |
|
456 // ----------------------------------------------------------------------------- |
|
457 // aPos is relative to source position in that it includes any header offsets |
|
458 // Will return KErrNotFound if the position is not found in the buffers. |
|
459 // Will look only in full buffers. |
|
460 EXPORT_C TInt CAdvancedAudioPlayController::FindBufferFromPos(TUint aPos) |
|
461 { |
|
462 DP1(_L("CAdvancedAudioPlayController::FindBufferFromPos, aPos[%d]"), aPos); |
|
463 |
|
464 TInt retVal = KErrNotFound; |
|
465 |
|
466 for (TInt i = 0; i < iSharedBufferMaxNum; i++) |
|
467 { |
|
468 DP5(_L("CAdvancedAudioPlayController::FindBufferFromPos iSharedBuffers[%d], ptr=%x, FrameNumber[%d], Status[%d], LastBuffer[%d]"), i, iSharedBuffers[i]->Data().Ptr(), iSharedBuffers[i]->FrameNumber(), iSharedBuffers[i]->Status(), iSharedBuffers[i]->LastBuffer()); |
|
469 TUint framenumber = iSharedBuffers[i]->FrameNumber(); |
|
470 TUint buffersize = iSharedBuffers[i]->BufferSize(); |
|
471 DP6(_L("CAdvancedAudioPlayController::FindBufferFromPos iSharedBuffers[%d], ptr=%x, FrameNumber[%d], Status[%d], LastBuffer[%d], BufferSize[%d]"), i, iSharedBuffers[i]->Data().Ptr(), framenumber, iSharedBuffers[i]->Status(), iSharedBuffers[i]->LastBuffer(), buffersize); |
|
472 if ((aPos >= framenumber) && (aPos < (framenumber+buffersize)) && |
|
473 // if ((aPos >= framenumber) && (aPos < (framenumber+iSharedBufferMaxSize)) && |
|
474 (iSharedBuffers[i]->Status() == EFull)) |
|
475 { |
|
476 iSharedBuffers[i]->SetPosition(aPos-framenumber); |
|
477 DP1(_L("CAdvancedAudioPlayController::FindBufferFromPos setting position to [%d]"), iSharedBuffers[i]->Position()); |
|
478 retVal = i; |
|
479 break; |
|
480 } |
|
481 } |
|
482 DP1(_L("CAdvancedAudioPlayController::FindBufferFromPos retVal[%d]"), retVal); |
|
483 return retVal; |
|
484 } |
|
485 |
|
486 // ----------------------------------------------------------------------------- |
|
487 // CAdvancedAudioPlayController::SetPositionInSharedBuffers |
|
488 // ----------------------------------------------------------------------------- |
|
489 // |
|
490 /* |
|
491 This function will look in current buffers that aren't being filled and set the |
|
492 buffer and position in it to the corresponding current time. |
|
493 An error will be returned if the exact position was not located in a full buffer. |
|
494 A closest available will be calculated. |
|
495 The buffers past the set will be sent to be filled. |
|
496 If a buffer is full, it can be used. |
|
497 If it is being filled, it can not be used here. |
|
498 If a buffer is other than full or being filled, it should be sent to be filled |
|
499 in the correct sequence after the buffer position is determined. |
|
500 */ |
|
501 EXPORT_C TInt CAdvancedAudioPlayController::SetPositionInSharedBuffers(TUint aTimeMs, TInt& aFoundPosition, TInt& aFoundTimeMs) |
|
502 { |
|
503 TInt err = KErrNone; |
|
504 TUint position; |
|
505 TUint timeMs; |
|
506 |
|
507 DP1(_L("CAdvancedAudioPlayController::SetPositionInSharedBuffersL -- start this[%x]"), this); |
|
508 |
|
509 for (TInt i = 0; i < iSharedBufferMaxNum; i++) |
|
510 { |
|
511 DP6(_L("CAdvancedAudioPlayController::SetPositionInSharedBuffersL iSharedBuffers[%d] ptr[%x] FrameNumber[%d] Status[%d] LastBuffer[%d] bufpos[%d]"), |
|
512 i, iSharedBuffers[i]->Data().Ptr(), iSharedBuffers[i]->FrameNumber(), iSharedBuffers[i]->Status(), iSharedBuffers[i]->LastBuffer(), iSharedBuffers[i]->Position()); |
|
513 |
|
514 if (iSharedBuffers[i]->Status() != EBeingFilled) |
|
515 { // reset the positions on the buffers that the source does not have |
|
516 iSharedBuffers[i]->SetPosition(0); |
|
517 } |
|
518 |
|
519 if (iSharedBuffers[i]->Status() == EBeingEmptied) |
|
520 { |
|
521 iSharedBuffers[i]->SetStatus(EFull); |
|
522 } |
|
523 } |
|
524 timeMs = aTimeMs; |
|
525 // get the closest position from the table for the given time |
|
526 err = iAudioUtility->FindFramePosFromTime(timeMs, position); // err indicates if position found, or just what was available |
|
527 // see if the buffer with this position exists |
|
528 iSharedBufferIndex = FindBufferFromPos(position + iHeaderOffset + iSyncOffset); |
|
529 TUint framenumber = 0; |
|
530 |
|
531 if (iSharedBufferIndex >= 0) |
|
532 { |
|
533 } |
|
534 else |
|
535 { |
|
536 DP0(_L("CAdvancedAudioPlayController::SetPositionInSharedBuffersL, buffer not found")); |
|
537 err = KErrNotFound; |
|
538 // find a frame in current buffers |
|
539 TInt minindex = 0; |
|
540 TInt tempframenum = -1; |
|
541 |
|
542 for (TInt j = 0; j < iSharedBufferMaxNum; j++) |
|
543 { |
|
544 if (iSharedBuffers[j]->Status() == EFull) |
|
545 { |
|
546 framenumber = iSharedBuffers[j]->FrameNumber(); |
|
547 } |
|
548 |
|
549 if (((framenumber < tempframenum) || (tempframenum == -1)) && |
|
550 (iSharedBuffers[j]->Status() == EFull)) |
|
551 { |
|
552 tempframenum = framenumber; |
|
553 minindex = j; |
|
554 } |
|
555 } |
|
556 if (tempframenum == -1) |
|
557 { |
|
558 return KErrNotFound; |
|
559 } |
|
560 iSharedBufferIndex = minindex; |
|
561 framenumber = iSharedBuffers[iSharedBufferIndex]->FrameNumber(); |
|
562 // find a frame start |
|
563 if (framenumber < (iHeaderOffset+iSyncOffset)) |
|
564 { // special case for buffer that still has header info |
|
565 position = 0; |
|
566 timeMs = 0; |
|
567 } |
|
568 else |
|
569 { |
|
570 position = framenumber-iHeaderOffset-iSyncOffset; |
|
571 TInt err1 = iAudioUtility->FindFrameTimeFromPos(timeMs, position); |
|
572 //#ifdef _DEBUG |
|
573 if (err1 != KErrNone) |
|
574 { // we have to find a location in the table for the buffers we have |
|
575 // amr may scan whole file and buffers won't contain start data |
|
576 // but it would only happen for seekable source |
|
577 DP0(_L("CAdvancedAudioPlayController::SetPositionInSharedBuffersL, position in buffers not found -- aborting")); |
|
578 return KErrGeneral; |
|
579 // ASSERT(err1 == KErrNone); |
|
580 } |
|
581 //#endif |
|
582 } |
|
583 } |
|
584 |
|
585 aFoundPosition = position + iHeaderOffset + iSyncOffset; |
|
586 aFoundTimeMs = timeMs; |
|
587 framenumber = iSharedBuffers[iSharedBufferIndex]->FrameNumber(); |
|
588 iSharedBuffers[iSharedBufferIndex]->SetPosition(aFoundPosition-framenumber); |
|
589 // after this send buffers to be filled that need to be filled to maintain correct sequence. |
|
590 DP2(_L("CAdvancedAudioPlayController::SetPositionInSharedBuffersL, iSharedBufferIndex[%d] pos[%d]-- end"), |
|
591 iSharedBufferIndex, aFoundPosition-framenumber); |
|
592 return err; |
|
593 } |
|
594 |
|
595 |
|
596 // ----------------------------------------------------------------------------- |
|
597 // CAdvancedAudioPlayController::UpdateDuration |
|
598 // |
|
599 // Possible parameters are: |
|
600 // -1 = just update duration |
|
601 // 0 = triggers duration changed immediately |
|
602 // a number = will trigger duration changed event if duration has changed this amount given |
|
603 // ----------------------------------------------------------------------------- |
|
604 // |
|
605 EXPORT_C TInt CAdvancedAudioPlayController::UpdateDuration(TInt aLimitInMilliSecond) |
|
606 { // updates iDuration |
|
607 DP2(_L("CAdvancedAudioPlayController::UpdateDuration, iEventsEnabled[%d], aLimitInMilliSecond[%d]"), iEventsEnabled, aLimitInMilliSecond); |
|
608 |
|
609 if (iDurationFrozen) |
|
610 { |
|
611 return KErrNone; |
|
612 } |
|
613 |
|
614 if (aLimitInMilliSecond < -1) |
|
615 { |
|
616 return KErrArgument; |
|
617 } |
|
618 |
|
619 if (!iAudioUtility) |
|
620 { |
|
621 return KErrNone; |
|
622 } |
|
623 |
|
624 TInt64 duration = iAudioUtility->Duration(); // calculates new duration |
|
625 if ((aLimitInMilliSecond == -1) || !iEventsEnabled) |
|
626 { |
|
627 iDuration = duration; |
|
628 } |
|
629 else if ((iDuration != duration) && (Abs(duration-iDuration) >= (aLimitInMilliSecond*1000))) |
|
630 { |
|
631 iDuration = duration; |
|
632 SendEventToClient(TMMFEvent(KStreamControlEventDurationChanged, KErrNone)); |
|
633 } |
|
634 DP1(_L("CAdvancedAudioPlayController::UpdateDuration, iDuration[%d]"), iDuration); |
|
635 return KErrNone; |
|
636 } |
|
637 |
|
638 EXPORT_C TInt CAdvancedAudioPlayController::UpdateBitRate() |
|
639 { |
|
640 DP0(_L("CAdvancedAudioPlayController::UpdateBitRate")); |
|
641 if (iBitRateFrozen) |
|
642 { |
|
643 DP0(_L("CAdvancedAudioPlayController::UpdateBitRate frozen")); |
|
644 return KErrNone; |
|
645 } |
|
646 if (iAudioUtility) |
|
647 { |
|
648 iBitRate = iAudioUtility->BitRate(); |
|
649 DP1(_L("CAdvancedAudioPlayController::UpdateBitRate iBitRate[%d]"), iBitRate); |
|
650 } |
|
651 return KErrNone; |
|
652 } |
|
653 |
|
654 // ----------------------------------------------------------------------------- |
|
655 // CAdvancedAudioPlayController::HandleAutoPauseEvent |
|
656 // ----------------------------------------------------------------------------- |
|
657 // |
|
658 EXPORT_C void CAdvancedAudioPlayController::HandleAutoPauseEvent() |
|
659 { |
|
660 DP0(_L("CAdvancedAudioPlayController::HandleAutoPauseEvent")); |
|
661 iState = EAutoPaused; |
|
662 SendEventToClient(TMMFEvent(KStreamControlEventStateChangedAutoPaused, KErrNone)); |
|
663 } |
|
664 |
|
665 // ----------------------------------------------------------------------------- |
|
666 // CAdvancedAudioPlayController::HandlePreemptionEvent |
|
667 // ----------------------------------------------------------------------------- |
|
668 // |
|
669 EXPORT_C void CAdvancedAudioPlayController::HandlePreemptionEvent(TInt aError) |
|
670 { |
|
671 DP1(_L("CAdvancedAudioPlayController::HandlePreemptionEvent this[%x]"), this); |
|
672 TInt err; |
|
673 |
|
674 // Stop the CActiveSchedulerWait for SetPosition if it is started during Playforseek |
|
675 if(iBlockSetPos) |
|
676 { |
|
677 if (iBlockSetPos->IsStarted()) |
|
678 { |
|
679 iBlockSetPos->AsyncStop(); |
|
680 } |
|
681 } |
|
682 |
|
683 iRequestState = EPaused; |
|
684 TRAP(err, DoPauseL(ETrue)); // this is a preemption pause |
|
685 // In case of pre-emption we should only Pause ... but not Stop. |
|
686 SendEventToClient(TMMFEvent(KMMFEventCategoryPlaybackComplete, aError)); |
|
687 } |
|
688 |
|
689 // ----------------------------------------------------------------------------- |
|
690 // CAdvancedAudioPlayController::HandleGeneralEvent |
|
691 // ----------------------------------------------------------------------------- |
|
692 // |
|
693 EXPORT_C void CAdvancedAudioPlayController::HandleGeneralEvent(const TMMFEvent& aEvent) |
|
694 { |
|
695 DP1(_L("CAdvancedAudioPlayController::HandleGeneralEvent this[%x]"), this); |
|
696 TRAP_IGNORE(DoStopL(aEvent.iErrorCode)); |
|
697 } |
|
698 |
|
699 // ----------------------------------------------------------------------------- |
|
700 // CAdvancedAudioPlayController::SetPlaybackWindowBoundariesL |
|
701 // ----------------------------------------------------------------------------- |
|
702 // |
|
703 EXPORT_C void CAdvancedAudioPlayController::SetPlaybackWindowBoundariesL(const TTimeIntervalMicroSeconds& aStart, const TTimeIntervalMicroSeconds& aEnd) |
|
704 { |
|
705 DP2(_L("CAdvancedAudioPlayController::SetPlaybackWindowBoundariesL start[%d] end[%d]"), aStart.Int64(), aEnd.Int64()); |
|
706 |
|
707 // if client calls SetPlayWindow with the same values then it can be ignored |
|
708 // as the controller may be in the middle of processing. |
|
709 if (iPlayWindowStartPosition == aStart && iPlayWindowEndPosition == aEnd) |
|
710 { |
|
711 return; |
|
712 } |
|
713 |
|
714 if ( iPlayWindowStartPosition < TTimeIntervalMicroSeconds(0) ) |
|
715 { |
|
716 iPlayWindowStartPosition = TTimeIntervalMicroSeconds(0); |
|
717 } |
|
718 else |
|
719 { |
|
720 iPlayWindowStartPosition = aStart; |
|
721 } |
|
722 |
|
723 if ( iPlayWindowEndPosition < TTimeIntervalMicroSeconds(0) ) |
|
724 { |
|
725 iPlayWindowEndPosition = TTimeIntervalMicroSeconds(0); |
|
726 } |
|
727 else |
|
728 { |
|
729 iPlayWindowEndPosition = aEnd; |
|
730 } |
|
731 |
|
732 // We should not set the iInitPosition here because, if ClearPlayWindow is called when iState == EPlaying || EPaused |
|
733 // then iInitPosition will be reset to zero, which should not be the case because the default iInitPosition should be -1. |
|
734 // We just have to clear the play window end postion and continue to play from the current playback position |
|
735 // iInitPosition = iPlayWindowStartPosition; |
|
736 |
|
737 DP2(_L("CAdvancedAudioPlayController::SetPlaybackWindowBoundariesL iPlayWindowStartPosition[%d] iPlayWindowEndPosition[%d]"), iPlayWindowStartPosition.Int64()/1000, iPlayWindowEndPosition.Int64()/1000); |
|
738 // Registers / Unregisters the PlayWindowEndPosition depending on the aEnd value, whenever the play window is set / cleared |
|
739 // For SYMBIAN ClearPlayWindow(): If the ClearPlayWindow() is called during playing, |
|
740 // it deletes the playwindow that has been set |
|
741 iAudioUtility->SetPlayWindowEndTimeMs(iPlayWindowEndPosition.Int64()/1000); |
|
742 if (aStart == iSavedSetPosition) |
|
743 { |
|
744 return; |
|
745 } |
|
746 switch (iState) |
|
747 { |
|
748 case EStopped: // no need to do anything with start position since the start position is saved |
|
749 // iAudioUtility->SetPlayWindowEndTimeMs(iPlayWindowEndPosition.Int64()/1000); |
|
750 // break; |
|
751 case EInitializing: // if already primed or priming, we need to get to correct start position |
|
752 case EInitialized: |
|
753 // DoSetPositionL(iInitPosition); |
|
754 // iAudioUtility->SetPlayWindowEndTimeMs(iPlayWindowEndPosition.Int64()/1000); |
|
755 SetPositionL(iPlayWindowStartPosition); |
|
756 break; |
|
757 case EPlaying: |
|
758 case EPaused: |
|
759 case EAutoPaused: |
|
760 // If the Playwindow start position is greater than the current position |
|
761 // then we seek to the new position and start playing from there. |
|
762 if ( iPlayWindowEndPosition != TTimeIntervalMicroSeconds(0) ) |
|
763 { |
|
764 TTimeIntervalMicroSeconds currentPosition = PositionL(); |
|
765 if ( currentPosition < iPlayWindowStartPosition ) |
|
766 { |
|
767 SetPositionL(iPlayWindowStartPosition); |
|
768 } |
|
769 } |
|
770 break; |
|
771 default: |
|
772 Panic(EBadState); |
|
773 break; |
|
774 } |
|
775 |
|
776 } |
|
777 |
|
778 // ----------------------------------------------------------------------------- |
|
779 // CAdvancedAudioPlayController::AddDataSourceL |
|
780 // ----------------------------------------------------------------------------- |
|
781 // |
|
782 EXPORT_C void CAdvancedAudioPlayController::AddDataSourceL( |
|
783 MDataSource& aSource) |
|
784 { |
|
785 DP1(_L("CAdvancedAudioPlayController::AddDataSourceL this[%x]"), this); |
|
786 iSourceUnreadable = EFalse; |
|
787 iEnablePrimedStateChangedEvent = EFalse; |
|
788 // source type is intended to not be needed by controllers |
|
789 // but metadata functions still use it |
|
790 iSourceType = aSource.DataSourceType(); |
|
791 iBitRateFrozen = EFalse; |
|
792 iDurationFrozen = EFalse; |
|
793 if (iWait) |
|
794 { |
|
795 iWait->AsyncStop(); |
|
796 } |
|
797 if (iDataSourceAdapter) |
|
798 { |
|
799 User::Leave(KErrAlreadyExists); |
|
800 } |
|
801 if (iSharedBufferMaxNum <= 2) |
|
802 { |
|
803 iSharedBufferMaxNum = 3; |
|
804 } |
|
805 |
|
806 |
|
807 // set iReadHeader here in case prime is not called before set position is used. |
|
808 // reset before adding data source |
|
809 DP0(_L("CAdvancedAudioPlayController::AddDataSourceL reseting iSharedBufferCnt iReadHeader iInitPosition position vars")); |
|
810 iSharedBufferCnt = 0; |
|
811 iReadHeader = ETrue; |
|
812 iInitPosition = -1; |
|
813 ResetPositionVariables(); |
|
814 |
|
815 DoAddDataSourceL(); |
|
816 |
|
817 if (!iDataSourceAdapter) |
|
818 { |
|
819 iDataSourceAdapter = CDataSourceAdapter::NewL(); |
|
820 } |
|
821 iDataSourceAdapter->SetDataSourceL(&aSource, this, this); |
|
822 |
|
823 iDataSource = &aSource; // remove this eventually when all the references are removed |
|
824 |
|
825 iSourceIsTimeSeekable = iDataSourceAdapter->IsTimeSeekable(); |
|
826 iSourceIsPosSeekable = iDataSourceAdapter->IsPositonSeekable(); |
|
827 |
|
828 if (iDataSourceAdapter->IsProtectedL()) |
|
829 { |
|
830 if (iDataSink && iDataSink->DataSinkType() == KUidMmfFileSink) |
|
831 { |
|
832 // Conversion is not allowed for DRM protected files |
|
833 User::Leave(KErrNotSupported); |
|
834 } |
|
835 } |
|
836 |
|
837 iDataSourceAdapter->SetSourcePrioritySettings(iPrioritySettings); |
|
838 |
|
839 if (iAudioUtility) |
|
840 { // 3gp would not have utility built yet |
|
841 iAudioUtility->SetObserver(*this); |
|
842 } |
|
843 |
|
844 // we need to block this until duration is calculated if using mmfplayutility |
|
845 iBlockDuration = EFalse; |
|
846 |
|
847 if ((!iEventsEnabled) && (!iDataSourceAdapter->OnlyHeaderPresent())) |
|
848 { |
|
849 // recorder inserts just the header into the file before recording |
|
850 // we don't want to prime in this case |
|
851 DP0(_L("CAdvancedAudioPlayController::AddDataSourceL() Prime to get duration")); |
|
852 iBlockDuration = ETrue; |
|
853 DoInitializeL(); // to get data from the source to calculate bitrate and duration |
|
854 } |
|
855 if ((!iEventsEnabled) && (iDataSourceAdapter->OnlyHeaderPresent())) |
|
856 { |
|
857 // this is a file being recorded. |
|
858 // the recorder might have to open this file again - and if we keep it open |
|
859 // with shared read access, he won't be able to open it for writing. |
|
860 // So we will close the file here. |
|
861 iDataSourceAdapter->SourceStopL(); |
|
862 } |
|
863 } |
|
864 |
|
865 // ----------------------------------------------------------------------------- |
|
866 // CAdvancedAudioPlayController::DurationL |
|
867 // |
|
868 // ----------------------------------------------------------------------------- |
|
869 // |
|
870 EXPORT_C TTimeIntervalMicroSeconds CAdvancedAudioPlayController::DurationL() const |
|
871 { |
|
872 DP2(_L("CAdvancedAudioController::DurationL this[%x] iDuration[%d]"), this, iDuration); |
|
873 // we need to block this until duration is calculated if using mmfplayutility |
|
874 if (iBlockDuration) |
|
875 { |
|
876 iBlockDuration = EFalse; |
|
877 iWait = new (ELeave) CActiveSchedulerWait(); |
|
878 DP0(_L("CAdvancedAudioController::DurationL() blocking for duration")); |
|
879 iWait->Start(); |
|
880 DP0(_L("CAdvancedAudioController::DurationL() continuing")); |
|
881 delete iWait; |
|
882 iWait = NULL; |
|
883 } |
|
884 return TTimeIntervalMicroSeconds(iDuration); |
|
885 } |
|
886 |
|
887 |
|
888 // ----------------------------------------------------------------------------- |
|
889 // CAdvancedAudioPlayController::AddDataSinkL |
|
890 // ----------------------------------------------------------------------------- |
|
891 // |
|
892 EXPORT_C void CAdvancedAudioPlayController::AddDataSinkL( |
|
893 MDataSink& aSink) |
|
894 { |
|
895 DP1(_L("CAdvancedAudioPlayController::AddDataSinkL this[%x]"), this); |
|
896 |
|
897 // TThreadStackInfo info; |
|
898 // RThread().StackInfo(info); |
|
899 // DP1(_L("### Stack Base Address: [0x%x]"), info.iBase); |
|
900 // DP1(_L("### Stack End Address: [0x%x]"), info.iLimit); |
|
901 |
|
902 if (iDataSink) |
|
903 { |
|
904 User::Leave(KErrAlreadyExists); |
|
905 } |
|
906 |
|
907 if (aSink.DataSinkType() == KUidMmfAudioOutput) |
|
908 { |
|
909 iDataSink = &aSink; |
|
910 } |
|
911 else if (aSink.DataSinkType() == KUidMmfFileSink) |
|
912 { // only use of source type here other than metadata functions |
|
913 if (iDataSource && iSourceType == KUidMmfFileSource) |
|
914 { |
|
915 CMMFFile* file = static_cast<CMMFFile*>(iDataSource); |
|
916 file->SourcePrimeL(); |
|
917 |
|
918 if (file->IsProtectedL()) |
|
919 { |
|
920 // Conversion is not allowed for DRM protected files |
|
921 User::Leave(KErrNotSupported); |
|
922 } |
|
923 } |
|
924 |
|
925 iDataSink = &aSink; |
|
926 iDataSink->SinkPrimeL(); |
|
927 iDataSink->SinkThreadLogon(*this); |
|
928 iDriveNumber = iAudioUtility->GetDriveNumber(static_cast<CMMFFile*>(iDataSink)->FileDrive()); |
|
929 } |
|
930 else |
|
931 { |
|
932 User::Leave(KErrNotSupported); |
|
933 } |
|
934 DoAddDataSinkL(); // iAudioOutput will be created here |
|
935 // if the source has already been added but the output has not been configured because the sink was |
|
936 // not ready, then we will configure the output here. |
|
937 if (iSinkInitDataReady) |
|
938 { |
|
939 DoInitializeSinkL(); // the decoder will be created here |
|
940 } |
|
941 } |
|
942 |
|
943 // ----------------------------------------------------------------------------- |
|
944 // CAdvancedAudioPlayController::RemoveDataSourceL |
|
945 // ----------------------------------------------------------------------------- |
|
946 // |
|
947 EXPORT_C void CAdvancedAudioPlayController::RemoveDataSourceL( |
|
948 MDataSource& aDataSource) |
|
949 { |
|
950 DP0(_L("CAdvancedAudioPlayController::RemoveDataSourceL")); |
|
951 |
|
952 if (!iDataSource) |
|
953 { |
|
954 User::Leave(KErrNotReady); |
|
955 } |
|
956 |
|
957 if (iDataSource != &aDataSource) |
|
958 { |
|
959 User::Leave(KErrArgument); |
|
960 } |
|
961 |
|
962 if ((iState != EStopped) && (iState != EInitialized)) |
|
963 { |
|
964 User::Leave(KErrNotReady); |
|
965 } |
|
966 |
|
967 iDataSource->SourceStopL(); // should always stop source before logoff |
|
968 iDataSource->SourceThreadLogoff(); |
|
969 |
|
970 MapcDeletePlaybackWindowL(); |
|
971 |
|
972 if (iIsDRMProtected) |
|
973 { |
|
974 delete iDataSource; |
|
975 } |
|
976 iDataSource = NULL; |
|
977 delete iDataSourceAdapter; |
|
978 iDataSourceAdapter = NULL; |
|
979 iSinkInitDataReady = EFalse; |
|
980 } |
|
981 |
|
982 // ----------------------------------------------------------------------------- |
|
983 // CAdvancedAudioPlayController::RemoveDataSinkL |
|
984 // ----------------------------------------------------------------------------- |
|
985 // |
|
986 EXPORT_C void CAdvancedAudioPlayController::RemoveDataSinkL( |
|
987 MDataSink& aDataSink) |
|
988 { |
|
989 DP0(_L("CAdvancedAudioPlayController::RemoveDataSinkL")); |
|
990 |
|
991 if (!iDataSink) |
|
992 { |
|
993 User::Leave(KErrNotReady); |
|
994 } |
|
995 |
|
996 if (iDataSink != &aDataSink) |
|
997 { |
|
998 User::Leave(KErrArgument); |
|
999 } |
|
1000 |
|
1001 if ((iState != EStopped) && (iState != EInitialized)) |
|
1002 { |
|
1003 User::Leave(KErrNotReady); |
|
1004 } |
|
1005 |
|
1006 iDataSink->SinkStopL(); // should always stop source before logoff |
|
1007 iDataSink->SinkThreadLogoff(); |
|
1008 |
|
1009 // dereference Decoder from Utility before deleting AudioOutput (which took ownership of decoder) |
|
1010 if (iAudioUtility) |
|
1011 { |
|
1012 iAudioUtility->DeReferenceDecoder(); |
|
1013 } |
|
1014 |
|
1015 delete iAudioOutput; |
|
1016 iAudioOutput = NULL; |
|
1017 iDataSink = NULL; |
|
1018 iDecoderExists = EFalse; |
|
1019 } |
|
1020 |
|
1021 // ----------------------------------------------------------------------------- |
|
1022 // CAdvancedAudioPlayController::ResetL |
|
1023 // ----------------------------------------------------------------------------- |
|
1024 // |
|
1025 EXPORT_C void CAdvancedAudioPlayController::ResetL() |
|
1026 { |
|
1027 DP0(_L("CAdvancedAudioPlayController::ResetL")); |
|
1028 |
|
1029 RemoveDataSourceL(*iDataSource); |
|
1030 RemoveDataSinkL(*iDataSink); |
|
1031 } |
|
1032 |
|
1033 // ----------------------------------------------------------------------------- |
|
1034 // CAdvancedAudioPlayController::PrimeL |
|
1035 // ----------------------------------------------------------------------------- |
|
1036 // |
|
1037 EXPORT_C void CAdvancedAudioPlayController::PrimeL() |
|
1038 { // this is for user call only - this changes the request state |
|
1039 DP2(_L("CAdvancedAudioPlayController::PrimeL this[%x] iState[%d]"), this, iState); |
|
1040 |
|
1041 switch (iState) |
|
1042 { |
|
1043 case EStopped: |
|
1044 iRequestState = EInitialized; |
|
1045 iEnablePrimedStateChangedEvent = ETrue; |
|
1046 DoInitializeL(); |
|
1047 break; |
|
1048 case EInitializing: // we may already be initializing since we may doinitialize to get header info for mmf client-events disabled) |
|
1049 iRequestState = EInitialized; |
|
1050 iEnablePrimedStateChangedEvent = ETrue; |
|
1051 break; |
|
1052 case EInitialized: |
|
1053 iRequestState = EInitialized; |
|
1054 iEnablePrimedStateChangedEvent = ETrue; |
|
1055 if (AllBuffersFilled()) |
|
1056 { |
|
1057 iEnablePrimedStateChangedEvent = EFalse; |
|
1058 DP0(_L("CAdvancedAudioPlayController::PrimeL state changed primed")); |
|
1059 SendEventToClient(TMMFEvent(KStreamControlEventStateChangedPrimed, KErrNone)); // both source and sink are ready. |
|
1060 } |
|
1061 break; |
|
1062 case EPlaying: |
|
1063 case EPaused: |
|
1064 case EAutoPaused: |
|
1065 break; |
|
1066 default: |
|
1067 Panic(EBadState); |
|
1068 break; |
|
1069 } |
|
1070 } |
|
1071 |
|
1072 void CAdvancedAudioPlayController::DoInitializeL() |
|
1073 { // this is the DoPrimeL |
|
1074 DP1(_L("CAdvancedAudioPlayController::DoInitializeL this[%x]"), this); |
|
1075 |
|
1076 if (iSourceUnreadable) |
|
1077 { |
|
1078 DP0(_L("CAdvancedAudioPlayController::PrimeL KErrCorrupt")); |
|
1079 User::Leave(KErrCorrupt); |
|
1080 } |
|
1081 |
|
1082 if (iDataSourceAdapter) |
|
1083 { |
|
1084 iState = EInitializing; |
|
1085 if (iAudioUtility) |
|
1086 { // 3gp won't have a utility yet |
|
1087 TInt err = iAudioUtility->ResetTable(); |
|
1088 } |
|
1089 iDataSourceAdapter->SourcePrimeL(); // get the source ready to process data |
|
1090 iDataSourceAdapter->SourcePlayL(); // get the source ready to send data |
|
1091 InitSharedBuffersL(); |
|
1092 // The position variables are reset when primed. |
|
1093 // We don't want to reset them during stop because time needs to be maintained |
|
1094 // in case position is called after stopping. |
|
1095 ResetPositionVariables(); |
|
1096 } |
|
1097 } |
|
1098 |
|
1099 |
|
1100 // ----------------------------------------------------------------------------- |
|
1101 // CAdvancedAudioPlayController::PlayL |
|
1102 // ----------------------------------------------------------------------------- |
|
1103 // |
|
1104 EXPORT_C void CAdvancedAudioPlayController::PlayL() |
|
1105 { // this is for user call only - this changes the request state |
|
1106 DP5(_L("CAdvancedAudioPlayController::PlayL this[%x] iCurrentPosition[%d] iSourceReadPosition[%d] iState[%d] iRequestState[%d]"), |
|
1107 this, iCurrentPosition, iSourceReadPosition, iState, iRequestState); |
|
1108 if (iSourceUnreadable) |
|
1109 { |
|
1110 SendEventToClient(TMMFEvent(KMMFEventCategoryPlaybackComplete, KErrCorrupt)); |
|
1111 SendEventToClient(TMMFEvent(KStreamControlEventStateChangedStopped, KErrCorrupt)); |
|
1112 return; |
|
1113 } |
|
1114 if (iRequestState == EPlaying) |
|
1115 { |
|
1116 return; |
|
1117 } |
|
1118 if (iPlayingForDuration || iPlayingForPauseSeek || iPlayingForInitPos) |
|
1119 { |
|
1120 // PlayForDuration is not used. |
|
1121 // Internally we use DoPlayL(). |
|
1122 // Just save the request and return, we don't want to call doplay again here. |
|
1123 // User has overridden reason for play - we don't want to transition back to old state now. |
|
1124 // iPlayingForDuration, iPlayingForPauseSeek, and iPlayingForInitPos will |
|
1125 // be reset when the current seek is complete. |
|
1126 // Already playing internally so send state change |
|
1127 iRequestState = EPlaying; |
|
1128 SendEventToClient(TMMFEvent(KStreamControlEventStateChangedPlaying, KErrNone)); |
|
1129 return; |
|
1130 } |
|
1131 switch (iState) |
|
1132 { |
|
1133 case EStopped: |
|
1134 // don't initialize playback with DoInitialize() here |
|
1135 // because latent play calls would get through after stops - seek to eof and play |
|
1136 // also, latent play calls would get through after pausing just after eof reached and controller stops. |
|
1137 DP1(_L("CAdvancedAudioPlayController::PlayL iState=EStopped and iRequestState[%d]"), iRequestState); |
|
1138 if ((iRequestState == EInitialized) || (iRequestState == EPaused)) |
|
1139 { // primed state requested, but will stop if eof |
|
1140 SendEventToClient(TMMFEvent(KMMFEventCategoryPlaybackComplete, KErrNone)); |
|
1141 } |
|
1142 break; |
|
1143 case EInitializing: // priming |
|
1144 iRequestState = EPlaying; |
|
1145 break; |
|
1146 case EInitialized: // primed |
|
1147 iRequestState = EPlaying; |
|
1148 if (iPlayWindowEndPosition > 0) |
|
1149 { |
|
1150 DP1(_L("CAdvancedAudioPlayController::PlayL iAudioUtility->SetPlayWindowEndTimeMs(%d)"), I64LOW(iPlayWindowEndPosition.Int64()/1000)); |
|
1151 iAudioUtility->SetPlayWindowEndTimeMs(iPlayWindowEndPosition.Int64() / 1000); |
|
1152 } |
|
1153 if (iAudioOutput->IsDSStopped()) |
|
1154 { // during loop play the output is not stopped unless we did a seek - seek stops the output and we need to call DoPlay |
|
1155 DP0(_L("CAdvancedAudioPlayController::PlayL Calling DoPlay iState=EInitialized and iRequestState=EPlaying")); |
|
1156 DoPlayL(); |
|
1157 } |
|
1158 else |
|
1159 { |
|
1160 DP1(_L("CAdvancedAudioPlayController::PlayL Calling DoResume iState=EInitialized iCurrentPosition[%d]"), iCurrentPosition); |
|
1161 if (IsLoopPlayEnabled()) |
|
1162 { |
|
1163 DoResume(iCurrentPosition); // sends state change event if successful |
|
1164 } |
|
1165 else |
|
1166 { |
|
1167 DoPlayL(); |
|
1168 } |
|
1169 } |
|
1170 break; |
|
1171 case EPlaying: |
|
1172 break; |
|
1173 case EPaused: |
|
1174 iRequestState = EPlaying; |
|
1175 if (iPlayWindowEndPosition > 0) |
|
1176 { |
|
1177 DP1(_L("CAdvancedAudioPlayController::PlayL iAudioUtility->SetPlayWindowEndTimeMs(%d)"), I64LOW(iPlayWindowEndPosition.Int64()/1000)); |
|
1178 iAudioUtility->SetPlayWindowEndTimeMs(iPlayWindowEndPosition.Int64() / 1000); |
|
1179 } |
|
1180 if (iAudioOutput->IsDSStopped()) |
|
1181 { // during loop play the output is not stopped unless we did a seek - seek stops the output and we need to call DoPlay |
|
1182 DP0(_L("CAdvancedAudioPlayController::PlayL Calling DoPlay iState=EPaused")); |
|
1183 DoPlayL(); |
|
1184 } |
|
1185 else |
|
1186 { |
|
1187 DP1(_L("CAdvancedAudioPlayController::PlayL Calling DoResume iState=EPaused iCurrentPosition[%d]"), iCurrentPosition); |
|
1188 if (IsLoopPlayEnabled()) |
|
1189 { |
|
1190 DoResume(iCurrentPosition); |
|
1191 } |
|
1192 else |
|
1193 { |
|
1194 DoPlayL(); |
|
1195 } |
|
1196 } |
|
1197 break; |
|
1198 case EAutoPaused: |
|
1199 break; |
|
1200 default: |
|
1201 Panic(EBadState); |
|
1202 break; |
|
1203 } |
|
1204 |
|
1205 // SendEventToClient(TMMFEvent(KStreamControlEventStateChangedPlaying, KErrNone)); |
|
1206 } |
|
1207 |
|
1208 |
|
1209 void CAdvancedAudioPlayController::DoPlayL() |
|
1210 { |
|
1211 DP2(_L("CAdvancedAudioPlayController::DoPlayL reqstate[%d] pfps[%d]"),iRequestState,iPlayingForPauseSeek); |
|
1212 if ((iRequestState == EPlaying) || iPlayingForInitPos || iPlayingForDuration || iPlayingForPauseSeek) |
|
1213 { |
|
1214 if (AllBuffersFilled()) // state entry condition |
|
1215 { // DoSetPositionL will look in shared buffers first and not seek if found |
|
1216 // we may consider to use the current time here and resolve current position here instead of other places in the code |
|
1217 |
|
1218 if (iCurrentPosition == KMaxTUint) |
|
1219 { // in case of a time seekable source, we use KMaxTUint in the seek since we don't know source position |
|
1220 DP0(_L("CAdvancedAudioPlayController::DoPlayL Resetting iCurrentPosition to zero")); |
|
1221 iCurrentPosition = 0; |
|
1222 } |
|
1223 |
|
1224 iSharedBufferIndex = FindBufferFromPos(iCurrentPosition); |
|
1225 |
|
1226 // if there was seek past end of file, the buffers may not have any data |
|
1227 // they may all be empty last buffers |
|
1228 if ((iSharedBufferIndex < 0) and AllBuffersEmpty()) |
|
1229 { // position in buffer not found |
|
1230 DoStopL(KErrNone); |
|
1231 return; |
|
1232 } |
|
1233 if (iSharedBufferIndex < 0) |
|
1234 { |
|
1235 DoStopL(KErrGeneral); |
|
1236 return; |
|
1237 } |
|
1238 |
|
1239 if (iDataSink->DataSinkType() == KUidMmfFileSink) |
|
1240 { |
|
1241 static_cast<CMMFClip*>(iDataSink)->SinkPrimeL(); |
|
1242 static_cast<CMMFFile*>(iDataSink)->FileL().SetSize(0); // Reset output file |
|
1243 } |
|
1244 |
|
1245 // if client has called Play() again, then we need to set the repeats so that the loop play can go on. |
|
1246 // this must be done only when all the repeats are done and when the play back has stopped after the repeats |
|
1247 // if client issues a play after the loop play, we must retain the repeat count and start the loop play again. |
|
1248 // if play was called during loop play it must be ignored and loop play should continue |
|
1249 if ((!iLoopPlayEnabled) && ((iRepeatCount > 0) || (iRepeatCount == KMdaRepeatForever))) |
|
1250 { |
|
1251 if ((iTrailingSilenceTimer) && (iTrailingSilenceTimer->IsActive())) |
|
1252 iTrailingSilenceTimer->Cancel(); |
|
1253 DoSetRepeats(iRepeatCount, TTimeIntervalMicroSeconds(iTrailingSilenceMs.Int())); |
|
1254 } |
|
1255 TInt errExIntent = KErrNone; |
|
1256 if (!iDisableAutoIntent && (iRequestState == EPlaying)) |
|
1257 { |
|
1258 if (iIntentStopped) |
|
1259 { |
|
1260 errExIntent = iDataSourceAdapter->EvaluateIntent(ContentAccess::EPlay); |
|
1261 if (errExIntent == KErrNone) |
|
1262 { |
|
1263 errExIntent = iDataSourceAdapter->ExecuteIntent(ContentAccess::EPlay); |
|
1264 DP2(_L("CAdvancedAudioPlayController::DoPlayL() iIntentStopped[%d] errExIntent[%d]"), iIntentStopped, errExIntent ); |
|
1265 if (errExIntent == KErrNone) |
|
1266 iIntentStopped = EFalse; |
|
1267 } |
|
1268 else // if ((errExIntent == KErrKErrNoRights) || any other error) |
|
1269 { |
|
1270 DoStopL(errExIntent); |
|
1271 return; |
|
1272 } |
|
1273 } |
|
1274 else |
|
1275 { |
|
1276 errExIntent = iDataSourceAdapter->EvaluateIntent((iState == EPaused) ? ContentAccess::EContinue : ContentAccess::EPlay); |
|
1277 if (errExIntent == KErrNone) |
|
1278 { |
|
1279 errExIntent = iDataSourceAdapter->ExecuteIntent((iState == EPaused) ? ContentAccess::EContinue : ContentAccess::EPlay); |
|
1280 DP2(_L("CAdvancedAudioPlayController::DoPlayL() iIntentStopped[%d] errExIntent[%d]"), iIntentStopped, errExIntent ); |
|
1281 } |
|
1282 else // if ((errExIntent == KErrKErrNoRights) || any other error) |
|
1283 { |
|
1284 DoStopL(errExIntent); |
|
1285 return; |
|
1286 } |
|
1287 } |
|
1288 } |
|
1289 if ((errExIntent != KErrNone) && (errExIntent != KErrNotSupported)) |
|
1290 { |
|
1291 DP1(_L("CAdvancedAudioPlayController::DoPlayL() errExIntent[%d]"), errExIntent); |
|
1292 // const TInt KErrCANoRights = -17452; from caferr.h |
|
1293 // don't leave because, stopping the source above will delete this active object.. |
|
1294 // the active scheduler will try to call runerror on the active object, but it's gone. |
|
1295 //User::Leave(errExIntent); |
|
1296 return; |
|
1297 } |
|
1298 iState = EPlaying; // stay in initialized state so bufferfilled will continue to call doplay |
|
1299 iResumePosition = -1; |
|
1300 iAudioOutput->PlayL(&iSharedBuffers, iSharedBufferIndex); |
|
1301 SendEventToClient(TMMFEvent(KStreamControlEventStateChangedPlaying, KErrNone)); |
|
1302 } |
|
1303 } |
|
1304 } |
|
1305 |
|
1306 // ----------------------------------------------------------------------------- |
|
1307 // CAdvancedAudioPlayController::PauseL |
|
1308 // ----------------------------------------------------------------------------- |
|
1309 // |
|
1310 EXPORT_C void CAdvancedAudioPlayController::PauseL() |
|
1311 { // this is for user call only - this changes the request state |
|
1312 DP2(_L("CAdvancedAudioPlayController::PauseL this[%x] iState[%d]"), this, iState); |
|
1313 if (iRequestState == EPaused) |
|
1314 { |
|
1315 return; |
|
1316 } |
|
1317 iRequestState = EPaused; |
|
1318 |
|
1319 switch (iState) |
|
1320 { |
|
1321 case EStopped: |
|
1322 case EInitializing: |
|
1323 case EInitialized: |
|
1324 break; |
|
1325 case EAutoPaused: |
|
1326 case EPlaying: // pause even if we are playing for seeking so state change will occur |
|
1327 DoPauseL(); // the pause will set position correctly |
|
1328 SendEventToClient(TMMFEvent(KStreamControlEventStateChangedPaused, KErrNone)); |
|
1329 break; |
|
1330 case EPaused: |
|
1331 break; |
|
1332 default: |
|
1333 Panic(EBadState); |
|
1334 break; |
|
1335 } |
|
1336 // SendEventToClient(TMMFEvent(KStreamControlEventStateChangedPaused, KErrNone)); |
|
1337 } |
|
1338 |
|
1339 void CAdvancedAudioPlayController::DoPauseL(TBool aPreemption) |
|
1340 { |
|
1341 DP5(_L("CAdvancedAudioPlayController::DoPauseL pfsp[%d] pfip[%d] pfps[%d] pfd[%d] rqststate[%d]"), |
|
1342 iPausingForSetPos, iPlayingForInitPos, iPlayingForPauseSeek, iPlayingForDuration, iRequestState); |
|
1343 // if ((iPausingForSetPos || iPlayingForInitPos || iPlayingForPauseSeek || iPlayingForDuration) && |
|
1344 // (iRequestState != EPaused)) // seek position reached and returning to pause state automatically |
|
1345 // both user pause and internal pause come here. |
|
1346 // Internal pause may be from preemption or seek position reached. |
|
1347 /* |
|
1348 * Pre-emption case: Pause during a pre-emption and not seeking |
|
1349 */ |
|
1350 if ((iPlayingForInitPos || iPlayingForPauseSeek || iPausingForSetPos) && aPreemption) |
|
1351 {// we got preempted during a seek |
|
1352 // we're already seeking to a position. When we get there we'll come here again, but handle it below |
|
1353 DP0(_L("CAdvancedAudioPlayController::DoPauseL got a preemption during seek")); |
|
1354 return; |
|
1355 } |
|
1356 |
|
1357 /* |
|
1358 * Internal Pause case: Pausing during an internal seeking and not pre-emption case. |
|
1359 */ |
|
1360 if ((iPlayingForInitPos || iPlayingForPauseSeek || iPausingForSetPos) && !aPreemption) |
|
1361 { // already seeking to position, so we don't want to set position again |
|
1362 DP0(_L("CAdvancedAudioPlayController::DoPauseL not setting pos because we are already seeking")); |
|
1363 if (IsLoopPlayEnabled()) |
|
1364 { |
|
1365 DP0(_L("CAdvancedAudioPlayController::DoPauseL AudioOutput->StopL(EFalse)")); |
|
1366 // If in LoopPlay mode, DO NOT STOP the Devsound from AudioOutput |
|
1367 iAudioOutput->StopL(EFalse); |
|
1368 } |
|
1369 else |
|
1370 { |
|
1371 // If in normal Play mode, Devsound can be stopped during Pause |
|
1372 // StopL method takes the default value as ETrue, so we don't need to pass any value. |
|
1373 |
|
1374 // if we are seeking, we need to flush the devsound buffers regardless of loop play |
|
1375 DP0(_L("CAdvancedAudioPlayController::DoPauseL AudioOutput->StopL()")); |
|
1376 iAudioOutput->StopL(); |
|
1377 } |
|
1378 if (iPlayingForInitPos) |
|
1379 { |
|
1380 iState = EInitialized; |
|
1381 } |
|
1382 else |
|
1383 { |
|
1384 iState = EPaused; |
|
1385 } |
|
1386 iPlayingForPauseSeek = EFalse; |
|
1387 iPlayingForInitPos = EFalse; |
|
1388 // iPausingForSetPos is cleared when seekposition reached |
|
1389 // iPlayingForDuration is cleared in stop which is where seekposreached sends it |
|
1390 TInt foundPosition; |
|
1391 TInt foundTimeMs; |
|
1392 TUint time = iTimePositionInMicroSecs/1000; // time was set at the seek so it would be correct after seek. |
|
1393 DP1(_L("CAdvancedAudioPlayController::DoPauseL iTimePositionInMicroSecs[%u]"),iTimePositionInMicroSecs); |
|
1394 // this set position is short version because we expect that we have the buffer available after the seek. |
|
1395 // since we are not setting position as below, we can get the buffer ready for play. |
|
1396 TInt err = SetPositionInSharedBuffers(time, foundPosition, foundTimeMs); |
|
1397 iCurrentPosition = foundPosition; |
|
1398 iTimePositionInMicroSecs = foundTimeMs; // just to get exact to position |
|
1399 iTimePositionInMicroSecs *=1000; |
|
1400 DP1(_L("CAdvancedAudioPlayController::DoPauseL iCurrentPosition[%d]"),iCurrentPosition); |
|
1401 DP1(_L("CAdvancedAudioPlayController::DoPauseL iTimePositionInMicroSecs[%u]"),foundTimeMs); |
|
1402 // setpositioninsharedbuffers can reposition, so we need to update the ref |
|
1403 iAudioUtility->SetSourceReference(foundTimeMs, iCurrentPosition-iHeaderOffset-iSyncOffset); |
|
1404 |
|
1405 RefillPreceedingBuffersL(); |
|
1406 |
|
1407 return; |
|
1408 } |
|
1409 |
|
1410 /* |
|
1411 * User Pause case: User Pause when TruePause is not supported by DevSound adaptation (not seeking and not pre-emption) |
|
1412 */ |
|
1413 // if user interrupts pause, don't mess with the time since it was already set at the seek |
|
1414 // and the position will end up getting set to that time below. |
|
1415 if (iPlayingForInitPos || iPlayingForPauseSeek) |
|
1416 { |
|
1417 DP2(_L("CAdvancedAudioPlayController::DoPauseL UserPause pfip[%d] pfps[%d]"),iPlayingForInitPos, iPlayingForPauseSeek); |
|
1418 iPlayingForPauseSeek = EFalse; |
|
1419 iPlayingForInitPos = EFalse; |
|
1420 } |
|
1421 else |
|
1422 { |
|
1423 DP1(_L("CAdvancedAudioPlayController::DoPauseL UserPause before calc iTimePositionInMicroSecs [%d]"), iTimePositionInMicroSecs); |
|
1424 // during loop play devsound returns the incremented value of the position |
|
1425 // it must be adjusted to the duration of the audio clip so that playback can resume from the position where it was paused |
|
1426 if (IsLoopPlayEnabled()) |
|
1427 { |
|
1428 iTimePositionInMicroSecs += (iAudioOutput->CalculateAudioOutputPositionL() - iSavedTimePositionInMicroSecs); |
|
1429 } |
|
1430 else |
|
1431 { |
|
1432 iTimePositionInMicroSecs += iAudioOutput->CalculateAudioOutputPositionL(); |
|
1433 } |
|
1434 DP1(_L("CAdvancedAudioPlayController::DoPauseL UserPause after calc iTimePositionInMicroSecs [%d]"), iTimePositionInMicroSecs); |
|
1435 } |
|
1436 |
|
1437 // in case of client pause, stop the trailing silence timer during loop play and stay in paused state. |
|
1438 // controller goes to play state when client calls play |
|
1439 if ((iTrailingSilenceTimer) && (iTrailingSilenceTimer->IsActive())) |
|
1440 { |
|
1441 DP0(_L("CAdvancedAudioPlayController::DoPauseL UserPause Cancelling the TrailingSilenceTimer for User Pause ")); |
|
1442 iTrailingSilenceTimer->Cancel(); |
|
1443 } |
|
1444 |
|
1445 TInt errExIntent = KErrNone; |
|
1446 if (!iDisableAutoIntent) |
|
1447 { |
|
1448 errExIntent = iDataSourceAdapter->EvaluateIntent(ContentAccess::EPause); |
|
1449 if (errExIntent == KErrNone) |
|
1450 { |
|
1451 errExIntent = iDataSourceAdapter->ExecuteIntent(ContentAccess::EPause); |
|
1452 } |
|
1453 } |
|
1454 |
|
1455 if (IsLoopPlayEnabled()) |
|
1456 { |
|
1457 DP0(_L("CAdvancedAudioPlayController::DoPauseL UserPause AudioOutput->StopL(EFalse)")); |
|
1458 // if in LoopPlay mode, DO NOT STOP the Devsound during a pause operation since we resume the playback from the paused position |
|
1459 iAudioOutput->StopL(EFalse); |
|
1460 } |
|
1461 else |
|
1462 { |
|
1463 // If in normal Play mode, Devsound can be stopped during Pause |
|
1464 // StopL method takes the default value as ETrue, so we don't need to pass any value. |
|
1465 DP0(_L("CAdvancedAudioPlayController::DoPauseL UserPause AudioOutput->StopL()")); |
|
1466 iAudioOutput->StopL(); |
|
1467 } |
|
1468 iState = EPaused; |
|
1469 DoSetPositionL(TTimeIntervalMicroSeconds(iTimePositionInMicroSecs)); // if we were play seeking, this will reseek to desired position |
|
1470 |
|
1471 if ((errExIntent != KErrNone) && (errExIntent != KErrNotSupported)) |
|
1472 { |
|
1473 // User::Leave(errExIntent); |
|
1474 return; |
|
1475 } |
|
1476 } |
|
1477 |
|
1478 // ----------------------------------------------------------------------------- |
|
1479 // CAdvancedAudioPlayController::StopL |
|
1480 // ----------------------------------------------------------------------------- |
|
1481 // |
|
1482 EXPORT_C void CAdvancedAudioPlayController::StopL() |
|
1483 { // this is for user call only - this changes the request state |
|
1484 DP2(_L("CAdvancedAudioPlayController::StopL this[%x] iState[%d]"), this, iState); |
|
1485 if (iRequestState == EStopped) |
|
1486 { |
|
1487 return; |
|
1488 } |
|
1489 iRequestState = EStopped; |
|
1490 switch (iState) |
|
1491 { |
|
1492 case EStopped: |
|
1493 break; |
|
1494 case EInitializing: |
|
1495 case EInitialized: |
|
1496 case EPlaying: |
|
1497 case EPaused: |
|
1498 case EAutoPaused: |
|
1499 TRAP_IGNORE(DoStopL(KErrNone)); // ignore if any leave to ensure internal state change on the next statement |
|
1500 break; |
|
1501 default: |
|
1502 Panic(EBadState); |
|
1503 break; |
|
1504 } |
|
1505 // user event |
|
1506 |
|
1507 SendEventToClient(TMMFEvent(KStreamControlEventStateChangedStopped, KErrNone)); |
|
1508 } |
|
1509 |
|
1510 // ----------------------------------------------------------------------------- |
|
1511 // CAdvancedAudioPlayController::DoStopL |
|
1512 // ----------------------------------------------------------------------------- |
|
1513 // |
|
1514 EXPORT_C void CAdvancedAudioPlayController::DoStopL(TInt aError) |
|
1515 { |
|
1516 DP3(_L("CAdvancedAudioPlayController::DoStopL this[%x] iState[%d], aError[%d]"), this, iState, aError); |
|
1517 DP0(_L("CAdvancedAudioPlayController::DoStopL reseting iInitPosition iReadHeader")); |
|
1518 CleanupForStop(); |
|
1519 // If the playwindow is still active (iPlayWindowEndPosition > 0) |
|
1520 // then set the current playback position to play window start position |
|
1521 // If there is a client Stop() call or End of playback event then we need to check for the |
|
1522 // playwindow start position. |
|
1523 if (iPlayWindowEndPosition > 0) |
|
1524 { |
|
1525 iInitPosition = iPlayWindowStartPosition; |
|
1526 } |
|
1527 else |
|
1528 { |
|
1529 iInitPosition = -1; |
|
1530 } |
|
1531 if (iTrailingSilenceTimer) |
|
1532 { |
|
1533 delete iTrailingSilenceTimer; |
|
1534 iTrailingSilenceTimer = NULL; |
|
1535 } |
|
1536 iReadHeader = ETrue; |
|
1537 iEnablePrimedStateChangedEvent = EFalse; |
|
1538 iSharedBufferCnt = 0; |
|
1539 if (iAudioOutput) |
|
1540 { |
|
1541 // during loop play devsound returns the incremented value of the position |
|
1542 // it must be adjusted to the duration of the audio clip so that playback can resume from the position where it was paused |
|
1543 if (IsLoopPlayEnabled()) |
|
1544 { |
|
1545 DP1(_L("CAdvancedAudioPlayController::DoStopL() Number of times repeated = %d"), iCurrentRepeatCount); |
|
1546 iTimePositionInMicroSecs += (iAudioOutput->CalculateAudioOutputPositionL() - iSavedTimePositionInMicroSecs); |
|
1547 } |
|
1548 else |
|
1549 { |
|
1550 iTimePositionInMicroSecs += iAudioOutput->CalculateAudioOutputPositionL(); |
|
1551 } |
|
1552 // clear the repeat flag |
|
1553 ClearRepeatFlag(); |
|
1554 |
|
1555 // In order to support adaptation implementation of loop play, we cannot stop |
|
1556 // the output at the end of file. |
|
1557 // if (aError == KErrUnderflow) |
|
1558 // { |
|
1559 // TRAP_IGNORE(iAudioOutput->StopL(EFalse)); |
|
1560 // } |
|
1561 // else |
|
1562 // { |
|
1563 TRAP_IGNORE(iAudioOutput->StopL()); |
|
1564 // } |
|
1565 TRAP_IGNORE(SourceSinkStopL()); |
|
1566 } |
|
1567 |
|
1568 DP0(_L("CAdvancedAudioPlayController::DoStopL state changed to stop")); |
|
1569 iState = EStopped; |
|
1570 |
|
1571 if (!iPlayingForInitPos) // internal play for seeking before user calls play |
|
1572 { |
|
1573 // we don't want an event if seeking past eof before play is called - we will get a playcomplete and stop |
|
1574 // no event for a user stop which will have no error |
|
1575 if (aError == KErrUnderflow) |
|
1576 { |
|
1577 // normal end of playback |
|
1578 SendEventToClient(TMMFEvent(KMMFEventCategoryPlaybackComplete, KErrNone)); |
|
1579 SendEventToClient(TMMFEvent(KStreamControlEventStateChangedStopped, KErrEof)); |
|
1580 } |
|
1581 else if (aError != KErrNone) |
|
1582 { |
|
1583 // processing had an error |
|
1584 if (iSourceUnreadable) |
|
1585 { |
|
1586 // if source was not even readable, we never made it to user play |
|
1587 // so we don't want to send playback complete |
|
1588 } |
|
1589 else |
|
1590 { |
|
1591 SendEventToClient(TMMFEvent(KMMFEventCategoryPlaybackComplete, aError)); |
|
1592 SendEventToClient(TMMFEvent(KStreamControlEventStateChangedStopped, aError)); |
|
1593 } |
|
1594 } |
|
1595 } |
|
1596 } |
|
1597 |
|
1598 TInt CAdvancedAudioPlayController::CleanupForStop() |
|
1599 { |
|
1600 // This is used in cases that need to initial back to a stop like state without a state change |
|
1601 DP1(_L("CAdvancedAudioPlayController::CleanupForStop iState[%d]"), iState); |
|
1602 TInt status = KErrNone; |
|
1603 |
|
1604 iPlaySeeking = EFalse; |
|
1605 |
|
1606 if (iWait) |
|
1607 { |
|
1608 iWait->AsyncStop(); |
|
1609 } |
|
1610 |
|
1611 if (iBlockSetPos) |
|
1612 { |
|
1613 if (iBlockSetPos->IsStarted()) |
|
1614 { |
|
1615 iBlockSetPos->AsyncStop(); |
|
1616 } |
|
1617 } |
|
1618 |
|
1619 iPlayingForDuration = EFalse; |
|
1620 iBlockDuration = EFalse; |
|
1621 iPlayingForPauseSeek = EFalse; |
|
1622 iPlayingForInitPos = EFalse; |
|
1623 iPausingForSetPos = EFalse; |
|
1624 return status; |
|
1625 } |
|
1626 |
|
1627 // ----------------------------------------------------------------------------- |
|
1628 // CAdvancedAudioPlayController::ResetPositionVariables() |
|
1629 // ----------------------------------------------------------------------------- |
|
1630 // |
|
1631 // These variables are always updated together, they are reset together here. |
|
1632 void CAdvancedAudioPlayController::ResetPositionVariables() |
|
1633 { |
|
1634 iSourceReadPosition = 0; |
|
1635 iCurrentPosition = 0; |
|
1636 iTimePositionInMicroSecs = 0; |
|
1637 } |
|
1638 |
|
1639 // ----------------------------------------------------------------------------- |
|
1640 // CAdvancedAudioPlayController::PositionL() |
|
1641 // ----------------------------------------------------------------------------- |
|
1642 // |
|
1643 EXPORT_C TTimeIntervalMicroSeconds CAdvancedAudioPlayController::PositionL() const |
|
1644 { |
|
1645 DP2(_L("CAdvancedAudioPlayController::PositionL, this[%x] iState[%d]"), this, iState); |
|
1646 |
|
1647 TTimeIntervalMicroSeconds positionMicroSeconds(0); |
|
1648 |
|
1649 if (iState == EPlaying) |
|
1650 { |
|
1651 DP1 (_L("CAdvancedAudioPlayController::PositionL iTimePositionInMicroSecs [%d] msec"), iTimePositionInMicroSecs); |
|
1652 // adjust the position here since devsound returns the incremented postion value during loopplay |
|
1653 if (IsLoopPlayEnabled()) |
|
1654 { |
|
1655 positionMicroSeconds = TTimeIntervalMicroSeconds( iAudioOutput->CalculateAudioOutputPositionL() - iSavedTimePositionInMicroSecs); |
|
1656 } |
|
1657 else |
|
1658 { |
|
1659 positionMicroSeconds = TTimeIntervalMicroSeconds(iTimePositionInMicroSecs + iAudioOutput->CalculateAudioOutputPositionL()); |
|
1660 } |
|
1661 } |
|
1662 else |
|
1663 { |
|
1664 positionMicroSeconds = TTimeIntervalMicroSeconds(iTimePositionInMicroSecs); |
|
1665 } |
|
1666 |
|
1667 DP1 (_L("CAdvancedAudioPlayController::PositionL returns[%d] msec"), I64LOW(positionMicroSeconds.Int64()/1000)); |
|
1668 return positionMicroSeconds; |
|
1669 } |
|
1670 |
|
1671 // ----------------------------------------------------------------------------- |
|
1672 // CAdvancedAudioPlayController::SetPositionL |
|
1673 // ----------------------------------------------------------------------------- |
|
1674 // |
|
1675 EXPORT_C void CAdvancedAudioPlayController::SetPositionL( |
|
1676 const TTimeIntervalMicroSeconds& aTimePos) |
|
1677 { // this is for user call only |
|
1678 DP3(_L("CAdvancedAudioPlayController::SetPositionL this[%x] [%d]msec iState[%d]"), this, I64LOW(aTimePos.Int64()/1000), iState); |
|
1679 if (iSourceUnreadable) |
|
1680 { |
|
1681 DP0(_L("CAdvancedAudioPlayController::SetPositionL KErrCorrupt")); |
|
1682 User::Leave(KErrCorrupt); |
|
1683 } |
|
1684 |
|
1685 // if play window is set then validate the position with the play window boundaries |
|
1686 // play window boundaries must be checked when seeking during playback in a playwindow |
|
1687 TTimeIntervalMicroSeconds position = aTimePos; |
|
1688 // if play window is set then the playwindowendposition is > 0 |
|
1689 if (iPlayWindowEndPosition > 0) |
|
1690 { |
|
1691 if (aTimePos < iPlayWindowStartPosition) |
|
1692 { |
|
1693 position = iPlayWindowStartPosition; |
|
1694 } |
|
1695 else if (aTimePos > iPlayWindowEndPosition) |
|
1696 { |
|
1697 position = iPlayWindowEndPosition; |
|
1698 } |
|
1699 } |
|
1700 |
|
1701 switch (iState) |
|
1702 { |
|
1703 case EStopped: |
|
1704 case EInitializing: |
|
1705 if (position != 0) |
|
1706 { // if we are priming, we will already be ready to play from 0. |
|
1707 DP2(_L("CAdvancedAudioPlayController::SetPositionL, saving pos iReadHeader[%d] iState[%d]"),iReadHeader,iState); |
|
1708 iInitPosition = position; |
|
1709 } |
|
1710 DP0(_L("CAdvancedAudioPlayController::SetPositionL, can ignore")); |
|
1711 break; |
|
1712 case EInitialized: |
|
1713 case EPaused: |
|
1714 iSavedSetPosition = position; |
|
1715 DoSetPositionL(position); |
|
1716 if (iPlaySeeking) |
|
1717 { |
|
1718 DP0(_L("CAdvancedAudioController::SetPositionL() blocking")); |
|
1719 iBlockSetPos = new (ELeave) CActiveSchedulerWait(); |
|
1720 iBlockSetPos->Start(); |
|
1721 DP0(_L("CAdvancedAudioController::SetPositionL() continuing")); |
|
1722 delete iBlockSetPos; |
|
1723 iBlockSetPos = NULL; |
|
1724 } |
|
1725 break; |
|
1726 case EAutoPaused: |
|
1727 case EPlaying: |
|
1728 DP0(_L("CAdvancedAudioPlayController::SetPositionL, PauseForSetPosL so we can set position")); |
|
1729 PauseForSetPosL(); // will return to play state when position reached |
|
1730 iSavedSetPosition = position; |
|
1731 DP0(_L("CAdvancedAudioPlayController::SetPositionL, After PauseForSetPosL, now set the desired position")); |
|
1732 DoSetPositionL(position); |
|
1733 if (iPlaySeeking) |
|
1734 { |
|
1735 DP0(_L("CAdvancedAudioController::SetPositionL() blocking")); |
|
1736 iBlockSetPos = new (ELeave) CActiveSchedulerWait(); |
|
1737 iBlockSetPos->Start(); |
|
1738 DP0(_L("CAdvancedAudioController::SetPositionL() continuing")); |
|
1739 delete iBlockSetPos; |
|
1740 iBlockSetPos = NULL; |
|
1741 } |
|
1742 else |
|
1743 { |
|
1744 DP0(_L("CAdvancedAudioPlayController::SetPositionL Calling SeekPositionReached ")); |
|
1745 // comes here if seek position found in source, or starting another loop during loop play |
|
1746 // during loop play we seek back to the beginning of the clip or play window start position. |
|
1747 SeekPositionReached(KMaxTUint); |
|
1748 } |
|
1749 break; |
|
1750 } |
|
1751 } |
|
1752 |
|
1753 // ----------------------------------------------------------------------------- |
|
1754 // CAdvancedAudioPlayController::SetPrioritySettings |
|
1755 // ----------------------------------------------------------------------------- |
|
1756 // |
|
1757 EXPORT_C void CAdvancedAudioPlayController::SetPrioritySettings( |
|
1758 const TMMFPrioritySettings& aPrioritySettings) |
|
1759 { |
|
1760 DP0(_L("CAdvancedAudioPlayController::SetPrioritySettings")); |
|
1761 |
|
1762 CAdvancedAudioController::SetPrioritySettings(aPrioritySettings); |
|
1763 |
|
1764 if(iDataSink) |
|
1765 { |
|
1766 TRAPD(err, iAudioOutput->SetPrioritySettingsL(aPrioritySettings)); |
|
1767 err = err; |
|
1768 } |
|
1769 } |
|
1770 |
|
1771 // ----------------------------------------------------------------------------- |
|
1772 // CAdvancedAudioPlayController::SendEventToClient |
|
1773 // ----------------------------------------------------------------------------- |
|
1774 // |
|
1775 EXPORT_C TInt CAdvancedAudioPlayController::SendEventToClient(const TMMFEvent& aEvent) |
|
1776 { |
|
1777 DP4(_L("CAdvancedAudioPlayController::SendEventToClient, this[%x] iEventsEnabled[%d], iEventType[%d], ErrorCode[%d]"), this, iEventsEnabled, aEvent.iEventType, aEvent.iErrorCode); |
|
1778 |
|
1779 // The following logic is to take care of only forward the appropiate event depends on "iEventsEanbled" flag |
|
1780 // KMMFEventCategoryPlaybackComplete event is to support the Existing Symbian MMF API behavior |
|
1781 // while KStreamControlEventStateChangedXXX for Streaming/PDL events, and ONLY ONE of these events should be forwarded to the client |
|
1782 // Current implementation is instead of deciding what event when a SendEventToClient issued, both events would be sent, and the decision |
|
1783 // on which one to be forwarded is being implemented here |
|
1784 // *NOTE*: KStreamControlEventStateChangedStopped does NOT equal to KMMFEventCategoryPlaybackComplete, |
|
1785 // while both would happends during error situation, KStreamControlEventStateChangedStopped also happens when StopL is called |
|
1786 // but KMMFEventCategoryPlaybackComplete would not |
|
1787 if( (aEvent.iErrorCode == KErrSourceAdapter) || ( aEvent.iErrorCode == KErrCorrupt ) ) |
|
1788 {//Stop the controller and send error since error occured in source adapter |
|
1789 iSourceUnreadable = ETrue; |
|
1790 DoStopL(KErrDied); |
|
1791 } |
|
1792 else |
|
1793 { |
|
1794 if (iEventsEnabled) |
|
1795 { // request for new events |
|
1796 if ((aEvent.iEventType == KStreamControlEventStateChangedStopped) || |
|
1797 (aEvent.iEventType == KStreamControlEventStateChangedPrimed) || |
|
1798 (aEvent.iEventType == KStreamControlEventStateChangedPlaying) || |
|
1799 (aEvent.iEventType == KStreamControlEventStateChangedPaused) || |
|
1800 (aEvent.iEventType == KStreamControlEventStateChangedAutoPaused)) |
|
1801 { |
|
1802 return CAdvancedAudioController::SendEventToClient(aEvent); |
|
1803 } |
|
1804 else |
|
1805 { |
|
1806 // do not send any other events for advanced clients. |
|
1807 } |
|
1808 } |
|
1809 else |
|
1810 { |
|
1811 if ((aEvent.iEventType == KStreamControlEventStateChangedStopped) || |
|
1812 (aEvent.iEventType == KStreamControlEventStateChangedPrimed) || |
|
1813 (aEvent.iEventType == KStreamControlEventStateChangedPlaying) || |
|
1814 (aEvent.iEventType == KStreamControlEventStateChangedPaused) || |
|
1815 (aEvent.iEventType == KStreamControlEventStateChangedAutoPaused)) |
|
1816 { |
|
1817 // ignore event and do nothing except convert autopause to old event |
|
1818 } |
|
1819 else |
|
1820 { |
|
1821 return CAdvancedAudioController::SendEventToClient(aEvent); |
|
1822 } |
|
1823 } |
|
1824 } |
|
1825 return KErrNone; |
|
1826 } |
|
1827 |
|
1828 // ----------------------------------------------------------------------------- |
|
1829 // CAdvancedAudioPlayController::BufferFilledL |
|
1830 // Called after the data buffer is filled. |
|
1831 // ----------------------------------------------------------------------------- |
|
1832 // |
|
1833 EXPORT_C void CAdvancedAudioPlayController::BufferFilledL(CMMFBuffer* aBuffer) |
|
1834 { |
|
1835 aBuffer->SetPosition(0); |
|
1836 CMMFDataBuffer* buffer = static_cast<CMMFDataBuffer*>(aBuffer); |
|
1837 |
|
1838 DP6(_L("CAdvancedAudioPlayController::BufferFilledL[%x], readPos[%d], Length[%d], iState[%d], LB[%d], d0[%x]"), |
|
1839 buffer->Data().Ptr(), iSourceReadPosition, buffer->Data().Length(), iState, aBuffer->LastBuffer(), |
|
1840 buffer->Data().Ptr()[0]); |
|
1841 |
|
1842 if ((buffer->Data().Length() > 0) || buffer->LastBuffer()) |
|
1843 { |
|
1844 aBuffer->SetStatus(EFull); |
|
1845 |
|
1846 // iSourceReadPosition is used to mark the buffer with the source position |
|
1847 // This is stored in aBuffer->Frame(). aBuffer->Frame() will indicate |
|
1848 // the source position for the starting byte position for that buffer |
|
1849 aBuffer->SetFrameNumber(iSourceReadPosition); |
|
1850 iSourceReadPosition += buffer->Data().Length(); |
|
1851 |
|
1852 DP1(_L("CAdvancedAudioPlayController::BufferFilledL next readPos[%d]"), iSourceReadPosition); |
|
1853 } |
|
1854 else |
|
1855 { |
|
1856 DP0(_L("CAdvancedAudioPlayController::BufferFilledL, unexpected 0 length buffer")); |
|
1857 User::Leave(KErrAbort); |
|
1858 } |
|
1859 |
|
1860 if (iState != EStopped) |
|
1861 { |
|
1862 DoBufferFilledL(aBuffer); |
|
1863 } |
|
1864 |
|
1865 TBool doState = ETrue; |
|
1866 while (doState) |
|
1867 { |
|
1868 DP5(_L("CAdvancedAudioPlayController::BufferFilledL, state check state[%d] reqstate[%d] pfps[%d] pfd[%d] pfip[%d]"), |
|
1869 iState, iRequestState, iPlayingForPauseSeek,iPlayingForDuration,iPlayingForInitPos); |
|
1870 doState = EFalse; |
|
1871 switch (iState) |
|
1872 { |
|
1873 case EStopped: |
|
1874 DP0(_L("CAdvancedAudioPlayController::BufferFilledL EStopped")); |
|
1875 break; |
|
1876 case EInitializing: |
|
1877 DP0(_L("CAdvancedAudioPlayController::BufferFilledL EInitializing")); |
|
1878 if (!iReadHeader) |
|
1879 { |
|
1880 // do not transition to initialized if there was a problem |
|
1881 if (iSourceUnreadable) |
|
1882 { |
|
1883 return; |
|
1884 } |
|
1885 iState = EInitialized; |
|
1886 // when playwindow is active for a non-seekable source during loop play |
|
1887 // we must seek to the playwindow start position and then start the playback |
|
1888 if (iPlayWindowStartPosition > 0) // do we need additional checks as loop play / non-seekable source ?? |
|
1889 iInitPosition = iPlayWindowStartPosition; |
|
1890 GoToInitPositionL(); // see if we need to seek to somewhere |
|
1891 doState = ETrue; |
|
1892 } |
|
1893 break; |
|
1894 case EInitialized: |
|
1895 DP0(_L("CAdvancedAudioPlayController::BufferFilledL EInitialized")); |
|
1896 if ((iRequestState == EInitialized) && AllBuffersFilled() && iEnablePrimedStateChangedEvent) |
|
1897 { // we have read the header, user has called prime but needed to wait for priming, all the input buffers are filled |
|
1898 // the controller itself may need to prime to get duration, but we just want to send the state change in response to user prime |
|
1899 iEnablePrimedStateChangedEvent = EFalse; |
|
1900 DP0(_L("CAdvancedAudioPlayController::BufferFilledL state changed primed")); |
|
1901 SendEventToClient(TMMFEvent(KStreamControlEventStateChangedPrimed, KErrNone)); // both source and sink are ready. |
|
1902 } |
|
1903 if ((iRequestState == EPlaying) || iPlayingForDuration || iPlayingForPauseSeek || iPlayingForInitPos) |
|
1904 { |
|
1905 if (iAudioOutput->IsDSStopped()) |
|
1906 { |
|
1907 DP0(_L("CAdvancedAudioPlayController::BufferFilledL calling DoPlayL Devsound is stopped iState=EInitialized")); |
|
1908 DoPlayL(); |
|
1909 } |
|
1910 else |
|
1911 { |
|
1912 // This is needed for non-seekable sources as DoRepeat() calls DoInitialize in this case |
|
1913 // this resets the source to read from 0 and sets the iState to EInitializing. |
|
1914 // BufferFilled will not read the header again, change state to EInitialized and seek to the iInitPosition. |
|
1915 // The next BufferFilled will come here, where we will continue playback from byte position 0 |
|
1916 // that is now in the buffers. |
|
1917 DP0(_L("CAdvancedAudioPlayController::BufferFilledL Resuming the playback iState=EInitialized")); |
|
1918 // we need to be able to seek fwd to playwindow start pos |
|
1919 if (IsLoopPlayEnabled()) |
|
1920 { |
|
1921 DoResume(iCurrentPosition); |
|
1922 } |
|
1923 else |
|
1924 { |
|
1925 DoPlayL(); |
|
1926 } |
|
1927 |
|
1928 } |
|
1929 } |
|
1930 break; |
|
1931 case EPlaying: |
|
1932 DP0(_L("CAdvancedAudioPlayController::BufferFilledL EPlaying")); |
|
1933 break; |
|
1934 case EPaused: |
|
1935 DP0(_L("CAdvancedAudioPlayController::BufferFilledL EPaused")); |
|
1936 // iPlayingForPauseSeek would be set if we are in pause mode and we need to seek. |
|
1937 // the controller will not go to play state until all buffers are filled. |
|
1938 // so we need to call DoPlay until all buffers are filled and transition to play state. |
|
1939 // if PauseForSetPos, we will resume play in seekpositionreached. |
|
1940 // if (((iRequestState == EPlaying) || iPlayingForPauseSeek) && (!iPausingForSetPos) ) Suk |
|
1941 if ((iRequestState == EPlaying) || iPlayingForPauseSeek) |
|
1942 { |
|
1943 if (iAudioOutput->IsDSStopped()) |
|
1944 { // during loop play the output is not stopped unless we did a seek - seek stops the output and we need to call DoPlay |
|
1945 DP0(_L("CAdvancedAudioPlayController::BufferFilledL Calling DoPlay Devsound is stopped iState=EPaused")); |
|
1946 DoPlayL(); |
|
1947 } |
|
1948 else |
|
1949 { |
|
1950 DP1(_L("CAdvancedAudioPlayController::BufferFilledL Calling DoResume iState=EPaused iCurrentPosition[%d]"), iCurrentPosition); |
|
1951 if (IsLoopPlayEnabled()) |
|
1952 { |
|
1953 DoResume(iCurrentPosition); |
|
1954 } |
|
1955 else |
|
1956 { |
|
1957 DP0(_L("CAdvancedAudioPlayController::BufferFilledL Calling DoPlay iState=EPaused")); |
|
1958 DoPlayL(); |
|
1959 } |
|
1960 } |
|
1961 } |
|
1962 break; |
|
1963 case EAutoPaused: |
|
1964 DP0(_L("CAdvancedAudioPlayController::BufferFilledL EAutoPaused")); |
|
1965 DoResume(); |
|
1966 break; |
|
1967 default: |
|
1968 DP0(_L("CAdvancedAudioPlayController::BufferFilledL EBadState")); |
|
1969 Panic(EBadState); |
|
1970 break; |
|
1971 } |
|
1972 } |
|
1973 } |
|
1974 |
|
1975 void CAdvancedAudioPlayController::DoResume(TInt aResumePosition) // defaults to -1 |
|
1976 { |
|
1977 DP3(_L("CAdvancedAudioPlayController::DoResume iState[%d] iRequestState[%d] aResumePosition[%d]"), iState, iRequestState, aResumePosition); |
|
1978 TInt bufferIndex = -1; |
|
1979 if (aResumePosition >= 0) |
|
1980 { |
|
1981 iResumePosition = aResumePosition; |
|
1982 DP2(_L("CAdvancedAudioPlayController::DoResume saving resume position [%d] iState[%d]"), iResumePosition, iState); |
|
1983 } |
|
1984 |
|
1985 if (iCurrentPosition == KMaxTUint) |
|
1986 { |
|
1987 DP0(_L("CAdvancedAudioPlayController::DoResume Resetting iCurrentPosition to zero")); |
|
1988 iCurrentPosition = 0; |
|
1989 } |
|
1990 |
|
1991 if (AllBuffersFilled()) // state entry condition |
|
1992 { |
|
1993 if (iResumePosition >= 0) |
|
1994 { |
|
1995 bufferIndex = FindBufferFromPos(iResumePosition); |
|
1996 DP1(_L("CAdvancedAudioPlayController::DoResume bufferIndex [%d]"), bufferIndex); |
|
1997 iResumePosition = -1; |
|
1998 DP0(_L("CAdvancedAudioPlayController::DoResume Resetting the ResumePosition")); |
|
1999 // if there was seek past end of file, the buffers may not have any data |
|
2000 // they may all be empty last buffers |
|
2001 if ((bufferIndex < 0) && (AllBuffersEmpty())) |
|
2002 { // position in buffer buffer not found |
|
2003 DP0(_L("CAdvancedAudioPlayController::DoResume Position in the buffer not found ")); |
|
2004 DoStopL(KErrNone); |
|
2005 return; |
|
2006 } |
|
2007 if (bufferIndex < 0) |
|
2008 { |
|
2009 DP0(_L("CAdvancedAudioPlayController::DoResume bufferindex < 0")); |
|
2010 DoStopL(KErrGeneral); |
|
2011 return; |
|
2012 } |
|
2013 } |
|
2014 |
|
2015 TInt errExIntent = KErrNone; |
|
2016 if (!iDisableAutoIntent && (iRequestState == EPlaying)) |
|
2017 { |
|
2018 if (iIntentStopped) |
|
2019 { |
|
2020 errExIntent = iDataSourceAdapter->EvaluateIntent(ContentAccess::EPlay); |
|
2021 if (errExIntent == KErrNone) |
|
2022 { |
|
2023 errExIntent = iDataSourceAdapter->ExecuteIntent(ContentAccess::EPlay); |
|
2024 DP2(_L("CAdvancedAudioPlayController::DoResume() iIntentStopped[%d] errExIntent[%d]"), iIntentStopped, errExIntent ); |
|
2025 if (errExIntent == KErrNone) |
|
2026 iIntentStopped = EFalse; |
|
2027 } |
|
2028 else // if ((errExIntent == KErrKErrNoRights) || any other error) |
|
2029 { |
|
2030 DoStopL(errExIntent); |
|
2031 return; |
|
2032 } |
|
2033 } |
|
2034 else |
|
2035 { |
|
2036 errExIntent = iDataSourceAdapter->EvaluateIntent((iState == EPaused) ? ContentAccess::EContinue : ContentAccess::EPlay); |
|
2037 if (errExIntent == KErrNone) |
|
2038 { |
|
2039 errExIntent = iDataSourceAdapter->ExecuteIntent((iState == EPaused) ? ContentAccess::EContinue : ContentAccess::EPlay); |
|
2040 DP2(_L("CAdvancedAudioPlayController::DoResume() iIntentStopped[%d] errExIntent[%d]"), iIntentStopped, errExIntent ); |
|
2041 } |
|
2042 else // if ((errExIntent == KErrKErrNoRights) || any other error) |
|
2043 { |
|
2044 DoStopL(errExIntent); |
|
2045 return; |
|
2046 } |
|
2047 } |
|
2048 } |
|
2049 if ((errExIntent != KErrNone) && (errExIntent != KErrNotSupported)) |
|
2050 { |
|
2051 DP1(_L("CAdvancedAudioPlayController::DoResume() errExIntent[%d]"), errExIntent); |
|
2052 return; |
|
2053 } |
|
2054 |
|
2055 DP1(_L("CAdvancedAudioPlayController::DoResume iAudioOutput->Resume with bufferIndex [%d]"), bufferIndex); |
|
2056 iState = EPlaying; |
|
2057 // iRequestState should not be changed since it represents user request. |
|
2058 iAudioOutput->Resume(bufferIndex); |
|
2059 |
|
2060 if ((!iRepeatForever) && (iCurrentRepeatCount == iRepeatCount)) |
|
2061 { // this is the last play of the repeats so tell the AudioOutput to set the lastbuffer to True |
|
2062 DP1(_L("CAdvancedAudioPlayController::DoResume iCurrentRepeatCount[%d]"), iCurrentRepeatCount); |
|
2063 iAudioOutput->UnSetLastBuffer(EFalse); |
|
2064 } |
|
2065 SendEventToClient(TMMFEvent(KStreamControlEventStateChangedPlaying, KErrNone)); |
|
2066 } |
|
2067 } |
|
2068 |
|
2069 |
|
2070 TBool CAdvancedAudioPlayController::AllBuffersFilled() |
|
2071 { |
|
2072 DP0(_L("CAdvancedAudioPlayController::AllBuffersFilled")); |
|
2073 TBool allFilled = ETrue; |
|
2074 for (TInt i = 0; i < iSharedBufferMaxNum; i++) |
|
2075 { |
|
2076 if (iSharedBuffers[i]->LastBuffer() && iSharedBuffers[i]->Status() == EFull) |
|
2077 { // if one buffer is filled and marked last buffer |
|
2078 allFilled = ETrue; |
|
2079 break; |
|
2080 } |
|
2081 else if (iSharedBuffers[i]->Status() == EBeingFilled) |
|
2082 { |
|
2083 allFilled = EFalse; |
|
2084 } |
|
2085 } |
|
2086 DP1(_L("CAdvancedAudioPlayController::AllBuffersFilled [%d]"),allFilled); |
|
2087 return allFilled; |
|
2088 } |
|
2089 |
|
2090 TBool CAdvancedAudioPlayController::AllBuffersEmpty() |
|
2091 { |
|
2092 DP0(_L("CAdvancedAudioPlayController::AllBuffersEmpty")); |
|
2093 TBool allEmpty = ETrue; |
|
2094 for (TInt i = 0; i < iSharedBufferMaxNum; i++) |
|
2095 { |
|
2096 DP3(_L("CAdvancedAudioPlayController::AllBuffersEmpty indx[%d] len[%d] stat[%d]"), i, iSharedBuffers[i]->BufferSize(), iSharedBuffers[i]->Status()); |
|
2097 if ((iSharedBuffers[i]->BufferSize() != 0) && |
|
2098 (iSharedBuffers[i]->Status() == EFull)) |
|
2099 { |
|
2100 allEmpty = EFalse; |
|
2101 break; |
|
2102 } |
|
2103 } |
|
2104 DP1(_L("CAdvancedAudioPlayController::AllBuffersEmpty [%d]"), allEmpty); |
|
2105 return allEmpty; |
|
2106 } |
|
2107 |
|
2108 |
|
2109 void CAdvancedAudioPlayController::DoBufferFilledL(CMMFBuffer* aBuffer) |
|
2110 { |
|
2111 DP0(_L("CAdvancedAudioPlayController::DoBufferFilledL")); |
|
2112 |
|
2113 CMMFDataBuffer* buffer = static_cast<CMMFDataBuffer*>(aBuffer); |
|
2114 if (iReadHeader) |
|
2115 { |
|
2116 TRAPD(err, DoReadHeaderL(buffer)); |
|
2117 DP2(_L("CAdvancedAudioPlayController::DoBufferFilledL header is read iHeaderOffset[%d] iSyncOffset[%d]"), iHeaderOffset, iSyncOffset); |
|
2118 DP1(_L("CAdvancedAudioPlayController::DoBufferFilledL DoReadHeaderL err[%d]"), err); |
|
2119 |
|
2120 if (((err == KErrNotReady) || (err == KErrNotFound) || (err == KErrCompletion && iSourceIsPosSeekable)) && !aBuffer->LastBuffer()) |
|
2121 { |
|
2122 // this shared buffer does not contain any part of the first frame |
|
2123 DP0(_L("CAdvancedAudioPlayController::DoBufferFilledL iInitPosition = 0 to seek back to start when done")); |
|
2124 iInitPosition = 0; // if we are going to throw away these buffers, we need to indicate we need to seek back to the start |
|
2125 RefillBuffer(aBuffer); |
|
2126 } |
|
2127 else |
|
2128 { |
|
2129 if ( err == KErrCompletion ) |
|
2130 { |
|
2131 if(((iSharedBufferCnt+1) < iSharedBufferMaxNum) && !aBuffer->LastBuffer()) |
|
2132 { |
|
2133 iSharedBufferCnt++; |
|
2134 return; |
|
2135 } |
|
2136 else |
|
2137 { |
|
2138 err = KErrNone; |
|
2139 } |
|
2140 } |
|
2141 |
|
2142 iReadHeader = EFalse; |
|
2143 if (err != KErrNone) |
|
2144 { |
|
2145 if (((err == KErrNotReady) || (err == KErrNotFound)) && (aBuffer->LastBuffer())) |
|
2146 { |
|
2147 // we went through the whole file without finding the header |
|
2148 // so the source is corrupted |
|
2149 DP0(_L("CAdvancedAudioPlayController::DoBufferFilledL KErrCorrupt")); |
|
2150 err = KErrCorrupt; |
|
2151 iSourceUnreadable = ETrue; |
|
2152 } |
|
2153 TRAP_IGNORE(DoStopL(err)); |
|
2154 } |
|
2155 else |
|
2156 { |
|
2157 if (iAudioUtility) |
|
2158 { // 3gp won't have a utility until it reads the header info |
|
2159 TInt sourceSize = iDataSourceAdapter->SourceSize(); |
|
2160 if (sourceSize < 0) |
|
2161 { |
|
2162 sourceSize = 0; |
|
2163 } |
|
2164 TRAP_IGNORE(iAudioUtility->SetClipSizeL(sourceSize)); |
|
2165 } |
|
2166 |
|
2167 iCurrentPosition = iHeaderOffset+iSyncOffset; |
|
2168 DP3(_L("CAdvancedAudioPlayController::DoBufferFilledL header read curpos[%d] hdroff[%d] syncoff[%d]"), |
|
2169 iCurrentPosition, iHeaderOffset, iSyncOffset); |
|
2170 iTimePositionInMicroSecs = 0; |
|
2171 if (iAudioUtility) |
|
2172 { |
|
2173 iAudioUtility->SetSourceReference(0,0); |
|
2174 } |
|
2175 |
|
2176 UpdateDuration(); |
|
2177 UpdateBitRate(); |
|
2178 // we need to unblock any blocked duration call and also disable it from blocking |
|
2179 // since we now have duration and bitrate. |
|
2180 iBlockDuration = EFalse; |
|
2181 if (iWait) |
|
2182 { |
|
2183 iWait->AsyncStop(); // unblock Duration() now that duration is calculated |
|
2184 } |
|
2185 |
|
2186 // Sink may not be provided yet. Client might add source first. |
|
2187 // Or a client trying to get duration may not have provided a sink. |
|
2188 // Without a sink, we'll just return here, but know that we have read enough |
|
2189 // source data to configure the sink once it is added. |
|
2190 // But if the sink is available here, we'll initialize below. |
|
2191 iSinkInitDataReady = ETrue; |
|
2192 // Primed state change event would be sent when both source and sink are ready. |
|
2193 if (!iAudioOutput) |
|
2194 { |
|
2195 // iBlockDuration = EFalse; |
|
2196 // if (iWait) |
|
2197 // { |
|
2198 // iWait->AsyncStop(); // unblock Duration() now that duration is calculated |
|
2199 // } |
|
2200 return; |
|
2201 } |
|
2202 DoInitializeSinkL(); // the decoder will be created here |
|
2203 } |
|
2204 } |
|
2205 } |
|
2206 } |
|
2207 |
|
2208 EXPORT_C void CAdvancedAudioPlayController::DoInitializeSinkL() |
|
2209 { |
|
2210 DP0(_L("CAdvancedAudioPlayController::DoInitializeSinkL")); |
|
2211 iSinkInitDataReady = EFalse; |
|
2212 |
|
2213 //both source and sink have been added |
|
2214 if(iAudioOutput && iDataSourceAdapter) |
|
2215 { |
|
2216 iAudioOutput->SetDataSourceAdapter(iDataSourceAdapter); |
|
2217 } |
|
2218 |
|
2219 if (!iDecoderExists) |
|
2220 { |
|
2221 // move this common code to here from doadddatasink's |
|
2222 CAdvancedAudioDecoder* decoder = BuildDecoderL(); |
|
2223 iDecoderExists = ETrue; |
|
2224 // AudioOutput takes ownership of decoder object |
|
2225 iAudioOutput->SetDecoder(decoder); |
|
2226 iAudioUtility->SetDecoder(*decoder); |
|
2227 iAudioUtility->SetObserver(*this); |
|
2228 decoder->SetDecoderUtilityObserver(*iAudioUtility); |
|
2229 |
|
2230 // Leave if HWCodec and Conversion tried |
|
2231 if(decoder->IsHwAccelerated() && iDataSink->DataSinkType() == KUidMmfFileSink) |
|
2232 { |
|
2233 User::Leave(KErrNotSupported); |
|
2234 } |
|
2235 } |
|
2236 |
|
2237 |
|
2238 |
|
2239 // Read the default codec configuration parameters from resource file |
|
2240 RArray<TInt>& codecConfigData = const_cast<RArray<TInt>&>(iAudioResource->CodecConfigParametersL()); |
|
2241 // Override default values with values found from header, if available |
|
2242 GetCodecConfigData(codecConfigData); |
|
2243 iAudioOutput->ConfigureL(iSampleRate, iSinkNumChannels, iDataType, codecConfigData); |
|
2244 DP0(_L("CAdvancedAudioPlayController::DoInitializeSinkL, output configured")); |
|
2245 iAudioOutput->PrimeL(); |
|
2246 DP0(_L("CAdvancedAudioPlayController::DoInitializeSinkL, output primed")); |
|
2247 |
|
2248 // we would use this code when we have a NULL sink |
|
2249 /* if (iDuration > 0) |
|
2250 { |
|
2251 DP0(_L("CAdvancedAudioPlayController::BufferFilledL, unblocking duration")); |
|
2252 iBlockDuration = EFalse; |
|
2253 } |
|
2254 if (iWait) |
|
2255 { |
|
2256 if (iDuration > 0) |
|
2257 { |
|
2258 DP0(_L("CAdvancedAudioPlayController::DoBufferFilledL() unblocking")); |
|
2259 iWait->AsyncStop(); // unblock DoAddDataSource now that duration is calculated |
|
2260 } |
|
2261 else |
|
2262 { |
|
2263 PlayForDurationL(); // this should only be used if we are given a NULL sink |
|
2264 } // because policy will get involved with an audio output sink |
|
2265 } // We can skip using this even for NULL sink if we just continue to |
|
2266 */ |
|
2267 } // stay in read header mode and calulate bitrate on more buffers |
|
2268 |
|
2269 void CAdvancedAudioPlayController::PlayForDurationL() |
|
2270 { |
|
2271 DP0(_L("CAdvancedAudioPlayController::PlayForDurationL()")); |
|
2272 iPlayingForDuration = ETrue; |
|
2273 DoSetPositionL(1000000); // 1 sec |
|
2274 DoPlayL(); |
|
2275 } |
|
2276 |
|
2277 void CAdvancedAudioPlayController::PlayForInitPositionL() |
|
2278 { |
|
2279 DP0(_L("CAdvancedAudioPlayController::PlayForInitPositionL()")); |
|
2280 iPlayingForInitPos = ETrue; |
|
2281 DoPlayL(); |
|
2282 } |
|
2283 |
|
2284 void CAdvancedAudioPlayController::PlayForPauseSeekL() |
|
2285 { |
|
2286 DP1(_L("CAdvancedAudioPlayController::PlayForPauseSeekL() pfsp[%d]"), iPausingForSetPos); |
|
2287 if (!iPausingForSetPos) |
|
2288 { // used to return the state to pause |
|
2289 iPlayingForPauseSeek = ETrue; |
|
2290 } |
|
2291 DoPlayL(); |
|
2292 } |
|
2293 |
|
2294 void CAdvancedAudioPlayController::PauseForSetPosL() |
|
2295 { |
|
2296 DP0(_L("CAdvancedAudioPlayController::PauseForSetPosL()")); |
|
2297 iPausingForSetPos = ETrue; // so that pause won't set position too. |
|
2298 DoPauseL(); // stops the output for reposition - it also repositions at pause point using dosetposition |
|
2299 } |
|
2300 |
|
2301 TInt CAdvancedAudioPlayController::DoSetRepeats(TInt aRepeatNumberOfTimes, const TTimeIntervalMicroSeconds& aTrailingSilence) |
|
2302 { |
|
2303 DP2(_L("CAdvancedAudioPlayController::SetRepeats RepeatCount [%d] TrailingSilencePeriod [%d]"), aRepeatNumberOfTimes, I64LOW(aTrailingSilence.Int64()/1000)); |
|
2304 if ((aRepeatNumberOfTimes != KMdaRepeatForever) && (aRepeatNumberOfTimes <= 0)) |
|
2305 { |
|
2306 return KErrArgument; |
|
2307 } |
|
2308 if (aTrailingSilence < 0) |
|
2309 { |
|
2310 return KErrArgument; |
|
2311 } |
|
2312 |
|
2313 if (aRepeatNumberOfTimes == KMdaRepeatForever) // -2 |
|
2314 { |
|
2315 iRepeatForever = ETrue; |
|
2316 } |
|
2317 else |
|
2318 { |
|
2319 iRepeatForever = EFalse; |
|
2320 } |
|
2321 iRepeatCount = aRepeatNumberOfTimes; |
|
2322 iLoopPlayEnabled = ETrue; |
|
2323 if (aTrailingSilence.Int64() > KMaxTInt) |
|
2324 { |
|
2325 iTrailingSilenceMs = TTimeIntervalMicroSeconds32(KMaxTInt); |
|
2326 } |
|
2327 else |
|
2328 { |
|
2329 iTrailingSilenceMs = TTimeIntervalMicroSeconds32(aTrailingSilence.Int64()); |
|
2330 } |
|
2331 if (iAudioOutput) |
|
2332 { |
|
2333 iAudioOutput->IsLoopPlayEnabled(iLoopPlayEnabled); |
|
2334 iAudioOutput->UnSetLastBuffer(ETrue); |
|
2335 } |
|
2336 if (iTrailingSilenceTimer) |
|
2337 { |
|
2338 delete iTrailingSilenceTimer; |
|
2339 iTrailingSilenceTimer = NULL; |
|
2340 } |
|
2341 iTrailingSilenceTimer = CTrailingSilenceTimer::NewL(*this); |
|
2342 // if MapcSetRepeats is called twice or more from the client side, |
|
2343 // then the loop play re-starts and the latest repeat count is considered for |
|
2344 // loop play operation. Reset the counter and the samplesplayed value |
|
2345 iCurrentRepeatCount = 0; |
|
2346 iSavedTimePositionInMicroSecs = 0; |
|
2347 return KErrNone; |
|
2348 } |
|
2349 |
|
2350 void CAdvancedAudioPlayController::ClearRepeatFlag() |
|
2351 { |
|
2352 DP0(_L("CAdvancedAudioPlayController::ClearRepeatFlag")); |
|
2353 iLoopPlayEnabled = EFalse; |
|
2354 if (iAudioOutput) |
|
2355 { |
|
2356 iAudioOutput->IsLoopPlayEnabled(iLoopPlayEnabled); |
|
2357 iAudioOutput->UnSetLastBuffer(EFalse); |
|
2358 } |
|
2359 } |
|
2360 |
|
2361 EXPORT_C void CAdvancedAudioPlayController::LastBufferSent() |
|
2362 { // this is the callback we will get during loop play, instead of playcomplete/dostop |
|
2363 DP2(_L("CAdvancedAudioPlayController::LastBufferSent Begin iRequestedState [%d] iState [%d]"), iRequestState, iState); |
|
2364 if (!iDisableAutoIntent) |
|
2365 { |
|
2366 TInt errExIntent = iDataSourceAdapter->ExecuteIntent(ContentAccess::EStop); |
|
2367 DP1(_L("CAdvancedAudioPlayController::LastBufferSent Calling ExecuteIntent Stop on DataSource [%d]"), errExIntent); |
|
2368 if (errExIntent == KErrNone) |
|
2369 { |
|
2370 iIntentStopped = ETrue; |
|
2371 } |
|
2372 } |
|
2373 if ((iRequestState == EPlaying) && (iState == EPlaying) && (IsLoopPlayEnabled())) // evaluate use of iState |
|
2374 { |
|
2375 // start timer and let it's RunL call repeat |
|
2376 if (iTrailingSilenceTimer) |
|
2377 { |
|
2378 DP1(_L("CAdvancedAudioPlayController::LastBufferSent Waiting for the iTrailingSilenceTimer for [%d] ms"), I64LOW(iTrailingSilenceMs.Int()/1000)); |
|
2379 iTrailingSilenceTimer->After(iTrailingSilenceMs); |
|
2380 } |
|
2381 // save the current position, this will be used to calculate the position in loop play when |
|
2382 // client calls for PositionL() or Pause() operations |
|
2383 // TODO: need to check this position when loop play is going on in a play window |
|
2384 // iSavedTimePositionInMicroSecs = iAudioOutput->CalculateAudioOutputPositionL(); |
|
2385 |
|
2386 /* if ((!iRepeatForever) && (iCurrentRepeatCount < iRepeatCount)) |
|
2387 { |
|
2388 iCurrentRepeatCount++; |
|
2389 } |
|
2390 DP1(_L("CAdvancedAudioPlayController::LastBufferSent() Number of times played till now = %d"), iCurrentRepeatCount); |
|
2391 */ |
|
2392 } |
|
2393 //else if ((iState == EPaused) && |
|
2394 /* |
|
2395 * This is needed for TruePause in a LoopPlay. |
|
2396 * When User Pauses after LastBufferSent and cancels the TrailingSilenceTimer, UserPlay should automatically kickback the DoRepeats |
|
2397 */ |
|
2398 /*#ifdef __TRUEPAUSE_SUPPORT__ |
|
2399 if (IsLoopPlayEnabled()) |
|
2400 { // repeat enabled and last buffer sent but userwe're paused |
|
2401 DP0(_L("CAdvancedAudioPlayController::LastBufferSent iNeedToResumeForRepeat ETrue")); |
|
2402 iNeedToResumeForRepeat = ETrue; // always set in case user pauses - only to be used when resuming from DoPlayL |
|
2403 } |
|
2404 #endif |
|
2405 */ |
|
2406 DP0(_L("CAdvancedAudioPlayController::LastBufferSent End")); |
|
2407 } |
|
2408 |
|
2409 void CAdvancedAudioPlayController::DoRepeat() |
|
2410 { |
|
2411 DP0(_L("CAdvancedAudioPlayController::DoRepeat Begin")); |
|
2412 // save the current position, this will be used to calculate the position in loop play when |
|
2413 // client calls for PositionL() or Pause() operations |
|
2414 // TODO: need to check this position when loop play is going on in a play window |
|
2415 iSavedTimePositionInMicroSecs = iAudioOutput->CalculateAudioOutputPositionL(); |
|
2416 DP1(_L("CAdvancedAudioPlayController::DoRepeat iSavedTimePositionInMicroSecs[%u]"), iSavedTimePositionInMicroSecs); |
|
2417 |
|
2418 if ((!iRepeatForever) && (iCurrentRepeatCount < iRepeatCount)) |
|
2419 { |
|
2420 iCurrentRepeatCount++; |
|
2421 } |
|
2422 DP1(_L("CAdvancedAudioPlayController::DoRepeat Number of times played till now = %d"), iCurrentRepeatCount); |
|
2423 |
|
2424 if (iSourceIsTimeSeekable || iSourceIsPosSeekable) |
|
2425 { // For seekable source |
|
2426 // if there is a playwindow set then use that, otherwise go back to 0 time |
|
2427 // if ((iPlayWindowStartPosition != 0) || (iPlayWindowEndPosition != 0)) |
|
2428 // SetPlayWindow(iPlayWindowStartPosition, iPlayWindowEndPosition); |
|
2429 if (iPlayWindowStartPosition > 0) |
|
2430 { |
|
2431 DP1(_L("CAdvancedAudioPlayController::DoRepeat SetPositionL[%d]ms"), I64LOW(iPlayWindowStartPosition.Int64()/1000)); |
|
2432 SetPositionL(iPlayWindowStartPosition); |
|
2433 } |
|
2434 else |
|
2435 { |
|
2436 DP0(_L("CAdvancedAudioPlayController::DoRepeat SetPositionL(0)")); |
|
2437 SetPositionL(0); |
|
2438 } |
|
2439 // Register for PlayWindow end position as the FrameTable has set its playwindowendpostime to zero |
|
2440 if (iPlayWindowEndPosition > 0) |
|
2441 { |
|
2442 DP1(_L("CAdvancedAudioPlayController::DoRepeat iAudioUtility->SetPlayWindowEndTimeMs(%d)"), I64LOW(iPlayWindowEndPosition.Int64()/1000)); |
|
2443 iAudioUtility->SetPlayWindowEndTimeMs(iPlayWindowEndPosition.Int64() / 1000); |
|
2444 } |
|
2445 } |
|
2446 else |
|
2447 { // For non-seekable source |
|
2448 // Stop and start playback |
|
2449 DP0(_L("CAdvancedAudioPlayController::DoRepeat Non-Seekable source.")); |
|
2450 iAudioOutput->StopL(EFalse); |
|
2451 iDataSourceAdapter->SourceStopL(); // clear the buffers in the source before seeking and priming it |
|
2452 DoInitializeL(); |
|
2453 // set the read header flag to true so that the header is read before the playback is resumed |
|
2454 // and the current position is adjusted to be placed after the header. |
|
2455 iReadHeader = ETrue; |
|
2456 } |
|
2457 DP0(_L("CAdvancedAudioPlayController::DoRepeat End") ); |
|
2458 } |
|
2459 |
|
2460 EXPORT_C void CAdvancedAudioPlayController::TrailingSilenceTimerComplete() |
|
2461 { |
|
2462 DP0(_L("CAdvancedAudioPlayController::TrailingSilenceTimerComplete ")); |
|
2463 DoRepeat(); |
|
2464 } |
|
2465 |
|
2466 EXPORT_C TInt CAdvancedAudioPlayController::GetCodecConfigData(RArray<TInt>& aCodecConfigData) |
|
2467 { |
|
2468 TInt stat = KErrNone; |
|
2469 iAudioUtility->SetCodecConfigData(aCodecConfigData); |
|
2470 iSinkNumChannels = iAudioUtility->ChannelsOut(); |
|
2471 return stat; |
|
2472 } |
|
2473 |
|
2474 // ----------------------------------------------------------------------------- |
|
2475 // CAdvancedAudioPlayController::Refillbuffer |
|
2476 // |
|
2477 // Called after the data buffer is filled. Update the number of bytes read |
|
2478 // and the current read position for the next read operation. |
|
2479 // ----------------------------------------------------------------------------- |
|
2480 // |
|
2481 EXPORT_C TInt CAdvancedAudioPlayController::RefillBuffer(CMMFBuffer* refillBuffer) |
|
2482 { |
|
2483 DP1(_L("CAdvancedAudioPlayController::RefillBuffer: [%x]"), |
|
2484 static_cast<CMMFDataBuffer*>(refillBuffer)->Data().Ptr() ); |
|
2485 |
|
2486 // prevent further request - is this really neccessary |
|
2487 TBool lastBufferSet = EFalse; |
|
2488 |
|
2489 for (TInt i = 0; i < iSharedBuffers.Count(); i++) |
|
2490 { |
|
2491 if (iSharedBuffers[i]->LastBuffer() && |
|
2492 (iSharedBuffers[i]->Status() != EBeingFilled)) // need to make sure it is not still held by the source |
|
2493 { |
|
2494 lastBufferSet = ETrue; |
|
2495 break; |
|
2496 } |
|
2497 } |
|
2498 |
|
2499 if (lastBufferSet) |
|
2500 { |
|
2501 // invalidate this buffer |
|
2502 DP1(_L("CAdvancedAudioPlayController::RefillBuffer: marking[%x] EUnavailable and clearing its LB"), |
|
2503 static_cast<CMMFDataBuffer*>(refillBuffer)->Data().Ptr() ); |
|
2504 refillBuffer->SetLastBuffer(EFalse); |
|
2505 refillBuffer->SetStatus(EUnAvailable); |
|
2506 |
|
2507 return KErrCancel; |
|
2508 } |
|
2509 |
|
2510 TRAPD(err, FillSharedBufferL(refillBuffer)); // Trap if DRM read fails |
|
2511 |
|
2512 if (err != KErrNone) |
|
2513 { |
|
2514 DP1(_L("Error filling shared buffer!!! %d"),err); |
|
2515 |
|
2516 iState = EPlaying; // Set here to get StopL to shutdown completely |
|
2517 TRAP_IGNORE(DoStopL(err)); // If stop leaves, then just return err |
|
2518 } |
|
2519 |
|
2520 return err; |
|
2521 } |
|
2522 |
|
2523 // ----------------------------------------------------------------------------- |
|
2524 // CAdvancedAudioPlayController::PlaybackComplete |
|
2525 // ----------------------------------------------------------------------------- |
|
2526 // |
|
2527 EXPORT_C void CAdvancedAudioPlayController::PlaybackComplete() |
|
2528 { // comes here for KErrUnderflow - no error |
|
2529 DP3(_L("CAdvancedAudioPlayController::PlaybackComplete() reqstate[%d] state[%d] playseek[%d]"), iRequestState, iState, iPlaySeeking); |
|
2530 // Keep in mind that seek past end of file would end up here instead of SeekPositionReached() |
|
2531 if (iPlaySeeking) |
|
2532 { |
|
2533 // Seeking past end of file. |
|
2534 // Here we should be in play state and iPlaySeeking (playing for seeking purpose) |
|
2535 // Take care of this with the SeekPositionReached method, but don't adjust time. |
|
2536 SeekPositionReached(KMaxTUint); |
|
2537 } |
|
2538 else |
|
2539 { // normal play to end of file |
|
2540 DP0(_L("CAdvancedAudioPlayController::PlaybackComplete() stopping")); |
|
2541 TRAP_IGNORE(DoStopL(KErrUnderflow)); |
|
2542 } |
|
2543 } |
|
2544 |
|
2545 // ----------------------------------------------------------------------------- |
|
2546 // CAdvancedAudioPlayController::SendEvent |
|
2547 // ----------------------------------------------------------------------------- |
|
2548 // |
|
2549 EXPORT_C void CAdvancedAudioPlayController::SendEvent( |
|
2550 const TMMFEvent& aEvent) |
|
2551 { |
|
2552 DP2(_L("CAdvancedAudioPlayController::SendEvent[%d] this[%x]"), aEvent.iErrorCode, this); |
|
2553 |
|
2554 if (aEvent.iErrorCode == KErrBufferNotReady) |
|
2555 { |
|
2556 HandleAutoPauseEvent(); |
|
2557 } |
|
2558 // MMFDevSound throws the following error codes incase of any preemption events |
|
2559 // (DevSound instance has been thrown-off or initial request has been rejected) |
|
2560 else if ((aEvent.iErrorCode == KErrAccessDenied) || (aEvent.iErrorCode == KErrInUse) || (aEvent.iErrorCode == KErrDied) ) |
|
2561 { |
|
2562 // this might be a DevSound Preemption |
|
2563 // KErrDied is too generic because it is being returned in many situations |
|
2564 HandlePreemptionEvent(aEvent.iErrorCode); |
|
2565 } |
|
2566 else |
|
2567 { |
|
2568 HandleGeneralEvent(aEvent); |
|
2569 } |
|
2570 } |
|
2571 |
|
2572 // ----------------------------------------------------------------------------- |
|
2573 // CAdvancedAudioPlayController::BitRateChanged |
|
2574 // ----------------------------------------------------------------------------- |
|
2575 // |
|
2576 EXPORT_C void CAdvancedAudioPlayController::BitRateChanged() |
|
2577 { |
|
2578 DP0(_L("CAdvancedAudioPlayController::BitRateChanged")); |
|
2579 iDataSourceAdapter->Event(KMultimediaDataSourceEventBitRateChanged); |
|
2580 UpdateDuration(KOneThousandMilliSecond); |
|
2581 } |
|
2582 |
|
2583 // ----------------------------------------------------------------------------- |
|
2584 // CAdvancedAudioPlayController::BufferFilled |
|
2585 // ----------------------------------------------------------------------------- |
|
2586 // |
|
2587 EXPORT_C void CAdvancedAudioPlayController::BufferFilled(CMMFBuffer* aBuffer) |
|
2588 { |
|
2589 DP0(_L("CAdvancedAudioPlayController::BufferFilled")); |
|
2590 TRAPD(err, BufferFilledL(aBuffer)); |
|
2591 if (err != KErrNone) |
|
2592 { |
|
2593 DP1(_L("CAdvancedAudioPlayController::BufferFilled, BufferFilledL err[%d]"), err); |
|
2594 TRAP_IGNORE(DoStopL(err)); |
|
2595 } |
|
2596 } |
|
2597 |
|
2598 // ----------------------------------------------------------------------------- |
|
2599 // CAdvancedAudioPlayController::Event |
|
2600 // ----------------------------------------------------------------------------- |
|
2601 // |
|
2602 EXPORT_C void CAdvancedAudioPlayController::Event(TUid aEvent) |
|
2603 { |
|
2604 if (iEventsEnabled) |
|
2605 { |
|
2606 if (aEvent == KMultimediaDataSourceObserverEventSourceSizeChanged) |
|
2607 { |
|
2608 TInt sourceSize = iDataSourceAdapter->SourceSize(); |
|
2609 if (sourceSize < 0) |
|
2610 { |
|
2611 sourceSize = 0; |
|
2612 } |
|
2613 if (iAudioUtility) |
|
2614 { |
|
2615 TRAP_IGNORE(iAudioUtility->SetClipSizeL(sourceSize)); |
|
2616 } |
|
2617 UpdateDuration(0); |
|
2618 } |
|
2619 if (aEvent == KMultimediaDataSourceEventRandomSeekingSupportChanged) |
|
2620 { |
|
2621 iSourceIsTimeSeekable = iDataSourceAdapter->IsTimeSeekable(); |
|
2622 iSourceIsPosSeekable = iDataSourceAdapter->IsPositonSeekable(); |
|
2623 } |
|
2624 } |
|
2625 } |
|
2626 |
|
2627 EXPORT_C void CAdvancedAudioPlayController::SeekPositionReached(TUint aTimeMs) |
|
2628 {// this can only be called from play state - we have reached this seek time |
|
2629 // update the time played and transition back to correct state |
|
2630 DP1(_L("CAdvancedAudioPlayController::SeekPositionReached[%d]"), aTimeMs); |
|
2631 if (aTimeMs < KMaxTUint) |
|
2632 { // no update if seek past end of file - this comes from playbackcomplete() |
|
2633 iTimePositionInMicroSecs = aTimeMs; // this is set before the seek - may not need to do this here |
|
2634 iTimePositionInMicroSecs *=1000; |
|
2635 DP1(_L("CAdvancedAudioPlayController::SeekPositionReached iTimePositionInMicroSecs[%d]"),aTimeMs); |
|
2636 } |
|
2637 |
|
2638 iPlaySeeking = EFalse; |
|
2639 if (iPlayingForDuration) |
|
2640 { |
|
2641 UpdateDuration(); |
|
2642 if (iRequestState == EPlaying) |
|
2643 { // since we are already playing for the seek and the requested is to play, we can just keep playing |
|
2644 // rendering will be enabled when position reached so we don't have to call play here - we're already playing |
|
2645 DP0(_L("CAdvancedAudioPlayController::SeekPositionReached iPlayingForDuration - not stopping")); |
|
2646 iPlayingForDuration = EFalse; |
|
2647 } |
|
2648 else |
|
2649 { // normally this would need to go back to stop state. |
|
2650 DP0(_L("CAdvancedAudioPlayController::SeekPositionReached iPlayingForDuration - stopping")); |
|
2651 TRAP_IGNORE(DoStopL(KErrNone)); |
|
2652 } |
|
2653 } |
|
2654 else if (iPlayingForInitPos) |
|
2655 { |
|
2656 if (iRequestState == EPlaying) |
|
2657 { // since we are already playing for the seek and the requested is to play, we can just keep playing |
|
2658 // rendering will be enabled when position reached so we don't have to call play here - we're already playing |
|
2659 DP0(_L("CAdvancedAudioPlayController::SeekPositionReached iPlayingForInitPos - not pausing")); |
|
2660 iPlayingForInitPos = EFalse; |
|
2661 } |
|
2662 else |
|
2663 { // normally this would need to go back to pause state. |
|
2664 DP0(_L("CAdvancedAudioPlayController::SeekPositionReached iPlayingForInitPos - pausing")); |
|
2665 TRAP_IGNORE(DoPauseL()); |
|
2666 } |
|
2667 } |
|
2668 else if (iPausingForSetPos) |
|
2669 { // seek was initiated during play but paused in order to seek and are now returning to play |
|
2670 // rendering will be enabled when position reached so we don't have to call play here - we're already playing |
|
2671 DP0(_L("CAdvancedAudioPlayController::SeekPositionReached iPausingForSetPos - already playing - rendering should be enabled")); |
|
2672 iPausingForSetPos = EFalse; |
|
2673 if (iState == EPaused) |
|
2674 { |
|
2675 if (iAudioOutput->IsDSStopped()) |
|
2676 { // during loop play the output is not stopped unless we did a seek - seek stops the output and we need to call DoPlay |
|
2677 DP0(_L("CAdvancedAudioPlayController::SeekPositionReached Calling DoPlay iState=EPaused")); |
|
2678 DoPlayL(); |
|
2679 } |
|
2680 else |
|
2681 { |
|
2682 DP1(_L("CAdvancedAudioPlayController::SeekPositionReached Calling DoResume iState=EPaused iCurrentPosition[%d]"), iCurrentPosition); |
|
2683 if (IsLoopPlayEnabled()) |
|
2684 { |
|
2685 DoResume(iCurrentPosition); |
|
2686 } |
|
2687 else |
|
2688 { |
|
2689 DoPlayL(); |
|
2690 } |
|
2691 } |
|
2692 } |
|
2693 } |
|
2694 else if (iPlayingForPauseSeek) |
|
2695 { // seek was initiated during a pause |
|
2696 if (iRequestState == EPlaying) |
|
2697 { // since we are already playing for the seek and the requested is to play, we can just keep playing |
|
2698 // rendering will be enabled when position reached so we don't have to call play here - we're already playing |
|
2699 DP0(_L("CAdvancedAudioPlayController::SeekPositionReached iPlayingForPauseSeek - not pausing")); |
|
2700 iPlayingForPauseSeek = EFalse; |
|
2701 } |
|
2702 else |
|
2703 { // normally this would need to go back to pause state. |
|
2704 DP0(_L("CAdvancedAudioPlayController::SeekPositionReached iPlayingForPauseSeek - pausing")); |
|
2705 TRAP_IGNORE(DoPauseL()); |
|
2706 } |
|
2707 } |
|
2708 if (iBlockSetPos) |
|
2709 { |
|
2710 DP0(_L("CAdvancedAudioPlayController::SeekPositionReached() unblocking")); |
|
2711 if (iBlockSetPos->IsStarted()) |
|
2712 { |
|
2713 iBlockSetPos->AsyncStop(); |
|
2714 } |
|
2715 } |
|
2716 } |
|
2717 |
|
2718 EXPORT_C void CAdvancedAudioPlayController::PlayWindowEndPositionReached() |
|
2719 { |
|
2720 } |
|
2721 |
|
2722 TBool CAdvancedAudioPlayController::IsLoopPlayEnabled() const |
|
2723 { |
|
2724 if ((iRepeatForever) || (iCurrentRepeatCount <= iRepeatCount)) |
|
2725 { |
|
2726 return ETrue; |
|
2727 } |
|
2728 else |
|
2729 { |
|
2730 return EFalse; |
|
2731 } |
|
2732 } |
|
2733 |
|
2734 // -------------------------------------------------------------------------------------------------------------- |
|
2735 // CTrailingSilenceTimer class definitions |
|
2736 // -------------------------------------------------------------------------------------------------------------- |
|
2737 CTrailingSilenceTimer* CTrailingSilenceTimer::NewL(MTrailingSilenceObserver &aobserver) |
|
2738 { |
|
2739 DP0(_L("CTrailingSilenceTimer::NewL Begin")); |
|
2740 CTrailingSilenceTimer* self=new(ELeave) CTrailingSilenceTimer(aobserver); |
|
2741 CleanupStack::PushL(self); |
|
2742 self->ConstructL(); |
|
2743 CleanupStack::Pop(); |
|
2744 DP0(_L("CTrailingSilenceTimer::NewL End")); |
|
2745 return self; |
|
2746 } |
|
2747 |
|
2748 CTrailingSilenceTimer::CTrailingSilenceTimer(MTrailingSilenceObserver &aobserver) |
|
2749 : |
|
2750 CTimer(CActive::EPriorityStandard), |
|
2751 iObserver(&aobserver) |
|
2752 { |
|
2753 } |
|
2754 |
|
2755 void CTrailingSilenceTimer::ConstructL() |
|
2756 { |
|
2757 DP0(_L("CTrailingSilenceTimer::ConstructL Begin")); |
|
2758 // Base class second-phase construction. |
|
2759 CTimer::ConstructL(); |
|
2760 // Add to the ActiveScheduler |
|
2761 CActiveScheduler::Add(this); |
|
2762 DP0(_L("CTrailingSilenceTimer::ConstructL End")); |
|
2763 } |
|
2764 |
|
2765 CTrailingSilenceTimer::~CTrailingSilenceTimer() |
|
2766 { |
|
2767 DP0(_L("CTrailingSilenceTimer::~CTrailingSilenceTimer Begin")); |
|
2768 Cancel(); |
|
2769 DP0(_L("CTrailingSilenceTimer::~CTrailingSilenceTimer End")); |
|
2770 } |
|
2771 |
|
2772 void CTrailingSilenceTimer::DoCancel() |
|
2773 { |
|
2774 DP0(_L("CTrailingSilenceTimer::DoCancel Begin")); |
|
2775 // Call the default DoCancel method |
|
2776 CTimer::DoCancel(); |
|
2777 DP0(_L("CTrailingSilenceTimer::DoCancel End")); |
|
2778 } |
|
2779 |
|
2780 void CTrailingSilenceTimer::RunL() |
|
2781 { |
|
2782 DP0(_L("CTrailingSilenceTimer::RunL")); |
|
2783 iObserver->TrailingSilenceTimerComplete(); |
|
2784 } |
|
2785 |
|
2786 void CTrailingSilenceTimer::RunError() |
|
2787 { |
|
2788 DP0(_L("CTrailingSilenceTimer::RunError")); |
|
2789 // Handle error here tbd |
|
2790 } |
|
2791 // -------------------------------------------------------------------------------------------------------------- |
|
2792 |
|
2793 // End of file |