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