[M120 Migration] Support translated url
[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 DrmErrorCb(int err_code, char* err_str, void* data) {
16   DCHECK(data);
17   media::MediaPlayerBridgeCapiTV* player =
18       static_cast<media::MediaPlayerBridgeCapiTV*>(data);
19
20   player->OnDrmError(err_code, err_str);
21 }
22
23 namespace media {
24
25 MediaPlayerBridgeCapiTV::MediaPlayerBridgeCapiTV(const GURL& url,
26                                                  const std::string& user_agent,
27                                                  double volume)
28     : MediaPlayerBridgeCapi(url, user_agent, volume), weak_factory_(this) {
29   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
30 }
31
32 MediaPlayerBridgeCapiTV::~MediaPlayerBridgeCapiTV() {
33   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
34   weak_factory_.InvalidateWeakPtrs();
35 }
36
37 void MediaPlayerBridgeCapiTV::SetContentMimeType(const std::string& mime_type) {
38   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
39             << " mime_type : " << mime_type;
40   mime_type_ = mime_type;
41 }
42
43 void MediaPlayerBridgeCapiTV::Prepare() {
44   bool media_resource_acquired = false;
45   std::string translated_url;
46   std::string drm_info;
47
48   if (GetMediaPlayerClient())
49     GetMediaPlayerClient()->NotifyPlaybackState(
50         kPlaybackLoad, player_id_, url_.spec(), mime_type_,
51         &media_resource_acquired, &translated_url, &drm_info);
52
53   LOG(INFO) << "media_resource_acquired: " << media_resource_acquired
54             << ",translated_url:" << translated_url
55             << ",drm_info: " << drm_info;
56
57   if (mime_type_.find("application/vnd.oipf.contentaccessstreaming+xml") !=
58       std::string::npos) {
59     LOG(INFO) << "CASD url,waiting for hbbtv parse the real url and set "
60                  "translated url";
61     return;
62   }
63
64   if (GetMediaPlayerClient() &&
65       GetMediaPlayerClient()->PlaybackNotificationEnabled() &&
66       blink::IsHbbTV()) {
67     if (!SetDrmInfo(drm_info)) {
68       LOG(ERROR) << "SetDrmInfo failed";
69       return;
70     }
71     if (!translated_url.empty())
72       url_ = media::GetCleanURL(translated_url);
73   }
74
75   if (url_.spec().find(".mpd") != std::string::npos)
76     stream_type_ = DASH_STREAM;
77   else if (url_.spec().find(".m3u") != std::string::npos)
78     stream_type_ = HLS_STREAM;
79   else if (mime_type_.find("application/dash+xml") != std::string::npos) {
80     char steaming_type_dash[] = "DASH";
81     char steaming_type_dash_ex[] = "DASHEX";
82     player_set_streaming_type(
83         player_, blink::IsHbbTV() ? steaming_type_dash_ex : steaming_type_dash);
84     stream_type_ = DASH_STREAM;
85   }
86
87   if (blink::IsHbbTV() && CheckHighBitRate() && stream_type_ == DASH_STREAM)
88     AppendUrlHighBitRate(url_.spec());
89   MediaPlayerBridgeCapi::Prepare();
90   if (GetMediaPlayerClient())
91     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackReady, player_id_);
92 }
93
94 void MediaPlayerBridgeCapiTV::Release() {
95   StopSeekableTimeUpdateTimer();
96   MediaPlayerBridgeCapi::Release();
97   if (GetMediaPlayerClient())
98     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStop, player_id_);
99 }
100
101 bool MediaPlayerBridgeCapiTV::Play() {
102   if (!MediaPlayerBridgeCapi::Play())
103     return false;
104   if (GetMediaPlayerClient())
105     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStart, player_id_);
106   return true;
107 }
108
109 void MediaPlayerBridgeCapiTV::PlaybackCompleteUpdate() {
110   MediaPlayerBridgeCapi::PlaybackCompleteUpdate();
111   if (GetMediaPlayerClient())
112     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackFinish, player_id_);
113 }  // namespace media
114
115 void MediaPlayerBridgeCapiTV::PlayerPrepared() {
116   MediaPlayerBridgeCapi::PlayerPrepared();
117
118   GetAdaptiveStreamingInfo();
119   if (/*!blink::IsHbbTV() && */is_live_stream_) {
120     UpdateSeekableTime();
121     StartSeekableTimeUpdateTimer();
122   }
123 }
124
125 void MediaPlayerBridgeCapiTV::StartSeekableTimeUpdateTimer() {
126   if (!seekable_time_update_timer_.IsRunning()) {
127     seekable_time_update_timer_.Start(
128         FROM_HERE, base::Milliseconds(kSeekableTimeUpdateInterval), this,
129         &MediaPlayerBridgeCapiTV::OnSeekableTimeUpdateTimerFired);
130   }
131 }
132
133 void MediaPlayerBridgeCapiTV::StopSeekableTimeUpdateTimer() {
134   if (seekable_time_update_timer_.IsRunning())
135     seekable_time_update_timer_.Stop();
136 }
137
138 void MediaPlayerBridgeCapiTV::OnSeekableTimeUpdateTimerFired() {
139   UpdateSeekableTime();
140 }
141
142 void MediaPlayerBridgeCapiTV::GetAdaptiveStreamingInfo() {
143   int ret = player_get_adaptive_streaming_info(player_, &is_live_stream_,
144                                                PLAYER_ADAPTIVE_INFO_IS_LIVE);
145   if (ret != PLAYER_ERROR_NONE || is_live_stream_) {
146     LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
147               << " A live stream.";
148   }
149 }
150
151 void MediaPlayerBridgeCapiTV::UpdateSeekableTime() {
152   if (GetPlayerState() == PLAYER_STATE_NONE || !is_live_stream_)
153     return;
154
155   int64_t min = 0, max = 0;
156   if (GetLiveStreamingDuration(&min, &max)) {
157     if (min_seekable_time_.InMilliseconds() != min ||
158         max_seekable_time_.InMilliseconds() != max) {
159       min_seekable_time_ = base::Milliseconds(min);
160       max_seekable_time_ = base::Milliseconds(max);
161       if (GetMediaPlayerClient())
162       GetMediaPlayerClient()->OnSeekableTimeChange(
163           min_seekable_time_, max_seekable_time_, is_live_stream_);
164     }
165
166     return;
167   }
168
169   GetAdaptiveStreamingInfo();
170   if (!is_live_stream_) {
171     LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
172               << " changed to static stream";
173     if (GetMediaPlayerClient())
174       GetMediaPlayerClient()->OnSeekableTimeChange({}, {}, is_live_stream_);
175     MediaPlayerBridgeCapi::UpdateDuration();
176   }
177 }
178
179 bool MediaPlayerBridgeCapiTV::GetLiveStreamingDuration(int64_t* min,
180                                                        int64_t* max) {
181   DCHECK(min);
182   DCHECK(max);
183   constexpr const size_t kDurationBufferSize = 64;
184   char live_duration[kDurationBufferSize] = {
185       0,
186   };
187   char* live_ptr = live_duration;
188   const auto err = player_get_adaptive_streaming_info(
189       player_, live_duration, PLAYER_ADAPTIVE_INFO_LIVE_DURATION);
190   if (err != PLAYER_ERROR_NONE) {
191     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
192                << " |player_get_adaptive_streaming_info| failed " << err;
193     return false;
194   }
195
196   const std::string duration(live_duration);
197   const std::string::size_type delimiter = duration.find('|');
198   if (delimiter == std::string::npos) {
199     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
200                << " Failed to find delimiter | in duration: " << duration;
201     return false;
202   }
203
204   const std::string duration_min = duration.substr(0, delimiter);
205   if (duration_min.empty()) {
206     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
207                << " Failed empty min sub str: " << duration << ", "
208                << delimiter;
209     return false;
210   }
211
212   int64_t out_min = 0;
213   if (!base::StringToInt64(duration_min, &out_min)) {
214     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
215                << " Failed to get min from duration: " << duration;
216     return false;
217   }
218
219   const std::string duration_max = duration.substr(delimiter + 1);
220   if (duration_max.empty()) {
221     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
222                << " empty max sub str: " << duration << ", " << delimiter;
223     return false;
224   }
225
226   int64_t out_max = 0;
227   if (!base::StringToInt64(duration_max, &out_max)) {
228     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
229                << " Failed to get max from duration: " << duration;
230     return false;
231   }
232
233   *min = out_min;
234   *max = out_max;
235   return true;
236 }
237
238 void MediaPlayerBridgeCapiTV::AppendUrlHighBitRate(const std::string& url) {
239   // don't use url.append("|STARTBITRATE=HIGHEST") to get hbbtv url
240   // "|" will be replaced with "%7C"
241   const char high_bitrate[] = "|STARTBITRATE=HIGHEST";
242   int len = url.length() + strlen(high_bitrate) + 1;
243   char* str_url = new char[len];
244   if (!str_url) {
245     return;
246   }
247
248   memset(str_url, 0, len);
249   strncat(str_url, url.c_str(), url.length());
250   strncat(str_url, high_bitrate, strlen(high_bitrate));
251   hbbtv_url_ = str_url;
252   BLINKFREE(str_url);
253   LOG(INFO) << "hbbtv url:" << hbbtv_url_.c_str();
254 }
255
256 bool MediaPlayerBridgeCapiTV::CheckHighBitRate() {
257   if (!GetMediaPlayerClient()) {
258     LOG(ERROR) << "MediaPlayerClient is null";
259     return false;
260   }
261   content::WebContentsDelegate* web_contents_delegate =
262       GetMediaPlayerClient()->GetWebContentsDelegate();
263   if (!web_contents_delegate) {
264     LOG(ERROR) << "get web_contents_delegate fail";
265     return false;
266   }
267   bool ret = web_contents_delegate->IsHighBitRate();
268   LOG(INFO) << "get high bit rate: " << std::boolalpha << ret;
269   return ret;
270 }
271
272 void MediaPlayerBridgeCapiTV::HandleDownloadableFontInfo(
273     const std::string& scheme_id_uri,
274     const std::string& value,
275     const std::string& data,
276     int type) {
277   content::WebContentsDelegate* web_contents_delegate =
278       GetMediaPlayerClient()->GetWebContentsDelegate();
279   if (!web_contents_delegate)
280     return;
281   web_contents_delegate->NotifyDownloadableFontInfo(scheme_id_uri, value, data,
282                                                     type);
283 }
284
285 void MediaPlayerBridgeCapiTV::Initialize(VideoRendererSink* sink) {
286   player_set_drm_error_cb(player_, DrmErrorCb, this);
287   MediaPlayerBridgeCapi::Initialize(sink);
288 }
289
290 bool MediaPlayerBridgeCapiTV::SetDrmInfo(std::string& drm_info) {
291   // The DRM info from HbbTV comes as a JSON-like string in the following
292   // format:
293   // pair = Property ':' Value
294   // string = pair {',' pair}
295   std::vector<std::string> drm_info_pairs = base::SplitStringUsingSubstr(
296       drm_info, ", ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
297   for (auto it = drm_info_pairs.begin(); it != drm_info_pairs.end(); ++it) {
298     std::vector<std::string> drm_info_pair = base::SplitStringUsingSubstr(
299         *it, ": ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
300
301     if (drm_info_pair.size() != 2)
302       continue;
303
304     std::string trim_key = drm_info_pair.at(0);
305     std::string trim_value = drm_info_pair.at(1);
306     LOG(INFO) << "trim_key: " << trim_key.c_str()
307               << ",trim_value: " << trim_value.c_str();
308
309     if (!SetMediaDRMInfo(trim_key, trim_value)) {
310       LOG(ERROR)
311           << "MediaPlayerBridgeCapiTV::SetDrmInfo SetMediaDRMInfo failed";
312       return false;
313     }
314   }
315
316   return true;
317 }
318
319 bool MediaPlayerBridgeCapiTV::SetMediaDRMInfo(const std::string& type_data,
320                                               const std::string& value_data) {
321   LOG(INFO) << "player_set_drm_info(type_length(" << type_data.length() << ") "
322             << " value_length(" << value_data.length() << ")) ";
323   int ret = PLAYER_ERROR_INVALID_OPERATION;
324   const void* type_data_ptr = type_data.c_str();
325   const void* value_data_ptr = value_data.c_str();
326   player_drm_type_e drm_type = PLAYER_DRM_TYPE_PLAYREADY;
327   ret = player_set_drm_info(player_, type_data_ptr, type_data.length(),
328                             value_data_ptr, value_data.length(), drm_type);
329   if (ret != PLAYER_ERROR_NONE) {
330     MediaPlayerBridgeCapi::OnHandlePlayerError(ret, FROM_HERE);
331     return false;
332   }
333
334   return true;
335 }
336
337 void MediaPlayerBridgeCapiTV::OnDrmError(int err_code, char* err_str) {
338   LOG(ERROR) << "OnDrmError err_str[" << err_str << "]";
339   if (!task_runner_->BelongsToCurrentThread()) {
340     task_runner_->PostTask(
341         FROM_HERE,
342         base::BindOnce(&MediaPlayerBridgeCapiTV::OnDrmError,
343                        weak_factory_.GetWeakPtr(), err_code, err_str));
344   }
345   MediaPlayerBridgeCapi::OnHandlePlayerError(err_code, FROM_HERE);
346 }
347
348 }  // namespace media