1 /*
2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16
17 #define HST_LOG_TAG "MediaSyncManager"
18
19 #include "media_sync_manager.h"
20 #include <algorithm>
21 #include <functional>
22 #include <cmath>
23 #include "common/log.h"
24 #include "osal/utils/steady_clock.h"
25
26 namespace {
27 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_SYSTEM_PLAYER, "MediaSyncManager" };
28 }
29
30 namespace OHOS {
31 namespace Media {
32 namespace Pipeline {
33 namespace {
34 using namespace std::chrono;
35 }
36
~MediaSyncManager()37 MediaSyncManager::~MediaSyncManager()
38 {
39 MEDIA_LOG_D_SHORT("~MediaSyncManager enter.");
40 }
41
AddSynchronizer(IMediaSynchronizer * syncer)42 void MediaSyncManager::AddSynchronizer(IMediaSynchronizer* syncer)
43 {
44 if (syncer != nullptr) {
45 OHOS::Media::AutoLock lock(syncersMutex_);
46 if (std::find(syncers_.begin(), syncers_.end(), syncer) != syncers_.end()) {
47 return;
48 }
49 syncers_.emplace_back(syncer);
50 }
51 }
52
RemoveSynchronizer(IMediaSynchronizer * syncer)53 void MediaSyncManager::RemoveSynchronizer(IMediaSynchronizer* syncer)
54 {
55 if (syncer != nullptr) {
56 OHOS::Media::AutoLock lock(syncersMutex_);
57 auto ite = std::find(syncers_.begin(), syncers_.end(), syncer);
58 if (ite != syncers_.end()) {
59 syncers_.erase(ite);
60 }
61 }
62 }
63
SetPlaybackRate(float rate)64 Status MediaSyncManager::SetPlaybackRate(float rate)
65 {
66 if (rate < 0) {
67 return Status::ERROR_INVALID_PARAMETER;
68 }
69 FALSE_RETURN_V_MSG_W(rate >= 0, Status::ERROR_INVALID_PARAMETER, "Invalid playback Rate: %{public}f", rate);
70 OHOS::Media::AutoLock lock(clockMutex_);
71 MEDIA_LOG_I_SHORT("set play rate " PUBLIC_LOG_F, rate);
72 int64_t currentClockTime = GetSystemClock();
73 int64_t currentMediaTime = GetMediaTime(currentClockTime);
74 if (currentMediaTime != HST_TIME_NONE) {
75 SimpleUpdateTimeAnchor(currentClockTime, currentMediaTime);
76 }
77 playRate_ = rate;
78 return Status::OK;
79 }
80
GetPlaybackRate()81 float MediaSyncManager::GetPlaybackRate()
82 {
83 OHOS::Media::AutoLock lock(clockMutex_);
84 return playRate_;
85 }
86
SetMediaTimeRangeStart(int64_t startMediaTime,int32_t trackId,IMediaSynchronizer * supplier)87 void MediaSyncManager::SetMediaTimeRangeStart(int64_t startMediaTime, int32_t trackId, IMediaSynchronizer* supplier)
88 {
89 FALSE_RETURN_NOLOG(IsSupplierValid(supplier) && supplier->GetPriority() >= currentRangeStartPriority_);
90 currentRangeStartPriority_ = supplier->GetPriority();
91 OHOS::Media::AutoLock lock(clockMutex_);
92 if (minRangeStartOfMediaTime_ == HST_TIME_NONE || startMediaTime < minRangeStartOfMediaTime_) {
93 minRangeStartOfMediaTime_ = startMediaTime;
94 MEDIA_LOG_I_SHORT("set media started at " PUBLIC_LOG_D64, minRangeStartOfMediaTime_);
95 }
96 }
97
SetMediaTimeRangeEnd(int64_t endMediaTime,int32_t trackId,IMediaSynchronizer * supplier)98 void MediaSyncManager::SetMediaTimeRangeEnd(int64_t endMediaTime, int32_t trackId, IMediaSynchronizer* supplier)
99 {
100 FALSE_RETURN_NOLOG(IsSupplierValid(supplier) && supplier->GetPriority() >= currentRangeEndPriority_);
101 currentRangeEndPriority_ = supplier->GetPriority();
102 OHOS::Media::AutoLock lock(clockMutex_);
103 if (maxRangeEndOfMediaTime_ == HST_TIME_NONE || endMediaTime > maxRangeEndOfMediaTime_) {
104 maxRangeEndOfMediaTime_ = endMediaTime;
105 MEDIA_LOG_I_SHORT("set media end at " PUBLIC_LOG_D64, maxRangeEndOfMediaTime_);
106 }
107 }
108
SetAllSyncShouldWaitNoLock()109 void MediaSyncManager::SetAllSyncShouldWaitNoLock()
110 {
111 if (!alreadySetSyncersShouldWait_) {
112 prerolledSyncers_.clear();
113 {
114 OHOS::Media::AutoLock lock1(syncersMutex_);
115 if (syncers_.size() > 1) {
116 for (const auto &supplier: syncers_) {
117 supplier->WaitAllPrerolled(true);
118 }
119 }
120 }
121 alreadySetSyncersShouldWait_ = true;
122 }
123 }
124
Resume()125 Status MediaSyncManager::Resume()
126 {
127 OHOS::Media::AutoLock lock(clockMutex_);
128 // update time anchor after a pause during normal playing
129 if (clockState_ == State::PAUSED && pausedMediaTime_ != HST_TIME_NONE && alreadySetSyncersShouldWait_) {
130 SimpleUpdateTimeAnchor(GetSystemClock(), pausedMediaTime_);
131 pausedClockTime_ = HST_TIME_NONE;
132 pausedMediaTime_ = HST_TIME_NONE;
133 }
134 FALSE_RETURN_V_NOLOG(clockState_ != State::RESUMED, Status::OK);
135 SetAllSyncShouldWaitNoLock();
136 MEDIA_LOG_I_SHORT("resume");
137 clockState_ = State::RESUMED;
138 return Status::OK;
139 }
140
GetSystemClock()141 int64_t MediaSyncManager::GetSystemClock()
142 {
143 return Plugins::HstTime2Us(SteadyClock::GetCurrentTimeNanoSec());
144 }
145
Pause()146 Status MediaSyncManager::Pause()
147 {
148 OHOS::Media::AutoLock lock(clockMutex_);
149 FALSE_RETURN_V_NOLOG(clockState_ != State::PAUSED, Status::OK);
150 pausedClockTime_ = GetSystemClock();
151 pausedMediaTime_ = GetMediaTime(pausedClockTime_);
152 MEDIA_LOG_I("pause with clockTime " PUBLIC_LOG_D64 ", mediaTime " PUBLIC_LOG_D64,
153 pausedClockTime_, pausedMediaTime_);
154 clockState_ = State::PAUSED;
155 return Status::OK;
156 }
157
Seek(int64_t mediaTime,bool isClosest)158 Status MediaSyncManager::Seek(int64_t mediaTime, bool isClosest)
159 {
160 OHOS::Media::AutoLock lock(clockMutex_);
161 FALSE_RETURN_V_NOLOG(minRangeStartOfMediaTime_ != HST_TIME_NONE && maxRangeEndOfMediaTime_ != HST_TIME_NONE,
162 Status::ERROR_INVALID_OPERATION);
163 isSeeking_ = true;
164 MEDIA_LOG_I_SHORT("isSeeking_ mediaTime: %{public}" PRId64, mediaTime);
165 seekingMediaTime_ = mediaTime;
166 alreadySetSyncersShouldWait_ = false; // set already as false
167 SetAllSyncShouldWaitNoLock(); // all suppliers should sync preroll again after seek
168 ResetTimeAnchorNoLock(); // reset the time anchor
169 isFrameAfterSeeked_ = true;
170 if (isClosest) {
171 firstMediaTimeAfterSeek_ = mediaTime;
172 } else {
173 firstMediaTimeAfterSeek_ = HST_TIME_NONE;
174 }
175 return Status::OK;
176 }
177
Reset()178 Status MediaSyncManager::Reset()
179 {
180 MEDIA_LOG_D("do Reset");
181 Stop();
182 {
183 OHOS::Media::AutoLock lock1(syncersMutex_);
184 syncers_.clear();
185 prerolledSyncers_.clear();
186 }
187 isFrameAfterSeeked_ = false;
188 lastReportMediaTime_ = HST_TIME_NONE;
189 firstMediaTimeAfterSeek_ = HST_TIME_NONE;
190 return Status::OK;
191 }
192
Stop()193 Status MediaSyncManager::Stop()
194 {
195 MEDIA_LOG_D("do Stop");
196 OHOS::Media::AutoLock lock(clockMutex_);
197 clockState_ = State::PAUSED;
198 ResetTimeAnchorNoLock();
199 pausedClockTime_ = HST_TIME_NONE;
200 playRate_ = 1.0f;
201 alreadySetSyncersShouldWait_ = false;
202 isSeeking_ = false;
203 seekCond_.notify_all();
204 seekingMediaTime_ = HST_TIME_NONE;
205 minRangeStartOfMediaTime_ = HST_TIME_NONE;
206 maxRangeEndOfMediaTime_ = HST_TIME_NONE;
207 lastVideoBufferAbsPts_ = HST_TIME_NONE;
208
209 return Status::OK;
210 }
211
ResetTimeAnchorNoLock()212 void MediaSyncManager::ResetTimeAnchorNoLock()
213 {
214 pausedMediaTime_ = HST_TIME_NONE;
215 currentSyncerPriority_ = IMediaSynchronizer::NONE;
216 SimpleUpdateTimeAnchor(HST_TIME_NONE, HST_TIME_NONE);
217 }
218
SimpleUpdateTimeAnchor(int64_t clockTime,int64_t mediaTime)219 void MediaSyncManager::SimpleUpdateTimeAnchor(int64_t clockTime, int64_t mediaTime)
220 {
221 currentAnchorClockTime_ = clockTime;
222 currentAnchorMediaTime_ = mediaTime;
223 }
224
IsSupplierValid(IMediaSynchronizer * supplier)225 bool MediaSyncManager::IsSupplierValid(IMediaSynchronizer* supplier)
226 {
227 OHOS::Media::AutoLock lock(syncersMutex_);
228 return std::find(syncers_.begin(), syncers_.end(), supplier) != syncers_.end();
229 }
230
UpdateFirstPtsAfterSeek(int64_t mediaTime)231 void MediaSyncManager::UpdateFirstPtsAfterSeek(int64_t mediaTime)
232 {
233 if (firstMediaTimeAfterSeek_ == HST_TIME_NONE) {
234 firstMediaTimeAfterSeek_ = mediaTime;
235 return;
236 }
237 if (mediaTime > firstMediaTimeAfterSeek_) {
238 firstMediaTimeAfterSeek_ = mediaTime;
239 }
240 }
241
UpdateTimeAnchor(int64_t clockTime,int64_t delayTime,IMediaTime iMediaTime,IMediaSynchronizer * supplier)242 bool MediaSyncManager::UpdateTimeAnchor(int64_t clockTime, int64_t delayTime, IMediaTime iMediaTime,
243 IMediaSynchronizer* supplier)
244 {
245 OHOS::Media::AutoLock lock(clockMutex_);
246 bool render = true;
247 if (clockTime == HST_TIME_NONE || iMediaTime.mediaTime == HST_TIME_NONE
248 || delayTime == HST_TIME_NONE || supplier == nullptr) {
249 return render;
250 }
251 clockTime += delayTime;
252 delayTime_ = delayTime;
253 if (IsSupplierValid(supplier) && supplier->GetPriority() >= currentSyncerPriority_) {
254 currentSyncerPriority_ = supplier->GetPriority();
255 SimpleUpdateTimeAnchor(clockTime, iMediaTime.mediaTime);
256 MEDIA_LOG_D_SHORT("update time anchor to priority " PUBLIC_LOG_D32 ", mediaTime " PUBLIC_LOG_D64 ", clockTime "
257 PUBLIC_LOG_D64, currentSyncerPriority_, currentAnchorMediaTime_, currentAnchorClockTime_);
258 if (isSeeking_) {
259 if (clockState_ != State::PAUSED) {
260 MEDIA_LOG_I_SHORT("leaving seeking_");
261 isSeeking_ = false;
262 seekCond_.notify_all();
263 }
264 UpdateFirstPtsAfterSeek(iMediaTime.mediaTime);
265 }
266 }
267 return render;
268 }
269
270
SetLastAudioBufferDuration(int64_t durationUs)271 void MediaSyncManager::SetLastAudioBufferDuration(int64_t durationUs)
272 {
273 if (durationUs > 0) {
274 lastAudioBufferDuration_ = durationUs;
275 } else {
276 lastAudioBufferDuration_ = 0; // If buffer duration is unavailable, treat it as 0.
277 }
278 }
279
SetLastVideoBufferPts(int64_t bufferPts)280 void MediaSyncManager::SetLastVideoBufferPts(int64_t bufferPts)
281 {
282 lastVideoBufferPts_ = bufferPts;
283 }
284
CheckSeekingMediaTime(int64_t & mediaTime)285 bool MediaSyncManager::CheckSeekingMediaTime(int64_t& mediaTime)
286 {
287 FALSE_RETURN_V_NOLOG(isSeeking_, true);
288 // no need to bound media progress during seek
289 MEDIA_LOG_D_SHORT("GetMediaTimeNow seekingMediaTime_: %{public}" PRId64, seekingMediaTime_);
290 mediaTime = seekingMediaTime_;
291 return false;
292 }
293
CheckPausedMediaTime(int64_t & mediaTime)294 bool MediaSyncManager::CheckPausedMediaTime(int64_t& mediaTime)
295 {
296 mediaTime = (clockState_ == State::PAUSED) ? pausedMediaTime_ : GetMediaTime(GetSystemClock());
297 return true;
298 }
299
CheckIfMediaTimeIsNone(int64_t & mediaTime)300 bool MediaSyncManager::CheckIfMediaTimeIsNone(int64_t& mediaTime)
301 {
302 FALSE_RETURN_V_NOLOG(mediaTime == HST_TIME_NONE, true);
303 mediaTime = 0;
304 return false;
305 }
306
CheckFirstMediaTimeAfterSeek(int64_t & mediaTime)307 bool MediaSyncManager::CheckFirstMediaTimeAfterSeek(int64_t& mediaTime)
308 {
309 bool isAudioNotRendered = (firstMediaTimeAfterSeek_ != HST_TIME_NONE && mediaTime < firstMediaTimeAfterSeek_);
310 FALSE_RETURN_V_NOLOG(isAudioNotRendered, true);
311 MEDIA_LOG_W_SHORT("audio has not been rendered since seek");
312 mediaTime = firstMediaTimeAfterSeek_;
313 return true;
314 }
315
GetMaxMediaProgress()316 int64_t MediaSyncManager::GetMaxMediaProgress()
317 {
318 FALSE_RETURN_V_NOLOG(currentSyncerPriority_ != IMediaSynchronizer::AUDIO_SINK,
319 currentAnchorMediaTime_ + lastAudioBufferDuration_);
320 FALSE_RETURN_V_NOLOG(currentSyncerPriority_ != IMediaSynchronizer::VIDEO_SINK,
321 lastVideoBufferPts_);
322 return std::max(currentAnchorMediaTime_, lastReportMediaTime_.load());
323 }
324
BoundMediaProgress(int64_t newMediaProgressTime)325 int64_t MediaSyncManager::BoundMediaProgress(int64_t newMediaProgressTime)
326 {
327 int64_t maxMediaProgress = GetMaxMediaProgress();
328
329 FALSE_RETURN_V_MSG_W(newMediaProgressTime <= maxMediaProgress,
330 maxMediaProgress,
331 "Media progress lag for %{public}" PRId64 " us, currentSyncerPriority_ is %{public}" PRId32,
332 newMediaProgressTime - maxMediaProgress, currentSyncerPriority_);
333
334 FALSE_RETURN_V_MSG_W(newMediaProgressTime >= lastReportMediaTime_ || isFrameAfterSeeked_,
335 lastReportMediaTime_,
336 "Avoid media time to go back without seek, from %{public}" PRId64 " to %{public}" PRId64,
337 lastReportMediaTime_.load(), newMediaProgressTime);
338 isFrameAfterSeeked_ = false;
339 return newMediaProgressTime;
340 }
341
GetMediaTimeNow()342 int64_t MediaSyncManager::GetMediaTimeNow()
343 {
344 OHOS::Media::AutoLock lock(clockMutex_);
345 int64_t currentMediaTime = HST_TIME_NONE;
346 for (const auto &func : setMediaTimeFuncs) {
347 FALSE_RETURN_V(func(this, currentMediaTime), currentMediaTime);
348 }
349 currentMediaTime = BoundMediaProgress(currentMediaTime);
350 lastReportMediaTime_ = currentMediaTime;
351 MEDIA_LOG_D_SHORT("GetMediaTimeNow currentMediaTime: %{public}" PRId64, currentMediaTime);
352 return currentMediaTime;
353 }
354
GetClockTimeNow()355 int64_t MediaSyncManager::GetClockTimeNow()
356 {
357 {
358 OHOS::Media::AutoLock lock(clockMutex_);
359 if (clockState_ == State::PAUSED) {
360 return pausedClockTime_;
361 }
362 }
363 return GetSystemClock();
364 }
365
IsPlayRateValid(float playRate)366 bool MediaSyncManager::IsPlayRateValid(float playRate)
367 {
368 static constexpr float MIN_PLAYRATE = 1e-9;
369 FALSE_RETURN_V_NOLOG(std::fabs(playRate_) >= MIN_PLAYRATE, false);
370 return true;
371 }
372
GetMediaTime(int64_t clockTime)373 int64_t MediaSyncManager::GetMediaTime(int64_t clockTime)
374 {
375 bool isMediaTimeValid = (clockTime != HST_TIME_NONE && currentAnchorClockTime_ != HST_TIME_NONE
376 && currentAnchorMediaTime_ != HST_TIME_NONE && delayTime_ != HST_TIME_NONE);
377 FALSE_RETURN_V_NOLOG(IsPlayRateValid(playRate_) && isMediaTimeValid, HST_TIME_NONE);
378 return currentAnchorMediaTime_ + (clockTime - currentAnchorClockTime_ + delayTime_)
379 * static_cast<double>(playRate_) - delayTime_;
380 }
381
GetAnchoredClockTime(int64_t mediaTime)382 int64_t MediaSyncManager::GetAnchoredClockTime(int64_t mediaTime)
383 {
384 OHOS::Media::AutoLock lock(clockMutex_);
385 if (minRangeStartOfMediaTime_ != HST_TIME_NONE && mediaTime < minRangeStartOfMediaTime_) {
386 MEDIA_LOG_D_SHORT("media time " PUBLIC_LOG_D64 " less than min media time " PUBLIC_LOG_D64,
387 mediaTime, minRangeStartOfMediaTime_);
388 }
389 if (maxRangeEndOfMediaTime_ != HST_TIME_NONE && mediaTime > maxRangeEndOfMediaTime_) {
390 MEDIA_LOG_D_SHORT("media time " PUBLIC_LOG_D64 " exceed max media time " PUBLIC_LOG_D64,
391 mediaTime, maxRangeEndOfMediaTime_);
392 }
393
394 bool isAnchoredClockTimeValid = (mediaTime != HST_TIME_NONE && currentAnchorClockTime_ != HST_TIME_NONE
395 && currentAnchorMediaTime_ != HST_TIME_NONE);
396 if (!IsPlayRateValid(playRate_) || !isAnchoredClockTimeValid) {
397 return HST_TIME_NONE;
398 }
399 return currentAnchorClockTime_ + (mediaTime - currentAnchorMediaTime_) / static_cast<double>(playRate_);
400 }
401
ReportPrerolled(IMediaSynchronizer * supplier)402 void MediaSyncManager::ReportPrerolled(IMediaSynchronizer* supplier)
403 {
404 if (supplier == nullptr) {
405 return;
406 }
407 OHOS::Media::AutoLock lock(syncersMutex_);
408 auto ite = std::find(prerolledSyncers_.begin(), prerolledSyncers_.end(), supplier);
409 if (ite != prerolledSyncers_.end()) {
410 MEDIA_LOG_I_SHORT("supplier already reported prerolled");
411 return;
412 }
413 prerolledSyncers_.emplace_back(supplier);
414 if (prerolledSyncers_.size() == syncers_.size()) {
415 for (const auto& prerolled : prerolledSyncers_) {
416 prerolled->NotifyAllPrerolled();
417 }
418 prerolledSyncers_.clear();
419 }
420 }
421
GetSeekTime()422 int64_t MediaSyncManager::GetSeekTime()
423 {
424 return seekingMediaTime_;
425 }
426
InSeeking()427 bool MediaSyncManager::InSeeking()
428 {
429 return isSeeking_;
430 }
431
SetMediaStartPts(int64_t startPts)432 void MediaSyncManager::SetMediaStartPts(int64_t startPts)
433 {
434 bool isStartPtsValid = startPts_ == HST_TIME_NONE || startPts < startPts_;
435 if (isStartPtsValid) {
436 startPts_ = startPts;
437 }
438 }
439
ResetMediaStartPts()440 void MediaSyncManager::ResetMediaStartPts()
441 {
442 startPts_ = HST_TIME_NONE;
443 }
444
GetMediaStartPts()445 int64_t MediaSyncManager::GetMediaStartPts()
446 {
447 return startPts_;
448 }
449
ReportEos(IMediaSynchronizer * supplier)450 void MediaSyncManager::ReportEos(IMediaSynchronizer* supplier)
451 {
452 if (supplier == nullptr) {
453 return;
454 }
455 OHOS::Media::AutoLock lock(clockMutex_);
456 if (IsSupplierValid(supplier) && supplier->GetPriority() >= currentSyncerPriority_) {
457 currentSyncerPriority_ = IMediaSynchronizer::NONE;
458 if (isSeeking_) {
459 MEDIA_LOG_I_SHORT("reportEos leaving seeking_");
460 isSeeking_ = false;
461 seekCond_.notify_all();
462 }
463 }
464 }
SetLastVideoBufferAbsPts(int64_t lastVideoBufferAbsPts)465 void MediaSyncManager::SetLastVideoBufferAbsPts(int64_t lastVideoBufferAbsPts)
466 {
467 MEDIA_LOG_I("SetLastVideoBufferAbsPts " PUBLIC_LOG_D64, lastVideoBufferAbsPts);
468 lastVideoBufferAbsPts_ = lastVideoBufferAbsPts;
469 }
470
GetLastVideoBufferAbsPts() const471 int64_t MediaSyncManager::GetLastVideoBufferAbsPts() const
472 {
473 MEDIA_LOG_I("GetLastVideoBufferAbsPts" PUBLIC_LOG_D64, lastVideoBufferAbsPts_);
474 return lastVideoBufferAbsPts_;
475 }
476 } // namespace Pipeline
477 } // namespace Media
478 } // namespace OHOS