1 /*
2 * Copyright (C) 2021 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 #include "playbin_ctrler_base.h"
17 #include <gst/playback/gstplay-enum.h>
18 #include "nocopyable.h"
19 #include "string_ex.h"
20 #include "media_errors.h"
21 #include "media_log.h"
22 #include "player.h"
23 #include "format.h"
24 #include "uri_helper.h"
25 #include "scope_guard.h"
26 #include "playbin_state.h"
27 #include "gst_utils.h"
28 #include "media_dfx.h"
29 #include "player_xcollie.h"
30
31 namespace {
32 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "PlayBinCtrlerBase"};
33 constexpr uint64_t RING_BUFFER_MAX_SIZE = 5242880; // 5 * 1024 * 1024
34 constexpr int32_t PLAYBIN_QUEUE_MAX_SIZE = 100 * 1024 * 1024; // 100 * 1024 * 1024 Bytes
35 constexpr uint64_t BUFFER_DURATION = 15000000000; // 15s
36 constexpr int32_t BUFFER_LOW_PERCENT_DEFAULT = 1;
37 constexpr int32_t BUFFER_HIGH_PERCENT_DEFAULT = 4;
38 constexpr int32_t BUFFER_PERCENT_THRESHOLD = 100;
39 constexpr uint32_t HTTP_TIME_OUT_DEFAULT = 15; // 15s
40 constexpr int32_t NANO_SEC_PER_USEC = 1000;
41 constexpr int32_t USEC_PER_MSEC = 1000;
42 constexpr double DEFAULT_RATE = 1.0;
43 constexpr uint32_t INTERRUPT_EVENT_SHIFT = 8;
44 }
45
46 namespace OHOS {
47 namespace Media {
48 static const std::unordered_map<int32_t, int32_t> SEEK_OPTION_TO_GST_SEEK_FLAGS = {
49 {
50 IPlayBinCtrler::PlayBinSeekMode::PREV_SYNC,
51 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_BEFORE,
52 },
53 {
54 IPlayBinCtrler::PlayBinSeekMode::NEXT_SYNC,
55 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_AFTER,
56 },
57 {
58 IPlayBinCtrler::PlayBinSeekMode::CLOSET_SYNC,
59 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_NEAREST,
60 },
61 {
62 IPlayBinCtrler::PlayBinSeekMode::CLOSET,
63 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
64 }
65 };
66
67 using PlayBinCtrlerWrapper = ThizWrapper<PlayBinCtrlerBase>;
68
ElementSetup(const GstElement * playbin,GstElement * elem,gpointer userData)69 void PlayBinCtrlerBase::ElementSetup(const GstElement *playbin, GstElement *elem, gpointer userData)
70 {
71 (void)playbin;
72 if (elem == nullptr || userData == nullptr) {
73 return;
74 }
75
76 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
77 if (thizStrong != nullptr) {
78 return thizStrong->OnElementSetup(*elem);
79 }
80 }
81
ElementUnSetup(const GstElement * playbin,GstElement * subbin,GstElement * child,gpointer userData)82 void PlayBinCtrlerBase::ElementUnSetup(const GstElement *playbin, GstElement *subbin,
83 GstElement *child, gpointer userData)
84 {
85 (void)playbin;
86 (void)subbin;
87 if (child == nullptr || userData == nullptr) {
88 return;
89 }
90
91 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
92 if (thizStrong != nullptr) {
93 return thizStrong->OnElementUnSetup(*child);
94 }
95 }
96
SourceSetup(const GstElement * playbin,GstElement * elem,gpointer userData)97 void PlayBinCtrlerBase::SourceSetup(const GstElement *playbin, GstElement *elem, gpointer userData)
98 {
99 if (elem == nullptr || userData == nullptr) {
100 return;
101 }
102
103 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
104 if (thizStrong != nullptr) {
105 return thizStrong->OnSourceSetup(playbin, elem, thizStrong);
106 }
107 }
108
PlayBinCtrlerBase(const PlayBinCreateParam & createParam)109 PlayBinCtrlerBase::PlayBinCtrlerBase(const PlayBinCreateParam &createParam)
110 : renderMode_(createParam.renderMode),
111 notifier_(createParam.notifier),
112 sinkProvider_(createParam.sinkProvider)
113 {
114 MEDIA_LOGD("enter ctor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
115 }
116
~PlayBinCtrlerBase()117 PlayBinCtrlerBase::~PlayBinCtrlerBase()
118 {
119 MEDIA_LOGD("enter dtor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
120 if (Reset() == MSERR_OK) {
121 sinkProvider_ = nullptr;
122 notifier_ = nullptr;
123 }
124 }
125
Init()126 int32_t PlayBinCtrlerBase::Init()
127 {
128 CHECK_AND_RETURN_RET_LOG(sinkProvider_ != nullptr, MSERR_INVALID_VAL, "sinkprovider is nullptr");
129
130 idleState_ = std::make_shared<IdleState>(*this);
131 initializedState_ = std::make_shared<InitializedState>(*this);
132 preparingState_ = std::make_shared<PreparingState>(*this);
133 preparedState_ = std::make_shared<PreparedState>(*this);
134 playingState_ = std::make_shared<PlayingState>(*this);
135 pausedState_ = std::make_shared<PausedState>(*this);
136 stoppingState_ = std::make_shared<StoppingState>(*this);
137 stoppedState_ = std::make_shared<StoppedState>(*this);
138 playbackCompletedState_ = std::make_shared<PlaybackCompletedState>(*this);
139
140 rate_ = DEFAULT_RATE;
141
142 ChangeState(idleState_);
143
144 msgQueue_ = std::make_unique<TaskQueue>("PlaybinCtrl");
145 int32_t ret = msgQueue_->Start();
146 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "msgqueue start failed");
147
148 return ret;
149 }
150
IsLiveSource() const151 bool PlayBinCtrlerBase::IsLiveSource() const
152 {
153 if (appsrcWrap_ != nullptr && appsrcWrap_->IsLiveMode()) {
154 return true;
155 }
156 return false;
157 }
158
SetSource(const std::string & url)159 int32_t PlayBinCtrlerBase::SetSource(const std::string &url)
160 {
161 std::unique_lock<std::mutex> lock(mutex_);
162 uri_ = url;
163 if (url.find("http") == 0 || url.find("https") == 0) {
164 isNetWorkPlay_ = true;
165 }
166
167 MEDIA_LOGI("Set source: %{public}s", url.c_str());
168 return MSERR_OK;
169 }
170
SetSource(const std::shared_ptr<GstAppsrcWrap> & appsrcWrap)171 int32_t PlayBinCtrlerBase::SetSource(const std::shared_ptr<GstAppsrcWrap> &appsrcWrap)
172 {
173 std::unique_lock<std::mutex> lock(mutex_);
174 appsrcWrap_ = appsrcWrap;
175 return MSERR_OK;
176 }
177
Prepare()178 int32_t PlayBinCtrlerBase::Prepare()
179 {
180 MEDIA_LOGD("enter");
181
182 std::unique_lock<std::mutex> lock(mutex_);
183
184 int32_t ret = PrepareAsyncInternal();
185 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
186
187 {
188 MEDIA_LOGD("Prepare Start");
189 preparingCond_.wait(lock);
190 MEDIA_LOGD("Prepare End");
191 }
192
193 if (isErrorHappened_) {
194 MEDIA_LOGE("Prepare failed");
195 GstStateChangeReturn gstRet = gst_element_set_state(GST_ELEMENT_CAST(playbin_), GST_STATE_READY);
196 if (gstRet == GST_STATE_CHANGE_FAILURE) {
197 MEDIA_LOGE("Failed to change playbin's state to %{public}s", gst_element_state_get_name(GST_STATE_READY));
198 }
199 return MSERR_INVALID_STATE;
200 }
201
202 MEDIA_LOGD("exit");
203 return MSERR_OK;
204 }
205
PrepareAsync()206 int32_t PlayBinCtrlerBase::PrepareAsync()
207 {
208 MEDIA_LOGD("enter");
209
210 std::unique_lock<std::mutex> lock(mutex_);
211 return PrepareAsyncInternal();
212 }
213
Play()214 int32_t PlayBinCtrlerBase::Play()
215 {
216 MEDIA_LOGD("enter");
217
218 std::unique_lock<std::mutex> lock(mutex_);
219
220 if (GetCurrState() == playingState_) {
221 MEDIA_LOGI("already at playing state, skip");
222 return MSERR_OK;
223 }
224
225 if (isBuffering_) {
226 ChangeState(playingState_);
227 return MSERR_OK;
228 }
229
230 auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
231 int32_t ret = currState->Play();
232 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "Play failed");
233
234 return MSERR_OK;
235 }
236
Pause()237 int32_t PlayBinCtrlerBase::Pause()
238 {
239 MEDIA_LOGD("enter");
240
241 std::unique_lock<std::mutex> lock(mutex_);
242
243 if (GetCurrState() == pausedState_ || GetCurrState() == preparedState_) {
244 MEDIA_LOGI("already at paused state, skip");
245 return MSERR_OK;
246 }
247
248 auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
249 int32_t ret = currState->Pause();
250 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "Pause failed");
251
252 return MSERR_OK;
253 }
254
Seek(int64_t timeUs,int32_t seekOption)255 int32_t PlayBinCtrlerBase::Seek(int64_t timeUs, int32_t seekOption)
256 {
257 MEDIA_LOGD("enter");
258
259 if (SEEK_OPTION_TO_GST_SEEK_FLAGS.find(seekOption) == SEEK_OPTION_TO_GST_SEEK_FLAGS.end()) {
260 MEDIA_LOGE("unsupported seek option: %{public}d", seekOption);
261 return MSERR_INVALID_VAL;
262 }
263
264 std::unique_lock<std::mutex> lock(mutex_);
265 std::unique_lock<std::mutex> cacheLock(cacheCtrlMutex_);
266
267 auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
268 int32_t ret = currState->Seek(timeUs, seekOption);
269 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "Seek failed");
270
271 return MSERR_OK;
272 }
273
Stop(bool needWait)274 int32_t PlayBinCtrlerBase::Stop(bool needWait)
275 {
276 MEDIA_LOGD("enter");
277 std::unique_lock<std::mutex> lock(mutex_);
278
279 if (GetCurrState() == preparingState_ && needWait) {
280 MEDIA_LOGD("begin wait stop for current status is preparing");
281 static constexpr int32_t timeout = 2;
282 preparedCond_.wait_for(lock, std::chrono::seconds(timeout));
283 MEDIA_LOGD("end wait stop for current status is preparing");
284 }
285
286 if (appsrcWrap_ != nullptr) {
287 appsrcWrap_->Stop();
288 }
289
290 g_object_set(playbin_, "exit-block", 1, nullptr);
291 auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
292 (void)currState->Stop();
293
294 {
295 MEDIA_LOGD("Stop Start");
296 if (GetCurrState() != stoppedState_) {
297 int32_t id = PlayerXCollie::GetInstance().SetTimerByLog("stoppingCond_.wait");
298 stoppingCond_.wait(lock);
299 PlayerXCollie::GetInstance().CancelTimer(id);
300 }
301 MEDIA_LOGD("Stop End");
302 }
303
304 if (GetCurrState() != stoppedState_) {
305 MEDIA_LOGE("Stop failed");
306 return MSERR_INVALID_STATE;
307 }
308 return MSERR_OK;
309 }
310
ChooseSetRateFlags(double rate)311 GstSeekFlags PlayBinCtrlerBase::ChooseSetRateFlags(double rate)
312 {
313 GstSeekFlags seekFlags;
314
315 if (rate > 0.0) {
316 seekFlags = static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH |
317 GST_SEEK_FLAG_TRICKMODE | GST_SEEK_FLAG_SNAP_AFTER);
318 } else {
319 seekFlags = static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH |
320 GST_SEEK_FLAG_TRICKMODE | GST_SEEK_FLAG_SNAP_BEFORE);
321 }
322
323 return seekFlags;
324 }
325
SetRateInternal(double rate)326 int32_t PlayBinCtrlerBase::SetRateInternal(double rate)
327 {
328 MEDIA_LOGD("execute set rate, rate: %{public}lf", rate);
329
330 gint64 position;
331 gboolean ret;
332
333 isRating_ = true;
334 if (isDuration_.load()) {
335 position = duration_ * NANO_SEC_PER_USEC;
336 } else {
337 ret = gst_element_query_position(GST_ELEMENT_CAST(playbin_), GST_FORMAT_TIME, &position);
338 if (!ret) {
339 MEDIA_LOGW("query position failed, use lastTime");
340 position = lastTime_;
341 }
342 }
343
344 GstSeekFlags flags = ChooseSetRateFlags(rate);
345 int64_t start = rate > 0 ? position : 0;
346 int64_t stop = rate > 0 ? static_cast<int64_t>(GST_CLOCK_TIME_NONE) : position;
347
348 GstEvent *event = gst_event_new_seek(rate, GST_FORMAT_TIME, flags,
349 GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_SET, stop);
350 CHECK_AND_RETURN_RET_LOG(event != nullptr, MSERR_NO_MEMORY, "set rate failed");
351
352 ret = gst_element_send_event(GST_ELEMENT_CAST(playbin_), event);
353 CHECK_AND_RETURN_RET_LOG(ret, MSERR_SEEK_FAILED, "set rate failed");
354
355 rate_ = rate;
356
357 return MSERR_OK;
358 }
359
SetRate(double rate)360 int32_t PlayBinCtrlerBase::SetRate(double rate)
361 {
362 MEDIA_LOGD("enter");
363 std::unique_lock<std::mutex> lock(mutex_);
364 std::unique_lock<std::mutex> cacheLock(cacheCtrlMutex_);
365
366 if (IsLiveSource()) {
367 return MSERR_INVALID_OPERATION;
368 }
369
370 auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
371 int32_t ret = currState->SetRate(rate);
372 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "SetRate failed");
373
374 return MSERR_OK;
375 }
376
GetRate()377 double PlayBinCtrlerBase::GetRate()
378 {
379 std::unique_lock<std::mutex> lock(mutex_);
380 MEDIA_LOGI("get rate=%{public}lf", rate_);
381 return rate_;
382 }
383
SetLoop(bool loop)384 int32_t PlayBinCtrlerBase::SetLoop(bool loop)
385 {
386 if (IsLiveSource()) {
387 return MSERR_INVALID_OPERATION;
388 }
389 enableLooping_ = loop;
390 return MSERR_OK;
391 }
392
SetVolume(const float & leftVolume,const float & rightVolume)393 void PlayBinCtrlerBase::SetVolume(const float &leftVolume, const float &rightVolume)
394 {
395 (void)rightVolume;
396 std::unique_lock<std::mutex> lock(mutex_);
397 float volume = leftVolume;
398 if (audioSink_ != nullptr) {
399 MEDIA_LOGI("SetVolume(%{public}f) to audio sink", volume);
400 g_object_set(audioSink_, "volume", volume, nullptr);
401 }
402 }
403
SetAudioRendererInfo(const uint32_t rendererInfo,const int32_t rendererFlag)404 int32_t PlayBinCtrlerBase::SetAudioRendererInfo(const uint32_t rendererInfo, const int32_t rendererFlag)
405 {
406 std::unique_lock<std::mutex> lock(mutex_, std::try_to_lock);
407 rendererInfo_ = rendererInfo;
408 rendererFlag_ = rendererFlag;
409 if (audioSink_ != nullptr) {
410 g_object_set(audioSink_, "audio-renderer-desc", rendererInfo, nullptr);
411 g_object_set(audioSink_, "audio-renderer-flag", rendererFlag, nullptr);
412 }
413 return MSERR_OK;
414 }
415
SetAudioInterruptMode(const int32_t interruptMode)416 void PlayBinCtrlerBase::SetAudioInterruptMode(const int32_t interruptMode)
417 {
418 std::unique_lock<std::mutex> lock(mutex_);
419 if (audioSink_ != nullptr) {
420 g_object_set(audioSink_, "audio-interrupt-mode", interruptMode, nullptr);
421 }
422 }
423
SelectBitRate(uint32_t bitRate)424 int32_t PlayBinCtrlerBase::SelectBitRate(uint32_t bitRate)
425 {
426 std::unique_lock<std::mutex> lock(mutex_);
427 if (bitRateVec_.empty()) {
428 MEDIA_LOGE("BitRate is empty");
429 return MSERR_INVALID_OPERATION;
430 }
431
432 g_object_set(playbin_, "connection-speed", static_cast<uint64_t>(bitRate), nullptr);
433
434 PlayBinMessage msg = { PLAYBIN_MSG_BITRATEDONE, 0, static_cast<int32_t>(bitRate), {} };
435 ReportMessage(msg);
436
437 return MSERR_OK;
438 }
439
Reset()440 int32_t PlayBinCtrlerBase::Reset() noexcept
441 {
442 MEDIA_LOGD("enter");
443
444 std::unique_lock<std::mutex> lock(mutex_);
445 {
446 std::unique_lock<std::mutex> lk(listenerMutex_);
447 elemSetupListener_ = nullptr;
448 elemUnSetupListener_ = nullptr;
449 autoPlugSortListener_ = nullptr;
450 }
451 // Do it here before the ChangeState to IdleState, for avoding the deadlock when msg handler
452 // try to call the ChangeState.
453 ExitInitializedState();
454 ChangeState(idleState_);
455
456 if (msgQueue_ != nullptr) {
457 (void)msgQueue_->Stop();
458 }
459
460 uri_.clear();
461 isErrorHappened_ = false;
462 enableLooping_ = false;
463 {
464 std::unique_lock<std::mutex> appsrcLock(appsrcMutex_);
465 appsrcWrap_ = nullptr;
466 }
467
468 rate_ = DEFAULT_RATE;
469 seekPos_ = 0;
470 lastTime_ = 0;
471 isSeeking_ = false;
472 isRating_ = false;
473 isBuffering_ = false;
474 cachePercent_ = BUFFER_PERCENT_THRESHOLD;
475 isDuration_ = false;
476 isUserSetPause_ = false;
477
478 MEDIA_LOGD("exit");
479 return MSERR_OK;
480 }
481
SetElemSetupListener(ElemSetupListener listener)482 void PlayBinCtrlerBase::SetElemSetupListener(ElemSetupListener listener)
483 {
484 std::unique_lock<std::mutex> lock(mutex_);
485 std::unique_lock<std::mutex> lk(listenerMutex_);
486 elemSetupListener_ = listener;
487 }
488
SetElemUnSetupListener(ElemSetupListener listener)489 void PlayBinCtrlerBase::SetElemUnSetupListener(ElemSetupListener listener)
490 {
491 std::unique_lock<std::mutex> lock(mutex_);
492 std::unique_lock<std::mutex> lk(listenerMutex_);
493 elemUnSetupListener_ = listener;
494 }
495
SetAutoPlugSortListener(AutoPlugSortListener listener)496 void PlayBinCtrlerBase::SetAutoPlugSortListener(AutoPlugSortListener listener)
497 {
498 std::unique_lock<std::mutex> lock(mutex_);
499 std::unique_lock<std::mutex> lk(listenerMutex_);
500 autoPlugSortListener_ = listener;
501 }
502
DoInitializeForHttp()503 void PlayBinCtrlerBase::DoInitializeForHttp()
504 {
505 if (isNetWorkPlay_) {
506 g_object_set(playbin_, "ring-buffer-max-size", RING_BUFFER_MAX_SIZE, nullptr);
507 g_object_set(playbin_, "buffering-flags", true, "buffer-size", PLAYBIN_QUEUE_MAX_SIZE,
508 "buffer-duration", BUFFER_DURATION, "low-percent", BUFFER_LOW_PERCENT_DEFAULT,
509 "high-percent", BUFFER_HIGH_PERCENT_DEFAULT, nullptr);
510 g_object_set(playbin_, "timeout", HTTP_TIME_OUT_DEFAULT, nullptr);
511
512 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
513 CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
514
515 gulong id = g_signal_connect_data(playbin_, "bitrate-parse-complete",
516 G_CALLBACK(&PlayBinCtrlerBase::OnBitRateParseCompleteCb), wrapper,
517 (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
518 (void)signalIds_.emplace_back(SignalInfo { GST_ELEMENT_CAST(playbin_), id });
519 }
520 }
521
EnterInitializedState()522 int32_t PlayBinCtrlerBase::EnterInitializedState()
523 {
524 if (isInitialized_) {
525 return MSERR_OK;
526 }
527 MediaTrace("PlayBinCtrlerBase::InitializedState");
528 MEDIA_LOGD("EnterInitializedState enter");
529
530 ON_SCOPE_EXIT(0) {
531 ExitInitializedState();
532 PlayBinMessage msg { PlayBinMsgType::PLAYBIN_MSG_ERROR,
533 PlayBinMsgErrorSubType::PLAYBIN_SUB_MSG_ERROR_NO_MESSAGE,
534 MSERR_CREATE_PLAYER_ENGINE_FAILED, "failed to EnterInitializedState" };
535 ReportMessage(msg);
536 MEDIA_LOGE("enter initialized state failed");
537 };
538
539 int32_t ret = OnInit();
540 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
541 CHECK_AND_RETURN_RET(playbin_ != nullptr, static_cast<int32_t>(MSERR_CREATE_PLAYER_ENGINE_FAILED));
542
543 ret = DoInitializeForDataSource();
544 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "DoInitializeForDataSource failed!");
545
546 SetupCustomElement();
547 ret = SetupSignalMessage();
548 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
549 ret = SetupElementUnSetupSignal();
550 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
551 SetAudioRendererInfo(rendererInfo_, rendererFlag_);
552
553 uint32_t flags = 0;
554 g_object_get(playbin_, "flags", &flags, nullptr);
555 if ((renderMode_ & PlayBinRenderMode::DEFAULT_RENDER) != 0) {
556 flags &= ~GST_PLAY_FLAG_VIS;
557 }
558 if ((renderMode_ & PlayBinRenderMode::NATIVE_STREAM) != 0) {
559 flags |= GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_NATIVE_AUDIO;
560 flags &= ~(GST_PLAY_FLAG_SOFT_COLORBALANCE | GST_PLAY_FLAG_SOFT_VOLUME);
561 }
562 if ((renderMode_ & PlayBinRenderMode::DISABLE_TEXT) != 0) {
563 flags &= ~GST_PLAY_FLAG_TEXT;
564 }
565 g_object_set(playbin_, "flags", flags, nullptr);
566
567 // There may be a risk of data competition, but the uri is unlikely to be reconfigured.
568 if (!uri_.empty()) {
569 g_object_set(playbin_, "uri", uri_.c_str(), nullptr);
570 }
571
572 DoInitializeForHttp();
573
574 isInitialized_ = true;
575 ChangeState(initializedState_);
576
577 CANCEL_SCOPE_EXIT_GUARD(0);
578 MEDIA_LOGD("EnterInitializedState exit");
579
580 return MSERR_OK;
581 }
582
ExitInitializedState()583 void PlayBinCtrlerBase::ExitInitializedState()
584 {
585 MEDIA_LOGD("ExitInitializedState enter");
586
587 if (!isInitialized_) {
588 return;
589 }
590 isInitialized_ = false;
591
592 mutex_.unlock();
593 if (msgProcessor_ != nullptr) {
594 msgProcessor_->Reset();
595 msgProcessor_ = nullptr;
596 }
597 mutex_.lock();
598
599 if (sinkProvider_ != nullptr) {
600 sinkProvider_->SetMsgNotifier(nullptr);
601 }
602 for (auto &item : signalIds_) {
603 g_signal_handler_disconnect(item.element, item.signalId);
604 }
605 signalIds_.clear();
606
607 MEDIA_LOGD("unref playbin start");
608 if (playbin_ != nullptr) {
609 (void)gst_element_set_state(GST_ELEMENT_CAST(playbin_), GST_STATE_NULL);
610 gst_object_unref(playbin_);
611 playbin_ = nullptr;
612 }
613 MEDIA_LOGD("unref playbin stop");
614
615 MEDIA_LOGD("ExitInitializedState exit");
616 }
617
PrepareAsyncInternal()618 int32_t PlayBinCtrlerBase::PrepareAsyncInternal()
619 {
620 if ((GetCurrState() == preparingState_) || (GetCurrState() == preparedState_)) {
621 MEDIA_LOGI("already at preparing state, skip");
622 return MSERR_OK;
623 }
624
625 CHECK_AND_RETURN_RET_LOG((!uri_.empty() || appsrcWrap_), MSERR_INVALID_OPERATION, "Set uri firsty!");
626
627 int32_t ret = EnterInitializedState();
628 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
629
630 auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
631 ret = currState->Prepare();
632 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "PrepareAsyncInternal failed");
633
634 return MSERR_OK;
635 }
636
SeekInternal(int64_t timeUs,int32_t seekOption)637 int32_t PlayBinCtrlerBase::SeekInternal(int64_t timeUs, int32_t seekOption)
638 {
639 MEDIA_LOGI("execute seek, time: %{public}" PRIi64 ", option: %{public}d", timeUs, seekOption);
640
641 int32_t seekFlags = SEEK_OPTION_TO_GST_SEEK_FLAGS.at(seekOption);
642 timeUs = timeUs > duration_ ? duration_ : timeUs;
643 timeUs = timeUs < 0 ? 0 : timeUs;
644
645 constexpr int32_t usecToNanoSec = 1000;
646 int64_t timeNs = timeUs * usecToNanoSec;
647 seekPos_ = timeUs;
648 isSeeking_ = true;
649 GstEvent *event = gst_event_new_seek(rate_, GST_FORMAT_TIME, static_cast<GstSeekFlags>(seekFlags),
650 GST_SEEK_TYPE_SET, timeNs, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE);
651 CHECK_AND_RETURN_RET_LOG(event != nullptr, MSERR_NO_MEMORY, "seek failed");
652
653 gboolean ret = gst_element_send_event(GST_ELEMENT_CAST(playbin_), event);
654 CHECK_AND_RETURN_RET_LOG(ret, MSERR_SEEK_FAILED, "seek failed");
655
656 return MSERR_OK;
657 }
658
SetupInterruptEventCb()659 void PlayBinCtrlerBase::SetupInterruptEventCb()
660 {
661 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
662 CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
663
664 gulong id = g_signal_connect_data(audioSink_, "interrupt-event",
665 G_CALLBACK(&PlayBinCtrlerBase::OnInterruptEventCb), wrapper,
666 (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
667 (void)signalIds_.emplace_back(SignalInfo { GST_ELEMENT_CAST(audioSink_), id });
668 }
669
SetupAudioStateEventCb()670 void PlayBinCtrlerBase::SetupAudioStateEventCb()
671 {
672 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
673 CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
674
675 gulong id = g_signal_connect_data(audioSink_, "audio-state-event",
676 G_CALLBACK(&PlayBinCtrlerBase::OnAudioStateEventCb), wrapper,
677 (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
678 (void)signalIds_.emplace_back(SignalInfo { GST_ELEMENT_CAST(audioSink_), id });
679 }
680
SetupCustomElement()681 void PlayBinCtrlerBase::SetupCustomElement()
682 {
683 // There may be a risk of data competition, but the sinkProvider is unlikely to be reconfigured.
684 if (sinkProvider_ != nullptr) {
685 audioSink_ = sinkProvider_->CreateAudioSink();
686 if (audioSink_ != nullptr) {
687 g_object_set(playbin_, "audio-sink", audioSink_, nullptr);
688 SetupInterruptEventCb();
689 SetupAudioStateEventCb();
690 }
691 videoSink_ = sinkProvider_->CreateVideoSink();
692 if (videoSink_ != nullptr) {
693 g_object_set(playbin_, "video-sink", videoSink_, nullptr);
694 } else if (audioSink_ != nullptr) {
695 g_object_set(playbin_, "video-sink", audioSink_, nullptr);
696 }
697 auto msgNotifier = std::bind(&PlayBinCtrlerBase::OnSinkMessageReceived, this, std::placeholders::_1);
698 sinkProvider_->SetMsgNotifier(msgNotifier);
699 } else {
700 MEDIA_LOGD("no sinkprovider, delay the sink selection until the playbin enters pause state.");
701 }
702
703 if ((renderMode_ & PlayBinRenderMode::NATIVE_STREAM) == 0) {
704 GstElement *audioFilter = gst_element_factory_make("scaletempo", "scaletempo");
705 if (audioFilter != nullptr) {
706 g_object_set(playbin_, "audio-filter", audioFilter, nullptr);
707 } else {
708 MEDIA_LOGD("can not create scaletempo, the audio playback speed can not be adjusted");
709 }
710 }
711 }
712
SetupSignalMessage()713 int32_t PlayBinCtrlerBase::SetupSignalMessage()
714 {
715 MEDIA_LOGD("SetupSignalMessage enter");
716
717 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
718 CHECK_AND_RETURN_RET_LOG(wrapper != nullptr, MSERR_NO_MEMORY, "can not create this wrapper");
719
720 gulong id = g_signal_connect_data(playbin_, "element-setup",
721 G_CALLBACK(&PlayBinCtrlerBase::ElementSetup), wrapper, (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory,
722 static_cast<GConnectFlags>(0));
723 (void)signalIds_.emplace_back(SignalInfo { GST_ELEMENT_CAST(playbin_), id });
724
725 GstBus *bus = gst_pipeline_get_bus(playbin_);
726 CHECK_AND_RETURN_RET_LOG(bus != nullptr, MSERR_UNKNOWN, "can not get bus");
727
728 auto msgNotifier = std::bind(&PlayBinCtrlerBase::OnMessageReceived, this, std::placeholders::_1);
729 msgProcessor_ = std::make_unique<GstMsgProcessor>(*bus, msgNotifier);
730
731 gst_object_unref(bus);
732 bus = nullptr;
733
734 int32_t ret = msgProcessor_->Init();
735 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
736
737 // only concern the msg from playbin
738 msgProcessor_->AddMsgFilter(ELEM_NAME(GST_ELEMENT_CAST(playbin_)));
739
740 MEDIA_LOGD("SetupSignalMessage exit");
741 return MSERR_OK;
742 }
743
SetupElementUnSetupSignal()744 int32_t PlayBinCtrlerBase::SetupElementUnSetupSignal()
745 {
746 MEDIA_LOGD("SetupElementUnSetupSignal enter");
747
748 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
749 CHECK_AND_RETURN_RET_LOG(wrapper != nullptr, MSERR_NO_MEMORY, "can not create this wrapper");
750
751 gulong id = g_signal_connect_data(playbin_, "deep-element-removed",
752 G_CALLBACK(&PlayBinCtrlerBase::ElementUnSetup), wrapper, (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory,
753 static_cast<GConnectFlags>(0));
754 (void)signalIds_.emplace_back(SignalInfo { GST_ELEMENT_CAST(playbin_), id });
755
756 return MSERR_OK;
757 }
758
QueryDuration()759 void PlayBinCtrlerBase::QueryDuration()
760 {
761 auto state = GetCurrState();
762 if (state != preparedState_ && state != playingState_ && state != pausedState_ &&
763 state != playbackCompletedState_) {
764 MEDIA_LOGE("reuse the last query result: %{public}" PRIi64 " microsecond", duration_);
765 return;
766 }
767
768 gint64 duration = -1;
769 gboolean ret = gst_element_query_duration(GST_ELEMENT_CAST(playbin_), GST_FORMAT_TIME, &duration);
770 CHECK_AND_RETURN_LOG(ret, "query duration failed");
771
772 if (duration >= 0) {
773 duration_ = duration / NANO_SEC_PER_USEC;
774 }
775 MEDIA_LOGI("update the duration: %{public}" PRIi64 " microsecond", duration_);
776 }
777
QueryPosition()778 int64_t PlayBinCtrlerBase::QueryPosition()
779 {
780 gint64 position = 0;
781 gboolean ret = gst_element_query_position(GST_ELEMENT_CAST(playbin_), GST_FORMAT_TIME, &position);
782 if (!ret) {
783 MEDIA_LOGW("query position failed");
784 return lastTime_ / USEC_PER_MSEC;
785 }
786
787 int64_t curTime = position / NANO_SEC_PER_USEC;
788 if (duration_ >= 0) {
789 curTime = std::min(curTime, duration_);
790 }
791 lastTime_ = curTime;
792 MEDIA_LOGI("update the position: %{public}" PRIi64 " microsecond", curTime);
793 return curTime / USEC_PER_MSEC;
794 }
795
ProcessEndOfStream()796 void PlayBinCtrlerBase::ProcessEndOfStream()
797 {
798 MEDIA_LOGD("End of stream");
799 isDuration_ = true;
800 if (IsLiveSource()) {
801 MEDIA_LOGD("appsrc livemode, can not loop");
802 return;
803 }
804
805 if (!enableLooping_.load() && !isSeeking_) { // seek duration done->seeking->eos
806 ChangeState(playbackCompletedState_);
807 }
808 }
809
DoInitializeForDataSource()810 int32_t PlayBinCtrlerBase::DoInitializeForDataSource()
811 {
812 if (appsrcWrap_ != nullptr) {
813 (void)appsrcWrap_->Prepare();
814 auto msgNotifier = std::bind(&PlayBinCtrlerBase::OnAppsrcErrorMessageReceived, this, std::placeholders::_1);
815 CHECK_AND_RETURN_RET_LOG(appsrcWrap_->SetErrorCallback(msgNotifier) == MSERR_OK,
816 MSERR_INVALID_OPERATION, "set appsrc error callback failed");
817
818 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
819 CHECK_AND_RETURN_RET_LOG(wrapper != nullptr, MSERR_NO_MEMORY, "can not create this wrapper");
820
821 gulong id = g_signal_connect_data(playbin_, "source-setup",
822 G_CALLBACK(&PlayBinCtrlerBase::SourceSetup), wrapper, (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory,
823 static_cast<GConnectFlags>(0));
824 (void)signalIds_.emplace_back(SignalInfo { GST_ELEMENT_CAST(playbin_), id });
825
826 g_object_set(playbin_, "uri", "appsrc://", nullptr);
827 }
828 return MSERR_OK;
829 }
830
HandleCacheCtrl(int32_t percent)831 void PlayBinCtrlerBase::HandleCacheCtrl(int32_t percent)
832 {
833 MEDIA_LOGI("HandleCacheCtrl percent is %{public}d", percent);
834 if (!isBuffering_) {
835 HandleCacheCtrlWhenNoBuffering(percent);
836 } else {
837 HandleCacheCtrlWhenBuffering(percent);
838 }
839 }
840
HandleCacheCtrlCb(const InnerMessage & msg)841 void PlayBinCtrlerBase::HandleCacheCtrlCb(const InnerMessage &msg)
842 {
843 if (isNetWorkPlay_) {
844 PlayBinMessage playBinMsg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BUFFERING_PERCENT, msg.detail1, {} };
845 ReportMessage(playBinMsg);
846
847 cachePercent_ = msg.detail1;
848 HandleCacheCtrl(cachePercent_);
849 }
850 }
851
HandleCacheCtrlWhenNoBuffering(int32_t percent)852 void PlayBinCtrlerBase::HandleCacheCtrlWhenNoBuffering(int32_t percent)
853 {
854 if (percent < static_cast<float>(BUFFER_LOW_PERCENT_DEFAULT) / BUFFER_HIGH_PERCENT_DEFAULT *
855 BUFFER_PERCENT_THRESHOLD && !isSeeking_ && !isRating_ && !isUserSetPause_) {
856 isBuffering_ = true;
857 {
858 std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
859 g_object_set(playbin_, "state-change", GST_PLAYER_STATUS_BUFFERING, nullptr);
860 }
861 if (GetCurrState() == playingState_) {
862 std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
863 MEDIA_LOGI("HandleCacheCtrl percent is %{public}d, begin set to paused", percent);
864 GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT_CAST(playbin_), GST_STATE_PAUSED);
865 if (ret == GST_STATE_CHANGE_FAILURE) {
866 MEDIA_LOGE("Failed to change playbin's state to GST_STATE_PAUSED");
867 return;
868 }
869 }
870
871 PlayBinMessage msg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BUFFERING_START, 0, {} };
872 ReportMessage(msg);
873 }
874 }
875
HandleCacheCtrlWhenBuffering(int32_t percent)876 void PlayBinCtrlerBase::HandleCacheCtrlWhenBuffering(int32_t percent)
877 {
878 if (percent >= BUFFER_PERCENT_THRESHOLD) {
879 isBuffering_ = false;
880 if (GetCurrState() == playingState_ && !isUserSetPause_) {
881 {
882 std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
883 g_object_set(playbin_, "state-change", GST_PLAYER_STATUS_PLAYING, nullptr);
884 }
885 std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
886 MEDIA_LOGI("HandleCacheCtrl percent is %{public}d, begin set to playing", percent);
887 GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT_CAST(playbin_), GST_STATE_PLAYING);
888 if (ret == GST_STATE_CHANGE_FAILURE) {
889 MEDIA_LOGE("Failed to change playbin's state to GST_STATE_PLAYING");
890 return;
891 }
892 } else {
893 std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
894 g_object_set(playbin_, "state-change", GST_PLAYER_STATUS_PAUSED, nullptr);
895 }
896
897 PlayBinMessage msg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BUFFERING_END, 0, {} };
898 ReportMessage(msg);
899 }
900 }
901
RemoveGstPlaySinkVideoConvertPlugin()902 void PlayBinCtrlerBase::RemoveGstPlaySinkVideoConvertPlugin()
903 {
904 uint32_t flags = 0;
905
906 CHECK_AND_RETURN_LOG(playbin_ != nullptr, "playbin_ is nullptr");
907 g_object_get(playbin_, "flags", &flags, nullptr);
908 flags |= (GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_HARDWARE_VIDEO);
909 flags &= ~GST_PLAY_FLAG_SOFT_COLORBALANCE;
910 MEDIA_LOGD("set gstplaysink flags %{public}d", flags);
911 // set playsink remove GstPlaySinkVideoConvert, for first-frame performance optimization
912 g_object_set(playbin_, "flags", flags, nullptr);
913 }
914
AutoPlugSort(const GstElement * uriDecoder,GstPad * pad,GstCaps * caps,GValueArray * factories,gpointer userData)915 GValueArray *PlayBinCtrlerBase::AutoPlugSort(const GstElement *uriDecoder, GstPad *pad, GstCaps *caps,
916 GValueArray *factories, gpointer userData)
917 {
918 CHECK_AND_RETURN_RET_LOG(uriDecoder != nullptr, nullptr, "uriDecoder is null");
919 CHECK_AND_RETURN_RET_LOG(pad != nullptr, nullptr, "pad is null");
920 CHECK_AND_RETURN_RET_LOG(caps != nullptr, nullptr, "caps is null");
921 CHECK_AND_RETURN_RET_LOG(factories != nullptr, nullptr, "factories is null");
922
923 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
924 CHECK_AND_RETURN_RET_LOG(thizStrong != nullptr, nullptr, "thizStrong is null");
925 return thizStrong->OnAutoPlugSort(*factories);
926 }
OnAutoPlugSort(GValueArray & factories)927 GValueArray *PlayBinCtrlerBase::OnAutoPlugSort(GValueArray &factories)
928 {
929 MEDIA_LOGD("OnAutoPlugSort");
930
931 decltype(autoPlugSortListener_) listener = nullptr;
932 {
933 std::unique_lock<std::mutex> lock(listenerMutex_);
934 listener = autoPlugSortListener_;
935 }
936
937 if (listener != nullptr) {
938 return listener(factories);
939 }
940 return nullptr;
941 }
942
OnSourceSetup(const GstElement * playbin,GstElement * src,const std::shared_ptr<PlayBinCtrlerBase> & playbinCtrl)943 void PlayBinCtrlerBase::OnSourceSetup(const GstElement *playbin, GstElement *src,
944 const std::shared_ptr<PlayBinCtrlerBase> &playbinCtrl)
945 {
946 (void)playbin;
947 CHECK_AND_RETURN_LOG(playbinCtrl != nullptr, "playbinCtrl is null");
948 CHECK_AND_RETURN_LOG(src != nullptr, "src is null");
949
950 GstElementFactory *elementFac = gst_element_get_factory(src);
951 const gchar *eleTypeName = g_type_name(gst_element_factory_get_element_type(elementFac));
952 CHECK_AND_RETURN_LOG(eleTypeName != nullptr, "eleTypeName is nullptr");
953
954 std::unique_lock<std::mutex> appsrcLock(appsrcMutex_);
955 if ((strstr(eleTypeName, "GstAppSrc") != nullptr) && (playbinCtrl->appsrcWrap_ != nullptr)) {
956 (void)playbinCtrl->appsrcWrap_->SetAppsrc(src);
957 } else if (strstr(eleTypeName, "GstCurlHttpSrc") != nullptr) {
958 g_object_set(src, "ssl-ca-file", "/etc/ssl/certs/cacert.pem", nullptr);
959 MEDIA_LOGI("setup curl_http ca_file done");
960 }
961 }
962
OnVideoDecoderSetup(GstElement & elem)963 bool PlayBinCtrlerBase::OnVideoDecoderSetup(GstElement &elem)
964 {
965 const gchar *metadata = gst_element_get_metadata(&elem, GST_ELEMENT_METADATA_KLASS);
966 if (metadata == nullptr) {
967 MEDIA_LOGE("gst_element_get_metadata return nullptr");
968 return false;
969 }
970
971 std::string metaStr(metadata);
972 if (metaStr.find("Decoder/Video") != std::string::npos) {
973 return true;
974 }
975
976 return false;
977 }
978
OnElementSetup(GstElement & elem)979 void PlayBinCtrlerBase::OnElementSetup(GstElement &elem)
980 {
981 MEDIA_LOGI("element setup: %{public}s", ELEM_NAME(&elem));
982
983 // limit to the g-signal, send this notification at this thread, do not change the work thread.
984 // otherwise ,the avmetaengine will work improperly.
985
986 if (OnVideoDecoderSetup(elem) || strncmp(ELEM_NAME(&elem), "multiqueue", strlen("multiqueue")) == 0 ||
987 strncmp(ELEM_NAME(&elem), "qtdemux", strlen("qtdemux")) == 0) {
988 MEDIA_LOGI("add msgfilter element: %{public}s", ELEM_NAME(&elem));
989 msgProcessor_->AddMsgFilter(ELEM_NAME(&elem));
990 }
991
992 std::string elementName(GST_ELEMENT_NAME(&elem));
993 if (isNetWorkPlay_ == false && elementName.find("uridecodebin") != std::string::npos) {
994 PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
995 CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
996 gulong id = g_signal_connect_data(&elem, "autoplug-sort",
997 G_CALLBACK(&PlayBinCtrlerBase::AutoPlugSort), wrapper,
998 (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
999 (void)signalIds_.emplace_back(SignalInfo { &elem, id });
1000 }
1001
1002 decltype(elemSetupListener_) listener = nullptr;
1003 {
1004 std::unique_lock<std::mutex> lock(listenerMutex_);
1005 listener = elemSetupListener_;
1006 }
1007
1008 if (listener != nullptr) {
1009 listener(elem);
1010 }
1011 }
1012
OnElementUnSetup(GstElement & elem)1013 void PlayBinCtrlerBase::OnElementUnSetup(GstElement &elem)
1014 {
1015 MEDIA_LOGI("element unsetup: %{public}s", ELEM_NAME(&elem));
1016
1017 decltype(elemUnSetupListener_) listener = nullptr;
1018 {
1019 std::unique_lock<std::mutex> lock(listenerMutex_);
1020 listener = elemUnSetupListener_;
1021 }
1022
1023 if (listener != nullptr) {
1024 listener(elem);
1025 }
1026 }
1027
OnInterruptEventCb(const GstElement * audioSink,const uint32_t eventType,const uint32_t forceType,const uint32_t hintType,gpointer userData)1028 void PlayBinCtrlerBase::OnInterruptEventCb(const GstElement *audioSink, const uint32_t eventType,
1029 const uint32_t forceType, const uint32_t hintType, gpointer userData)
1030 {
1031 (void)audioSink;
1032 if (userData == nullptr) {
1033 return;
1034 }
1035 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1036 if (thizStrong != nullptr) {
1037 uint32_t value = 0;
1038 value = (((eventType << INTERRUPT_EVENT_SHIFT) | forceType) << INTERRUPT_EVENT_SHIFT) | hintType;
1039 PlayBinMessage msg { PLAYBIN_MSG_AUDIO_SINK, PLAYBIN_MSG_INTERRUPT_EVENT, 0, value };
1040 thizStrong->ReportMessage(msg);
1041 }
1042 }
1043
OnAudioStateEventCb(const GstElement * audioSink,const uint32_t audioState,gpointer userData)1044 void PlayBinCtrlerBase::OnAudioStateEventCb(const GstElement *audioSink, const uint32_t audioState, gpointer userData)
1045 {
1046 (void)audioSink;
1047 if (userData == nullptr) {
1048 return;
1049 }
1050 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1051 if (thizStrong != nullptr) {
1052 int32_t value = static_cast<int32_t>(audioState);
1053 PlayBinMessage msg { PLAYBIN_MSG_AUDIO_SINK, PLAYBIN_MSG_AUDIO_STATE_EVENT, 0, value };
1054 thizStrong->ReportMessage(msg);
1055 }
1056 }
1057
OnBitRateParseCompleteCb(const GstElement * playbin,uint32_t * bitrateInfo,uint32_t bitrateNum,gpointer userData)1058 void PlayBinCtrlerBase::OnBitRateParseCompleteCb(const GstElement *playbin, uint32_t *bitrateInfo,
1059 uint32_t bitrateNum, gpointer userData)
1060 {
1061 (void)playbin;
1062 auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1063 if (thizStrong != nullptr) {
1064 MEDIA_LOGD("bitrateNum = %{public}u", bitrateNum);
1065 for (uint32_t i = 0; i < bitrateNum; i++) {
1066 MEDIA_LOGD("bitrate = %{public}u", bitrateInfo[i]);
1067 thizStrong->bitRateVec_.push_back(bitrateInfo[i]);
1068 }
1069 Format format;
1070 (void)format.PutBuffer(std::string(PlayerKeys::PLAYER_BITRATE),
1071 static_cast<uint8_t *>(static_cast<void *>(bitrateInfo)), bitrateNum * sizeof(uint32_t));
1072 PlayBinMessage msg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BITRATE_COLLECT, 0, format };
1073 thizStrong->ReportMessage(msg);
1074 }
1075 }
1076
OnAppsrcErrorMessageReceived(int32_t errorCode)1077 void PlayBinCtrlerBase::OnAppsrcErrorMessageReceived(int32_t errorCode)
1078 {
1079 (void)errorCode;
1080 PlayBinMessage msg { PlayBinMsgType::PLAYBIN_MSG_ERROR,
1081 PlayBinMsgErrorSubType::PLAYBIN_SUB_MSG_ERROR_NO_MESSAGE,
1082 MSERR_DATA_SOURCE_IO_ERROR, "PlayBinCtrlerBase::OnAppsrcErrorMessageReceived" };
1083 ReportMessage(msg);
1084 }
1085
OnMessageReceived(const InnerMessage & msg)1086 void PlayBinCtrlerBase::OnMessageReceived(const InnerMessage &msg)
1087 {
1088 HandleMessage(msg);
1089 }
1090
OnSinkMessageReceived(const PlayBinMessage & msg)1091 void PlayBinCtrlerBase::OnSinkMessageReceived(const PlayBinMessage &msg)
1092 {
1093 ReportMessage(msg);
1094 }
1095
SetNotifier(PlayBinMsgNotifier notifier)1096 void PlayBinCtrlerBase::SetNotifier(PlayBinMsgNotifier notifier)
1097 {
1098 std::unique_lock<std::mutex> lock(mutex_);
1099 notifier_ = notifier;
1100 }
1101
ReportMessage(const PlayBinMessage & msg)1102 void PlayBinCtrlerBase::ReportMessage(const PlayBinMessage &msg)
1103 {
1104 if (msg.type == PlayBinMsgType::PLAYBIN_MSG_ERROR) {
1105 MEDIA_LOGE("error happend, error code: %{public}d", msg.code);
1106
1107 {
1108 std::unique_lock<std::mutex> lock(mutex_);
1109 isErrorHappened_ = true;
1110 preparingCond_.notify_all();
1111 stoppingCond_.notify_all();
1112 }
1113 }
1114
1115 MEDIA_LOGD("report msg, type: %{public}d", msg.type);
1116
1117 PlayBinMsgNotifier notifier = notifier_;
1118 if (notifier != nullptr) {
1119 auto msgReportHandler = std::make_shared<TaskHandler<void>>([msg, notifier]() {
1120 int32_t id = PlayerXCollie::GetInstance().SetTimerByLog("PlayBinCtrlerBase::ReportMessage");
1121 notifier(msg);
1122 PlayerXCollie::GetInstance().CancelTimer(id);
1123 });
1124 int32_t ret = msgQueue_->EnqueueTask(msgReportHandler);
1125 if (ret != MSERR_OK) {
1126 MEDIA_LOGE("async report msg failed, type: %{public}d, subType: %{public}d, code: %{public}d",
1127 msg.type, msg.subType, msg.code);
1128 };
1129 }
1130
1131 if (msg.type == PlayBinMsgType::PLAYBIN_MSG_EOS) {
1132 ProcessEndOfStream();
1133 }
1134 }
1135 } // namespace Media
1136 } // namespace OHOS
1137
1138