Home | History | Annotate | Download | only in android
      1 // Copyright (c) 2012 The Chromium Authors. 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/base/android/media_player_bridge.h"
      6 
      7 #include "base/android/jni_android.h"
      8 #include "base/android/jni_string.h"
      9 #include "base/basictypes.h"
     10 #include "base/logging.h"
     11 #include "base/message_loop/message_loop_proxy.h"
     12 #include "base/strings/string_util.h"
     13 #include "jni/MediaPlayerBridge_jni.h"
     14 #include "media/base/android/media_player_manager.h"
     15 #include "media/base/android/media_resource_getter.h"
     16 
     17 using base::android::ConvertUTF8ToJavaString;
     18 using base::android::ScopedJavaLocalRef;
     19 
     20 // Time update happens every 250ms.
     21 static const int kTimeUpdateInterval = 250;
     22 
     23 namespace media {
     24 
     25 MediaPlayerBridge::MediaPlayerBridge(
     26     int player_id,
     27     const GURL& url,
     28     const GURL& first_party_for_cookies,
     29     bool hide_url_log,
     30     MediaPlayerManager* manager)
     31     : MediaPlayerAndroid(player_id,
     32                          manager),
     33       prepared_(false),
     34       pending_play_(false),
     35       url_(url),
     36       first_party_for_cookies_(first_party_for_cookies),
     37       hide_url_log_(hide_url_log),
     38       width_(0),
     39       height_(0),
     40       can_pause_(true),
     41       can_seek_forward_(true),
     42       can_seek_backward_(true),
     43       weak_this_(this),
     44       listener_(base::MessageLoopProxy::current(),
     45                 weak_this_.GetWeakPtr()) {
     46 }
     47 
     48 MediaPlayerBridge::~MediaPlayerBridge() {
     49   if (!j_media_player_bridge_.is_null()) {
     50     JNIEnv* env = base::android::AttachCurrentThread();
     51     CHECK(env);
     52     Java_MediaPlayerBridge_destroy(env, j_media_player_bridge_.obj());
     53   }
     54   Release();
     55 }
     56 
     57 void MediaPlayerBridge::Initialize() {
     58   if (url_.SchemeIsFile()) {
     59     cookies_.clear();
     60     ExtractMediaMetadata(url_.spec());
     61     return;
     62   }
     63 
     64   media::MediaResourceGetter* resource_getter =
     65       manager()->GetMediaResourceGetter();
     66   if (url_.SchemeIsFileSystem()) {
     67     cookies_.clear();
     68     resource_getter->GetPlatformPathFromFileSystemURL(url_, base::Bind(
     69         &MediaPlayerBridge::ExtractMediaMetadata, weak_this_.GetWeakPtr()));
     70     return;
     71   }
     72 
     73   resource_getter->GetCookies(url_, first_party_for_cookies_, base::Bind(
     74       &MediaPlayerBridge::OnCookiesRetrieved, weak_this_.GetWeakPtr()));
     75 }
     76 
     77 void MediaPlayerBridge::CreateJavaMediaPlayerBridge() {
     78   JNIEnv* env = base::android::AttachCurrentThread();
     79   CHECK(env);
     80 
     81   j_media_player_bridge_.Reset(Java_MediaPlayerBridge_create(
     82       env, reinterpret_cast<intptr_t>(this)));
     83 
     84   SetMediaPlayerListener();
     85 }
     86 
     87 void MediaPlayerBridge::SetJavaMediaPlayerBridge(
     88     jobject j_media_player_bridge) {
     89   JNIEnv* env = base::android::AttachCurrentThread();
     90   CHECK(env);
     91 
     92   j_media_player_bridge_.Reset(env, j_media_player_bridge);
     93 }
     94 
     95 base::android::ScopedJavaLocalRef<jobject> MediaPlayerBridge::
     96     GetJavaMediaPlayerBridge() {
     97   base::android::ScopedJavaLocalRef<jobject> j_bridge(
     98       j_media_player_bridge_);
     99   return j_bridge;
    100 }
    101 
    102 void MediaPlayerBridge::SetMediaPlayerListener() {
    103   jobject j_context = base::android::GetApplicationContext();
    104   DCHECK(j_context);
    105 
    106   listener_.CreateMediaPlayerListener(j_context, j_media_player_bridge_.obj());
    107 }
    108 
    109 void MediaPlayerBridge::SetDuration(base::TimeDelta duration) {
    110   duration_ = duration;
    111 }
    112 
    113 void MediaPlayerBridge::SetVideoSurface(gfx::ScopedJavaSurface surface) {
    114   if (j_media_player_bridge_.is_null()) {
    115     if (surface.IsEmpty())
    116       return;
    117     Prepare();
    118   }
    119 
    120   JNIEnv* env = base::android::AttachCurrentThread();
    121   CHECK(env);
    122 
    123   Java_MediaPlayerBridge_setSurface(
    124       env, j_media_player_bridge_.obj(), surface.j_surface().obj());
    125 }
    126 
    127 void MediaPlayerBridge::Prepare() {
    128   DCHECK(j_media_player_bridge_.is_null());
    129   CreateJavaMediaPlayerBridge();
    130   if (url_.SchemeIsFileSystem()) {
    131     manager()->GetMediaResourceGetter()->GetPlatformPathFromFileSystemURL(
    132             url_, base::Bind(&MediaPlayerBridge::SetDataSource,
    133                              weak_this_.GetWeakPtr()));
    134   } else {
    135     SetDataSource(url_.spec());
    136   }
    137 }
    138 
    139 void MediaPlayerBridge::SetDataSource(const std::string& url) {
    140   if (j_media_player_bridge_.is_null())
    141     return;
    142 
    143   JNIEnv* env = base::android::AttachCurrentThread();
    144   CHECK(env);
    145 
    146   // Create a Java String for the URL.
    147   ScopedJavaLocalRef<jstring> j_url_string = ConvertUTF8ToJavaString(env, url);
    148   ScopedJavaLocalRef<jstring> j_cookies = ConvertUTF8ToJavaString(
    149       env, cookies_);
    150 
    151   jobject j_context = base::android::GetApplicationContext();
    152   DCHECK(j_context);
    153 
    154   const std::string data_uri_prefix("data:");
    155   if (StartsWithASCII(url, data_uri_prefix, true)) {
    156     if (!Java_MediaPlayerBridge_setDataUriDataSource(
    157         env, j_media_player_bridge_.obj(), j_context, j_url_string.obj())) {
    158       OnMediaError(MEDIA_ERROR_FORMAT);
    159     }
    160     return;
    161   }
    162 
    163   if (!Java_MediaPlayerBridge_setDataSource(
    164       env, j_media_player_bridge_.obj(), j_context, j_url_string.obj(),
    165       j_cookies.obj(), hide_url_log_)) {
    166     OnMediaError(MEDIA_ERROR_FORMAT);
    167     return;
    168   }
    169 
    170   manager()->RequestMediaResources(player_id());
    171   if (!Java_MediaPlayerBridge_prepareAsync(env, j_media_player_bridge_.obj()))
    172     OnMediaError(MEDIA_ERROR_FORMAT);
    173 }
    174 
    175 void MediaPlayerBridge::OnDidSetDataUriDataSource(JNIEnv* env, jobject obj,
    176     jboolean success) {
    177   if (!success) {
    178     OnMediaError(MEDIA_ERROR_FORMAT);
    179     return;
    180   }
    181 
    182   manager()->RequestMediaResources(player_id());
    183   if (!Java_MediaPlayerBridge_prepareAsync(env, j_media_player_bridge_.obj()))
    184     OnMediaError(MEDIA_ERROR_FORMAT);
    185 }
    186 
    187 void MediaPlayerBridge::OnCookiesRetrieved(const std::string& cookies) {
    188   cookies_ = cookies;
    189   ExtractMediaMetadata(url_.spec());
    190 }
    191 
    192 void MediaPlayerBridge::ExtractMediaMetadata(const std::string& url) {
    193   manager()->GetMediaResourceGetter()->ExtractMediaMetadata(
    194       url, cookies_, base::Bind(&MediaPlayerBridge::OnMediaMetadataExtracted,
    195                                 weak_this_.GetWeakPtr()));
    196 }
    197 
    198 void MediaPlayerBridge::OnMediaMetadataExtracted(
    199     base::TimeDelta duration, int width, int height, bool success) {
    200   if (success) {
    201     duration_ = duration;
    202     width_ = width;
    203     height_ = height;
    204   }
    205   manager()->OnMediaMetadataChanged(
    206       player_id(), duration_, width_, height_, success);
    207 }
    208 
    209 void MediaPlayerBridge::Start() {
    210   if (j_media_player_bridge_.is_null()) {
    211     pending_play_ = true;
    212     Prepare();
    213   } else {
    214     if (prepared_)
    215       StartInternal();
    216     else
    217       pending_play_ = true;
    218   }
    219 }
    220 
    221 void MediaPlayerBridge::Pause(bool is_media_related_action) {
    222   if (j_media_player_bridge_.is_null()) {
    223     pending_play_ = false;
    224   } else {
    225     if (prepared_ && IsPlaying())
    226       PauseInternal();
    227     else
    228       pending_play_ = false;
    229   }
    230 }
    231 
    232 bool MediaPlayerBridge::IsPlaying() {
    233   if (!prepared_)
    234     return pending_play_;
    235 
    236   JNIEnv* env = base::android::AttachCurrentThread();
    237   CHECK(env);
    238   jboolean result = Java_MediaPlayerBridge_isPlaying(
    239       env, j_media_player_bridge_.obj());
    240   return result;
    241 }
    242 
    243 int MediaPlayerBridge::GetVideoWidth() {
    244   if (!prepared_)
    245     return width_;
    246   JNIEnv* env = base::android::AttachCurrentThread();
    247   return Java_MediaPlayerBridge_getVideoWidth(
    248       env, j_media_player_bridge_.obj());
    249 }
    250 
    251 int MediaPlayerBridge::GetVideoHeight() {
    252   if (!prepared_)
    253     return height_;
    254   JNIEnv* env = base::android::AttachCurrentThread();
    255   return Java_MediaPlayerBridge_getVideoHeight(
    256       env, j_media_player_bridge_.obj());
    257 }
    258 
    259 void MediaPlayerBridge::SeekTo(const base::TimeDelta& timestamp) {
    260   // Record the time to seek when OnMediaPrepared() is called.
    261   pending_seek_ = timestamp;
    262 
    263   if (j_media_player_bridge_.is_null())
    264     Prepare();
    265   else if (prepared_)
    266     SeekInternal(timestamp);
    267 }
    268 
    269 base::TimeDelta MediaPlayerBridge::GetCurrentTime() {
    270   if (!prepared_)
    271     return pending_seek_;
    272   JNIEnv* env = base::android::AttachCurrentThread();
    273   return base::TimeDelta::FromMilliseconds(
    274       Java_MediaPlayerBridge_getCurrentPosition(
    275           env, j_media_player_bridge_.obj()));
    276 }
    277 
    278 base::TimeDelta MediaPlayerBridge::GetDuration() {
    279   if (!prepared_)
    280     return duration_;
    281   JNIEnv* env = base::android::AttachCurrentThread();
    282   return base::TimeDelta::FromMilliseconds(
    283       Java_MediaPlayerBridge_getDuration(
    284           env, j_media_player_bridge_.obj()));
    285 }
    286 
    287 void MediaPlayerBridge::Release() {
    288   if (j_media_player_bridge_.is_null())
    289     return;
    290 
    291   time_update_timer_.Stop();
    292   if (prepared_)
    293     pending_seek_ = GetCurrentTime();
    294   prepared_ = false;
    295   pending_play_ = false;
    296   SetVideoSurface(gfx::ScopedJavaSurface());
    297 
    298   JNIEnv* env = base::android::AttachCurrentThread();
    299   Java_MediaPlayerBridge_release(env, j_media_player_bridge_.obj());
    300   j_media_player_bridge_.Reset();
    301   manager()->ReleaseMediaResources(player_id());
    302   listener_.ReleaseMediaPlayerListenerResources();
    303 }
    304 
    305 void MediaPlayerBridge::SetVolume(double volume) {
    306   if (j_media_player_bridge_.is_null())
    307     return;
    308 
    309   JNIEnv* env = base::android::AttachCurrentThread();
    310   CHECK(env);
    311   Java_MediaPlayerBridge_setVolume(
    312       env, j_media_player_bridge_.obj(), volume);
    313 }
    314 
    315 void MediaPlayerBridge::OnVideoSizeChanged(int width, int height) {
    316   width_ = width;
    317   height_ = height;
    318   manager()->OnVideoSizeChanged(player_id(), width, height);
    319 }
    320 
    321 void MediaPlayerBridge::OnMediaError(int error_type) {
    322   manager()->OnError(player_id(), error_type);
    323 }
    324 
    325 void MediaPlayerBridge::OnBufferingUpdate(int percent) {
    326   manager()->OnBufferingUpdate(player_id(), percent);
    327 }
    328 
    329 void MediaPlayerBridge::OnPlaybackComplete() {
    330   time_update_timer_.Stop();
    331   manager()->OnPlaybackComplete(player_id());
    332 }
    333 
    334 void MediaPlayerBridge::OnMediaInterrupted() {
    335   time_update_timer_.Stop();
    336   manager()->OnMediaInterrupted(player_id());
    337 }
    338 
    339 void MediaPlayerBridge::OnSeekComplete() {
    340   manager()->OnSeekComplete(player_id(), GetCurrentTime());
    341 }
    342 
    343 void MediaPlayerBridge::OnMediaPrepared() {
    344   if (j_media_player_bridge_.is_null())
    345     return;
    346 
    347   prepared_ = true;
    348   duration_ = GetDuration();
    349 
    350   // If media player was recovered from a saved state, consume all the pending
    351   // events.
    352   PendingSeekInternal(pending_seek_);
    353 
    354   if (pending_play_) {
    355     StartInternal();
    356     pending_play_ = false;
    357   }
    358 
    359   UpdateAllowedOperations();
    360   manager()->OnMediaMetadataChanged(
    361       player_id(), duration_, width_, height_, true);
    362 }
    363 
    364 ScopedJavaLocalRef<jobject> MediaPlayerBridge::GetAllowedOperations() {
    365   JNIEnv* env = base::android::AttachCurrentThread();
    366   CHECK(env);
    367 
    368   return Java_MediaPlayerBridge_getAllowedOperations(
    369       env, j_media_player_bridge_.obj());
    370 }
    371 
    372 void MediaPlayerBridge::UpdateAllowedOperations() {
    373   JNIEnv* env = base::android::AttachCurrentThread();
    374   CHECK(env);
    375 
    376   ScopedJavaLocalRef<jobject> allowedOperations = GetAllowedOperations();
    377 
    378   can_pause_ = Java_AllowedOperations_canPause(env, allowedOperations.obj());
    379   can_seek_forward_ = Java_AllowedOperations_canSeekForward(
    380       env, allowedOperations.obj());
    381   can_seek_backward_ = Java_AllowedOperations_canSeekBackward(
    382       env, allowedOperations.obj());
    383 }
    384 
    385 void MediaPlayerBridge::StartInternal() {
    386   JNIEnv* env = base::android::AttachCurrentThread();
    387   Java_MediaPlayerBridge_start(env, j_media_player_bridge_.obj());
    388   if (!time_update_timer_.IsRunning()) {
    389     time_update_timer_.Start(
    390         FROM_HERE,
    391         base::TimeDelta::FromMilliseconds(kTimeUpdateInterval),
    392         this, &MediaPlayerBridge::OnTimeUpdateTimerFired);
    393   }
    394 }
    395 
    396 void MediaPlayerBridge::PauseInternal() {
    397   JNIEnv* env = base::android::AttachCurrentThread();
    398   Java_MediaPlayerBridge_pause(env, j_media_player_bridge_.obj());
    399   time_update_timer_.Stop();
    400 }
    401 
    402 void MediaPlayerBridge::PendingSeekInternal(const base::TimeDelta& time) {
    403   SeekInternal(time);
    404 }
    405 
    406 void MediaPlayerBridge::SeekInternal(base::TimeDelta time) {
    407   if (time > duration_)
    408     time = duration_;
    409 
    410   // Seeking to an invalid position may cause media player to stuck in an
    411   // error state.
    412   if (time < base::TimeDelta()) {
    413     DCHECK_EQ(-1.0, time.InMillisecondsF());
    414     return;
    415   }
    416 
    417   JNIEnv* env = base::android::AttachCurrentThread();
    418   CHECK(env);
    419   int time_msec = static_cast<int>(time.InMilliseconds());
    420   Java_MediaPlayerBridge_seekTo(
    421       env, j_media_player_bridge_.obj(), time_msec);
    422 }
    423 
    424 void MediaPlayerBridge::OnTimeUpdateTimerFired() {
    425   manager()->OnTimeUpdate(player_id(), GetCurrentTime());
    426 }
    427 
    428 bool MediaPlayerBridge::RegisterMediaPlayerBridge(JNIEnv* env) {
    429   bool ret = RegisterNativesImpl(env);
    430   DCHECK(g_MediaPlayerBridge_clazz);
    431   return ret;
    432 }
    433 
    434 bool MediaPlayerBridge::CanPause() {
    435   return can_pause_;
    436 }
    437 
    438 bool MediaPlayerBridge::CanSeekForward() {
    439   return can_seek_forward_;
    440 }
    441 
    442 bool MediaPlayerBridge::CanSeekBackward() {
    443   return can_seek_backward_;
    444 }
    445 
    446 bool MediaPlayerBridge::IsPlayerReady() {
    447   return prepared_;
    448 }
    449 
    450 GURL MediaPlayerBridge::GetUrl() {
    451   return url_;
    452 }
    453 
    454 GURL MediaPlayerBridge::GetFirstPartyForCookies() {
    455   return first_party_for_cookies_;
    456 }
    457 
    458 }  // namespace media
    459