• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "param_wrapper.h"
31 
32 namespace {
33     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "PlayBinCtrlerBase"};
34     constexpr uint64_t RING_BUFFER_MAX_SIZE = 5242880; // 5 * 1024 * 1024
35     constexpr int32_t PLAYBIN_QUEUE_MAX_SIZE = 100 * 1024 * 1024; // 100 * 1024 * 1024 Bytes
36     constexpr uint64_t BUFFER_DURATION = 15000000000; // 15s
37     constexpr int32_t BUFFER_LOW_PERCENT_DEFAULT = 1;
38     constexpr int32_t BUFFER_HIGH_PERCENT_DEFAULT = 4;
39     constexpr int32_t BUFFER_PERCENT_THRESHOLD = 100;
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     constexpr uint64_t CONNECT_SPEED_DEFAULT = 4 * 8 * 1024 * 1024;  // 4Mbps
45     constexpr uint32_t MAX_SUBTITLE_TRACK_NUN = 8;
46 }
47 
48 namespace OHOS {
49 namespace Media {
50 static const std::unordered_map<int32_t, int32_t> SEEK_OPTION_TO_GST_SEEK_FLAGS = {
51     {
52         IPlayBinCtrler::PlayBinSeekMode::PREV_SYNC,
53         GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_BEFORE,
54     },
55     {
56         IPlayBinCtrler::PlayBinSeekMode::NEXT_SYNC,
57         GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_AFTER,
58     },
59     {
60         IPlayBinCtrler::PlayBinSeekMode::CLOSET_SYNC,
61         GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_NEAREST,
62     },
63     {
64         IPlayBinCtrler::PlayBinSeekMode::CLOSET,
65         GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
66     }
67 };
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     CHECK_AND_RETURN_LOG(elem != nullptr, "elem is nullptr");
73     CHECK_AND_RETURN_LOG(userData != nullptr, "userData is nullptr");
74 
75     auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
76     if (thizStrong != nullptr) {
77         return thizStrong->OnElementSetup(*elem);
78     }
79 }
80 
ElementUnSetup(const GstElement * playbin,GstElement * subbin,GstElement * child,gpointer userData)81 void PlayBinCtrlerBase::ElementUnSetup(const GstElement *playbin, GstElement *subbin,
82     GstElement *child, gpointer userData)
83 {
84     (void)playbin;
85     (void)subbin;
86     CHECK_AND_RETURN_LOG(child != nullptr, "elem is nullptr");
87     CHECK_AND_RETURN_LOG(userData != nullptr, "userData is nullptr");
88 
89     auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
90     if (thizStrong != nullptr) {
91         return thizStrong->OnElementUnSetup(*child);
92     }
93 }
94 
SourceSetup(const GstElement * playbin,GstElement * elem,gpointer userData)95 void PlayBinCtrlerBase::SourceSetup(const GstElement *playbin, GstElement *elem, gpointer userData)
96 {
97     CHECK_AND_RETURN_LOG(elem != nullptr, "elem is nullptr");
98     CHECK_AND_RETURN_LOG(userData != nullptr, "userData is nullptr");
99 
100     auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
101     if (thizStrong != nullptr) {
102         return thizStrong->OnSourceSetup(playbin, elem, thizStrong);
103     }
104 }
105 
PlayBinCtrlerBase(const PlayBinCreateParam & createParam)106 PlayBinCtrlerBase::PlayBinCtrlerBase(const PlayBinCreateParam &createParam)
107     : renderMode_(createParam.renderMode),
108     notifier_(createParam.notifier),
109     sinkProvider_(createParam.sinkProvider)
110 {
111     MEDIA_LOGD("enter ctor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
112 }
113 
~PlayBinCtrlerBase()114 PlayBinCtrlerBase::~PlayBinCtrlerBase()
115 {
116     MEDIA_LOGD("enter dtor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
117     if (Reset() == MSERR_OK) {
118         sinkProvider_ = nullptr;
119         notifier_ = nullptr;
120     }
121 }
122 
Init()123 int32_t PlayBinCtrlerBase::Init()
124 {
125     CHECK_AND_RETURN_RET_LOG(sinkProvider_ != nullptr, MSERR_INVALID_VAL, "sinkprovider is nullptr");
126 
127     idleState_ = std::make_shared<IdleState>(*this);
128     initializedState_ = std::make_shared<InitializedState>(*this);
129     preparingState_ = std::make_shared<PreparingState>(*this);
130     preparedState_ = std::make_shared<PreparedState>(*this);
131     playingState_ = std::make_shared<PlayingState>(*this);
132     pausedState_ = std::make_shared<PausedState>(*this);
133     stoppingState_ = std::make_shared<StoppingState>(*this);
134     stoppedState_ = std::make_shared<StoppedState>(*this);
135     playbackCompletedState_ = std::make_shared<PlaybackCompletedState>(*this);
136 
137     rate_ = DEFAULT_RATE;
138 
139     ChangeState(idleState_);
140 
141     msgQueue_ = std::make_unique<TaskQueue>("PlaybinCtrl");
142     int32_t ret = msgQueue_->Start();
143     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "msgqueue start failed");
144 
145     return ret;
146 }
147 
IsLiveSource() const148 bool PlayBinCtrlerBase::IsLiveSource() const
149 {
150     if (appsrcWrap_ != nullptr && appsrcWrap_->IsLiveMode()) {
151         return true;
152     }
153     return false;
154 }
155 
EnableBufferingBySysParam() const156 bool PlayBinCtrlerBase::EnableBufferingBySysParam() const
157 {
158     std::string cmd;
159     int32_t ret = OHOS::system::GetStringParameter("sys.media.player.buffering.enable", cmd, "");
160     if (ret == 0 && !cmd.empty()) {
161         return cmd == "TRUE" ? TRUE : FALSE;
162     }
163     return FALSE;
164 }
165 
SetSource(const std::string & url)166 int32_t PlayBinCtrlerBase::SetSource(const std::string &url)
167 {
168     std::unique_lock<std::mutex> lock(mutex_);
169     uri_ = url;
170     if (url.find("http") == 0 || url.find("https") == 0 || EnableBufferingBySysParam()) {
171         isNetWorkPlay_ = true;
172     }
173 
174     MEDIA_LOGI("Set source: %{public}s", url.c_str());
175     return MSERR_OK;
176 }
177 
SetSource(const std::shared_ptr<GstAppsrcEngine> & appsrcWrap)178 int32_t PlayBinCtrlerBase::SetSource(const std::shared_ptr<GstAppsrcEngine> &appsrcWrap)
179 {
180     std::unique_lock<std::mutex> lock(mutex_);
181     appsrcWrap_ = appsrcWrap;
182     return MSERR_OK;
183 }
184 
AddSubSource(const std::string & url)185 int32_t PlayBinCtrlerBase::AddSubSource(const std::string &url)
186 {
187     MEDIA_LOGD("enter");
188 
189     std::unique_lock<std::mutex> lock(mutex_);
190     ON_SCOPE_EXIT(0) {
191         OnAddSubDone();
192     };
193 
194     CHECK_AND_RETURN_RET(sinkProvider_ != nullptr, MSERR_INVALID_VAL);
195     CHECK_AND_RETURN_RET(subtitleTrackNum_ < MAX_SUBTITLE_TRACK_NUN,
196         (OnError(MSERR_INVALID_OPERATION, "subtitle tracks exceed the max num limit!"), MSERR_INVALID_OPERATION));
197 
198     if (subtitleSink_ == nullptr) {
199         subtitleSink_ = sinkProvider_->CreateSubtitleSink();
200         g_object_set(playbin_, "text-sink", subtitleSink_, nullptr);
201     }
202 
203     isAddingSubtitle_ = true;
204     g_object_set(playbin_, "add-suburi", url.c_str(), nullptr);
205     CANCEL_SCOPE_EXIT_GUARD(0);
206 
207     return MSERR_OK;
208 }
209 
PrepareAsync()210 int32_t PlayBinCtrlerBase::PrepareAsync()
211 {
212     MEDIA_LOGD("enter");
213 
214     std::unique_lock<std::mutex> lock(mutex_);
215     return PrepareAsyncInternal();
216 }
217 
Play()218 int32_t PlayBinCtrlerBase::Play()
219 {
220     MEDIA_LOGD("enter");
221 
222     std::unique_lock<std::mutex> lock(mutex_);
223     CHECK_AND_RETURN_RET_LOG(GetCurrState() != playingState_, MSERR_OK, "already at playing state");
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     CHECK_AND_RETURN_RET_LOG(GetCurrState() != pausedState_, MSERR_OK, "already at paused state");
243     CHECK_AND_RETURN_RET_LOG(GetCurrState() != preparedState_, MSERR_OK, "already at prepared state");
244 
245     auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
246     int32_t ret = currState->Pause();
247     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "Pause failed");
248 
249     return MSERR_OK;
250 }
251 
Seek(int64_t timeUs,int32_t seekOption)252 int32_t PlayBinCtrlerBase::Seek(int64_t timeUs, int32_t seekOption)
253 {
254     MEDIA_LOGD("enter");
255     CHECK_AND_RETURN_RET_LOG(SEEK_OPTION_TO_GST_SEEK_FLAGS.find(seekOption) !=
256         SEEK_OPTION_TO_GST_SEEK_FLAGS.end(), MSERR_INVALID_VAL,
257         "unsupported seek option: %{public}d", seekOption);
258     std::unique_lock<std::mutex> lock(mutex_);
259     std::unique_lock<std::mutex> cacheLock(cacheCtrlMutex_);
260 
261     auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
262     int32_t ret = currState->Seek(timeUs, seekOption);
263     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "Seek failed");
264 
265     return MSERR_OK;
266 }
267 
Stop(bool needWait)268 int32_t PlayBinCtrlerBase::Stop(bool needWait)
269 {
270     MEDIA_LOGD("enter");
271     std::unique_lock<std::mutex> lock(mutex_);
272     if (trackParse_ != nullptr) {
273         trackParse_->Stop();
274     }
275     audioIndex_ = -1;
276 
277     if (GetCurrState() == preparingState_ && needWait) {
278         MEDIA_LOGD("begin wait stop for current status is preparing");
279         static constexpr int32_t timeout = 2;
280         preparedCond_.wait_for(lock, std::chrono::seconds(timeout));
281         MEDIA_LOGD("end wait stop for current status is preparing");
282     }
283 
284     if (appsrcWrap_ != nullptr) {
285         appsrcWrap_->Stop();
286     }
287 
288     std::unique_lock<std::mutex> stateChangeLock(stateChangePropertyMutex_);
289     stopBuffering_ = true;
290     if (videoSink_ == nullptr) {
291         g_object_set(playbin_, "state-change", GST_PLAYER_STATUS_READY, nullptr);
292     }
293     if (seekFuture_.valid()) {
294         (void)seekFuture_.get();
295     }
296     auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
297     (void)currState->Stop();
298 
299     {
300         MEDIA_LOGD("Stop Start");
301         if (GetCurrState() != stoppedState_) {
302             LISTENER(stoppingCond_.wait(lock), "stoppingCond_.wait", PlayerXCollie::timerTimeout)
303         }
304         MEDIA_LOGD("Stop End");
305     }
306     trackParse_ = nullptr;
307     CHECK_AND_RETURN_RET_LOG(GetCurrState() == stoppedState_, MSERR_INVALID_STATE, "Stop failed");
308     return MSERR_OK;
309 }
310 
ChooseSetRateFlags(double rate)311 GstSeekFlags PlayBinCtrlerBase::ChooseSetRateFlags(double rate)
312 {
313     (void)rate;
314     GstSeekFlags seekFlags = static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH |
315         GST_SEEK_FLAG_TRICKMODE | GST_SEEK_FLAG_SNAP_AFTER);
316     return seekFlags;
317 }
318 
SetRateInternal(double rate)319 int32_t PlayBinCtrlerBase::SetRateInternal(double rate)
320 {
321     MEDIA_LOGD("execute set rate, rate: %{public}lf", rate);
322 
323     gint64 position;
324     gboolean ret;
325 
326     isRating_ = true;
327     if (isDuration_.load()) {
328         position = duration_ * NANO_SEC_PER_USEC;
329     } else {
330         ret = gst_element_query_position(GST_ELEMENT_CAST(playbin_), GST_FORMAT_TIME, &position);
331         if (!ret) {
332             MEDIA_LOGW("query position failed, use lastTime");
333             position = lastTime_;
334         }
335     }
336 
337     GstSeekFlags flags = ChooseSetRateFlags(rate);
338     int64_t start = rate > 0 ? position : 0;
339     int64_t stop = rate > 0 ? static_cast<int64_t>(GST_CLOCK_TIME_NONE) : position;
340 
341     GstEvent *event = gst_event_new_seek(rate, GST_FORMAT_TIME, flags,
342         GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_SET, stop);
343     CHECK_AND_RETURN_RET_LOG(event != nullptr, MSERR_NO_MEMORY, "set rate failed");
344 
345     ret = gst_element_send_event(GST_ELEMENT_CAST(playbin_), event);
346     CHECK_AND_RETURN_RET_LOG(ret, MSERR_SEEK_FAILED, "set rate failed");
347 
348     rate_ = rate;
349 
350     return MSERR_OK;
351 }
352 
SetRate(double rate)353 int32_t PlayBinCtrlerBase::SetRate(double rate)
354 {
355     MEDIA_LOGD("enter");
356     std::unique_lock<std::mutex> lock(mutex_);
357     std::unique_lock<std::mutex> cacheLock(cacheCtrlMutex_);
358 
359     auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
360     int32_t ret = currState->SetRate(rate);
361     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "SetRate failed");
362 
363     return MSERR_OK;
364 }
365 
SetLoop(bool loop)366 int32_t PlayBinCtrlerBase::SetLoop(bool loop)
367 {
368     enableLooping_ = loop;
369     return MSERR_OK;
370 }
371 
SetVolume(const float & leftVolume,const float & rightVolume)372 void PlayBinCtrlerBase::SetVolume(const float &leftVolume, const float &rightVolume)
373 {
374     (void)rightVolume;
375     std::unique_lock<std::mutex> lock(mutex_);
376     float volume = leftVolume;
377     if (audioSink_ != nullptr) {
378         MEDIA_LOGI("SetVolume(%{public}f) to audio sink", volume);
379         g_object_set(audioSink_, "volume", volume, nullptr);
380     }
381 }
382 
SetAudioRendererInfo(const uint32_t rendererInfo,const int32_t rendererFlag)383 int32_t PlayBinCtrlerBase::SetAudioRendererInfo(const uint32_t rendererInfo, const int32_t rendererFlag)
384 {
385     std::unique_lock<std::mutex> lock(mutex_, std::try_to_lock);
386     rendererInfo_ = rendererInfo;
387     rendererFlag_ = rendererFlag;
388     if (audioSink_ != nullptr) {
389         MEDIA_LOGI("SetAudioRendererInfo to audio sink");
390         g_object_set(audioSink_, "audio-renderer-desc", rendererInfo, nullptr);
391         g_object_set(audioSink_, "audio-renderer-flag", rendererFlag, nullptr);
392     }
393     return MSERR_OK;
394 }
395 
SetAudioInterruptMode(const int32_t interruptMode)396 void PlayBinCtrlerBase::SetAudioInterruptMode(const int32_t interruptMode)
397 {
398     std::unique_lock<std::mutex> lock(mutex_);
399     if (audioSink_ != nullptr) {
400         g_object_set(audioSink_, "audio-interrupt-mode", interruptMode, nullptr);
401     }
402 }
403 
SetAudioEffectMode(const int32_t effectMode)404 int32_t PlayBinCtrlerBase::SetAudioEffectMode(const int32_t effectMode)
405 {
406     std::unique_lock<std::mutex> lock(mutex_);
407     if (audioSink_ != nullptr) {
408         g_object_set(audioSink_, "audio-effect-mode", effectMode, nullptr);
409         int32_t effectModeNow = -1;
410         g_object_get(audioSink_, "audio-effect-mode", &effectModeNow, nullptr);
411         CHECK_AND_RETURN_RET_LOG(effectModeNow == effectMode, MSERR_INVALID_VAL, "failed to set audio-effect-mode");
412     }
413     return MSERR_OK;
414 }
415 
SelectBitRate(uint32_t bitRate)416 int32_t PlayBinCtrlerBase::SelectBitRate(uint32_t bitRate)
417 {
418     std::unique_lock<std::mutex> lock(mutex_);
419     MEDIA_LOGD("enter SelectBitRate, bandwidth: %{public}u", bitRate);
420     if (bitRateVec_.empty()) {
421         MEDIA_LOGE("BitRate is empty");
422         return MSERR_INVALID_OPERATION;
423     }
424     if (connectSpeed_ == bitRate && !isSelectBitRate_) {
425         PlayBinMessage msg = { PLAYBIN_MSG_BITRATEDONE, 0, static_cast<int32_t>(bitRate), {} };
426         ReportMessage(msg);
427     } else {
428         MEDIA_LOGD("set bandwidth to: %{public}u", bitRate);
429         isSelectBitRate_ = true;
430         g_object_set(playbin_, "connection-speed", static_cast<uint64_t>(bitRate), nullptr);
431     }
432     return MSERR_OK;
433 }
434 
Reset()435 int32_t PlayBinCtrlerBase::Reset() noexcept
436 {
437     MEDIA_LOGD("enter");
438 
439     std::unique_lock<std::mutex> lock(mutex_);
440     {
441         std::unique_lock<std::mutex> lk(listenerMutex_);
442         elemSetupListener_ = nullptr;
443         elemUnSetupListener_ = nullptr;
444         autoPlugSortListener_ = nullptr;
445     }
446     // Do it here before the ChangeState to IdleState, for avoding the deadlock when msg handler
447     // try to call the ChangeState.
448     ExitInitializedState();
449     ChangeState(idleState_);
450 
451     if (msgQueue_ != nullptr) {
452         (void)msgQueue_->Stop();
453     }
454 
455     uri_.clear();
456     isErrorHappened_ = false;
457     enableLooping_ = false;
458     {
459         std::unique_lock<std::mutex> appsrcLock(appsrcMutex_);
460         appsrcWrap_ = nullptr;
461     }
462 
463     rate_ = DEFAULT_RATE;
464     seekPos_ = 0;
465     lastTime_ = 0;
466     isSeeking_ = false;
467     isRating_ = false;
468     isAddingSubtitle_ = false;
469     isBuffering_ = false;
470     isSelectBitRate_ = false;
471     cachePercent_ = BUFFER_PERCENT_THRESHOLD;
472     isDuration_ = false;
473     isUserSetPause_ = false;
474     subtitleTrackNum_ = 0;
475 
476     MEDIA_LOGD("exit");
477     return MSERR_OK;
478 }
479 
SetElemSetupListener(ElemSetupListener listener)480 void PlayBinCtrlerBase::SetElemSetupListener(ElemSetupListener listener)
481 {
482     std::unique_lock<std::mutex> lock(mutex_);
483     std::unique_lock<std::mutex> lk(listenerMutex_);
484     elemSetupListener_ = listener;
485 }
486 
SetElemUnSetupListener(ElemSetupListener listener)487 void PlayBinCtrlerBase::SetElemUnSetupListener(ElemSetupListener listener)
488 {
489     std::unique_lock<std::mutex> lock(mutex_);
490     std::unique_lock<std::mutex> lk(listenerMutex_);
491     elemUnSetupListener_ = listener;
492 }
493 
SetAutoPlugSortListener(AutoPlugSortListener listener)494 void PlayBinCtrlerBase::SetAutoPlugSortListener(AutoPlugSortListener listener)
495 {
496     std::unique_lock<std::mutex> lock(mutex_);
497     std::unique_lock<std::mutex> lk(listenerMutex_);
498     autoPlugSortListener_ = listener;
499 }
500 
DoInitializeForHttp()501 void PlayBinCtrlerBase::DoInitializeForHttp()
502 {
503     if (isNetWorkPlay_) {
504         g_object_set(playbin_, "ring-buffer-max-size", RING_BUFFER_MAX_SIZE, nullptr);
505         g_object_set(playbin_, "buffering-flags", true, "buffer-size", PLAYBIN_QUEUE_MAX_SIZE,
506             "buffer-duration", BUFFER_DURATION, "low-percent", BUFFER_LOW_PERCENT_DEFAULT,
507             "high-percent", BUFFER_HIGH_PERCENT_DEFAULT, nullptr);
508 
509         std::string autoSelectBitrate;
510         int32_t res = OHOS::system::GetStringParameter(
511             "sys.media.hls.set.autoSelectBitrate", autoSelectBitrate, "");
512         if (res == 0 && !autoSelectBitrate.empty() && autoSelectBitrate == "TRUE") {
513             SetAutoSelectBitrate(true);
514             MEDIA_LOGD("set autoSelectBitrate to true");
515         } else {
516             SetAutoSelectBitrate(false);
517             MEDIA_LOGD("set autoSelectBitrate to false");
518         }
519 
520         PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
521         CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
522 
523         gulong id = g_signal_connect_data(playbin_, "bitrate-parse-complete",
524             G_CALLBACK(&PlayBinCtrlerBase::OnBitRateParseCompleteCb), wrapper,
525             (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
526         CheckAndAddSignalIds(id, wrapper, GST_ELEMENT_CAST(playbin_));
527 
528         PlayBinCtrlerWrapper *wrap = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
529         CHECK_AND_RETURN_LOG(wrap != nullptr, "can not create this wrap");
530 
531         id = g_signal_connect_data(videoSink_, "bandwidth-change",
532             G_CALLBACK(&PlayBinCtrlerBase::OnSelectBitrateDoneCb), wrap,
533             (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
534         CheckAndAddSignalIds(id, wrap, videoSink_);
535     }
536 }
537 
EnterInitializedState()538 int32_t PlayBinCtrlerBase::EnterInitializedState()
539 {
540     if (isInitialized_) {
541         (void)DoInitializeForDataSource();
542         return MSERR_OK;
543     }
544     MediaTrace("PlayBinCtrlerBase::InitializedState");
545     MEDIA_LOGD("EnterInitializedState enter");
546 
547     ON_SCOPE_EXIT(0) {
548         ExitInitializedState();
549         PlayBinMessage msg { PlayBinMsgType::PLAYBIN_MSG_ERROR,
550             PlayBinMsgErrorSubType::PLAYBIN_SUB_MSG_ERROR_WITH_MESSAGE,
551             MSERR_CREATE_PLAYER_ENGINE_FAILED, std::string("failed to EnterInitializedState") };
552         ReportMessage(msg);
553         MEDIA_LOGE("enter initialized state failed");
554     };
555 
556     int32_t ret = OnInit();
557     CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
558     CHECK_AND_RETURN_RET(playbin_ != nullptr, static_cast<int32_t>(MSERR_CREATE_PLAYER_ENGINE_FAILED));
559 
560     ret = DoInitializeForDataSource();
561     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "DoInitializeForDataSource failed!");
562 
563     SetupCustomElement();
564     SetupSourceSetupSignal();
565     ret = SetupSignalMessage();
566     CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
567     ret = SetupElementUnSetupSignal();
568     CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
569     SetAudioRendererInfo(rendererInfo_, rendererFlag_);
570 
571     uint32_t flags = 0;
572     g_object_get(playbin_, "flags", &flags, nullptr);
573     if ((renderMode_ & PlayBinRenderMode::DEFAULT_RENDER) != 0) {
574         flags &= ~GST_PLAY_FLAG_VIS;
575     }
576     if ((renderMode_ & PlayBinRenderMode::NATIVE_STREAM) != 0) {
577         flags |= GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_NATIVE_AUDIO;
578         flags &= ~(GST_PLAY_FLAG_SOFT_COLORBALANCE | GST_PLAY_FLAG_SOFT_VOLUME);
579     }
580     if ((renderMode_ & PlayBinRenderMode::DISABLE_TEXT) != 0) {
581         flags &= ~GST_PLAY_FLAG_TEXT;
582     }
583     g_object_set(playbin_, "flags", flags, nullptr);
584 
585     // There may be a risk of data competition, but the uri is unlikely to be reconfigured.
586     if (!uri_.empty()) {
587         g_object_set(playbin_, "uri", uri_.c_str(), nullptr);
588     }
589 
590     DoInitializeForHttp();
591 
592     isInitialized_ = true;
593     ChangeState(initializedState_);
594 
595     CANCEL_SCOPE_EXIT_GUARD(0);
596     MEDIA_LOGD("EnterInitializedState exit");
597 
598     return MSERR_OK;
599 }
600 
ExitInitializedState()601 void PlayBinCtrlerBase::ExitInitializedState()
602 {
603     MEDIA_LOGD("ExitInitializedState enter");
604 
605     if (!isInitialized_) {
606         return;
607     }
608     isInitialized_ = false;
609 
610     mutex_.unlock();
611     if (msgProcessor_ != nullptr) {
612         msgProcessor_->Reset();
613         msgProcessor_ = nullptr;
614     }
615     mutex_.lock();
616 
617     if (sinkProvider_ != nullptr) {
618         sinkProvider_->SetMsgNotifier(nullptr);
619     }
620     for (auto &item : signalIds_) {
621         for (auto id : item.second) {
622             g_signal_handler_disconnect(item.first, id);
623         }
624     }
625     signalIds_.clear();
626 
627     MEDIA_LOGD("unref playbin start");
628     if (playbin_ != nullptr) {
629         (void)gst_element_set_state(GST_ELEMENT_CAST(playbin_), GST_STATE_NULL);
630         gst_object_unref(playbin_);
631         playbin_ = nullptr;
632     }
633     MEDIA_LOGD("unref playbin stop");
634 
635     MEDIA_LOGD("ExitInitializedState exit");
636 }
637 
PrepareAsyncInternal()638 int32_t PlayBinCtrlerBase::PrepareAsyncInternal()
639 {
640     if ((GetCurrState() == preparingState_) || (GetCurrState() == preparedState_)) {
641         MEDIA_LOGI("already at preparing state, skip");
642         return MSERR_OK;
643     }
644 
645     CHECK_AND_RETURN_RET_LOG((!uri_.empty() || appsrcWrap_), MSERR_INVALID_OPERATION, "Set uri firsty!");
646     trackParse_ = PlayerTrackParse::Create();
647     int32_t ret = EnterInitializedState();
648     CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
649 
650     stopBuffering_ = false;
651     auto currState = std::static_pointer_cast<BaseState>(GetCurrState());
652     ret = currState->Prepare();
653     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "PrepareAsyncInternal failed");
654 
655     return MSERR_OK;
656 }
657 
SeekInternal(int64_t timeUs,int32_t seekOption)658 int32_t PlayBinCtrlerBase::SeekInternal(int64_t timeUs, int32_t seekOption)
659 {
660     MEDIA_LOGI("execute seek, time: %{public}" PRIi64 ", option: %{public}d", timeUs, seekOption);
661 
662     int32_t seekFlags = SEEK_OPTION_TO_GST_SEEK_FLAGS.at(seekOption);
663     timeUs = timeUs > duration_ ? duration_ : timeUs;
664     timeUs = timeUs < 0 ? 0 : timeUs;
665 
666     constexpr int32_t usecToNanoSec = 1000;
667     int64_t timeNs = timeUs * usecToNanoSec;
668     seekPos_ = timeUs;
669     isSeeking_ = true;
670     if (videoSink_ == nullptr || seekOption == IPlayBinCtrler::PlayBinSeekMode::CLOSET) {
671         isClosetSeeking_ = true;
672     }
673     GstEvent *event = gst_event_new_seek(rate_, GST_FORMAT_TIME, static_cast<GstSeekFlags>(seekFlags),
674         GST_SEEK_TYPE_SET, timeNs, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE);
675     CHECK_AND_RETURN_RET_LOG(event != nullptr, MSERR_NO_MEMORY, "seek failed");
676 
677     if (videoSink_ != nullptr) {
678         gboolean ret = gst_element_send_event(GST_ELEMENT_CAST(playbin_), event);
679         CHECK_AND_RETURN_RET_LOG(ret, MSERR_SEEK_FAILED, "seek failed");
680     } else {
681         seekFuture_ = std::async(std::launch::async, [this, event]() -> gboolean {
682             gboolean ret = FALSE;
683             CHECK_AND_RETURN_RET_LOG(playbin_ != nullptr, FALSE, "playbin is nullptr");
684             pthread_setname_np(pthread_self(), "AudioAsyncSeek");
685             MEDIA_LOGI("audio seek start");
686             ret = gst_element_send_event(GST_ELEMENT_CAST(playbin_), event);
687             MEDIA_LOGI("audio seek end");
688             return ret;
689         });
690     }
691     return MSERR_OK;
692 }
693 
SetupInterruptEventCb()694 void PlayBinCtrlerBase::SetupInterruptEventCb()
695 {
696     PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
697     CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
698 
699     gulong id = g_signal_connect_data(audioSink_, "interrupt-event",
700         G_CALLBACK(&PlayBinCtrlerBase::OnInterruptEventCb), wrapper,
701         (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
702     CheckAndAddSignalIds(id, wrapper, audioSink_);
703 }
704 
SetupAudioSegmentEventCb()705 void PlayBinCtrlerBase::SetupAudioSegmentEventCb()
706 {
707     PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
708     CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
709 
710     gulong id = g_signal_connect_data(audioSink_, "segment-updated",
711         G_CALLBACK(&PlayBinCtrlerBase::OnAudioSegmentEventCb), wrapper,
712         (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
713     CheckAndAddSignalIds(id, wrapper, audioSink_);
714 }
715 
SetupAudioDiedEventCb()716 void PlayBinCtrlerBase::SetupAudioDiedEventCb()
717 {
718     PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
719     CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
720 
721     gulong id = g_signal_connect_data(audioSink_, "audio-service-died",
722         G_CALLBACK(&PlayBinCtrlerBase::OnAudioDiedEventCb), wrapper,
723         (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
724     CheckAndAddSignalIds(id, wrapper, audioSink_);
725 }
726 
SetupCustomElement()727 void PlayBinCtrlerBase::SetupCustomElement()
728 {
729     // There may be a risk of data competition, but the sinkProvider is unlikely to be reconfigured.
730     if (sinkProvider_ != nullptr) {
731         audioSink_ = sinkProvider_->CreateAudioSink();
732         if (audioSink_ != nullptr) {
733             g_object_set(playbin_, "audio-sink", audioSink_, nullptr);
734             SetupInterruptEventCb();
735             SetupAudioSegmentEventCb();
736             SetupAudioDiedEventCb();
737         }
738         videoSink_ = sinkProvider_->CreateVideoSink();
739         if (videoSink_ != nullptr) {
740             g_object_set(playbin_, "video-sink", videoSink_, nullptr);
741         } else if (audioSink_ != nullptr) {
742             g_object_set(playbin_, "video-sink", audioSink_, nullptr);
743         }
744         auto msgNotifier = std::bind(&PlayBinCtrlerBase::OnSinkMessageReceived, this, std::placeholders::_1);
745         sinkProvider_->SetMsgNotifier(msgNotifier);
746     } else {
747         MEDIA_LOGD("no sinkprovider, delay the sink selection until the playbin enters pause state.");
748     }
749 
750     if ((renderMode_ & PlayBinRenderMode::NATIVE_STREAM) == 0) {
751         GstElement *audioFilter = gst_element_factory_make("scaletempo", "scaletempo");
752         if (audioFilter != nullptr) {
753             g_object_set(playbin_, "audio-filter", audioFilter, nullptr);
754         } else {
755             MEDIA_LOGD("can not create scaletempo, the audio playback speed can not be adjusted");
756         }
757     }
758 }
759 
SetupSourceSetupSignal()760 void PlayBinCtrlerBase::SetupSourceSetupSignal()
761 {
762     PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
763     CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
764 
765     gulong id = g_signal_connect_data(playbin_, "source-setup",
766         G_CALLBACK(&PlayBinCtrlerBase::SourceSetup), wrapper, (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory,
767         static_cast<GConnectFlags>(0));
768     CheckAndAddSignalIds(id, wrapper, GST_ELEMENT_CAST(playbin_));
769 }
770 
SetupSignalMessage()771 int32_t PlayBinCtrlerBase::SetupSignalMessage()
772 {
773     MEDIA_LOGD("SetupSignalMessage enter");
774 
775     PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
776     CHECK_AND_RETURN_RET_LOG(wrapper != nullptr, MSERR_NO_MEMORY, "can not create this wrapper");
777 
778     gulong id = g_signal_connect_data(playbin_, "element-setup",
779         G_CALLBACK(&PlayBinCtrlerBase::ElementSetup), wrapper, (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory,
780         static_cast<GConnectFlags>(0));
781     CheckAndAddSignalIds(id, wrapper, GST_ELEMENT_CAST(playbin_));
782 
783     PlayBinCtrlerWrapper *wrap = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
784     CHECK_AND_RETURN_RET_LOG(wrap != nullptr, MSERR_NO_MEMORY, "can not create this wrapper");
785     id = g_signal_connect_data(playbin_, "audio-changed", G_CALLBACK(&PlayBinCtrlerBase::AudioChanged),
786         wrap, (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
787     CheckAndAddSignalIds(id, wrap, GST_ELEMENT_CAST(playbin_));
788 
789     GstBus *bus = gst_pipeline_get_bus(playbin_);
790     CHECK_AND_RETURN_RET_LOG(bus != nullptr, MSERR_UNKNOWN, "can not get bus");
791 
792     auto msgNotifier = std::bind(&PlayBinCtrlerBase::OnMessageReceived, this, std::placeholders::_1);
793     msgProcessor_ = std::make_unique<GstMsgProcessor>(*bus, msgNotifier);
794 
795     gst_object_unref(bus);
796     bus = nullptr;
797 
798     int32_t ret = msgProcessor_->Init();
799     CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
800 
801     // only concern the msg from playbin
802     msgProcessor_->AddMsgFilter(ELEM_NAME(GST_ELEMENT_CAST(playbin_)));
803 
804     MEDIA_LOGD("SetupSignalMessage exit");
805     return MSERR_OK;
806 }
807 
SetupElementUnSetupSignal()808 int32_t PlayBinCtrlerBase::SetupElementUnSetupSignal()
809 {
810     MEDIA_LOGD("SetupElementUnSetupSignal enter");
811 
812     PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
813     CHECK_AND_RETURN_RET_LOG(wrapper != nullptr, MSERR_NO_MEMORY, "can not create this wrapper");
814 
815     gulong id = g_signal_connect_data(playbin_, "deep-element-removed",
816         G_CALLBACK(&PlayBinCtrlerBase::ElementUnSetup), wrapper, (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory,
817         static_cast<GConnectFlags>(0));
818     CheckAndAddSignalIds(id, wrapper, GST_ELEMENT_CAST(playbin_));
819 
820     return MSERR_OK;
821 }
822 
QueryDuration()823 void PlayBinCtrlerBase::QueryDuration()
824 {
825     auto state = GetCurrState();
826     if (state != preparedState_ && state != playingState_ && state != pausedState_ &&
827         state != playbackCompletedState_) {
828         MEDIA_LOGE("reuse the last query result: %{public}" PRIi64 " microsecond", duration_);
829         return;
830     }
831 
832     gint64 duration = -1;
833     gboolean ret = gst_element_query_duration(GST_ELEMENT_CAST(playbin_), GST_FORMAT_TIME, &duration);
834     CHECK_AND_RETURN_LOG(ret, "query duration failed");
835 
836     if (duration >= 0) {
837         duration_ = duration / NANO_SEC_PER_USEC;
838     }
839     MEDIA_LOGI("update the duration: %{public}" PRIi64 " microsecond", duration_);
840 }
841 
QueryPosition()842 int64_t PlayBinCtrlerBase::QueryPosition()
843 {
844     gint64 position = 0;
845     gboolean ret = gst_element_query_position(GST_ELEMENT_CAST(playbin_), GST_FORMAT_TIME, &position);
846     if (!ret) {
847         MEDIA_LOGW("query position failed");
848         return lastTime_ / USEC_PER_MSEC;
849     }
850 
851     int64_t curTime = position / NANO_SEC_PER_USEC;
852     if (duration_ >= 0) {
853         curTime = std::min(curTime, duration_);
854     }
855     lastTime_ = curTime;
856     MEDIA_LOGI("update the position: %{public}" PRIi64 " microsecond", curTime);
857     return curTime / USEC_PER_MSEC;
858 }
859 
ProcessEndOfStream()860 void PlayBinCtrlerBase::ProcessEndOfStream()
861 {
862     MEDIA_LOGD("End of stream");
863     isDuration_ = true;
864 
865     if (!enableLooping_.load() && !isSeeking_) { // seek duration done->seeking->eos
866         ChangeState(playbackCompletedState_);
867     }
868 }
869 
DoInitializeForDataSource()870 int32_t PlayBinCtrlerBase::DoInitializeForDataSource()
871 {
872     if (appsrcWrap_ != nullptr) {
873         (void)appsrcWrap_->Prepare();
874         if (isInitialized_) {
875             return MSERR_OK;
876         }
877         auto msgNotifier = std::bind(&PlayBinCtrlerBase::OnAppsrcMessageReceived, this, std::placeholders::_1);
878         CHECK_AND_RETURN_RET_LOG(appsrcWrap_->SetCallback(msgNotifier) == MSERR_OK,
879             MSERR_INVALID_OPERATION, "set appsrc error callback failed");
880 
881         g_object_set(playbin_, "uri", "appsrc://", nullptr);
882     }
883     return MSERR_OK;
884 }
885 
GetVideoTrackInfo(std::vector<Format> & videoTrack)886 int32_t PlayBinCtrlerBase::GetVideoTrackInfo(std::vector<Format> &videoTrack)
887 {
888     std::unique_lock<std::mutex> lock(mutex_);
889     CHECK_AND_RETURN_RET_LOG(trackParse_ != nullptr, MSERR_INVALID_OPERATION, "trackParse_ is nullptr");
890     return trackParse_->GetVideoTrackInfo(videoTrack);
891 }
892 
GetAudioTrackInfo(std::vector<Format> & audioTrack)893 int32_t PlayBinCtrlerBase::GetAudioTrackInfo(std::vector<Format> &audioTrack)
894 {
895     std::unique_lock<std::mutex> lock(mutex_);
896     CHECK_AND_RETURN_RET_LOG(trackParse_ != nullptr, MSERR_INVALID_OPERATION, "trackParse_ is nullptr");
897     return trackParse_->GetAudioTrackInfo(audioTrack);
898 }
899 
GetSubtitleTrackInfo(std::vector<Format> & subtitleTrack)900 int32_t PlayBinCtrlerBase::GetSubtitleTrackInfo(std::vector<Format> &subtitleTrack)
901 {
902     std::unique_lock<std::mutex> lock(mutex_);
903     CHECK_AND_RETURN_RET_LOG(trackParse_ != nullptr, MSERR_INVALID_OPERATION, "trackParse_ is nullptr");
904     return trackParse_->GetSubtitleTrackInfo(subtitleTrack);
905 }
906 
SelectTrack(int32_t index)907 int32_t PlayBinCtrlerBase::SelectTrack(int32_t index)
908 {
909     std::unique_lock<std::mutex> lock(mutex_);
910     ON_SCOPE_EXIT(0) {
911         OnTrackDone();
912     };
913 
914     CHECK_AND_RETURN_RET_LOG(trackParse_ != nullptr, MSERR_INVALID_OPERATION, "trackParse_ is nullptr");
915     int32_t trackType = -1;
916     int32_t innerIndex = -1;
917     int32_t ret = trackParse_->GetTrackInfo(index, innerIndex, trackType);
918     CHECK_AND_RETURN_RET(ret == MSERR_OK, (OnError(ret, "Invalid track index!"), ret));
919     CHECK_AND_RETURN_RET(innerIndex >= 0,
920         (OnError(MSERR_INVALID_OPERATION, "This track is currently not supported!"), MSERR_INVALID_OPERATION));
921 
922     if (trackType == MediaType::MEDIA_TYPE_AUD) {
923         ret = MSERR_INVALID_OPERATION;
924         CHECK_AND_RETURN_RET(GetCurrState() == preparedState_,
925             (OnError(ret, "Audio tracks can only be selected in the prepared state!"), ret));
926 
927         int32_t currentIndex = -1;
928         g_object_get(playbin_, "current-audio", &currentIndex, nullptr);
929         CHECK_AND_RETURN_RET(innerIndex != currentIndex,
930             (OnError(MSERR_OK, "This track has already been selected!"), MSERR_OK));
931 
932         lastStartTime_ = gst_element_get_start_time(GST_ELEMENT_CAST(playbin_));
933         g_object_set(playbin_, "current-audio", innerIndex, nullptr);
934         // The seek operation clears the original audio data and re parses the new track data.
935         isTrackChanging_ = true;
936         trackChangeType_ = MediaType::MEDIA_TYPE_AUD;
937         SeekInternal(seekPos_, IPlayBinCtrler::PlayBinSeekMode::CLOSET_SYNC);
938         CANCEL_SCOPE_EXIT_GUARD(0);
939     } else if (trackType == MediaType::MEDIA_TYPE_SUBTITLE) {
940         int32_t currentIndex = -1;
941         g_object_get(playbin_, "current-text", &currentIndex, nullptr);
942         CHECK_AND_RETURN_RET((!hasSubtitleTrackSelected_ || innerIndex != currentIndex),
943             (OnError(MSERR_OK, "This track has already been selected!"), MSERR_OK));
944 
945         MEDIA_LOGI("start select subtitle track %{public}d", index);
946         isTrackChanging_ = true;
947         trackChangeType_ = MediaType::MEDIA_TYPE_SUBTITLE;
948         g_object_set(subtitleSink_, "change-track", true, nullptr);
949         lastStartTime_ = gst_element_get_start_time(GST_ELEMENT_CAST(playbin_));
950         gst_element_set_start_time(GST_ELEMENT_CAST(playbin_), GST_CLOCK_TIME_NONE);
951         g_object_set(playbin_, "current-text", innerIndex, nullptr);
952         hasSubtitleTrackSelected_ = true;
953         g_object_set(subtitleSink_, "enable-display", hasSubtitleTrackSelected_, nullptr);
954         CANCEL_SCOPE_EXIT_GUARD(0);
955     } else {
956         OnError(MSERR_INVALID_VAL, "The track type does not support this operation!");
957         return MSERR_INVALID_OPERATION;
958     }
959     return MSERR_OK;
960 }
961 
DeselectTrack(int32_t index)962 int32_t PlayBinCtrlerBase::DeselectTrack(int32_t index)
963 {
964     std::unique_lock<std::mutex> lock(mutex_);
965     ON_SCOPE_EXIT(0) {
966         OnTrackDone();
967     };
968 
969     CHECK_AND_RETURN_RET_LOG(trackParse_ != nullptr, MSERR_INVALID_OPERATION, "trackParse_ is nullptr");
970     int32_t trackType = -1;
971     int32_t innerIndex = -1;
972     int32_t ret = trackParse_->GetTrackInfo(index, innerIndex, trackType);
973     CHECK_AND_RETURN_RET(ret == MSERR_OK, (OnError(ret, "Invalid track index!"), ret));
974     CHECK_AND_RETURN_RET(innerIndex >= 0,
975         (OnError(MSERR_INVALID_OPERATION, "This track has not been selected yet!"), MSERR_INVALID_OPERATION));
976 
977     if (trackType == MediaType::MEDIA_TYPE_AUD) {
978         ret = MSERR_INVALID_OPERATION;
979         CHECK_AND_RETURN_RET(GetCurrState() == preparedState_,
980             (OnError(ret, "Audio tracks can only be deselected in the prepared state!"), ret));
981 
982         int32_t currentIndex = -1;
983         g_object_get(playbin_, "current-audio", &currentIndex, nullptr);
984         CHECK_AND_RETURN_RET(innerIndex == currentIndex,
985             (OnError(ret, "This track has not been selected yet!"), ret));
986 
987         CHECK_AND_RETURN_RET(currentIndex != 0,
988             (OnError(MSERR_OK, "The current audio track is already the default track!"), MSERR_OK));
989 
990         g_object_set(playbin_, "current-audio", 0, nullptr); // 0 is the default track
991         // The seek operation clears the original audio data and re parses the new track data.
992         isTrackChanging_ = true;
993         trackChangeType_ = MediaType::MEDIA_TYPE_AUD;
994         SeekInternal(seekPos_, IPlayBinCtrler::PlayBinSeekMode::CLOSET_SYNC);
995         CANCEL_SCOPE_EXIT_GUARD(0);
996     } else if (trackType == MediaType::MEDIA_TYPE_SUBTITLE) {
997         ret = MSERR_INVALID_OPERATION;
998         int32_t currentIndex = -1;
999         g_object_get(playbin_, "current-text", &currentIndex, nullptr);
1000         CHECK_AND_RETURN_RET((hasSubtitleTrackSelected_ && innerIndex == currentIndex),
1001             (OnError(ret, "This track has not been selected yet!"), ret));
1002 
1003         hasSubtitleTrackSelected_ = false;
1004         g_object_set(subtitleSink_, "enable-display", hasSubtitleTrackSelected_, nullptr);
1005         trackChangeType_ = MediaType::MEDIA_TYPE_SUBTITLE;
1006         ReportTrackChange();
1007         CANCEL_SCOPE_EXIT_GUARD(0);
1008     } else {
1009         OnError(MSERR_INVALID_VAL, "The track type does not support this operation!");
1010         return MSERR_INVALID_VAL;
1011     }
1012     return MSERR_OK;
1013 }
1014 
GetCurrentTrack(int32_t trackType,int32_t & index)1015 int32_t PlayBinCtrlerBase::GetCurrentTrack(int32_t trackType, int32_t &index)
1016 {
1017     std::unique_lock<std::mutex> lock(mutex_);
1018     MEDIA_LOGI("GetCurrentTrack in");
1019     CHECK_AND_RETURN_RET(trackParse_ != nullptr, MSERR_INVALID_OPERATION);
1020     int32_t innerIndex = -1;
1021     if (trackType == MediaType::MEDIA_TYPE_AUD) {
1022         if (isTrackChanging_) {
1023             // During the change track process, return the original value.
1024             innerIndex = audioIndex_;
1025         } else {
1026             g_object_get(playbin_, "current-audio", &innerIndex, nullptr);
1027         }
1028     } else if (trackType == MediaType::MEDIA_TYPE_VID) {
1029         g_object_get(playbin_, "current-video", &innerIndex, nullptr);
1030     } else {
1031         if (hasSubtitleTrackSelected_) {
1032             g_object_get(playbin_, "current-text", &innerIndex, nullptr);
1033         } else {
1034             innerIndex = -1;
1035         }
1036     }
1037 
1038     if (innerIndex >= 0) {
1039         return trackParse_->GetTrackIndex(innerIndex, trackType, index);
1040     } else {
1041         // There are no tracks currently playing, return to -1.
1042         index = innerIndex;
1043         return MSERR_OK;
1044     }
1045 }
1046 
HandleCacheCtrl(int32_t percent)1047 void PlayBinCtrlerBase::HandleCacheCtrl(int32_t percent)
1048 {
1049     MEDIA_LOGI("HandleCacheCtrl percent is %{public}d", percent);
1050     if (!isBuffering_) {
1051         HandleCacheCtrlWhenNoBuffering(percent);
1052     } else {
1053         HandleCacheCtrlWhenBuffering(percent);
1054     }
1055 }
1056 
HandleCacheCtrlCb(const InnerMessage & msg)1057 void PlayBinCtrlerBase::HandleCacheCtrlCb(const InnerMessage &msg)
1058 {
1059     if (isNetWorkPlay_) {
1060         cachePercent_ = msg.detail1;
1061         HandleCacheCtrl(cachePercent_);
1062     }
1063 }
1064 
HandleCacheCtrlWhenNoBuffering(int32_t percent)1065 void PlayBinCtrlerBase::HandleCacheCtrlWhenNoBuffering(int32_t percent)
1066 {
1067     if (isSelectBitRate_) {
1068         MEDIA_LOGD("switch bitrate, just return");
1069         return;
1070     }
1071     if (percent < static_cast<float>(BUFFER_LOW_PERCENT_DEFAULT) / BUFFER_HIGH_PERCENT_DEFAULT *
1072         BUFFER_PERCENT_THRESHOLD) {
1073         // percent<25% buffering start
1074         PlayBinMessage msg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BUFFERING_START, 0, {} };
1075         ReportMessage(msg);
1076 
1077         // percent<25% buffering percent
1078         PlayBinMessage percentMsg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BUFFERING_PERCENT, percent, {} };
1079         ReportMessage(percentMsg);
1080 
1081         isBuffering_ = true;
1082         if (!SetPlayerState(GST_PLAYER_STATUS_BUFFERING)) {
1083             MEDIA_LOGD("Stopping, just return");
1084             return;
1085         }
1086 
1087         if (GetCurrState() == playingState_ && !isSeeking_ && !isRating_ &&
1088             !isAddingSubtitle_ && !isUserSetPause_) {
1089             std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
1090             MEDIA_LOGI("HandleCacheCtrl percent is %{public}d, begin set to paused", percent);
1091             GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT_CAST(playbin_), GST_STATE_PAUSED);
1092             if (ret == GST_STATE_CHANGE_FAILURE) {
1093                 MEDIA_LOGE("Failed to change playbin's state to GST_STATE_PAUSED");
1094                 return;
1095             }
1096         }
1097     }
1098 }
1099 
HandleCacheCtrlWhenBuffering(int32_t percent)1100 void PlayBinCtrlerBase::HandleCacheCtrlWhenBuffering(int32_t percent)
1101 {
1102     // 0% < percent < 100% buffering percent
1103     PlayBinMessage percentMsg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BUFFERING_PERCENT, percent, {} };
1104     ReportMessage(percentMsg);
1105 
1106     // percent > 100% buffering end
1107     if (percent >= BUFFER_PERCENT_THRESHOLD) {
1108         isBuffering_ = false;
1109         if (GetCurrState() == playingState_ && !isUserSetPause_) {
1110             if (!SetPlayerState(GST_PLAYER_STATUS_PLAYING)) {
1111                 MEDIA_LOGD("Stopping, just return");
1112                 return;
1113             }
1114             std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
1115             MEDIA_LOGI("percent is %{public}d, begin set to playing", percent);
1116             GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT_CAST(playbin_), GST_STATE_PLAYING);
1117             if (ret == GST_STATE_CHANGE_FAILURE) {
1118                 MEDIA_LOGE("Failed to change playbin's state to GST_STATE_PLAYING");
1119                 return;
1120             }
1121         } else {
1122             if (!SetPlayerState(GST_PLAYER_STATUS_PAUSED)) {
1123                 MEDIA_LOGD("Stopping, just return");
1124                 return;
1125             }
1126         }
1127 
1128         PlayBinMessage msg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BUFFERING_END, 0, {} };
1129         ReportMessage(msg);
1130     }
1131 }
1132 
RemoveGstPlaySinkVideoConvertPlugin()1133 void PlayBinCtrlerBase::RemoveGstPlaySinkVideoConvertPlugin()
1134 {
1135     uint32_t flags = 0;
1136 
1137     CHECK_AND_RETURN_LOG(playbin_ != nullptr, "playbin_ is nullptr");
1138     g_object_get(playbin_, "flags", &flags, nullptr);
1139     flags |= (GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_HARDWARE_VIDEO);
1140     flags &= ~GST_PLAY_FLAG_SOFT_COLORBALANCE;
1141     MEDIA_LOGD("set gstplaysink flags %{public}d", flags);
1142     // set playsink remove GstPlaySinkVideoConvert, for first-frame performance optimization
1143     g_object_set(playbin_, "flags", flags, nullptr);
1144 }
1145 
AutoPlugSort(const GstElement * uriDecoder,GstPad * pad,GstCaps * caps,GValueArray * factories,gpointer userData)1146 GValueArray *PlayBinCtrlerBase::AutoPlugSort(const GstElement *uriDecoder, GstPad *pad, GstCaps *caps,
1147     GValueArray *factories, gpointer userData)
1148 {
1149     CHECK_AND_RETURN_RET_LOG(uriDecoder != nullptr, nullptr, "uriDecoder is null");
1150     CHECK_AND_RETURN_RET_LOG(pad != nullptr, nullptr, "pad is null");
1151     CHECK_AND_RETURN_RET_LOG(caps != nullptr, nullptr, "caps is null");
1152     CHECK_AND_RETURN_RET_LOG(factories != nullptr, nullptr, "factories is null");
1153 
1154     auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1155     CHECK_AND_RETURN_RET_LOG(thizStrong != nullptr, nullptr, "thizStrong is null");
1156     return thizStrong->OnAutoPlugSort(*factories);
1157 }
OnAutoPlugSort(GValueArray & factories)1158 GValueArray *PlayBinCtrlerBase::OnAutoPlugSort(GValueArray &factories)
1159 {
1160     MEDIA_LOGD("OnAutoPlugSort");
1161 
1162     decltype(autoPlugSortListener_) listener = nullptr;
1163     {
1164         std::unique_lock<std::mutex> lock(listenerMutex_);
1165         listener = autoPlugSortListener_;
1166     }
1167 
1168     if (listener != nullptr) {
1169         return listener(factories);
1170     }
1171     return nullptr;
1172 }
1173 
OnSourceSetup(const GstElement * playbin,GstElement * src,const std::shared_ptr<PlayBinCtrlerBase> & playbinCtrl)1174 void PlayBinCtrlerBase::OnSourceSetup(const GstElement *playbin, GstElement *src,
1175     const std::shared_ptr<PlayBinCtrlerBase> &playbinCtrl)
1176 {
1177     (void)playbin;
1178     CHECK_AND_RETURN_LOG(playbinCtrl != nullptr, "playbinCtrl is null");
1179     CHECK_AND_RETURN_LOG(src != nullptr, "src is null");
1180 
1181     GstElementFactory *elementFac = gst_element_get_factory(src);
1182     const gchar *eleTypeName = g_type_name(gst_element_factory_get_element_type(elementFac));
1183     CHECK_AND_RETURN_LOG(eleTypeName != nullptr, "eleTypeName is nullptr");
1184 
1185     std::unique_lock<std::mutex> appsrcLock(appsrcMutex_);
1186     if ((strstr(eleTypeName, "GstAppSrc") != nullptr) && (playbinCtrl->appsrcWrap_ != nullptr)) {
1187         g_object_set(src, "datasrc-mode", true, nullptr);
1188         (void)playbinCtrl->appsrcWrap_->SetAppsrc(src);
1189     } else if (strstr(eleTypeName, "GstCurlHttpSrc") != nullptr) {
1190         g_object_set(src, "ssl-ca-file", "/etc/ssl/certs/cacert.pem", nullptr);
1191         MEDIA_LOGI("setup curl_http ca_file done");
1192     }
1193 }
1194 
OnVideoDecoderSetup(GstElement & elem)1195 bool PlayBinCtrlerBase::OnVideoDecoderSetup(GstElement &elem)
1196 {
1197     const gchar *metadata = gst_element_get_metadata(&elem, GST_ELEMENT_METADATA_KLASS);
1198     if (metadata == nullptr) {
1199         MEDIA_LOGE("gst_element_get_metadata return nullptr");
1200         return false;
1201     }
1202 
1203     std::string metaStr(metadata);
1204     if (metaStr.find("Decoder/Video") != std::string::npos) {
1205         return true;
1206     }
1207 
1208     return false;
1209 }
1210 
OnIsLiveStream(const GstElement * demux,gboolean isLiveStream,gpointer userData)1211 void PlayBinCtrlerBase::OnIsLiveStream(const GstElement *demux, gboolean isLiveStream, gpointer userData)
1212 {
1213     (void)demux;
1214     MEDIA_LOGI("is live stream: %{public}d", isLiveStream);
1215     auto thizStrong  = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1216     if (isLiveStream) {
1217         PlayBinMessage msg { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_IS_LIVE_STREAM, 0, {} };
1218         thizStrong->ReportMessage(msg);
1219     }
1220 }
1221 
OnAdaptiveElementSetup(GstElement & elem)1222 void PlayBinCtrlerBase::OnAdaptiveElementSetup(GstElement &elem)
1223 {
1224     const gchar *metadata = gst_element_get_metadata(&elem, GST_ELEMENT_METADATA_KLASS);
1225     if (metadata == nullptr) {
1226         return;
1227     }
1228 
1229     std::string metaStr(metadata);
1230     if (metaStr.find("Demuxer/Adaptive") == std::string::npos) {
1231         return;
1232     }
1233     MEDIA_LOGI("get element_name %{public}s, get metadata %{public}s", GST_ELEMENT_NAME(&elem), metadata);
1234     PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
1235     CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
1236     gulong id = g_signal_connect_data(&elem, "is-live-scene", G_CALLBACK(&PlayBinCtrlerBase::OnIsLiveStream), wrapper,
1237         (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
1238     CheckAndAddSignalIds(id, wrapper, &elem);
1239 }
1240 
OnElementSetup(GstElement & elem)1241 void PlayBinCtrlerBase::OnElementSetup(GstElement &elem)
1242 {
1243     MEDIA_LOGI("element setup: %{public}s", ELEM_NAME(&elem));
1244     // limit to the g-signal, send this notification at this thread, do not change the work thread.
1245     // otherwise ,the avmetaengine will work improperly.
1246 
1247     if (OnVideoDecoderSetup(elem) || strncmp(ELEM_NAME(&elem), "multiqueue", strlen("multiqueue")) == 0 ||
1248         strncmp(ELEM_NAME(&elem), "qtdemux", strlen("qtdemux")) == 0) {
1249         MEDIA_LOGI("add msgfilter element: %{public}s", ELEM_NAME(&elem));
1250         msgProcessor_->AddMsgFilter(ELEM_NAME(&elem));
1251     }
1252 
1253     OnAdaptiveElementSetup(elem);
1254     std::string elementName(GST_ELEMENT_NAME(&elem));
1255     if (isNetWorkPlay_ == false && elementName.find("uridecodebin") != std::string::npos) {
1256         PlayBinCtrlerWrapper *wrapper = new(std::nothrow) PlayBinCtrlerWrapper(shared_from_this());
1257         CHECK_AND_RETURN_LOG(wrapper != nullptr, "can not create this wrapper");
1258         gulong id = g_signal_connect_data(&elem, "autoplug-sort",
1259             G_CALLBACK(&PlayBinCtrlerBase::AutoPlugSort), wrapper,
1260             (GClosureNotify)&PlayBinCtrlerWrapper::OnDestory, static_cast<GConnectFlags>(0));
1261         CheckAndAddSignalIds(id, wrapper, &elem);
1262     }
1263 
1264     if (trackParse_ != nullptr) {
1265         trackParse_->OnElementSetup(elem);
1266     }
1267 
1268     decltype(elemSetupListener_) listener = nullptr;
1269     {
1270         std::unique_lock<std::mutex> lock(listenerMutex_);
1271         listener = elemSetupListener_;
1272     }
1273 
1274     if (listener != nullptr) {
1275         listener(elem);
1276     }
1277 }
1278 
OnElementUnSetup(GstElement & elem)1279 void PlayBinCtrlerBase::OnElementUnSetup(GstElement &elem)
1280 {
1281     MEDIA_LOGI("element unsetup: %{public}s", ELEM_NAME(&elem));
1282     if (trackParse_ != nullptr) {
1283         trackParse_->OnElementUnSetup(elem);
1284     }
1285 
1286     decltype(elemUnSetupListener_) listener = nullptr;
1287     {
1288         std::unique_lock<std::mutex> lock(listenerMutex_);
1289         listener = elemUnSetupListener_;
1290     }
1291 
1292     if (listener != nullptr) {
1293         listener(elem);
1294     }
1295     RemoveSignalIds(&elem);
1296 }
1297 
OnInterruptEventCb(const GstElement * audioSink,const uint32_t eventType,const uint32_t forceType,const uint32_t hintType,gpointer userData)1298 void PlayBinCtrlerBase::OnInterruptEventCb(const GstElement *audioSink, const uint32_t eventType,
1299     const uint32_t forceType, const uint32_t hintType, gpointer userData)
1300 {
1301     (void)audioSink;
1302     auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1303     CHECK_AND_RETURN(thizStrong != nullptr);
1304     uint32_t value = 0;
1305     value = (((eventType << INTERRUPT_EVENT_SHIFT) | forceType) << INTERRUPT_EVENT_SHIFT) | hintType;
1306     PlayBinMessage msg { PLAYBIN_MSG_AUDIO_SINK, PLAYBIN_MSG_INTERRUPT_EVENT, 0, value };
1307     thizStrong->ReportMessage(msg);
1308 }
1309 
OnAudioSegmentEventCb(const GstElement * audioSink,gpointer userData)1310 void PlayBinCtrlerBase::OnAudioSegmentEventCb(const GstElement *audioSink, gpointer userData)
1311 {
1312     (void)audioSink;
1313     auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1314     CHECK_AND_RETURN(thizStrong != nullptr);
1315     if (thizStrong->subtitleSink_ != nullptr) {
1316         g_object_set(G_OBJECT(thizStrong->subtitleSink_), "segment-updated", TRUE, nullptr);
1317     }
1318 }
1319 
OnAudioDiedEventCb(const GstElement * audioSink,gpointer userData)1320 void PlayBinCtrlerBase::OnAudioDiedEventCb(const GstElement *audioSink, gpointer userData)
1321 {
1322     (void)audioSink;
1323     auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1324     CHECK_AND_RETURN(thizStrong != nullptr);
1325     MEDIA_LOGE("audio service died callback");
1326     PlayBinMessage msg {
1327         PLAYBIN_MSG_ERROR,
1328         PlayBinMsgErrorSubType::PLAYBIN_SUB_MSG_ERROR_WITH_MESSAGE,
1329         MSERR_AUD_RENDER_FAILED,
1330         std::string("audio service died!")
1331     };
1332     thizStrong->ReportMessage(msg);
1333 }
1334 
OnBitRateParseCompleteCb(const GstElement * playbin,uint32_t * bitrateInfo,uint32_t bitrateNum,gpointer userData)1335 void PlayBinCtrlerBase::OnBitRateParseCompleteCb(const GstElement *playbin, uint32_t *bitrateInfo,
1336     uint32_t bitrateNum, gpointer userData)
1337 {
1338     (void)playbin;
1339     auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1340     CHECK_AND_RETURN(thizStrong != nullptr);
1341     MEDIA_LOGD("bitrateNum = %{public}u", bitrateNum);
1342     for (uint32_t i = 0; i < bitrateNum; i++) {
1343         MEDIA_LOGD("bitrate = %{public}u", bitrateInfo[i]);
1344         thizStrong->bitRateVec_.push_back(bitrateInfo[i]);
1345     }
1346     Format format;
1347     (void)format.PutBuffer(std::string(PlayerKeys::PLAYER_BITRATE),
1348         static_cast<uint8_t *>(static_cast<void *>(bitrateInfo)), bitrateNum * sizeof(uint32_t));
1349     PlayBinMessage msg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BITRATE_COLLECT, 0, format };
1350     thizStrong->ReportMessage(msg);
1351 }
1352 
AudioChanged(const GstElement * playbin,gpointer userData)1353 void PlayBinCtrlerBase::AudioChanged(const GstElement *playbin, gpointer userData)
1354 {
1355     (void)playbin;
1356     auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1357     CHECK_AND_RETURN(thizStrong != nullptr);
1358     thizStrong->OnAudioChanged();
1359 }
1360 
OnAudioChanged()1361 void PlayBinCtrlerBase::OnAudioChanged()
1362 {
1363     CHECK_AND_RETURN(playbin_ != nullptr && trackParse_ != nullptr);
1364     if (!trackParse_->FindTrackInfo()) {
1365         MEDIA_LOGI("The plugin has been cleared, no need to report it");
1366         return;
1367     }
1368 
1369     int32_t audioIndex = -1;
1370     g_object_get(playbin_, "current-audio", &audioIndex, nullptr);
1371     MEDIA_LOGI("AudioChanged, current-audio %{public}d", audioIndex);
1372     if (audioIndex == audioIndex_) {
1373         MEDIA_LOGI("Audio Not Changed");
1374         return;
1375     }
1376 
1377     if (isTrackChanging_) {
1378         MEDIA_LOGI("Waiting for the seek event to complete, not reporting at this time!");
1379         return;
1380     }
1381 
1382     audioIndex_ = audioIndex;
1383     int32_t index;
1384     CHECK_AND_RETURN(trackParse_->GetTrackIndex(audioIndex, MediaType::MEDIA_TYPE_AUD, index) == MSERR_OK);
1385 
1386     if (GetCurrState() == preparingState_) {
1387         MEDIA_LOGI("defaule audio index %{public}d, inner index %{public}d", index, audioIndex);
1388         Format format;
1389         (void)format.PutIntValue(std::string(PlayerKeys::PLAYER_TRACK_INDEX), index);
1390         (void)format.PutIntValue(std::string(PlayerKeys::PLAYER_TRACK_TYPE), MediaType::MEDIA_TYPE_AUD);
1391         PlayBinMessage msg = { PlayBinMsgType::PLAYBIN_MSG_SUBTYPE,
1392             PlayBinMsgSubType::PLAYBIN_SUB_MSG_DEFAULE_TRACK, 0, format };
1393         ReportMessage(msg);
1394         return;
1395     }
1396 
1397     Format format;
1398     (void)format.PutIntValue(std::string(PlayerKeys::PLAYER_TRACK_INDEX), index);
1399     (void)format.PutIntValue(std::string(PlayerKeys::PLAYER_IS_SELECT), true);
1400     PlayBinMessage msg = { PlayBinMsgType::PLAYBIN_MSG_SUBTYPE,
1401         PlayBinMsgSubType::PLAYBIN_SUB_MSG_AUDIO_CHANGED, 0, format };
1402     ReportMessage(msg);
1403 }
1404 
OnSubtitleChanged()1405 void PlayBinCtrlerBase::OnSubtitleChanged()
1406 {
1407     CHECK_AND_RETURN(playbin_ != nullptr && trackParse_ != nullptr);
1408     if (!trackParse_->FindTrackInfo()) {
1409         MEDIA_LOGI("The plugin has been cleared, no need to report it");
1410         return;
1411     }
1412 
1413     int32_t index;
1414     if (!hasSubtitleTrackSelected_) {
1415         index = -1;
1416         MEDIA_LOGI("SubtitleChanged, current text: -1");
1417     } else {
1418         int32_t subtitleIndex = -1;
1419         g_object_get(playbin_, "current-text", &subtitleIndex, nullptr);
1420         MEDIA_LOGI("SubtitleChanged, current text: %{public}d", subtitleIndex);
1421         CHECK_AND_RETURN(trackParse_->GetTrackIndex(subtitleIndex, MediaType::MEDIA_TYPE_SUBTITLE, index) == MSERR_OK);
1422     }
1423 
1424     Format format;
1425     (void)format.PutIntValue(std::string(PlayerKeys::PLAYER_TRACK_INDEX), index);
1426     (void)format.PutIntValue(std::string(PlayerKeys::PLAYER_IS_SELECT), true);
1427     PlayBinMessage msg = { PlayBinMsgType::PLAYBIN_MSG_SUBTYPE,
1428         PlayBinMsgSubType::PLAYBIN_SUB_MSG_SUBTITLE_CHANGED, 0, format };
1429     ReportMessage(msg);
1430 }
1431 
ReportTrackChange()1432 void PlayBinCtrlerBase::ReportTrackChange()
1433 {
1434     MEDIA_LOGI("Seek event completed, report track change!");
1435     if (trackChangeType_ == MediaType::MEDIA_TYPE_AUD) {
1436         OnAudioChanged();
1437     } else if (trackChangeType_ == MediaType::MEDIA_TYPE_SUBTITLE) {
1438         OnSubtitleChanged();
1439     }
1440     OnTrackDone();
1441 }
1442 
OnTrackDone()1443 void PlayBinCtrlerBase::OnTrackDone()
1444 {
1445     PlayBinMessage msg = { PlayBinMsgType::PLAYBIN_MSG_SUBTYPE, PlayBinMsgSubType::PLAYBIN_SUB_MSG_TRACK_DONE, 0, {} };
1446     ReportMessage(msg);
1447 }
1448 
OnAddSubDone()1449 void PlayBinCtrlerBase::OnAddSubDone()
1450 {
1451     PlayBinMessage msg = { PlayBinMsgType::PLAYBIN_MSG_SUBTYPE,
1452         PlayBinMsgSubType::PLAYBIN_SUB_MSG_ADD_SUBTITLE_DONE, 0, {} };
1453     ReportMessage(msg);
1454 }
1455 
OnError(int32_t errorCode,std::string message)1456 void PlayBinCtrlerBase::OnError(int32_t errorCode, std::string message)
1457 {
1458     // There is no limit on the number of reports and the state machine is not changed.
1459     PlayBinMessage msg = { PlayBinMsgType::PLAYBIN_MSG_SUBTYPE,
1460         PlayBinMsgSubType::PLAYBIN_SUB_MSG_ONERROR, errorCode, message };
1461     ReportMessage(msg);
1462 }
1463 
OnSelectBitrateDoneCb(const GstElement * playbin,uint32_t bandwidth,gpointer userData)1464 void PlayBinCtrlerBase::OnSelectBitrateDoneCb(const GstElement *playbin, uint32_t bandwidth, gpointer userData)
1465 {
1466     (void)playbin;
1467     auto thizStrong = PlayBinCtrlerWrapper::TakeStrongThiz(userData);
1468     MEDIA_LOGD("OnSelectBitrateDoneCb, Get bandwidth is: %{public}u", bandwidth);
1469     if (thizStrong != nullptr && bandwidth != 0) {
1470         thizStrong->isSelectBitRate_ = false;
1471         thizStrong->connectSpeed_ = bandwidth;
1472         PlayBinMessage msg = { PLAYBIN_MSG_BITRATEDONE, 0, bandwidth, {} };
1473         thizStrong->ReportMessage(msg);
1474     }
1475 }
1476 
OnAppsrcMessageReceived(const InnerMessage & msg)1477 bool PlayBinCtrlerBase::OnAppsrcMessageReceived(const InnerMessage &msg)
1478 {
1479     MEDIA_LOGI("in OnAppsrcMessageReceived");
1480     if (msg.type == INNER_MSG_ERROR) {
1481         PlayBinMessage message { PlayBinMsgType::PLAYBIN_MSG_ERROR,
1482             PlayBinMsgErrorSubType::PLAYBIN_SUB_MSG_ERROR_WITH_MESSAGE,
1483             msg.detail1, msg.extend };
1484         ReportMessage(message);
1485     } else if (msg.type == INNER_MSG_BUFFERING) {
1486         if (msg.detail1 < static_cast<float>(BUFFER_LOW_PERCENT_DEFAULT) / BUFFER_HIGH_PERCENT_DEFAULT *
1487             BUFFER_PERCENT_THRESHOLD) {
1488             CHECK_AND_RETURN_RET_LOG(GetCurrState() == playingState_ && !isSeeking_ && !isRating_ && !isUserSetPause_,
1489                 false, "ignore change to pause");
1490             std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
1491             MEDIA_LOGI("begin set to pause");
1492             GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT_CAST(playbin_), GST_STATE_PAUSED);
1493             if (ret == GST_STATE_CHANGE_FAILURE) {
1494                 MEDIA_LOGE("Failed to change playbin's state to GST_STATE_PAUSED");
1495                 return false;
1496             }
1497         } else if (msg.detail1 >= BUFFER_PERCENT_THRESHOLD) {
1498             CHECK_AND_RETURN_RET_LOG(GetCurrState() == playingState_ && !isUserSetPause_,
1499                 false, "ignore change to playing");
1500             std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
1501             MEDIA_LOGI("begin set to play");
1502             GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT_CAST(playbin_), GST_STATE_PLAYING);
1503             if (ret == GST_STATE_CHANGE_FAILURE) {
1504                 MEDIA_LOGE("Failed to change playbin's state to GST_STATE_PLAYING");
1505                 return false;
1506             }
1507         }
1508     }
1509     return true;
1510 }
1511 
OnMessageReceived(const InnerMessage & msg)1512 void PlayBinCtrlerBase::OnMessageReceived(const InnerMessage &msg)
1513 {
1514     HandleMessage(msg);
1515 }
1516 
OnSinkMessageReceived(const PlayBinMessage & msg)1517 void PlayBinCtrlerBase::OnSinkMessageReceived(const PlayBinMessage &msg)
1518 {
1519     ReportMessage(msg);
1520 }
1521 
SetNotifier(PlayBinMsgNotifier notifier)1522 void PlayBinCtrlerBase::SetNotifier(PlayBinMsgNotifier notifier)
1523 {
1524     std::unique_lock<std::mutex> lock(mutex_);
1525     notifier_ = notifier;
1526 }
1527 
SetAutoSelectBitrate(bool enable)1528 void PlayBinCtrlerBase::SetAutoSelectBitrate(bool enable)
1529 {
1530     if (enable) {
1531         g_object_set(playbin_, "connection-speed", 0, nullptr);
1532     } else if (connectSpeed_ == 0) {
1533         g_object_set(playbin_, "connection-speed", CONNECT_SPEED_DEFAULT, nullptr);
1534     }
1535 }
1536 
ReportMessage(const PlayBinMessage & msg)1537 void PlayBinCtrlerBase::ReportMessage(const PlayBinMessage &msg)
1538 {
1539     if (msg.type == PlayBinMsgType::PLAYBIN_MSG_ERROR) {
1540         MEDIA_LOGE("error happend, error code: %{public}d", msg.code);
1541 
1542         {
1543             std::unique_lock<std::mutex> lock(mutex_);
1544             isErrorHappened_ = true;
1545             preparingCond_.notify_all();
1546             stoppingCond_.notify_all();
1547         }
1548     }
1549 
1550     MEDIA_LOGD("report msg, type: %{public}d", msg.type);
1551 
1552     PlayBinMsgNotifier notifier = notifier_;
1553     if (notifier != nullptr) {
1554         auto msgReportHandler = std::make_shared<TaskHandler<void>>([msg, notifier]() {
1555             LISTENER(notifier(msg), "PlayBinCtrlerBase::ReportMessage", PlayerXCollie::timerTimeout)
1556         });
1557         (void)msgQueue_->EnqueueTask(msgReportHandler);
1558     }
1559 
1560     if (msg.type == PlayBinMsgType::PLAYBIN_MSG_EOS) {
1561         ProcessEndOfStream();
1562     }
1563 }
1564 
CheckAndAddSignalIds(gulong id,PlayBinCtrlerWrapper * wrapper,GstElement * elem)1565 void PlayBinCtrlerBase::CheckAndAddSignalIds(gulong id, PlayBinCtrlerWrapper *wrapper, GstElement *elem)
1566 {
1567     if (id == 0) {
1568         delete wrapper;
1569         MEDIA_LOGW("add signal failed");
1570     } else {
1571         AddSignalIds(elem, id);
1572     }
1573 }
1574 
SetPlayerState(GstPlayerStatus status)1575 bool PlayBinCtrlerBase::SetPlayerState(GstPlayerStatus status)
1576 {
1577     std::unique_lock<std::mutex> stateChangeLock(stateChangePropertyMutex_);
1578     if (stopBuffering_) {
1579         MEDIA_LOGD("Do not set player state when stopping");
1580         return false;
1581     }
1582     std::unique_lock<std::mutex> lock(cacheCtrlMutex_);
1583     g_object_set(playbin_, "state-change", status, nullptr);
1584     return true;
1585 }
1586 } // namespace Media
1587 } // namespace OHOS
1588 
1589