• 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 = 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