1 /* 2 * Copyright (C) 2015 The Android Open Source Project 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 express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //#define LOG_NDEBUG 0 18 #define LOG_TAG "MediaClock" 19 #include <utils/Log.h> 20 #include <map> 21 22 #include <media/stagefright/MediaClock.h> 23 24 #include <media/stagefright/foundation/ADebug.h> 25 #include <media/stagefright/foundation/AMessage.h> 26 27 namespace android { 28 29 // Maximum allowed time backwards from anchor change. 30 // If larger than this threshold, it's treated as discontinuity. 31 static const int64_t kAnchorFluctuationAllowedUs = 10000LL; 32 33 MediaClock::Timer::Timer(const sp<AMessage> ¬ify, int64_t mediaTimeUs, int64_t adjustRealUs) 34 : mNotify(notify), 35 mMediaTimeUs(mediaTimeUs), 36 mAdjustRealUs(adjustRealUs) { 37 } 38 39 MediaClock::MediaClock() 40 : mAnchorTimeMediaUs(-1), 41 mAnchorTimeRealUs(-1), 42 mMaxTimeMediaUs(INT64_MAX), 43 mStartingTimeMediaUs(-1), 44 mPlaybackRate(1.0), 45 mGeneration(0) { 46 mLooper = new ALooper; 47 mLooper->setName("MediaClock"); 48 mLooper->start(false /* runOnCallingThread */, 49 false /* canCallJava */, 50 ANDROID_PRIORITY_AUDIO); 51 } 52 53 void MediaClock::init() { 54 mLooper->registerHandler(this); 55 } 56 57 MediaClock::~MediaClock() { 58 reset(); 59 if (mLooper != NULL) { 60 mLooper->unregisterHandler(id()); 61 mLooper->stop(); 62 } 63 } 64 65 void MediaClock::reset() { 66 Mutex::Autolock autoLock(mLock); 67 auto it = mTimers.begin(); 68 while (it != mTimers.end()) { 69 it->mNotify->setInt32("reason", TIMER_REASON_RESET); 70 it->mNotify->post(); 71 it = mTimers.erase(it); 72 } 73 mMaxTimeMediaUs = INT64_MAX; 74 mStartingTimeMediaUs = -1; 75 updateAnchorTimesAndPlaybackRate_l(-1, -1, 1.0); 76 ++mGeneration; 77 } 78 79 void MediaClock::setStartingTimeMedia(int64_t startingTimeMediaUs) { 80 Mutex::Autolock autoLock(mLock); 81 mStartingTimeMediaUs = startingTimeMediaUs; 82 } 83 84 void MediaClock::clearAnchor() { 85 Mutex::Autolock autoLock(mLock); 86 updateAnchorTimesAndPlaybackRate_l(-1, -1, mPlaybackRate); 87 } 88 89 void MediaClock::updateAnchor( 90 int64_t anchorTimeMediaUs, 91 int64_t anchorTimeRealUs, 92 int64_t maxTimeMediaUs) { 93 if (anchorTimeMediaUs < 0 || anchorTimeRealUs < 0) { 94 ALOGW("reject anchor time since it is negative."); 95 return; 96 } 97 98 Mutex::Autolock autoLock(mLock); 99 int64_t nowUs = ALooper::GetNowUs(); 100 int64_t nowMediaUs = 101 anchorTimeMediaUs + (nowUs - anchorTimeRealUs) * (double)mPlaybackRate; 102 if (nowMediaUs < 0) { 103 ALOGW("reject anchor time since it leads to negative media time."); 104 return; 105 } 106 107 if (maxTimeMediaUs != -1) { 108 mMaxTimeMediaUs = maxTimeMediaUs; 109 } 110 if (mAnchorTimeRealUs != -1) { 111 int64_t oldNowMediaUs = 112 mAnchorTimeMediaUs + (nowUs - mAnchorTimeRealUs) * (double)mPlaybackRate; 113 if (nowMediaUs < oldNowMediaUs + kAnchorFluctuationAllowedUs 114 && nowMediaUs > oldNowMediaUs - kAnchorFluctuationAllowedUs) { 115 return; 116 } 117 } 118 updateAnchorTimesAndPlaybackRate_l(nowMediaUs, nowUs, mPlaybackRate); 119 120 ++mGeneration; 121 processTimers_l(); 122 } 123 124 void MediaClock::updateMaxTimeMedia(int64_t maxTimeMediaUs) { 125 Mutex::Autolock autoLock(mLock); 126 mMaxTimeMediaUs = maxTimeMediaUs; 127 } 128 129 void MediaClock::setPlaybackRate(float rate) { 130 CHECK_GE(rate, 0.0); 131 Mutex::Autolock autoLock(mLock); 132 if (mAnchorTimeRealUs == -1) { 133 mPlaybackRate = rate; 134 return; 135 } 136 137 int64_t nowUs = ALooper::GetNowUs(); 138 int64_t nowMediaUs = mAnchorTimeMediaUs + (nowUs - mAnchorTimeRealUs) * (double)mPlaybackRate; 139 if (nowMediaUs < 0) { 140 ALOGW("setRate: anchor time should not be negative, set to 0."); 141 nowMediaUs = 0; 142 } 143 updateAnchorTimesAndPlaybackRate_l(nowMediaUs, nowUs, rate); 144 145 if (rate > 0.0) { 146 ++mGeneration; 147 processTimers_l(); 148 } 149 } 150 151 float MediaClock::getPlaybackRate() const { 152 Mutex::Autolock autoLock(mLock); 153 return mPlaybackRate; 154 } 155 156 status_t MediaClock::getMediaTime( 157 int64_t realUs, int64_t *outMediaUs, bool allowPastMaxTime) const { 158 if (outMediaUs == NULL) { 159 return BAD_VALUE; 160 } 161 162 Mutex::Autolock autoLock(mLock); 163 return getMediaTime_l(realUs, outMediaUs, allowPastMaxTime); 164 } 165 166 status_t MediaClock::getMediaTime_l( 167 int64_t realUs, int64_t *outMediaUs, bool allowPastMaxTime) const { 168 if (mAnchorTimeRealUs == -1) { 169 return NO_INIT; 170 } 171 172 int64_t mediaUs = mAnchorTimeMediaUs 173 + (realUs - mAnchorTimeRealUs) * (double)mPlaybackRate; 174 if (mediaUs > mMaxTimeMediaUs && !allowPastMaxTime) { 175 mediaUs = mMaxTimeMediaUs; 176 } 177 if (mediaUs < mStartingTimeMediaUs) { 178 mediaUs = mStartingTimeMediaUs; 179 } 180 if (mediaUs < 0) { 181 mediaUs = 0; 182 } 183 *outMediaUs = mediaUs; 184 return OK; 185 } 186 187 status_t MediaClock::getRealTimeFor( 188 int64_t targetMediaUs, int64_t *outRealUs) const { 189 if (outRealUs == NULL) { 190 return BAD_VALUE; 191 } 192 193 Mutex::Autolock autoLock(mLock); 194 if (mPlaybackRate == 0.0) { 195 return NO_INIT; 196 } 197 198 int64_t nowUs = ALooper::GetNowUs(); 199 int64_t nowMediaUs; 200 status_t status = 201 getMediaTime_l(nowUs, &nowMediaUs, true /* allowPastMaxTime */); 202 if (status != OK) { 203 return status; 204 } 205 *outRealUs = (targetMediaUs - nowMediaUs) / (double)mPlaybackRate + nowUs; 206 return OK; 207 } 208 209 void MediaClock::addTimer(const sp<AMessage> ¬ify, int64_t mediaTimeUs, 210 int64_t adjustRealUs) { 211 Mutex::Autolock autoLock(mLock); 212 213 bool updateTimer = (mPlaybackRate != 0.0); 214 if (updateTimer) { 215 auto it = mTimers.begin(); 216 while (it != mTimers.end()) { 217 if (((it->mAdjustRealUs - (double)adjustRealUs) * (double)mPlaybackRate 218 + (it->mMediaTimeUs - mediaTimeUs)) <= 0) { 219 updateTimer = false; 220 break; 221 } 222 ++it; 223 } 224 } 225 226 mTimers.emplace_back(notify, mediaTimeUs, adjustRealUs); 227 228 if (updateTimer) { 229 ++mGeneration; 230 processTimers_l(); 231 } 232 } 233 234 void MediaClock::onMessageReceived(const sp<AMessage> &msg) { 235 switch (msg->what()) { 236 case kWhatTimeIsUp: 237 { 238 int32_t generation; 239 CHECK(msg->findInt32("generation", &generation)); 240 241 Mutex::Autolock autoLock(mLock); 242 if (generation != mGeneration) { 243 break; 244 } 245 processTimers_l(); 246 break; 247 } 248 249 default: 250 TRESPASS(); 251 break; 252 } 253 } 254 255 void MediaClock::processTimers_l() { 256 int64_t nowMediaTimeUs; 257 status_t status = getMediaTime_l( 258 ALooper::GetNowUs(), &nowMediaTimeUs, false /* allowPastMaxTime */); 259 260 if (status != OK) { 261 return; 262 } 263 264 int64_t nextLapseRealUs = INT64_MAX; 265 std::multimap<int64_t, Timer> notifyList; 266 auto it = mTimers.begin(); 267 while (it != mTimers.end()) { 268 double diff = it->mAdjustRealUs * (double)mPlaybackRate 269 + it->mMediaTimeUs - nowMediaTimeUs; 270 int64_t diffMediaUs; 271 if (diff > (double)INT64_MAX) { 272 diffMediaUs = INT64_MAX; 273 } else if (diff < (double)INT64_MIN) { 274 diffMediaUs = INT64_MIN; 275 } else { 276 diffMediaUs = diff; 277 } 278 279 if (diffMediaUs <= 0) { 280 notifyList.emplace(diffMediaUs, *it); 281 it = mTimers.erase(it); 282 } else { 283 if (mPlaybackRate != 0.0 284 && (double)diffMediaUs < INT64_MAX * (double)mPlaybackRate) { 285 int64_t targetRealUs = diffMediaUs / (double)mPlaybackRate; 286 if (targetRealUs < nextLapseRealUs) { 287 nextLapseRealUs = targetRealUs; 288 } 289 } 290 ++it; 291 } 292 } 293 294 auto itNotify = notifyList.begin(); 295 while (itNotify != notifyList.end()) { 296 itNotify->second.mNotify->setInt32("reason", TIMER_REASON_REACHED); 297 itNotify->second.mNotify->post(); 298 itNotify = notifyList.erase(itNotify); 299 } 300 301 if (mTimers.empty() || mPlaybackRate == 0.0 || mAnchorTimeMediaUs < 0 302 || nextLapseRealUs == INT64_MAX) { 303 return; 304 } 305 306 sp<AMessage> msg = new AMessage(kWhatTimeIsUp, this); 307 msg->setInt32("generation", mGeneration); 308 msg->post(nextLapseRealUs); 309 } 310 311 void MediaClock::updateAnchorTimesAndPlaybackRate_l(int64_t anchorTimeMediaUs, 312 int64_t anchorTimeRealUs, float playbackRate) { 313 if (mAnchorTimeMediaUs != anchorTimeMediaUs 314 || mAnchorTimeRealUs != anchorTimeRealUs 315 || mPlaybackRate != playbackRate) { 316 mAnchorTimeMediaUs = anchorTimeMediaUs; 317 mAnchorTimeRealUs = anchorTimeRealUs; 318 mPlaybackRate = playbackRate; 319 notifyDiscontinuity_l(); 320 } 321 } 322 323 void MediaClock::setNotificationMessage(const sp<AMessage> &msg) { 324 Mutex::Autolock autoLock(mLock); 325 mNotify = msg; 326 } 327 328 void MediaClock::notifyDiscontinuity_l() { 329 if (mNotify != nullptr) { 330 sp<AMessage> msg = mNotify->dup(); 331 msg->setInt64("anchor-media-us", mAnchorTimeMediaUs); 332 msg->setInt64("anchor-real-us", mAnchorTimeRealUs); 333 msg->setFloat("playback-rate", mPlaybackRate); 334 msg->post(); 335 } 336 } 337 338 } // namespace android 339