• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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