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