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 #include "base/message_loop_proxy.h" | 12 #include "base/message_loop_proxy.h" |
13 #include "jni/MediaPlayerBridge_jni.h" | 13 #include "jni/MediaPlayerBridge_jni.h" |
14 #include "jni/MediaPlayer_jni.h" | 14 #include "jni/MediaPlayer_jni.h" |
15 #include "media/base/android/cookie_getter.h" | 15 #include "media/base/android/cookie_getter.h" |
16 #include "media/base/android/media_player_bridge_manager.h" | 16 #include "media/base/android/media_player_bridge_manager.h" |
17 | 17 |
18 using base::android::AttachCurrentThread; | |
19 using base::android::CheckException; | |
20 using base::android::ConvertUTF8ToJavaString; | 18 using base::android::ConvertUTF8ToJavaString; |
21 using base::android::GetClass; | |
22 using base::android::JavaRef; | |
23 using base::android::MethodID; | |
24 using base::android::ScopedJavaLocalRef; | 19 using base::android::ScopedJavaLocalRef; |
25 | 20 |
26 // These constants are from the android source tree and need to be kept in | |
27 // sync with android/media/MediaMetadata.java. | |
28 static const jint kPauseAvailable = 1; | |
29 static const jint kSeekBackwardAvailable = 2; | |
30 static const jint kSeekForwardAvailable = 3; | |
31 | |
32 // Time update happens every 250ms. | 21 // Time update happens every 250ms. |
33 static const int kTimeUpdateInterval = 250; | 22 static const int kTimeUpdateInterval = 250; |
34 | 23 |
35 // Because we create the media player lazily on android, the duration of the | 24 // Because we create the media player lazily on android, the duration of the |
36 // media is initially unknown to us. This makes the user unable to perform | 25 // media is initially unknown to us. This makes the user unable to perform |
37 // seek. To solve this problem, we use a temporary duration of 100 seconds when | 26 // seek. To solve this problem, we use a temporary duration of 100 seconds when |
38 // the duration is unknown. And we scale the seek position later when duration | 27 // the duration is unknown. And we scale the seek position later when duration |
39 // is available. | 28 // is available. |
40 // TODO(qinmin): create a thread and use android MediaMetadataRetriever | 29 // TODO(qinmin): create a thread and use android MediaMetadataRetriever |
41 // class to extract the duration. | 30 // class to extract the duration. |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 cookie_getter_(cookie_getter), | 72 cookie_getter_(cookie_getter), |
84 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)), | 73 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)), |
85 listener_(base::MessageLoopProxy::current(), | 74 listener_(base::MessageLoopProxy::current(), |
86 weak_this_.GetWeakPtr()) {} | 75 weak_this_.GetWeakPtr()) {} |
87 | 76 |
88 MediaPlayerBridge::~MediaPlayerBridge() { | 77 MediaPlayerBridge::~MediaPlayerBridge() { |
89 Release(); | 78 Release(); |
90 } | 79 } |
91 | 80 |
92 void MediaPlayerBridge::InitializePlayer() { | 81 void MediaPlayerBridge::InitializePlayer() { |
93 JNIEnv* env = AttachCurrentThread(); | 82 JNIEnv* env = base::android::AttachCurrentThread(); |
94 CHECK(env); | 83 CHECK(env); |
95 | 84 |
96 j_media_player_.Reset(JNI_MediaPlayer::Java_MediaPlayer_Constructor(env)); | 85 j_media_player_.Reset(JNI_MediaPlayer::Java_MediaPlayer_Constructor(env)); |
97 | 86 |
98 jobject j_context = base::android::GetApplicationContext(); | 87 jobject j_context = base::android::GetApplicationContext(); |
99 DCHECK(j_context); | 88 DCHECK(j_context); |
100 | 89 |
101 listener_.CreateMediaPlayerListener(j_context, j_media_player_.obj()); | 90 listener_.CreateMediaPlayerListener(j_context, j_media_player_.obj()); |
102 } | 91 } |
103 | 92 |
104 void MediaPlayerBridge::SetVideoSurface(jobject surface) { | 93 void MediaPlayerBridge::SetVideoSurface(jobject surface) { |
105 if (j_media_player_.is_null() && surface != NULL) | 94 if (j_media_player_.is_null() && surface != NULL) |
106 Prepare(); | 95 Prepare(); |
107 | 96 |
108 JNIEnv* env = AttachCurrentThread(); | 97 JNIEnv* env = base::android::AttachCurrentThread(); |
109 CHECK(env); | 98 CHECK(env); |
110 | 99 |
111 JNI_MediaPlayer::Java_MediaPlayer_setSurface( | 100 JNI_MediaPlayer::Java_MediaPlayer_setSurface( |
112 env, j_media_player_.obj(), surface); | 101 env, j_media_player_.obj(), surface); |
113 } | 102 } |
114 | 103 |
115 void MediaPlayerBridge::Prepare() { | 104 void MediaPlayerBridge::Prepare() { |
116 if (j_media_player_.is_null()) | 105 if (j_media_player_.is_null()) |
117 InitializePlayer(); | 106 InitializePlayer(); |
118 | 107 |
119 if (has_cookies_) { | 108 if (has_cookies_) { |
120 GetCookiesCallback(cookies_); | 109 GetCookiesCallback(cookies_); |
121 } else { | 110 } else { |
122 cookie_getter_->GetCookies(url_, first_party_for_cookies_, base::Bind( | 111 cookie_getter_->GetCookies(url_, first_party_for_cookies_, base::Bind( |
123 &MediaPlayerBridge::GetCookiesCallback, weak_this_.GetWeakPtr())); | 112 &MediaPlayerBridge::GetCookiesCallback, weak_this_.GetWeakPtr())); |
124 } | 113 } |
125 } | 114 } |
126 | 115 |
127 void MediaPlayerBridge::GetCookiesCallback(const std::string& cookies) { | 116 void MediaPlayerBridge::GetCookiesCallback(const std::string& cookies) { |
128 cookies_ = cookies; | 117 cookies_ = cookies; |
129 has_cookies_ = true; | 118 has_cookies_ = true; |
130 if (j_media_player_.is_null()) | 119 if (j_media_player_.is_null()) |
131 return; | 120 return; |
132 | 121 |
133 JNIEnv* env = AttachCurrentThread(); | 122 JNIEnv* env = base::android::AttachCurrentThread(); |
134 CHECK(env); | 123 CHECK(env); |
135 | 124 |
136 // Create a Java String for the URL. | 125 // Create a Java String for the URL. |
137 ScopedJavaLocalRef<jstring> j_url_string = ConvertUTF8ToJavaString(env, url_); | 126 ScopedJavaLocalRef<jstring> j_url_string = ConvertUTF8ToJavaString(env, url_); |
138 ScopedJavaLocalRef<jstring> j_cookies = ConvertUTF8ToJavaString( | 127 ScopedJavaLocalRef<jstring> j_cookies = ConvertUTF8ToJavaString( |
139 env, cookies_); | 128 env, cookies_); |
140 | 129 |
141 jobject j_context = base::android::GetApplicationContext(); | 130 jobject j_context = base::android::GetApplicationContext(); |
142 DCHECK(j_context); | 131 DCHECK(j_context); |
143 | 132 |
(...skipping 29 matching lines...) Expand all Loading... |
173 PauseInternal(); | 162 PauseInternal(); |
174 else | 163 else |
175 pending_play_ = false; | 164 pending_play_ = false; |
176 } | 165 } |
177 } | 166 } |
178 | 167 |
179 bool MediaPlayerBridge::IsPlaying() { | 168 bool MediaPlayerBridge::IsPlaying() { |
180 if (!prepared_) | 169 if (!prepared_) |
181 return pending_play_; | 170 return pending_play_; |
182 | 171 |
183 JNIEnv* env = AttachCurrentThread(); | 172 JNIEnv* env = base::android::AttachCurrentThread(); |
184 CHECK(env); | 173 CHECK(env); |
185 jboolean result = JNI_MediaPlayer::Java_MediaPlayer_isPlaying( | 174 jboolean result = JNI_MediaPlayer::Java_MediaPlayer_isPlaying( |
186 env, j_media_player_.obj()); | 175 env, j_media_player_.obj()); |
187 return result; | 176 return result; |
188 } | 177 } |
189 | 178 |
190 int MediaPlayerBridge::GetVideoWidth() { | 179 int MediaPlayerBridge::GetVideoWidth() { |
191 if (!prepared_) | 180 if (!prepared_) |
192 return width_; | 181 return width_; |
193 JNIEnv* env = AttachCurrentThread(); | 182 JNIEnv* env = base::android::AttachCurrentThread(); |
194 return JNI_MediaPlayer::Java_MediaPlayer_getVideoWidth( | 183 return JNI_MediaPlayer::Java_MediaPlayer_getVideoWidth( |
195 env, j_media_player_.obj()); | 184 env, j_media_player_.obj()); |
196 } | 185 } |
197 | 186 |
198 int MediaPlayerBridge::GetVideoHeight() { | 187 int MediaPlayerBridge::GetVideoHeight() { |
199 if (!prepared_) | 188 if (!prepared_) |
200 return height_; | 189 return height_; |
201 JNIEnv* env = AttachCurrentThread(); | 190 JNIEnv* env = base::android::AttachCurrentThread(); |
202 return JNI_MediaPlayer::Java_MediaPlayer_getVideoHeight( | 191 return JNI_MediaPlayer::Java_MediaPlayer_getVideoHeight( |
203 env, j_media_player_.obj()); | 192 env, j_media_player_.obj()); |
204 } | 193 } |
205 | 194 |
206 void MediaPlayerBridge::SeekTo(base::TimeDelta time) { | 195 void MediaPlayerBridge::SeekTo(base::TimeDelta time) { |
207 // Record the time to seek when OnMediaPrepared() is called. | 196 // Record the time to seek when OnMediaPrepared() is called. |
208 pending_seek_ = time; | 197 pending_seek_ = time; |
209 | 198 |
210 if (j_media_player_.is_null()) | 199 if (j_media_player_.is_null()) |
211 Prepare(); | 200 Prepare(); |
212 else if (prepared_) | 201 else if (prepared_) |
213 SeekInternal(time); | 202 SeekInternal(time); |
214 } | 203 } |
215 | 204 |
216 base::TimeDelta MediaPlayerBridge::GetCurrentTime() { | 205 base::TimeDelta MediaPlayerBridge::GetCurrentTime() { |
217 if (!prepared_) | 206 if (!prepared_) |
218 return pending_seek_; | 207 return pending_seek_; |
219 JNIEnv* env = AttachCurrentThread(); | 208 JNIEnv* env = base::android::AttachCurrentThread(); |
220 return base::TimeDelta::FromMilliseconds( | 209 return base::TimeDelta::FromMilliseconds( |
221 JNI_MediaPlayer::Java_MediaPlayer_getCurrentPosition( | 210 JNI_MediaPlayer::Java_MediaPlayer_getCurrentPosition( |
222 env, j_media_player_.obj())); | 211 env, j_media_player_.obj())); |
223 } | 212 } |
224 | 213 |
225 base::TimeDelta MediaPlayerBridge::GetDuration() { | 214 base::TimeDelta MediaPlayerBridge::GetDuration() { |
226 if (!prepared_) | 215 if (!prepared_) |
227 return duration_; | 216 return duration_; |
228 JNIEnv* env = AttachCurrentThread(); | 217 JNIEnv* env = base::android::AttachCurrentThread(); |
229 return base::TimeDelta::FromMilliseconds( | 218 return base::TimeDelta::FromMilliseconds( |
230 JNI_MediaPlayer::Java_MediaPlayer_getDuration( | 219 JNI_MediaPlayer::Java_MediaPlayer_getDuration( |
231 env, j_media_player_.obj())); | 220 env, j_media_player_.obj())); |
232 } | 221 } |
233 | 222 |
234 void MediaPlayerBridge::Release() { | 223 void MediaPlayerBridge::Release() { |
235 if (j_media_player_.is_null()) | 224 if (j_media_player_.is_null()) |
236 return; | 225 return; |
237 | 226 |
238 time_update_timer_.Stop(); | 227 time_update_timer_.Stop(); |
239 if (prepared_) | 228 if (prepared_) |
240 pending_seek_ = GetCurrentTime(); | 229 pending_seek_ = GetCurrentTime(); |
241 if (manager_) | 230 if (manager_) |
242 manager_->ReleaseMediaResources(this); | 231 manager_->ReleaseMediaResources(this); |
243 prepared_ = false; | 232 prepared_ = false; |
244 pending_play_ = false; | 233 pending_play_ = false; |
245 SetVideoSurface(NULL); | 234 SetVideoSurface(NULL); |
246 | 235 |
247 JNIEnv* env = AttachCurrentThread(); | 236 JNIEnv* env = base::android::AttachCurrentThread(); |
248 JNI_MediaPlayer::Java_MediaPlayer_release(env, j_media_player_.obj()); | 237 JNI_MediaPlayer::Java_MediaPlayer_release(env, j_media_player_.obj()); |
249 j_media_player_.Reset(); | 238 j_media_player_.Reset(); |
250 | 239 |
251 listener_.ReleaseMediaPlayerListenerResources(); | 240 listener_.ReleaseMediaPlayerListenerResources(); |
252 } | 241 } |
253 | 242 |
254 void MediaPlayerBridge::SetVolume(float left_volume, float right_volume) { | 243 void MediaPlayerBridge::SetVolume(float left_volume, float right_volume) { |
255 if (j_media_player_.is_null()) | 244 if (j_media_player_.is_null()) |
256 return; | 245 return; |
257 | 246 |
258 JNIEnv* env = AttachCurrentThread(); | 247 JNIEnv* env = base::android::AttachCurrentThread(); |
259 CHECK(env); | 248 CHECK(env); |
260 JNI_MediaPlayer::Java_MediaPlayer_setVolume( | 249 JNI_MediaPlayer::Java_MediaPlayer_setVolume( |
261 env, j_media_player_.obj(), left_volume, right_volume); | 250 env, j_media_player_.obj(), left_volume, right_volume); |
262 } | 251 } |
263 | 252 |
264 void MediaPlayerBridge::DoTimeUpdate() { | 253 void MediaPlayerBridge::DoTimeUpdate() { |
265 base::TimeDelta current = GetCurrentTime(); | 254 base::TimeDelta current = GetCurrentTime(); |
266 time_update_cb_.Run(player_id_, current); | 255 time_update_cb_.Run(player_id_, current); |
267 } | 256 } |
268 | 257 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 StartInternal(); | 307 StartInternal(); |
319 pending_play_ = false; | 308 pending_play_ = false; |
320 } | 309 } |
321 | 310 |
322 GetMetadata(); | 311 GetMetadata(); |
323 | 312 |
324 media_prepared_cb_.Run(player_id_, duration_); | 313 media_prepared_cb_.Run(player_id_, duration_); |
325 } | 314 } |
326 | 315 |
327 void MediaPlayerBridge::GetMetadata() { | 316 void MediaPlayerBridge::GetMetadata() { |
328 JNIEnv* env = AttachCurrentThread(); | 317 JNIEnv* env = base::android::AttachCurrentThread(); |
329 CHECK(env); | 318 CHECK(env); |
330 | 319 |
331 ScopedJavaLocalRef<jclass> media_player_class( | 320 ScopedJavaLocalRef<jobject> allowedOperations = |
332 GetClass(env, "android/media/MediaPlayer")); | 321 Java_MediaPlayerBridge_getAllowedOperations(env, j_media_player_.obj()); |
333 jmethodID method = MethodID::Get<MethodID::TYPE_INSTANCE>( | 322 can_pause_ = Java_AllowedOperations_canPause(env, allowedOperations.obj()); |
334 env, media_player_class.obj(), "getMetadata", | 323 can_seek_forward_ = Java_AllowedOperations_canSeekForward( |
335 "(ZZ)Landroid/media/Metadata;"); | 324 env, allowedOperations.obj()); |
336 ScopedJavaLocalRef<jobject> j_metadata( | 325 can_seek_backward_ = Java_AllowedOperations_canSeekBackward( |
337 env, env->CallObjectMethod( | 326 env, allowedOperations.obj()); |
338 j_media_player_.obj(), method, JNI_FALSE, JNI_FALSE)); | |
339 CheckException(env); | |
340 if (j_metadata.is_null()) | |
341 return; | |
342 | |
343 ScopedJavaLocalRef<jclass> metadata_class( | |
344 GetClass(env, "android/media/Metadata")); | |
345 jmethodID get_boolean = MethodID::Get<MethodID::TYPE_INSTANCE>( | |
346 env, metadata_class.obj(), "getBoolean", "(I)Z"); | |
347 can_pause_ = env->CallBooleanMethod(j_metadata.obj(), | |
348 get_boolean, | |
349 kPauseAvailable); | |
350 CheckException(env); | |
351 can_seek_forward_ = env->CallBooleanMethod(j_metadata.obj(), | |
352 get_boolean, | |
353 kSeekBackwardAvailable); | |
354 CheckException(env); | |
355 can_seek_backward_ = env->CallBooleanMethod(j_metadata.obj(), | |
356 get_boolean, | |
357 kSeekForwardAvailable); | |
358 CheckException(env); | |
359 } | 327 } |
360 | 328 |
361 void MediaPlayerBridge::StartInternal() { | 329 void MediaPlayerBridge::StartInternal() { |
362 JNIEnv* env = AttachCurrentThread(); | 330 JNIEnv* env = base::android::AttachCurrentThread(); |
363 JNI_MediaPlayer::Java_MediaPlayer_start(env, j_media_player_.obj()); | 331 JNI_MediaPlayer::Java_MediaPlayer_start(env, j_media_player_.obj()); |
364 if (!time_update_timer_.IsRunning()) { | 332 if (!time_update_timer_.IsRunning()) { |
365 time_update_timer_.Start( | 333 time_update_timer_.Start( |
366 FROM_HERE, | 334 FROM_HERE, |
367 base::TimeDelta::FromMilliseconds(kTimeUpdateInterval), | 335 base::TimeDelta::FromMilliseconds(kTimeUpdateInterval), |
368 this, &MediaPlayerBridge::DoTimeUpdate); | 336 this, &MediaPlayerBridge::DoTimeUpdate); |
369 } | 337 } |
370 } | 338 } |
371 | 339 |
372 void MediaPlayerBridge::PauseInternal() { | 340 void MediaPlayerBridge::PauseInternal() { |
373 JNIEnv* env = AttachCurrentThread(); | 341 JNIEnv* env = base::android::AttachCurrentThread(); |
374 JNI_MediaPlayer::Java_MediaPlayer_pause(env, j_media_player_.obj()); | 342 JNI_MediaPlayer::Java_MediaPlayer_pause(env, j_media_player_.obj()); |
375 time_update_timer_.Stop(); | 343 time_update_timer_.Stop(); |
376 } | 344 } |
377 | 345 |
378 void MediaPlayerBridge::SeekInternal(base::TimeDelta time) { | 346 void MediaPlayerBridge::SeekInternal(base::TimeDelta time) { |
379 JNIEnv* env = AttachCurrentThread(); | 347 JNIEnv* env = base::android::AttachCurrentThread(); |
380 CHECK(env); | 348 CHECK(env); |
381 | 349 |
382 int time_msec = static_cast<int>(time.InMilliseconds()); | 350 int time_msec = static_cast<int>(time.InMilliseconds()); |
383 JNI_MediaPlayer::Java_MediaPlayer_seekTo( | 351 JNI_MediaPlayer::Java_MediaPlayer_seekTo( |
384 env, j_media_player_.obj(), time_msec); | 352 env, j_media_player_.obj(), time_msec); |
385 } | 353 } |
386 | 354 |
387 bool MediaPlayerBridge::RegisterMediaPlayerBridge(JNIEnv* env) { | 355 bool MediaPlayerBridge::RegisterMediaPlayerBridge(JNIEnv* env) { |
388 bool ret = RegisterNativesImpl(env); | 356 bool ret = RegisterNativesImpl(env); |
389 DCHECK(g_MediaPlayerBridge_clazz); | 357 DCHECK(g_MediaPlayerBridge_clazz); |
390 if (ret) | 358 if (ret) |
391 ret = JNI_MediaPlayer::RegisterNativesImpl(env); | 359 ret = JNI_MediaPlayer::RegisterNativesImpl(env); |
392 return ret; | 360 return ret; |
393 } | 361 } |
394 | 362 |
395 } // namespace media | 363 } // namespace media |
OLD | NEW |