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 = std::min(GetMediaTime(currentClockTime), GetMaxMediaProgress());
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
SetInitialVideoFrameRate(double frameRate)109 void MediaSyncManager::SetInitialVideoFrameRate(double frameRate)
110 {
111 videoInitialFrameRate_ = frameRate;
112 }
113
GetInitialVideoFrameRate()114 double MediaSyncManager::GetInitialVideoFrameRate()
115 {
116 return videoInitialFrameRate_;
117 }
118
SetAllSyncShouldWaitNoLock()119 void MediaSyncManager::SetAllSyncShouldWaitNoLock()
120 {
121 if (!alreadySetSyncersShouldWait_) {
122 prerolledSyncers_.clear();
123 {
124 OHOS::Media::AutoLock lock1(syncersMutex_);
125 if (syncers_.size() > 1) {
126 for (const auto &supplier: syncers_) {
127 supplier->WaitAllPrerolled(true);
128 }
129 }
130 }
131 alreadySetSyncersShouldWait_ = true;
132 }
133 }
134
Resume()135 Status MediaSyncManager::Resume()
136 {
137 OHOS::Media::AutoLock lock(clockMutex_);
138 // update time anchor after a pause during normal playing
139 if (clockState_ == State::PAUSED && pausedMediaTime_ != HST_TIME_NONE && alreadySetSyncersShouldWait_) {
140 SimpleUpdateTimeAnchor(GetSystemClock(), pausedMediaTime_);
141 pausedClockTime_ = HST_TIME_NONE;
142 pausedMediaTime_ = HST_TIME_NONE;
143 }
144 FALSE_RETURN_V_NOLOG(clockState_ != State::RESUMED, Status::OK);
145 SetAllSyncShouldWaitNoLock();
146 MEDIA_LOG_I_SHORT("resume");
147 clockState_ = State::RESUMED;
148 return Status::OK;
149 }
150
GetSystemClock()151 int64_t MediaSyncManager::GetSystemClock()
152 {
153 return Plugins::HstTime2Us(SteadyClock::GetCurrentTimeNanoSec());
154 }
155
Pause()156 Status MediaSyncManager::Pause()
157 {
158 OHOS::Media::AutoLock lock(clockMutex_);
159 FALSE_RETURN_V_NOLOG(clockState_ != State::PAUSED, Status::OK);
160 pausedClockTime_ = GetSystemClock();
161 pausedMediaTime_ = std::min(GetMediaTime(pausedClockTime_), GetMaxMediaProgress());
162 MEDIA_LOG_I("pause with clockTime " PUBLIC_LOG_D64 ", mediaTime " PUBLIC_LOG_D64,
163 pausedClockTime_, pausedMediaTime_);
164 clockState_ = State::PAUSED;
165 return Status::OK;
166 }
167
Seek(int64_t mediaTime,bool isClosest)168 Status MediaSyncManager::Seek(int64_t mediaTime, bool isClosest)
169 {
170 OHOS::Media::AutoLock lock(clockMutex_);
171 FALSE_RETURN_V_NOLOG(minRangeStartOfMediaTime_ != HST_TIME_NONE && maxRangeEndOfMediaTime_ != HST_TIME_NONE,
172 Status::ERROR_INVALID_OPERATION);
173 isSeeking_ = true;
174 MEDIA_LOG_I_SHORT("isSeeking_ mediaTime: %{public}" PRId64, mediaTime);
175 seekingMediaTime_ = mediaTime;
176 alreadySetSyncersShouldWait_ = false; // set already as false
177 SetAllSyncShouldWaitNoLock(); // all suppliers should sync preroll again after seek
178 ResetTimeAnchorNoLock(); // reset the time anchor
179 isFrameAfterSeeked_ = true;
180 if (isClosest) {
181 firstMediaTimeAfterSeek_ = mediaTime;
182 } else {
183 firstMediaTimeAfterSeek_ = HST_TIME_NONE;
184 }
185 return Status::OK;
186 }
187
Reset()188 Status MediaSyncManager::Reset()
189 {
190 MEDIA_LOG_D("do Reset");
191 Stop();
192 {
193 OHOS::Media::AutoLock lock1(syncersMutex_);
194 syncers_.clear();
195 prerolledSyncers_.clear();
196 }
197 isFrameAfterSeeked_ = false;
198 lastReportMediaTime_ = HST_TIME_NONE;
199 firstMediaTimeAfterSeek_ = HST_TIME_NONE;
200 return Status::OK;
201 }
202
Stop()203 Status MediaSyncManager::Stop()
204 {
205 MEDIA_LOG_D("do Stop");
206 OHOS::Media::AutoLock lock(clockMutex_);
207 clockState_ = State::PAUSED;
208 ResetTimeAnchorNoLock();
209 pausedClockTime_ = HST_TIME_NONE;
210 playRate_ = 1.0f;
211 alreadySetSyncersShouldWait_ = false;
212 isSeeking_ = false;
213 seekCond_.notify_all();
214 seekingMediaTime_ = HST_TIME_NONE;
215 minRangeStartOfMediaTime_ = HST_TIME_NONE;
216 maxRangeEndOfMediaTime_ = HST_TIME_NONE;
217 lastVideoBufferAbsPts_ = HST_TIME_NONE;
218
219 return Status::OK;
220 }
221
ResetTimeAnchorNoLock()222 void MediaSyncManager::ResetTimeAnchorNoLock()
223 {
224 pausedMediaTime_ = HST_TIME_NONE;
225 currentSyncerPriority_ = IMediaSynchronizer::NONE;
226 SimpleUpdateTimeAnchor(HST_TIME_NONE, HST_TIME_NONE);
227 }
228
SimpleUpdateTimeAnchor(int64_t clockTime,int64_t mediaTime)229 void MediaSyncManager::SimpleUpdateTimeAnchor(int64_t clockTime, int64_t mediaTime)
230 {
231 currentAnchorClockTime_ = clockTime;
232 currentAnchorMediaTime_ = mediaTime;
233 }
234
IsSupplierValid(IMediaSynchronizer * supplier)235 bool MediaSyncManager::IsSupplierValid(IMediaSynchronizer* supplier)
236 {
237 OHOS::Media::AutoLock lock(syncersMutex_);
238 return std::find(syncers_.begin(), syncers_.end(), supplier) != syncers_.end();
239 }
240
UpdateFirstPtsAfterSeek(int64_t mediaTime)241 void MediaSyncManager::UpdateFirstPtsAfterSeek(int64_t mediaTime)
242 {
243 if (firstMediaTimeAfterSeek_ == HST_TIME_NONE) {
244 firstMediaTimeAfterSeek_ = mediaTime;
245 return;
246 }
247 if (mediaTime > firstMediaTimeAfterSeek_) {
248 firstMediaTimeAfterSeek_ = mediaTime;
249 }
250 }
251
UpdateTimeAnchor(int64_t clockTime,int64_t delayTime,IMediaTime iMediaTime,IMediaSynchronizer * supplier)252 bool MediaSyncManager::UpdateTimeAnchor(int64_t clockTime, int64_t delayTime, IMediaTime iMediaTime,
253 IMediaSynchronizer* supplier)
254 {
255 OHOS::Media::AutoLock lock(clockMutex_);
256 bool render = true;
257 if (clockTime == HST_TIME_NONE || iMediaTime.mediaTime == HST_TIME_NONE
258 || delayTime == HST_TIME_NONE || supplier == nullptr) {
259 return render;
260 }
261 clockTime += delayTime;
262 delayTime_ = delayTime;
263 if (IsSupplierValid(supplier) && supplier->GetPriority() >= currentSyncerPriority_) {
264 currentSyncerPriority_ = supplier->GetPriority();
265 SimpleUpdateTimeAnchor(clockTime, iMediaTime.mediaTime);
266 MEDIA_LOG_D_SHORT("update time anchor to priority " PUBLIC_LOG_D32 ", mediaTime " PUBLIC_LOG_D64 ", clockTime "
267 PUBLIC_LOG_D64, currentSyncerPriority_, currentAnchorMediaTime_, currentAnchorClockTime_);
268 if (isSeeking_) {
269 MEDIA_LOG_I_SHORT("leaving seeking_");
270 isSeeking_ = false;
271 seekCond_.notify_all();
272 UpdateFirstPtsAfterSeek(iMediaTime.mediaTime);
273 }
274 }
275 return render;
276 }
277
278
SetLastAudioBufferDuration(int64_t durationUs)279 void MediaSyncManager::SetLastAudioBufferDuration(int64_t durationUs)
280 {
281 if (durationUs > 0) {
282 lastAudioBufferDuration_ = durationUs;
283 } else {
284 lastAudioBufferDuration_ = 0; // If buffer duration is unavailable, treat it as 0.
285 }
286 }
287
SetLastVideoBufferPts(int64_t bufferPts)288 void MediaSyncManager::SetLastVideoBufferPts(int64_t bufferPts)
289 {
290 lastVideoBufferPts_ = bufferPts;
291 }
292
CheckSeekingMediaTime(int64_t & mediaTime)293 bool MediaSyncManager::CheckSeekingMediaTime(int64_t& mediaTime)
294 {
295 FALSE_RETURN_V_NOLOG(isSeeking_, true);
296 // no need to bound media progress during seek
297 MEDIA_LOG_D_SHORT("GetMediaTimeNow seekingMediaTime_: %{public}" PRId64, seekingMediaTime_);
298 mediaTime = seekingMediaTime_;
299 return false;
300 }
301
CheckPausedMediaTime(int64_t & mediaTime)302 bool MediaSyncManager::CheckPausedMediaTime(int64_t& mediaTime)
303 {
304 mediaTime = (clockState_ == State::PAUSED) ? pausedMediaTime_ : GetMediaTime(GetSystemClock());
305 return true;
306 }
307
CheckIfMediaTimeIsNone(int64_t & mediaTime)308 bool MediaSyncManager::CheckIfMediaTimeIsNone(int64_t& mediaTime)
309 {
310 FALSE_RETURN_V_NOLOG(mediaTime == HST_TIME_NONE, true);
311 mediaTime = 0;
312 return false;
313 }
314
CheckFirstMediaTimeAfterSeek(int64_t & mediaTime)315 bool MediaSyncManager::CheckFirstMediaTimeAfterSeek(int64_t& mediaTime)
316 {
317 bool isAudioNotRendered = (firstMediaTimeAfterSeek_ != HST_TIME_NONE && mediaTime < firstMediaTimeAfterSeek_);
318 FALSE_RETURN_V_NOLOG(isAudioNotRendered, true);
319 MEDIA_LOG_W_SHORT("audio has not been rendered since seek");
320 mediaTime = firstMediaTimeAfterSeek_;
321 return true;
322 }
323
UpdataPausedMediaTime(int32_t pausedMediaTime)324 void MediaSyncManager::UpdataPausedMediaTime(int32_t pausedMediaTime)
325 {
326 pausedMediaTime_ = pausedMediaTime;
327 }
328
GetMaxMediaProgress()329 int64_t MediaSyncManager::GetMaxMediaProgress()
330 {
331 FALSE_RETURN_V_NOLOG(currentSyncerPriority_ != IMediaSynchronizer::AUDIO_SINK,
332 currentAnchorMediaTime_ + lastAudioBufferDuration_);
333 FALSE_RETURN_V_NOLOG(currentSyncerPriority_ != IMediaSynchronizer::VIDEO_SINK,
334 lastVideoBufferPts_);
335 return std::max(currentAnchorMediaTime_, lastReportMediaTime_.load());
336 }
337
BoundMediaProgress(int64_t newMediaProgressTime)338 int64_t MediaSyncManager::BoundMediaProgress(int64_t newMediaProgressTime)
339 {
340 int64_t maxMediaProgress = GetMaxMediaProgress();
341
342 FALSE_RETURN_V_MSG_W(newMediaProgressTime <= maxMediaProgress,
343 maxMediaProgress,
344 "Media progress lag for %{public}" PRId64 " us, currentSyncerPriority_ is %{public}" PRId32,
345 newMediaProgressTime - maxMediaProgress, currentSyncerPriority_);
346
347 FALSE_RETURN_V_MSG_W(newMediaProgressTime >= lastReportMediaTime_ || isFrameAfterSeeked_,
348 lastReportMediaTime_,
349 "Avoid media time to go back without seek, from %{public}" PRId64 " to %{public}" PRId64,
350 lastReportMediaTime_.load(), newMediaProgressTime);
351 isFrameAfterSeeked_ = false;
352 return newMediaProgressTime;
353 }
354
GetMediaTimeNow()355 int64_t MediaSyncManager::GetMediaTimeNow()
356 {
357 OHOS::Media::AutoLock lock(clockMutex_);
358 int64_t currentMediaTime = HST_TIME_NONE;
359 for (const auto &func : setMediaTimeFuncs) {
360 FALSE_RETURN_V_NOLOG(func(this, currentMediaTime), currentMediaTime);
361 }
362 currentMediaTime = BoundMediaProgress(currentMediaTime);
363 lastReportMediaTime_ = currentMediaTime;
364 MEDIA_LOG_D_SHORT("GetMediaTimeNow currentMediaTime: %{public}" PRId64, currentMediaTime);
365 return currentMediaTime;
366 }
367
GetClockTimeNow()368 int64_t MediaSyncManager::GetClockTimeNow()
369 {
370 {
371 OHOS::Media::AutoLock lock(clockMutex_);
372 if (clockState_ == State::PAUSED) {
373 return pausedClockTime_;
374 }
375 }
376 return GetSystemClock();
377 }
378
IsPlayRateValid(float playRate)379 bool MediaSyncManager::IsPlayRateValid(float playRate)
380 {
381 static constexpr float MIN_PLAYRATE = 1e-9;
382 FALSE_RETURN_V_NOLOG(std::fabs(playRate_) >= MIN_PLAYRATE, false);
383 return true;
384 }
385
GetMediaTime(int64_t clockTime)386 int64_t MediaSyncManager::GetMediaTime(int64_t clockTime)
387 {
388 bool isMediaTimeValid = (clockTime != HST_TIME_NONE && currentAnchorClockTime_ != HST_TIME_NONE
389 && currentAnchorMediaTime_ != HST_TIME_NONE && delayTime_ != HST_TIME_NONE);
390 FALSE_RETURN_V_NOLOG(IsPlayRateValid(playRate_) && isMediaTimeValid, HST_TIME_NONE);
391 return currentAnchorMediaTime_ + (clockTime - currentAnchorClockTime_ + delayTime_)
392 * static_cast<double>(playRate_) - delayTime_;
393 }
394
GetAnchoredClockTime(int64_t mediaTime)395 int64_t MediaSyncManager::GetAnchoredClockTime(int64_t mediaTime)
396 {
397 OHOS::Media::AutoLock lock(clockMutex_);
398 if (minRangeStartOfMediaTime_ != HST_TIME_NONE && mediaTime < minRangeStartOfMediaTime_) {
399 MEDIA_LOG_D_SHORT("media time " PUBLIC_LOG_D64 " less than min media time " PUBLIC_LOG_D64,
400 mediaTime, minRangeStartOfMediaTime_);
401 }
402 if (maxRangeEndOfMediaTime_ != HST_TIME_NONE && mediaTime > maxRangeEndOfMediaTime_) {
403 MEDIA_LOG_D_SHORT("media time " PUBLIC_LOG_D64 " exceed max media time " PUBLIC_LOG_D64,
404 mediaTime, maxRangeEndOfMediaTime_);
405 }
406
407 bool isAnchoredClockTimeValid = (mediaTime != HST_TIME_NONE && currentAnchorClockTime_ != HST_TIME_NONE
408 && currentAnchorMediaTime_ != HST_TIME_NONE);
409 if (!IsPlayRateValid(playRate_) || !isAnchoredClockTimeValid) {
410 return HST_TIME_NONE;
411 }
412 return currentAnchorClockTime_ + (mediaTime - currentAnchorMediaTime_) / static_cast<double>(playRate_);
413 }
414
ReportPrerolled(IMediaSynchronizer * supplier)415 void MediaSyncManager::ReportPrerolled(IMediaSynchronizer* supplier)
416 {
417 if (supplier == nullptr) {
418 return;
419 }
420 OHOS::Media::AutoLock lock(syncersMutex_);
421 auto ite = std::find(prerolledSyncers_.begin(), prerolledSyncers_.end(), supplier);
422 if (ite != prerolledSyncers_.end()) {
423 MEDIA_LOG_I_SHORT("supplier already reported prerolled");
424 return;
425 }
426 prerolledSyncers_.emplace_back(supplier);
427 if (prerolledSyncers_.size() == syncers_.size()) {
428 for (const auto& prerolled : prerolledSyncers_) {
429 prerolled->NotifyAllPrerolled();
430 }
431 prerolledSyncers_.clear();
432 }
433 }
434
GetSeekTime()435 int64_t MediaSyncManager::GetSeekTime()
436 {
437 return seekingMediaTime_;
438 }
439
InSeeking()440 bool MediaSyncManager::InSeeking()
441 {
442 return isSeeking_;
443 }
444
SetMediaStartPts(int64_t startPts)445 void MediaSyncManager::SetMediaStartPts(int64_t startPts)
446 {
447 bool isStartPtsValid = startPts_ == HST_TIME_NONE || startPts < startPts_;
448 if (isStartPtsValid) {
449 startPts_ = startPts;
450 }
451 }
452
ResetMediaStartPts()453 void MediaSyncManager::ResetMediaStartPts()
454 {
455 startPts_ = HST_TIME_NONE;
456 }
457
GetMediaStartPts()458 int64_t MediaSyncManager::GetMediaStartPts()
459 {
460 return startPts_;
461 }
462
ReportEos(IMediaSynchronizer * supplier)463 void MediaSyncManager::ReportEos(IMediaSynchronizer* supplier)
464 {
465 if (supplier == nullptr) {
466 return;
467 }
468 OHOS::Media::AutoLock lock(clockMutex_);
469 if (IsSupplierValid(supplier) && supplier->GetPriority() >= currentSyncerPriority_) {
470 currentSyncerPriority_ = IMediaSynchronizer::NONE;
471 if (isSeeking_) {
472 MEDIA_LOG_I_SHORT("reportEos leaving seeking_");
473 isSeeking_ = false;
474 seekCond_.notify_all();
475 }
476 }
477 }
SetLastVideoBufferAbsPts(int64_t lastVideoBufferAbsPts)478 void MediaSyncManager::SetLastVideoBufferAbsPts(int64_t lastVideoBufferAbsPts)
479 {
480 MEDIA_LOG_D("SetLastVideoBufferAbsPts " PUBLIC_LOG_D64, lastVideoBufferAbsPts);
481 lastVideoBufferAbsPts_ = lastVideoBufferAbsPts;
482 }
483
GetLastVideoBufferAbsPts() const484 int64_t MediaSyncManager::GetLastVideoBufferAbsPts() const
485 {
486 MEDIA_LOG_D("GetLastVideoBufferAbsPts" PUBLIC_LOG_D64, lastVideoBufferAbsPts_);
487 return lastVideoBufferAbsPts_;
488 }
489 } // namespace Pipeline
490 } // namespace Media
491 } // namespace OHOS