2d979d1299645e7f5d9a13148f77db93e39d0170
[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 "third_party/blink/public/common/web_preferences/web_preferences.h"
10 #include "third_party/blink/public/platform/web_media_player.h"
11 #include "tizen_src/chromium_impl/media/filters/media_player_tizen_client.h"
12
13 #include <jsoncpp/json/json.h>
14 #include <vconf/vconf.h>
15
16 namespace {
17 const int kSeekableTimeUpdateInterval = 500;
18 }
19
20 static void OnSubtitleDataCallback(unsigned long long time_stamp,
21                                    unsigned index,
22                                    void* buffer,
23                                    void* user_data) {
24   DCHECK(user_data);
25   media::MediaPlayerBridgeCapiTV* player =
26       static_cast<media::MediaPlayerBridgeCapiTV*>(user_data);
27   if (buffer) {
28     const std::string info{static_cast<char*>(buffer)};
29     LOG(INFO) << " onSubtitleDataCallback : index=" << index
30               << ",time stamp=" << time_stamp << ",bufferSize=" << info.size();
31
32     constexpr size_t null_terminator_size = 1;
33     player->SubtitleDataCB(time_stamp, index, info,
34                            info.size() + null_terminator_size);
35   }
36 }
37
38 static void PlayerPreLoadingCb(void* data) {
39   if (!data) {
40     LOG(ERROR) << "input data is null";
41     return;
42   }
43   media::MediaPlayerBridgeCapiTV* player =
44       static_cast<media::MediaPlayerBridgeCapiTV*>(data);
45   player->OnPlayerPreloading();
46 }
47
48 static void DrmErrorCb(int err_code, char* err_str, void* data) {
49   DCHECK(data);
50   media::MediaPlayerBridgeCapiTV* player =
51       static_cast<media::MediaPlayerBridgeCapiTV*>(data);
52
53   player->OnDrmError(err_code, err_str);
54 }
55
56 static void OtherEventCb(int event_type, void* event_data, void* data) {
57   DCHECK(data);
58   media::MediaPlayerBridgeCapiTV* player =
59       static_cast<media::MediaPlayerBridgeCapiTV*>(data);
60   player->OnOtherEvent(event_type, event_data);
61 }
62
63 #if TIZEN_VERSION_AT_LEAST(6, 0, 0)
64 static void FirstTimeStampCb(unsigned long long timestamp,
65                              int time_base_num,
66                              int time_base_den,
67                              void* user_data) {
68   DCHECK(user_data);
69   media::MediaPlayerBridgeCapiTV* player =
70       static_cast<media::MediaPlayerBridgeCapiTV*>(user_data);
71   player->OnFirstTimeStamp(timestamp, time_base_num, time_base_den);
72 }
73
74 static void TSSubtitleDataCb(int pid,
75                              unsigned char* data,
76                              unsigned int len,
77                              void* user_data) {
78   DCHECK(user_data);
79   media::MediaPlayerBridgeCapiTV* player =
80       static_cast<media::MediaPlayerBridgeCapiTV*>(user_data);
81   if (data) {
82     player->OnTSSubtitleData(pid, data, len);
83   }
84 }
85 #endif
86 namespace media {
87
88 MediaPlayerBridgeCapiTV::MediaPlayerBridgeCapiTV(const GURL& url,
89                                                  const std::string& user_agent,
90                                                  double volume)
91     : MediaPlayerBridgeCapi(url, user_agent, volume), weak_factory_(this) {
92   LOG_ID(INFO, GetPlayerId())
93       << "(" << static_cast<void*>(this) << ") " << __func__;
94 }
95
96 MediaPlayerBridgeCapiTV::~MediaPlayerBridgeCapiTV() {
97   LOG_ID(INFO, GetPlayerId())
98       << "(" << static_cast<void*>(this) << ") " << __func__;
99   weak_factory_.InvalidateWeakPtrs();
100 }
101
102 void MediaPlayerBridgeCapiTV::SetContentMimeType(const std::string& mime_type) {
103   LOG_ID(INFO, GetPlayerId()) << "(" << static_cast<void*>(this) << ") "
104                               << __func__ << " mime_type : " << mime_type;
105   mime_type_ = mime_type;
106 }
107
108 void MediaPlayerBridgeCapiTV::Prepare() {
109   bool media_resource_acquired = false;
110   std::string translated_url;
111   std::string drm_info;
112
113   if (GetMediaPlayerClient())
114     GetMediaPlayerClient()->NotifyPlaybackState(
115         kPlaybackLoad, player_id_, url_.spec(), mime_type_,
116         &media_resource_acquired, &translated_url, &drm_info);
117
118   LOG_ID(INFO, GetPlayerId())
119       << "media_resource_acquired: " << media_resource_acquired
120       << ",translated_url:" << translated_url << ",drm_info: " << drm_info;
121
122   if (mime_type_.find("application/vnd.oipf.contentaccessstreaming+xml") !=
123       std::string::npos) {
124     LOG_ID(INFO, GetPlayerId())
125         << "CASD url,waiting for hbbtv parse the real url and set "
126            "translated url";
127     return;
128   }
129
130   if (GetMediaPlayerClient() &&
131       GetMediaPlayerClient()->PlaybackNotificationEnabled() &&
132       blink::IsHbbTV()) {
133 #if !defined(TIZEN_MULTIMEDIA_DRMMANAGER_SUPPORT)
134     if (!SetDrmInfo(drm_info)) {
135       LOG_ID(ERROR, GetPlayerId()) << "SetDrmInfo failed";
136       return;
137     }
138 #endif
139     if (!translated_url.empty())
140       url_ = media::GetCleanURL(translated_url);
141   }
142
143   if (blink::IsHbbTV()) {
144     GetUserPreferAudioLanguage();
145   }
146   if (url_.spec().find(".mpd") != std::string::npos)
147     stream_type_ = DASH_STREAM;
148   else if (url_.spec().find(".m3u") != std::string::npos)
149     stream_type_ = HLS_STREAM;
150   else if (mime_type_.find("application/dash+xml") != std::string::npos) {
151     char steaming_type_dash[] = "DASH";
152     char steaming_type_dash_ex[] = "DASHEX";
153     player_set_streaming_type(
154         player_, blink::IsHbbTV() ? steaming_type_dash_ex : steaming_type_dash);
155     stream_type_ = DASH_STREAM;
156   }
157
158   if (blink::IsHbbTV() && !is_preloaded_) {
159     int ret = player_set_others_event_cb(player_, OtherEventCb, this);
160     if (ret != PLAYER_ERROR_NONE)
161       LOG(ERROR) << "player_set_others_event_cb() failed";
162 #if TIZEN_VERSION_AT_LEAST(6, 0, 0)
163     if (stream_type_ == TS_STREAM) {
164       if (prefer_subtitle_lang_ == "") {
165         prefer_subtitle_lang_ = "und";
166         player_set_ini_param(player_, "set_subtitle_language = und");
167       }
168       if (prefer_subtitle_lang_ != "off") {
169         //-999 means invalid pes id, MM will decide use which pes id
170         player_set_pes_cb(player_, -999, TSSubtitleDataCb, this);
171         player_set_first_timestamp_callback(player_, FirstTimeStampCb, this);
172       }
173     }
174 #endif
175   }
176   if (blink::IsHbbTV() && CheckHighBitRate() && stream_type_ == DASH_STREAM)
177     AppendUrlHighBitRate(url_.spec());
178   player_prepared_ = false;
179
180   parental_rating_pass_ = true;
181   MediaPlayerBridgeCapi::Prepare();
182   if (GetMediaPlayerClient())
183     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackReady, player_id_);
184 }
185
186 void MediaPlayerBridgeCapiTV::Release() {
187   is_preloaded_ = false;
188   player_prepared_ = false;
189   StopSeekableTimeUpdateTimer();
190   MediaPlayerBridgeCapi::Release();
191   if (GetMediaPlayerClient())
192     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStop, player_id_);
193   NotifySubtitleState(blink::WebMediaPlayer::kSubtitleStop);
194   pending_active_text_track_id_ = active_text_track_id_;
195   pending_active_audio_track_id_ = active_audio_track_id_;
196   pending_active_video_track_id_ = active_video_track_id_;
197   active_audio_track_id_ = -1;
198   active_video_track_id_ = -1;
199   active_text_track_id_ = -1;
200 #if TIZEN_VERSION_AT_LEAST(6, 0, 0)
201   player_unset_pes_cb(player_, -999);
202 #endif
203 }
204
205 bool MediaPlayerBridgeCapiTV::Play() {
206   LOG_ID(INFO, GetPlayerId())
207       << "(" << static_cast<void*>(this) << ") " << __func__
208       << ",current_time:" << GetCurrentTime().InSecondsF();
209
210   // HBBTV run in preloading and preplay mode. If no prepread do prepare
211   // in PlayerPrePlay(), otherwise do normal Play.
212   if (blink::IsHbbTV() && !player_prepared_) {
213     if (!PlayerPrePlay())
214       LOG_ID(ERROR, GetPlayerId()) << "HBBTV prePlay fail.";
215     return false;
216   }
217
218   if (blink::IsHbbTV() && !parental_rating_pass_) {
219     LOG_ID(INFO, GetPlayerId())
220         << "parental rating authenticatoin is not pass yet,waiting...";
221     delayed_player_state_ = PLAYER_STATE_DELAYED_PLAY;
222     MediaPlayerBridgeCapi::ExecuteDelayedPlayerState();
223     return false;
224   }
225
226   if (!MediaPlayerBridgeCapi::Play())
227     return false;
228   if (blink::IsHbbTV()) {
229     UpdatePreferAudio();
230   }
231
232   LOG_ID(INFO, player_id_) << "pending_active_text_track_id_:"
233                            << pending_active_text_track_id_
234                            << " active_text_track_id_ " << active_text_track_id_
235                            << " pending_active_audio_track_id_ "
236                            << pending_active_audio_track_id_
237                            << " active_audio_track_id_ "
238                            << active_audio_track_id_
239                            << " pending_active_video_track_id_ "
240                            << pending_active_video_track_id_
241                            << " active_video_track_id_ "
242                            << active_video_track_id_;
243
244   if (pending_active_text_track_id_ != -1 && active_text_track_id_ == -1) {
245     active_text_track_id_ = pending_active_text_track_id_;
246     pending_active_text_track_id_ = -1;
247   }
248
249   if (pending_active_audio_track_id_ != -1 && active_audio_track_id_ == -1) {
250     SetActiveAudioTrack(pending_active_audio_track_id_);
251     pending_active_audio_track_id_ = -1;
252   }
253
254   if (pending_active_video_track_id_ != -1 && active_video_track_id_ == -1) {
255     SetActiveVideoTrack(pending_active_video_track_id_);
256     pending_active_video_track_id_ = -1;
257   }
258
259   if (GetMediaPlayerClient())
260     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStart, player_id_);
261   NotifySubtitleState(blink::WebMediaPlayer::kSubtitlePlay);
262   return true;
263 }
264
265 void MediaPlayerBridgeCapiTV::Pause(bool is_media_related_action) {
266   if (!player_prepared_) {
267     LOG_ID(INFO, GetPlayerId())
268         << "(" << static_cast<void*>(this)
269         << "), pause while player is not prepared, pause delay";
270     delayed_player_state_ = PLAYER_STATE_DELAYED_PAUSE;
271     return;
272   }
273   MediaPlayerBridgeCapi::Pause(is_media_related_action);
274   NotifySubtitleState(blink::WebMediaPlayer::kSubtitlePause);
275 }
276
277 void MediaPlayerBridgeCapiTV::PlaybackCompleteUpdate() {
278   MediaPlayerBridgeCapi::PlaybackCompleteUpdate();
279   if (GetMediaPlayerClient()) {
280     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackFinish, player_id_);
281     GetMediaPlayerClient()->UpdateCurrentTime(
282         MediaPlayerBridgeCapi::GetCurrentTime());
283     if (is_live_stream_)
284       GetMediaPlayerClient()->OnLivePlaybackComplete();
285   }
286
287   NotifySubtitleState(blink::WebMediaPlayer::kSubtitleStop);
288 }  // namespace media
289
290 void MediaPlayerBridgeCapiTV::Seek(base::TimeDelta time,
291                                    base::OnceClosure seek_cb) {
292   LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
293                            << __func__ << " time: " << time.InSecondsF();
294
295   seek_cb_ = std::move(seek_cb);
296   if (IsPlayerSuspended() && playback_time_ != time) {
297     playback_time_ = time;
298     delayed_player_state_ = PLAYER_STATE_DELAYED_SEEK;
299     pending_seek_duration_ = playback_time_;
300     OnTimeUpdate(player_id_, playback_time_);
301     OnTimeChanged(player_id_);
302     Resume();
303     return;
304   }
305
306   MediaPlayerBridgeCapi::SeekInternal(time);
307   NotifySubtitleState(blink::WebMediaPlayer::kSubtitleSeekStart,
308                       time.InSecondsF());
309 }
310
311 void MediaPlayerBridgeCapiTV::SubtitleDataCB(long long time_stamp,
312                                              unsigned index,
313                                              const std::string& buffer,
314                                              unsigned buffer_size) {
315   task_runner_->PostTask(
316       FROM_HERE, base::BindOnce(&MediaPlayerBridgeCapiTV::NotifySubtitleData,
317                                 weak_factory_.GetWeakPtr(), index, time_stamp,
318                                 buffer, buffer_size));
319 }
320
321 void MediaPlayerBridgeCapiTV::NotifySubtitlePlay(int id,
322                                                  const std::string& url,
323                                                  const std::string& lang) {
324   if (!GetMediaPlayerClient()) {
325     LOG(ERROR) << "MediaPlayerClient is null";
326     return;
327   }
328   content::WebContentsDelegate* web_contents_delegate =
329       GetMediaPlayerClient()->GetWebContentsDelegate();
330   if (!web_contents_delegate)
331     return;
332
333   web_contents_delegate->NotifySubtitlePlay(id, url, lang);
334 }
335
336 void MediaPlayerBridgeCapiTV::NotifySubtitleData(int track_id,
337                                                  double time_stamp,
338                                                  const std::string& data,
339                                                  unsigned int size) {
340   content::WebContentsDelegate* web_contents_delegate =
341       GetMediaPlayerClient()->GetWebContentsDelegate();
342
343   if (!web_contents_delegate) {
344     LOG(ERROR) << "web_contents_delegate is null";
345     return;
346   }
347
348   web_contents_delegate->NotifySubtitleData(track_id, time_stamp, data, size);
349 }
350
351 void MediaPlayerBridgeCapiTV::NotifySubtitleState(int new_state,
352                                                   double time_stamp) {
353   if (!blink::IsHbbTV() || !GetMediaPlayerClient() ||
354       !GetMediaPlayerClient()->SubtitleNotificationEnabled() ||
355       subtitle_state_ == new_state) {
356     LOG(ERROR)
357         << " MediaPlayerBridgeCapiTV::NotifySubtitleState null condition  ";
358     return;
359   }
360
361   content::WebContentsDelegate* web_contents_delegate =
362       GetMediaPlayerClient()->GetWebContentsDelegate();
363   if (!web_contents_delegate) {
364     LOG(ERROR) << "web_contents_delegate is null";
365     return;
366   }
367
368   // Workaround. Use subtitle state machine only when player has
369   // activated a text_track. Right now, subtitle state machine
370   // is shared between players, so any Player A notification
371   // influences Player B notification, which causes issues.
372   // This workaround won't work when two players have activated a text_track.
373   if (active_text_track_id_ == -1) {
374     LOG(ERROR) << "active_text_track_id_==-1";
375     return;
376   }
377
378   int old_state = subtitle_state_;
379   if (new_state != blink::WebMediaPlayer::kSubtitleSeekStart &&
380       new_state != blink::WebMediaPlayer::kSubtitleSeekComplete)
381     subtitle_state_ = new_state;
382
383   LOG(INFO) << "subtitle state transision:"
384             << "new_state=" << new_state << ", old_state=" << old_state
385             << ", subtitle_state=" << subtitle_state_
386             << ", time_stamp=" << time_stamp;
387
388   switch (new_state) {
389     case blink::WebMediaPlayer::kSubtitlePlay:
390       if (old_state == blink::WebMediaPlayer::kSubtitlePause)
391         web_contents_delegate->NotifySubtitleState(
392             blink::WebMediaPlayer::kSubtitleResume);
393       else
394         NotifyPlayTrack();
395       break;
396     case blink::WebMediaPlayer::kSubtitlePause:
397       if (old_state != blink::WebMediaPlayer::kSubtitleStop)
398         web_contents_delegate->NotifySubtitleState(new_state);
399       break;
400     case blink::WebMediaPlayer::kSubtitleStop:
401       NotifyStopTrack();
402       break;
403     case blink::WebMediaPlayer::kSubtitleSeekStart:
404       web_contents_delegate->NotifySubtitleState(new_state, time_stamp);
405       break;
406     case blink::WebMediaPlayer::kSubtitleSeekComplete:
407       web_contents_delegate->NotifySubtitleState(new_state);
408       break;
409     default:
410       NOTREACHED();
411       return;
412   }
413 }
414
415 void MediaPlayerBridgeCapiTV::NotifyPlayTrack() {
416   if (active_text_track_id_ == -1 ||
417       subtitle_state_ == blink::WebMediaPlayer::kSubtitleStop)
418     return;
419   if (is_inband_text_track_) {
420     // process select player's track ...
421     UpdateActiveTextTrack(active_text_track_id_);
422     NotifySubtitlePlay(active_text_track_id_, blink::WebString().Utf8(),
423                        blink::WebString().Utf8());
424   } else {
425     // get outband track info and then NotifyPlayTrack
426     LOG_ID(INFO, player_id_) << __func__;
427
428     if (GetMediaPlayerClient())
429       GetMediaPlayerClient()->NotifyTrackInfoToBrowser(active_text_track_id_);
430   }
431 }
432
433 void MediaPlayerBridgeCapiTV::NotifyStopTrack() {
434   active_text_track_id_ = -1;
435   if (is_inband_text_track_)
436     UpdateActiveTextTrack(active_text_track_id_);
437
438   is_inband_text_track_ = false;
439   if (!GetMediaPlayerClient()) {
440     LOG(ERROR) << "MediaPlayerClient is null";
441     return;
442   }
443   content::WebContentsDelegate* web_contents_delegate =
444       GetMediaPlayerClient()->GetWebContentsDelegate();
445   if (!web_contents_delegate) {
446     LOG(ERROR) << "web contents delegate is null";
447     return;
448   }
449
450   web_contents_delegate->NotifySubtitleState(
451       blink::WebMediaPlayer::kSubtitleStop);
452 }
453
454 void MediaPlayerBridgeCapiTV::UpdateActiveTextTrack(int id) {
455   int ret = PLAYER_ERROR_NONE;
456
457   // unselected...
458   if (id == -1) {
459     LOG_ID(INFO, player_id_) << "UpdateActiveTextTrack id=-1";
460     return;
461   }
462
463   int count = 0;
464   int err = player_get_track_count(player_, PLAYER_STREAM_TYPE_TEXT, &count);
465   if (err != PLAYER_ERROR_NONE || count <= 0 || id >= count) {
466     LOG(ERROR) << "player_get_track_count err,ret=" << ret
467                << ",count=" << count;
468     return;
469   }
470
471   ret = player_select_track_ex(player_, PLAYER_STREAM_TYPE_TEXT, id,
472                                -1);  //-1 means use the default mode  for
473                                      // mmplayer demuxer to select stream
474   if (ret != PLAYER_ERROR_NONE) {
475     LOG(ERROR) << "player_select_track_ex err,ret=" << ret;
476     return;
477   }
478 }
479
480 void MediaPlayerBridgeCapiTV::OnCurrentTimeUpdateTimerFired() {
481   MediaPlayerBridgeCapi::OnCurrentTimeUpdateTimerFired();
482   if (!GetMediaPlayerClient()) {
483     LOG(ERROR) << "media player client is null";
484     return;
485   }
486   GetMediaPlayerClient()->UpdateCurrentTime(
487       MediaPlayerBridgeCapi::GetCurrentTime());
488 }
489
490 void MediaPlayerBridgeCapiTV::SeekCompleteUpdate() {
491   MediaPlayerBridgeCapi::SeekCompleteUpdate();
492   NotifySubtitleState(blink::WebMediaPlayer::kSubtitleSeekComplete);
493 }
494
495 void MediaPlayerBridgeCapiTV::OnResumeComplete(bool success) {
496   LOG(INFO) << __func__ << ", success: " << success;
497   MediaPlayerBridgeCapi::OnResumeComplete(success);
498
499   if (!GetMediaPlayerClient()) {
500     LOG(ERROR) << "media player client is null";
501     return;
502   }
503
504   if (success)
505     GetMediaPlayerClient()->UpdateCurrentTime(
506         MediaPlayerBridgeCapi::GetCurrentTime());
507 }
508
509 void MediaPlayerBridgeCapiTV::PlayerPrepared() {
510   player_prepared_ = true;
511   MediaPlayerBridgeCapi::PlayerPrepared();
512
513   int canSeek = 0;
514   int retVal = player_seek_available(player_, &canSeek);
515   if (retVal == PLAYER_ERROR_NONE && !canSeek)
516     is_player_seek_available_ = false;
517
518   GetAdaptiveStreamingInfo();
519   if (!blink::IsHbbTV() && is_live_stream_) {
520     UpdateSeekableTime();
521     StartSeekableTimeUpdateTimer();
522   }
523
524   if (blink::IsHbbTV())
525     UpdatePreferAudio();
526 }
527
528 void MediaPlayerBridgeCapiTV::StartSeekableTimeUpdateTimer() {
529   if (!seekable_time_update_timer_.IsRunning()) {
530     seekable_time_update_timer_.Start(
531         FROM_HERE, base::Milliseconds(kSeekableTimeUpdateInterval), this,
532         &MediaPlayerBridgeCapiTV::OnSeekableTimeUpdateTimerFired);
533   }
534 }
535
536 void MediaPlayerBridgeCapiTV::StopSeekableTimeUpdateTimer() {
537   if (seekable_time_update_timer_.IsRunning())
538     seekable_time_update_timer_.Stop();
539 }
540
541 void MediaPlayerBridgeCapiTV::OnSeekableTimeUpdateTimerFired() {
542   UpdateSeekableTime();
543 }
544
545 void MediaPlayerBridgeCapiTV::GetAdaptiveStreamingInfo() {
546   int ret = player_get_adaptive_streaming_info(player_, &is_live_stream_,
547                                                PLAYER_ADAPTIVE_INFO_IS_LIVE);
548   if (ret != PLAYER_ERROR_NONE || is_live_stream_) {
549     LOG_ID(INFO, GetPlayerId()) << "(" << static_cast<void*>(this) << ") "
550                                 << __func__ << " A live stream.";
551   }
552 }
553
554 void MediaPlayerBridgeCapiTV::UpdateSeekableTime() {
555   if (GetPlayerState() == PLAYER_STATE_NONE || !is_live_stream_)
556     return;
557
558   int64_t min = 0, max = 0;
559   if (GetLiveStreamingDuration(&min, &max)) {
560     if (min_seekable_time_.InMilliseconds() != min ||
561         max_seekable_time_.InMilliseconds() != max) {
562       min_seekable_time_ = base::Milliseconds(min);
563       max_seekable_time_ = base::Milliseconds(max);
564       if (GetMediaPlayerClient())
565       GetMediaPlayerClient()->OnSeekableTimeChange(
566           min_seekable_time_, max_seekable_time_, is_live_stream_);
567     }
568
569     return;
570   }
571
572   GetAdaptiveStreamingInfo();
573   if (!is_live_stream_) {
574     LOG_ID(INFO, GetPlayerId()) << "(" << static_cast<void*>(this) << ") "
575                                 << __func__ << " changed to static stream";
576     if (GetMediaPlayerClient())
577       GetMediaPlayerClient()->OnSeekableTimeChange({}, {}, is_live_stream_);
578     MediaPlayerBridgeCapi::UpdateDuration();
579   }
580 }
581
582 bool MediaPlayerBridgeCapiTV::GetLiveStreamingDuration(int64_t* min,
583                                                        int64_t* max) {
584   DCHECK(min);
585   DCHECK(max);
586   constexpr const size_t kDurationBufferSize = 64;
587   char live_duration[kDurationBufferSize] = {
588       0,
589   };
590   char* live_ptr = live_duration;
591   const auto err = player_get_adaptive_streaming_info(
592       player_, &live_ptr, PLAYER_ADAPTIVE_INFO_LIVE_DURATION);
593   if (err != PLAYER_ERROR_NONE) {
594     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
595                << " |player_get_adaptive_streaming_info| failed " << err;
596     return false;
597   }
598
599   const std::string duration(live_duration);
600   const std::string::size_type delimiter = duration.find('|');
601   if (delimiter == std::string::npos) {
602     LOG_ID(ERROR, GetPlayerId())
603         << "(" << static_cast<void*>(this) << ") " << __func__
604         << " Failed to find delimiter | in duration: " << duration;
605     return false;
606   }
607
608   const std::string duration_min = duration.substr(0, delimiter);
609   if (duration_min.empty()) {
610     LOG_ID(ERROR, GetPlayerId())
611         << "(" << static_cast<void*>(this) << ") " << __func__
612         << " Failed empty min sub str: " << duration << ", " << delimiter;
613     return false;
614   }
615
616   int64_t out_min = 0;
617   if (!base::StringToInt64(duration_min, &out_min)) {
618     LOG_ID(ERROR, GetPlayerId())
619         << "(" << static_cast<void*>(this) << ") " << __func__
620         << " Failed to get min from duration: " << duration;
621     return false;
622   }
623
624   const std::string duration_max = duration.substr(delimiter + 1);
625   if (duration_max.empty()) {
626     LOG_ID(ERROR, GetPlayerId())
627         << "(" << static_cast<void*>(this) << ") " << __func__
628         << " empty max sub str: " << duration << ", " << delimiter;
629     return false;
630   }
631
632   int64_t out_max = 0;
633   if (!base::StringToInt64(duration_max, &out_max)) {
634     LOG_ID(ERROR, GetPlayerId())
635         << "(" << static_cast<void*>(this) << ") " << __func__
636         << " Failed to get max from duration: " << duration;
637     return false;
638   }
639
640   *min = out_min;
641   *max = out_max;
642   return true;
643 }
644
645 void MediaPlayerBridgeCapiTV::ParseDashInfo() {
646   std::string dash_info = GetDashInfo();
647   Json::CharReaderBuilder builder;
648   Json::CharReader* reader(builder.newCharReader());
649   Json::Value value;
650
651   if (reader->parse(dash_info.c_str(), dash_info.c_str() + dash_info.length(),
652                     &value, nullptr)) {
653     mrs_url_ = value["mrsUrl"].asString();
654     std::string periodId = value["periodId"].asString();
655     if (periodId != "")
656       content_id_ = clean_url_ + "#period=" + periodId;
657   }
658   LOG(INFO) << "mrsUrl: " << mrs_url_ << ",contentId: " << content_id_;
659 }
660
661 std::string MediaPlayerBridgeCapiTV::GetDashInfo() {
662   char* dash_info = nullptr;
663   // dash_info format:
664   // {"type":0,"minBufferTime":4000,"mrsUrl":"","periodId":"first"}
665   const int ret = player_get_dash_info(player_, &dash_info);
666   if (ret != PLAYER_ERROR_NONE) {
667     if (dash_info)
668       free(dash_info);
669     LOG(ERROR) << "Fail to call player_get_dash_info,ret:" << ret;
670     return "";
671   }
672
673   if (!dash_info) {
674     LOG(ERROR) << "empty dash_info.";
675     return "";
676   }
677
678   const std::string info(dash_info);
679   free(dash_info);
680   LOG(INFO) << "dash info str: " << info;
681
682   return info;
683 }
684
685 bool MediaPlayerBridgeCapiTV::GetDashLiveDuration(int64_t* duration) {
686   DCHECK(duration);
687   std::string dash_info = GetDashInfo();
688   Json::CharReaderBuilder builder;
689   Json::CharReader* reader(builder.newCharReader());
690   Json::Value value;
691   int64_t out_duration = 0;
692
693   if (reader->parse(dash_info.c_str(), dash_info.c_str() + dash_info.length(),
694                     &value, nullptr)) {
695     out_duration = value["mediaPresentationDuration"].asInt();
696   }
697
698   // According to dash spec, if duration == -1, set max time as duration.
699   if (out_duration == -1)
700     out_duration = base::TimeDelta::Max().InMilliseconds();
701   *duration = out_duration;
702
703   return true;
704 }
705
706 void MediaPlayerBridgeCapiTV::HandleBufferingStatus(int percent) {
707   if (is_paused_ || is_seeking_)
708     return;
709
710   if (percent == 100) {
711     LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
712     is_buffering_compeleted_ = true;
713     if (MediaPlayerBridgeCapi::GetPlayerState() != PLAYER_STATE_PAUSED)
714       return;
715     if (player_start(player_) != PLAYER_ERROR_NONE) {
716       LOG(ERROR) << "|player_start| failed";
717       return;
718     }
719
720     if (is_buffering_compeleted_ && blink::IsHbbTV())
721       UpdatePreferAudio();
722
723     if (!is_file_url_)
724       MediaPlayerBridgeCapi::StartBufferingUpdateTimer();
725
726     MediaPlayerBridgeCapi::OnReadyStateChange(
727         player_id_, blink::WebMediaPlayer::kReadyStateHaveEnoughData);
728   } else {
729     is_buffering_compeleted_ = false;
730     if (GetPlayerState() != PLAYER_STATE_PLAYING)
731       return;
732     if (player_pause(player_) != PLAYER_ERROR_NONE) {
733       LOG(ERROR) << "|player_pause| failed";
734       return;
735     }
736
737     MediaPlayerBridgeCapi::StopCurrentTimeUpdateTimer();
738     MediaPlayerBridgeCapi::OnReadyStateChange(
739         player_id_, blink::WebMediaPlayer::kReadyStateHaveCurrentData);
740   }
741   MediaPlayerBridgeCapi::OnNetworkStateChange(
742       player_id_, blink::WebMediaPlayer::kNetworkStateLoading);
743 }
744
745 void MediaPlayerBridgeCapiTV::AppendUrlHighBitRate(const std::string& url) {
746   // don't use url.append("|STARTBITRATE=HIGHEST") to get hbbtv url
747   // "|" will be replaced with "%7C"
748   const char high_bitrate[] = "|STARTBITRATE=HIGHEST";
749   int len = url.length() + strlen(high_bitrate) + 1;
750   char* str_url = new char[len];
751   if (!str_url) {
752     return;
753   }
754
755   memset(str_url, 0, len);
756   strncat(str_url, url.c_str(), url.length());
757   strncat(str_url, high_bitrate, strlen(high_bitrate));
758   hbbtv_url_ = str_url;
759   BLINKFREE(str_url);
760   LOG_ID(INFO, GetPlayerId()) << "hbbtv url:" << hbbtv_url_.c_str();
761 }
762
763 bool MediaPlayerBridgeCapiTV::CheckHighBitRate() {
764   if (!GetMediaPlayerClient()) {
765     LOG_ID(ERROR, GetPlayerId()) << "MediaPlayerClient is null";
766     return false;
767   }
768   content::WebContentsDelegate* web_contents_delegate =
769       GetMediaPlayerClient()->GetWebContentsDelegate();
770   if (!web_contents_delegate) {
771     LOG_ID(ERROR, GetPlayerId()) << "get web_contents_delegate fail";
772     return false;
773   }
774   bool ret = web_contents_delegate->IsHighBitRate();
775   LOG_ID(INFO, GetPlayerId()) << "get high bit rate: " << std::boolalpha << ret;
776   return ret;
777 }
778
779 void MediaPlayerBridgeCapiTV::HandleDownloadableFontInfo(
780     const std::string& scheme_id_uri,
781     const std::string& value,
782     const std::string& data,
783     int type) {
784   content::WebContentsDelegate* web_contents_delegate =
785       GetMediaPlayerClient()->GetWebContentsDelegate();
786   if (!web_contents_delegate)
787     return;
788   web_contents_delegate->NotifyDownloadableFontInfo(scheme_id_uri, value, data,
789                                                     type);
790 }
791
792 bool MediaPlayerBridgeCapiTV::PreloadIfNeeded(int& ret) {
793   LOG_ID(INFO, GetPlayerId())
794       << "PreloadIfNeeded, is_preloaded_ " << is_preloaded_;
795   if (blink::IsHbbTV() && !is_preloaded_) {
796     ret = player_preloading_async(player_, -1, PlayerPreLoadingCb, this);
797     return true;
798   }
799
800   // fixup : kPlaybackReady status need checked by HBBTVResourceAcquired() patch
801   if (GetMediaPlayerClient())
802     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackReady, player_id_);
803   else
804     LOG_ID(ERROR, GetPlayerId()) << "(" << static_cast<void*>(this)
805                                  << "), GetMediaPlayerClient return null";
806   SetDisplayAtPausedState();
807   return false;
808 }
809
810 void MediaPlayerBridgeCapiTV::SetDisplayAtPausedState() {
811   int ret = PLAYER_ERROR_NONE;
812   if (!pending_seek_duration_.is_zero())
813     ret = player_display_video_at_paused_state(player_, false);
814   else
815     ret = player_display_video_at_paused_state(player_, true);
816
817   if (ret != PLAYER_ERROR_NONE)
818     LOG_ID(ERROR, GetPlayerId())
819         << "player_display_video_at_paused_state() failed";
820 }
821
822 #if TIZEN_VERSION_AT_LEAST(6, 0, 0)
823 void MediaPlayerBridgeCapiTV::HandleFirstTimeStamp(unsigned long long timestamp,
824                                                    int time_base_num,
825                                                    int time_base_den) {
826   LOG_ID(INFO, player_id_) << "HandleFirstTimeStamp,timestamp:" << timestamp
827                            << ",time_base_num:" << time_base_num
828                            << ",time_base_den:" << time_base_den;
829   NotifyFirstTimeStamp(timestamp, time_base_num, time_base_den);
830 }
831
832 void MediaPlayerBridgeCapiTV::HandleTSSubtitleData(int pid,
833                                                    const std::string& buf,
834                                                    unsigned int len) {
835   NotifyPESData(buf, len, GetCurrentTime().InMilliseconds());
836 }
837
838 void MediaPlayerBridgeCapiTV::OnFirstTimeStamp(unsigned long long timestamp,
839                                                int time_base_num,
840                                                int time_base_den) {
841   task_runner_->PostTask(
842       FROM_HERE, base::BindOnce(&MediaPlayerBridgeCapiTV::HandleFirstTimeStamp,
843                                 weak_factory_.GetWeakPtr(), timestamp,
844                                 time_base_num, time_base_den));
845 }
846
847 void MediaPlayerBridgeCapiTV::OnTSSubtitleData(int pid,
848                                                unsigned char* data,
849                                                unsigned int len) {
850   // maybe prefer subtitle lang changed
851   if (prefer_subtitle_lang_ == "off")
852     return;
853
854   if (!data || !len) {
855     LOG(ERROR) << "invalid data";
856     return;
857   }
858
859   std::string buf((char*)data);
860   task_runner_->PostTask(
861       FROM_HERE, base::BindOnce(&MediaPlayerBridgeCapiTV::HandleTSSubtitleData,
862                                 weak_factory_.GetWeakPtr(), pid, buf, len));
863 }
864
865 void MediaPlayerBridgeCapiTV::NotifyFirstTimeStamp(unsigned long long timestamp,
866                                                    int time_base_num,
867                                                    int time_base_den) {
868   if (!GetMediaPlayerClient()) {
869     LOG(ERROR) << "MediaPlayerClient is null";
870     return;
871   }
872   if (!blink::IsHbbTV() ||
873       !GetMediaPlayerClient()->SubtitleNotificationEnabled())
874     return;
875   content::WebContentsDelegate* web_contents_delegate =
876       GetMediaPlayerClient()->GetWebContentsDelegate();
877   if (!web_contents_delegate) {
878     LOG(ERROR) << "web contents delegate is null";
879     return;
880   }
881   web_contents_delegate->NotifyFirstTimeStamp(timestamp, time_base_num,
882                                               time_base_den);
883 }
884
885 void MediaPlayerBridgeCapiTV::NotifyPESData(const std::string& buf,
886                                             unsigned int len,
887                                             int media_position) {
888   if (!GetMediaPlayerClient()) {
889     LOG(ERROR) << "MediaPlayerClient is null";
890     return;
891   }
892   if (!blink::IsHbbTV() ||
893       !GetMediaPlayerClient()->SubtitleNotificationEnabled())
894     return;
895   content::WebContentsDelegate* web_contents_delegate =
896       GetMediaPlayerClient()->GetWebContentsDelegate();
897   if (!web_contents_delegate) {
898     LOG(ERROR) << "web contents delegate is null";
899     return;
900   }
901   web_contents_delegate->NotifyPESData(buf, len, media_position);
902 }
903 #endif
904
905 void MediaPlayerBridgeCapiTV::UpdateDuration() {
906   LOG_ID(INFO, GetPlayerId())
907       << "(" << static_cast<void*>(this) << ") " << __func__;
908   if (blink::IsHbbTV() && !is_preloaded_) {
909     LOG_ID(INFO, GetPlayerId())
910         << "HBBTV preload not finished, no need update duration. ";
911     return;
912   }
913   if (is_live_stream_) {
914     int64_t duration = 0;
915     if (stream_type_ == HLS_STREAM) {
916       int64_t min = 0;
917       if (!GetLiveStreamingDuration(&min, &duration)) {
918         LOG(ERROR) << "Fail to get duration for hls live stream.";
919         return;
920       }
921     } else if (stream_type_ == DASH_STREAM) {
922       if (!GetDashLiveDuration(&duration)) {
923         if (duration_ != base::TimeDelta::Max()) {
924           duration_ = base::TimeDelta::Max();
925           OnDurationChange(player_id_, duration_.InSecondsF());
926         }
927         return;
928       }
929     } else {
930       LOG(ERROR) << "Unknown live stream type : " << stream_type_;
931     }
932
933     if (duration == 0) {
934       LOG(WARNING) << "live stream type : convert duration to max";
935       duration_ = base::TimeDelta::Max();
936       OnDurationChange(player_id_, duration_.InSecondsF());
937     } else if (duration_.InSecondsF() !=
938                ConvertMilliSecondsToSeconds(duration)) {
939       duration_ = base::Milliseconds(duration);
940       OnDurationChange(player_id_, duration_.InSecondsF());
941     }
942   } else {  // non-live stream sequence
943     MediaPlayerBridgeCapi::UpdateDuration();
944   }
945 }
946
947 void MediaPlayerBridgeCapiTV::UpdateMediaType() {
948   LOG_ID(INFO, GetPlayerId())
949       << "(" << static_cast<void*>(this) << ") " << __func__;
950
951   if (blink::IsHbbTV() && !is_preloaded_) {
952     LOG_ID(INFO, GetPlayerId())
953         << "HBBTV preload not finished, no need update media type. ";
954     return;
955   }
956   MediaPlayerBridgeCapi::UpdateMediaType();
957 }
958
959 bool MediaPlayerBridgeCapiTV::CheckLiveStreaming() const {
960   int isLive = 0;
961   int retVal = player_get_adaptive_streaming_info(player_, &isLive,
962                                                   PLAYER_ADAPTIVE_INFO_IS_LIVE);
963   if (retVal != PLAYER_ERROR_NONE) {
964     LOG(ERROR) << "player_get_adaptive_streaming_info failed, error: "
965                << retVal;
966     return false;
967   }
968
969   if (!isLive)
970     return false;
971
972   LOG(INFO) << "This is a live streaming.";
973   return true;
974 }
975
976 void MediaPlayerBridgeCapiTV::OnPlayerPreloading() {
977   task_runner_->PostTask(
978       FROM_HERE, base::BindOnce(&MediaPlayerBridgeCapiTV::PlayerPreloaded,
979                                 weak_factory_.GetWeakPtr()));
980 }
981
982 bool MediaPlayerBridgeCapiTV::HBBTVResourceAcquired() {
983   bool media_resource_acquired = false;
984   if (!GetMediaPlayerClient()) {
985     LOG_ID(ERROR, GetPlayerId()) << "MediaPlayerTizenClient is nullptr";
986     return false;
987   }
988
989   GetMediaPlayerClient()->NotifyPlaybackState(
990       kPlaybackReady, player_id_, url_.spec(), mime_type_,
991       &media_resource_acquired, NULL, NULL);
992   if (!media_resource_acquired) {
993     GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStop, player_id_);
994     LOG_ID(ERROR, GetPlayerId()) << "HBBTV media resource acquired failed";
995   }
996   return media_resource_acquired;
997 }
998
999 void MediaPlayerBridgeCapiTV::PlayerPreloaded() {
1000   LOG_ID(INFO, GetPlayerId()) << "PlayerPreloaded,this: " << this
1001                               << ",player_prepared_:" << player_prepared_;
1002
1003   is_preloaded_ = true;
1004   is_live_stream_ = CheckLiveStreaming();
1005   if (stream_type_ == DASH_STREAM)
1006     ParseDashInfo();
1007   if (is_live_stream_ && stream_type_ != OTHER_STREAM) {
1008     // UpdateSeekableTime();
1009     // StartSeekableTimeUpdateTimer();
1010   }
1011   UpdateAudioTrackInfo();
1012   UpdateVideoTrackInfo();
1013   UpdateTextTrackInfo();
1014   UpdateDuration();
1015   UpdateMediaType();
1016   if (GetMediaType() == MediaType::Invalid) {
1017     LOG_ID(ERROR, GetPlayerId()) << "Media type is not valid!";
1018     return;
1019   }
1020
1021   OnReadyStateChange(player_id_,
1022                      blink::WebMediaPlayer::kReadyStateHaveFutureData);
1023   OnNetworkStateChange(player_id_, blink::WebMediaPlayer::kNetworkStateLoading);
1024
1025   if (!player_prepared_ && HBBTVResourceAcquired()) {
1026     int ret = SetPlayerPrepareAsync();
1027     if (ret != PLAYER_ERROR_NONE) {
1028       OnHandlePlayerError(ret, FROM_HERE);
1029     }
1030   }
1031 }
1032
1033 bool MediaPlayerBridgeCapiTV::PlayerPrePlay() {
1034   LOG_ID(INFO, GetPlayerId()) << "PlayerPrePlay, this: " << this
1035                               << ",is_player_prepared : " << player_prepared_;
1036   if (IsPlayerSuspended()) {
1037     LOG_ID(INFO, GetPlayerId()) << "PlayerPrePlay while player is suspended";
1038     return false;
1039   }
1040
1041   if (!HBBTVResourceAcquired()) {
1042     LOG_ID(INFO, GetPlayerId())
1043         << "PlayerPrePlay while it's not in case of HBBTV Resource Acquired";
1044     return false;
1045   }
1046
1047   delayed_player_state_ = PLAYER_STATE_DELAYED_PLAY;
1048   LOG_ID(INFO, GetPlayerId()) << "begin to |player_prepare_async|";
1049
1050   SetDisplayAtPausedState();
1051   int ret = SetPlayerPrepareAsync();
1052   if (ret != PLAYER_ERROR_NONE) {
1053     OnHandlePlayerError(ret, FROM_HERE);
1054     return false;
1055   }
1056
1057   return true;
1058 }
1059 void MediaPlayerBridgeCapiTV::Initialize(VideoRendererSink* sink) {
1060   player_set_drm_error_cb(player_, DrmErrorCb, this);
1061   MediaPlayerBridgeCapi::Initialize(sink);
1062 }
1063
1064 bool MediaPlayerBridgeCapiTV::SetDrmInfo(std::string& drm_info) {
1065   // The DRM info from HbbTV comes as a JSON-like string in the following
1066   // format:
1067   // pair = Property ':' Value
1068   // string = pair {',' pair}
1069   std::vector<std::string> drm_info_pairs = base::SplitStringUsingSubstr(
1070       drm_info, ", ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
1071   for (auto it = drm_info_pairs.begin(); it != drm_info_pairs.end(); ++it) {
1072     std::vector<std::string> drm_info_pair = base::SplitStringUsingSubstr(
1073         *it, ": ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
1074
1075     if (drm_info_pair.size() != 2)
1076       continue;
1077
1078     std::string trim_key = drm_info_pair.at(0);
1079     std::string trim_value = drm_info_pair.at(1);
1080     LOG_ID(INFO, GetPlayerId()) << "trim_key: " << trim_key.c_str()
1081                                 << ",trim_value: " << trim_value.c_str();
1082
1083     if (!SetMediaDRMInfo(trim_key, trim_value)) {
1084       LOG_ID(ERROR, GetPlayerId())
1085           << "MediaPlayerBridgeCapiTV::SetDrmInfo SetMediaDRMInfo failed";
1086       return false;
1087     }
1088   }
1089
1090   return true;
1091 }
1092
1093 bool MediaPlayerBridgeCapiTV::SetMediaDRMInfo(const std::string& type_data,
1094                                               const std::string& value_data) {
1095   LOG_ID(INFO, GetPlayerId())
1096       << "player_set_drm_info(type_length(" << type_data.length() << ") "
1097       << " value_length(" << value_data.length() << ")) ";
1098   int ret = PLAYER_ERROR_INVALID_OPERATION;
1099   const void* type_data_ptr = type_data.c_str();
1100   const void* value_data_ptr = value_data.c_str();
1101   player_drm_type_e drm_type = PLAYER_DRM_TYPE_PLAYREADY;
1102   ret = player_set_drm_info(player_, type_data_ptr, type_data.length(),
1103                             value_data_ptr, value_data.length(), drm_type);
1104   if (ret != PLAYER_ERROR_NONE) {
1105     MediaPlayerBridgeCapi::OnHandlePlayerError(ret, FROM_HERE);
1106     return false;
1107   }
1108
1109   return true;
1110 }
1111
1112 void MediaPlayerBridgeCapiTV::OnDrmError(int err_code, char* err_str) {
1113   LOG_ID(ERROR, GetPlayerId()) << "OnDrmError err_str[" << err_str << "]";
1114   if (!task_runner_->BelongsToCurrentThread()) {
1115     task_runner_->PostTask(
1116         FROM_HERE,
1117         base::BindOnce(&MediaPlayerBridgeCapiTV::OnDrmError,
1118                        weak_factory_.GetWeakPtr(), err_code, err_str));
1119   }
1120   MediaPlayerBridgeCapi::OnHandlePlayerError(err_code, FROM_HERE);
1121 }
1122
1123 void MediaPlayerBridgeCapiTV::HandleParentalRatingInfo(const std::string& info,
1124                                                        const std::string& url) {
1125   content::WebContentsDelegate* web_contents_delegate =
1126       GetMediaPlayerClient()->GetWebContentsDelegate();
1127   if (!web_contents_delegate) {
1128     LOG_ID(ERROR, GetPlayerId()) << "web_contents_delegate is null";
1129     return;
1130   }
1131   web_contents_delegate->NotifyParentalRatingInfo(info, url);
1132 }
1133
1134 void MediaPlayerBridgeCapiTV::SetParentalRatingResult(bool is_pass) {
1135   LOG_ID(INFO, GetPlayerId())
1136       << "ParentalRatingResult:" << std::boolalpha << is_pass;
1137   parental_rating_pass_ = is_pass;
1138
1139   // if authentication fail, raise MEDIA_ERROR_DECODE
1140   if (!parental_rating_pass_) {
1141     OnHandlePlayerError(PLAYER_ERROR_INVALID_OPERATION, FROM_HERE);
1142     return;
1143   }
1144
1145   if (player_prepared_) {
1146     LOG_ID(INFO, GetPlayerId()) << "player already prepared,execute play";
1147     ExecuteDelayedPlayerState();
1148   }
1149 }
1150 void MediaPlayerBridgeCapiTV::AddAudioTrackInfo(const std::string& id,
1151                                                 const std::string& kind,
1152                                                 const std::string& label,
1153                                                 const std::string& lang,
1154                                                 int enabled) {
1155   LOG_ID(INFO, player_id_) << "AudioTrack Info - id: " << id
1156                            << ", kind: " << kind.c_str()
1157                            << ", label: " << label.c_str()
1158                            << ", lang: " << lang.c_str();
1159
1160   media::mojom::MediaTrackInfoPtr trackinfo =
1161       media::mojom::MediaTrackInfo::New();
1162   trackinfo->cmd = media::mojom::TRACKCMD::SETAUDIO;
1163   trackinfo->ck = media::mojom::COOKIES::NewTrack(
1164       media::mojom::Track::New(id, kind, label, lang, enabled));
1165   if (GetMediaPlayerClient())
1166     GetMediaPlayerClient()->AddTrackInfo(std::move(trackinfo));
1167   else
1168     LOG(ERROR) << "Media player client is null";
1169 }
1170
1171 void MediaPlayerBridgeCapiTV::OnOtherEvent(int event_type, void* event_data) {
1172   if (!event_data) {
1173     LOG(ERROR) << "event_data is null.";
1174     return;
1175   }
1176   switch (event_type) {
1177     case PLAYER_MSG_STREAM_EVENT_TYPE: {
1178       LOG_ID(INFO, player_id_) << "PLAYER_MSG_STREAM_EVENT_TYPE";
1179       EventStream* eventstream = static_cast<EventStream*>(event_data);
1180       if (!eventstream) {
1181         LOG(ERROR) << "eventstream is null.";
1182         return;
1183       }
1184       std::string uri(eventstream->schemeIdUri ? eventstream->schemeIdUri : "");
1185       std::string value(eventstream->value ? eventstream->value : "");
1186 #if TIZEN_VERSION_AT_LEAST(6, 5, 0)
1187       int band_type = eventstream->type;
1188       int event_mode = static_cast<player_event_mode>(
1189           (band_type >= IN_BAND) ? (band_type - IN_BAND)
1190                                  : (band_type - OUT_BAND));
1191 #else
1192       player_event_mode event_mode = eventstream->type;
1193       int band_type = static_cast<int>(event_mode);
1194 #endif
1195       LOG_ID(INFO, player_id_)
1196           << "uri:" << uri << ",value:" << value << ",band_type:" << band_type
1197           << ",event_mode:" << event_mode;
1198
1199       // parental rating event only need to handle data info
1200       if (event_mode == PLAYER_DVB_EVENT_MODE_PARENTAL_GUIDANCE) {
1201         LOG_ID(INFO, player_id_) << "parental rating event, skip type";
1202         return;
1203       }
1204
1205       if (!uri.compare("urn:mpeg:dash:event:2012") ||
1206           !uri.compare("urn:dvb:iptv:cpm:2014")) {
1207         LOG_ID(INFO, player_id_) << "not supported scheme id uri,uri:" << uri;
1208         return;
1209       }
1210
1211       if (!uri.compare("urn:dvb:css")) {
1212         LOG_ID(INFO, player_id_) << "event->value:" << eventstream->value
1213                                  << " evalue " << value.c_str();
1214         task_runner_->PostTask(
1215             FROM_HERE, base::BindOnce(&MediaPlayerBridgeCapi::UpdateEventData,
1216                                       weak_factory_.GetWeakPtr(), value));
1217         return;
1218       }
1219
1220       const std::string info = uri + " " + value;
1221       task_runner_->PostTask(
1222           FROM_HERE,
1223           base::BindOnce(&MediaPlayerBridgeCapiTV::HandleInbandTextTrack,
1224                          weak_factory_.GetWeakPtr(), info, band_type,
1225                          ADD_INBAND_TEXT_TRACK));
1226       break;
1227     }
1228     case PLAYER_MSG_STREAM_EVENT_DATA: {
1229       LOG_ID(INFO, player_id_) << "PLAYER_MSG_STREAM_EVENT_DATA";
1230       Event* event = static_cast<Event*>(event_data);
1231       if (!event) {
1232         LOG(ERROR) << "event is null.";
1233         return;
1234       }
1235       std::string uri(event->schemeIdUri ? event->schemeIdUri : "");
1236       std::string value(event->value ? event->value : "");
1237       unsigned int id = event->id;
1238       long long int start_time = event->startTimeMs;
1239       long long int end_time = event->endTimeMs;
1240       std::string data(event->data ? event->data : "");
1241 #if TIZEN_VERSION_AT_LEAST(6, 5, 0)
1242       int band_type = event->type;
1243       int event_mode = static_cast<player_event_mode>(
1244           (band_type >= IN_BAND) ? (band_type - IN_BAND)
1245                                  : (band_type - OUT_BAND));
1246 #else
1247       player_event_mode event_mode = event->type;
1248       int band_type = static_cast<int>(event_mode);
1249 #endif
1250       LOG_ID(INFO, player_id_)
1251           << "uri:" << uri << ",value:" << value << ",data:" << data
1252           << ",id:" << id << ",start_time:" << start_time
1253           << ",end_time:" << end_time << ",band_type:" << band_type
1254           << ",event_mode:" << event_mode;
1255
1256       if (event_mode == PLAYER_DVB_EVENT_MODE_DEAULT) {
1257         if (0 == uri.compare("urn:mpeg:dash:event:2012") ||
1258             0 == uri.compare("urn:dvb:iptv:cpm:2014")) {
1259           LOG_ID(INFO, player_id_) << "not supported scheme id uri,uri:" << uri;
1260           return;
1261         }
1262         const std::string info = uri + " " + value + "$" + data;
1263         task_runner_->PostTask(
1264             FROM_HERE,
1265             base::BindOnce(&MediaPlayerBridgeCapiTV::HandleInbandTextCue,
1266                            weak_factory_.GetWeakPtr(), info, id, band_type,
1267                            start_time, end_time));
1268       } else if (event_mode == PLAYER_DVB_EVENT_MODE_PARENTAL_GUIDANCE) {
1269         //<mpeg7:ParentalRating href="urn:dvb:iptv:rating:2014:15"/>
1270         std::size_t pos = data.find("ParentalRating href=");
1271         if (pos != std::string::npos) {
1272           parental_rating_pass_ = false;
1273           std::size_t quotation1 = data.find('"', pos);
1274           std::size_t quotation2 = data.find('"', quotation1 + 1);
1275           std::string target =
1276               data.substr(quotation1 + 1, quotation2 - quotation1 - 1);
1277           LOG_ID(INFO, player_id_)
1278               << "parentl rating info string is:" << target;
1279           task_runner_->PostTask(
1280               FROM_HERE,
1281               base::BindOnce(&MediaPlayerBridgeCapiTV::HandleParentalRatingInfo,
1282                              weak_factory_.GetWeakPtr(), target, url_.spec()));
1283         }
1284       } else if (
1285           event_mode ==
1286               PLAYER_DVB_EVENT_MODE_SUPPLEMENTAL_PROPERTY_FONT_DOWNLOAD ||
1287           event_mode ==
1288               PLAYER_DVB_EVENT_MODE_ESSENTIAL_PROPERTY_FONT_DOWNLOAD) {
1289         task_runner_->PostTask(
1290             FROM_HERE,
1291             base::BindOnce(&MediaPlayerBridgeCapiTV::HandleDownloadableFontInfo,
1292                            weak_factory_.GetWeakPtr(), uri, value, data,
1293                            event_mode));
1294       }
1295       break;
1296     }
1297     case PLAYER_MSG_STREAM_EVENT_MRS_URL_CHANGED: {
1298       LOG_ID(INFO, player_id_) << "PLAYER_MSG_STREAM_EVENT_MRS_URL_CHANGED";
1299       char* url = static_cast<char*>(event_data);
1300       std::string mrsUrl(url ? url : "");
1301       LOG_ID(INFO, player_id_) << "mrsUrl:" << mrsUrl;
1302 #if !defined(EWK_BRINGUP)
1303       task_runner_->PostTask(
1304           FROM_HERE,
1305           base::BindOnce(&MediaPlayerBridgeCapiTV::HandleMrsUrlChange,
1306                          weak_factory_.GetWeakPtr(), mrsUrl));
1307 #endif
1308       break;
1309     }
1310     case PLAYER_MSG_STREAM_EVENT_PERIOAD_ID_CHANGED: {
1311       LOG_ID(INFO, player_id_) << "PLAYER_MSG_STREAM_EVENT_PERIOAD_ID_CHANGED";
1312       char* id = static_cast<char*>(event_data);
1313       std::string periodId(id ? id : "");
1314       LOG_ID(INFO, player_id_) << "periodId:" << periodId;
1315 #if !defined(EWK_BRINGUP)
1316       task_runner_->PostTask(
1317           FROM_HERE,
1318           base::BindOnce(&MediaPlayerBridgeCapiTV::HandlePeriodIdChange,
1319                          weak_factory_.GetWeakPtr(), periodId));
1320 #endif
1321       break;
1322     }
1323     case PLAYER_MSG_STREAM_EVENT_REMOVE_TRACK: {
1324       LOG_ID(INFO, player_id_) << "PLAYER_MSG_STREAM_EVENT_REMOVE_TRACK";
1325       EventStream* eventstream = static_cast<EventStream*>(event_data);
1326       if (!eventstream) {
1327         LOG(ERROR) << "eventstream is null.";
1328         return;
1329       }
1330       std::string uri(eventstream->schemeIdUri ? eventstream->schemeIdUri : "");
1331       std::string value(eventstream->value ? eventstream->value : "");
1332       LOG_ID(INFO, player_id_) << "uri:" << uri << ",value:" << value;
1333
1334       const std::string info = uri + " " + value;
1335 #if TIZEN_VERSION_AT_LEAST(6, 5, 0)
1336       int band_type = eventstream->type;
1337 #else
1338       int band_type = static_cast<int>(eventstream->type);
1339 #endif
1340       task_runner_->PostTask(
1341           FROM_HERE,
1342           base::BindOnce(&MediaPlayerBridgeCapiTV::HandleInbandTextTrack,
1343                          weak_factory_.GetWeakPtr(), info, band_type,
1344                          DEL_INBAND_TEXT_TRACK));
1345       break;
1346     }
1347     default:
1348       LOG_ID(INFO, player_id_) << "unknow event type:" << event_type;
1349       break;
1350   }
1351 }
1352
1353 void MediaPlayerBridgeCapiTV::HandleInbandTextTrack(const std::string& info,
1354                                                     int band_type,
1355                                                     int action) {
1356   LOG_ID(INFO, player_id_) << "HandleInbandTextTrack info:" << info
1357                            << " band_type:" << band_type
1358                            << " action:" << action;
1359   media::mojom::MediaTrackInfoPtr trackinfo =
1360       media::mojom::MediaTrackInfo::New();
1361   trackinfo->cmd = media::mojom::TRACKCMD::SETINBAND;
1362   trackinfo->ck = media::mojom::COOKIES::NewInband(
1363       media::mojom::InbandTextInfo::New(info, band_type, action));
1364   if (GetMediaPlayerClient())
1365     GetMediaPlayerClient()->AddTrackInfo(std::move(trackinfo));
1366 }
1367
1368 void MediaPlayerBridgeCapiTV::HandleInbandTextCue(const std::string& info,
1369                                                   unsigned int id,
1370                                                   int band_type,
1371                                                   long long int start_time,
1372                                                   long long int end_time) {
1373   LOG_ID(INFO, player_id_) << "HandleInbandTextCue info:" << info
1374                            << " id:" << id << " band_type:" << band_type
1375                            << " start_time:" << start_time
1376                            << " end_time:" << end_time;
1377   media::mojom::MediaTrackInfoPtr trackinfo =
1378       media::mojom::MediaTrackInfo::New();
1379   trackinfo->cmd = media::mojom::TRACKCMD::SETCUE;
1380   trackinfo->ck =
1381       media::mojom::COOKIES::NewCue(media::mojom::InbandCueInfo::New(
1382           info, id, band_type, start_time, end_time));
1383   if (GetMediaPlayerClient())
1384     GetMediaPlayerClient()->AddTrackInfo(std::move(trackinfo));
1385   else
1386     LOG(ERROR) << "Media player client is null";
1387 }
1388
1389 std::string MediaPlayerBridgeCapiTV::MapDashMediaTrackKind(
1390     const std::string& role,
1391     const int size,
1392     bool isAudio) {
1393   // HBBTV Spec : A.2.12.3 Modifications to clause 8.4.6
1394   // HBBTV spec v2.0.2 seperate audioTrack and videoTrack kind definition
1395   // and changed the "main" definiton of audioTrack(page 258)
1396   if (role.find("alternate") != std::string::npos &&
1397       role.find("main") == std::string::npos &&
1398       role.find("commentary") == std::string::npos &&
1399       role.find("dub") == std::string::npos)
1400     return "alternative";
1401
1402   if (role.find("caption") != std::string::npos &&
1403       role.find("main") != std::string::npos)
1404     return "captions";
1405
1406   if (role.find("description") != std::string::npos &&
1407       role.find("supplementary") != std::string::npos)
1408     return "descriptions";
1409
1410   if (role.find("main") != std::string::npos &&
1411       role.find("caption") == std::string::npos &&
1412       role.find("subtitle") == std::string::npos &&
1413       role.find("dub") == std::string::npos) {
1414     if (!isAudio)
1415       return "main";
1416     else if (role.find("description") == std::string::npos)
1417       return "main";
1418   }
1419
1420   if (role.find("main") != std::string::npos &&
1421       role.find("description") != std::string::npos)
1422     return "main-desc";
1423
1424   if (role.find("subtitle") != std::string::npos &&
1425       role.find("main") != std::string::npos)
1426     return "subtitles";
1427
1428   if (role.find("dub") != std::string::npos &&
1429       role.find("main") != std::string::npos)
1430     return "translation";
1431
1432   if (role.find("commentary") != std::string::npos &&
1433       role.find("main") == std::string::npos)
1434     return "commentary";
1435
1436   return "";
1437 }
1438
1439 void MediaPlayerBridgeCapiTV::UpdateAudioTrackInfo() {
1440   int cntTracks = 0;
1441   int err = player_get_adaptationset_count(player_, PLAYER_STREAM_TYPE_AUDIO,
1442                                            &cntTracks);
1443   if (err != PLAYER_ERROR_NONE || cntTracks == 0) {
1444     LOG_ID(ERROR, player_id_)
1445         << "get audio track fail,err:" << err << ",count:" << cntTracks;
1446     return;
1447   }
1448
1449   LOG_ID(INFO, player_id_) << "audio track count: " << cntTracks;
1450
1451   player_audio_adaptationset_info* audio_track_info =
1452       static_cast<player_audio_adaptationset_info*>(
1453           malloc(cntTracks * sizeof(player_audio_adaptationset_info)));
1454   if (!audio_track_info) {
1455     LOG_ID(ERROR, player_id_) << "malloc fail";
1456     return;
1457   }
1458   memset(audio_track_info, 0,
1459          cntTracks * sizeof(player_audio_adaptationset_info));
1460
1461   unsigned audio_alter_count_total = 0;
1462   for (int i = 0; i < cntTracks; i++) {
1463     int audio_alter_count = 0;
1464     err = player_get_alternative_count(player_, PLAYER_STREAM_TYPE_AUDIO, i,
1465                                        &audio_alter_count);
1466     if (err != PLAYER_ERROR_NONE || audio_alter_count == 0) {
1467       LOG_ID(WARNING, player_id_)
1468           << "player_get_alternative_count error,idx: " << i
1469           << ",audio_alter_count: " << audio_alter_count;
1470       continue;
1471     }
1472
1473     LOG_ID(INFO, player_id_)
1474         << "audio track idx:" << i << ",alter_count:" << audio_alter_count;
1475     audio_alter_count_total += audio_alter_count;
1476     audio_track_info[i].alternatives =
1477         static_cast<Alternative_audioStreamInfo*>(
1478             malloc(audio_alter_count * sizeof(Alternative_audioStreamInfo)));
1479     if (!audio_track_info[i].alternatives) {
1480       LOG_ID(ERROR, player_id_)
1481           << "malloc fail,free memory which is already malloced";
1482       if (i >= 1) {
1483         for (int j = 0; j <= i - 1; j++)
1484           BLINKFREE(audio_track_info[j].alternatives);
1485       }
1486       BLINKFREE(audio_track_info);
1487       return;
1488     }
1489     memset(audio_track_info[i].alternatives, 0,
1490            audio_alter_count * sizeof(Alternative_audioStreamInfo));
1491   }
1492 #if !defined(EWK_BRINGUP)
1493   if (blink::IsHbbTV())
1494     AudioTracksCountChanged(audio_alter_count_total);
1495 #endif
1496   err = player_get_audio_adaptationset_info(player_, audio_track_info);
1497   if (err != PLAYER_ERROR_NONE) {
1498     LOG_ID(ERROR, player_id_) << "|player_get_audio_adaptationset_info| failed";
1499     for (int i = 0; i < cntTracks; i++)
1500       BLINKFREE(audio_track_info[i].alternatives);
1501     BLINKFREE(audio_track_info);
1502     return;
1503   }
1504
1505   int selected_idx = -1;
1506   int audio_track_index = 0;
1507
1508   /* Get audio index for prefer languange & audio description */
1509   for (int i = 0; i < cntTracks; i++) {
1510     if (!audio_track_info[i].alternatives) {
1511       LOG_ID(WARNING, player_id_) << "track[" << i << "] fail,ignore it.";
1512       continue;
1513     }
1514
1515     const char* language = audio_track_info[i].language;
1516     if (prefer_audio_lang_.find(language) != std::string::npos ||
1517         (GetAlpha2(prefer_audio_lang_).find(language) != std::string::npos)) {
1518       if (stream_type_ == DASH_STREAM)
1519         prefer_audio_adaptionset_idx_ = audio_track_info[i].index;
1520       else
1521         prefer_audio_adaptionset_idx_ = i;
1522
1523       selected_idx = i;
1524       break;
1525     }
1526   }
1527   LOG_ID(INFO, player_id_) << "prefer_audio_adaptationset_idx_: "
1528                            << prefer_audio_adaptionset_idx_
1529                            << ",selected_idx:" << selected_idx;
1530
1531   audio_track_index = 0;
1532
1533   for (int i = 0; i < cntTracks; i++) {
1534 #if TIZEN_VERSION_AT_LEAST(7, 0, 0)
1535     if (audio_track_info[i].preselectionInfo_count) {
1536       for (int j = 0; j < audio_track_info[i].preselectionInfo_count; j++) {
1537         std::string pres_id = audio_track_info[i].preselectionInfos[j].m_id;
1538         std::string language = audio_track_info[i].preselectionInfos[j].m_lang;
1539         std::string kind = audio_track_info[i].preselectionInfos[j].m_roleValue;
1540         std::string label = "";
1541         int enabled = (selected_idx == audio_track_index);
1542         AddAudioTrackInfo(pres_id, kind, label, language, enabled);
1543         audio_track_index++;
1544       }
1545       continue;
1546     }
1547 #endif
1548
1549     if (!audio_track_info[i].alternatives) {
1550       LOG_ID(WARNING, player_id_) << "track[" << i << "] fail,ignore it.";
1551       continue;
1552     }
1553     const char* lang = audio_track_info[i].language;
1554     std::string langStr(lang ? lang : "");
1555
1556     std::stringstream roleInfoBuilder;
1557     const int role_count = audio_track_info[i].role_count;
1558
1559     for (int k = 0; k < role_count; k++) {
1560       const char* role_member = audio_track_info[i].role_value[k];
1561       const std::string role_str(role_member ? role_member : "");
1562       roleInfoBuilder << role_str << ",";
1563     }
1564
1565     LOG_ID(INFO, player_id_)
1566         << "role str:" << roleInfoBuilder.str() << ",role count:" << role_count;
1567     std::string kindStr = "";
1568     if (stream_type_ == DASH_STREAM)
1569       kindStr = MapDashMediaTrackKind(roleInfoBuilder.str(), role_count, true);
1570     if (stream_type_ == TS_STREAM)  // role_count = 1
1571       kindStr = audio_track_info[i].role_value[0];
1572
1573     char* label = nullptr;
1574     err = player_get_content_info(player_, PLAYER_CONTENT_INFO_TITLE, &label);
1575     if (err != PLAYER_ERROR_NONE)
1576       LOG_ID(WARNING, player_id_) << "|player_get_content_info| failed";
1577     std::string labelStr(label ? label : "");
1578     BLINKFREE(label);
1579
1580     int id = 0;
1581     if (stream_type_ == DASH_STREAM)
1582       id = audio_track_info[i].adaptationset_id;
1583     else
1584       id = audio_track_info[i].alternatives[0].track_id;
1585
1586     std::string pres_id = std::to_string(id);
1587     std::string language = langStr;
1588     std::string kind = kindStr;
1589     std::string labels = labelStr;
1590     int enabled = (selected_idx == audio_track_index);
1591     AddAudioTrackInfo(pres_id, kind, labels, language, enabled);
1592     audio_track_index++;
1593   }
1594
1595   for (int j = 0; j < cntTracks; j++) {
1596     BLINKFREE(audio_track_info[j].alternatives);
1597 #if TIZEN_VERSION_AT_LEAST(7, 0, 0)
1598     BLINKFREE(audio_track_info[j].preselectionInfos);
1599 #endif
1600   }
1601
1602   BLINKFREE(audio_track_info);
1603 }
1604
1605 void MediaPlayerBridgeCapiTV::UpdateVideoTrackInfo() {
1606   int cntTracks = 0;
1607   int err = player_get_adaptationset_count(player_, PLAYER_STREAM_TYPE_VIDEO,
1608                                            &cntTracks);
1609   if (err != PLAYER_ERROR_NONE || cntTracks == 0) {
1610     LOG(ERROR) << "get video track fail,err:" << err << ",count" << cntTracks;
1611     return;
1612   }
1613
1614   LOG_ID(INFO, player_id_) << "video track count: " << cntTracks;
1615
1616   player_video_adaptationset_info* video_track_info =
1617       static_cast<player_video_adaptationset_info*>(
1618           malloc(cntTracks * sizeof(player_video_adaptationset_info)));
1619   if (!video_track_info) {
1620     LOG(ERROR) << "malloc fail";
1621     return;
1622   }
1623   memset(video_track_info, 0,
1624          cntTracks * sizeof(player_video_adaptationset_info));
1625
1626   int adaptionSetIdx = -1;
1627   int alternativeIdx = -1;
1628   err = player_get_current_track_ex(player_, PLAYER_STREAM_TYPE_VIDEO,
1629                                     &adaptionSetIdx, &alternativeIdx);
1630   if (err != PLAYER_ERROR_NONE)
1631     LOG(WARNING) << "|player_get_current_track| failed";
1632   LOG_ID(INFO, player_id_) << "video adaptionSetIdx:" << adaptionSetIdx
1633                            << ",alternativeIdx:" << alternativeIdx;
1634
1635   for (int i = 0; i < cntTracks; i++) {
1636     int video_alter_count = 0;
1637     err = player_get_alternative_count(player_, PLAYER_STREAM_TYPE_VIDEO, i,
1638                                        &video_alter_count);
1639     if (err != PLAYER_ERROR_NONE || video_alter_count == 0) {
1640       LOG(WARNING) << "player_get_alternative_count error,idx: " << i
1641                    << ",video_alter_count: " << video_alter_count;
1642       continue;
1643     }
1644
1645     LOG_ID(INFO, player_id_)
1646         << "video track idx:" << i << ",alter_count:" << video_alter_count;
1647     video_track_info[i].alternatives =
1648         static_cast<Alternative_videoStreamInfo*>(
1649             malloc(video_alter_count * sizeof(Alternative_videoStreamInfo)));
1650     if (!video_track_info[i].alternatives) {
1651       LOG(ERROR) << "malloc fail,free memory which is already malloced";
1652       if (i >= 1) {
1653         for (int j = 0; j <= i - 1; j++)
1654           BLINKFREE(video_track_info[j].alternatives);
1655       }
1656       BLINKFREE(video_track_info);
1657       return;
1658     }
1659     memset(video_track_info[i].alternatives, 0,
1660            video_alter_count * sizeof(Alternative_videoStreamInfo));
1661   }
1662
1663   err = player_get_video_adaptationset_info(player_, video_track_info);
1664   if (err != PLAYER_ERROR_NONE) {
1665     LOG(WARNING) << "|player_get_video_adaptationset_info| failed";
1666     for (int i = 0; i < cntTracks; i++)
1667       BLINKFREE(video_track_info[i].alternatives);
1668     BLINKFREE(video_track_info);
1669     return;
1670   }
1671
1672   for (int i = 0; i < cntTracks; i++) {
1673     if (!video_track_info[i].alternatives) {
1674       LOG(WARNING) << "track[" << i << "] fail,ignore it.";
1675       continue;
1676     }
1677
1678     char* lang = nullptr;
1679     err = player_get_track_language_code_ex(player_, PLAYER_STREAM_TYPE_VIDEO,
1680                                             i, &lang);
1681     if (err != PLAYER_ERROR_NONE)
1682       LOG(WARNING) << "|player_get_track_language_code| failed";
1683     std::string langStr(lang ? lang : "");
1684     BLINKFREE(lang);
1685
1686     std::stringstream roleInfoBuilder;
1687     const int role_count = video_track_info[i].role_count;
1688
1689     for (int k = 0; k < role_count; k++) {
1690       const char* role_member = video_track_info[i].role_value[k];
1691       const std::string role_str(role_member ? role_member : "");
1692       roleInfoBuilder << role_str << ",";
1693     }
1694
1695     LOG_ID(INFO, player_id_)
1696         << "role str:" << roleInfoBuilder.str() << ",role count:" << role_count;
1697
1698     std::string kindStr = "";
1699     if (stream_type_ == DASH_STREAM)
1700       kindStr = MapDashMediaTrackKind(roleInfoBuilder.str(), role_count, false);
1701
1702     char* label = nullptr;
1703     err = player_get_content_info(player_, PLAYER_CONTENT_INFO_TITLE, &label);
1704     if (err != PLAYER_ERROR_NONE)
1705       LOG(WARNING) << "|player_get_content_info| failed";
1706     std::string labelStr(label ? label : "");
1707     BLINKFREE(label);
1708
1709     int id = 0;
1710     if (stream_type_ == DASH_STREAM)
1711       id = video_track_info[i].adaptationset_id;
1712     else
1713       id = video_track_info[i].alternatives[0].track_id;
1714
1715     if (adaptionSetIdx == i)
1716       LOG_ID(INFO, player_id_) << "VideoTrack index: [" << i << "] is selected";
1717
1718     BLINKFREE(video_track_info[i].alternatives);
1719
1720     LOG_ID(INFO, player_id_)
1721         << "VideoTrack Info - id: " << id << ", kind: " << kindStr.c_str()
1722         << ", label: " << labelStr.c_str() << ", lang: " << langStr.c_str();
1723
1724     media::mojom::MediaTrackInfoPtr trackinfo =
1725         media::mojom::MediaTrackInfo::New();
1726     trackinfo->cmd = media::mojom::TRACKCMD::SETVIDEO;
1727     trackinfo->ck = media::mojom::COOKIES::NewTrack(media::mojom::Track::New(
1728         std::to_string(id), kindStr, labelStr, langStr, adaptionSetIdx == i));
1729
1730     if (GetMediaPlayerClient())
1731       GetMediaPlayerClient()->AddTrackInfo(std::move(trackinfo));
1732     else
1733       LOG(ERROR) << "Media player client is null";
1734   }
1735   BLINKFREE(video_track_info);
1736 }
1737
1738 void MediaPlayerBridgeCapiTV::UpdateTextTrackInfo() {
1739   int cntTracks = 0;
1740   int err = player_get_adaptationset_count(player_, PLAYER_STREAM_TYPE_TEXT,
1741                                            &cntTracks);
1742   if (err != PLAYER_ERROR_NONE || cntTracks == 0) {
1743     LOG_ID(ERROR, player_id_)
1744         << "get text track fail,err:" << err << ",count:" << cntTracks;
1745     return;
1746   }
1747
1748   LOG_ID(INFO, player_id_) << "text track count: " << cntTracks;
1749
1750   player_subtitle_adaptationset_info* text_track_info =
1751       static_cast<player_subtitle_adaptationset_info*>(
1752           malloc(cntTracks * sizeof(player_subtitle_adaptationset_info)));
1753   if (!text_track_info) {
1754     LOG_ID(ERROR, player_id_) << "malloc fail";
1755     return;
1756   }
1757   memset(text_track_info, 0,
1758          cntTracks * sizeof(player_subtitle_adaptationset_info));
1759
1760   int adaptionSetIdx = -1;
1761   int alternativeIdx = -1;
1762   err = player_get_current_track_ex(player_, PLAYER_STREAM_TYPE_TEXT,
1763                                     &adaptionSetIdx, &alternativeIdx);
1764   if (err != PLAYER_ERROR_NONE)
1765     LOG_ID(WARNING, player_id_) << "|player_get_current_track| failed";
1766   LOG_ID(INFO, player_id_) << "text adaptionSetIdx:" << adaptionSetIdx
1767                            << ",alternativeIdx:" << alternativeIdx;
1768
1769   for (int i = 0; i < cntTracks; i++) {
1770     int text_alter_count = 0;
1771     err = player_get_alternative_count(player_, PLAYER_STREAM_TYPE_TEXT, i,
1772                                        &text_alter_count);
1773     if (err != PLAYER_ERROR_NONE || text_alter_count == 0) {
1774       LOG_ID(WARNING, player_id_)
1775           << "player_get_alternative_count error,idx: " << i
1776           << ",text_alter_count: " << text_alter_count;
1777       continue;
1778     }
1779
1780     LOG_ID(INFO, player_id_)
1781         << "text track idx:" << i << ",alter_count:" << text_alter_count;
1782     text_track_info[i].alternatives =
1783         static_cast<Alternative_subtitleStreamInfo*>(
1784             malloc(text_alter_count * sizeof(Alternative_subtitleStreamInfo)));
1785     if (!text_track_info[i].alternatives) {
1786       LOG_ID(ERROR, player_id_)
1787           << "malloc fail,free memory which is already malloced";
1788       if (i >= 1) {
1789         for (int j = 0; j <= i - 1; j++)
1790           BLINKFREE(text_track_info[j].alternatives);
1791       }
1792       BLINKFREE(text_track_info);
1793       return;
1794     }
1795     memset(text_track_info[i].alternatives, 0,
1796            text_alter_count * sizeof(Alternative_subtitleStreamInfo));
1797   }
1798
1799   err = player_get_subtitle_adaptationset_info(player_, text_track_info);
1800   if (err != PLAYER_ERROR_NONE) {
1801     LOG_ID(ERROR, player_id_)
1802         << "|player_get_subtitle_adaptationset_info| failed";
1803     for (int i = 0; i < cntTracks; i++)
1804       BLINKFREE(text_track_info[i].alternatives);
1805     BLINKFREE(text_track_info);
1806     return;
1807   }
1808
1809   for (int i = 0; i < cntTracks; i++) {
1810     if (!text_track_info[i].alternatives) {
1811       LOG_ID(WARNING, player_id_) << "track[" << i << "] fail,ignore it.";
1812       continue;
1813     }
1814
1815     char* lang = nullptr;
1816     err = player_get_track_language_code_ex(player_, PLAYER_STREAM_TYPE_TEXT, i,
1817                                             &lang);
1818     if (err != PLAYER_ERROR_NONE)
1819       LOG_ID(ERROR, player_id_) << "|player_get_track_language_code| failed";
1820     std::string langStr(lang ? lang : "");
1821     BLINKFREE(lang);
1822
1823     char* label = nullptr;
1824     err = player_get_content_info(player_, PLAYER_CONTENT_INFO_TITLE, &label);
1825     if (err != PLAYER_ERROR_NONE)
1826       LOG_ID(ERROR, player_id_) << "|player_get_content_info| failed";
1827     std::string labelStr(label ? label : "");
1828     BLINKFREE(label);
1829
1830     int id = 0;
1831     if (stream_type_ == TS_STREAM)
1832       id = text_track_info[i].alternatives[0].track_id;
1833     else
1834       id = text_track_info[i].adaptationset_id;
1835
1836     std::string kindStr("");
1837 #if TIZEN_VERSION_AT_LEAST(6, 0, 0)
1838     // subtitling_type: 8bit, maybe unvisible char
1839     if (stream_type_ == TS_STREAM) {
1840       int subitle_type = (int)text_track_info[i].role_value[0][0];
1841       LOG(INFO) << "subitle_type:" << subitle_type;
1842       if (subitle_type == 0x10 || subitle_type == 0x11 ||
1843           subitle_type == 0x12 || subitle_type == 0x13 ||
1844           subitle_type == 0x14 || subitle_type == 0x15)
1845         kindStr = "subtitles";
1846     }
1847 #endif
1848
1849     if (adaptionSetIdx == i)
1850       LOG_ID(INFO, player_id_) << "TextTrack index: [" << i << "] is selected";
1851
1852     BLINKFREE(text_track_info[i].alternatives);
1853
1854     LOG_ID(INFO, player_id_)
1855         << "TextTrack Info - id: " << id << ", label: " << labelStr.c_str()
1856         << ", lang: " << langStr.c_str() << ", kind: " << kindStr.c_str();
1857
1858     media::mojom::MediaTrackInfoPtr trackinfo =
1859         media::mojom::MediaTrackInfo::New();
1860     trackinfo->cmd = media::mojom::TRACKCMD::SETTEXT;
1861     trackinfo->ck = media::mojom::COOKIES::NewTrack(media::mojom::Track::New(
1862         std::to_string(id), kindStr, labelStr, langStr, true));
1863
1864     if (GetMediaPlayerClient())
1865       GetMediaPlayerClient()->AddTrackInfo(std::move(trackinfo));
1866   }
1867
1868   BLINKFREE(text_track_info);
1869 }
1870
1871 void MediaPlayerBridgeCapiTV::UpdatePreferAudio() {
1872   LOG(INFO) << "UpdatePreferAudio,idx: " << prefer_audio_adaptionset_idx_
1873             << ",last idx:" << last_prefer_audio_adaptionset_idx_;
1874   if (prefer_audio_adaptionset_idx_ == last_prefer_audio_adaptionset_idx_) {
1875     LOG_ID(ERROR, player_id_) << "same track,no need to select";
1876     return;
1877   }
1878   int ret = player_select_track_ex(player_, PLAYER_STREAM_TYPE_AUDIO,
1879                                    prefer_audio_adaptionset_idx_, -1);
1880   if (ret != PLAYER_ERROR_NONE) {
1881     LOG_ID(ERROR, player_id_) << "player_select_track_ex fail";
1882     return;
1883   }
1884   active_audio_track_id_ = prefer_audio_adaptionset_idx_;
1885   last_prefer_audio_adaptionset_idx_ = prefer_audio_adaptionset_idx_;
1886 }
1887
1888 bool MediaPlayerBridgeCapiTV::GetUserPreferAudioLanguage() {
1889   prefer_audio_lang_.clear();
1890   int retval;
1891   const char* primary_audio_lang =
1892       "db/menu/broadcasting/audio_options/primary_audio_language";
1893   int ret = vconf_get_int(primary_audio_lang, &retval);
1894   if (ret != 0) {
1895     LOG(ERROR) << "vconf_get_int failed";
1896     return false;
1897   }
1898   prefer_audio_lang_ += (char)(retval >> 16 & 0xFF);
1899   prefer_audio_lang_ += (char)(retval >> 8 & 0xFF);
1900   prefer_audio_lang_ += (char)(retval & 0xFF);
1901   LOG_ID(INFO, player_id_) << "primary audio lang is: "
1902                            << prefer_audio_lang_.c_str();
1903   return true;
1904 }
1905
1906 void MediaPlayerBridgeCapiTV::SetActiveTextTrack(int id, bool is_in_band) {
1907   LOG_ID(INFO, player_id_) << "id=" << id << ",is_in_band=" << is_in_band
1908                            << " active_text_track_id_ "
1909                            << active_text_track_id_;
1910   if (!GetMediaPlayerClient()) {
1911     LOG(ERROR) << "GetMediaPlayerClient return null";
1912     return;
1913   }
1914   if (!GetMediaPlayerClient()->SubtitleNotificationEnabled()) {
1915     LOG(ERROR) << "SubtitleNotificationEnabled failed";
1916     return;
1917   }
1918
1919 #if !defined(EWK_BRINGUP)
1920   if (id == -1) {
1921     NotifyStopTrack();
1922     return;
1923   }
1924
1925   if (active_text_track_id_ == id)
1926     return;
1927
1928   active_text_track_id_ = id;
1929
1930   is_inband_text_track_ = is_in_band;
1931   NotifyPlayTrack();
1932 #endif
1933 }
1934
1935 void MediaPlayerBridgeCapiTV::SetActiveAudioTrack(int index) {
1936   LOG_ID(INFO, player_id_) << "active_audio_track_id_ "
1937                            << active_audio_track_id_ << " index " << index;
1938
1939   if (index == -1) {
1940     player_set_mute(player_, true);
1941     active_audio_track_id_ = -1;
1942     return;
1943   }
1944
1945   if (active_audio_track_id_ == index)
1946     return;
1947   active_audio_track_id_ = index;
1948   int ret = player_select_track_ex(player_, PLAYER_STREAM_TYPE_AUDIO,
1949                                    active_audio_track_id_, -1);
1950   if (ret != PLAYER_ERROR_NONE)
1951     LOG_ID(WARNING, player_id_) << "player_select_track_ex fail,ret:" << ret;
1952 }
1953
1954 void MediaPlayerBridgeCapiTV::SetActiveVideoTrack(int index) {
1955   LOG_ID(INFO, player_id_) << "active_video_track_id_ "
1956                            << active_video_track_id_ << " index " << index;
1957
1958   if (index == -1) {
1959     player_set_display_visible(player_, false);
1960     active_video_track_id_ = -1;
1961     return;
1962   }
1963
1964   if (active_video_track_id_ == index)
1965     return;
1966   active_video_track_id_ = index;
1967   int ret = player_select_track_ex(player_, PLAYER_STREAM_TYPE_VIDEO,
1968                                    active_video_track_id_, -1);
1969   if (ret != PLAYER_ERROR_NONE)
1970     LOG_ID(WARNING, player_id_) << "player_select_track_ex fail,ret:" << ret;
1971 }
1972
1973 void MediaPlayerBridgeCapiTV::SetPreferTextLanguage(const std::string& lang) {
1974   LOG_ID(INFO, player_id_)
1975       << "MediaPlayerBridgeCapiTV::SetPreferTextLanguage lang" << lang
1976       << " prefer_subtitle_lang_ " << prefer_subtitle_lang_;
1977
1978   if (lang == prefer_subtitle_lang_)
1979     return;
1980   prefer_subtitle_lang_ = lang;
1981   const std::string prefer_subtitle_language =
1982       "set_subtitle_language = " + lang;
1983
1984   LOG_ID(INFO, player_id_) << "prefer_subtitle_language:"
1985                            << prefer_subtitle_language.c_str();
1986   player_set_ini_param(player_, prefer_subtitle_language.c_str());
1987 }
1988
1989 std::string MediaPlayerBridgeCapiTV::ParseDashKeyword(
1990     const std::string& keyword) {
1991   std::string dash_info = GetDashInfo();
1992   Json::CharReaderBuilder builder;
1993   Json::CharReader* reader(builder.newCharReader());
1994   Json::Value value;
1995   std::string valueForKey;
1996
1997   if (reader->parse(dash_info.c_str(), dash_info.c_str() + dash_info.length(),
1998                     &value, nullptr)) {
1999     valueForKey = value[keyword].asString();
2000     LOG_ID(INFO, player_id_)
2001         << "keyword: " << keyword << ",valueForKey:" << valueForKey;
2002     return valueForKey;
2003   }
2004   return "";
2005 }
2006
2007 double MediaPlayerBridgeCapiTV::GetStartDate() {
2008   int64_t millisecond = 0;
2009   int ret = player_get_start_date(player_, &millisecond);
2010   if (ret != PLAYER_ERROR_NONE) {
2011     /* In case of invalid state try to use player_get_dash_info()
2012      and parse it for availabilityStartTime -legacy hack*/
2013     if (ret == PLAYER_ERROR_INVALID_STATE) {
2014       const std::string start_date_keyword = "availabilityStartTime";
2015       std::string start_date = ParseDashKeyword(start_date_keyword);
2016       LOG_ID(ERROR, player_id_) << "from ParseDashKeyword: " << start_date;
2017       if (!start_date.empty()) {
2018         double start_date_ret = 0.0;
2019         std::stringstream ss;
2020         ss << start_date;
2021         ss >> start_date_ret;
2022         OnHandlePlayerError(ret, FROM_HERE);
2023         return start_date_ret;
2024       }
2025     }
2026     OnHandlePlayerError(ret, FROM_HERE);
2027     LOG_ID(ERROR, player_id_) << "player_get_start_date fail,ret:" << ret;
2028     return std::numeric_limits<double>::quiet_NaN();
2029   }
2030
2031   return static_cast<double>(millisecond);
2032 }
2033 }  // namespace media