[M120 Migration][MM][HBBTV] Support Parental rating 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
101   parental_rating_pass_ = true;
102   MediaPlayerBridgeCapi::Prepare();
103   if (GetMediaPlayerClient())
104     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackReady, player_id_);
105 }
106
107 void MediaPlayerBridgeCapiTV::Release() {
108   is_preloaded_ = false;
109   player_prepared_ = false;
110   StopSeekableTimeUpdateTimer();
111   MediaPlayerBridgeCapi::Release();
112   if (GetMediaPlayerClient())
113     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStop, player_id_);
114 }
115
116 bool MediaPlayerBridgeCapiTV::Play() {
117   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
118             << ",current_time:" << GetCurrentTime().InSecondsF();
119
120   // HBBTV run in preloading and preplay mode. If no prepread do prepare
121   // in PlayerPrePlay(), otherwise do normal Play.
122   if (blink::IsHbbTV() && !player_prepared_) {
123     if (!PlayerPrePlay())
124       LOG(ERROR) << "HBBTV prePlay fail.";
125     return false;
126   }
127
128   if (blink::IsHbbTV() && !parental_rating_pass_) {
129     LOG(INFO) << "parental rating authenticatoin is not pass yet,waiting...";
130     delayed_player_state_ = PLAYER_STATE_DELAYED_PLAY;
131     MediaPlayerBridgeCapi::ExecuteDelayedPlayerState();
132     return false;
133   }
134
135   if (!MediaPlayerBridgeCapi::Play())
136     return false;
137   if (GetMediaPlayerClient())
138     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStart, player_id_);
139   return true;
140 }
141
142 void MediaPlayerBridgeCapiTV::Pause(bool is_media_related_action) {
143   if (!player_prepared_) {
144     LOG(INFO) << "(" << static_cast<void*>(this)
145               << "), pause while player is not prepared, pause delay";
146     delayed_player_state_ = PLAYER_STATE_DELAYED_PAUSE;
147     return;
148   }
149   MediaPlayerBridgeCapi::Pause(is_media_related_action);
150 }
151
152 void MediaPlayerBridgeCapiTV::PlaybackCompleteUpdate() {
153   MediaPlayerBridgeCapi::PlaybackCompleteUpdate();
154   if (GetMediaPlayerClient())
155     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackFinish, player_id_);
156 }  // namespace media
157
158 void MediaPlayerBridgeCapiTV::PlayerPrepared() {
159   player_prepared_ = true;
160   MediaPlayerBridgeCapi::PlayerPrepared();
161
162   int canSeek = 0;
163   int retVal = player_seek_available(player_, &canSeek);
164   if (retVal == PLAYER_ERROR_NONE && !canSeek)
165     is_player_seek_available_ = false;
166
167   GetAdaptiveStreamingInfo();
168   if (!blink::IsHbbTV() && is_live_stream_) {
169     UpdateSeekableTime();
170     StartSeekableTimeUpdateTimer();
171   }
172 }
173
174 void MediaPlayerBridgeCapiTV::StartSeekableTimeUpdateTimer() {
175   if (!seekable_time_update_timer_.IsRunning()) {
176     seekable_time_update_timer_.Start(
177         FROM_HERE, base::Milliseconds(kSeekableTimeUpdateInterval), this,
178         &MediaPlayerBridgeCapiTV::OnSeekableTimeUpdateTimerFired);
179   }
180 }
181
182 void MediaPlayerBridgeCapiTV::StopSeekableTimeUpdateTimer() {
183   if (seekable_time_update_timer_.IsRunning())
184     seekable_time_update_timer_.Stop();
185 }
186
187 void MediaPlayerBridgeCapiTV::OnSeekableTimeUpdateTimerFired() {
188   UpdateSeekableTime();
189 }
190
191 void MediaPlayerBridgeCapiTV::GetAdaptiveStreamingInfo() {
192   int ret = player_get_adaptive_streaming_info(player_, &is_live_stream_,
193                                                PLAYER_ADAPTIVE_INFO_IS_LIVE);
194   if (ret != PLAYER_ERROR_NONE || is_live_stream_) {
195     LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
196               << " A live stream.";
197   }
198 }
199
200 void MediaPlayerBridgeCapiTV::UpdateSeekableTime() {
201   if (GetPlayerState() == PLAYER_STATE_NONE || !is_live_stream_)
202     return;
203
204   int64_t min = 0, max = 0;
205   if (GetLiveStreamingDuration(&min, &max)) {
206     if (min_seekable_time_.InMilliseconds() != min ||
207         max_seekable_time_.InMilliseconds() != max) {
208       min_seekable_time_ = base::Milliseconds(min);
209       max_seekable_time_ = base::Milliseconds(max);
210       if (GetMediaPlayerClient())
211       GetMediaPlayerClient()->OnSeekableTimeChange(
212           min_seekable_time_, max_seekable_time_, is_live_stream_);
213     }
214
215     return;
216   }
217
218   GetAdaptiveStreamingInfo();
219   if (!is_live_stream_) {
220     LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
221               << " changed to static stream";
222     if (GetMediaPlayerClient())
223       GetMediaPlayerClient()->OnSeekableTimeChange({}, {}, is_live_stream_);
224     MediaPlayerBridgeCapi::UpdateDuration();
225   }
226 }
227
228 bool MediaPlayerBridgeCapiTV::GetLiveStreamingDuration(int64_t* min,
229                                                        int64_t* max) {
230   DCHECK(min);
231   DCHECK(max);
232   constexpr const size_t kDurationBufferSize = 64;
233   char live_duration[kDurationBufferSize] = {
234       0,
235   };
236   char* live_ptr = live_duration;
237   const auto err = player_get_adaptive_streaming_info(
238       player_, live_duration, PLAYER_ADAPTIVE_INFO_LIVE_DURATION);
239   if (err != PLAYER_ERROR_NONE) {
240     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
241                << " |player_get_adaptive_streaming_info| failed " << err;
242     return false;
243   }
244
245   const std::string duration(live_duration);
246   const std::string::size_type delimiter = duration.find('|');
247   if (delimiter == std::string::npos) {
248     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
249                << " Failed to find delimiter | in duration: " << duration;
250     return false;
251   }
252
253   const std::string duration_min = duration.substr(0, delimiter);
254   if (duration_min.empty()) {
255     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
256                << " Failed empty min sub str: " << duration << ", "
257                << delimiter;
258     return false;
259   }
260
261   int64_t out_min = 0;
262   if (!base::StringToInt64(duration_min, &out_min)) {
263     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
264                << " Failed to get min from duration: " << duration;
265     return false;
266   }
267
268   const std::string duration_max = duration.substr(delimiter + 1);
269   if (duration_max.empty()) {
270     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
271                << " empty max sub str: " << duration << ", " << delimiter;
272     return false;
273   }
274
275   int64_t out_max = 0;
276   if (!base::StringToInt64(duration_max, &out_max)) {
277     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
278                << " Failed to get max from duration: " << duration;
279     return false;
280   }
281
282   *min = out_min;
283   *max = out_max;
284   return true;
285 }
286
287 void MediaPlayerBridgeCapiTV::AppendUrlHighBitRate(const std::string& url) {
288   // don't use url.append("|STARTBITRATE=HIGHEST") to get hbbtv url
289   // "|" will be replaced with "%7C"
290   const char high_bitrate[] = "|STARTBITRATE=HIGHEST";
291   int len = url.length() + strlen(high_bitrate) + 1;
292   char* str_url = new char[len];
293   if (!str_url) {
294     return;
295   }
296
297   memset(str_url, 0, len);
298   strncat(str_url, url.c_str(), url.length());
299   strncat(str_url, high_bitrate, strlen(high_bitrate));
300   hbbtv_url_ = str_url;
301   BLINKFREE(str_url);
302   LOG(INFO) << "hbbtv url:" << hbbtv_url_.c_str();
303 }
304
305 bool MediaPlayerBridgeCapiTV::CheckHighBitRate() {
306   if (!GetMediaPlayerClient()) {
307     LOG(ERROR) << "MediaPlayerClient is null";
308     return false;
309   }
310   content::WebContentsDelegate* web_contents_delegate =
311       GetMediaPlayerClient()->GetWebContentsDelegate();
312   if (!web_contents_delegate) {
313     LOG(ERROR) << "get web_contents_delegate fail";
314     return false;
315   }
316   bool ret = web_contents_delegate->IsHighBitRate();
317   LOG(INFO) << "get high bit rate: " << std::boolalpha << ret;
318   return ret;
319 }
320
321 void MediaPlayerBridgeCapiTV::HandleDownloadableFontInfo(
322     const std::string& scheme_id_uri,
323     const std::string& value,
324     const std::string& data,
325     int type) {
326   content::WebContentsDelegate* web_contents_delegate =
327       GetMediaPlayerClient()->GetWebContentsDelegate();
328   if (!web_contents_delegate)
329     return;
330   web_contents_delegate->NotifyDownloadableFontInfo(scheme_id_uri, value, data,
331                                                     type);
332 }
333
334 bool MediaPlayerBridgeCapiTV::PreloadIfNeeded(int& ret) {
335   LOG(INFO) << "PreloadIfNeeded, is_preloaded_ " << is_preloaded_;
336   if (blink::IsHbbTV() && !is_preloaded_) {
337     ret = player_preloading_async(player_, -1, PlayerPreLoadingCb, this);
338     return true;
339   }
340
341   // fixup : kPlaybackReady status need checked by HBBTVResourceAcquired() patch
342   if (GetMediaPlayerClient())
343     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackReady, player_id_);
344   else
345     LOG(ERROR) << "(" << static_cast<void*>(this)
346                << "), GetMediaPlayerClient return null";
347   SetDisplayAtPausedState();
348   return false;
349 }
350
351 void MediaPlayerBridgeCapiTV::SetDisplayAtPausedState() {
352   int ret = PLAYER_ERROR_NONE;
353   if (!pending_seek_duration_.is_zero())
354     ret = player_display_video_at_paused_state(player_, false);
355   else
356     ret = player_display_video_at_paused_state(player_, true);
357
358   if (ret != PLAYER_ERROR_NONE)
359     LOG(ERROR) << "player_display_video_at_paused_state() failed";
360 }
361
362 void MediaPlayerBridgeCapiTV::UpdateDuration() {
363   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
364   if (blink::IsHbbTV() && !is_preloaded_) {
365     LOG(INFO) << "HBBTV preload not finished, no need update duration. ";
366     return;
367   }
368   MediaPlayerBridgeCapi::UpdateDuration();
369 }
370
371 void MediaPlayerBridgeCapiTV::UpdateMediaType() {
372   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
373
374   if (blink::IsHbbTV() && !is_preloaded_) {
375     LOG(INFO) << "HBBTV preload not finished, no need update media type. ";
376     return;
377   }
378   MediaPlayerBridgeCapi::UpdateMediaType();
379 }
380
381 bool MediaPlayerBridgeCapiTV::CheckLiveStreaming() const {
382   int isLive = 0;
383   int retVal = player_get_adaptive_streaming_info(player_, &isLive,
384                                                   PLAYER_ADAPTIVE_INFO_IS_LIVE);
385   if (retVal != PLAYER_ERROR_NONE) {
386     LOG(ERROR) << "player_get_adaptive_streaming_info failed, error: "
387                << retVal;
388     return false;
389   }
390
391   if (!isLive)
392     return false;
393
394   LOG(INFO) << "This is a live streaming.";
395   return true;
396 }
397
398 void MediaPlayerBridgeCapiTV::OnPlayerPreloading() {
399   task_runner_->PostTask(
400       FROM_HERE, base::BindOnce(&MediaPlayerBridgeCapiTV::PlayerPreloaded,
401                                 weak_factory_.GetWeakPtr()));
402 }
403
404 bool MediaPlayerBridgeCapiTV::HBBTVResourceAcquired() {
405   bool media_resource_acquired = false;
406   if (!GetMediaPlayerClient()) {
407     LOG(ERROR) << "MediaPlayerTizenClient is nullptr";
408     return false;
409   }
410
411   GetMediaPlayerClient()->NotifyPlaybackState(
412       kPlaybackReady, player_id_, url_.spec(), mime_type_,
413       &media_resource_acquired, NULL, NULL);
414   if (!media_resource_acquired) {
415     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStop, player_id_);
416     LOG(ERROR) << "HBBTV media resource acquired failed";
417   }
418   return media_resource_acquired;
419 }
420
421 void MediaPlayerBridgeCapiTV::PlayerPreloaded() {
422   LOG(INFO) << "PlayerPreloaded,this: " << this
423             << ",player_prepared_:" << player_prepared_;
424
425   is_preloaded_ = true;
426   is_live_stream_ = CheckLiveStreaming();
427   // if (stream_type_ == DASH_STREAM)
428   //  ParseDashInfo();
429   if (is_live_stream_ && stream_type_ != OTHER_STREAM) {
430     // UpdateSeekableTime();
431     // StartSeekableTimeUpdateTimer();
432   }
433   // UpdateAudioTrackInfo();
434   // UpdateVideoTrackInfo();
435   // UpdateTextTrackInfo();
436   UpdateDuration();
437   UpdateMediaType();
438   if (GetMediaType() == MediaType::Invalid) {
439     LOG(ERROR) << "Media type is not valid!";
440     return;
441   }
442
443   OnReadyStateChange(player_id_,
444                      blink::WebMediaPlayer::kReadyStateHaveFutureData);
445   OnNetworkStateChange(player_id_, blink::WebMediaPlayer::kNetworkStateLoading);
446
447   if (!player_prepared_ && HBBTVResourceAcquired()) {
448     int ret = SetPlayerPrepareAsync();
449     if (ret != PLAYER_ERROR_NONE) {
450       OnHandlePlayerError(ret, FROM_HERE);
451     }
452   }
453 }
454
455 bool MediaPlayerBridgeCapiTV::PlayerPrePlay() {
456   LOG(INFO) << "PlayerPrePlay, this: " << this
457             << ",is_player_prepared : " << player_prepared_;
458   if (IsPlayerSuspended()) {
459     LOG(INFO) << "PlayerPrePlay while player is suspended";
460     return false;
461   }
462
463   if (!HBBTVResourceAcquired()) {
464     LOG(INFO)
465         << "PlayerPrePlay while it's not in case of HBBTV Resource Acquired";
466     return false;
467   }
468
469   delayed_player_state_ = PLAYER_STATE_DELAYED_PLAY;
470   LOG(INFO) << "begin to |player_prepare_async|";
471
472   SetDisplayAtPausedState();
473   int ret = SetPlayerPrepareAsync();
474   if (ret != PLAYER_ERROR_NONE) {
475     OnHandlePlayerError(ret, FROM_HERE);
476     return false;
477   }
478
479   return true;
480 }
481 void MediaPlayerBridgeCapiTV::Initialize(VideoRendererSink* sink) {
482   player_set_drm_error_cb(player_, DrmErrorCb, this);
483   MediaPlayerBridgeCapi::Initialize(sink);
484 }
485
486 bool MediaPlayerBridgeCapiTV::SetDrmInfo(std::string& drm_info) {
487   // The DRM info from HbbTV comes as a JSON-like string in the following
488   // format:
489   // pair = Property ':' Value
490   // string = pair {',' pair}
491   std::vector<std::string> drm_info_pairs = base::SplitStringUsingSubstr(
492       drm_info, ", ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
493   for (auto it = drm_info_pairs.begin(); it != drm_info_pairs.end(); ++it) {
494     std::vector<std::string> drm_info_pair = base::SplitStringUsingSubstr(
495         *it, ": ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
496
497     if (drm_info_pair.size() != 2)
498       continue;
499
500     std::string trim_key = drm_info_pair.at(0);
501     std::string trim_value = drm_info_pair.at(1);
502     LOG(INFO) << "trim_key: " << trim_key.c_str()
503               << ",trim_value: " << trim_value.c_str();
504
505     if (!SetMediaDRMInfo(trim_key, trim_value)) {
506       LOG(ERROR)
507           << "MediaPlayerBridgeCapiTV::SetDrmInfo SetMediaDRMInfo failed";
508       return false;
509     }
510   }
511
512   return true;
513 }
514
515 bool MediaPlayerBridgeCapiTV::SetMediaDRMInfo(const std::string& type_data,
516                                               const std::string& value_data) {
517   LOG(INFO) << "player_set_drm_info(type_length(" << type_data.length() << ") "
518             << " value_length(" << value_data.length() << ")) ";
519   int ret = PLAYER_ERROR_INVALID_OPERATION;
520   const void* type_data_ptr = type_data.c_str();
521   const void* value_data_ptr = value_data.c_str();
522   player_drm_type_e drm_type = PLAYER_DRM_TYPE_PLAYREADY;
523   ret = player_set_drm_info(player_, type_data_ptr, type_data.length(),
524                             value_data_ptr, value_data.length(), drm_type);
525   if (ret != PLAYER_ERROR_NONE) {
526     MediaPlayerBridgeCapi::OnHandlePlayerError(ret, FROM_HERE);
527     return false;
528   }
529
530   return true;
531 }
532
533 void MediaPlayerBridgeCapiTV::OnDrmError(int err_code, char* err_str) {
534   LOG(ERROR) << "OnDrmError err_str[" << err_str << "]";
535   if (!task_runner_->BelongsToCurrentThread()) {
536     task_runner_->PostTask(
537         FROM_HERE,
538         base::BindOnce(&MediaPlayerBridgeCapiTV::OnDrmError,
539                        weak_factory_.GetWeakPtr(), err_code, err_str));
540   }
541   MediaPlayerBridgeCapi::OnHandlePlayerError(err_code, FROM_HERE);
542 }
543
544 void MediaPlayerBridgeCapiTV::HandleParentalRatingInfo(const std::string& info,
545                                                        const std::string& url) {
546   content::WebContentsDelegate* web_contents_delegate =
547       GetMediaPlayerClient()->GetWebContentsDelegate();
548   if (!web_contents_delegate){
549     LOG(ERROR) << "web_contents_delegate is null";
550     return;
551   }
552   web_contents_delegate->NotifyParentalRatingInfo(info, url);
553 }
554
555 void MediaPlayerBridgeCapiTV::SetParentalRatingResult(bool is_pass) {
556   LOG(INFO) << "ParentalRatingResult:" << std::boolalpha << is_pass;
557   parental_rating_pass_ = is_pass;
558
559   // if authentication fail, raise MEDIA_ERROR_DECODE
560   if (!parental_rating_pass_) {
561     OnHandlePlayerError(PLAYER_ERROR_INVALID_OPERATION, FROM_HERE);
562     return;
563   }
564
565   if (player_prepared_) {
566     LOG(INFO) << "player already prepared,execute play";
567     ExecuteDelayedPlayerState();
568   }
569 }
570 }  // namespace media