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