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