| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/android/media_player_bridge.h" | 5 #include "media/base/android/media_player_bridge.h" |
| 6 | 6 |
| 7 #include "base/android/jni_android.h" | 7 #include "base/android/jni_android.h" |
| 8 #include "base/android/jni_string.h" | 8 #include "base/android/jni_string.h" |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/stringprintf.h" | 11 #include "base/stringprintf.h" |
| 12 | 12 #include "base/message_loop_proxy.h" |
| 13 // Auto generated jni class from MediaPlayerListener.java. | 13 #include "media/base/android/cookie_getter.h" |
| 14 // Check base/android/jni_generator/golden_sample_for_tests_jni.h for example. | 14 #include "media/base/android/media_player_bridge_manager.h" |
| 15 #include "jni/MediaPlayerListener_jni.h" | 15 #include "media/base/android/media_player_listener.h" |
| 16 | 16 |
| 17 using base::android::AttachCurrentThread; | 17 using base::android::AttachCurrentThread; |
| 18 using base::android::CheckException; | 18 using base::android::CheckException; |
| 19 using base::android::ConvertUTF8ToJavaString; | 19 using base::android::ConvertUTF8ToJavaString; |
| 20 using base::android::GetClass; | 20 using base::android::GetClass; |
| 21 using base::android::GetMethodID; | 21 using base::android::GetMethodID; |
| 22 using base::android::JavaRef; | 22 using base::android::JavaRef; |
| 23 using base::android::ScopedJavaLocalRef; | 23 using base::android::ScopedJavaLocalRef; |
| 24 | 24 |
| 25 // These constants are from the android source tree and need to be kept in | 25 // These constants are from the android source tree and need to be kept in |
| 26 // sync with android/media/MediaMetadata.java. | 26 // sync with android/media/MediaMetadata.java. |
| 27 static const jint kPauseAvailable = 1; | 27 static const jint kPauseAvailable = 1; |
| 28 static const jint kSeekBackwardAvailable = 2; | 28 static const jint kSeekBackwardAvailable = 2; |
| 29 static const jint kSeekForwardAvailable = 3; | 29 static const jint kSeekForwardAvailable = 3; |
| 30 | 30 |
| 31 // This needs to be kept in sync with android.os.PowerManager | 31 // This needs to be kept in sync with android.os.PowerManager |
| 32 static const int kAndroidFullWakeLock = 26; | 32 static const int kAndroidFullWakeLock = 26; |
| 33 | 33 |
| 34 // Time update happens every 250ms. |
| 35 static const int kTimeUpdateInterval = 250; |
| 36 |
| 37 // Because we create the media player lazily on android, the duration of the |
| 38 // media is initially unknown to us. This makes the user unable to perform |
| 39 // seek. To solve this problem, we use a temporary duration of 100 seconds when |
| 40 // the duration is unknown. And we scale the seek position later when duration |
| 41 // is available. |
| 42 // TODO(qinmin): create a thread and use android MediaMetadataRetriever |
| 43 // class to extract the duration. |
| 44 static const int kTemporaryDuration = 100; |
| 45 |
| 34 namespace media { | 46 namespace media { |
| 35 | 47 |
| 36 MediaPlayerBridge::MediaPlayerBridge() { | 48 MediaPlayerBridge::MediaPlayerBridge( |
| 49 int player_id, |
| 50 const std::string& url, |
| 51 media::CookieGetter* cookie_getter, |
| 52 bool hide_url_log, |
| 53 media::MediaPlayerBridgeManager* manager, |
| 54 const MediaErrorCB& media_error_cb, |
| 55 const VideoSizeChangedCB& video_size_changed_cb, |
| 56 const BufferingUpdateCB& buffering_update_cb, |
| 57 const MediaPreparedCB& media_prepared_cb, |
| 58 const PlaybackCompleteCB& playback_complete_cb, |
| 59 const SeekCompleteCB& seek_complete_cb, |
| 60 const TimeUpdateCB& time_update_cb) |
| 61 : media_error_cb_(media_error_cb), |
| 62 video_size_changed_cb_(video_size_changed_cb), |
| 63 buffering_update_cb_(buffering_update_cb), |
| 64 media_prepared_cb_(media_prepared_cb), |
| 65 playback_complete_cb_(playback_complete_cb), |
| 66 seek_complete_cb_(seek_complete_cb), |
| 67 time_update_cb_(time_update_cb), |
| 68 player_id_(player_id), |
| 69 prepared_(false), |
| 70 pending_play_(false), |
| 71 url_(url), |
| 72 has_cookies_(false), |
| 73 hide_url_log_(hide_url_log), |
| 74 duration_(base::TimeDelta::FromSeconds(kTemporaryDuration)), |
| 75 width_(0), |
| 76 height_(0), |
| 77 can_pause_(true), |
| 78 can_seek_forward_(true), |
| 79 can_seek_backward_(true), |
| 80 manager_(manager), |
| 81 cookie_getter_(cookie_getter), |
| 82 listener_(new MediaPlayerListener(base::MessageLoopProxy::current(), |
| 83 AsWeakPtr())) { |
| 84 } |
| 85 |
| 86 MediaPlayerBridge::~MediaPlayerBridge() { |
| 87 Release(); |
| 88 } |
| 89 |
| 90 void MediaPlayerBridge::InitializePlayer() { |
| 37 JNIEnv* env = AttachCurrentThread(); | 91 JNIEnv* env = AttachCurrentThread(); |
| 38 CHECK(env); | 92 CHECK(env); |
| 39 | 93 |
| 40 j_media_player_class_.Reset(GetClass(env, "android/media/MediaPlayer")); | 94 j_media_player_class_.Reset(GetClass(env, "android/media/MediaPlayer")); |
| 41 | 95 |
| 42 jmethodID constructor = GetMethodID(env, | 96 jmethodID constructor = GetMethodID(env, |
| 43 j_media_player_class_, | 97 j_media_player_class_, |
| 44 "<init>", | 98 "<init>", |
| 45 "()V"); | 99 "()V"); |
| 46 ScopedJavaLocalRef<jobject> tmp(env, | 100 ScopedJavaLocalRef<jobject> tmp(env, |
| 47 env->NewObject(j_media_player_class_.obj(), constructor)); | 101 env->NewObject(j_media_player_class_.obj(), constructor)); |
| 48 j_media_player_.Reset(tmp); | 102 j_media_player_.Reset(tmp); |
| 49 | 103 |
| 50 ScopedJavaLocalRef<jobject> j_listener( | 104 ScopedJavaLocalRef<jobject> j_listener( |
| 51 Java_MediaPlayerListener_create(env, | 105 listener_->CreateMediaPlayerListener()); |
| 52 reinterpret_cast<intptr_t>(this))); | |
| 53 DCHECK(!j_listener.is_null()); | |
| 54 | 106 |
| 55 // Set it as the various listeners. | 107 // Set it as the various listeners. |
| 56 const char* listeners[] = { | 108 const char* listeners[] = { |
| 57 "OnBufferingUpdateListener", | 109 "OnBufferingUpdateListener", |
| 58 "OnCompletionListener", | 110 "OnCompletionListener", |
| 59 "OnErrorListener", | 111 "OnErrorListener", |
| 60 "OnInfoListener", | |
| 61 "OnPreparedListener", | 112 "OnPreparedListener", |
| 62 "OnSeekCompleteListener", | 113 "OnSeekCompleteListener", |
| 63 "OnVideoSizeChangedListener", | 114 "OnVideoSizeChangedListener", |
| 64 }; | 115 }; |
| 65 for (unsigned int i = 0; i < arraysize(listeners); ++i) { | 116 for (unsigned int i = 0; i < arraysize(listeners); ++i) { |
| 66 std::string signature = StringPrintf("(Landroid/media/MediaPlayer$%s;)V", | 117 std::string signature = StringPrintf("(Landroid/media/MediaPlayer$%s;)V", |
| 67 listeners[i]); | 118 listeners[i]); |
| 68 std::string method_name = StringPrintf("set%s", listeners[i]); | 119 std::string method_name = StringPrintf("set%s", listeners[i]); |
| 69 jmethodID method = GetMethodID(env, | 120 jmethodID method = GetMethodID(env, |
| 70 j_media_player_class_, | 121 j_media_player_class_, |
| 71 method_name.c_str(), | 122 method_name.c_str(), |
| 72 signature.c_str()); | 123 signature.c_str()); |
| 73 env->CallVoidMethod(j_media_player_.obj(), method, j_listener.obj()); | 124 env->CallVoidMethod(j_media_player_.obj(), method, j_listener.obj()); |
| 74 CheckException(env); | 125 CheckException(env); |
| 75 } | 126 } |
| 127 |
| 128 jobject j_context = base::android::GetApplicationContext(); |
| 129 DCHECK(j_context); |
| 130 jmethodID method = GetMethodID(env, j_media_player_class_, |
| 131 "setWakeMode", "(Landroid/content/Context;I)V"); |
| 132 env->CallVoidMethod(j_media_player_.obj(), method, j_context, |
| 133 kAndroidFullWakeLock); |
| 134 CheckException(env); |
| 76 } | 135 } |
| 77 | 136 |
| 78 MediaPlayerBridge::~MediaPlayerBridge() { | 137 void MediaPlayerBridge::SetVideoSurface(jobject surface) { |
| 79 SetVideoSurface(NULL); | 138 if (j_media_player_.is_null() && surface != NULL) |
| 80 CallVoidMethod("release"); | 139 Prepare(); |
| 140 |
| 141 JNIEnv* env = AttachCurrentThread(); |
| 142 CHECK(env); |
| 143 |
| 144 jmethodID method = GetMethodID(env, |
| 145 j_media_player_class_, |
| 146 "setSurface", |
| 147 "(Landroid/view/Surface;)V"); |
| 148 env->CallVoidMethod(j_media_player_.obj(), method, surface); |
| 149 CheckException(env); |
| 81 } | 150 } |
| 82 | 151 |
| 83 void MediaPlayerBridge::SetDataSource( | 152 void MediaPlayerBridge::Prepare() { |
| 84 const std::string& url, | 153 if (j_media_player_.is_null()) |
| 85 const std::string& cookies, | 154 InitializePlayer(); |
| 86 bool hide_url_log) { | 155 |
| 156 if (has_cookies_) { |
| 157 GetCookiesCallback(cookies_); |
| 158 } else { |
| 159 cookie_getter_->GetCookies(url_, base::Bind( |
| 160 &MediaPlayerBridge::GetCookiesCallback, AsWeakPtr())); |
| 161 } |
| 162 } |
| 163 |
| 164 void MediaPlayerBridge::GetCookiesCallback(std::string cookies) { |
| 165 cookies_ = cookies; |
| 166 has_cookies_ = true; |
| 167 |
| 87 JNIEnv* env = AttachCurrentThread(); | 168 JNIEnv* env = AttachCurrentThread(); |
| 88 CHECK(env); | 169 CHECK(env); |
| 89 | 170 |
| 90 // Create a Java String for the URL. | 171 // Create a Java String for the URL. |
| 91 ScopedJavaLocalRef<jstring> j_url_string = ConvertUTF8ToJavaString(env, url); | 172 ScopedJavaLocalRef<jstring> j_url_string = ConvertUTF8ToJavaString(env, url_); |
| 92 | 173 |
| 93 // Create the android.net.Uri object. | 174 // Create the android.net.Uri object. |
| 94 ScopedJavaLocalRef<jclass> cls(GetClass(env, "android/net/Uri")); | 175 ScopedJavaLocalRef<jclass> cls(GetClass(env, "android/net/Uri")); |
| 95 jmethodID method = GetStaticMethodID(env, cls, | 176 jmethodID method = GetStaticMethodID(env, cls, |
| 96 "parse", "(Ljava/lang/String;)Landroid/net/Uri;"); | 177 "parse", "(Ljava/lang/String;)Landroid/net/Uri;"); |
| 97 ScopedJavaLocalRef<jobject> j_uri(env, | 178 ScopedJavaLocalRef<jobject> j_uri(env, |
| 98 env->CallStaticObjectMethod(cls.obj(), method, j_url_string.obj())); | 179 env->CallStaticObjectMethod(cls.obj(), method, j_url_string.obj())); |
| 99 | 180 |
| 100 // Create the java.util.Map. | 181 // Create the java.util.Map. |
| 101 cls.Reset(GetClass(env, "java/util/HashMap")); | 182 cls.Reset(GetClass(env, "java/util/HashMap")); |
| 102 jmethodID constructor = GetMethodID(env, cls, "<init>", "()V"); | 183 jmethodID constructor = GetMethodID(env, cls, "<init>", "()V"); |
| 103 ScopedJavaLocalRef<jobject> j_map(env, | 184 ScopedJavaLocalRef<jobject> j_map(env, |
| 104 env->NewObject(cls.obj(), constructor)); | 185 env->NewObject(cls.obj(), constructor)); |
| 105 jmethodID put_method = GetMethodID(env, cls, "put", | 186 jmethodID put_method = GetMethodID(env, cls, "put", |
| 106 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); | 187 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); |
| 107 | 188 |
| 108 // Construct headers that needs to be sent with the url. | 189 // Construct headers that needs to be sent with the url. |
| 109 HeadersMap headers; | 190 HeadersMap headers; |
| 110 // For incognito mode, we need a header to hide url log. | 191 // For incognito mode, we need a header to hide url log. |
| 111 if (hide_url_log) | 192 if (hide_url_log_) |
| 112 headers.insert(std::make_pair("x-hide-urls-from-log", "true")); | 193 headers.insert(std::make_pair("x-hide-urls-from-log", "true")); |
| 113 // If cookies are present, add them in the header. | 194 // If cookies are present, add them in the header. |
| 114 if (!cookies.empty()) | 195 if (!cookies_.empty()) |
| 115 headers.insert(std::make_pair("Cookie", cookies)); | 196 headers.insert(std::make_pair("Cookie", cookies_)); |
| 116 | 197 |
| 117 // Fill the Map with the headers. | 198 // Fill the Map with the headers. |
| 118 for (HeadersMap::const_iterator iter = headers.begin(); | 199 for (HeadersMap::const_iterator iter = headers.begin(); |
| 119 iter != headers.end(); ++iter) { | 200 iter != headers.end(); ++iter) { |
| 120 ScopedJavaLocalRef<jstring> key = ConvertUTF8ToJavaString(env, iter->first); | 201 ScopedJavaLocalRef<jstring> key = ConvertUTF8ToJavaString(env, iter->first); |
| 121 ScopedJavaLocalRef<jstring> value = | 202 ScopedJavaLocalRef<jstring> value = |
| 122 ConvertUTF8ToJavaString(env, iter->second); | 203 ConvertUTF8ToJavaString(env, iter->second); |
| 123 ScopedJavaLocalRef<jobject> result(env, | 204 ScopedJavaLocalRef<jobject> result(env, |
| 124 env->CallObjectMethod(j_map.obj(), put_method, key.obj(), value.obj())); | 205 env->CallObjectMethod(j_map.obj(), put_method, key.obj(), value.obj())); |
| 125 } | 206 } |
| 126 | 207 |
| 127 jobject j_context = base::android::GetApplicationContext(); | 208 jobject j_context = base::android::GetApplicationContext(); |
| 128 DCHECK(j_context); | 209 DCHECK(j_context); |
| 129 | 210 |
| 130 // Finally- Call the setDataSource method. | 211 // Finally- Call the setDataSource method. |
| 131 jmethodID set_data_source = | 212 jmethodID set_data_source = |
| 132 GetMethodID(env, j_media_player_class_, "setDataSource", | 213 GetMethodID(env, j_media_player_class_, "setDataSource", |
| 133 "(Landroid/content/Context;Landroid/net/Uri;Ljava/util/Map;)V"); | 214 "(Landroid/content/Context;Landroid/net/Uri;Ljava/util/Map;)V"); |
| 134 DCHECK(set_data_source); | |
| 135 env->CallVoidMethod(j_media_player_.obj(), set_data_source, j_context, | 215 env->CallVoidMethod(j_media_player_.obj(), set_data_source, j_context, |
| 136 j_uri.obj(), j_map.obj()); | 216 j_uri.obj(), j_map.obj()); |
| 137 CheckException(env); | 217 bool is_data_source_set_ = !base::android::ClearException(env); |
| 218 |
| 219 if (is_data_source_set_) { |
| 220 if (manager_) |
| 221 manager_->RequestMediaResources(this); |
| 222 CallVoidMethod("prepareAsync"); |
| 223 } else { |
| 224 media_error_cb_.Run(player_id_, MEDIA_ERROR_UNKNOWN); |
| 225 } |
| 138 } | 226 } |
| 139 | 227 |
| 140 void MediaPlayerBridge::SetVideoSurface(jobject surface) { | 228 void MediaPlayerBridge::Start() { |
| 229 if (j_media_player_.is_null()) { |
| 230 pending_play_ = true; |
| 231 Prepare(); |
| 232 } else { |
| 233 if (prepared_) |
| 234 StartInternal(); |
| 235 else |
| 236 pending_play_ = true; |
| 237 } |
| 238 } |
| 239 |
| 240 void MediaPlayerBridge::Pause() { |
| 241 if (j_media_player_.is_null()) { |
| 242 pending_play_ = false; |
| 243 } else { |
| 244 if (prepared_ && IsPlaying()) |
| 245 PauseInternal(); |
| 246 else |
| 247 pending_play_ = false; |
| 248 } |
| 249 } |
| 250 |
| 251 |
| 252 bool MediaPlayerBridge::IsPlaying() { |
| 253 if (!prepared_) |
| 254 return pending_play_; |
| 255 |
| 141 JNIEnv* env = AttachCurrentThread(); | 256 JNIEnv* env = AttachCurrentThread(); |
| 142 CHECK(env); | 257 CHECK(env); |
| 143 | 258 |
| 144 jmethodID method = GetMethodID(env, | 259 jmethodID method = GetMethodID(env, j_media_player_class_, "isPlaying", |
| 145 j_media_player_class_, | |
| 146 "setSurface", | |
| 147 "(Landroid/view/Surface;)V"); | |
| 148 env->CallVoidMethod(j_media_player_.obj(), method, surface); | |
| 149 CheckException(env); | |
| 150 } | |
| 151 | |
| 152 void MediaPlayerBridge::Prepare(const MediaInfoCB& media_info_cb, | |
| 153 const MediaErrorCB& media_error_cb, | |
| 154 const VideoSizeChangedCB& video_size_changed_cb, | |
| 155 const BufferingUpdateCB& buffering_update_cb, | |
| 156 const base::Closure& media_prepared_cb) { | |
| 157 media_info_cb_ = media_info_cb; | |
| 158 media_error_cb_ = media_error_cb, | |
| 159 video_size_changed_cb_ = video_size_changed_cb; | |
| 160 buffering_update_cb_ = buffering_update_cb; | |
| 161 media_prepared_cb_ = media_prepared_cb; | |
| 162 CallVoidMethod("prepareAsync"); | |
| 163 } | |
| 164 | |
| 165 void MediaPlayerBridge::Start(const base::Closure& playback_complete_cb) { | |
| 166 playback_complete_cb_ = playback_complete_cb; | |
| 167 CallVoidMethod("start"); | |
| 168 } | |
| 169 | |
| 170 void MediaPlayerBridge::Pause() { | |
| 171 CallVoidMethod("pause"); | |
| 172 } | |
| 173 | |
| 174 void MediaPlayerBridge::Stop() { | |
| 175 CallVoidMethod("stop"); | |
| 176 } | |
| 177 | |
| 178 bool MediaPlayerBridge::IsPlaying() { | |
| 179 JNIEnv* env = AttachCurrentThread(); | |
| 180 CHECK(env); | |
| 181 | |
| 182 jmethodID method = GetMethodID(env, | |
| 183 j_media_player_class_, | |
| 184 "isPlaying", | |
| 185 "()Z"); | 260 "()Z"); |
| 186 jint result = env->CallBooleanMethod(j_media_player_.obj(), method); | 261 jboolean result = env->CallBooleanMethod(j_media_player_.obj(), method); |
| 187 CheckException(env); | 262 CheckException(env); |
| 188 | 263 |
| 189 return result; | 264 return result; |
| 190 } | 265 } |
| 191 | 266 |
| 192 int MediaPlayerBridge::GetVideoWidth() { | 267 int MediaPlayerBridge::GetVideoWidth() { |
| 268 if (!prepared_) |
| 269 return width_; |
| 193 return CallIntMethod("getVideoWidth"); | 270 return CallIntMethod("getVideoWidth"); |
| 194 } | 271 } |
| 195 | 272 |
| 196 int MediaPlayerBridge::GetVideoHeight() { | 273 int MediaPlayerBridge::GetVideoHeight() { |
| 274 if (!prepared_) |
| 275 return height_; |
| 197 return CallIntMethod("getVideoHeight"); | 276 return CallIntMethod("getVideoHeight"); |
| 198 } | 277 } |
| 199 | 278 |
| 200 void MediaPlayerBridge::SeekTo(base::TimeDelta time, | 279 void MediaPlayerBridge::SeekTo(base::TimeDelta time) { |
| 201 const base::Closure& seek_complete_cb) { | 280 // Record the time to seek when OnMediaPrepared() is called. |
| 202 seek_complete_cb_ = seek_complete_cb; | 281 pending_seek_ = time; |
| 203 JNIEnv* env = AttachCurrentThread(); | |
| 204 CHECK(env); | |
| 205 | 282 |
| 206 jmethodID method = GetMethodID(env, j_media_player_class_, "seekTo", "(I)V"); | 283 if (j_media_player_.is_null()) |
| 207 DCHECK(method); | 284 Prepare(); |
| 208 int time_msec = static_cast<int>(time.InMilliseconds()); | 285 else if (prepared_) |
| 209 DCHECK_EQ(time.InMilliseconds(), static_cast<int64>(time_msec)); | 286 SeekInternal(time); |
| 210 env->CallVoidMethod(j_media_player_.obj(), | |
| 211 method, | |
| 212 time_msec); | |
| 213 CheckException(env); | |
| 214 } | 287 } |
| 215 | 288 |
| 216 base::TimeDelta MediaPlayerBridge::GetCurrentTime() { | 289 base::TimeDelta MediaPlayerBridge::GetCurrentTime() { |
| 290 if (!prepared_) |
| 291 return pending_seek_; |
| 217 return base::TimeDelta::FromMilliseconds(CallIntMethod("getCurrentPosition")); | 292 return base::TimeDelta::FromMilliseconds(CallIntMethod("getCurrentPosition")); |
| 218 } | 293 } |
| 219 | 294 |
| 220 base::TimeDelta MediaPlayerBridge::GetDuration() { | 295 base::TimeDelta MediaPlayerBridge::GetDuration() { |
| 296 if (!prepared_) |
| 297 return duration_; |
| 221 return base::TimeDelta::FromMilliseconds(CallIntMethod("getDuration")); | 298 return base::TimeDelta::FromMilliseconds(CallIntMethod("getDuration")); |
| 222 } | 299 } |
| 223 | 300 |
| 224 void MediaPlayerBridge::Reset() { | 301 void MediaPlayerBridge::Release() { |
| 225 CallVoidMethod("reset"); | 302 if (j_media_player_.is_null()) |
| 303 return; |
| 304 |
| 305 time_update_timer_.Stop(); |
| 306 if (prepared_) |
| 307 pending_seek_ = GetCurrentTime(); |
| 308 if (manager_) |
| 309 manager_->ReleaseMediaResources(this); |
| 310 prepared_ = false; |
| 311 pending_play_ = false; |
| 312 SetVideoSurface(NULL); |
| 313 CallVoidMethod("release"); |
| 314 j_media_player_.Reset(); |
| 226 } | 315 } |
| 227 | 316 |
| 228 void MediaPlayerBridge::SetVolume(float left_volume, float right_volume) { | 317 void MediaPlayerBridge::SetVolume(float left_volume, float right_volume) { |
| 318 if (j_media_player_.is_null()) |
| 319 return; |
| 320 |
| 229 JNIEnv* env = AttachCurrentThread(); | 321 JNIEnv* env = AttachCurrentThread(); |
| 230 CHECK(env); | 322 CHECK(env); |
| 231 | 323 |
| 232 jmethodID method = GetMethodID(env, | 324 jmethodID method = GetMethodID(env, |
| 233 j_media_player_class_, | 325 j_media_player_class_, |
| 234 "setVolume", | 326 "setVolume", |
| 235 "(FF)V"); | 327 "(FF)V"); |
| 236 DCHECK(method); | 328 DCHECK(method); |
| 237 env->CallVoidMethod(j_media_player_.obj(), method, | 329 env->CallVoidMethod(j_media_player_.obj(), method, |
| 238 left_volume, right_volume); | 330 left_volume, right_volume); |
| 239 CheckException(env); | 331 CheckException(env); |
| 240 } | 332 } |
| 241 | 333 |
| 242 void MediaPlayerBridge::SetStayAwakeWhilePlaying() { | 334 void MediaPlayerBridge::DoTimeUpdate() { |
| 335 base::TimeDelta current = GetCurrentTime(); |
| 336 time_update_cb_.Run(player_id_, current); |
| 337 } |
| 338 |
| 339 void MediaPlayerBridge::OnMediaError(int error_type) { |
| 340 media_error_cb_.Run(player_id_, error_type); |
| 341 } |
| 342 |
| 343 void MediaPlayerBridge::OnVideoSizeChanged(int width, int height) { |
| 344 width_ = width; |
| 345 height_ = height_; |
| 346 video_size_changed_cb_.Run(player_id_, width, height); |
| 347 } |
| 348 |
| 349 void MediaPlayerBridge::OnBufferingUpdate(int percent) { |
| 350 buffering_update_cb_.Run(player_id_, percent); |
| 351 } |
| 352 |
| 353 void MediaPlayerBridge::OnPlaybackComplete() { |
| 354 time_update_timer_.Stop(); |
| 355 playback_complete_cb_.Run(player_id_); |
| 356 } |
| 357 |
| 358 void MediaPlayerBridge::OnSeekComplete() { |
| 359 seek_complete_cb_.Run(player_id_, GetCurrentTime()); |
| 360 } |
| 361 |
| 362 void MediaPlayerBridge::OnMediaPrepared() { |
| 363 if (j_media_player_.is_null()) |
| 364 return; |
| 365 |
| 366 prepared_ = true; |
| 367 |
| 368 base::TimeDelta dur = duration_; |
| 369 duration_ = GetDuration(); |
| 370 |
| 371 if (duration_ != dur && 0 != dur.InMilliseconds()) { |
| 372 // Scale the |pending_seek_| according to the new duration. |
| 373 pending_seek_ = base::TimeDelta::FromSeconds( |
| 374 pending_seek_.InSecondsF() * duration_.InSecondsF() / dur.InSecondsF()); |
| 375 } |
| 376 |
| 377 // If media player was recovered from a saved state, consume all the pending |
| 378 // events. |
| 379 SeekInternal(pending_seek_); |
| 380 |
| 381 if (pending_play_) { |
| 382 StartInternal(); |
| 383 pending_play_ = false; |
| 384 } |
| 385 |
| 386 GetMetadata(); |
| 387 |
| 388 media_prepared_cb_.Run(player_id_, duration_); |
| 389 } |
| 390 |
| 391 void MediaPlayerBridge::GetMetadata() { |
| 243 JNIEnv* env = AttachCurrentThread(); | 392 JNIEnv* env = AttachCurrentThread(); |
| 244 CHECK(env); | 393 CHECK(env); |
| 245 | 394 |
| 246 jobject j_context = base::android::GetApplicationContext(); | |
| 247 DCHECK(j_context); | |
| 248 jint j_mode = kAndroidFullWakeLock; | |
| 249 jmethodID method = GetMethodID(env, j_media_player_class_, | |
| 250 "setWakeMode", "(Landroid/content/Context;I)V"); | |
| 251 env->CallVoidMethod(j_media_player_.obj(), method, j_context, j_mode); | |
| 252 CheckException(env); | |
| 253 } | |
| 254 | |
| 255 void MediaPlayerBridge::OnMediaError(JNIEnv* /* env */, | |
| 256 jobject /* obj */, | |
| 257 jint error_type) { | |
| 258 media_error_cb_.Run(error_type); | |
| 259 } | |
| 260 | |
| 261 void MediaPlayerBridge::OnMediaInfo(JNIEnv* /* env */, | |
| 262 jobject /* obj */, | |
| 263 jint info_type) { | |
| 264 media_info_cb_.Run(info_type); | |
| 265 } | |
| 266 | |
| 267 void MediaPlayerBridge::OnVideoSizeChanged(JNIEnv* /* env */, | |
| 268 jobject /* obj */, | |
| 269 jint width, | |
| 270 jint height) { | |
| 271 video_size_changed_cb_.Run(width, height); | |
| 272 } | |
| 273 | |
| 274 void MediaPlayerBridge::OnBufferingUpdate(JNIEnv* /* env */, | |
| 275 jobject /* obj */, | |
| 276 jint percent) { | |
| 277 buffering_update_cb_.Run(percent); | |
| 278 } | |
| 279 | |
| 280 void MediaPlayerBridge::OnPlaybackComplete(JNIEnv* /* env */, | |
| 281 jobject /* obj */) { | |
| 282 playback_complete_cb_.Run(); | |
| 283 } | |
| 284 | |
| 285 void MediaPlayerBridge::OnSeekComplete(JNIEnv* /* env */, | |
| 286 jobject /* obj */) { | |
| 287 seek_complete_cb_.Run(); | |
| 288 } | |
| 289 | |
| 290 void MediaPlayerBridge::OnMediaPrepared(JNIEnv* /* env */, | |
| 291 jobject /* obj */) { | |
| 292 media_prepared_cb_.Run(); | |
| 293 } | |
| 294 | |
| 295 void MediaPlayerBridge::GetMetadata(bool* can_pause, | |
| 296 bool* can_seek_forward, | |
| 297 bool* can_seek_backward) { | |
| 298 JNIEnv* env = AttachCurrentThread(); | |
| 299 CHECK(env); | |
| 300 | |
| 301 jmethodID method = GetMethodID(env, | 395 jmethodID method = GetMethodID(env, |
| 302 j_media_player_class_, | 396 j_media_player_class_, |
| 303 "getMetadata", | 397 "getMetadata", |
| 304 "(ZZ)Landroid/media/Metadata;"); | 398 "(ZZ)Landroid/media/Metadata;"); |
| 305 ScopedJavaLocalRef<jobject> j_metadata(env, | 399 ScopedJavaLocalRef<jobject> j_metadata(env, |
| 306 env->CallObjectMethod(j_media_player_.obj(), | 400 env->CallObjectMethod(j_media_player_.obj(), |
| 307 method, JNI_FALSE, JNI_FALSE)); | 401 method, JNI_FALSE, JNI_FALSE)); |
| 308 CheckException(env); | 402 CheckException(env); |
| 309 if (j_metadata.is_null()) | 403 if (j_metadata.is_null()) |
| 310 return; | 404 return; |
| 311 | 405 |
| 312 ScopedJavaLocalRef<jclass> cls(GetClass(env, "android/media/Metadata")); | 406 ScopedJavaLocalRef<jclass> cls(GetClass(env, "android/media/Metadata")); |
| 313 jmethodID get_boolean = GetMethodID(env, cls, "getBoolean", "(I)Z"); | 407 jmethodID get_boolean = GetMethodID(env, cls, "getBoolean", "(I)Z"); |
| 314 *can_pause = env->CallBooleanMethod(j_metadata.obj(), | 408 can_pause_ = env->CallBooleanMethod(j_metadata.obj(), |
| 315 get_boolean, | 409 get_boolean, |
| 316 kPauseAvailable); | 410 kPauseAvailable); |
| 317 CheckException(env); | 411 CheckException(env); |
| 318 *can_seek_backward = env->CallBooleanMethod(j_metadata.obj(), | 412 can_seek_forward_ = env->CallBooleanMethod(j_metadata.obj(), |
| 413 get_boolean, |
| 414 kSeekBackwardAvailable); |
| 415 CheckException(env); |
| 416 can_seek_backward_ = env->CallBooleanMethod(j_metadata.obj(), |
| 319 get_boolean, | 417 get_boolean, |
| 320 kSeekBackwardAvailable); | 418 kSeekForwardAvailable); |
| 321 CheckException(env); | |
| 322 *can_seek_forward = env->CallBooleanMethod(j_metadata.obj(), | |
| 323 get_boolean, | |
| 324 kSeekForwardAvailable); | |
| 325 CheckException(env); | 419 CheckException(env); |
| 326 } | 420 } |
| 327 | 421 |
| 422 void MediaPlayerBridge::StartInternal() { |
| 423 CallVoidMethod("start"); |
| 424 if (!time_update_timer_.IsRunning()) { |
| 425 time_update_timer_.Start( |
| 426 FROM_HERE, |
| 427 base::TimeDelta::FromMilliseconds(kTimeUpdateInterval), |
| 428 this, &MediaPlayerBridge::DoTimeUpdate); |
| 429 } |
| 430 } |
| 431 |
| 432 void MediaPlayerBridge::PauseInternal() { |
| 433 CallVoidMethod("pause"); |
| 434 time_update_timer_.Stop(); |
| 435 } |
| 436 |
| 437 void MediaPlayerBridge::SeekInternal(base::TimeDelta time) { |
| 438 JNIEnv* env = AttachCurrentThread(); |
| 439 CHECK(env); |
| 440 |
| 441 jmethodID method = GetMethodID(env, j_media_player_class_, "seekTo", "(I)V"); |
| 442 DCHECK(method); |
| 443 int time_msec = static_cast<int>(time.InMilliseconds()); |
| 444 DCHECK_EQ(time.InMilliseconds(), static_cast<int64>(time_msec)); |
| 445 env->CallVoidMethod(j_media_player_.obj(), |
| 446 method, |
| 447 time_msec); |
| 448 CheckException(env); |
| 449 } |
| 450 |
| 328 // ---- JNI Helpers for repeated call patterns. ---- | 451 // ---- JNI Helpers for repeated call patterns. ---- |
| 329 | 452 |
| 330 void MediaPlayerBridge::CallVoidMethod(std::string method_name) { | 453 void MediaPlayerBridge::CallVoidMethod(std::string method_name) { |
| 331 JNIEnv* env = AttachCurrentThread(); | 454 JNIEnv* env = AttachCurrentThread(); |
| 332 CHECK(env); | 455 CHECK(env); |
| 333 | 456 |
| 334 jmethodID method = GetMethodID(env, | 457 jmethodID method = GetMethodID(env, |
| 335 j_media_player_class_, | 458 j_media_player_class_, |
| 336 method_name.c_str(), | 459 method_name.c_str(), |
| 337 "()V"); | 460 "()V"); |
| 338 env->CallVoidMethod(j_media_player_.obj(), method); | 461 env->CallVoidMethod(j_media_player_.obj(), method); |
| 339 CheckException(env); | 462 CheckException(env); |
| 340 } | 463 } |
| 341 | 464 |
| 342 int MediaPlayerBridge::CallIntMethod(std::string method_name) { | 465 int MediaPlayerBridge::CallIntMethod(std::string method_name) { |
| 343 JNIEnv* env = AttachCurrentThread(); | 466 JNIEnv* env = AttachCurrentThread(); |
| 344 CHECK(env); | 467 CHECK(env); |
| 345 | 468 |
| 346 jmethodID method = GetMethodID(env, | 469 jmethodID method = GetMethodID(env, |
| 347 j_media_player_class_, | 470 j_media_player_class_, |
| 348 method_name.c_str(), | 471 method_name.c_str(), |
| 349 "()I"); | 472 "()I"); |
| 350 jint j_result = env->CallIntMethod(j_media_player_.obj(), method); | 473 jint j_result = env->CallIntMethod(j_media_player_.obj(), method); |
| 351 CheckException(env); | 474 CheckException(env); |
| 352 return j_result; | 475 return j_result; |
| 353 } | 476 } |
| 354 | 477 |
| 355 bool MediaPlayerBridge::RegisterMediaPlayerListener(JNIEnv* env) { | |
| 356 bool ret = RegisterNativesImpl(env); | |
| 357 DCHECK(g_MediaPlayerListener_clazz); | |
| 358 return ret; | |
| 359 } | |
| 360 | |
| 361 } // namespace media | 478 } // namespace media |
| OLD | NEW |