1 /*
2  * Copyright (c) 2022-2022 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 #define HST_LOG_TAG "MediaSyncManager"
17 
18 #include "pipeline/core/media_sync_manager.h"
19 
20 #include <algorithm>
21 #include <cmath>
22 #include "foundation/log.h"
23 #include "foundation/osal/thread/scoped_lock.h"
24 #include "foundation/utils/steady_clock.h"
25 #include "foundation/utils/hitrace_utils.h"
26 #include "plugin/common/plugin_time.h"
27 
28 namespace OHOS {
29 namespace Media {
30 namespace Pipeline {
31 namespace {
32 #define MEDIA_TUPLE_START_INDEX 1
33 #define MEDIA_TUPLE_END_INDEX 2
34 }
35 
~MediaSyncManager()36 MediaSyncManager::~MediaSyncManager()
37 {
38     MEDIA_LOG_I("~MediaSyncManager enter.");
39 }
40 
AddSynchronizer(IMediaSynchronizer * syncer)41 void MediaSyncManager::AddSynchronizer(IMediaSynchronizer* syncer)
42 {
43     if (syncer != nullptr) {
44         OSAL::ScopedLock lock(syncersMutex_);
45         if (std::find(syncers_.begin(), syncers_.end(), syncer) != syncers_.end()) {
46             return;
47         }
48         syncers_.emplace_back(syncer);
49         MEDIA_LOG_I("add syncer supplier " PUBLIC_LOG_S, syncer->GetSynchronizerName().c_str());
50     }
51 }
52 
RemoveSynchronizer(IMediaSynchronizer * syncer)53 void MediaSyncManager::RemoveSynchronizer(IMediaSynchronizer* syncer)
54 {
55     if (syncer != nullptr) {
56         OSAL::ScopedLock lock(syncersMutex_);
57         auto ite = std::find(syncers_.begin(), syncers_.end(), syncer);
58         if (ite != syncers_.end()) {
59             syncers_.erase(ite);
60             MEDIA_LOG_I("remove syncer supplier " PUBLIC_LOG_S, syncer->GetSynchronizerName().c_str());
61         }
62     }
63 }
64 
SetPlaybackRate(float rate)65 ErrorCode MediaSyncManager::SetPlaybackRate(float rate)
66 {
67     if (rate < 0) {
68         return ErrorCode::ERROR_INVALID_PARAMETER_VALUE;
69     }
70     OSAL::ScopedLock lock(clockMutex_);
71     MEDIA_LOG_I("set play rate " PUBLIC_LOG_F, rate);
72     if (currentAnchorClockTime_ == HST_TIME_NONE || currentAnchorMediaTime_ == HST_TIME_NONE) {
73         SimpleUpdatePlayRate(rate);
74         return ErrorCode::SUCCESS;
75     }
76     int64_t now = GetSystemClock();
77     int64_t currentMedia = SimpleGetMediaTime(currentAnchorClockTime_, now, currentAnchorMediaTime_, playRate_);
78     SimpleUpdateTimeAnchor(now, currentMedia);
79     SimpleUpdatePlayRate(rate);
80     return ErrorCode::SUCCESS;
81 }
82 
GetPlaybackRate()83 float MediaSyncManager::GetPlaybackRate()
84 {
85     OSAL::ScopedLock lock(clockMutex_);
86     return playRate_;
87 }
SetMediaTimeStartEnd(int32_t trackId,int32_t index,int64_t val)88 void MediaSyncManager::SetMediaTimeStartEnd(int32_t trackId, int32_t index, int64_t val)
89 {
90     auto target = std::find_if(trackMediaTimeRange_.begin(), trackMediaTimeRange_.end(),
91                                [&trackId] (const std::tuple<int32_t, int64_t, int64_t>& item) -> bool {
92         return std::get<0>(item) == trackId;
93     });
94     if (target == trackMediaTimeRange_.end()) {
95         trackMediaTimeRange_.emplace_back(
96             std::tuple<int32_t, int64_t, int64_t>(trackId, HST_TIME_NONE, HST_TIME_NONE));
97         if (index == MEDIA_TUPLE_START_INDEX) {
98             std::get<MEDIA_TUPLE_START_INDEX>(*trackMediaTimeRange_.rbegin()) = val;
99         } else if (index == MEDIA_TUPLE_END_INDEX) {
100             std::get<MEDIA_TUPLE_END_INDEX>(*trackMediaTimeRange_.rbegin()) = val;
101         } else {
102             MEDIA_LOG_W("invalid index");
103         }
104     } else {
105         if (index == MEDIA_TUPLE_START_INDEX) {
106             std::get<MEDIA_TUPLE_START_INDEX>(*target) = val;
107         } else if (index == MEDIA_TUPLE_END_INDEX) {
108             std::get<MEDIA_TUPLE_END_INDEX>(*target) = val;
109         } else {
110             MEDIA_LOG_W("invalid index");
111         }
112     }
113 }
114 
SetMediaTimeRangeStart(int64_t startMediaTime,int32_t trackId)115 void MediaSyncManager::SetMediaTimeRangeStart(int64_t startMediaTime, int32_t trackId)
116 {
117     OSAL::ScopedLock lock(clockMutex_);
118     SetMediaTimeStartEnd(trackId, MEDIA_TUPLE_START_INDEX, startMediaTime);
119     if (minRangeStartOfMediaTime_ == HST_TIME_NONE || startMediaTime < minRangeStartOfMediaTime_) {
120         minRangeStartOfMediaTime_ = startMediaTime;
121         MEDIA_LOG_I("set media started at " PUBLIC_LOG_D64, minRangeStartOfMediaTime_);
122     }
123 }
SetMediaTimeRangeEnd(int64_t endMediaTime,int32_t trackId)124 void MediaSyncManager::SetMediaTimeRangeEnd(int64_t endMediaTime, int32_t trackId)
125 {
126     OSAL::ScopedLock lock(clockMutex_);
127     SetMediaTimeStartEnd(trackId, MEDIA_TUPLE_END_INDEX, endMediaTime);
128     if (maxRangeEndOfMediaTime_ == HST_TIME_NONE || endMediaTime > maxRangeEndOfMediaTime_) {
129         maxRangeEndOfMediaTime_ = endMediaTime;
130         MEDIA_LOG_I("set media end at " PUBLIC_LOG_D64, maxRangeEndOfMediaTime_);
131     }
132 }
133 
WaitAllPrerolled(bool prerolled)134 void MediaSyncManager::WaitAllPrerolled(bool prerolled)
135 {
136     allSyncerShouldPrerolled_ = prerolled;
137 }
138 
SetAllSyncShouldWaitNoLock()139 void MediaSyncManager::SetAllSyncShouldWaitNoLock()
140 {
141     if (allSyncerShouldPrerolled_ && !alreadySetSyncersShouldWait_) {
142         prerolledSyncers_.clear();
143         {
144             OSAL::ScopedLock lock1(syncersMutex_);
145             if (syncers_.size() > 1) {
146                 for (const auto &supplier: syncers_) {
147                     supplier->WaitAllPrerolled(true);
148                 }
149             }
150         }
151         alreadySetSyncersShouldWait_ = true;
152     }
153 }
154 
Resume()155 ErrorCode MediaSyncManager::Resume()
156 {
157     OSAL::ScopedLock lock(clockMutex_);
158     // update time anchor after a pause during normal playing
159     if (clockState_ == State::PAUSED && pausedMediaTime_ != HST_TIME_NONE && alreadySetSyncersShouldWait_) {
160         SimpleUpdateTimeAnchor(GetSystemClock(), pausedMediaTime_);
161         pausedMediaTime_ = HST_TIME_NONE;
162         pausedClockTime_ = HST_TIME_NONE;
163     }
164     if (clockState_ == State::RESUMED) {
165         return ErrorCode::SUCCESS;
166     }
167     SetAllSyncShouldWaitNoLock();
168     MEDIA_LOG_I("resume");
169     clockState_ = State::RESUMED;
170     return ErrorCode::SUCCESS;
171 }
GetSystemClock()172 int64_t MediaSyncManager::GetSystemClock()
173 {
174     auto tmp = SteadyClock::GetCurrentTimeNanoSec();
175     int64_t hstTime = 0;
176     if (!Plugin::Ns2HstTime(tmp, hstTime)) {
177         return HST_TIME_NONE;
178     }
179     return hstTime;
180 }
Pause()181 ErrorCode MediaSyncManager::Pause()
182 {
183     OSAL::ScopedLock lock(clockMutex_);
184     if (clockState_ == State::PAUSED) {
185         return ErrorCode::SUCCESS;
186     }
187     pausedClockTime_ = GetSystemClock();
188     if (currentAnchorMediaTime_ != HST_TIME_NONE && currentAnchorClockTime_ != HST_TIME_NONE) {
189         pausedMediaTime_ = SimpleGetMediaTime(currentAnchorClockTime_, pausedClockTime_, currentAnchorMediaTime_,
190                                               playRate_);
191     } else {
192         pausedMediaTime_ = HST_TIME_NONE;
193     }
194     pausedMediaTime_ = ClipMediaTime(pausedMediaTime_);
195     MEDIA_LOG_I("pause with clockTime " PUBLIC_LOG_D64 ", mediaTime " PUBLIC_LOG_D64, pausedClockTime_,
196                 pausedMediaTime_);
197     clockState_ = State::PAUSED;
198     return ErrorCode::SUCCESS;
199 }
200 
Seek(int64_t mediaTime)201 ErrorCode MediaSyncManager::Seek(int64_t mediaTime)
202 {
203     SYNC_TRACER();
204     OSAL::ScopedLock lock(clockMutex_);
205     if (minRangeStartOfMediaTime_ == HST_TIME_NONE || maxRangeEndOfMediaTime_ == HST_TIME_NONE) {
206         return ErrorCode::ERROR_INVALID_OPERATION;
207     }
208     if (mediaTime > maxRangeEndOfMediaTime_ || mediaTime < minRangeStartOfMediaTime_) {
209         return ErrorCode::ERROR_INVALID_PARAMETER_VALUE;
210     }
211     isSeeking_ = true;
212     seekingMediaTime_ = mediaTime;
213     alreadySetSyncersShouldWait_ = false; // set already as false
214     SetAllSyncShouldWaitNoLock(); // all suppliers should sync preroll again after seek
215     ResetTimeAnchorNoLock(); // reset the time anchor
216     return ErrorCode::SUCCESS;
217 }
218 
Reset()219 ErrorCode MediaSyncManager::Reset()
220 {
221     MEDIA_LOG_I("do Reset");
222     OSAL::ScopedLock lock(clockMutex_);
223     clockState_ = State::PAUSED;
224     ResetTimeAnchorNoLock();
225     pausedClockTime_ = HST_TIME_NONE;
226     playRate_ = 1.0f;
227     alreadySetSyncersShouldWait_ = false;
228     allSyncerShouldPrerolled_ = true;
229     isSeeking_ = false;
230     seekingMediaTime_ = HST_TIME_NONE;
231     trackMediaTimeRange_.clear();
232     minRangeStartOfMediaTime_ = HST_TIME_NONE;
233     maxRangeEndOfMediaTime_ = HST_TIME_NONE;
234     {
235         OSAL::ScopedLock lock1(syncersMutex_);
236         syncers_.clear();
237         prerolledSyncers_.clear();
238     }
239     return ErrorCode::SUCCESS;
240 }
241 
ClipMediaTime(int64_t inTime)242 int64_t MediaSyncManager::ClipMediaTime(int64_t inTime)
243 {
244     int64_t ret = inTime;
245     if (minRangeStartOfMediaTime_ != HST_TIME_NONE && ret < minRangeStartOfMediaTime_) {
246         ret = minRangeStartOfMediaTime_;
247         MEDIA_LOG_D("clip to min media time " PUBLIC_LOG_D64, ret);
248     }
249     if (maxRangeEndOfMediaTime_ != HST_TIME_NONE && ret > maxRangeEndOfMediaTime_) {
250         ret = maxRangeEndOfMediaTime_;
251         MEDIA_LOG_D("clip to max media time " PUBLIC_LOG_D64, ret);
252     }
253     return ret;
254 }
255 
ResetTimeAnchorNoLock()256 void MediaSyncManager::ResetTimeAnchorNoLock()
257 {
258     // todo we should let suppliers wait again?
259     pausedMediaTime_ = HST_TIME_NONE;
260     currentSyncerPriority_ = IMediaSynchronizer::NONE;
261     SimpleUpdateTimeAnchor(HST_TIME_NONE, HST_TIME_NONE);
262 }
263 
SimpleUpdatePlayRate(float playRate)264 void MediaSyncManager::SimpleUpdatePlayRate(float playRate)
265 {
266     playRate_ = playRate;
267 }
268 
SimpleUpdateTimeAnchor(int64_t clockTime,int64_t mediaTime)269 void MediaSyncManager::SimpleUpdateTimeAnchor(int64_t clockTime, int64_t mediaTime)
270 {
271     currentAnchorMediaTime_ = mediaTime;
272     currentAnchorClockTime_ = clockTime;
273 }
IsSupplierValid(IMediaSynchronizer * supplier)274 bool MediaSyncManager::IsSupplierValid(IMediaSynchronizer* supplier)
275 {
276     OSAL::ScopedLock lock(syncersMutex_);
277     return std::find(syncers_.begin(), syncers_.end(), supplier) != syncers_.end();
278 }
UpdateTimeAnchor(int64_t clockTime,int64_t mediaTime,IMediaSynchronizer * supplier)279 bool MediaSyncManager::UpdateTimeAnchor(int64_t clockTime, int64_t mediaTime, IMediaSynchronizer* supplier)
280 {
281     OSAL::ScopedLock lock(clockMutex_);
282     bool render = true;
283     if (clockTime == HST_TIME_NONE || mediaTime == HST_TIME_NONE || supplier == nullptr) {
284         return render;
285     }
286     if (IsSupplierValid(supplier) && supplier->GetPriority() >= currentSyncerPriority_) {
287         currentSyncerPriority_ = supplier->GetPriority();
288         SimpleUpdateTimeAnchor(clockTime, mediaTime);
289         MEDIA_LOG_DD("update time anchor to priority " PUBLIC_LOG_D32 ", mediaTime " PUBLIC_LOG_D64 ", clockTime "
290         PUBLIC_LOG_D64, currentSyncerPriority_, currentAnchorMediaTime_, currentAnchorClockTime_);
291     }
292     if (isSeeking_ && Plugin::HstTime2Ms(abs(mediaTime - seekingMediaTime_)) <= 50) { // 50 ms
293         MEDIA_LOG_I("leaving seeking_");
294         isSeeking_ = false;
295     }
296     if (isSeeking_) {
297         render = false;
298     }
299     return render;
300 }
SimpleGetMediaTime(int64_t anchorClockTime,int64_t nowClockTime,int64_t anchorMediaTime,float playRate)301 int64_t MediaSyncManager::SimpleGetMediaTime(int64_t anchorClockTime, int64_t nowClockTime, int64_t anchorMediaTime,
302                                              float playRate)
303 {
304     if (std::fabs(playRate - 0) < 1e-9) { // 0 threshold
305         return HST_TIME_NONE;
306     }
307     if (anchorClockTime == HST_TIME_NONE || nowClockTime == HST_TIME_NONE || anchorMediaTime == HST_TIME_NONE) {
308         return HST_TIME_NONE;
309     }
310     return anchorMediaTime + (nowClockTime - anchorClockTime) * static_cast<double>(playRate);
311 }
GetMediaTimeNow()312 int64_t MediaSyncManager::GetMediaTimeNow()
313 {
314     OSAL::ScopedLock lock(clockMutex_);
315     if (isSeeking_) {
316         return seekingMediaTime_;
317     }
318     if (clockState_ == State::PAUSED) {
319         if (pausedMediaTime_ == HST_TIME_NONE) {
320             return 0;
321         }
322         return pausedMediaTime_;
323     }
324     auto ret = SimpleGetMediaTime(currentAnchorClockTime_, GetSystemClock(), currentAnchorMediaTime_, playRate_);
325     // clip into min&max media time
326     return ClipMediaTime(ret);
327 }
328 
GetClockTimeNow()329 int64_t MediaSyncManager::GetClockTimeNow()
330 {
331     {
332         OSAL::ScopedLock lock(clockMutex_);
333         if (clockState_ == State::PAUSED) {
334             return pausedClockTime_;
335         }
336     }
337     return GetSystemClock();
338 }
SimpleGetClockTime(int64_t anchorClockTime,int64_t nowMediaTime,int64_t anchorMediaTime,float playRate)339 int64_t MediaSyncManager::SimpleGetClockTime(int64_t anchorClockTime, int64_t nowMediaTime, int64_t anchorMediaTime,
340                                              float playRate)
341 {
342     if (std::fabs(playRate - 0) < 1e-9) { // 0 threshold
343         return HST_TIME_NONE;
344     }
345     if (anchorClockTime == HST_TIME_NONE || nowMediaTime == HST_TIME_NONE || anchorMediaTime == HST_TIME_NONE) {
346         return HST_TIME_NONE;
347     }
348     return anchorClockTime + (nowMediaTime - anchorMediaTime) / static_cast<double>(playRate);
349 }
GetClockTime(int64_t mediaTime)350 int64_t MediaSyncManager::GetClockTime(int64_t mediaTime)
351 {
352     OSAL::ScopedLock lock(clockMutex_);
353     if (minRangeStartOfMediaTime_ != HST_TIME_NONE && mediaTime < minRangeStartOfMediaTime_) {
354         MEDIA_LOG_W("media time " PUBLIC_LOG_D64 " less than min media time " PUBLIC_LOG_D64,
355                     mediaTime, minRangeStartOfMediaTime_);
356     }
357     if (maxRangeEndOfMediaTime_ != HST_TIME_NONE && mediaTime > maxRangeEndOfMediaTime_) {
358         MEDIA_LOG_W("media time " PUBLIC_LOG_D64 " exceed max media time " PUBLIC_LOG_D64,
359                     mediaTime, maxRangeEndOfMediaTime_);
360     }
361     return SimpleGetClockTime(currentAnchorClockTime_, mediaTime, currentAnchorMediaTime_, playRate_);
362 }
363 
ReportPrerolled(IMediaSynchronizer * supplier)364 void MediaSyncManager::ReportPrerolled(IMediaSynchronizer* supplier)
365 {
366     if (supplier == nullptr) {
367         return;
368     }
369     if (!allSyncerShouldPrerolled_) {
370         return;
371     }
372     OSAL::ScopedLock lock(syncersMutex_);
373     auto ite = std::find(prerolledSyncers_.begin(), prerolledSyncers_.end(), supplier);
374     if (ite != prerolledSyncers_.end()) {
375         MEDIA_LOG_I("supplier already reported prerolled");
376         return;
377     }
378     prerolledSyncers_.emplace_back(supplier);
379     if (prerolledSyncers_.size() == syncers_.size()) {
380         for (const auto& prerolled : prerolledSyncers_) {
381             prerolled->NotifyAllPrerolled();
382         }
383         prerolledSyncers_.clear();
384     }
385 }
386 } // namespace Pipeline
387 } // namespace Media
388 } // namespace OHOS