Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(160)

Unified Diff: media/base/android/media_player_bridge.cc

Issue 10919075: Move android mediaplayer from render process to browser process. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: addressing comments and resolving merge conflicts Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/base/android/media_player_bridge.h ('k') | media/base/android/media_player_bridge_manager.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/base/android/media_player_bridge.cc
diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc
index 2728271217a8e6f0793f305707309465e80ed00a..423ae7a5e949011800423199de490949e26e3bce 100644
--- a/media/base/android/media_player_bridge.cc
+++ b/media/base/android/media_player_bridge.cc
@@ -9,10 +9,9 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/stringprintf.h"
-
-// Auto generated jni class from MediaPlayerListener.java.
-// Check base/android/jni_generator/golden_sample_for_tests_jni.h for example.
-#include "jni/MediaPlayerListener_jni.h"
+#include "base/message_loop_proxy.h"
+#include "media/base/android/cookie_getter.h"
+#include "media/base/android/media_player_bridge_manager.h"
using base::android::AttachCurrentThread;
using base::android::CheckException;
@@ -31,9 +30,65 @@ static const jint kSeekForwardAvailable = 3;
// This needs to be kept in sync with android.os.PowerManager
static const int kAndroidFullWakeLock = 26;
+// Time update happens every 250ms.
+static const int kTimeUpdateInterval = 250;
+
+// Because we create the media player lazily on android, the duration of the
+// media is initially unknown to us. This makes the user unable to perform
+// seek. To solve this problem, we use a temporary duration of 100 seconds when
+// the duration is unknown. And we scale the seek position later when duration
+// is available.
+// TODO(qinmin): create a thread and use android MediaMetadataRetriever
+// class to extract the duration.
+static const int kTemporaryDuration = 100;
+
namespace media {
-MediaPlayerBridge::MediaPlayerBridge() {
+MediaPlayerBridge::MediaPlayerBridge(
+ int player_id,
+ const std::string& url,
+ const std::string& first_party_for_cookies,
+ CookieGetter* cookie_getter,
+ bool hide_url_log,
+ MediaPlayerBridgeManager* manager,
+ const MediaErrorCB& media_error_cb,
+ const VideoSizeChangedCB& video_size_changed_cb,
+ const BufferingUpdateCB& buffering_update_cb,
+ const MediaPreparedCB& media_prepared_cb,
+ const PlaybackCompleteCB& playback_complete_cb,
+ const SeekCompleteCB& seek_complete_cb,
+ const TimeUpdateCB& time_update_cb)
+ : media_error_cb_(media_error_cb),
+ video_size_changed_cb_(video_size_changed_cb),
+ buffering_update_cb_(buffering_update_cb),
+ media_prepared_cb_(media_prepared_cb),
+ playback_complete_cb_(playback_complete_cb),
+ seek_complete_cb_(seek_complete_cb),
+ time_update_cb_(time_update_cb),
+ player_id_(player_id),
+ prepared_(false),
+ pending_play_(false),
+ url_(url),
+ first_party_for_cookies_(first_party_for_cookies),
+ has_cookies_(false),
+ hide_url_log_(hide_url_log),
+ duration_(base::TimeDelta::FromSeconds(kTemporaryDuration)),
+ width_(0),
+ height_(0),
+ can_pause_(true),
+ can_seek_forward_(true),
+ can_seek_backward_(true),
+ manager_(manager),
+ cookie_getter_(cookie_getter),
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)),
+ listener_(base::MessageLoopProxy::current(),
+ weak_this_.GetWeakPtr()) {}
+
+MediaPlayerBridge::~MediaPlayerBridge() {
+ Release();
+}
+
+void MediaPlayerBridge::InitializePlayer() {
JNIEnv* env = AttachCurrentThread();
CHECK(env);
@@ -48,16 +103,13 @@ MediaPlayerBridge::MediaPlayerBridge() {
j_media_player_.Reset(tmp);
ScopedJavaLocalRef<jobject> j_listener(
- Java_MediaPlayerListener_create(env,
- reinterpret_cast<intptr_t>(this)));
- DCHECK(!j_listener.is_null());
+ listener_.CreateMediaPlayerListener());
// Set it as the various listeners.
const char* listeners[] = {
"OnBufferingUpdateListener",
"OnCompletionListener",
"OnErrorListener",
- "OnInfoListener",
"OnPreparedListener",
"OnSeekCompleteListener",
"OnVideoSizeChangedListener",
@@ -73,22 +125,52 @@ MediaPlayerBridge::MediaPlayerBridge() {
env->CallVoidMethod(j_media_player_.obj(), method, j_listener.obj());
CheckException(env);
}
+
+ jobject j_context = base::android::GetApplicationContext();
+ DCHECK(j_context);
+ jmethodID method = GetMethodID(env, j_media_player_class_,
+ "setWakeMode", "(Landroid/content/Context;I)V");
+ env->CallVoidMethod(j_media_player_.obj(), method, j_context,
+ kAndroidFullWakeLock);
+ CheckException(env);
}
-MediaPlayerBridge::~MediaPlayerBridge() {
- SetVideoSurface(NULL);
- CallVoidMethod("release");
+void MediaPlayerBridge::SetVideoSurface(jobject surface) {
+ if (j_media_player_.is_null() && surface != NULL)
+ Prepare();
+
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+
+ jmethodID method = GetMethodID(env,
+ j_media_player_class_,
+ "setSurface",
+ "(Landroid/view/Surface;)V");
+ env->CallVoidMethod(j_media_player_.obj(), method, surface);
+ CheckException(env);
}
-void MediaPlayerBridge::SetDataSource(
- const std::string& url,
- const std::string& cookies,
- bool hide_url_log) {
+void MediaPlayerBridge::Prepare() {
+ if (j_media_player_.is_null())
+ InitializePlayer();
+
+ if (has_cookies_) {
+ GetCookiesCallback(cookies_);
+ } else {
+ cookie_getter_->GetCookies(url_, first_party_for_cookies_, base::Bind(
+ &MediaPlayerBridge::GetCookiesCallback, weak_this_.GetWeakPtr()));
+ }
+}
+
+void MediaPlayerBridge::GetCookiesCallback(const std::string& cookies) {
+ cookies_ = cookies;
+ has_cookies_ = true;
+
JNIEnv* env = AttachCurrentThread();
CHECK(env);
// Create a Java String for the URL.
- ScopedJavaLocalRef<jstring> j_url_string = ConvertUTF8ToJavaString(env, url);
+ ScopedJavaLocalRef<jstring> j_url_string = ConvertUTF8ToJavaString(env, url_);
// Create the android.net.Uri object.
ScopedJavaLocalRef<jclass> cls(GetClass(env, "android/net/Uri"));
@@ -108,11 +190,11 @@ void MediaPlayerBridge::SetDataSource(
// Construct headers that needs to be sent with the url.
HeadersMap headers;
// For incognito mode, we need a header to hide url log.
- if (hide_url_log)
+ if (hide_url_log_)
headers.insert(std::make_pair("x-hide-urls-from-log", "true"));
// If cookies are present, add them in the header.
- if (!cookies.empty())
- headers.insert(std::make_pair("Cookie", cookies));
+ if (!cookies_.empty())
+ headers.insert(std::make_pair("Cookie", cookies_));
// Fill the Map with the headers.
for (HeadersMap::const_iterator iter = headers.begin();
@@ -131,101 +213,112 @@ void MediaPlayerBridge::SetDataSource(
jmethodID set_data_source =
GetMethodID(env, j_media_player_class_, "setDataSource",
"(Landroid/content/Context;Landroid/net/Uri;Ljava/util/Map;)V");
- DCHECK(set_data_source);
env->CallVoidMethod(j_media_player_.obj(), set_data_source, j_context,
j_uri.obj(), j_map.obj());
- CheckException(env);
-}
-
-void MediaPlayerBridge::SetVideoSurface(jobject surface) {
- JNIEnv* env = AttachCurrentThread();
- CHECK(env);
-
- jmethodID method = GetMethodID(env,
- j_media_player_class_,
- "setSurface",
- "(Landroid/view/Surface;)V");
- env->CallVoidMethod(j_media_player_.obj(), method, surface);
- CheckException(env);
-}
-
-void MediaPlayerBridge::Prepare(const MediaInfoCB& media_info_cb,
- const MediaErrorCB& media_error_cb,
- const VideoSizeChangedCB& video_size_changed_cb,
- const BufferingUpdateCB& buffering_update_cb,
- const base::Closure& media_prepared_cb) {
- media_info_cb_ = media_info_cb;
- media_error_cb_ = media_error_cb,
- video_size_changed_cb_ = video_size_changed_cb;
- buffering_update_cb_ = buffering_update_cb;
- media_prepared_cb_ = media_prepared_cb;
- CallVoidMethod("prepareAsync");
+ bool is_data_source_set_ = !base::android::ClearException(env);
+
+ if (is_data_source_set_) {
+ if (manager_)
+ manager_->RequestMediaResources(this);
+ CallVoidMethod("prepareAsync");
+ } else {
+ media_error_cb_.Run(player_id_, MEDIA_ERROR_UNKNOWN);
+ }
}
-void MediaPlayerBridge::Start(const base::Closure& playback_complete_cb) {
- playback_complete_cb_ = playback_complete_cb;
- CallVoidMethod("start");
+void MediaPlayerBridge::Start() {
+ if (j_media_player_.is_null()) {
+ pending_play_ = true;
+ Prepare();
+ } else {
+ if (prepared_)
+ StartInternal();
+ else
+ pending_play_ = true;
+ }
}
void MediaPlayerBridge::Pause() {
- CallVoidMethod("pause");
+ if (j_media_player_.is_null()) {
+ pending_play_ = false;
+ } else {
+ if (prepared_ && IsPlaying())
+ PauseInternal();
+ else
+ pending_play_ = false;
+ }
}
-void MediaPlayerBridge::Stop() {
- CallVoidMethod("stop");
-}
bool MediaPlayerBridge::IsPlaying() {
+ if (!prepared_)
+ return pending_play_;
+
JNIEnv* env = AttachCurrentThread();
CHECK(env);
- jmethodID method = GetMethodID(env,
- j_media_player_class_,
- "isPlaying",
+ jmethodID method = GetMethodID(env, j_media_player_class_, "isPlaying",
"()Z");
- jint result = env->CallBooleanMethod(j_media_player_.obj(), method);
+ jboolean result = env->CallBooleanMethod(j_media_player_.obj(), method);
CheckException(env);
return result;
}
int MediaPlayerBridge::GetVideoWidth() {
+ if (!prepared_)
+ return width_;
return CallIntMethod("getVideoWidth");
}
int MediaPlayerBridge::GetVideoHeight() {
+ if (!prepared_)
+ return height_;
return CallIntMethod("getVideoHeight");
}
-void MediaPlayerBridge::SeekTo(base::TimeDelta time,
- const base::Closure& seek_complete_cb) {
- seek_complete_cb_ = seek_complete_cb;
- JNIEnv* env = AttachCurrentThread();
- CHECK(env);
+void MediaPlayerBridge::SeekTo(base::TimeDelta time) {
+ // Record the time to seek when OnMediaPrepared() is called.
+ pending_seek_ = time;
- jmethodID method = GetMethodID(env, j_media_player_class_, "seekTo", "(I)V");
- DCHECK(method);
- int time_msec = static_cast<int>(time.InMilliseconds());
- DCHECK_EQ(time.InMilliseconds(), static_cast<int64>(time_msec));
- env->CallVoidMethod(j_media_player_.obj(),
- method,
- time_msec);
- CheckException(env);
+ if (j_media_player_.is_null())
+ Prepare();
+ else if (prepared_)
+ SeekInternal(time);
}
base::TimeDelta MediaPlayerBridge::GetCurrentTime() {
+ if (!prepared_)
+ return pending_seek_;
return base::TimeDelta::FromMilliseconds(CallIntMethod("getCurrentPosition"));
}
base::TimeDelta MediaPlayerBridge::GetDuration() {
+ if (!prepared_)
+ return duration_;
return base::TimeDelta::FromMilliseconds(CallIntMethod("getDuration"));
}
-void MediaPlayerBridge::Reset() {
- CallVoidMethod("reset");
+void MediaPlayerBridge::Release() {
+ if (j_media_player_.is_null())
+ return;
+
+ time_update_timer_.Stop();
+ if (prepared_)
+ pending_seek_ = GetCurrentTime();
+ if (manager_)
+ manager_->ReleaseMediaResources(this);
+ prepared_ = false;
+ pending_play_ = false;
+ SetVideoSurface(NULL);
+ CallVoidMethod("release");
+ j_media_player_.Reset();
}
void MediaPlayerBridge::SetVolume(float left_volume, float right_volume) {
+ if (j_media_player_.is_null())
+ return;
+
JNIEnv* env = AttachCurrentThread();
CHECK(env);
@@ -239,62 +332,64 @@ void MediaPlayerBridge::SetVolume(float left_volume, float right_volume) {
CheckException(env);
}
-void MediaPlayerBridge::SetStayAwakeWhilePlaying() {
- JNIEnv* env = AttachCurrentThread();
- CHECK(env);
-
- jobject j_context = base::android::GetApplicationContext();
- DCHECK(j_context);
- jint j_mode = kAndroidFullWakeLock;
- jmethodID method = GetMethodID(env, j_media_player_class_,
- "setWakeMode", "(Landroid/content/Context;I)V");
- env->CallVoidMethod(j_media_player_.obj(), method, j_context, j_mode);
- CheckException(env);
+void MediaPlayerBridge::DoTimeUpdate() {
+ base::TimeDelta current = GetCurrentTime();
+ time_update_cb_.Run(player_id_, current);
}
-void MediaPlayerBridge::OnMediaError(JNIEnv* /* env */,
- jobject /* obj */,
- jint error_type) {
- media_error_cb_.Run(error_type);
+void MediaPlayerBridge::OnMediaError(int error_type) {
+ media_error_cb_.Run(player_id_, error_type);
}
-void MediaPlayerBridge::OnMediaInfo(JNIEnv* /* env */,
- jobject /* obj */,
- jint info_type) {
- media_info_cb_.Run(info_type);
+void MediaPlayerBridge::OnVideoSizeChanged(int width, int height) {
+ width_ = width;
+ height_ = height_;
+ video_size_changed_cb_.Run(player_id_, width, height);
}
-void MediaPlayerBridge::OnVideoSizeChanged(JNIEnv* /* env */,
- jobject /* obj */,
- jint width,
- jint height) {
- video_size_changed_cb_.Run(width, height);
+void MediaPlayerBridge::OnBufferingUpdate(int percent) {
+ buffering_update_cb_.Run(player_id_, percent);
}
-void MediaPlayerBridge::OnBufferingUpdate(JNIEnv* /* env */,
- jobject /* obj */,
- jint percent) {
- buffering_update_cb_.Run(percent);
+void MediaPlayerBridge::OnPlaybackComplete() {
+ time_update_timer_.Stop();
+ playback_complete_cb_.Run(player_id_);
}
-void MediaPlayerBridge::OnPlaybackComplete(JNIEnv* /* env */,
- jobject /* obj */) {
- playback_complete_cb_.Run();
+void MediaPlayerBridge::OnSeekComplete() {
+ seek_complete_cb_.Run(player_id_, GetCurrentTime());
}
-void MediaPlayerBridge::OnSeekComplete(JNIEnv* /* env */,
- jobject /* obj */) {
- seek_complete_cb_.Run();
-}
+void MediaPlayerBridge::OnMediaPrepared() {
+ if (j_media_player_.is_null())
+ return;
+
+ prepared_ = true;
+
+ base::TimeDelta dur = duration_;
+ duration_ = GetDuration();
+
+ if (duration_ != dur && 0 != dur.InMilliseconds()) {
+ // Scale the |pending_seek_| according to the new duration.
+ pending_seek_ = base::TimeDelta::FromSeconds(
+ pending_seek_.InSecondsF() * duration_.InSecondsF() / dur.InSecondsF());
+ }
+
+ // If media player was recovered from a saved state, consume all the pending
+ // events.
+ SeekInternal(pending_seek_);
+
+ if (pending_play_) {
+ StartInternal();
+ pending_play_ = false;
+ }
-void MediaPlayerBridge::OnMediaPrepared(JNIEnv* /* env */,
- jobject /* obj */) {
- media_prepared_cb_.Run();
+ GetMetadata();
+
+ media_prepared_cb_.Run(player_id_, duration_);
}
-void MediaPlayerBridge::GetMetadata(bool* can_pause,
- bool* can_seek_forward,
- bool* can_seek_backward) {
+void MediaPlayerBridge::GetMetadata() {
JNIEnv* env = AttachCurrentThread();
CHECK(env);
@@ -311,17 +406,46 @@ void MediaPlayerBridge::GetMetadata(bool* can_pause,
ScopedJavaLocalRef<jclass> cls(GetClass(env, "android/media/Metadata"));
jmethodID get_boolean = GetMethodID(env, cls, "getBoolean", "(I)Z");
- *can_pause = env->CallBooleanMethod(j_metadata.obj(),
+ can_pause_ = env->CallBooleanMethod(j_metadata.obj(),
get_boolean,
kPauseAvailable);
CheckException(env);
- *can_seek_backward = env->CallBooleanMethod(j_metadata.obj(),
+ can_seek_forward_ = env->CallBooleanMethod(j_metadata.obj(),
+ get_boolean,
+ kSeekBackwardAvailable);
+ CheckException(env);
+ can_seek_backward_ = env->CallBooleanMethod(j_metadata.obj(),
get_boolean,
- kSeekBackwardAvailable);
+ kSeekForwardAvailable);
CheckException(env);
- *can_seek_forward = env->CallBooleanMethod(j_metadata.obj(),
- get_boolean,
- kSeekForwardAvailable);
+}
+
+void MediaPlayerBridge::StartInternal() {
+ CallVoidMethod("start");
+ if (!time_update_timer_.IsRunning()) {
+ time_update_timer_.Start(
+ FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kTimeUpdateInterval),
+ this, &MediaPlayerBridge::DoTimeUpdate);
+ }
+}
+
+void MediaPlayerBridge::PauseInternal() {
+ CallVoidMethod("pause");
+ time_update_timer_.Stop();
+}
+
+void MediaPlayerBridge::SeekInternal(base::TimeDelta time) {
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+
+ jmethodID method = GetMethodID(env, j_media_player_class_, "seekTo", "(I)V");
+ DCHECK(method);
+ int time_msec = static_cast<int>(time.InMilliseconds());
+ DCHECK_EQ(time.InMilliseconds(), static_cast<int64>(time_msec));
+ env->CallVoidMethod(j_media_player_.obj(),
+ method,
+ time_msec);
CheckException(env);
}
@@ -352,10 +476,4 @@ int MediaPlayerBridge::CallIntMethod(std::string method_name) {
return j_result;
}
-bool MediaPlayerBridge::RegisterMediaPlayerListener(JNIEnv* env) {
- bool ret = RegisterNativesImpl(env);
- DCHECK(g_MediaPlayerListener_clazz);
- return ret;
-}
-
} // namespace media
« no previous file with comments | « media/base/android/media_player_bridge.h ('k') | media/base/android/media_player_bridge_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698