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