[M120 Migration][MM] Support webmedia playback state notification
[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 "media/base/efl/media_player_util_efl.h"
8 #include "tizen_src/chromium_impl/media/filters/media_player_tizen_client.h"
9
10 namespace {
11 const int kSeekableTimeUpdateInterval = 500;
12 }
13
14 namespace media {
15
16 MediaPlayerBridgeCapiTV::MediaPlayerBridgeCapiTV(const GURL& url,
17                                                  const std::string& user_agent,
18                                                  double volume)
19     : MediaPlayerBridgeCapi(url, user_agent, volume), weak_factory_(this) {
20   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
21 }
22
23 MediaPlayerBridgeCapiTV::~MediaPlayerBridgeCapiTV() {
24   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
25   weak_factory_.InvalidateWeakPtrs();
26 }
27
28 void MediaPlayerBridgeCapiTV::SetContentMimeType(const std::string& mime_type) {
29   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
30             << " mime_type : " << mime_type;
31   mime_type_ = mime_type;
32 }
33
34 void MediaPlayerBridgeCapiTV::Prepare() {
35   bool media_resource_acquired = false;
36   std::string translated_url;
37   std::string drm_info;
38
39   if (GetMediaPlayerClient())
40     GetMediaPlayerClient()->NotifyPlaybackState(
41         kPlaybackLoad, player_id_, url_.spec(), mime_type_,
42         &media_resource_acquired, &translated_url, &drm_info);
43
44   LOG(INFO) << "media_resource_acquired: " << media_resource_acquired
45             << ",translated_url:" << translated_url
46             << ",drm_info: " << drm_info;
47
48   if (GetMediaPlayerClient() &&
49       GetMediaPlayerClient()->PlaybackNotificationEnabled() &&
50       blink::IsHbbTV() && !translated_url.empty())
51     url_ = media::GetCleanURL(translated_url);
52
53   if (url_.spec().find(".mpd") != std::string::npos)
54     stream_type_ = DASH_STREAM;
55   else if (url_.spec().find(".m3u") != std::string::npos)
56     stream_type_ = HLS_STREAM;
57   else if (mime_type_.find("application/dash+xml") != std::string::npos) {
58     char steaming_type_dash[] = "DASH";
59     char steaming_type_dash_ex[] = "DASHEX";
60     player_set_streaming_type(
61         player_, blink::IsHbbTV() ? steaming_type_dash_ex : steaming_type_dash);
62     stream_type_ = DASH_STREAM;
63   }
64   if (blink::IsHbbTV() && CheckHighBitRate() && stream_type_ == DASH_STREAM)
65     AppendUrlHighBitRate(url_.spec());
66   MediaPlayerBridgeCapi::Prepare();
67   if (GetMediaPlayerClient())
68     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackReady, player_id_);
69 }
70
71 void MediaPlayerBridgeCapiTV::Release() {
72   StopSeekableTimeUpdateTimer();
73   MediaPlayerBridgeCapi::Release();
74   if (GetMediaPlayerClient())
75     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStop, player_id_);
76 }
77
78 bool MediaPlayerBridgeCapiTV::Play() {
79   if (!MediaPlayerBridgeCapi::Play())
80     return false;
81   if (GetMediaPlayerClient())
82     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStart, player_id_);
83   return true;
84 }
85
86 void MediaPlayerBridgeCapiTV::PlaybackCompleteUpdate() {
87   MediaPlayerBridgeCapi::PlaybackCompleteUpdate();
88   if (GetMediaPlayerClient())
89     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackFinish, player_id_);
90 }  // namespace media
91
92 void MediaPlayerBridgeCapiTV::PlayerPrepared() {
93   MediaPlayerBridgeCapi::PlayerPrepared();
94
95   GetAdaptiveStreamingInfo();
96   if (/*!blink::IsHbbTV() && */is_live_stream_) {
97     UpdateSeekableTime();
98     StartSeekableTimeUpdateTimer();
99   }
100 }
101
102 void MediaPlayerBridgeCapiTV::StartSeekableTimeUpdateTimer() {
103   if (!seekable_time_update_timer_.IsRunning()) {
104     seekable_time_update_timer_.Start(
105         FROM_HERE, base::Milliseconds(kSeekableTimeUpdateInterval), this,
106         &MediaPlayerBridgeCapiTV::OnSeekableTimeUpdateTimerFired);
107   }
108 }
109
110 void MediaPlayerBridgeCapiTV::StopSeekableTimeUpdateTimer() {
111   if (seekable_time_update_timer_.IsRunning())
112     seekable_time_update_timer_.Stop();
113 }
114
115 void MediaPlayerBridgeCapiTV::OnSeekableTimeUpdateTimerFired() {
116   UpdateSeekableTime();
117 }
118
119 void MediaPlayerBridgeCapiTV::GetAdaptiveStreamingInfo() {
120   int ret = player_get_adaptive_streaming_info(player_, &is_live_stream_,
121                                                PLAYER_ADAPTIVE_INFO_IS_LIVE);
122   if (ret != PLAYER_ERROR_NONE || is_live_stream_) {
123     LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
124               << " A live stream.";
125   }
126 }
127
128 void MediaPlayerBridgeCapiTV::UpdateSeekableTime() {
129   if (GetPlayerState() == PLAYER_STATE_NONE || !is_live_stream_)
130     return;
131
132   int64_t min = 0, max = 0;
133   if (GetLiveStreamingDuration(&min, &max)) {
134     if (min_seekable_time_.InMilliseconds() != min ||
135         max_seekable_time_.InMilliseconds() != max) {
136       min_seekable_time_ = base::Milliseconds(min);
137       max_seekable_time_ = base::Milliseconds(max);
138       if (GetMediaPlayerClient())
139       GetMediaPlayerClient()->OnSeekableTimeChange(
140           min_seekable_time_, max_seekable_time_, is_live_stream_);
141     }
142
143     return;
144   }
145
146   GetAdaptiveStreamingInfo();
147   if (!is_live_stream_) {
148     LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
149               << " changed to static stream";
150     if (GetMediaPlayerClient())
151       GetMediaPlayerClient()->OnSeekableTimeChange({}, {}, is_live_stream_);
152     MediaPlayerBridgeCapi::UpdateDuration();
153   }
154 }
155
156 bool MediaPlayerBridgeCapiTV::GetLiveStreamingDuration(int64_t* min,
157                                                        int64_t* max) {
158   DCHECK(min);
159   DCHECK(max);
160   constexpr const size_t kDurationBufferSize = 64;
161   char live_duration[kDurationBufferSize] = {
162       0,
163   };
164   char* live_ptr = live_duration;
165   const auto err = player_get_adaptive_streaming_info(
166       player_, live_duration, PLAYER_ADAPTIVE_INFO_LIVE_DURATION);
167   if (err != PLAYER_ERROR_NONE) {
168     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
169                << " |player_get_adaptive_streaming_info| failed " << err;
170     return false;
171   }
172
173   const std::string duration(live_duration);
174   const std::string::size_type delimiter = duration.find('|');
175   if (delimiter == std::string::npos) {
176     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
177                << " Failed to find delimiter | in duration: " << duration;
178     return false;
179   }
180
181   const std::string duration_min = duration.substr(0, delimiter);
182   if (duration_min.empty()) {
183     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
184                << " Failed empty min sub str: " << duration << ", "
185                << delimiter;
186     return false;
187   }
188
189   int64_t out_min = 0;
190   if (!base::StringToInt64(duration_min, &out_min)) {
191     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
192                << " Failed to get min from duration: " << duration;
193     return false;
194   }
195
196   const std::string duration_max = duration.substr(delimiter + 1);
197   if (duration_max.empty()) {
198     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
199                << " empty max sub str: " << duration << ", " << delimiter;
200     return false;
201   }
202
203   int64_t out_max = 0;
204   if (!base::StringToInt64(duration_max, &out_max)) {
205     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
206                << " Failed to get max from duration: " << duration;
207     return false;
208   }
209
210   *min = out_min;
211   *max = out_max;
212   return true;
213 }
214
215 void MediaPlayerBridgeCapiTV::AppendUrlHighBitRate(const std::string& url) {
216   // don't use url.append("|STARTBITRATE=HIGHEST") to get hbbtv url
217   // "|" will be replaced with "%7C"
218   const char high_bitrate[] = "|STARTBITRATE=HIGHEST";
219   int len = url.length() + strlen(high_bitrate) + 1;
220   char* str_url = new char[len];
221   if (!str_url) {
222     return;
223   }
224
225   memset(str_url, 0, len);
226   strncat(str_url, url.c_str(), url.length());
227   strncat(str_url, high_bitrate, strlen(high_bitrate));
228   hbbtv_url_ = str_url;
229   BLINKFREE(str_url);
230   LOG(INFO) << "hbbtv url:" << hbbtv_url_.c_str();
231 }
232
233 bool MediaPlayerBridgeCapiTV::CheckHighBitRate() {
234   if (!GetMediaPlayerClient()) {
235     LOG(ERROR) << "MediaPlayerClient is null";
236     return false;
237   }
238   content::WebContentsDelegate* web_contents_delegate =
239       GetMediaPlayerClient()->GetWebContentsDelegate();
240   if (!web_contents_delegate) {
241     LOG(ERROR) << "get web_contents_delegate fail";
242     return false;
243   }
244   bool ret = web_contents_delegate->IsHighBitRate();
245   LOG(INFO) << "get high bit rate: " << std::boolalpha << ret;
246   return ret;
247 }
248
249 void MediaPlayerBridgeCapiTV::HandleDownloadableFontInfo(
250     const std::string& scheme_id_uri,
251     const std::string& value,
252     const std::string& data,
253     int type) {
254   content::WebContentsDelegate* web_contents_delegate =
255       GetMediaPlayerClient()->GetWebContentsDelegate();
256   if (!web_contents_delegate)
257     return;
258   web_contents_delegate->NotifyDownloadableFontInfo(scheme_id_uri, value, data,
259                                                     type);
260 }
261
262 }  // namespace media