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