1 /* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18
19 #include "pvmf_media_clock.h"
20
PVMFMediaClock()21 OSCL_EXPORT_REF PVMFMediaClock::PVMFMediaClock() : OsclTimerObject(OsclActiveObject::EPriorityNominal, "PVMFMediaClock"),
22 iState(STOPPED),
23 iClockTimebase(NULL)
24 {
25 iLogger = PVLogger::GetLoggerObject("PVMFMediaClock");
26 iLatestRunningClockTime = 0;
27 iLatestRunningTimebaseTime = 0;
28 iStartTimebaseTickValue = 0;
29 iStartClockTime = 0;
30 iPauseClockTime = 0;
31 iLastAdjustObsTimebaseTime = 0;
32 iAdjustmentTimebaseTime = 0;
33 iStartNPT = 0;
34 iIsNPTPlayBackDirectionBackwards = 0;
35 iStartMediaClockTS = 0;
36 iClockUnit = PVMF_MEDIA_CLOCK_CLOCKUNIT_MSEC;
37 iPreviousClockUnit = PVMF_MEDIA_CLOCK_CLOCKUNIT_MSEC;
38 iActiveTimersCount = 0;
39 iTimerIDCount = 1;
40 OsclThread::GetId(iOrigThreadID);
41 AddToScheduler();
42 iMutex = OSCL_NEW(OsclMutex, ());
43 iMutex->Create();
44
45 //initialize this to real time
46 iLastTimebaseRate = REALTIME_PLAYBACK_RATE;
47
48 iIsTimebaseCountBased = false;
49 }
50
~PVMFMediaClock()51 OSCL_EXPORT_REF PVMFMediaClock::~PVMFMediaClock()
52 {
53 Reset();
54 iMutex->Close();
55 if (iMutex)
56 OSCL_DELETE(iMutex);
57 RemoveFromScheduler();
58 }
59
CleanCallbackInfImplObjects()60 void PVMFMediaClock::CleanCallbackInfImplObjects()
61 {
62 for (uint32 ii = 0; ii < iMediaClockSetCallbackObjects.size(); ii++)
63 {
64 if (iMediaClockSetCallbackObjects[ii]->iNotificationInterfaceDestroyedCallback)
65 {
66 (iMediaClockSetCallbackObjects[ii]->iNotificationInterfaceDestroyedCallback)->NotificationsInterfaceDestroyed();
67 }
68 OSCL_DELETE(iMediaClockSetCallbackObjects[ii]);
69 iMediaClockSetCallbackObjects.erase(&iMediaClockSetCallbackObjects[ii]);
70 }
71 }
72
73 OSCL_EXPORT_REF PVMFStatus
ConstructMediaClockNotificationsInterface(PVMFMediaClockNotificationsInterface * & aIface,PVMFMediaClockNotificationsObsBase & aNotificationInterfaceDestroyedCallback,uint32 aLatency)74 PVMFMediaClock::ConstructMediaClockNotificationsInterface(PVMFMediaClockNotificationsInterface*& aIface,
75 PVMFMediaClockNotificationsObsBase& aNotificationInterfaceDestroyedCallback,
76 uint32 aLatency)
77 {
78
79 PVMFMediaClockNotificationsInterfaceImpl* ifaceImpl = NULL;
80
81 if (RUNNING == iState)
82 {
83 return PVMFErrInvalidState;
84 }
85
86 ifaceImpl = OSCL_NEW(PVMFMediaClockNotificationsInterfaceImpl, (this, aLatency, aNotificationInterfaceDestroyedCallback));
87 aIface = OSCL_STATIC_CAST(PVMFMediaClockNotificationsInterface*, ifaceImpl);
88
89 if (aIface)
90 {
91 iMediaClockSetCallbackObjects.push_back(ifaceImpl);
92 AdjustLatenciesOfSinks();
93 return PVMFSuccess;
94 }
95 else
96 {
97 return PVMFFailure;
98 }
99 }
100
DestroyMediaClockNotificationsInterface(PVMFMediaClockNotificationsInterface * aInf)101 OSCL_EXPORT_REF void PVMFMediaClock::DestroyMediaClockNotificationsInterface(PVMFMediaClockNotificationsInterface* aInf)
102 {
103 if (!aInf)
104 {
105 return;
106 }
107
108 //Cancel all active callbacks created from this interface object.
109 if (!iTimersPriQueue.empty())
110 {
111 Oscl_Vector<PVMFMediaClockTimerQueueElement, OsclMemAllocator> qVector = iTimersPriQueue.vec();
112 for (uint32 ii = 0; ii < qVector.size(); ii++)
113 {
114 if (qVector[ii].pInterfaceObject == aInf)
115 {
116 CommonCancelCallback(qVector[ii].callBackID, false, false);
117 }
118 }
119 }
120
121 if (!iIsNPTPlayBackDirectionBackwards)
122 {
123 if (!iTimersPriQueueNPT.empty())
124 {
125 Oscl_Vector<PVMFMediaClockTimerQueueElement, OsclMemAllocator> qVector = iTimersPriQueueNPT.vec();
126 for (uint32 ii = 0; ii < qVector.size(); ii++)
127 {
128 if (qVector[ii].pInterfaceObject == aInf)
129 {
130 CommonCancelCallback(qVector[ii].callBackID, false, true);
131 }
132 }
133 }
134 }
135 else
136 {
137 if (!iTimersPriQueueNPTBackwards.empty())
138 {
139 Oscl_Vector<PVMFMediaClockTimerQueueElement, OsclMemAllocator> qVector = iTimersPriQueueNPTBackwards.vec();
140 for (uint32 ii = 0; ii < qVector.size(); ii++)
141 {
142 if (qVector[ii].pInterfaceObject == aInf)
143 {
144 CommonCancelCallback(qVector[ii].callBackID, false, true);
145 }
146 }
147
148 }
149 }
150
151
152
153 //Destroy the interface
154 PVMFMediaClockNotificationsInterfaceImpl* ifaceImpl = NULL;
155
156 ifaceImpl = OSCL_STATIC_CAST(PVMFMediaClockNotificationsInterfaceImpl*, aInf);
157 for (uint32 ii = 0; ii < iMediaClockSetCallbackObjects.size(); ii++)
158 {
159 if (iMediaClockSetCallbackObjects[ii] == ifaceImpl)
160 {
161 if (iMediaClockSetCallbackObjects[ii]->iNotificationInterfaceDestroyedCallback)
162 {
163 (iMediaClockSetCallbackObjects[ii]->iNotificationInterfaceDestroyedCallback)->NotificationsInterfaceDestroyed();
164 }
165 OSCL_DELETE(iMediaClockSetCallbackObjects[ii]);
166 iMediaClockSetCallbackObjects.erase(&iMediaClockSetCallbackObjects[ii]);
167 }
168 }
169 }
170
SetClockTimebase(PVMFTimebase & aTimebase)171 OSCL_EXPORT_REF bool PVMFMediaClock::SetClockTimebase(PVMFTimebase& aTimebase)
172 {
173 // Clock timebase can only be set during stopped or paused states
174 if (iState == RUNNING)
175 {
176 return false;
177 }
178
179 // Save the clock timebase object pointer
180 iClockTimebase = &aTimebase;
181
182 if ((iClockTimebase->GetRate() != iLastTimebaseRate) &&
183 iActiveTimersCount != 0)
184 {
185 //start scheduling afresh
186 AdjustScheduling();
187 }
188
189 //Update timebase rate
190 iLastTimebaseRate = iClockTimebase->GetRate();
191
192 //If this is a counting timebase, then set the timebase
193 //observer to this clock, so that we'll get the count update
194 //notices.
195 if (aTimebase.GetCountTimebase())
196 {
197 aTimebase.GetCountTimebase()->SetClockObserver(this);
198 iIsTimebaseCountBased = true;
199 }
200 else
201 {
202 iIsTimebaseCountBased = false;
203 }
204
205 //Notify observers that the timebase is updated.
206 ClockTimebaseUpdated();
207
208 return true;
209 }
AdjustLatenciesOfSinks()210 void PVMFMediaClock::AdjustLatenciesOfSinks()
211 {
212 uint32 size = iMediaClockSetCallbackObjects.size();
213 uint32 ii = 0;
214
215 if (!size)
216 return;
217
218 //find the minimum and maximum latencies
219 uint32 minLatency = iMediaClockSetCallbackObjects[0]->iLatency;
220 uint32 maxLatency = iMediaClockSetCallbackObjects[0]->iLatency;
221 for (ii = 0; ii < size - 1; ii++)
222 {
223 if (iMediaClockSetCallbackObjects[ii+1]->iLatency > iMediaClockSetCallbackObjects[ii]->iLatency)
224 {
225 minLatency = iMediaClockSetCallbackObjects[ii]->iLatency;
226 }
227 else
228 {
229 minLatency = iMediaClockSetCallbackObjects[ii+1]->iLatency;
230 }
231
232 if (iMediaClockSetCallbackObjects[ii+1]->iLatency > iMediaClockSetCallbackObjects[ii]->iLatency)
233 {
234 maxLatency = iMediaClockSetCallbackObjects[ii+1]->iLatency;
235 }
236 else
237 {
238 maxLatency = iMediaClockSetCallbackObjects[ii]->iLatency;
239 }
240 }
241
242 //set adjusted-latencies and latency-delays
243 for (ii = 0; ii < size; ii++)
244 {
245 iMediaClockSetCallbackObjects[ii]->iAdjustedLatency =
246 iMediaClockSetCallbackObjects[ii]->iLatency - minLatency;
247
248 iMediaClockSetCallbackObjects[ii]->iLatencyDelayForClockStartNotification =
249 maxLatency - iMediaClockSetCallbackObjects[ii]->iLatency;
250 }
251
252 }
253
Start()254 OSCL_EXPORT_REF bool PVMFMediaClock::Start()
255 {
256 bool overflowFlag = false;
257 // Can only start from stopped or paused states
258 if (iState == RUNNING)
259 {
260 return false;
261 }
262
263
264 uint32 tbval = 0;
265
266
267 // Save the clock timebase value to the appropriate
268 // variable and update the iLatest... values.
269 if (iState == STOPPED)
270 {
271 // Retrieve the current time value from the clock timebase
272 if (iClockTimebase != NULL)
273 {
274 iClockTimebase->GetCurrentTick32(iStartTimebaseTickValue, overflowFlag);
275 }
276
277 //can reuse overflowFlag as result would be virtually same
278 GetScaledTimebaseTickCount(tbval, overflowFlag);
279 // Starting from stop
280 UpdateLatestTimes(iStartClockTime, tbval);
281 }
282 else
283 {
284 GetScaledTimebaseTickCount(tbval, overflowFlag);
285 // Resuming from pause
286 UpdateLatestTimes(iPauseClockTime, tbval);
287 }
288
289 // Change to running state
290 SetClockState(RUNNING);
291
292 //Restart callback scheduling
293 AdjustScheduling();
294
295 return true;
296 }
297
Pause()298 OSCL_EXPORT_REF bool PVMFMediaClock::Pause()
299 {
300 bool overflowFlag = false;
301 // Can only pause during running state
302 if (iState != RUNNING)
303 {
304 return false;
305 }
306
307 // Save the current time
308 uint32 tbval = 0;
309 GetCurrentTime32(iPauseClockTime, overflowFlag, PVMF_MEDIA_CLOCK_MSEC, tbval);
310 UpdateLatestTimes(iPauseClockTime, tbval);
311
312 // Change to paused state
313 SetClockState(PAUSED);
314
315 //Cancel any scheduled Run
316 Cancel();
317 return true;
318 }
319
Stop()320 OSCL_EXPORT_REF bool PVMFMediaClock::Stop()
321 {
322 // Can only stop when running or paused
323 if (iState == STOPPED)
324 {
325 return false;
326 }
327
328 // Reset the time values
329 uint32 tmp = 0;
330 UpdateLatestTimes(tmp, tmp);
331 iStartClockTime = tmp;
332 iPauseClockTime = tmp;
333 iLastAdjustObsTimebaseTime = tmp;
334 iAdjustmentTimebaseTime = tmp;
335 iStartTimebaseTickValue = tmp;
336
337 // Change to stopped state
338 SetClockState(STOPPED);
339
340 //Clear all callback queues
341 ClearAllQueues();
342 return true;
343 }
344
GetStartTime32(uint32 & aTime,bool & aOverflow,PVMFMediaClock_TimeUnits aUnits)345 OSCL_EXPORT_REF void PVMFMediaClock::GetStartTime32(uint32& aTime, bool& aOverflow, PVMFMediaClock_TimeUnits aUnits)
346 {
347 aOverflow = false;
348 // Convert to the requested time units and return the start time
349 FromClockUnit(iStartClockTime, aTime, aUnits, aOverflow);
350 }
351
SetStartTime32(uint32 & aTime,PVMFMediaClock_TimeUnits aUnits,bool & aOverFlow)352 OSCL_EXPORT_REF bool PVMFMediaClock::SetStartTime32(uint32& aTime, PVMFMediaClock_TimeUnits aUnits, bool& aOverFlow)
353 {
354 aOverFlow = false;
355
356 // Can only set start time while stopped
357 if (iState != STOPPED)
358 {
359 return false;
360 }
361
362 iPreviousClockUnit = iClockUnit;
363 // set clock units to usec if units arg is usec. Otherwise, default is msec
364 (PVMF_MEDIA_CLOCK_USEC == aUnits) ? iClockUnit = PVMF_MEDIA_CLOCK_CLOCKUNIT_USEC :
365 iClockUnit = PVMF_MEDIA_CLOCK_CLOCKUNIT_MSEC;
366
367 if (iPreviousClockUnit != iClockUnit)
368 {
369 AdjustClockInternalsToNewUnits(aOverFlow);
370 }
371
372 // Convert to clock units and set the start time
373 bool overflowFlag1 = false;
374 ToClockUnit(aTime, aUnits, iStartClockTime, overflowFlag1);
375
376 aOverFlow = aOverFlow | overflowFlag1;
377
378 //start scheduling afresh
379 AdjustScheduling();
380 return true;
381 }
382
AdjustClockTime32(uint32 & aClockTime,uint32 & aTimebaseTime,uint32 & aAdjustedTime,PVMFMediaClock_TimeUnits aUnits,bool & aOverFlow)383 OSCL_EXPORT_REF PVMFMediaClockAdjustTimeStatus PVMFMediaClock::AdjustClockTime32(uint32& aClockTime, uint32& aTimebaseTime, uint32& aAdjustedTime, PVMFMediaClock_TimeUnits aUnits, bool& aOverFlow)
384 {
385 aOverFlow = false;
386
387 // Clock can only be adjusted when it is running
388 if (iState != RUNNING)
389 {
390 return PVMF_MEDIA_CLOCK_ADJUST_ERR_INVALID_STATE;
391 }
392
393 // Check if the adjustment's observed time is later than the last one
394 uint32 temp = 0;
395 if (PVTimeComparisonUtils::IsEarlier(aTimebaseTime, iLastAdjustObsTimebaseTime, temp) && (temp != 0))
396 {
397 // Old data so don't use it for adjustment
398 return PVMF_MEDIA_CLOCK_ADJUST_ERR_INVALID_TIMEBASE_TIME;
399 }
400
401 iPreviousClockUnit = iClockUnit;
402
403 // set clock units to usec if units arg is usec. Otherwise, default is msec
404 (PVMF_MEDIA_CLOCK_USEC == aUnits) ? iClockUnit = PVMF_MEDIA_CLOCK_CLOCKUNIT_USEC :
405 iClockUnit = PVMF_MEDIA_CLOCK_CLOCKUNIT_MSEC;
406
407 if (iPreviousClockUnit != iClockUnit)
408 {
409 AdjustClockInternalsToNewUnits(aOverFlow);
410 }
411
412 // Convert the observed clock and adjustment time to usec so it can be compared
413 uint32 adjusttime, clocktime;
414 bool overflowFlag1 = false, overflowFlag2 = false;
415 ToClockUnit(aClockTime, aUnits, clocktime, overflowFlag1);
416 ToClockUnit(aAdjustedTime, aUnits, adjusttime, overflowFlag2);
417
418 // Make sure the adjustment's clock and timebase times are before current time
419 uint32 currenttime = 0;
420 uint32 tbval = 0;
421 bool overflowFlag3 = false, overflowFlag4 = false;
422
423 // Get the current timebase time
424 GetScaledTimebaseTickCount(tbval, overflowFlag4);
425
426 // Get the current clock time in clock units
427 GetCurrentTime32(currenttime, overflowFlag3, iClockUnit == PVMF_MEDIA_CLOCK_CLOCKUNIT_USEC ? PVMF_MEDIA_CLOCK_USEC :
428 PVMF_MEDIA_CLOCK_MSEC);
429
430 aOverFlow = aOverFlow | overflowFlag1 | overflowFlag2 | overflowFlag3 | overflowFlag4;
431
432 if (PVTimeComparisonUtils::IsEarlier(tbval, aTimebaseTime, temp) && (temp != 0))
433 {
434 // Observed timebase time cannot be later than the current timebase time
435 return PVMF_MEDIA_CLOCK_ADJUST_ERR_INVALID_TIMEBASE_TIME;
436 }
437
438 if (clocktime > currenttime)
439 {
440 // Observed clock time cannot be later than the current clock time
441 return PVMF_MEDIA_CLOCK_ADJUST_ERR_CORRUPT_CLOCK_TIME;
442 }
443
444 // Make the adjustment
445 return AdjustClock(clocktime, aTimebaseTime, adjusttime, currenttime, tbval);
446
447 }
448
Reset()449 OSCL_EXPORT_REF bool PVMFMediaClock::Reset()
450 {
451 bool tmpFlag = true;
452
453 //stop clock if its not already stopped
454 if (STOPPED != iState)
455 {
456 tmpFlag = Stop();
457 }
458
459 // remove all ClockObservers
460 iClockObservers.clear();
461
462 // remove interface objects. This will also remove all ClockStateObservers.
463 CleanCallbackInfImplObjects();
464
465 return tmpFlag;
466 }
467
GetCurrentTick32(uint32 & aTimebaseTickCount,bool & aOverflow)468 OSCL_EXPORT_REF void PVMFMediaClock::GetCurrentTick32(uint32& aTimebaseTickCount, bool& aOverflow)
469 {
470 aOverflow = false;
471
472 if (iClockTimebase != NULL)
473 {
474 iClockTimebase->GetCurrentTick32(aTimebaseTickCount, aOverflow);
475 }
476 else
477 {
478 aTimebaseTickCount = 0;
479 }
480 }
481
GetTimebaseResolution(uint32 & aResolution)482 OSCL_EXPORT_REF void PVMFMediaClock::GetTimebaseResolution(uint32& aResolution)
483 {
484 if (iClockTimebase)
485 {
486 // Retrieve the resolution from the timebase being used
487 iClockTimebase->GetTimebaseResolution(aResolution);
488 }
489 else
490 {
491 // No timebase so set to 0
492 aResolution = 0;
493 }
494 }
495
GetRate(void)496 OSCL_EXPORT_REF int32 PVMFMediaClock::GetRate(void)
497 {
498 if (iClockTimebase)
499 {
500 // Retrieve the playback rate from the timebase being used
501 return iClockTimebase->GetRate();
502 }
503 else
504 {
505 // No timebase so return realtime rate
506 return REALTIME_PLAYBACK_RATE;
507 }
508 }
509
GetCurrentTime32(uint32 & aClockTime,bool & aOverflow,PVMFMediaClock_TimeUnits aUnits)510 OSCL_EXPORT_REF void PVMFMediaClock::GetCurrentTime32(uint32& aClockTime, bool& aOverflow, PVMFMediaClock_TimeUnits aUnits)
511 {
512 uint32 temp = 0;
513
514 GetCurrentTime32(aClockTime, aOverflow, aUnits, temp);
515 }
516
GetCurrentTime32(uint32 & aClockTime,bool & aOverflow,PVMFMediaClock_TimeUnits aUnits,uint32 & aTimebaseTime)517 OSCL_EXPORT_REF void PVMFMediaClock::GetCurrentTime32(uint32& aClockTime, bool& aOverflow, PVMFMediaClock_TimeUnits aUnits, uint32& aTimebaseTime)
518 {
519 // Get and return the current timebase value
520
521 bool overflowFlag1 = false, overflowFlag2 = false, overflowFlag3 = false;
522
523 aOverflow = false;
524
525 // Get the current timebase time
526 GetScaledTimebaseTickCount(aTimebaseTime, aOverflow);
527
528 // Determine and return the current clock time
529 if (iState == STOPPED)
530 {
531 // Return the specified start time
532 FromClockUnit(iStartClockTime, aClockTime, aUnits, overflowFlag3);
533 }
534 else if (iState == PAUSED)
535 {
536 // Returned the paused time
537 FromClockUnit(iPauseClockTime, aClockTime, aUnits, overflowFlag3);
538 }
539 else
540 {
541 // Running state
542 uint32 currenttime;
543
544 // Determine current clock time including any adjustment
545 GetAdjustedRunningClockTime(currenttime, aTimebaseTime);
546
547 // Convert to requested time units
548 FromClockUnit(currenttime, aClockTime, aUnits, overflowFlag3);
549 }
550
551 aOverflow = aOverflow | overflowFlag1 | overflowFlag2 | overflowFlag3;
552 }
553
QueryInterface(const PVUuid & uuid,PVInterface * & iface)554 OSCL_EXPORT_REF bool PVMFMediaClock::QueryInterface(const PVUuid& uuid, PVInterface*& iface)
555 {
556 if (uuid == PVMFMediaClockControlInterfaceUuid)
557 {
558 PVMFMediaClockControlInterface* myInterface =
559 OSCL_STATIC_CAST(PVMFMediaClockControlInterface*, this);
560 iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
561 }
562 else if (uuid == PVMFMediaClockAccessInterfaceUuid)
563 {
564 PVMFMediaClockAccessInterface* myInterface =
565 OSCL_STATIC_CAST(PVMFMediaClockAccessInterface*, this);
566 iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
567 }
568 else if (uuid == PVMFMediaClockNPTClockPositionAccessInterfaceUuid)
569 {
570 PVMFMediaClockNPTClockPositionAccessInterface* myInterface =
571 OSCL_STATIC_CAST(PVMFMediaClockNPTClockPositionAccessInterface*, this);
572 iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
573 }
574 else
575 {
576 return false;
577 }
578
579 return true;
580 }
581
SetClockObserver(PVMFMediaClockObserver & aObserver)582 OSCL_EXPORT_REF void PVMFMediaClock::SetClockObserver(PVMFMediaClockObserver& aObserver)
583 {
584 iClockObservers.push_back(&aObserver);
585 }
586
RemoveClockObserver(PVMFMediaClockObserver & aObserver)587 OSCL_EXPORT_REF void PVMFMediaClock::RemoveClockObserver(PVMFMediaClockObserver& aObserver)
588 {
589 for (uint32 i = 0; i < iClockObservers.size(); i++)
590 {
591 if (iClockObservers[i] == &aObserver)
592 iClockObservers.erase(&iClockObservers[i]);
593 }
594 }
595
SetClockState(PVMFMediaClockState aState)596 void PVMFMediaClock::SetClockState(PVMFMediaClockState aState)
597 {
598 // Change the clock state
599 iState = aState;
600
601 // Notify observers
602
603 //If this is clock start, we need to send start notification after adjusting latency
604 if (RUNNING == iState)
605 {
606 for (uint32 ii = 0; ii < iMediaClockSetCallbackObjects.size(); ii++)
607 {
608 if (iMediaClockSetCallbackObjects[ii]->iClockStateObserver != NULL)
609 {
610 if (0 == iMediaClockSetCallbackObjects[ii]->iLatencyDelayForClockStartNotification)
611 {
612 (iMediaClockSetCallbackObjects[ii]->iClockStateObserver)->ClockStateUpdated();
613 }
614 else
615 {
616 //Queue notification
617 QueueClockStartNotificationEvent(iMediaClockSetCallbackObjects[ii]->iLatencyDelayForClockStartNotification,
618 iMediaClockSetCallbackObjects[ii]->iClockStateObserver);
619 }
620 }
621 }
622 }
623 else
624 {
625 for (uint32 ii = 0; ii < iMediaClockSetCallbackObjects.size(); ii++)
626 {
627 if (iMediaClockSetCallbackObjects[ii]->iClockStateObserver != NULL)
628 {
629 (iMediaClockSetCallbackObjects[ii]->iClockStateObserver)->ClockStateUpdated();
630 }
631 }
632 }
633 }
634
GetScaledTimebaseTickCount(uint32 & aScaledTickCount,bool & aOverFlow)635 void PVMFMediaClock::GetScaledTimebaseTickCount(uint32& aScaledTickCount, bool& aOverFlow)
636 {
637 uint32 temp = 0;
638 aOverFlow = false;
639
640 if (iClockTimebase != NULL)
641 {
642 iClockTimebase->GetCurrentTick32(temp, aOverFlow);
643 }
644
645 PVTimeComparisonUtils::IsEarlier(iStartTimebaseTickValue, temp, aScaledTickCount);
646 }
647
UpdateLatestTimes(uint32 aTime,uint32 aTimebaseVal)648 void PVMFMediaClock::UpdateLatestTimes(uint32 aTime, uint32 aTimebaseVal)
649 {
650 // Set the latest time values
651 iLatestRunningClockTime = aTime;
652 iLatestRunningTimebaseTime = aTimebaseVal;
653 }
654
AdjustClockInternalsToNewUnits(bool & aOverFlow)655 void PVMFMediaClock::AdjustClockInternalsToNewUnits(bool& aOverFlow)
656 {
657
658 uint32 temp = 0;
659
660 aOverFlow = false;
661
662 // Change the units
663 if (PVMF_MEDIA_CLOCK_CLOCKUNIT_USEC == iPreviousClockUnit)
664 {
665 ToClockUnit(iLatestRunningClockTime, PVMF_MEDIA_CLOCK_USEC, temp, aOverFlow);
666 iLatestRunningClockTime = temp;
667
668 ToClockUnit(iStartClockTime, PVMF_MEDIA_CLOCK_USEC, temp, aOverFlow);
669 iStartClockTime = temp;
670
671 ToClockUnit(iPauseClockTime, PVMF_MEDIA_CLOCK_USEC, temp, aOverFlow);
672 iPauseClockTime = temp;
673 }
674 else if (PVMF_MEDIA_CLOCK_CLOCKUNIT_MSEC == iPreviousClockUnit)
675 {
676 ToClockUnit(iLatestRunningClockTime, PVMF_MEDIA_CLOCK_MSEC, temp, aOverFlow);
677 iLatestRunningClockTime = temp;
678
679 ToClockUnit(iStartClockTime, PVMF_MEDIA_CLOCK_MSEC, temp, aOverFlow);
680 iStartClockTime = temp;
681
682 ToClockUnit(iPauseClockTime, PVMF_MEDIA_CLOCK_MSEC, temp, aOverFlow);
683 iPauseClockTime = temp;
684 }
685 }
686
687 #define OSCL_DISABLE_WARNING_CONV_POSSIBLE_LOSS_OF_DATA
688 #include "osclconfig_compiler_warnings.h"
689
ToClockUnit(uint32 & aSrcVal,PVMFMediaClock_TimeUnits aSrcUnits,uint32 & aDestVal,bool & aOverFlow)690 void PVMFMediaClock::ToClockUnit(uint32& aSrcVal, PVMFMediaClock_TimeUnits aSrcUnits, uint32& aDestVal, bool& aOverFlow)
691 {
692 uint32 multconst = 1;
693
694 aOverFlow = false;
695
696 switch (iClockUnit)
697 {
698 case PVMF_MEDIA_CLOCK_CLOCKUNIT_MSEC:
699 {
700 if (PVMF_MEDIA_CLOCK_USEC == aSrcUnits)
701 {
702 aDestVal = aSrcVal / 1000;
703 }
704 else
705 {
706 // Determine the multiplier constant for the specified units
707 switch (aSrcUnits)
708 {
709 case PVMF_MEDIA_CLOCK_SEC:
710 multconst = 1000;
711 break;
712
713 case PVMF_MEDIA_CLOCK_MIN:
714 multconst = 60000;
715 break;
716
717 case PVMF_MEDIA_CLOCK_HOUR:
718 multconst = 0x36EE80;
719 break;
720
721 case PVMF_MEDIA_CLOCK_DAY:
722 multconst = 0x5265C00;
723 break;
724
725 case PVMF_MEDIA_CLOCK_MSEC:
726 default:
727 break;
728 }
729
730 // Convert value to clock units
731 uint64 time64 = (uint64)(aSrcVal * multconst);
732
733 //There is a chance that Tickcount did not wrap around but aTime value does
734 if (time64 > (uint64)(0xFFFFFFFF))
735 {
736 aOverFlow = true;
737 }
738 aDestVal = Oscl_Int64_Utils::get_uint64_lower32(time64);
739 }
740 }
741 break;
742
743 case PVMF_MEDIA_CLOCK_CLOCKUNIT_USEC:
744 {
745 // Determine the multiplier constant for the specified units
746 switch (aSrcUnits)
747 {
748 case PVMF_MEDIA_CLOCK_MSEC:
749 multconst = 1000;
750 break;
751
752 case PVMF_MEDIA_CLOCK_SEC:
753 multconst = 1000000;
754 break;
755
756 case PVMF_MEDIA_CLOCK_MIN:
757 multconst = 60000000;
758 break;
759
760 case PVMF_MEDIA_CLOCK_HOUR:
761 multconst = 0xD693A400;
762 break;
763
764 case PVMF_MEDIA_CLOCK_DAY:
765 {
766 uint64 temp = UINT64_HILO(0x14, 0x1DD76000);
767 multconst = Oscl_Int64_Utils::get_uint64_lower32(temp);
768 }
769 break;
770
771 case PVMF_MEDIA_CLOCK_USEC:
772 default:
773 break;
774 }
775
776 // Convert value to clock units
777 uint64 time64 = (uint64)(aSrcVal * multconst);
778 //There is a chance that Tickcount did not wrap around but aTime value does
779 if (time64 > (uint64)(0xFFFFFFFF))
780 {
781 aOverFlow = true;
782 }
783 aDestVal = Oscl_Int64_Utils::get_uint64_lower32(time64);
784 }
785 break;
786
787 default:
788 {
789 break;
790 }
791 }
792
793 }
794
FromClockUnit(uint32 & aClockUnitVal,uint32 & aDstVal,PVMFMediaClock_TimeUnits aDstUnits,bool & aOverflow)795 void PVMFMediaClock::FromClockUnit(uint32& aClockUnitVal, uint32& aDstVal,
796 PVMFMediaClock_TimeUnits aDstUnits, bool& aOverflow)
797 {
798
799 uint32 divconst = 1;
800
801 aOverflow = false;
802
803 switch (iClockUnit)
804 {
805 case PVMF_MEDIA_CLOCK_CLOCKUNIT_MSEC:
806 {
807 if (PVMF_MEDIA_CLOCK_USEC == aDstUnits)
808 {
809 //detect overflow;
810 uint64 time64 = (uint64)(aClockUnitVal * 1000);
811 if (time64 > (uint64)(0xFFFFFFFF))
812 {
813 aOverflow = true;
814 }
815 aDstVal = Oscl_Int64_Utils::get_uint64_lower32(time64);
816 }
817 else
818 {
819 // Determine the multiplier constant for the specified units
820 switch (aDstUnits)
821 {
822 case PVMF_MEDIA_CLOCK_SEC:
823 divconst = 1000;
824 break;
825
826 case PVMF_MEDIA_CLOCK_MIN:
827 divconst = 60000;
828 break;
829
830 case PVMF_MEDIA_CLOCK_HOUR:
831 divconst = 3600000;
832 break;
833
834 case PVMF_MEDIA_CLOCK_DAY:
835 divconst = 86400000;
836 break;
837
838 case PVMF_MEDIA_CLOCK_MSEC:
839 default:
840 break;
841 }
842
843 // Convert value to desired units
844 aDstVal = aClockUnitVal / divconst;
845 }
846 }
847 break;
848
849 case PVMF_MEDIA_CLOCK_CLOCKUNIT_USEC:
850 {
851 // Determine the multiplier constant for the specified units
852 switch (aDstUnits)
853 {
854 case PVMF_MEDIA_CLOCK_MSEC:
855 divconst = 1000;
856 break;
857
858 case PVMF_MEDIA_CLOCK_SEC:
859 divconst = 1000000;
860 break;
861
862 case PVMF_MEDIA_CLOCK_MIN:
863 divconst = 60000000;
864 break;
865
866 case PVMF_MEDIA_CLOCK_HOUR:
867 divconst = 0xD693A400;
868 break;
869
870 case PVMF_MEDIA_CLOCK_DAY:
871 {
872 uint64 temp = UINT64_HILO(0x14, 0x1DD76000);
873 divconst = Oscl_Int64_Utils::get_uint64_lower32(temp);
874 }
875 break;
876
877 case PVMF_MEDIA_CLOCK_USEC:
878 default:
879 break;
880 }
881 // Convert value to desired units
882 aDstVal = aClockUnitVal / divconst;
883
884 }
885 break;
886
887 default:
888 {
889 break;
890 }
891 }
892 }
893
ConvertTickcountToClockUnits(uint32 aTickcount,uint32 & aTimeValue,bool & aOverflowFlag)894 void PVMFMediaClock::ConvertTickcountToClockUnits(uint32 aTickcount, uint32& aTimeValue, bool& aOverflowFlag)
895 {
896 uint32 tbval = aTickcount;
897
898 aOverflowFlag = false;
899
900 //Convert tickCount value to msecs
901 uint32 usecPerTick = 0;
902 GetTimebaseResolution(usecPerTick);
903
904 if (usecPerTick)
905 {
906 tbval = tbval * (usecPerTick / 1000);
907 }
908 else /*timebase is not set*/
909 {
910 tbval = 0;
911 }
912
913 ToClockUnit(tbval, PVMF_MEDIA_CLOCK_MSEC, aTimeValue, aOverflowFlag);
914 }
ToUSec(uint32 & aSrcVal,PVMFMediaClock_TimeUnits aSrcUnits,uint32 & aUSecVal,bool & aOverFlow)915 void PVMFMediaClock::ToUSec(uint32& aSrcVal, PVMFMediaClock_TimeUnits aSrcUnits, uint32& aUSecVal, bool& aOverFlow)
916 {
917 uint32 multconst = 1;
918
919 aOverFlow = false;
920
921
922 // Determine the multiplier constant for the specified units
923 switch (aSrcUnits)
924 {
925 case PVMF_MEDIA_CLOCK_MSEC:
926 multconst = 1000;
927 break;
928
929 case PVMF_MEDIA_CLOCK_SEC:
930 multconst = 1000000;
931 break;
932
933 case PVMF_MEDIA_CLOCK_MIN:
934 multconst = 60000000;
935 break;
936
937 case PVMF_MEDIA_CLOCK_HOUR:
938 multconst = 0xD693A400;
939 break;
940
941 case PVMF_MEDIA_CLOCK_DAY:
942 {
943 uint64 temp = UINT64_HILO(0x14, 0x1DD76000);
944 multconst = Oscl_Int64_Utils::get_uint64_lower32(temp);
945 }
946 break;
947
948 case PVMF_MEDIA_CLOCK_USEC:
949 default:
950 break;
951 }
952
953 // Convert value to clock units
954 uint64 time64 = (uint64)(aSrcVal * multconst);
955 //There is a chance that Tickcount did not wrap around but aTime value does
956 if (time64 > (uint64)(0xFFFFFFFF))
957 {
958 aOverFlow = true;
959 }
960
961 aUSecVal = Oscl_Int64_Utils::get_uint64_lower32(time64);
962 }
963
AdjustClock(uint32 & aObsTime,uint32 & aObsTimebase,uint32 & aAdjTime,uint32 & aCurrentTime,uint32 & aCurrentTimebase)964 PVMFMediaClockAdjustTimeStatus PVMFMediaClock::AdjustClock(uint32& aObsTime, uint32& aObsTimebase, uint32& aAdjTime,
965 uint32& aCurrentTime, uint32& aCurrentTimebase)
966 {
967 // In this implementation, don't allow adjustments to be made with
968 // data older than when the last adjustment was made
969 uint32 temp = 0;
970 if (PVTimeComparisonUtils::IsEarlier(aObsTimebase, iAdjustmentTimebaseTime, temp) && (temp != 0))
971 {
972 return PVMF_MEDIA_CLOCK_ADJUST_ERR_INVALID_TIMEBASE_TIME;
973 }
974
975 // Make the adjustment
976 if (aAdjTime > aObsTime)
977 {
978 // Adjusted time is ahead so move ahead
979
980 // Save the observed timebase time of the adjusted time
981 iLastAdjustObsTimebaseTime = aObsTimebase;
982 UpdateLatestTimes(aAdjTime, aObsTimebase);
983
984 // Set the latest adjustment time as the current timebase time
985 iAdjustmentTimebaseTime = aCurrentTimebase;
986 }
987 else if (aAdjTime < aObsTime)
988 {
989 // Adjusted time is before the current time
990
991 // Save the observed timebase time of the adjusted time
992 iLastAdjustObsTimebaseTime = aObsTimebase;
993
994 // Set the latest clock time to the current clock time
995 // Set the latest timebase time to (current timebase time) + ((observed clock time) - (adjusted time))
996 uint32 offsettimebase = 0;
997 uint32 usecPerTick = 0;
998
999 GetTimebaseResolution(usecPerTick);
1000
1001 //calculate ticks in offsettbtime
1002 if (PVMF_MEDIA_CLOCK_CLOCKUNIT_MSEC == iClockUnit)
1003 {
1004 uint32 usecInOffset = (aObsTime - aAdjTime) * 1000;
1005
1006 //Calculate number of ticks
1007 offsettimebase = usecInOffset / usecPerTick;
1008 }
1009 else if (PVMF_MEDIA_CLOCK_CLOCKUNIT_USEC == iClockUnit)
1010 {
1011 offsettimebase = (aObsTime - aAdjTime) / usecPerTick;
1012 }
1013
1014 UpdateLatestTimes(aCurrentTime, aCurrentTimebase + offsettimebase);
1015 iAdjustmentTimebaseTime = aCurrentTimebase;
1016 }
1017 else
1018 {
1019 // Since there is no adjustment, do nothing
1020 }
1021
1022 //Start fresh scheduling
1023 AdjustScheduling();
1024
1025 ClockAdjusted();
1026 return PVMF_MEDIA_CLOCK_ADJUST_SUCCESS;
1027 }
1028
GetAdjustedRunningClockTime(uint32 & aDstTime,uint32 & aTimebaseVal)1029 void PVMFMediaClock::GetAdjustedRunningClockTime(uint32& aDstTime, uint32& aTimebaseVal)
1030 {
1031 uint32 delta = 0;
1032 // Current time is (latest clock time)+(current timebase time - latest timebase time)
1033 aDstTime = iLatestRunningClockTime;
1034
1035 // If backward adjustment occurs, iLatestRunningTimebaseTime might be greater than
1036 // the current value. To avoid negative values and clock going back, only
1037 // add the diff if current timebase value is greater. This makes the clock "freeze" until
1038 // the difference has elapsed
1039 if (PVTimeComparisonUtils::IsEarlier(iLatestRunningTimebaseTime, aTimebaseVal, delta) && (delta != 0))
1040 {
1041 //convert delta to clock units
1042 uint32 deltaTime = 0;
1043 bool overflowFlag = false;
1044 ConvertTickcountToClockUnits(delta, deltaTime, overflowFlag);
1045 aDstTime += deltaTime;
1046 }
1047 }
1048
ClockCountUpdated()1049 void PVMFMediaClock::ClockCountUpdated()
1050 {
1051 //Calling Run will fire any ready timers.
1052 Run();
1053
1054 //notify all observers that the clock count was updated.
1055 for (uint32 i = 0; i < iClockObservers.size(); i++)
1056 iClockObservers[i]->ClockCountUpdated();
1057 }
1058
ClockAdjusted()1059 void PVMFMediaClock::ClockAdjusted()
1060 {
1061 //notify all observers that the clock was adjusted
1062 for (uint32 i = 0; i < iClockObservers.size(); i++)
1063 iClockObservers[i]->ClockAdjusted();
1064 }
1065
ClockTimebaseUpdated()1066 void PVMFMediaClock::ClockTimebaseUpdated()
1067 {
1068 //notify all observers that the clock timebase was updated.
1069 for (uint32 i = 0; i < iClockObservers.size(); i++)
1070 {
1071 PVMFMediaClockObserver* obs = iClockObservers[i];
1072 obs->ClockTimebaseUpdated();
1073 }
1074 //reset timebase history.
1075 iLastAdjustObsTimebaseTime = 0;
1076 iAdjustmentTimebaseTime = 0;
1077 iStartTimebaseTickValue = 0;
1078 }
1079
SetCallbackCommon(uint32 aAbsoluteTime,uint32 aWindow,PVMFMediaClockNotificationsObs * aCallback,bool aThreadLock,const OsclAny * aContextData,uint32 & aCallBackID,const OsclAny * aInterfaceObject,uint32 aCurrentTime,bool aIsNPT)1080 PVMFStatus PVMFMediaClock::SetCallbackCommon(uint32 aAbsoluteTime,
1081 uint32 aWindow,
1082 PVMFMediaClockNotificationsObs* aCallback,
1083 bool aThreadLock,
1084 const OsclAny* aContextData,
1085 uint32& aCallBackID,
1086 const OsclAny* aInterfaceObject,
1087 uint32 aCurrentTime, bool aIsNPT)
1088 {
1089 uint32 delta = 0;
1090
1091 if (NULL == aCallback)
1092 {
1093 return PVMFErrArgument;
1094 }
1095
1096 //absolute time should be later than current time.
1097 //upper limit of 30 min for timer
1098
1099 if (!aIsNPT || (aIsNPT && !iIsNPTPlayBackDirectionBackwards))
1100 {
1101 if (PVTimeComparisonUtils::IsEarlier(aCurrentTime + MSECS_IN_30_MINS, aAbsoluteTime, delta) ||
1102 PVTimeComparisonUtils::IsEarlier(aAbsoluteTime, aCurrentTime, delta))
1103 {
1104 return PVMFErrArgument;
1105 }
1106 }
1107 else /*If this is NPT and clock direction is backwards. So, conditions will be opposite.*/
1108 {
1109 if (PVTimeComparisonUtils::IsEarlier(aAbsoluteTime, aCurrentTime + MSECS_IN_30_MINS, delta) ||
1110 PVTimeComparisonUtils::IsEarlier(aCurrentTime, aAbsoluteTime, delta))
1111 {
1112 return PVMFErrArgument;
1113 }
1114 }
1115
1116
1117 if (aThreadLock)
1118 iMutex->Lock();
1119
1120 aCallBackID = iTimerIDCount++;
1121 //insert the timer in the queue
1122 //
1123 PVMFMediaClockTimerQueueElement timerQueueElement;
1124
1125 timerQueueElement.contextData = aContextData;
1126 timerQueueElement.pInterfaceObject = aInterfaceObject;
1127 timerQueueElement.timeOut = aAbsoluteTime;
1128 timerQueueElement.callBackID = aCallBackID;
1129 timerQueueElement.isNPTTimer = aIsNPT;
1130 timerQueueElement.window = aWindow;
1131 timerQueueElement.obs = aCallback;
1132 if (!aIsNPT)
1133 {
1134 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
1135 (0, "PVMFMediaClock::SetCallbackCommon Setting regular callback for time %d at time %d",
1136 aAbsoluteTime, aCurrentTime));
1137
1138 iTimersPriQueue.push(timerQueueElement);
1139
1140 //Adjust scheduling if the element inserted is the topmost element
1141 if ((iTimersPriQueue.top()).callBackID == (iTimerIDCount - 1))
1142 {
1143 AdjustScheduling(false, aCurrentTime);
1144 }
1145 }
1146 else
1147 {
1148 if (!iIsNPTPlayBackDirectionBackwards)
1149 {
1150 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
1151 (0, "PVMFMediaClock::SetCallbackCommon Setting NPT callback for time %d at time %d",
1152 aAbsoluteTime, aCurrentTime));
1153
1154 iTimersPriQueueNPT.push(timerQueueElement);
1155 if ((iTimersPriQueueNPT.top()).callBackID == (iTimerIDCount - 1))
1156 {
1157 AdjustScheduling(true, aCurrentTime);
1158 }
1159 }
1160 else
1161 {
1162 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
1163 (0, "PVMFMediaClock::SetCallbackCommon Setting backwards NPT callback for time %d at time %d",
1164 aAbsoluteTime, aCurrentTime));
1165
1166 iTimersPriQueueNPTBackwards.push(timerQueueElement);
1167 if ((iTimersPriQueueNPT.top()).callBackID == (iTimerIDCount - 1))
1168 {
1169 AdjustScheduling(true, aCurrentTime);
1170 }
1171 }
1172
1173 }
1174 iActiveTimersCount++;
1175
1176 if (aThreadLock)
1177 iMutex->Unlock();
1178
1179 return PVMFSuccess;
1180 }
1181
SetCallbackAbsoluteTime(uint32 aAbsoluteTime,uint32 aWindow,PVMFMediaClockNotificationsObs * aCallback,bool aThreadLock,const OsclAny * aContextData,uint32 & aCallBackID,const OsclAny * aInterfaceObject)1182 PVMFStatus PVMFMediaClock::SetCallbackAbsoluteTime(
1183 uint32 aAbsoluteTime,
1184 uint32 aWindow,
1185 /*IN*/ PVMFMediaClockNotificationsObs* aCallback,
1186 /*IN*/ bool aThreadLock,
1187 /*IN*/ const OsclAny* aContextData,
1188 /*OUT*/ uint32& aCallBackID,
1189 /*IN*/ const OsclAny* aInterfaceObject
1190 )
1191 {
1192 uint32 currentTime = 0;
1193 bool overFlowFlag = false;
1194
1195 GetCurrentTime32(currentTime, overFlowFlag, PVMF_MEDIA_CLOCK_MSEC);
1196
1197 return SetCallbackCommon(aAbsoluteTime, aWindow, aCallback,
1198 aThreadLock, aContextData, aCallBackID, aInterfaceObject, currentTime, false);
1199
1200 }
1201
CalculateRunLTimerValue(bool aIsNPT,uint32 aCurrentTime,int32 & aDelta)1202 void PVMFMediaClock::CalculateRunLTimerValue(bool aIsNPT, uint32 aCurrentTime, int32& aDelta)
1203 {
1204 int32 nptDelta = 0;
1205 int32 delta = 0;
1206
1207 if (iTimersPriQueueNPT.size() ||
1208 iTimersPriQueueNPTBackwards.size())
1209 {
1210 uint32 temp = 0;
1211 GetNPTClockPosition(temp);
1212
1213 if (!iIsNPTPlayBackDirectionBackwards)
1214 {
1215 if (iTimersPriQueueNPT.size())
1216 {
1217 nptDelta = iTimersPriQueueNPT.top().timeOut - temp;
1218 }
1219 }
1220 else
1221 {
1222 if (iTimersPriQueueNPTBackwards.size())
1223 {
1224 nptDelta = temp - iTimersPriQueueNPT.top().timeOut;
1225 }
1226 }
1227
1228 if (!iTimersPriQueue.size())
1229 {
1230 aDelta = nptDelta;
1231 return;
1232 }
1233 }
1234
1235 if (iTimersPriQueue.size())
1236 {
1237 bool overFlowFlag = false;
1238
1239 uint32 currentTime = 0;
1240
1241 if (!aIsNPT)
1242 {
1243 currentTime = aCurrentTime;
1244 }
1245 else
1246 {
1247 GetCurrentTime32(currentTime, overFlowFlag, PVMF_MEDIA_CLOCK_MSEC);
1248 }
1249
1250
1251 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
1252 (0, "PVMFMediaClock::CalculateRunLTimerValue currtime %d top.timeOut %d", currentTime, iTimersPriQueue.top().timeOut));
1253
1254 delta = iTimersPriQueue.top().timeOut - currentTime;
1255
1256 if (!iTimersPriQueueNPT.size()
1257 && !iTimersPriQueueNPTBackwards.size())
1258 {
1259 aDelta = delta;
1260 return;
1261 }
1262 }
1263
1264 aDelta = delta < nptDelta ? delta : nptDelta;
1265 }
1266
AdjustScheduling(bool aIsNPT,uint32 aCurrentTime)1267 void PVMFMediaClock::AdjustScheduling(bool aIsNPT, uint32 aCurrentTime)
1268 {
1269
1270 //If timebase is count-based, no need for scheduling.
1271 if (iIsTimebaseCountBased)
1272 {
1273 return;
1274 }
1275 //Make sure current thread context is same on which AddToScheduler() was called
1276
1277 TOsclThreadId tempThreadID;
1278 OsclThread::GetId(tempThreadID);
1279
1280 if (!OsclThread::CompareId(tempThreadID, iOrigThreadID))
1281 {
1282 OsclError::Leave(OsclErrThreadContextIncorrect);
1283 }
1284
1285 uint32 currentTime = 0;
1286 bool overFlowFlag = false;
1287
1288 // A fresh RunIfInactive() will be called
1289 Cancel();
1290
1291 //get current time if argument aCurrentTime is 0
1292 if (!aIsNPT)
1293 {
1294 if (aCurrentTime)
1295 {
1296 currentTime = aCurrentTime;
1297 }
1298 else
1299 {
1300 GetCurrentTime32(currentTime, overFlowFlag, PVMF_MEDIA_CLOCK_MSEC);
1301 }
1302 }
1303 else
1304 {
1305 aCurrentTime ? currentTime = aCurrentTime : GetNPTClockPosition(currentTime);
1306 }
1307
1308 int32 deltaTime = 1;
1309
1310 //if queues are empty, no need to schedule
1311 if (iTimersPriQueue.size() != 0 ||
1312 iTimersPriQueueNPT.size() != 0 ||
1313 iTimersPriQueueNPTBackwards.size() != 0)
1314 {
1315 CalculateRunLTimerValue(aIsNPT, currentTime, deltaTime);
1316 if (deltaTime >= 0)
1317 {
1318 //Adjust for rate
1319 if ((iClockTimebase != NULL) && (iClockTimebase->GetRate() != 0)
1320 && (REALTIME_PLAYBACK_RATE != iClockTimebase->GetRate()))
1321 {
1322 //Support rate upto 0.1 resolution
1323 uint32 convNumerator = 10;
1324 uint32 conversionNumber =
1325 (iClockTimebase->GetRate() * convNumerator) / REALTIME_PLAYBACK_RATE;
1326
1327 if (conversionNumber != 0)
1328 {
1329 deltaTime = (deltaTime * convNumerator) / conversionNumber ;
1330 }
1331 else
1332 {
1333 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
1334 (0, "PVMFMediaClock::AdjustScheduling ERROR: Timebase rate corrupted"));
1335 }
1336 }
1337
1338 RunIfNotReady((uint32)deltaTime*1000);
1339
1340 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
1341 (0, "PVMFMediaClock::AdjustScheduling Timer set for %d msecs wall clock time", deltaTime));
1342 }
1343 else
1344 {
1345 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
1346 (0, "PVMFMediaClock::AdjustScheduling Late callback detected", deltaTime));
1347 //this means callback is already late. fire asap
1348 RunIfNotReady(0);
1349 }
1350 }
1351 }
1352
SetCallbackDeltaTime(uint32 aDeltaTime,uint32 aWindow,PVMFMediaClockNotificationsObs * aCallback,bool aThreadLock,const OsclAny * aContextData,uint32 & aCallBackID,const OsclAny * aInterfaceObject)1353 PVMFStatus PVMFMediaClock::SetCallbackDeltaTime(
1354 /*IN*/ uint32 aDeltaTime,
1355 /*IN*/ uint32 aWindow,
1356 /*IN*/ PVMFMediaClockNotificationsObs* aCallback,
1357 /*IN*/ bool aThreadLock,
1358 /*IN*/ const OsclAny* aContextData,
1359 /*OUT*/ uint32& aCallBackID,
1360 /*IN*/ const OsclAny* aInterfaceObject)
1361 {
1362 uint32 currentTime = 0;
1363 bool overFlowFlag = false;
1364
1365 GetCurrentTime32(currentTime, overFlowFlag, PVMF_MEDIA_CLOCK_MSEC);
1366
1367 return SetCallbackCommon(currentTime + aDeltaTime, aWindow, aCallback,
1368 aThreadLock, aContextData, aCallBackID, aInterfaceObject, currentTime, false);
1369 }
1370
CommonCancelCallback(uint32 aCallbackID,bool aThreadLock,bool aIsNPT)1371 PVMFStatus PVMFMediaClock::CommonCancelCallback(uint32 aCallbackID, bool aThreadLock, bool aIsNPT)
1372 {
1373 bool flag = 0;
1374 int elementRemoved = 0;
1375 PVMFStatus retVal;
1376
1377 if (aThreadLock)
1378 iMutex->Lock();
1379
1380 if (!aIsNPT)
1381 {
1382 if (!iTimersPriQueue.empty())
1383 {
1384 if ((iTimersPriQueue.top()).callBackID == (aCallbackID))
1385 {
1386 flag = 1;
1387 }
1388
1389 //Remove element from queue by ID
1390 PVMFMediaClockTimerQueueElement timerQueueElement;
1391 timerQueueElement.callBackID = aCallbackID;
1392
1393 elementRemoved = iTimersPriQueue.remove(timerQueueElement);
1394
1395 if (elementRemoved && flag)
1396 {
1397 AdjustScheduling();
1398 }
1399 }
1400 }
1401 else
1402 {
1403 if (!iIsNPTPlayBackDirectionBackwards)
1404 {
1405 if (!iTimersPriQueueNPT.empty())
1406 {
1407 if ((iTimersPriQueueNPT.top()).callBackID == (aCallbackID))
1408 {
1409 flag = 1;
1410 }
1411
1412 //Remove element from queue by ID
1413 PVMFMediaClockTimerQueueElement timerQueueElement;
1414 timerQueueElement.callBackID = aCallbackID;
1415
1416 elementRemoved = iTimersPriQueueNPT.remove(timerQueueElement);
1417 }
1418 }
1419 else
1420 {
1421 if (!iTimersPriQueueNPTBackwards.empty())
1422 {
1423 if ((iTimersPriQueueNPTBackwards.top()).callBackID == (aCallbackID))
1424 {
1425 flag = 1;
1426 }
1427
1428 //Remove element from queue by ID
1429 PVMFMediaClockTimerQueueElement timerQueueElement;
1430 timerQueueElement.callBackID = aCallbackID;
1431
1432 elementRemoved = iTimersPriQueueNPTBackwards.remove(timerQueueElement);
1433 }
1434 }
1435
1436 if (elementRemoved && flag)
1437 {
1438 /*When scheduling is for NPT, make sure to pass isNPT flag i.e. 'true' */
1439 AdjustScheduling(true);
1440 }
1441
1442 }
1443
1444 if (elementRemoved)
1445 {
1446 iActiveTimersCount--;
1447 retVal = PVMFSuccess;
1448 }
1449 else
1450 {
1451 retVal = PVMFErrBadHandle;
1452 }
1453 if (aThreadLock)
1454 iMutex->Unlock();
1455
1456 return retVal;
1457 }
1458
CancelCallback(uint32 aCallbackID,bool aThreadLock)1459 PVMFStatus PVMFMediaClock::CancelCallback(
1460 /*IN*/ uint32 aCallbackID, bool aThreadLock)
1461 {
1462 return CommonCancelCallback(aCallbackID, aThreadLock, false);
1463 }
1464
SetNPTCallbackAbsoluteTime(uint32 aAbsoluteTime,uint32 aWindow,PVMFMediaClockNotificationsObs * aCallback,bool aThreadLock,const OsclAny * aContextData,uint32 & aCallBackID,const OsclAny * aInterfaceObject)1465 PVMFStatus PVMFMediaClock::SetNPTCallbackAbsoluteTime(
1466 /*IN*/ uint32 aAbsoluteTime,
1467 /*IN*/ uint32 aWindow,
1468 /*IN*/ PVMFMediaClockNotificationsObs* aCallback,
1469 /*IN*/ bool aThreadLock,
1470 /*IN*/ const OsclAny* aContextData,
1471 /*OUT*/ uint32& aCallBackID,
1472 /*IN*/ const OsclAny* aInterfaceObject)
1473 {
1474
1475 uint32 currentTime = 0;
1476
1477 GetNPTClockPosition(currentTime);
1478
1479 return SetCallbackCommon(aAbsoluteTime, aWindow, aCallback,
1480 aThreadLock, aContextData, aCallBackID, aInterfaceObject, currentTime, true);
1481
1482 }
1483
SetNPTCallbackDeltaTime(uint32 aDeltaTime,uint32 aWindow,PVMFMediaClockNotificationsObs * aCallback,bool aThreadLock,const OsclAny * aContextData,uint32 & aCallBackID,const OsclAny * aInterfaceObject)1484 PVMFStatus PVMFMediaClock::SetNPTCallbackDeltaTime(
1485 /*IN*/ uint32 aDeltaTime,
1486 /*IN*/ uint32 aWindow,
1487 /*IN*/ PVMFMediaClockNotificationsObs* aCallback,
1488 /*IN*/ bool aThreadLock,
1489 /*IN*/ const OsclAny* aContextData,
1490 /*OUT*/ uint32& aCallBackID,
1491 /*IN*/ const OsclAny* aInterfaceObject)
1492 {
1493 uint32 currentTime = 0;
1494
1495 GetNPTClockPosition(currentTime);
1496
1497 return SetCallbackCommon(currentTime + aDeltaTime, aWindow, aCallback,
1498 aThreadLock, aContextData, aCallBackID, aInterfaceObject, currentTime, true);
1499
1500 }
1501
CancelNPTCallback(uint32 aCallbackID,bool aThreadLock)1502 PVMFStatus PVMFMediaClock::CancelNPTCallback(
1503 /*IN*/ uint32 aCallbackID, bool aThreadLock)
1504 {
1505 return CommonCancelCallback(aCallbackID, aThreadLock, true);
1506 }
1507
ClearAllQueues()1508 void PVMFMediaClock::ClearAllQueues()
1509 {
1510 PVMFMediaClockTimerQueueElement topTimerElement;
1511
1512 while (iTimersPriQueue.size() != 0)
1513 {
1514 topTimerElement = iTimersPriQueue.top();
1515 iTimersPriQueue.pop();
1516 iActiveTimersCount--;
1517 topTimerElement.obs->ProcessCallBack(topTimerElement.callBackID,
1518 PVTimeComparisonUtils::MEDIA_EARLY_OUTSIDE_WINDOW, 0,
1519 topTimerElement.contextData, PVMFErrCallbackClockStopped);
1520 }
1521
1522 if (!iIsNPTPlayBackDirectionBackwards)
1523 {
1524 while (iTimersPriQueueNPT.size() != 0)
1525 {
1526 topTimerElement = iTimersPriQueueNPT.top();
1527 iTimersPriQueueNPT.pop();
1528 iActiveTimersCount--;
1529 topTimerElement.obs->ProcessCallBack(topTimerElement.callBackID,
1530 PVTimeComparisonUtils::MEDIA_EARLY_OUTSIDE_WINDOW, 0,
1531 topTimerElement.contextData, PVMFErrCallbackClockStopped);
1532 }
1533 }
1534 else
1535 {
1536 while (iTimersPriQueueNPTBackwards.size() != 0)
1537 {
1538 topTimerElement = iTimersPriQueueNPTBackwards.top();
1539 iTimersPriQueueNPTBackwards.pop();
1540 iActiveTimersCount--;
1541 topTimerElement.obs->ProcessCallBack(topTimerElement.callBackID,
1542 PVTimeComparisonUtils::MEDIA_EARLY_OUTSIDE_WINDOW, 0,
1543 topTimerElement.contextData, PVMFErrCallbackClockStopped);
1544 }
1545 }
1546
1547 }
1548
ClearPresentNPTQueue()1549 void PVMFMediaClock::ClearPresentNPTQueue()
1550 {
1551 PVMFMediaClockTimerQueueElement topTimerElement;
1552
1553 if (!iIsNPTPlayBackDirectionBackwards)
1554 {
1555 while (iTimersPriQueueNPT.size() != 0)
1556 {
1557 topTimerElement = iTimersPriQueueNPT.top();
1558 iTimersPriQueueNPT.pop();
1559 iActiveTimersCount--;
1560 topTimerElement.obs->ProcessCallBack(topTimerElement.callBackID,
1561 PVTimeComparisonUtils::MEDIA_EARLY_OUTSIDE_WINDOW, 0,
1562 topTimerElement.contextData, PVMFErrCallbackHasBecomeInvalid);
1563 }
1564 }
1565 else
1566 {
1567 while (iTimersPriQueueNPTBackwards.size() != 0)
1568 {
1569 topTimerElement = iTimersPriQueueNPTBackwards.top();
1570 iTimersPriQueueNPTBackwards.pop();
1571 iActiveTimersCount--;
1572 topTimerElement.obs->ProcessCallBack(topTimerElement.callBackID,
1573 PVTimeComparisonUtils::MEDIA_EARLY_OUTSIDE_WINDOW, 0,
1574 topTimerElement.contextData, PVMFErrCallbackHasBecomeInvalid);
1575 }
1576 }
1577 }
1578
UpdateNPTClockPosition(uint32 aStartNPT,bool aIsPlayBackDirectionBackwards)1579 void PVMFMediaClock::UpdateNPTClockPosition(
1580 /*IN*/ uint32 aStartNPT,
1581 /*IN*/ bool aIsPlayBackDirectionBackwards)
1582 {
1583 bool overflow = false;
1584
1585 iStartNPT = aStartNPT;
1586
1587 GetCurrentTime32(iStartMediaClockTS, overflow, PVMF_MEDIA_CLOCK_MSEC);
1588
1589 if (iIsNPTPlayBackDirectionBackwards != aIsPlayBackDirectionBackwards)
1590 {
1591 //NPT clock direction has changed. So invalidate all existing timers
1592 ClearPresentNPTQueue();
1593 }
1594
1595 iIsNPTPlayBackDirectionBackwards = aIsPlayBackDirectionBackwards;
1596
1597 /*reschedule. Send argument as true so that this function knows that
1598 scheduling is being done for NPT.*/
1599 AdjustScheduling(true);
1600 }
1601
GetNPTClockPosition(uint32 & aCurrentPosition)1602 PVMFStatus PVMFMediaClock::GetNPTClockPosition(
1603 /*OUT*/ uint32& aCurrentPosition)
1604 {
1605 uint32 currentTime = 0;
1606 bool overflow = false;
1607
1608 GetCurrentTime32(currentTime, overflow, PVMF_MEDIA_CLOCK_MSEC);
1609
1610 if (overflow)
1611 {
1612 return PVMFErrOverflow;
1613 }
1614
1615 if (iIsNPTPlayBackDirectionBackwards)
1616 {
1617 aCurrentPosition = iStartNPT - (currentTime - iStartMediaClockTS);
1618 }
1619 else
1620 {
1621 aCurrentPosition = iStartNPT + (currentTime - iStartMediaClockTS);
1622 }
1623 return PVMFSuccess;
1624 }
1625
ClearNPTClockPosition()1626 void PVMFMediaClock::ClearNPTClockPosition()
1627 {
1628 iStartNPT = 0;
1629 iStartMediaClockTS = 0;
1630 iIsNPTPlayBackDirectionBackwards = 0;
1631 }
1632
QueueClockStartNotificationEvent(uint32 aDelta,PVMFMediaClockStateObserver * aClockStateObserver)1633 void PVMFMediaClock::QueueClockStartNotificationEvent(uint32 aDelta, PVMFMediaClockStateObserver *aClockStateObserver)
1634 {
1635 PVMFMediaClockStartNotificationEventElement element;
1636 uint32 queuedEventID;
1637 PVMFStatus status = PVMFFailure;
1638
1639 element.clockStateObserver = aClockStateObserver;
1640
1641 //Set a callback on the clock to set this event
1642 status = SetCallbackDeltaTime(aDelta, 0, (PVMFMediaClockNotificationsObs*)this, false,
1643 &iClockStartNotificationEventQueue, queuedEventID, this);
1644
1645 element.eventID = queuedEventID;
1646 if (PVMFSuccess == status)
1647 {
1648 iClockStartNotificationEventQueue.push_back(element);
1649 }
1650
1651 }
1652
QueueNPTClockTransitionEvent(uint32 aMediaClockPosition,uint32 aStartNPT,bool aIsPlayBackDirectionBackwards,uint32 aWindow,uint32 & aClockTransitionID)1653 PVMFStatus PVMFMediaClock::QueueNPTClockTransitionEvent(uint32 aMediaClockPosition, uint32 aStartNPT,
1654 bool aIsPlayBackDirectionBackwards, uint32 aWindow, uint32& aClockTransitionID)
1655 {
1656 PVMFMediaClockNPTTransitionEventElement element;
1657 PVMFStatus status = PVMFFailure;
1658
1659 element.isPlayBackDirectionBackwards = aIsPlayBackDirectionBackwards;
1660 element.mediaClockPosition = aMediaClockPosition;
1661 element.startNPT = aStartNPT;
1662 element.window = aWindow;
1663
1664 //Set a callback on the clock to set this event
1665 status = SetCallbackAbsoluteTime(element.mediaClockPosition, element.window, (PVMFMediaClockNotificationsObs*)this, false,
1666 &iNPTTransitionEventQueue, aClockTransitionID, this);
1667
1668 element.eventID = aClockTransitionID;
1669 if (PVMFSuccess == status)
1670 {
1671 iNPTTransitionEventQueue.push_back(element);
1672 }
1673
1674 return status;
1675 }
1676
CancelNPTClockTransitionEvent(uint32 aClockTransitionEventID)1677 PVMFStatus PVMFMediaClock::CancelNPTClockTransitionEvent(uint32 aClockTransitionEventID)
1678 {
1679 PVMFStatus status;
1680
1681 status = CancelCallback(aClockTransitionEventID, false);
1682
1683 if (PVMFSuccess != status)
1684 {
1685 return status;
1686 }
1687
1688 for (uint32 ii = 0; ii < iNPTTransitionEventQueue.size(); ii++)
1689 {
1690 if (iNPTTransitionEventQueue[ii].eventID == aClockTransitionEventID)
1691 iNPTTransitionEventQueue.erase(&iNPTTransitionEventQueue[ii]);
1692 }
1693 return PVMFSuccess;
1694 }
1695
ProcessCallBack(uint32 aCallBackID,PVTimeComparisonUtils::MediaTimeStatus aTimerAccuracy,uint32 delta,const OsclAny * aContextData,PVMFStatus aStatus)1696 void PVMFMediaClock::ProcessCallBack(uint32 aCallBackID, PVTimeComparisonUtils::MediaTimeStatus aTimerAccuracy, uint32 delta,
1697 const OsclAny* aContextData, PVMFStatus aStatus)
1698 {
1699
1700 OSCL_UNUSED_ARG(aTimerAccuracy);
1701 OSCL_UNUSED_ARG(delta);
1702 if (aStatus != PVMFSuccess)
1703 {
1704 /*This means the clock was stopped*/
1705 return;
1706 }
1707
1708 //if event is NPT transition
1709 if (aContextData == (void*)&iNPTTransitionEventQueue)
1710 {
1711 for (uint32 ii = 0; ii < iNPTTransitionEventQueue.size(); ii++)
1712 {
1713 if (iNPTTransitionEventQueue[ii].eventID == aCallBackID)
1714 {
1715 UpdateNPTClockPosition(iNPTTransitionEventQueue[ii].startNPT,
1716 iNPTTransitionEventQueue[ii].isPlayBackDirectionBackwards);
1717
1718 iNPTTransitionEventQueue.erase(&iNPTTransitionEventQueue[ii]);
1719 }
1720 }
1721 }
1722 //if event is clock-start notification
1723 else if (aContextData == (void*)&iClockStartNotificationEventQueue)
1724 {
1725 for (uint32 ii = 0; ii < iClockStartNotificationEventQueue.size(); ii++)
1726 {
1727 if (iClockStartNotificationEventQueue[ii].eventID == aCallBackID)
1728 {
1729 (iClockStartNotificationEventQueue[ii].clockStateObserver)->ClockStateUpdated();
1730 iClockStartNotificationEventQueue.erase(&iClockStartNotificationEventQueue[ii]);
1731 }
1732 }
1733 }
1734
1735 }
1736
NotificationsInterfaceDestroyed()1737 void PVMFMediaClock::NotificationsInterfaceDestroyed()
1738 {
1739 //do nothing
1740 }
1741
Run()1742 void PVMFMediaClock::Run()
1743 {
1744 uint32 currentTime = 0;
1745 bool overFlowFlag = false;
1746 uint32 delta = 0;
1747
1748 PVMFMediaClockTimerQueueElement topTimerElement;
1749 PVTimeComparisonUtils::MediaTimeStatus status;
1750
1751 /*Caution: Both loops below should always be similar. Any update needed for regular callback handling
1752 loop should also be checked for NPT loop ..and vice versa*/
1753
1754 if (iTimersPriQueue.size())
1755 {
1756 topTimerElement = iTimersPriQueue.top();
1757
1758 GetCurrentTime32(currentTime, overFlowFlag, PVMF_MEDIA_CLOCK_MSEC);
1759
1760 status = PVTimeComparisonUtils::CheckTimeWindow(topTimerElement.timeOut, currentTime, topTimerElement.window,
1761 topTimerElement.window, delta);
1762
1763 while (iTimersPriQueue.size() &&
1764 status != PVTimeComparisonUtils::MEDIA_EARLY_OUTSIDE_WINDOW)
1765 {
1766 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
1767 (0, "PVMFMediaClock::Run Timer for regular callback currentTime - %d callbackTime - %d callbackMargin - %d queue size - %d status - %d", currentTime,
1768 topTimerElement.timeOut, topTimerElement.window, iTimersPriQueue.size(), status));
1769
1770 switch (status)
1771 {
1772 case PVTimeComparisonUtils::MEDIA_EARLY_WITHIN_WINDOW:
1773 case PVTimeComparisonUtils::MEDIA_ONTIME_WITHIN_WINDOW:
1774 case PVTimeComparisonUtils::MEDIA_LATE_WITHIN_WINDOW:
1775 case PVTimeComparisonUtils::MEDIA_LATE_OUTSIDE_WINDOW:
1776 {
1777 iTimersPriQueue.pop();
1778 iActiveTimersCount--;
1779 topTimerElement.obs->ProcessCallBack(topTimerElement.callBackID, status, delta,
1780 topTimerElement.contextData, PVMFSuccess);
1781 }
1782 break;
1783
1784 case PVTimeComparisonUtils::MEDIA_EARLY_OUTSIDE_WINDOW:
1785 //If callback is early, just schedule fresh
1786 break;
1787
1788 default:
1789 {
1790 //@@error
1791 }
1792 }
1793
1794 //check if more timers fall within the window.
1795 topTimerElement = iTimersPriQueue.top();
1796
1797 GetCurrentTime32(currentTime, overFlowFlag, PVMF_MEDIA_CLOCK_MSEC);
1798
1799 status = PVTimeComparisonUtils::CheckTimeWindow(topTimerElement.timeOut, currentTime, topTimerElement.window,
1800 topTimerElement.window, delta);
1801 }
1802
1803 AdjustScheduling(false, currentTime);
1804 }
1805
1806 // Check NPT timers now
1807
1808 //normal NPT clock
1809 if (!iIsNPTPlayBackDirectionBackwards)
1810 {
1811 if (iTimersPriQueueNPT.size())
1812 {
1813 topTimerElement = iTimersPriQueueNPT.top();
1814
1815 GetNPTClockPosition(currentTime);
1816
1817 status = PVTimeComparisonUtils::CheckTimeWindow(topTimerElement.timeOut, currentTime, topTimerElement.window,
1818 topTimerElement.window, delta);
1819
1820 while (iTimersPriQueueNPT.size() &&
1821 status != PVTimeComparisonUtils::MEDIA_EARLY_OUTSIDE_WINDOW)
1822 {
1823 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
1824 (0, "PVMFMediaClock::Run Timer for NPT callback currentTime - %d callbackTime - %d callbackMargin - %d queue size - %d status - %d", currentTime,
1825 topTimerElement.timeOut, topTimerElement.window, iTimersPriQueueNPT.size(), status));
1826
1827 switch (status)
1828 {
1829 case PVTimeComparisonUtils::MEDIA_EARLY_WITHIN_WINDOW:
1830 case PVTimeComparisonUtils::MEDIA_ONTIME_WITHIN_WINDOW:
1831 case PVTimeComparisonUtils::MEDIA_LATE_WITHIN_WINDOW:
1832 case PVTimeComparisonUtils::MEDIA_LATE_OUTSIDE_WINDOW:
1833 {
1834 iTimersPriQueueNPT.pop();
1835 iActiveTimersCount--;
1836 topTimerElement.obs->ProcessCallBack(topTimerElement.callBackID, status, delta,
1837 topTimerElement.contextData, PVMFSuccess);
1838 }
1839 break;
1840
1841 case PVTimeComparisonUtils::MEDIA_EARLY_OUTSIDE_WINDOW:
1842 //If callback is early, just schedule fresh
1843 break;
1844
1845 default:
1846 {
1847 //@@error
1848 }
1849 }
1850
1851 //check if more timers fall within the window.
1852 topTimerElement = iTimersPriQueueNPT.top();
1853
1854 GetNPTClockPosition(currentTime);
1855
1856 status = PVTimeComparisonUtils::CheckTimeWindow(topTimerElement.timeOut, currentTime, topTimerElement.window,
1857 topTimerElement.window, delta);
1858 }
1859
1860 AdjustScheduling(true, currentTime);
1861 }
1862 }
1863 else /*When direction of NPT clock is backwards. Just use the other queue and reverse calculations*/
1864 {
1865 if (iTimersPriQueueNPTBackwards.size())
1866 {
1867 topTimerElement = iTimersPriQueueNPTBackwards.top();
1868
1869 GetNPTClockPosition(currentTime);
1870
1871 status = PVTimeComparisonUtils::CheckTimeWindow(topTimerElement.timeOut, currentTime, topTimerElement.window,
1872 topTimerElement.window, delta);
1873
1874 while (iTimersPriQueueNPTBackwards.size() &&
1875 status != PVTimeComparisonUtils::MEDIA_LATE_OUTSIDE_WINDOW)
1876 {
1877 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
1878 (0, "PVMFMediaClock::Run Timer for Backwards NPT callback currentTime - %d callbackTime - %d callbackMargin - %d queue size - %d status - %d", currentTime,
1879 topTimerElement.timeOut, topTimerElement.window, iTimersPriQueueNPTBackwards.size(), status));
1880
1881 switch (status)
1882 {
1883 case PVTimeComparisonUtils::MEDIA_EARLY_WITHIN_WINDOW:
1884 {
1885 iTimersPriQueueNPT.pop();
1886 iActiveTimersCount--;
1887 topTimerElement.obs->ProcessCallBack(topTimerElement.callBackID, PVTimeComparisonUtils::MEDIA_LATE_WITHIN_WINDOW, delta,
1888 topTimerElement.contextData, PVMFSuccess);
1889 }
1890 break;
1891
1892 case PVTimeComparisonUtils::MEDIA_ONTIME_WITHIN_WINDOW:
1893 case PVTimeComparisonUtils::MEDIA_LATE_WITHIN_WINDOW:
1894 {
1895 iTimersPriQueueNPT.pop();
1896 iActiveTimersCount--;
1897 topTimerElement.obs->ProcessCallBack(topTimerElement.callBackID, PVTimeComparisonUtils::MEDIA_EARLY_WITHIN_WINDOW, delta,
1898 topTimerElement.contextData, PVMFSuccess);
1899 }
1900 break;
1901 case PVTimeComparisonUtils::MEDIA_EARLY_OUTSIDE_WINDOW:
1902 {
1903 iTimersPriQueueNPT.pop();
1904 iActiveTimersCount--;
1905 topTimerElement.obs->ProcessCallBack(topTimerElement.callBackID, PVTimeComparisonUtils::MEDIA_LATE_OUTSIDE_WINDOW, delta,
1906 topTimerElement.contextData, PVMFSuccess);
1907 }
1908 break;
1909
1910 default:
1911 {
1912 //@@error
1913 }
1914 }
1915
1916 //check if more timers fall within the window.
1917 topTimerElement = iTimersPriQueueNPTBackwards.top();
1918
1919 GetNPTClockPosition(currentTime);
1920
1921 status = PVTimeComparisonUtils::CheckTimeWindow(topTimerElement.timeOut, currentTime, topTimerElement.window,
1922 topTimerElement.window, delta);
1923 }
1924
1925 AdjustScheduling(true, currentTime);
1926 }
1927 }
1928 }
1929
PVMFMediaClockNotificationsInterfaceImpl(PVMFMediaClock * aClock,uint32 aLatency,PVMFMediaClockNotificationsObsBase & aNotificationInterfaceDestroyedCallback)1930 OSCL_EXPORT_REF PVMFMediaClockNotificationsInterfaceImpl::PVMFMediaClockNotificationsInterfaceImpl(PVMFMediaClock *aClock,
1931 uint32 aLatency,
1932 PVMFMediaClockNotificationsObsBase& aNotificationInterfaceDestroyedCallback)
1933 {
1934 iContainer = aClock;
1935 iLatency = aLatency;
1936 iNotificationInterfaceDestroyedCallback = &aNotificationInterfaceDestroyedCallback;
1937 iAdjustedLatency = 0;
1938 iClockStateObserver = NULL;
1939 iLatencyDelayForClockStartNotification = 0;
1940 }
1941
~PVMFMediaClockNotificationsInterfaceImpl()1942 OSCL_EXPORT_REF PVMFMediaClockNotificationsInterfaceImpl::~PVMFMediaClockNotificationsInterfaceImpl()
1943 {
1944 //check if vectors need to be destroyed
1945 }
1946
SetCallbackAbsoluteTime(uint32 aAbsoluteTime,uint32 aWindow,PVMFMediaClockNotificationsObs * aCallback,bool aThreadLock,const OsclAny * aContextData,uint32 & aCallBackID)1947 OSCL_EXPORT_REF PVMFStatus PVMFMediaClockNotificationsInterfaceImpl::SetCallbackAbsoluteTime(
1948 /*IN*/ uint32 aAbsoluteTime,
1949 /*IN*/ uint32 aWindow,
1950 /*IN*/ PVMFMediaClockNotificationsObs* aCallback,
1951 /*IN*/ bool aThreadLock,
1952 /*IN*/ const OsclAny* aContextData,
1953 /*OUT*/ uint32& aCallBackID)
1954 {
1955 if (iContainer)
1956 {
1957 return iContainer->SetCallbackAbsoluteTime(aAbsoluteTime - iAdjustedLatency, aWindow, aCallback, aThreadLock, aContextData,
1958 aCallBackID, this);
1959 }
1960 else
1961 {
1962 return PVMFFailure;
1963 }
1964 }
1965
SetCallbackDeltaTime(uint32 aDeltaTime,uint32 aWindow,PVMFMediaClockNotificationsObs * aCallback,bool aThreadLock,const OsclAny * aContextData,uint32 & aCallBackID)1966 OSCL_EXPORT_REF PVMFStatus PVMFMediaClockNotificationsInterfaceImpl::SetCallbackDeltaTime(
1967 /*IN*/ uint32 aDeltaTime,
1968 /*IN*/ uint32 aWindow,
1969 /*IN*/ PVMFMediaClockNotificationsObs* aCallback,
1970 /*IN*/ bool aThreadLock,
1971 /*IN*/ const OsclAny* aContextData,
1972 /*OUT*/ uint32& aCallBackID)
1973 {
1974 if (iContainer)
1975 {
1976 return iContainer->SetCallbackDeltaTime(aDeltaTime - iAdjustedLatency, aWindow, aCallback, aThreadLock, aContextData,
1977 aCallBackID, this);
1978 }
1979 else
1980 {
1981 return PVMFFailure;
1982 }
1983 }
1984
CancelCallback(uint32 aCallbackID,bool aThreadLock)1985 OSCL_EXPORT_REF PVMFStatus PVMFMediaClockNotificationsInterfaceImpl::CancelCallback(
1986 /*IN*/ uint32 aCallbackID, bool aThreadLock)
1987 {
1988 if (iContainer)
1989 {
1990 return iContainer->CancelCallback(aCallbackID, aThreadLock);
1991 }
1992 else
1993 {
1994 return PVMFFailure;
1995 }
1996 }
1997
SetNPTCallbackAbsoluteTime(uint32 aAbsoluteTime,uint32 aWindow,PVMFMediaClockNotificationsObs * aCallback,bool aThreadLock,const OsclAny * aContextData,uint32 & aCallBackID)1998 OSCL_EXPORT_REF PVMFStatus PVMFMediaClockNotificationsInterfaceImpl::SetNPTCallbackAbsoluteTime(
1999 /*IN*/ uint32 aAbsoluteTime,
2000 /*IN*/ uint32 aWindow,
2001 /*IN*/ PVMFMediaClockNotificationsObs* aCallback,
2002 /*IN*/ bool aThreadLock,
2003 /*IN*/ const OsclAny* aContextData,
2004 /*OUT*/ uint32& aCallBackID)
2005 {
2006 if (iContainer)
2007 {
2008 return iContainer->SetNPTCallbackAbsoluteTime(aAbsoluteTime - iAdjustedLatency, aWindow, aCallback, aThreadLock, aContextData,
2009 aCallBackID, this);
2010 }
2011 else
2012 {
2013 return PVMFFailure;
2014 }
2015 }
2016
SetNPTCallbackDeltaTime(uint32 aDeltaTime,uint32 aWindow,PVMFMediaClockNotificationsObs * aCallback,bool aThreadLock,const OsclAny * aContextData,uint32 & aCallBackID)2017 OSCL_EXPORT_REF PVMFStatus PVMFMediaClockNotificationsInterfaceImpl::SetNPTCallbackDeltaTime(
2018 /*IN*/ uint32 aDeltaTime,
2019 /*IN*/ uint32 aWindow,
2020 /*IN*/ PVMFMediaClockNotificationsObs* aCallback,
2021 /*IN*/ bool aThreadLock,
2022 /*IN*/ const OsclAny* aContextData,
2023 /*OUT*/ uint32& aCallBackID)
2024 {
2025 if (iContainer)
2026 {
2027 return iContainer->SetNPTCallbackDeltaTime(aDeltaTime - iAdjustedLatency, aWindow, aCallback, aThreadLock, aContextData,
2028 aCallBackID, this);
2029 }
2030 else
2031 {
2032 return PVMFFailure;
2033 }
2034 }
2035
CancelNPTCallback(uint32 aCallbackID,bool aThreadLock)2036 OSCL_EXPORT_REF PVMFStatus PVMFMediaClockNotificationsInterfaceImpl::CancelNPTCallback(
2037 /*IN*/ uint32 aCallbackID, bool aThreadLock)
2038 {
2039 if (iContainer)
2040 {
2041 return iContainer->CancelNPTCallback(aCallbackID, aThreadLock);
2042 }
2043 else
2044 {
2045 return PVMFFailure;
2046 }
2047 }
2048
SetClockObserver(PVMFMediaClockObserver & aObserver)2049 OSCL_EXPORT_REF void PVMFMediaClockNotificationsInterfaceImpl::SetClockObserver(PVMFMediaClockObserver& aObserver)
2050 {
2051 if (iContainer)
2052 {
2053 iContainer->SetClockObserver(aObserver);
2054 }
2055 }
2056
RemoveClockObserver(PVMFMediaClockObserver & aObserver)2057 OSCL_EXPORT_REF void PVMFMediaClockNotificationsInterfaceImpl::RemoveClockObserver(PVMFMediaClockObserver& aObserver)
2058 {
2059 if (iContainer)
2060 {
2061 iContainer->RemoveClockObserver(aObserver);
2062 }
2063 }
2064
SetClockStateObserver(PVMFMediaClockStateObserver & aObserver)2065 OSCL_EXPORT_REF void PVMFMediaClockNotificationsInterfaceImpl::SetClockStateObserver(PVMFMediaClockStateObserver& aObserver)
2066 {
2067 iClockStateObserver = &aObserver;
2068 }
2069
RemoveClockStateObserver(PVMFMediaClockStateObserver & aObserver)2070 OSCL_EXPORT_REF void PVMFMediaClockNotificationsInterfaceImpl::RemoveClockStateObserver(PVMFMediaClockStateObserver& aObserver)
2071 {
2072 OSCL_UNUSED_ARG(aObserver);
2073 iClockStateObserver = NULL;
2074 }
2075
GetCurrentTick32(uint32 & aTimebaseTickCount,bool & aOverflow)2076 OSCL_EXPORT_REF void PVMFTimebase_Tickcount::GetCurrentTick32(uint32& aTimebaseTickCount, bool& aOverflow)
2077 {
2078 uint32 currenttickcount = OsclTickCount::TickCount();
2079
2080 aOverflow = false;
2081
2082 // Check to see if the tickcount wrapped around
2083 if (iPrevTickcount > currenttickcount)
2084 {
2085 aOverflow = true;
2086 }
2087
2088 aTimebaseTickCount = currenttickcount;
2089
2090 // Save the current tickcount for next comparison
2091 iPrevTickcount = currenttickcount;
2092 }
2093
GetCurrentTime32(uint32 & aTime,bool & aOverflow,PVMFMediaClock_TimeUnits aUnits)2094 OSCL_EXPORT_REF void PVMFTimebase_Tickcount::GetCurrentTime32(uint32& aTime, bool& aOverflow, PVMFMediaClock_TimeUnits aUnits)
2095 {
2096 uint32 currenttickcount = OsclTickCount::TickCount();
2097
2098 aOverflow = false;
2099
2100 // Check to see if the tickcount wrapped around
2101 if (iPrevTickcount > currenttickcount)
2102 {
2103 aOverflow = true;
2104 }
2105
2106 if (PVMF_MEDIA_CLOCK_USEC == aUnits)
2107 {
2108 uint64 time64 = (uint64)(currenttickcount * iMicrosecPerTick);
2109 //There is a chance that Tickcount did not wrap around but aTime value does
2110 if (time64 > (uint64)(0xFFFFFFFF))
2111 {
2112 aOverflow = true;
2113 }
2114 aTime = Oscl_Int64_Utils::get_uint64_lower32(time64);
2115 }
2116 else /*convert time to millsecs*/
2117 {
2118 aTime = OsclTickCount::TicksToMsec(currenttickcount);
2119 uint32 divConst = 1;
2120
2121 switch (aUnits)
2122 {
2123 case PVMF_MEDIA_CLOCK_SEC:
2124 divConst = 1000;
2125 break;
2126
2127 case PVMF_MEDIA_CLOCK_MIN:
2128 divConst = 60000;
2129 break;
2130
2131 case PVMF_MEDIA_CLOCK_HOUR:
2132 divConst = 3600000;
2133 break;
2134
2135 case PVMF_MEDIA_CLOCK_DAY:
2136 divConst = 86400000;
2137 break;
2138
2139 case PVMF_MEDIA_CLOCK_MSEC:
2140 default:
2141 break;
2142 }
2143
2144 aTime = aTime / divConst;
2145 }
2146
2147 // Save the current tickcount for next comparison
2148 iPrevTickcount = currenttickcount;
2149 }
2150