[M120 Migration][HBBTV][MM] Support Preloading feature
[platform/framework/web/chromium-efl.git] / tizen_src / chromium_impl / media / filters / media_player_bridge_capi_tv.cc
1 // Copyright 2023 Samsung Electronics Inc. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/filters/media_player_bridge_capi_tv.h"
6
7 #include "base/strings/string_split.h"
8 #include "media/base/efl/media_player_util_efl.h"
9 #include "tizen_src/chromium_impl/media/filters/media_player_tizen_client.h"
10
11 namespace {
12 const int kSeekableTimeUpdateInterval = 500;
13 }
14
15 static void PlayerPreLoadingCb(void* data) {
16   if (!data) {
17     LOG(ERROR) << "input data is null";
18     return;
19   }
20   media::MediaPlayerBridgeCapiTV* player =
21       static_cast<media::MediaPlayerBridgeCapiTV*>(data);
22   player->OnPlayerPreloading();
23 }
24
25 static void DrmErrorCb(int err_code, char* err_str, void* data) {
26   DCHECK(data);
27   media::MediaPlayerBridgeCapiTV* player =
28       static_cast<media::MediaPlayerBridgeCapiTV*>(data);
29
30   player->OnDrmError(err_code, err_str);
31 }
32
33 namespace media {
34
35 MediaPlayerBridgeCapiTV::MediaPlayerBridgeCapiTV(const GURL& url,
36                                                  const std::string& user_agent,
37                                                  double volume)
38     : MediaPlayerBridgeCapi(url, user_agent, volume), weak_factory_(this) {
39   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
40 }
41
42 MediaPlayerBridgeCapiTV::~MediaPlayerBridgeCapiTV() {
43   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
44   weak_factory_.InvalidateWeakPtrs();
45 }
46
47 void MediaPlayerBridgeCapiTV::SetContentMimeType(const std::string& mime_type) {
48   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
49             << " mime_type : " << mime_type;
50   mime_type_ = mime_type;
51 }
52
53 void MediaPlayerBridgeCapiTV::Prepare() {
54   bool media_resource_acquired = false;
55   std::string translated_url;
56   std::string drm_info;
57
58   if (GetMediaPlayerClient())
59     GetMediaPlayerClient()->NotifyPlaybackState(
60         kPlaybackLoad, player_id_, url_.spec(), mime_type_,
61         &media_resource_acquired, &translated_url, &drm_info);
62
63   LOG(INFO) << "media_resource_acquired: " << media_resource_acquired
64             << ",translated_url:" << translated_url
65             << ",drm_info: " << drm_info;
66
67   if (mime_type_.find("application/vnd.oipf.contentaccessstreaming+xml") !=
68       std::string::npos) {
69     LOG(INFO) << "CASD url,waiting for hbbtv parse the real url and set "
70                  "translated url";
71     return;
72   }
73
74   if (GetMediaPlayerClient() &&
75       GetMediaPlayerClient()->PlaybackNotificationEnabled() &&
76       blink::IsHbbTV()) {
77     if (!SetDrmInfo(drm_info)) {
78       LOG(ERROR) << "SetDrmInfo failed";
79       return;
80     }
81     if (!translated_url.empty())
82       url_ = media::GetCleanURL(translated_url);
83   }
84
85   if (url_.spec().find(".mpd") != std::string::npos)
86     stream_type_ = DASH_STREAM;
87   else if (url_.spec().find(".m3u") != std::string::npos)
88     stream_type_ = HLS_STREAM;
89   else if (mime_type_.find("application/dash+xml") != std::string::npos) {
90     char steaming_type_dash[] = "DASH";
91     char steaming_type_dash_ex[] = "DASHEX";
92     player_set_streaming_type(
93         player_, blink::IsHbbTV() ? steaming_type_dash_ex : steaming_type_dash);
94     stream_type_ = DASH_STREAM;
95   }
96
97   if (blink::IsHbbTV() && CheckHighBitRate() && stream_type_ == DASH_STREAM)
98     AppendUrlHighBitRate(url_.spec());
99   player_prepared_ = false;
100   MediaPlayerBridgeCapi::Prepare();
101   if (GetMediaPlayerClient())
102     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackReady, player_id_);
103 }
104
105 void MediaPlayerBridgeCapiTV::Release() {
106   is_preloaded_ = false;
107   player_prepared_ = false;
108   StopSeekableTimeUpdateTimer();
109   MediaPlayerBridgeCapi::Release();
110   if (GetMediaPlayerClient())
111     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStop, player_id_);
112 }
113
114 bool MediaPlayerBridgeCapiTV::Play() {
115   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
116             << ",current_time:" << GetCurrentTime().InSecondsF();
117
118   // HBBTV run in preloading and preplay mode. If no prepread do prepare
119   // in PlayerPrePlay(), otherwise do normal Play.
120   if (blink::IsHbbTV() && !player_prepared_) {
121     if (!PlayerPrePlay())
122       LOG(ERROR) << "HBBTV prePlay fail.";
123     return false;
124   }
125   if (!MediaPlayerBridgeCapi::Play())
126     return false;
127   if (GetMediaPlayerClient())
128     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStart, player_id_);
129   return true;
130 }
131
132 void MediaPlayerBridgeCapiTV::Pause(bool is_media_related_action) {
133   if (!player_prepared_) {
134     LOG(INFO) << "(" << static_cast<void*>(this)
135               << "), pause while player is not prepared, pause delay";
136     delayed_player_state_ = PLAYER_STATE_DELAYED_PAUSE;
137     return;
138   }
139   MediaPlayerBridgeCapi::Pause(is_media_related_action);
140 }
141
142 void MediaPlayerBridgeCapiTV::PlaybackCompleteUpdate() {
143   MediaPlayerBridgeCapi::PlaybackCompleteUpdate();
144   if (GetMediaPlayerClient())
145     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackFinish, player_id_);
146 }  // namespace media
147
148 void MediaPlayerBridgeCapiTV::PlayerPrepared() {
149   player_prepared_ = true;
150   MediaPlayerBridgeCapi::PlayerPrepared();
151
152   int canSeek = 0;
153   int retVal = player_seek_available(player_, &canSeek);
154   if (retVal == PLAYER_ERROR_NONE && !canSeek)
155     is_player_seek_available_ = false;
156
157   GetAdaptiveStreamingInfo();
158   if (!blink::IsHbbTV() && is_live_stream_) {
159     UpdateSeekableTime();
160     StartSeekableTimeUpdateTimer();
161   }
162 }
163
164 void MediaPlayerBridgeCapiTV::StartSeekableTimeUpdateTimer() {
165   if (!seekable_time_update_timer_.IsRunning()) {
166     seekable_time_update_timer_.Start(
167         FROM_HERE, base::Milliseconds(kSeekableTimeUpdateInterval), this,
168         &MediaPlayerBridgeCapiTV::OnSeekableTimeUpdateTimerFired);
169   }
170 }
171
172 void MediaPlayerBridgeCapiTV::StopSeekableTimeUpdateTimer() {
173   if (seekable_time_update_timer_.IsRunning())
174     seekable_time_update_timer_.Stop();
175 }
176
177 void MediaPlayerBridgeCapiTV::OnSeekableTimeUpdateTimerFired() {
178   UpdateSeekableTime();
179 }
180
181 void MediaPlayerBridgeCapiTV::GetAdaptiveStreamingInfo() {
182   int ret = player_get_adaptive_streaming_info(player_, &is_live_stream_,
183                                                PLAYER_ADAPTIVE_INFO_IS_LIVE);
184   if (ret != PLAYER_ERROR_NONE || is_live_stream_) {
185     LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
186               << " A live stream.";
187   }
188 }
189
190 void MediaPlayerBridgeCapiTV::UpdateSeekableTime() {
191   if (GetPlayerState() == PLAYER_STATE_NONE || !is_live_stream_)
192     return;
193
194   int64_t min = 0, max = 0;
195   if (GetLiveStreamingDuration(&min, &max)) {
196     if (min_seekable_time_.InMilliseconds() != min ||
197         max_seekable_time_.InMilliseconds() != max) {
198       min_seekable_time_ = base::Milliseconds(min);
199       max_seekable_time_ = base::Milliseconds(max);
200       if (GetMediaPlayerClient())
201       GetMediaPlayerClient()->OnSeekableTimeChange(
202           min_seekable_time_, max_seekable_time_, is_live_stream_);
203     }
204
205     return;
206   }
207
208   GetAdaptiveStreamingInfo();
209   if (!is_live_stream_) {
210     LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
211               << " changed to static stream";
212     if (GetMediaPlayerClient())
213       GetMediaPlayerClient()->OnSeekableTimeChange({}, {}, is_live_stream_);
214     MediaPlayerBridgeCapi::UpdateDuration();
215   }
216 }
217
218 bool MediaPlayerBridgeCapiTV::GetLiveStreamingDuration(int64_t* min,
219                                                        int64_t* max) {
220   DCHECK(min);
221   DCHECK(max);
222   constexpr const size_t kDurationBufferSize = 64;
223   char live_duration[kDurationBufferSize] = {
224       0,
225   };
226   char* live_ptr = live_duration;
227   const auto err = player_get_adaptive_streaming_info(
228       player_, live_duration, PLAYER_ADAPTIVE_INFO_LIVE_DURATION);
229   if (err != PLAYER_ERROR_NONE) {
230     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
231                << " |player_get_adaptive_streaming_info| failed " << err;
232     return false;
233   }
234
235   const std::string duration(live_duration);
236   const std::string::size_type delimiter = duration.find('|');
237   if (delimiter == std::string::npos) {
238     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
239                << " Failed to find delimiter | in duration: " << duration;
240     return false;
241   }
242
243   const std::string duration_min = duration.substr(0, delimiter);
244   if (duration_min.empty()) {
245     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
246                << " Failed empty min sub str: " << duration << ", "
247                << delimiter;
248     return false;
249   }
250
251   int64_t out_min = 0;
252   if (!base::StringToInt64(duration_min, &out_min)) {
253     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
254                << " Failed to get min from duration: " << duration;
255     return false;
256   }
257
258   const std::string duration_max = duration.substr(delimiter + 1);
259   if (duration_max.empty()) {
260     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
261                << " empty max sub str: " << duration << ", " << delimiter;
262     return false;
263   }
264
265   int64_t out_max = 0;
266   if (!base::StringToInt64(duration_max, &out_max)) {
267     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
268                << " Failed to get max from duration: " << duration;
269     return false;
270   }
271
272   *min = out_min;
273   *max = out_max;
274   return true;
275 }
276
277 void MediaPlayerBridgeCapiTV::AppendUrlHighBitRate(const std::string& url) {
278   // don't use url.append("|STARTBITRATE=HIGHEST") to get hbbtv url
279   // "|" will be replaced with "%7C"
280   const char high_bitrate[] = "|STARTBITRATE=HIGHEST";
281   int len = url.length() + strlen(high_bitrate) + 1;
282   char* str_url = new char[len];
283   if (!str_url) {
284     return;
285   }
286
287   memset(str_url, 0, len);
288   strncat(str_url, url.c_str(), url.length());
289   strncat(str_url, high_bitrate, strlen(high_bitrate));
290   hbbtv_url_ = str_url;
291   BLINKFREE(str_url);
292   LOG(INFO) << "hbbtv url:" << hbbtv_url_.c_str();
293 }
294
295 bool MediaPlayerBridgeCapiTV::CheckHighBitRate() {
296   if (!GetMediaPlayerClient()) {
297     LOG(ERROR) << "MediaPlayerClient is null";
298     return false;
299   }
300   content::WebContentsDelegate* web_contents_delegate =
301       GetMediaPlayerClient()->GetWebContentsDelegate();
302   if (!web_contents_delegate) {
303     LOG(ERROR) << "get web_contents_delegate fail";
304     return false;
305   }
306   bool ret = web_contents_delegate->IsHighBitRate();
307   LOG(INFO) << "get high bit rate: " << std::boolalpha << ret;
308   return ret;
309 }
310
311 void MediaPlayerBridgeCapiTV::HandleDownloadableFontInfo(
312     const std::string& scheme_id_uri,
313     const std::string& value,
314     const std::string& data,
315     int type) {
316   content::WebContentsDelegate* web_contents_delegate =
317       GetMediaPlayerClient()->GetWebContentsDelegate();
318   if (!web_contents_delegate)
319     return;
320   web_contents_delegate->NotifyDownloadableFontInfo(scheme_id_uri, value, data,
321                                                     type);
322 }
323
324 bool MediaPlayerBridgeCapiTV::PreloadIfNeeded(int& ret) {
325   LOG(INFO) << "PreloadIfNeeded, is_preloaded_ " << is_preloaded_;
326   if (blink::IsHbbTV() && !is_preloaded_) {
327     ret = player_preloading_async(player_, -1, PlayerPreLoadingCb, this);
328     return true;
329   }
330
331   // fixup : kPlaybackReady status need checked by HBBTVResourceAcquired() patch
332   if (GetMediaPlayerClient())
333     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackReady, player_id_);
334   else
335     LOG(ERROR) << "(" << static_cast<void*>(this)
336                << "), GetMediaPlayerClient return null";
337   SetDisplayAtPausedState();
338   return false;
339 }
340
341 void MediaPlayerBridgeCapiTV::SetDisplayAtPausedState() {
342   int ret = PLAYER_ERROR_NONE;
343   if (!pending_seek_duration_.is_zero())
344     ret = player_display_video_at_paused_state(player_, false);
345   else
346     ret = player_display_video_at_paused_state(player_, true);
347
348   if (ret != PLAYER_ERROR_NONE)
349     LOG(ERROR) << "player_display_video_at_paused_state() failed";
350 }
351
352 void MediaPlayerBridgeCapiTV::UpdateDuration() {
353   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
354   if (blink::IsHbbTV() && !is_preloaded_) {
355     LOG(INFO) << "HBBTV preload not finished, no need update duration. ";
356     return;
357   }
358   MediaPlayerBridgeCapi::UpdateDuration();
359 }
360
361 void MediaPlayerBridgeCapiTV::UpdateMediaType() {
362   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
363
364   if (blink::IsHbbTV() && !is_preloaded_) {
365     LOG(INFO) << "HBBTV preload not finished, no need update media type. ";
366     return;
367   }
368   MediaPlayerBridgeCapi::UpdateMediaType();
369 }
370
371 bool MediaPlayerBridgeCapiTV::CheckLiveStreaming() const {
372   int isLive = 0;
373   int retVal = player_get_adaptive_streaming_info(player_, &isLive,
374                                                   PLAYER_ADAPTIVE_INFO_IS_LIVE);
375   if (retVal != PLAYER_ERROR_NONE) {
376     LOG(ERROR) << "player_get_adaptive_streaming_info failed, error: "
377                << retVal;
378     return false;
379   }
380
381   if (!isLive)
382     return false;
383
384   LOG(INFO) << "This is a live streaming.";
385   return true;
386 }
387
388 void MediaPlayerBridgeCapiTV::OnPlayerPreloading() {
389   task_runner_->PostTask(
390       FROM_HERE, base::BindOnce(&MediaPlayerBridgeCapiTV::PlayerPreloaded,
391                                 weak_factory_.GetWeakPtr()));
392 }
393
394 bool MediaPlayerBridgeCapiTV::HBBTVResourceAcquired() {
395   bool media_resource_acquired = false;
396   if (!GetMediaPlayerClient()) {
397     LOG(ERROR) << "MediaPlayerTizenClient is nullptr";
398     return false;
399   }
400
401   GetMediaPlayerClient()->NotifyPlaybackState(
402       kPlaybackReady, player_id_, url_.spec(), mime_type_,
403       &media_resource_acquired, NULL, NULL);
404   if (!media_resource_acquired) {
405     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStop, player_id_);
406     LOG(ERROR) << "HBBTV media resource acquired failed";
407   }
408   return media_resource_acquired;
409 }
410
411 void MediaPlayerBridgeCapiTV::PlayerPreloaded() {
412   LOG(INFO) << "PlayerPreloaded,this: " << this
413             << ",player_prepared_:" << player_prepared_;
414
415   is_preloaded_ = true;
416   is_live_stream_ = CheckLiveStreaming();
417   // if (stream_type_ == DASH_STREAM)
418   //  ParseDashInfo();
419   if (is_live_stream_ && stream_type_ != OTHER_STREAM) {
420     // UpdateSeekableTime();
421     // StartSeekableTimeUpdateTimer();
422   }
423   // UpdateAudioTrackInfo();
424   // UpdateVideoTrackInfo();
425   // UpdateTextTrackInfo();
426   UpdateDuration();
427   UpdateMediaType();
428   if (GetMediaType() == MediaType::Invalid) {
429     LOG(ERROR) << "Media type is not valid!";
430     return;
431   }
432
433   OnReadyStateChange(player_id_,
434                      blink::WebMediaPlayer::kReadyStateHaveFutureData);
435   OnNetworkStateChange(player_id_, blink::WebMediaPlayer::kNetworkStateLoading);
436
437   if (!player_prepared_ && HBBTVResourceAcquired()) {
438     int ret = SetPlayerPrepareAsync();
439     if (ret != PLAYER_ERROR_NONE) {
440       OnHandlePlayerError(ret, FROM_HERE);
441     }
442   }
443 }
444
445 bool MediaPlayerBridgeCapiTV::PlayerPrePlay() {
446   LOG(INFO) << "PlayerPrePlay, this: " << this
447             << ",is_player_prepared : " << player_prepared_;
448   if (IsPlayerSuspended()) {
449     LOG(INFO) << "PlayerPrePlay while player is suspended";
450     return false;
451   }
452
453   if (!HBBTVResourceAcquired()) {
454     LOG(INFO)
455         << "PlayerPrePlay while it's not in case of HBBTV Resource Acquired";
456     return false;
457   }
458
459   delayed_player_state_ = PLAYER_STATE_DELAYED_PLAY;
460   LOG(INFO) << "begin to |player_prepare_async|";
461
462   SetDisplayAtPausedState();
463   int ret = SetPlayerPrepareAsync();
464   if (ret != PLAYER_ERROR_NONE) {
465     OnHandlePlayerError(ret, FROM_HERE);
466     return false;
467   }
468
469   return true;
470 }
471 void MediaPlayerBridgeCapiTV::Initialize(VideoRendererSink* sink) {
472   player_set_drm_error_cb(player_, DrmErrorCb, this);
473   MediaPlayerBridgeCapi::Initialize(sink);
474 }
475
476 bool MediaPlayerBridgeCapiTV::SetDrmInfo(std::string& drm_info) {
477   // The DRM info from HbbTV comes as a JSON-like string in the following
478   // format:
479   // pair = Property ':' Value
480   // string = pair {',' pair}
481   std::vector<std::string> drm_info_pairs = base::SplitStringUsingSubstr(
482       drm_info, ", ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
483   for (auto it = drm_info_pairs.begin(); it != drm_info_pairs.end(); ++it) {
484     std::vector<std::string> drm_info_pair = base::SplitStringUsingSubstr(
485         *it, ": ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
486
487     if (drm_info_pair.size() != 2)
488       continue;
489
490     std::string trim_key = drm_info_pair.at(0);
491     std::string trim_value = drm_info_pair.at(1);
492     LOG(INFO) << "trim_key: " << trim_key.c_str()
493               << ",trim_value: " << trim_value.c_str();
494
495     if (!SetMediaDRMInfo(trim_key, trim_value)) {
496       LOG(ERROR)
497           << "MediaPlayerBridgeCapiTV::SetDrmInfo SetMediaDRMInfo failed";
498       return false;
499     }
500   }
501
502   return true;
503 }
504
505 bool MediaPlayerBridgeCapiTV::SetMediaDRMInfo(const std::string& type_data,
506                                               const std::string& value_data) {
507   LOG(INFO) << "player_set_drm_info(type_length(" << type_data.length() << ") "
508             << " value_length(" << value_data.length() << ")) ";
509   int ret = PLAYER_ERROR_INVALID_OPERATION;
510   const void* type_data_ptr = type_data.c_str();
511   const void* value_data_ptr = value_data.c_str();
512   player_drm_type_e drm_type = PLAYER_DRM_TYPE_PLAYREADY;
513   ret = player_set_drm_info(player_, type_data_ptr, type_data.length(),
514                             value_data_ptr, value_data.length(), drm_type);
515   if (ret != PLAYER_ERROR_NONE) {
516     MediaPlayerBridgeCapi::OnHandlePlayerError(ret, FROM_HERE);
517     return false;
518   }
519
520   return true;
521 }
522
523 void MediaPlayerBridgeCapiTV::OnDrmError(int err_code, char* err_str) {
524   LOG(ERROR) << "OnDrmError err_str[" << err_str << "]";
525   if (!task_runner_->BelongsToCurrentThread()) {
526     task_runner_->PostTask(
527         FROM_HERE,
528         base::BindOnce(&MediaPlayerBridgeCapiTV::OnDrmError,
529                        weak_factory_.GetWeakPtr(), err_code, err_str));
530   }
531   MediaPlayerBridgeCapi::OnHandlePlayerError(err_code, FROM_HERE);
532 }
533
534 }  // namespace media