|
1 /* |
|
2 * Copyright (c) 2008-2009 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: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 /** |
|
20 @file |
|
21 @internalComponent |
|
22 */ |
|
23 |
|
24 #include <openmax/il/khronos/v1_x/OMX_Audio.h> |
|
25 |
|
26 #include <d32soundsc.h> |
|
27 |
|
28 #include "log.h" |
|
29 #include <openmax/il/common/omxilcallbacknotificationif.h> |
|
30 #include <openmax/il/common/omxilclockcomponentcmdsif.h> |
|
31 #include <openmax/il/extensions/omxilsymbianaudiopcmextensions.h> |
|
32 #include "omxilpcmrendererprocessingfunction.h" |
|
33 |
|
34 const TInt COmxILPcmRendererProcessingFunction::CPFHelper::KMaxMsgQueueEntries; |
|
35 |
|
36 COmxILPcmRendererProcessingFunction* |
|
37 COmxILPcmRendererProcessingFunction::NewL(MOmxILCallbackNotificationIf& aCallbacks, |
|
38 MOmxILClockComponentCmdsIf& aClientClockPort) |
|
39 { |
|
40 DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::NewL")); |
|
41 |
|
42 COmxILPcmRendererProcessingFunction* self = |
|
43 new (ELeave)COmxILPcmRendererProcessingFunction(aCallbacks, aClientClockPort); |
|
44 CleanupStack::PushL(self); |
|
45 self->ConstructL(); |
|
46 CleanupStack::Pop(self); |
|
47 return self; |
|
48 |
|
49 } |
|
50 |
|
51 void |
|
52 COmxILPcmRendererProcessingFunction::ConstructL() |
|
53 { |
|
54 DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::ConstructL")); |
|
55 |
|
56 iAudioDevice = CAudioDevice::NewL(*this); |
|
57 iPFHelper = CPFHelper::NewL(*iAudioDevice); |
|
58 } |
|
59 |
|
60 COmxILPcmRendererProcessingFunction::COmxILPcmRendererProcessingFunction( |
|
61 MOmxILCallbackNotificationIf& aCallbacks, |
|
62 MOmxILClockComponentCmdsIf& aClientClockPort) |
|
63 : |
|
64 COmxILProcessingFunction(aCallbacks), |
|
65 iClientClockPortPtr(&aClientClockPort) |
|
66 { |
|
67 DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::COmxILPcmRendererProcessingFunction")); |
|
68 |
|
69 } |
|
70 |
|
71 COmxILPcmRendererProcessingFunction::~COmxILPcmRendererProcessingFunction() |
|
72 { |
|
73 DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::~COmxILPcmRendererProcessingFunction")); |
|
74 |
|
75 // Check in case the Sound Device has not been closed. That would happen in |
|
76 // an scenario where the component is not being deleted in an orderer way. |
|
77 if(iAudioDevice && iPFHelper && |
|
78 (iState == OMX_StateInvalid || |
|
79 iState == OMX_StateExecuting || |
|
80 iState == OMX_StatePause)) |
|
81 { |
|
82 // Ignore error if the following call fails |
|
83 iPFHelper->CloseDeviceOnError(); |
|
84 } |
|
85 |
|
86 // Buffer headers are not owned by the processing function |
|
87 iBuffersToEmpty.Close(); |
|
88 iBuffersEmptied.Close(); |
|
89 delete iAudioDevice; |
|
90 delete iPFHelper; |
|
91 } |
|
92 |
|
93 |
|
94 OMX_ERRORTYPE |
|
95 COmxILPcmRendererProcessingFunction::StateTransitionIndication(TStateIndex aNewState) |
|
96 { |
|
97 DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::StateTransitionIndication")); |
|
98 |
|
99 OMX_ERRORTYPE err = OMX_ErrorNone; |
|
100 switch(aNewState) |
|
101 { |
|
102 case EStateExecuting: |
|
103 { |
|
104 DEBUG_PRINTF(_L8("StateTransitionIndication : OMX_StateExecuting")); |
|
105 if (iPFHelper->Execute() != KErrNone) |
|
106 { |
|
107 return OMX_ErrorInsufficientResources; |
|
108 } |
|
109 } |
|
110 break; |
|
111 case EStateInvalid: |
|
112 { |
|
113 DEBUG_PRINTF(_L8("StateTransitionIndication : OMX_StateInvalid")); |
|
114 if (iPFHelper->Stop() != KErrNone) |
|
115 { // InsufficientResources to stop??? |
|
116 return OMX_ErrorInsufficientResources; |
|
117 } |
|
118 } |
|
119 break; |
|
120 case EStatePause: |
|
121 { |
|
122 DEBUG_PRINTF(_L8("StateTransitionIndication : OMX_StatePause")); |
|
123 err = iAudioDevice->MoveToPausedState(); |
|
124 } |
|
125 break; |
|
126 case EStateIdle: |
|
127 { |
|
128 DEBUG_PRINTF(_L8("StateTransitionIndication : OMX_StateIdle")); |
|
129 iBuffersToEmpty.Reset(); |
|
130 if (iPFHelper->Stop() != KErrNone) |
|
131 { // InsufficientResources to stop??? |
|
132 return OMX_ErrorInsufficientResources; |
|
133 } |
|
134 } |
|
135 break; |
|
136 case EStateLoaded: |
|
137 case EStateWaitForResources: |
|
138 { |
|
139 DEBUG_PRINTF(_L8("StateTransitionIndication : OMX_StateLoaded, OMX_StateWaitForResources")); |
|
140 if (iPFHelper->Stop() != KErrNone) |
|
141 { // InsufficientResources to stop??? |
|
142 return OMX_ErrorInsufficientResources; |
|
143 } |
|
144 } |
|
145 break; |
|
146 case ESubStateLoadedToIdle: |
|
147 { |
|
148 DEBUG_PRINTF(_L8("StateTransitionIndication : ESubStateLoadedToIdle")); |
|
149 if (iPFHelper->OpenDevice() != KErrNone) |
|
150 { |
|
151 return OMX_ErrorInsufficientResources; |
|
152 } |
|
153 } |
|
154 break; |
|
155 case ESubStateIdleToLoaded: |
|
156 { |
|
157 DEBUG_PRINTF(_L8("StateTransitionIndication : ESubStateIdleToLoaded")); |
|
158 if (iPFHelper->CloseDevice() != KErrNone) |
|
159 { // InsufficientResources to close??? |
|
160 return OMX_ErrorInsufficientResources; |
|
161 } |
|
162 } |
|
163 break; |
|
164 case ESubStateExecutingToIdle: |
|
165 case ESubStatePauseToIdle: |
|
166 { |
|
167 // Ignore these transitions... |
|
168 return OMX_ErrorNone; |
|
169 } |
|
170 default: |
|
171 { |
|
172 // Always ASSERT; This would be a problem in the framework. |
|
173 ASSERT(0); |
|
174 return OMX_ErrorIncorrectStateTransition; |
|
175 } |
|
176 }; |
|
177 |
|
178 return err; |
|
179 |
|
180 } |
|
181 |
|
182 |
|
183 OMX_ERRORTYPE |
|
184 COmxILPcmRendererProcessingFunction::BufferFlushingIndication( |
|
185 TUint32 aPortIndex, |
|
186 OMX_DIRTYPE aDirection) |
|
187 { |
|
188 DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::BufferFlushingIndication : aPortIndex[%d]"), aPortIndex); |
|
189 |
|
190 if ((aPortIndex == OMX_ALL && aDirection == OMX_DirMax) || |
|
191 (aPortIndex == KPCMRENDERER_APB0PORT_INDEX && aDirection == OMX_DirInput)) |
|
192 { |
|
193 // If we are currently processing a buffer then cancel |
|
194 if (iPFHelper->CancelDevice() != KErrNone) |
|
195 { |
|
196 return OMX_ErrorInsufficientResources; |
|
197 } |
|
198 |
|
199 // Send BufferDone notifications for each emptied buffer... |
|
200 FlushBufferList(iBuffersEmptied); |
|
201 |
|
202 // Send BufferDone notifications for each pending buffer... |
|
203 FlushBufferList(iBuffersToEmpty); |
|
204 |
|
205 return OMX_ErrorNone; |
|
206 } |
|
207 else if (aPortIndex == KPCMRENDERER_OPB0PORT_INDEX && aDirection == OMX_DirInput) |
|
208 { |
|
209 // Since the clock port buffers are returned immediately, |
|
210 // there's nothing to flush for the port |
|
211 return OMX_ErrorNone; |
|
212 } |
|
213 else |
|
214 { |
|
215 // Always ASSERT; This would be a problem in the framework. |
|
216 ASSERT(0); |
|
217 return OMX_ErrorBadParameter; |
|
218 } |
|
219 } |
|
220 |
|
221 void |
|
222 COmxILPcmRendererProcessingFunction::FlushBufferList( |
|
223 RPointerArray<OMX_BUFFERHEADERTYPE>& aBufferList) |
|
224 { |
|
225 DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::FlushBufferList : [%s]"), |
|
226 &aBufferList == &iBuffersToEmpty ? "iBuffersToEmpty" : "iBuffersEmptied"); |
|
227 |
|
228 const TUint bufferCount = aBufferList.Count(); |
|
229 OMX_BUFFERHEADERTYPE* pBufferHeader = 0; |
|
230 // We know there is only one input port... |
|
231 OMX_DIRTYPE portDirection = OMX_DirInput; |
|
232 |
|
233 for (TUint i=0; i<bufferCount; ++i) |
|
234 { |
|
235 pBufferHeader = aBufferList[i]; |
|
236 pBufferHeader->nFilledLen = 0; |
|
237 iCallbacks. |
|
238 BufferDoneNotification( |
|
239 pBufferHeader, |
|
240 pBufferHeader->nInputPortIndex, |
|
241 portDirection |
|
242 ); |
|
243 } |
|
244 |
|
245 // Empty buffer list... |
|
246 aBufferList.Reset(); |
|
247 |
|
248 } |
|
249 |
|
250 |
|
251 OMX_ERRORTYPE |
|
252 COmxILPcmRendererProcessingFunction::ParamIndication( |
|
253 OMX_INDEXTYPE aParamIndex, |
|
254 const TAny* apComponentParameterStructure) |
|
255 { |
|
256 DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::ParamIndication")); |
|
257 |
|
258 OMX_ERRORTYPE err = OMX_ErrorNone; |
|
259 switch(aParamIndex) |
|
260 { |
|
261 case OMX_IndexParamAudioPcm: |
|
262 { |
|
263 const OMX_AUDIO_PARAM_PCMMODETYPE* pPcmProfile |
|
264 = static_cast<const OMX_AUDIO_PARAM_PCMMODETYPE*>( |
|
265 apComponentParameterStructure); |
|
266 |
|
267 if((pPcmProfile->nChannels == 1 || pPcmProfile->nChannels == 2) && |
|
268 (pPcmProfile->eNumData == OMX_NumericalDataSigned) && |
|
269 (pPcmProfile->eEndian == OMX_EndianBig) && |
|
270 (pPcmProfile->bInterleaved == OMX_TRUE) && |
|
271 (pPcmProfile->nBitPerSample == 16) && |
|
272 ((pPcmProfile->nSamplingRate == 8000) || |
|
273 (pPcmProfile->nSamplingRate == 11025) || |
|
274 (pPcmProfile->nSamplingRate == 12000) || |
|
275 (pPcmProfile->nSamplingRate == 16000) || |
|
276 (pPcmProfile->nSamplingRate == 22050) || |
|
277 (pPcmProfile->nSamplingRate == 24000) || |
|
278 (pPcmProfile->nSamplingRate == 32000) || |
|
279 (pPcmProfile->nSamplingRate == 44100) || |
|
280 (pPcmProfile->nSamplingRate == 48000)) && |
|
281 (pPcmProfile->ePCMMode == OMX_AUDIO_PCMModeLinear) && |
|
282 (pPcmProfile->eChannelMapping[0] == OMX_AUDIO_ChannelLF) && |
|
283 (pPcmProfile->eChannelMapping[1] == OMX_AUDIO_ChannelRF)) |
|
284 { |
|
285 if (iPFHelper->ParamIndication(pPcmProfile) != KErrNone) |
|
286 { |
|
287 err = OMX_ErrorInsufficientResources; |
|
288 } |
|
289 } |
|
290 else |
|
291 { |
|
292 err = OMX_ErrorBadParameter; |
|
293 } |
|
294 } |
|
295 break; |
|
296 default: |
|
297 { |
|
298 // Ignore other port param changes... |
|
299 } |
|
300 }; |
|
301 |
|
302 return err; |
|
303 |
|
304 } |
|
305 |
|
306 OMX_ERRORTYPE |
|
307 COmxILPcmRendererProcessingFunction::ConfigIndication(OMX_INDEXTYPE aConfigIndex, |
|
308 const TAny* apComponentConfigStructure) |
|
309 { |
|
310 DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::ConfigIndication %X"), aConfigIndex); |
|
311 |
|
312 OMX_ERRORTYPE err = OMX_ErrorNone; |
|
313 switch(aConfigIndex) |
|
314 { |
|
315 case OMX_SymbianIndexConfigAudioPcmVolumeRamp: |
|
316 { |
|
317 const OMX_SYMBIAN_AUDIO_CONFIG_PCM_VOLUMERAMP* |
|
318 pPcmVolumeRamp |
|
319 = static_cast< |
|
320 const OMX_SYMBIAN_AUDIO_CONFIG_PCM_VOLUMERAMP*>( |
|
321 apComponentConfigStructure); |
|
322 |
|
323 if (iPFHelper->SetVolumeRamp(pPcmVolumeRamp->nRampDuration) != KErrNone) |
|
324 { |
|
325 err = OMX_ErrorInsufficientResources; |
|
326 } |
|
327 } |
|
328 break; |
|
329 |
|
330 case OMX_IndexConfigAudioVolume: |
|
331 { |
|
332 const OMX_AUDIO_CONFIG_VOLUMETYPE* pVolumeType |
|
333 = static_cast<const OMX_AUDIO_CONFIG_VOLUMETYPE*>( |
|
334 apComponentConfigStructure); |
|
335 |
|
336 if (pVolumeType->bLinear == OMX_TRUE) |
|
337 { |
|
338 // Some configuration structures contain read-only fields. The |
|
339 // OMX_SetConfig method will preserve read-only fields in configuration |
|
340 // structures that contain them, and shall not generate an error when |
|
341 // the caller attempts to change the value of a read-only field. |
|
342 err = OMX_ErrorNone; |
|
343 break; |
|
344 } |
|
345 |
|
346 if ((pVolumeType->sVolume.nValue <= pVolumeType->sVolume.nMax) && |
|
347 (pVolumeType->sVolume.nValue >= pVolumeType->sVolume.nMin)) |
|
348 { |
|
349 if (iPFHelper->SetVolume(pVolumeType->sVolume.nValue) != KErrNone) |
|
350 { |
|
351 err = OMX_ErrorInsufficientResources; |
|
352 } |
|
353 } |
|
354 else |
|
355 { |
|
356 err = OMX_ErrorBadParameter; |
|
357 } |
|
358 } |
|
359 break; |
|
360 |
|
361 case OMX_IndexConfigAudioMute: |
|
362 { |
|
363 const OMX_AUDIO_CONFIG_MUTETYPE* pVolumeType |
|
364 = static_cast<const OMX_AUDIO_CONFIG_MUTETYPE*>( |
|
365 apComponentConfigStructure); |
|
366 |
|
367 if (iPFHelper->SetMuted(pVolumeType->bMute) != KErrNone) |
|
368 { |
|
369 err = OMX_ErrorInsufficientResources; |
|
370 } |
|
371 } |
|
372 break; |
|
373 |
|
374 default: |
|
375 { |
|
376 // Ignore other port config changes... |
|
377 } |
|
378 }; |
|
379 |
|
380 return err; |
|
381 |
|
382 } |
|
383 |
|
384 OMX_ERRORTYPE |
|
385 COmxILPcmRendererProcessingFunction::BufferIndication( |
|
386 OMX_BUFFERHEADERTYPE* apBufferHeader, |
|
387 OMX_DIRTYPE aDirection) |
|
388 { |
|
389 DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::BufferIndication : [%X]"), apBufferHeader); |
|
390 |
|
391 if (aDirection != OMX_DirInput) |
|
392 { |
|
393 return OMX_ErrorBadParameter; |
|
394 } |
|
395 |
|
396 if (iBuffersToEmpty.Append(apBufferHeader) != KErrNone) |
|
397 { |
|
398 return OMX_ErrorInsufficientResources; |
|
399 } |
|
400 |
|
401 // If we are not in an executing state or if the audio device is busy, delay playing back the buffer |
|
402 if (iState != OMX_StateExecuting || iAudioDevice->IsActive()) |
|
403 { |
|
404 return OMX_ErrorNone; |
|
405 } |
|
406 |
|
407 if (iPFHelper->BufferIndication() != KErrNone) |
|
408 { |
|
409 return OMX_ErrorInsufficientResources; |
|
410 } |
|
411 |
|
412 return OMX_ErrorNone; |
|
413 } |
|
414 |
|
415 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::MediaTimeIndication(const OMX_TIME_MEDIATIMETYPE& aMediaTimeType) |
|
416 { |
|
417 // Received a requested media time notification. |
|
418 DEBUG_PRINTF5(_L8("MediaTimeIndication : eUpdateType = %d eState = %d xScale = %d nMediaTimestamp = %d "), |
|
419 aMediaTimeType.eUpdateType, aMediaTimeType.eState, aMediaTimeType.xScale, aMediaTimeType.nMediaTimestamp); |
|
420 |
|
421 iPFHelper->MediaTimeIndication(aMediaTimeType); |
|
422 return OMX_ErrorNone; |
|
423 } |
|
424 |
|
425 OMX_BOOL |
|
426 COmxILPcmRendererProcessingFunction::BufferRemovalIndication( |
|
427 OMX_BUFFERHEADERTYPE* apBufferHeader, |
|
428 OMX_DIRTYPE /* aDirection */) |
|
429 { |
|
430 DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::BufferRemovalIndication : BUFFER [%X]"), apBufferHeader); |
|
431 |
|
432 TBool headerDeletionResult = ETrue; |
|
433 // Check if the buffer we want to remove is the one is being currently processed |
|
434 if (iAudioDevice->IsActive() && iAudioDevice->GetCurrentBuffer() == apBufferHeader) |
|
435 { |
|
436 if (iPFHelper->CancelDevice() != KErrNone) |
|
437 { |
|
438 return OMX_FALSE; |
|
439 } |
|
440 |
|
441 // if you cancel the audio device then you send the buffer to the other end of the tunnel |
|
442 // so you shouldn't say that you had the buffer in the processing function in this situation. |
|
443 headerDeletionResult = EFalse; |
|
444 } |
|
445 else |
|
446 { |
|
447 TInt headerIndexInArray = KErrNotFound; |
|
448 if (KErrNotFound != |
|
449 (headerIndexInArray = |
|
450 iBuffersToEmpty.Find(apBufferHeader))) |
|
451 { |
|
452 iBuffersToEmpty.Remove(headerIndexInArray); |
|
453 } |
|
454 else if(KErrNotFound != |
|
455 (headerIndexInArray = |
|
456 iBuffersEmptied.Find(apBufferHeader))) |
|
457 { |
|
458 iBuffersEmptied.Remove(headerIndexInArray); |
|
459 } |
|
460 else |
|
461 { |
|
462 headerDeletionResult = EFalse; |
|
463 } |
|
464 } |
|
465 |
|
466 DEBUG_PRINTF2(_L8("BufferRemovalIndication : Removal result [%s]"), (headerDeletionResult ? "YES" : "NO")); |
|
467 return (headerDeletionResult ? OMX_TRUE : OMX_FALSE); |
|
468 } |
|
469 |
|
470 TInt |
|
471 COmxILPcmRendererProcessingFunction::GetBytesPlayed() const |
|
472 { |
|
473 return iAudioDevice->GetBytesPlayed(); |
|
474 } |
|
475 |
|
476 |
|
477 COmxILPcmRendererProcessingFunction::CAudioDevice* COmxILPcmRendererProcessingFunction::CAudioDevice::NewL(COmxILPcmRendererProcessingFunction& aParent) |
|
478 { |
|
479 CAudioDevice* self = new (ELeave) CAudioDevice(aParent); |
|
480 CleanupStack::PushL(self); |
|
481 self->ConstructL(); |
|
482 CleanupStack::Pop(self); |
|
483 return self; |
|
484 } |
|
485 |
|
486 COmxILPcmRendererProcessingFunction::CAudioDevice::CAudioDevice(COmxILPcmRendererProcessingFunction& aParent) |
|
487 : CActive(EPriorityUserInput), |
|
488 iParent(aParent), |
|
489 iSampleRate(KDefaultSampleRate), |
|
490 iChannels(KDefaultNumberChannels), |
|
491 iEncoding(KDefaultEncoding), |
|
492 iVolume(KDefaultVolume), |
|
493 iMuted(KDefaultMuted), |
|
494 iBufferSize(KBufferSize), |
|
495 iClockStateRunning(EFalse), |
|
496 iPausedClockViaScale(EFalse), |
|
497 iIsStartTimeFlagSet(EFalse) |
|
498 { |
|
499 CActiveScheduler::Add(this); |
|
500 } |
|
501 |
|
502 |
|
503 void COmxILPcmRendererProcessingFunction::CAudioDevice::ConstructL() |
|
504 { |
|
505 iCachedPlayBuffer.CreateL(0); |
|
506 } |
|
507 |
|
508 COmxILPcmRendererProcessingFunction::CAudioDevice::~CAudioDevice() |
|
509 { |
|
510 delete iPeriodic; |
|
511 Cancel(); |
|
512 iCachedPlayBuffer.Close(); |
|
513 } |
|
514 |
|
515 void COmxILPcmRendererProcessingFunction::CAudioDevice::RunL() |
|
516 { |
|
517 DEBUG_PRINTF(_L8("CAudioDevice::RunL : ")); |
|
518 if (iStatus != KErrNone) |
|
519 { |
|
520 switch(iStatus.Int()) |
|
521 { |
|
522 case KErrUnderflow: |
|
523 DEBUG_PRINTF(_L8("CAudioDevice::RunL : KErrUnderflow")); |
|
524 iParent.iCallbacks.ErrorEventNotification(OMX_ErrorUnderflow); |
|
525 break; |
|
526 |
|
527 case KErrOverflow: |
|
528 DEBUG_PRINTF(_L8("CAudioDevice::RunL : KErrOverflow")); |
|
529 iParent.iCallbacks.ErrorEventNotification(OMX_ErrorOverflow); |
|
530 break; |
|
531 |
|
532 default: |
|
533 DEBUG_PRINTF2(_L8("CAudioDevice::RunL : [%d] -> OMX_ErrorHardware"), iStatus.Int()); |
|
534 iParent.iCallbacks.ErrorEventNotification(OMX_ErrorHardware); |
|
535 }; |
|
536 } |
|
537 |
|
538 ASSERT(iCurrentBuffer); |
|
539 // Update the last value of bytes played... |
|
540 iLastBytesPlayedValue = iSoundDevice.BytesPlayed(); |
|
541 |
|
542 // Return the emptied buffer to the IL Client or the tunnelled |
|
543 // component.. |
|
544 SignalBufferCompletion(iCurrentBuffer); |
|
545 iCurrentBuffer = 0; |
|
546 |
|
547 // Make sure to clear the aggregated cache buffer, if it was used |
|
548 iCachedPlayBuffer.Zero(); |
|
549 } |
|
550 |
|
551 void COmxILPcmRendererProcessingFunction::CAudioDevice::SignalBufferCompletion( |
|
552 OMX_BUFFERHEADERTYPE* apCurrentBuffer) |
|
553 { |
|
554 DEBUG_PRINTF2(_L8("CAudioDevice::SignalBufferCompletion : BUFFER = [%X]"), apCurrentBuffer); |
|
555 |
|
556 iParent.iBuffersEmptied.Append(apCurrentBuffer); |
|
557 |
|
558 // Process the queue only if in executing state... |
|
559 if (iParent.iState == OMX_StateExecuting) |
|
560 { |
|
561 const TUint bufferCount = iParent.iBuffersEmptied.Count(); |
|
562 OMX_BUFFERHEADERTYPE* pBufferHeader = 0; |
|
563 for (TUint i=0; i<bufferCount; ++i) |
|
564 { |
|
565 pBufferHeader = iParent.iBuffersEmptied[i]; |
|
566 TBool lastBuffer = EFalse; |
|
567 if (pBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) |
|
568 { |
|
569 lastBuffer = ETrue; |
|
570 } |
|
571 |
|
572 pBufferHeader->nFilledLen = 0; |
|
573 iParent.iCallbacks.BufferDoneNotification(pBufferHeader, |
|
574 pBufferHeader->nInputPortIndex, |
|
575 OMX_DirInput); |
|
576 if (lastBuffer) |
|
577 { |
|
578 pBufferHeader->nFlags |= OMX_BUFFERFLAG_EOS; |
|
579 // propagate the EOS flag |
|
580 iParent.iCallbacks.EventNotification( |
|
581 OMX_EventBufferFlag, |
|
582 KPCMRENDERER_APB0PORT_INDEX, |
|
583 pBufferHeader->nFlags, |
|
584 NULL); |
|
585 } |
|
586 } |
|
587 |
|
588 // Empty list... |
|
589 iParent.iBuffersEmptied.Reset(); |
|
590 } |
|
591 |
|
592 if (iParent.iBuffersToEmpty.Count() > 0) |
|
593 { |
|
594 DEBUG_PRINTF2(_L8("CAudioDevice::RunL : iBuffersToEmpty.Count = [%d]"), |
|
595 iParent.iBuffersToEmpty.Count()); |
|
596 iParent.iPFHelper->BufferIndication(); |
|
597 } |
|
598 |
|
599 } |
|
600 |
|
601 |
|
602 TBool COmxILPcmRendererProcessingFunction::CAudioDevice::ConstructAndStartUpdateTimer() |
|
603 { |
|
604 // Need this check if: |
|
605 // - The component state transitions from Execution-Idle-Execution |
|
606 // - The Clock's state transitions from Running-Stop-Running |
|
607 if (iPeriodic == NULL) |
|
608 { |
|
609 iPeriodic = CPeriodic::New(EPriorityStandard); |
|
610 |
|
611 if (iPeriodic == NULL) |
|
612 { |
|
613 iParent.iCallbacks.ErrorEventNotification(OMX_ErrorInsufficientResources); |
|
614 return EFalse; |
|
615 } |
|
616 } |
|
617 |
|
618 StartUpdateTimer(); |
|
619 |
|
620 return ETrue; |
|
621 } |
|
622 |
|
623 |
|
624 void COmxILPcmRendererProcessingFunction::CAudioDevice::ProcessNextBuffer() |
|
625 { |
|
626 if (iParent.iBuffersToEmpty.Count() == 0) |
|
627 return; |
|
628 |
|
629 // To implement A/V Sync, we should start playing only once the clock component gives the appopriate command |
|
630 // If the clock component is not available, we start playing immediately |
|
631 // Since the PCM Renderer supplies the reference clock, we make sure to initialise the clock component with |
|
632 // the reference when we receive the first buffer |
|
633 |
|
634 if (!iParent.iClientClockPortPtr->IsClockComponentAvailable()) |
|
635 { |
|
636 PlayData(); |
|
637 return; |
|
638 } |
|
639 |
|
640 OMX_BUFFERHEADERTYPE* bufferPtr = iParent.iBuffersToEmpty[0]; |
|
641 |
|
642 TBool bufferHasStartTime = bufferPtr->nFlags & OMX_BUFFERFLAG_STARTTIME; |
|
643 |
|
644 if (!iClockStateRunning) |
|
645 { |
|
646 if (!bufferHasStartTime) |
|
647 { |
|
648 // Connected with the Clock but OMX_BUFFERFLAG_STARTTIME isn't set; simply queue the buffer |
|
649 return; |
|
650 } |
|
651 else |
|
652 { |
|
653 OMX_ERRORTYPE err = iParent.iClientClockPortPtr->SetStartTime(static_cast<OMX_TICKS>(bufferPtr->nTimeStamp)); |
|
654 |
|
655 if (err == OMX_ErrorNone) |
|
656 { |
|
657 // Clear the returning buffer's flag |
|
658 bufferPtr->nFlags &= ~OMX_BUFFERFLAG_STARTTIME; |
|
659 } |
|
660 else |
|
661 { |
|
662 // NOTE: If the Clock is not in OMX_TIME_ClockStateWaitingForStartTime, |
|
663 // currently SetStartTime will return OMX_ErrorIncorrectStateOperation |
|
664 |
|
665 // It is not the PCM renderer to flag a Clock component error; |
|
666 // therefore, ignore the error. |
|
667 // |
|
668 // As the Clock is not in OMX_TIME_ClockStateRunning state, the Renderer needs |
|
669 // to keep the OMX_BUFFERFLAG_STARTTIME in the first buffer until the Clock |
|
670 // moves into OMX_TIME_ClockStateWaitingForStartTime or OMX_TIME_ClockStateRunning |
|
671 // state |
|
672 DEBUG_PRINTF2(_L8("CAudioDevice::ProcessNextBuffer SetStartTime() return %d"), err); |
|
673 } |
|
674 |
|
675 // Update the iStartMediaTime |
|
676 iParent.iStartMediaTime = static_cast<OMX_TICKS>(bufferPtr->nTimeStamp); |
|
677 iIsStartTimeFlagSet = ETrue; |
|
678 } |
|
679 } // (!iClockStateRunning) |
|
680 else |
|
681 { |
|
682 if (bufferHasStartTime) |
|
683 { |
|
684 // The Clock moves straight into OMX_TIME_ClockStateRunning state, |
|
685 // clear the returning buffer's flag. |
|
686 bufferPtr->nFlags &= ~OMX_BUFFERFLAG_STARTTIME; |
|
687 } |
|
688 |
|
689 if (!iPlayData) |
|
690 { |
|
691 // Not allowed to render audio. This could be due to: |
|
692 // - The renderer is waiting for a time completion notification from the Clock; |
|
693 return; |
|
694 } |
|
695 |
|
696 if (!iIsStartTimeFlagSet) |
|
697 { |
|
698 // As the StartTimeFlag is not mandatory; therefore it might be missing from the first audio buffer |
|
699 // In such a case, we use the first buffer's timestamp as the StartMediaTime. |
|
700 // |
|
701 // NOTE: Since the Clock is running, calling SetStartTime() to the Clock is meaningless |
|
702 |
|
703 // Update the iStartMediaTime |
|
704 iParent.iStartMediaTime = static_cast<OMX_TICKS>(bufferPtr->nTimeStamp); |
|
705 iIsStartTimeFlagSet = ETrue; |
|
706 |
|
707 // Cross checking the Clock's media timestamp with iStartMediaTime to see |
|
708 // data can be rendered straight away |
|
709 if (!CanPlayNow()) |
|
710 { |
|
711 return; |
|
712 } |
|
713 |
|
714 if (!ConstructAndStartUpdateTimer()) |
|
715 { |
|
716 return; |
|
717 } |
|
718 } |
|
719 |
|
720 DEBUG_PRINTF3(_L8("ProcessNextBuffer : iStartMediaTime = %d nTimeStamp = %d"), |
|
721 I64LOW(iParent.iStartMediaTime), I64LOW(bufferPtr->nTimeStamp)); |
|
722 |
|
723 if (!iPausedClockViaScale) //if clock scale is zero then we are effectively paused |
|
724 { |
|
725 PlayData(); |
|
726 } |
|
727 } // else |
|
728 } |
|
729 |
|
730 |
|
731 void COmxILPcmRendererProcessingFunction::CAudioDevice::PlayData() |
|
732 { |
|
733 DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::CAudioDevice::PlayData()++")); |
|
734 if (iParent.iBuffersToEmpty.Count() == 0 || iSoundDevice.Handle() == 0 || IsActive()) |
|
735 { |
|
736 DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::CAudioDevice::PlayData() nothing to play, or there is an outstanding request")); |
|
737 return; |
|
738 } |
|
739 |
|
740 iCurrentBuffer = iParent.iBuffersToEmpty[0]; |
|
741 |
|
742 iParent.iBuffersToEmpty.Remove(0); |
|
743 |
|
744 CMMFDataBuffer* mmfSrcBuffer = static_cast<CMMFDataBuffer*>(iCurrentBuffer->pInputPortPrivate); |
|
745 mmfSrcBuffer->Data().SetLength(iCurrentBuffer->nFilledLen); |
|
746 |
|
747 // Attenuate the amplitude of the samples if volume ramping has been changed |
|
748 if (iRampAudioSample) |
|
749 { |
|
750 iRampAudioSample = RampAudio(mmfSrcBuffer); |
|
751 } |
|
752 |
|
753 // First, check whether the buffer length is sufficient not to cause underflows in the device driver |
|
754 TBool isFilledLengthSufficient = IsBufferLengthSufficient(iCurrentBuffer->nFilledLen); |
|
755 // This variable defines whether we should send the data to the driver directly, or append it to an aggregated buffer |
|
756 // We append the buffer instead of sending it directly, if (i) the buffer is too small, or (ii) we have already aggregated something. |
|
757 TBool appendBuffer = (!isFilledLengthSufficient || iCachedPlayBuffer.Length() > 0) ? ETrue : EFalse; |
|
758 if (!appendBuffer) |
|
759 { |
|
760 SendBufferToSoundDevice(mmfSrcBuffer->Data()); |
|
761 } |
|
762 else |
|
763 { |
|
764 // Check if we need to allocate the cached buffer |
|
765 if (iCachedPlayBuffer.MaxLength() == 0) |
|
766 { |
|
767 // The RMdaDevSound shim allocates the shared chunk according to the maxLength of the descriptor it receives |
|
768 // For this reason, we must allocate our buffer conservatively, otherwise the chunk may be insufficient and the RMdaDevSound shim will panic |
|
769 TInt err = iCachedPlayBuffer.ReAlloc(GetMinBufferLength() + iCurrentBuffer->nAllocLen); |
|
770 if (err != KErrNone) |
|
771 { |
|
772 iParent.iCallbacks.ErrorEventNotification(OMX_ErrorInsufficientResources); |
|
773 return; |
|
774 } |
|
775 } |
|
776 |
|
777 iCachedPlayBuffer.Append(mmfSrcBuffer->Data()); |
|
778 |
|
779 // If we have sufficient length aggregated, play the cached buffer |
|
780 // Also if this is the last buffer, we have to play it now, there's nothing left to cache |
|
781 if (IsBufferLengthSufficient(iCachedPlayBuffer.Length()) || iCurrentBuffer->nFlags & OMX_BUFFERFLAG_EOS) |
|
782 { |
|
783 SendBufferToSoundDevice(iCachedPlayBuffer); |
|
784 } |
|
785 // If not, make sure to notify that we notify that the buffer is done for the OMX tunnnel, so that the port will be able to reuse it |
|
786 else |
|
787 { |
|
788 SignalBufferCompletion(iCurrentBuffer); |
|
789 iCurrentBuffer = NULL; |
|
790 } |
|
791 } |
|
792 } |
|
793 |
|
794 void COmxILPcmRendererProcessingFunction::CAudioDevice::SendBufferToSoundDevice(TDes8& aBuffer) |
|
795 { |
|
796 ASSERT(!IsActive()); |
|
797 iStatus = KRequestPending; |
|
798 DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::CAudioDevice::SendBufferToSoundDevice() PlayData [%d]"), aBuffer.Length()); |
|
799 iSoundDevice.PlayData(iStatus, aBuffer); |
|
800 if (iResumeAfterNextPlay) |
|
801 { |
|
802 iResumeAfterNextPlay = EFalse; |
|
803 iSoundDevice.ResumePlaying(); |
|
804 } |
|
805 SetActive(); |
|
806 } |
|
807 |
|
808 TInt COmxILPcmRendererProcessingFunction::CAudioDevice::GetMinBufferLength() const |
|
809 { |
|
810 TInt minBufSize = KMinBufferMilliseconds * iSampleRate * iChannels / 1000; |
|
811 if (iEncoding == RMdaDevSound::EMdaSoundEncoding16BitPCM) |
|
812 { |
|
813 minBufSize *= 2; // All other encodings use 1 byte per sample |
|
814 } |
|
815 return minBufSize; |
|
816 } |
|
817 |
|
818 TBool COmxILPcmRendererProcessingFunction::CAudioDevice::IsBufferLengthSufficient(TInt aBufferLength) const |
|
819 { |
|
820 return aBufferLength >= GetMinBufferLength() ? ETrue : EFalse; |
|
821 } |
|
822 |
|
823 |
|
824 void COmxILPcmRendererProcessingFunction::CAudioDevice::ProcessMediaTimeIndication(OMX_TIME_MEDIATIMETYPE& aMediaTimeType) |
|
825 { |
|
826 switch (aMediaTimeType.eUpdateType) |
|
827 { |
|
828 case OMX_TIME_UpdateClockStateChanged: |
|
829 { |
|
830 HandleClockStateChanged(aMediaTimeType); |
|
831 } |
|
832 break; |
|
833 |
|
834 case OMX_TIME_UpdateRequestFulfillment: |
|
835 { |
|
836 // As the Clock was using another earlier start time; |
|
837 // it is time for the PCM renderer to start playing the audio. |
|
838 iPlayData = ETrue; |
|
839 PlayData(); |
|
840 |
|
841 if (!ConstructAndStartUpdateTimer()) |
|
842 { |
|
843 return; |
|
844 } |
|
845 } |
|
846 break; |
|
847 |
|
848 case OMX_TIME_UpdateScaleChanged: |
|
849 { |
|
850 HandleClockScaleChanged(aMediaTimeType); |
|
851 } |
|
852 break; |
|
853 |
|
854 default: |
|
855 { |
|
856 // Do nothing here |
|
857 } |
|
858 } |
|
859 } |
|
860 |
|
861 |
|
862 void COmxILPcmRendererProcessingFunction::CAudioDevice::StartUpdateTimer() |
|
863 { |
|
864 if (!iIsStartTimeFlagSet) |
|
865 { |
|
866 DEBUG_PRINTF(_L8("COmxILPcmRendererProcessingFunction::CAudioDevice::StartUpdateTimer() iIsStartTimeFlagSet == EFalse!!")); |
|
867 return; |
|
868 } |
|
869 |
|
870 // In case the timer already started |
|
871 ASSERT(iPeriodic); |
|
872 iPeriodic->Cancel(); |
|
873 |
|
874 TCallBack callback(UpdateClockMediaTime, this); |
|
875 |
|
876 // Start updating the Clock comp. every KPcmRendererTimePlayedDelay |
|
877 iPeriodic->Start(KPcmRendererTimePlayedDelay, KPcmRendererTimePlayedDelay, callback); |
|
878 } |
|
879 |
|
880 |
|
881 TBool COmxILPcmRendererProcessingFunction::CAudioDevice::CanPlayNow() |
|
882 { |
|
883 if (iParent.iState != OMX_StateExecuting) |
|
884 { |
|
885 return EFalse; |
|
886 } |
|
887 |
|
888 if (iClockMediaTime < iParent.iStartMediaTime) |
|
889 { |
|
890 // Once all required Clock's clients have responded, the clock component starts |
|
891 // the media clock using the earliest client start time. |
|
892 // Therefore, start playing the audio only when such time comes; send a time |
|
893 // completion request to the Clock component |
|
894 OMX_ERRORTYPE err = iParent.iClientClockPortPtr->MediaTimeRequest(NULL, iParent.iStartMediaTime, 0); |
|
895 |
|
896 if (err != OMX_ErrorNone) |
|
897 { |
|
898 DEBUG_PRINTF2(_L8("CAudioDevice::CanPlayNow() MediaTimeRequest() return %d"), err); |
|
899 } |
|
900 |
|
901 // Indicate that processing a new buffer should not trigger a false start on playback. |
|
902 iPlayData = EFalse; |
|
903 return EFalse; |
|
904 } |
|
905 else if (iClockMediaTime > iParent.iStartMediaTime) |
|
906 { |
|
907 // NOTE: The spec. states that the clock should use the minimum of the received start times |
|
908 // Therefore the Clock should NOT jump forwards with timestamp greater than the PCM |
|
909 // Renderer iStartMediaTime |
|
910 DEBUG_PRINTF3(_L8("CanPlayNow() nMediaTimestamp(%d) > iStartMediaTime(%d) IGNORE this use case"), |
|
911 I64LOW(iClockMediaTime), I64LOW(iParent.iStartMediaTime)); |
|
912 |
|
913 // However if the Clock sends out a timestamp greater than the buffer's timestamp |
|
914 // drop the buffers that fall outside the Clock specified MediaTimestamp; |
|
915 |
|
916 OMX_BUFFERHEADERTYPE* bufferPtr = iParent.iBuffersToEmpty[0]; |
|
917 iParent.iBuffersToEmpty.Remove(0); |
|
918 SignalBufferCompletion(bufferPtr); |
|
919 bufferPtr = NULL; |
|
920 |
|
921 // Since the iStartMediaTime doesn't make sense anymore, reset iIsStartTimeFlagSet until the buffer's timestamp |
|
922 // is within the the Clock's Media timestamp |
|
923 iIsStartTimeFlagSet = EFalse; |
|
924 return EFalse; |
|
925 } |
|
926 |
|
927 return ETrue; |
|
928 } |
|
929 |
|
930 |
|
931 void COmxILPcmRendererProcessingFunction::CAudioDevice::HandleClockStateChanged(const OMX_TIME_MEDIATIMETYPE& aMediaTimeType) |
|
932 { |
|
933 switch (aMediaTimeType.eState) |
|
934 { |
|
935 case OMX_TIME_ClockStateRunning: |
|
936 { |
|
937 iClockMediaTime = aMediaTimeType.nMediaTimestamp; |
|
938 |
|
939 // There are two possibilities: |
|
940 // case 1 - The clock goes straight into running and the PCM renderer processes the |
|
941 // StateChanged notification prior the audio buffer |
|
942 |
|
943 if (iIsStartTimeFlagSet) |
|
944 { |
|
945 // OR |
|
946 // case 2 - The PCM recieves the audio buffer, and the clock StateChanged notification |
|
947 // comes later |
|
948 |
|
949 // Clear the returning buffer's flag. |
|
950 iParent.iBuffersToEmpty[0]->nFlags &= ~OMX_BUFFERFLAG_STARTTIME; |
|
951 |
|
952 // Cross checking the Clock's media timestamp with iStartMediaTime to see |
|
953 // data can be rendered straight away |
|
954 if (!CanPlayNow()) |
|
955 { |
|
956 break; |
|
957 } |
|
958 |
|
959 // Start playing the audio and start updating the Clock media time regularly |
|
960 PlayData(); |
|
961 |
|
962 if (!ConstructAndStartUpdateTimer()) |
|
963 { |
|
964 return; |
|
965 } |
|
966 } |
|
967 else if ((!iClockStateRunning) && (iParent.iState == OMX_StateExecuting)) |
|
968 { |
|
969 // The clock has gone to running but no start time flag was received. This would |
|
970 // indicate that the client moved it straight from stopped to running. As we may |
|
971 // have received buffers while in stopped state, we need to start processing |
|
972 // them now. |
|
973 DEBUG_PRINTF(_L8("HandleClockStateChanged() Gone to running without start time flag set")); |
|
974 iClockStateRunning = ETrue; |
|
975 ProcessNextBuffer(); |
|
976 } |
|
977 |
|
978 // Otherwise, the queue is empty; |
|
979 // |
|
980 // NOTE: When !iIsStartTimeFlagSet && !iClockStateRunning would drop the incoming buffers; |
|
981 // if the first buffer does not have the OMX_BUFFERFLAG_STARTTIME set |
|
982 } |
|
983 break; |
|
984 |
|
985 case OMX_TIME_ClockStateWaitingForStartTime: |
|
986 { |
|
987 if (iClockStateRunning) |
|
988 { |
|
989 DEBUG_PRINTF(_L8("HandleClockStateChanged() OMX_TIME_ClockStateRunning -> OMX_TIME_ClockStateWaitingForStartTime IGNORED!!")); |
|
990 } |
|
991 else |
|
992 { |
|
993 // Let's try to process buffers (if any). |
|
994 ProcessNextBuffer(); |
|
995 } |
|
996 } |
|
997 break; |
|
998 |
|
999 case OMX_TIME_ClockStateStopped: |
|
1000 { |
|
1001 if (iClockStateRunning) |
|
1002 { |
|
1003 // The Clock was in "Running" state but not anymore; stop the audio |
|
1004 if (IsActive()) |
|
1005 { |
|
1006 Cancel(); |
|
1007 } |
|
1008 else |
|
1009 { |
|
1010 DoCancel(); |
|
1011 } |
|
1012 |
|
1013 iPlayData = ETrue; |
|
1014 if (iIsStartTimeFlagSet) |
|
1015 { |
|
1016 iIsStartTimeFlagSet = EFalse; |
|
1017 iPeriodic->Cancel(); |
|
1018 } |
|
1019 } |
|
1020 |
|
1021 // Otherwise, ignore other possibilities |
|
1022 } |
|
1023 |
|
1024 break; |
|
1025 |
|
1026 default: |
|
1027 { |
|
1028 DEBUG_PRINTF2(_L8("HandleClockStateChanged() aMediaTimeType.eState = %d IGNORED!!"), aMediaTimeType.eState); |
|
1029 } |
|
1030 break; |
|
1031 } |
|
1032 |
|
1033 iClockStateRunning = (aMediaTimeType.eState == OMX_TIME_ClockStateRunning) ? ETrue : EFalse; |
|
1034 } |
|
1035 |
|
1036 |
|
1037 void COmxILPcmRendererProcessingFunction::CAudioDevice::HandleClockScaleChanged(const OMX_TIME_MEDIATIMETYPE& aMediaTimeType) |
|
1038 { |
|
1039 if (aMediaTimeType.xScale == 0) |
|
1040 { |
|
1041 PauseAudio(); |
|
1042 iPausedClockViaScale = ETrue; |
|
1043 DEBUG_PRINTF2(_L8("HandleClockScaleChanged() pausing iPausedClockViaScale = %d"), iPausedClockViaScale); |
|
1044 } |
|
1045 else if (aMediaTimeType.xScale == 0x10000) |
|
1046 { |
|
1047 // The scale is a Q16 value |
|
1048 iPausedClockViaScale = EFalse; |
|
1049 DEBUG_PRINTF2(_L8("HandleClockScaleChanged() resuming iPausedClockViaScale = %d"), iPausedClockViaScale); |
|
1050 |
|
1051 // If we are active then there is an outstanding PlayData() request so we need to call ResumePlaying(). |
|
1052 // However calling ResumePlaying() without an outstanding PlayData() request can cause the TimePLayed() API |
|
1053 // to go awry, so we should defer calling ResumePlaying() until the next PlayData() call. |
|
1054 if (IsActive()) |
|
1055 { |
|
1056 iSoundDevice.ResumePlaying(); |
|
1057 } |
|
1058 else |
|
1059 { |
|
1060 iResumeAfterNextPlay = ETrue; |
|
1061 } |
|
1062 iParent.iPFHelper->BufferIndication(); //handles the race condition where both 1) iSoundDevice was paused after the last PlayData() completed and before it was passed any data & 2) BufferIndication()s came in for all the IL buffers while in this paused state |
|
1063 StartUpdateTimer(); |
|
1064 } |
|
1065 |
|
1066 // TODO: Handle the rest of the scale values |
|
1067 |
|
1068 } |
|
1069 |
|
1070 |
|
1071 void COmxILPcmRendererProcessingFunction::CAudioDevice::DoCancel() |
|
1072 { |
|
1073 if (iSoundDevice.Handle() != 0) |
|
1074 { |
|
1075 iSoundDevice.CancelPlayData(); |
|
1076 iSoundDevice.FlushPlayBuffer(); |
|
1077 } |
|
1078 |
|
1079 if (iCurrentBuffer) |
|
1080 { |
|
1081 iCurrentBuffer->nFilledLen = 0; |
|
1082 |
|
1083 iParent.iCallbacks.BufferDoneNotification(iCurrentBuffer, |
|
1084 iCurrentBuffer->nInputPortIndex, |
|
1085 OMX_DirInput); |
|
1086 |
|
1087 iCachedPlayBuffer.Zero(); |
|
1088 iCurrentBuffer = NULL; |
|
1089 } |
|
1090 } |
|
1091 |
|
1092 |
|
1093 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::OpenDevice() |
|
1094 { |
|
1095 OMX_ERRORTYPE err = OMX_ErrorNone; |
|
1096 if(!iSoundDevice.Handle()) |
|
1097 { |
|
1098 if(KErrNone != iSoundDevice.Open(KSoundScTxUnit0)) |
|
1099 { |
|
1100 err = OMX_ErrorHardware; |
|
1101 } |
|
1102 } |
|
1103 return err; |
|
1104 } |
|
1105 |
|
1106 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::CloseDevice() |
|
1107 { |
|
1108 OMX_ERRORTYPE err = OMX_ErrorNone; |
|
1109 if(iSoundDevice.Handle()) |
|
1110 { |
|
1111 iSoundDevice.Close(); |
|
1112 iResumeAfterNextPlay = EFalse; |
|
1113 } |
|
1114 return err; |
|
1115 } |
|
1116 |
|
1117 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::Execute() |
|
1118 { |
|
1119 if(!iSoundDevice.Handle()) |
|
1120 { |
|
1121 if(KErrNone != iSoundDevice.Open()) |
|
1122 { |
|
1123 return OMX_ErrorHardware; |
|
1124 } |
|
1125 } |
|
1126 |
|
1127 if(iParent.iState == OMX_StatePause) |
|
1128 { |
|
1129 // Now we can send BufferDone notifications for each emptied |
|
1130 // buffer... |
|
1131 iParent.FlushBufferList(iParent.iBuffersEmptied); |
|
1132 // If we are active then there is an outstanding PlayData() request so we need to call ResumePlaying(). |
|
1133 // However calling ResumePlaying() without an outstanding PlayData() request can cause the TimePLayed() API |
|
1134 // to go awry, so we should defer calling ResumePlaying() until the next PlayData() call. |
|
1135 if (IsActive()) |
|
1136 { |
|
1137 iSoundDevice.ResumePlaying(); |
|
1138 } |
|
1139 else |
|
1140 { |
|
1141 iResumeAfterNextPlay = ETrue; |
|
1142 } |
|
1143 StartUpdateTimer(); |
|
1144 } |
|
1145 else |
|
1146 { |
|
1147 // Set play format |
|
1148 RMdaDevSound::TCurrentSoundFormatBuf buf; |
|
1149 iSoundDevice.GetPlayFormat(buf); |
|
1150 buf().iRate = iSampleRate; |
|
1151 buf().iChannels = iChannels; |
|
1152 buf().iBufferSize = iBufferSize; |
|
1153 buf().iEncoding = iEncoding; |
|
1154 if(KErrNone != iSoundDevice.SetPlayFormat(buf)) |
|
1155 { |
|
1156 return OMX_ErrorHardware; |
|
1157 } |
|
1158 |
|
1159 if (iMuted) |
|
1160 { |
|
1161 iSoundDevice.SetVolume(0); |
|
1162 } |
|
1163 else |
|
1164 { |
|
1165 iSoundDevice.SetVolume(iVolume); |
|
1166 } |
|
1167 } |
|
1168 |
|
1169 iParent.iState = OMX_StateExecuting; |
|
1170 |
|
1171 // Make sure to start processing of queued up buffers (if any) |
|
1172 if (!IsActive() && iParent.iBuffersToEmpty.Count() > 0) |
|
1173 { |
|
1174 ProcessNextBuffer(); |
|
1175 } |
|
1176 |
|
1177 return OMX_ErrorNone; |
|
1178 } |
|
1179 |
|
1180 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::MoveToPausedState() |
|
1181 { |
|
1182 iParent.iState = OMX_StatePause; |
|
1183 PauseAudio(); |
|
1184 |
|
1185 return OMX_ErrorNone; |
|
1186 } |
|
1187 |
|
1188 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::Stop() |
|
1189 { |
|
1190 if(iParent.iState == OMX_StateExecuting || iParent.iState == OMX_StatePause) |
|
1191 { |
|
1192 // Cancel and flush the device driver |
|
1193 Cancel(); |
|
1194 |
|
1195 // Cancel timer to stop calling RSoundSc::TimePlayed() |
|
1196 if (iIsStartTimeFlagSet) |
|
1197 { |
|
1198 ASSERT(iPeriodic); |
|
1199 iPeriodic->Cancel(); |
|
1200 } |
|
1201 |
|
1202 iParent.iState = OMX_StateIdle; |
|
1203 |
|
1204 // If the audio device is still open, store the last value of bytes |
|
1205 // played before closing the audio device... |
|
1206 if(iSoundDevice.Handle() != 0) |
|
1207 { |
|
1208 iLastBytesPlayedValue = iSoundDevice.BytesPlayed(); |
|
1209 // Close the sound device |
|
1210 iSoundDevice.Close(); |
|
1211 iResumeAfterNextPlay = EFalse; |
|
1212 } |
|
1213 } |
|
1214 |
|
1215 iClockStateRunning = EFalse; |
|
1216 iIsStartTimeFlagSet = EFalse; |
|
1217 iPlayData = ETrue; |
|
1218 |
|
1219 return OMX_ErrorNone; |
|
1220 } |
|
1221 |
|
1222 |
|
1223 void COmxILPcmRendererProcessingFunction::CAudioDevice::PauseAudio() |
|
1224 { |
|
1225 // Cancel timer to stop calling RSoundSc::TimePlayed() |
|
1226 if (iIsStartTimeFlagSet) |
|
1227 { |
|
1228 ASSERT(iPeriodic); |
|
1229 iPeriodic->Cancel(); |
|
1230 } |
|
1231 |
|
1232 if (iSoundDevice.Handle()) |
|
1233 { |
|
1234 iSoundDevice.PausePlayBuffer(); |
|
1235 } |
|
1236 } |
|
1237 |
|
1238 |
|
1239 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::SetChannels(TUint aChannels) |
|
1240 { |
|
1241 iChannels = aChannels; |
|
1242 return SetPlayFormat(); |
|
1243 } |
|
1244 |
|
1245 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::SetSampleRate(TUint aSampleRate) |
|
1246 { |
|
1247 iSampleRate = aSampleRate; |
|
1248 return SetPlayFormat(); |
|
1249 } |
|
1250 |
|
1251 TInt ConvertOmxToSymbianVolume(TInt aVolume) |
|
1252 { |
|
1253 // OpenMax volume is in millibels while Symbian volume is in 0.5 db increments in the [0..255] range |
|
1254 // We divide by 50 as 0.5 dB = 50 millibells |
|
1255 TInt res = KMedianVolume + aVolume / 50; |
|
1256 if (res < 0) |
|
1257 return 0; |
|
1258 if (res > KMaxVolume) |
|
1259 return KMaxVolume; |
|
1260 return res; |
|
1261 } |
|
1262 |
|
1263 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::SetVolume(TInt aVolume) |
|
1264 { |
|
1265 iVolume = ConvertOmxToSymbianVolume(aVolume); |
|
1266 if ((!iMuted) && (iSoundDevice.Handle() != 0)) |
|
1267 { |
|
1268 iSoundDevice.SetVolume(iVolume); |
|
1269 } |
|
1270 return OMX_ErrorNone; |
|
1271 } |
|
1272 |
|
1273 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::SetVolumeRamp(const TTimeIntervalMicroSeconds& aRampDuration) |
|
1274 { |
|
1275 iVolumeRamp = aRampDuration; |
|
1276 if(iVolumeRamp.Int64() != 0) |
|
1277 { |
|
1278 iRampAudioSample = ETrue; |
|
1279 ConfigAudioRamper( |
|
1280 iVolumeRamp.Int64()); |
|
1281 } |
|
1282 else |
|
1283 { |
|
1284 iRampAudioSample = EFalse; |
|
1285 } |
|
1286 return OMX_ErrorNone; |
|
1287 } |
|
1288 |
|
1289 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::SetMuted(TBool aMuted) |
|
1290 { |
|
1291 iMuted = aMuted; |
|
1292 |
|
1293 if (iSoundDevice.Handle() == 0) |
|
1294 { |
|
1295 // Just cache the value; the value will be set once the the device is opened |
|
1296 return OMX_ErrorNone; |
|
1297 } |
|
1298 |
|
1299 if (iMuted) |
|
1300 { |
|
1301 iSoundDevice.SetVolume(0); |
|
1302 } |
|
1303 else |
|
1304 { |
|
1305 iSoundDevice.SetVolume(iVolume); |
|
1306 } |
|
1307 return OMX_ErrorNone; |
|
1308 } |
|
1309 |
|
1310 OMX_ERRORTYPE COmxILPcmRendererProcessingFunction::CAudioDevice::SetPlayFormat() |
|
1311 { |
|
1312 if (iParent.iState == OMX_StateExecuting) |
|
1313 { |
|
1314 RMdaDevSound::TCurrentSoundFormatBuf buf; |
|
1315 iSoundDevice.GetPlayFormat(buf); |
|
1316 buf().iRate = iSampleRate; |
|
1317 buf().iChannels = iChannels; |
|
1318 buf().iBufferSize = iBufferSize; |
|
1319 buf().iEncoding = iEncoding; |
|
1320 if(KErrNone != iSoundDevice.SetPlayFormat(buf)) |
|
1321 { |
|
1322 return OMX_ErrorHardware; |
|
1323 } |
|
1324 } |
|
1325 return OMX_ErrorNone; |
|
1326 } |
|
1327 |
|
1328 OMX_BUFFERHEADERTYPE* COmxILPcmRendererProcessingFunction::CAudioDevice::GetCurrentBuffer() |
|
1329 { |
|
1330 return iCurrentBuffer; |
|
1331 } |
|
1332 |
|
1333 TInt COmxILPcmRendererProcessingFunction::CAudioDevice::GetBytesPlayed() |
|
1334 { |
|
1335 if(iSoundDevice.Handle() != 0) |
|
1336 { |
|
1337 return iSoundDevice.BytesPlayed(); |
|
1338 } |
|
1339 |
|
1340 return iLastBytesPlayedValue; |
|
1341 } |
|
1342 |
|
1343 void COmxILPcmRendererProcessingFunction::CAudioDevice::ConfigAudioRamper(TInt64 aRampTime) |
|
1344 { |
|
1345 iRampSamples = I64LOW(((TInt64(iSampleRate) * aRampTime) /1000000 )); // Add this |
|
1346 iRampSamplesLeft = iRampSamples; |
|
1347 iRampIncr = 0; |
|
1348 iSkip = ETrue; |
|
1349 } |
|
1350 |
|
1351 TBool COmxILPcmRendererProcessingFunction::CAudioDevice::RampAudio(CMMFDataBuffer* aBuffer) |
|
1352 { |
|
1353 TInt i=0; |
|
1354 TInt length = aBuffer->Data().Length()>>1; |
|
1355 if (length == 0) |
|
1356 { |
|
1357 return EFalse; |
|
1358 } |
|
1359 |
|
1360 TInt16* sample = REINTERPRET_CAST(TInt16*,&aBuffer->Data()[0]); |
|
1361 TInt64 theResult(0); |
|
1362 while ((i < length) && (iRampIncr < iRampSamples)) |
|
1363 { |
|
1364 theResult = sample[i]; |
|
1365 theResult *= iRampIncr; |
|
1366 theResult /= iRampSamples; |
|
1367 sample[i] = STATIC_CAST(TInt16, I64LOW(theResult) ); |
|
1368 |
|
1369 if ((iChannels == 1) || (!iSkip)) |
|
1370 { |
|
1371 iRampIncr++; |
|
1372 } |
|
1373 iSkip = !iSkip; |
|
1374 i++; |
|
1375 } |
|
1376 |
|
1377 if (iRampIncr < iRampSamples) |
|
1378 return ETrue; |
|
1379 else |
|
1380 return EFalse; |
|
1381 } |
|
1382 |
|
1383 |
|
1384 TInt COmxILPcmRendererProcessingFunction::CAudioDevice::UpdateClockMediaTime(TAny* aPtr) |
|
1385 { |
|
1386 CAudioDevice* ptr = (CAudioDevice*)aPtr; |
|
1387 TTimeIntervalMicroSeconds playedTime(0); |
|
1388 |
|
1389 if (ptr->iSoundDevice.GetTimePlayed(playedTime) != KErrNone) |
|
1390 { |
|
1391 ptr->iParent.iCallbacks.ErrorEventNotification(OMX_ErrorHardware); |
|
1392 return EFalse; |
|
1393 } |
|
1394 |
|
1395 OMX_ERRORTYPE err; |
|
1396 |
|
1397 // Update the clock component audio reference clock |
|
1398 err = ptr->iParent.iClientClockPortPtr->SetAudioReference(ptr->iParent.iStartMediaTime + playedTime.Int64()); |
|
1399 |
|
1400 if (err != OMX_ErrorNone) |
|
1401 { |
|
1402 ptr->iParent.iCallbacks.ErrorEventNotification(err); |
|
1403 return EFalse; |
|
1404 } |
|
1405 |
|
1406 DEBUG_PRINTF2(_L8("CAudioDevice::UpdateClockMediaTime : playedTime = %d"), |
|
1407 I64LOW(playedTime.Int64())); |
|
1408 |
|
1409 return ETrue; |
|
1410 } |
|
1411 |
|
1412 |
|
1413 void COmxILPcmRendererProcessingFunction::CAudioDevice::ProcessParamIndication(const OMX_AUDIO_PARAM_PCMMODETYPE& aPcmModeType) |
|
1414 { |
|
1415 if(SetChannels(aPcmModeType.nChannels) != OMX_ErrorNone) |
|
1416 { |
|
1417 iParent.iCallbacks.ErrorEventNotification(OMX_ErrorHardware); |
|
1418 return; |
|
1419 } |
|
1420 |
|
1421 if (SetSampleRate(aPcmModeType.nSamplingRate) != OMX_ErrorNone) |
|
1422 { |
|
1423 iParent.iCallbacks.ErrorEventNotification(OMX_ErrorHardware); |
|
1424 return; |
|
1425 } |
|
1426 } |
|
1427 |
|
1428 COmxILPcmRendererProcessingFunction::CPFHelper* COmxILPcmRendererProcessingFunction::CPFHelper::NewL(CAudioDevice& aAudioDevice) |
|
1429 { |
|
1430 CPFHelper* self = new (ELeave) CPFHelper(aAudioDevice); |
|
1431 CleanupStack::PushL(self); |
|
1432 self->ConstructL(); |
|
1433 CleanupStack::Pop(self); |
|
1434 return self; |
|
1435 } |
|
1436 |
|
1437 COmxILPcmRendererProcessingFunction::CPFHelper::CPFHelper(CAudioDevice& aAudioDevice) |
|
1438 : CActive(EPriorityUserInput), |
|
1439 iAudioDevice(aAudioDevice) |
|
1440 { |
|
1441 } |
|
1442 |
|
1443 void COmxILPcmRendererProcessingFunction::CPFHelper::ConstructL() |
|
1444 { |
|
1445 CActiveScheduler::Add(this); |
|
1446 User::LeaveIfError(iCallerSemaphore.CreateGlobal(KNullDesC, 0)); |
|
1447 User::LeaveIfError(iMsgQueue.CreateLocal(KMaxMsgQueueEntries)); |
|
1448 iMsgQueue.NotifyDataAvailable(iStatus); |
|
1449 RThread thisThread; |
|
1450 iHelperThreadId = thisThread.Id(); |
|
1451 thisThread.Close(); |
|
1452 SetActive(); |
|
1453 } |
|
1454 |
|
1455 COmxILPcmRendererProcessingFunction::CPFHelper::~CPFHelper() |
|
1456 { |
|
1457 Cancel(); |
|
1458 iMsgQueue.Close(); |
|
1459 iCallerSemaphore.Close(); |
|
1460 } |
|
1461 |
|
1462 void COmxILPcmRendererProcessingFunction::CPFHelper::RunL() |
|
1463 { |
|
1464 |
|
1465 TProcMessage msg; |
|
1466 while (iMsgQueue.Receive(msg)==KErrNone) |
|
1467 { |
|
1468 switch (msg.iType) |
|
1469 { |
|
1470 case EOpenDevice: |
|
1471 { |
|
1472 iAudioDevice.OpenDevice(); |
|
1473 break; |
|
1474 } |
|
1475 case ECloseDevice: |
|
1476 { |
|
1477 iAudioDevice.CloseDevice(); |
|
1478 break; |
|
1479 } |
|
1480 case ECloseDeviceOnError: |
|
1481 { |
|
1482 iAudioDevice.Cancel(); |
|
1483 iAudioDevice.CloseDevice(); |
|
1484 iCallerSemaphore.Signal(); |
|
1485 break; |
|
1486 } |
|
1487 case EExecuteCommand: |
|
1488 { |
|
1489 iAudioDevice.Execute(); |
|
1490 break; |
|
1491 } |
|
1492 |
|
1493 case EStopCommand: |
|
1494 { |
|
1495 iAudioDevice.Stop(); |
|
1496 break; |
|
1497 } |
|
1498 |
|
1499 case ECancelCommand: |
|
1500 { |
|
1501 iAudioDevice.Cancel(); |
|
1502 break; |
|
1503 } |
|
1504 |
|
1505 case EBufferIndication: |
|
1506 { |
|
1507 iAudioDevice.ProcessNextBuffer(); |
|
1508 break; |
|
1509 } |
|
1510 case EMediaTimeIndication: |
|
1511 { |
|
1512 iAudioDevice.ProcessMediaTimeIndication(msg.iMediaTimeType); |
|
1513 break; |
|
1514 } |
|
1515 case EParamIndication: |
|
1516 { |
|
1517 iAudioDevice.ProcessParamIndication(msg.iPcmModeType); |
|
1518 break; |
|
1519 } |
|
1520 case ESetVolumeRamp: |
|
1521 { |
|
1522 iAudioDevice.SetVolumeRamp(TTimeIntervalMicroSeconds(msg.iRampDuration)); |
|
1523 break; |
|
1524 } |
|
1525 case ESetVolume: |
|
1526 { |
|
1527 iAudioDevice.SetVolume(msg.iVolumeValue); |
|
1528 break; |
|
1529 } |
|
1530 case ESetMuted: |
|
1531 { |
|
1532 iAudioDevice.SetMuted(msg.iMuted); |
|
1533 break; |
|
1534 } |
|
1535 default: |
|
1536 { |
|
1537 break; |
|
1538 } |
|
1539 } |
|
1540 } |
|
1541 DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::CPFHelper::RunL : msg.iType[%d]"), msg.iType); |
|
1542 // setup for next callbacks |
|
1543 iMsgQueue.NotifyDataAvailable(iStatus); |
|
1544 SetActive(); |
|
1545 } |
|
1546 |
|
1547 void COmxILPcmRendererProcessingFunction::CPFHelper::DoCancel() |
|
1548 { |
|
1549 if (iMsgQueue.Handle()!=NULL) |
|
1550 { |
|
1551 iMsgQueue.CancelDataAvailable(); |
|
1552 } |
|
1553 } |
|
1554 |
|
1555 TInt COmxILPcmRendererProcessingFunction::CPFHelper::OpenDevice() |
|
1556 { |
|
1557 TProcMessage message; |
|
1558 message.iType = EOpenDevice; |
|
1559 return iMsgQueue.Send(message); |
|
1560 } |
|
1561 |
|
1562 TInt COmxILPcmRendererProcessingFunction::CPFHelper::CloseDevice() |
|
1563 { |
|
1564 DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::CPFHelper::CloseDevice : IsActive[%s]"), |
|
1565 (IsActive() ? "YES" : "NO")); |
|
1566 TProcMessage message; |
|
1567 message.iType = ECloseDevice; |
|
1568 return iMsgQueue.Send(message); |
|
1569 } |
|
1570 |
|
1571 TInt COmxILPcmRendererProcessingFunction::CPFHelper::CloseDeviceOnError() |
|
1572 { |
|
1573 DEBUG_PRINTF2(_L8("COmxILPcmRendererProcessingFunction::CPFHelper::CloseDeviceOnError : IsActive[%d]"), (IsActive() ? 1 : 0)); |
|
1574 |
|
1575 RThread thisThread; |
|
1576 if (thisThread.Id() == iHelperThreadId) |
|
1577 { |
|
1578 // Just do it... |
|
1579 iAudioDevice.Cancel(); |
|
1580 iAudioDevice.CloseDevice(); |
|
1581 } |
|
1582 else |
|
1583 { |
|
1584 |
|
1585 TProcMessage message; |
|
1586 message.iType = ECloseDeviceOnError; |
|
1587 TInt error = iMsgQueue.Send(message); |
|
1588 if (KErrNone != error) |
|
1589 { |
|
1590 // only wait if the message was sent into the queue... |
|
1591 iCallerSemaphore.Wait(); |
|
1592 } |
|
1593 } |
|
1594 |
|
1595 thisThread.Close(); |
|
1596 |
|
1597 return KErrNone; |
|
1598 |
|
1599 } |
|
1600 |
|
1601 TInt COmxILPcmRendererProcessingFunction::CPFHelper::Execute() |
|
1602 { |
|
1603 DEBUG_PRINTF2(_L8("CPFHelper::Execute : IsActive[%s]"), (IsActive() ? "YES" : "NO")); |
|
1604 TProcMessage message; |
|
1605 message.iType = EExecuteCommand; |
|
1606 return iMsgQueue.Send(message); |
|
1607 } |
|
1608 |
|
1609 TInt COmxILPcmRendererProcessingFunction::CPFHelper::Stop() |
|
1610 { |
|
1611 DEBUG_PRINTF2(_L8("CPFHelper::Stop : IsActive[%s]"), (IsActive() ? "YES" : "NO")); |
|
1612 TProcMessage message; |
|
1613 message.iType = EStopCommand; |
|
1614 return iMsgQueue.Send(message); |
|
1615 } |
|
1616 |
|
1617 TInt COmxILPcmRendererProcessingFunction::CPFHelper::CancelDevice() |
|
1618 { |
|
1619 DEBUG_PRINTF2(_L8("CPFHelper::CancelDevice : IsActive[%s]"), (IsActive() ? "YES" : "NO")); |
|
1620 TProcMessage message; |
|
1621 message.iType = ECancelCommand; |
|
1622 return iMsgQueue.Send(message); |
|
1623 } |
|
1624 |
|
1625 TInt COmxILPcmRendererProcessingFunction::CPFHelper::BufferIndication() |
|
1626 { |
|
1627 DEBUG_PRINTF2(_L8("CPFHelper::BufferIndication : IsActive[%s]"), (IsActive() ? "YES" : "NO")); |
|
1628 TProcMessage message; |
|
1629 message.iType = EBufferIndication; |
|
1630 return iMsgQueue.Send(message); |
|
1631 } |
|
1632 |
|
1633 TInt COmxILPcmRendererProcessingFunction::CPFHelper::MediaTimeIndication(const OMX_TIME_MEDIATIMETYPE& aMediaTimeType) |
|
1634 { |
|
1635 DEBUG_PRINTF2(_L8("CPFHelper::MediaTimeIndication : IsActive[%s]"), (IsActive() ? "YES" : "NO")); |
|
1636 TProcMessage message; |
|
1637 message.iType = EMediaTimeIndication; |
|
1638 message.iMediaTimeType.eUpdateType = aMediaTimeType.eUpdateType; |
|
1639 message.iMediaTimeType.eState = aMediaTimeType.eState; |
|
1640 message.iMediaTimeType.xScale = aMediaTimeType.xScale; |
|
1641 message.iMediaTimeType.nMediaTimestamp = aMediaTimeType.nMediaTimestamp; |
|
1642 |
|
1643 return iMsgQueue.Send(message); |
|
1644 } |
|
1645 |
|
1646 TInt COmxILPcmRendererProcessingFunction::CPFHelper::ParamIndication(const OMX_AUDIO_PARAM_PCMMODETYPE* aPcmModeType) |
|
1647 { |
|
1648 DEBUG_PRINTF2(_L8("CPFHelper::ParamIndication : IsActive[%s]"), (IsActive() ? "YES" : "NO")); |
|
1649 TProcMessage message; |
|
1650 message.iType = EParamIndication; |
|
1651 message.iPcmModeType.nChannels = aPcmModeType->nChannels; |
|
1652 message.iPcmModeType.nSamplingRate = aPcmModeType->nSamplingRate; |
|
1653 |
|
1654 return iMsgQueue.Send(message); |
|
1655 } |
|
1656 |
|
1657 TInt COmxILPcmRendererProcessingFunction::CPFHelper::SetVolumeRamp(const OMX_U64 aRampDuration) |
|
1658 { |
|
1659 DEBUG_PRINTF2(_L8("CPFHelper::SetVolumeRamp : IsActive[%s]"), (IsActive() ? "YES" : "NO")); |
|
1660 TProcMessage message; |
|
1661 message.iType = ESetVolumeRamp; |
|
1662 message.iRampDuration = aRampDuration; |
|
1663 |
|
1664 return iMsgQueue.Send(message); |
|
1665 } |
|
1666 |
|
1667 TInt COmxILPcmRendererProcessingFunction::CPFHelper::SetVolume(const OMX_S32 aVolumeValue) |
|
1668 { |
|
1669 DEBUG_PRINTF2(_L8("CPFHelper::SetVolume : IsActive[%s]"), (IsActive() ? "YES" : "NO")); |
|
1670 TProcMessage message; |
|
1671 message.iType = ESetVolume; |
|
1672 message.iVolumeValue = aVolumeValue; |
|
1673 |
|
1674 return iMsgQueue.Send(message); |
|
1675 } |
|
1676 |
|
1677 TInt COmxILPcmRendererProcessingFunction::CPFHelper::SetMuted(const OMX_BOOL aMuted) |
|
1678 { |
|
1679 DEBUG_PRINTF2(_L8("CPFHelper::SetMuted : IsActive[%s]"), (IsActive() ? "YES" : "NO")); |
|
1680 TProcMessage message; |
|
1681 message.iType = ESetMuted; |
|
1682 message.iMuted = aMuted; |
|
1683 |
|
1684 return iMsgQueue.Send(message); |
|
1685 } |