Home | History | Annotate | Download | only in src
      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 
     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 
     52 OSCL_EXPORT_REF PVMFMediaClock::~PVMFMediaClock()
     53 {
     54     Reset();
     55     iMutex->Close();
     56     if (iMutex)
     57         OSCL_DELETE(iMutex);
     58     RemoveFromScheduler();
     59 }
     60 
     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
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    586 OSCL_EXPORT_REF void PVMFMediaClock::SetClockObserver(PVMFMediaClockObserver& aObserver)
    587 {
    588     iClockObservers.push_back(&aObserver);
    589 }
    590 
    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 
    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 
    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 
    642 void PVMFMediaClock::UpdateLatestTimes(uint32 aTime, uint32 aTimebaseVal)
    643 {
    644     // Set the latest time values
    645     iLatestRunningClockTime = aTime;
    646     iLatestRunningTimebaseTime = aTimebaseVal;
    647 }
    648 
    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 
    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 
    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 
    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 }
    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 
    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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   1454 PVMFStatus PVMFMediaClock::CancelCallback(
   1455     /*IN*/  uint32 aCallbackID, bool aThreadLock)
   1456 {
   1457     return CommonCancelCallback(aCallbackID, aThreadLock, false);
   1458 }
   1459 
   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 
   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 
   1497 PVMFStatus PVMFMediaClock::CancelNPTCallback(
   1498     /*IN*/  uint32 aCallbackID, bool aThreadLock)
   1499 {
   1500     return CommonCancelCallback(aCallbackID, aThreadLock, true);
   1501 }
   1502 
   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 
   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 
   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 
   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 
   1621 void PVMFMediaClock::ClearNPTClockPosition()
   1622 {
   1623     iStartNPT = 0;
   1624     iStartMediaClockTS = 0;
   1625     iIsNPTPlayBackDirectionBackwards = 0;
   1626 }
   1627 
   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 
   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 
   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 
   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 
   1732 void PVMFMediaClock::NotificationsInterfaceDestroyed()
   1733 {
   1734     //do nothing
   1735 }
   1736 
   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 
   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 
   1935 OSCL_EXPORT_REF PVMFMediaClockNotificationsInterfaceImpl::~PVMFMediaClockNotificationsInterfaceImpl()
   1936 {
   1937     //check if vectors need to be destroyed
   1938 }
   1939 
   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 
   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 
   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 
   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 
   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 
   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 
   2042 OSCL_EXPORT_REF void PVMFMediaClockNotificationsInterfaceImpl::SetClockObserver(PVMFMediaClockObserver& aObserver)
   2043 {
   2044     if (iContainer)
   2045     {
   2046         iContainer->SetClockObserver(aObserver);
   2047     }
   2048 }
   2049 
   2050 OSCL_EXPORT_REF void PVMFMediaClockNotificationsInterfaceImpl::RemoveClockObserver(PVMFMediaClockObserver& aObserver)
   2051 {
   2052     if (iContainer)
   2053     {
   2054         iContainer->RemoveClockObserver(aObserver);
   2055     }
   2056 }
   2057 
   2058 OSCL_EXPORT_REF void PVMFMediaClockNotificationsInterfaceImpl::SetClockStateObserver(PVMFMediaClockStateObserver& aObserver)
   2059 {
   2060     iClockStateObserver = &aObserver;
   2061 }
   2062 
   2063 OSCL_EXPORT_REF void PVMFMediaClockNotificationsInterfaceImpl::RemoveClockStateObserver(PVMFMediaClockStateObserver& aObserver)
   2064 {
   2065     OSCL_UNUSED_ARG(aObserver);
   2066     iClockStateObserver = NULL;
   2067 }
   2068 
   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 
   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 
   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 
   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