• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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