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.
5 #include "media/base/android/media_player_bridge.h"
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 "jni/MediaPlayerBridge_jni.h"
13 #include "media/base/android/media_player_manager.h"
14 #include "media/base/android/media_resource_getter.h"
15 #include "media/base/android/media_source_player.h"
17 using base::android::ConvertUTF8ToJavaString
;
18 using base::android::ScopedJavaLocalRef
;
20 // Time update happens every 250ms.
21 static const int kTimeUpdateInterval
= 250;
25 #if !defined(GOOGLE_TV)
27 MediaPlayerAndroid
* MediaPlayerAndroid::Create(
30 SourceType source_type
,
31 const GURL
& first_party_for_cookies
,
33 MediaPlayerManager
* manager
) {
34 if (source_type
== SOURCE_TYPE_URL
) {
35 MediaPlayerBridge
* media_player_bridge
= new MediaPlayerBridge(
38 first_party_for_cookies
,
41 media_player_bridge
->Initialize();
42 return media_player_bridge
;
44 return new MediaSourcePlayer(
51 MediaPlayerBridge::MediaPlayerBridge(
54 const GURL
& first_party_for_cookies
,
56 MediaPlayerManager
* manager
)
57 : MediaPlayerAndroid(player_id
,
62 first_party_for_cookies_(first_party_for_cookies
),
63 hide_url_log_(hide_url_log
),
67 can_seek_forward_(true),
68 can_seek_backward_(true),
70 listener_(base::MessageLoopProxy::current(),
71 weak_this_
.GetWeakPtr()) {
74 MediaPlayerBridge::~MediaPlayerBridge() {
78 void MediaPlayerBridge::Initialize() {
79 if (url_
.SchemeIsFile()) {
81 ExtractMediaMetadata(url_
.spec());
85 media::MediaResourceGetter
* resource_getter
=
86 manager()->GetMediaResourceGetter();
87 if (url_
.SchemeIsFileSystem()) {
89 resource_getter
->GetPlatformPathFromFileSystemURL(url_
, base::Bind(
90 &MediaPlayerBridge::ExtractMediaMetadata
, weak_this_
.GetWeakPtr()));
94 resource_getter
->GetCookies(url_
, first_party_for_cookies_
, base::Bind(
95 &MediaPlayerBridge::OnCookiesRetrieved
, weak_this_
.GetWeakPtr()));
98 void MediaPlayerBridge::CreateJavaMediaPlayerBridge() {
99 JNIEnv
* env
= base::android::AttachCurrentThread();
102 j_media_player_bridge_
.Reset(Java_MediaPlayerBridge_create(env
));
104 SetMediaPlayerListener();
107 void MediaPlayerBridge::SetJavaMediaPlayerBridge(
108 jobject j_media_player_bridge
) {
109 JNIEnv
* env
= base::android::AttachCurrentThread();
112 j_media_player_bridge_
.Reset(env
, j_media_player_bridge
);
115 void MediaPlayerBridge::SetMediaPlayerListener() {
116 jobject j_context
= base::android::GetApplicationContext();
119 listener_
.CreateMediaPlayerListener(j_context
, j_media_player_bridge_
.obj());
122 void MediaPlayerBridge::SetDuration(base::TimeDelta duration
) {
123 duration_
= duration
;
126 void MediaPlayerBridge::SetVideoSurface(gfx::ScopedJavaSurface surface
) {
127 if (j_media_player_bridge_
.is_null()) {
128 if (surface
.IsEmpty())
133 JNIEnv
* env
= base::android::AttachCurrentThread();
136 Java_MediaPlayerBridge_setSurface(
137 env
, j_media_player_bridge_
.obj(), surface
.j_surface().obj());
140 void MediaPlayerBridge::Prepare() {
141 if (j_media_player_bridge_
.is_null())
142 CreateJavaMediaPlayerBridge();
143 if (url_
.SchemeIsFileSystem()) {
144 manager()->GetMediaResourceGetter()->GetPlatformPathFromFileSystemURL(
145 url_
, base::Bind(&MediaPlayerBridge::SetDataSource
,
146 weak_this_
.GetWeakPtr()));
148 SetDataSource(url_
.spec());
152 void MediaPlayerBridge::SetDataSource(const std::string
& url
) {
153 if (j_media_player_bridge_
.is_null())
156 JNIEnv
* env
= base::android::AttachCurrentThread();
159 // Create a Java String for the URL.
160 ScopedJavaLocalRef
<jstring
> j_url_string
= ConvertUTF8ToJavaString(env
, url
);
161 ScopedJavaLocalRef
<jstring
> j_cookies
= ConvertUTF8ToJavaString(
164 jobject j_context
= base::android::GetApplicationContext();
167 if (Java_MediaPlayerBridge_setDataSource(
168 env
, j_media_player_bridge_
.obj(), j_context
, j_url_string
.obj(),
169 j_cookies
.obj(), hide_url_log_
)) {
170 RequestMediaResourcesFromManager();
171 Java_MediaPlayerBridge_prepareAsync(
172 env
, j_media_player_bridge_
.obj());
174 OnMediaError(MEDIA_ERROR_FORMAT
);
178 void MediaPlayerBridge::OnCookiesRetrieved(const std::string
& cookies
) {
180 ExtractMediaMetadata(url_
.spec());
183 void MediaPlayerBridge::ExtractMediaMetadata(const std::string
& url
) {
184 manager()->GetMediaResourceGetter()->ExtractMediaMetadata(
185 url
, cookies_
, base::Bind(&MediaPlayerBridge::OnMediaMetadataExtracted
,
186 weak_this_
.GetWeakPtr()));
189 void MediaPlayerBridge::OnMediaMetadataExtracted(
190 base::TimeDelta duration
, int width
, int height
, bool success
) {
192 duration_
= duration
;
196 OnMediaMetadataChanged(duration_
, width_
, height_
, success
);
199 void MediaPlayerBridge::Start() {
200 if (j_media_player_bridge_
.is_null()) {
201 pending_play_
= true;
207 pending_play_
= true;
211 void MediaPlayerBridge::Pause() {
212 if (j_media_player_bridge_
.is_null()) {
213 pending_play_
= false;
215 if (prepared_
&& IsPlaying())
218 pending_play_
= false;
222 bool MediaPlayerBridge::IsPlaying() {
224 return pending_play_
;
226 JNIEnv
* env
= base::android::AttachCurrentThread();
228 jboolean result
= Java_MediaPlayerBridge_isPlaying(
229 env
, j_media_player_bridge_
.obj());
233 int MediaPlayerBridge::GetVideoWidth() {
236 JNIEnv
* env
= base::android::AttachCurrentThread();
237 return Java_MediaPlayerBridge_getVideoWidth(
238 env
, j_media_player_bridge_
.obj());
241 int MediaPlayerBridge::GetVideoHeight() {
244 JNIEnv
* env
= base::android::AttachCurrentThread();
245 return Java_MediaPlayerBridge_getVideoHeight(
246 env
, j_media_player_bridge_
.obj());
249 void MediaPlayerBridge::SeekTo(base::TimeDelta time
) {
250 // Record the time to seek when OnMediaPrepared() is called.
251 pending_seek_
= time
;
253 if (j_media_player_bridge_
.is_null())
259 base::TimeDelta
MediaPlayerBridge::GetCurrentTime() {
261 return pending_seek_
;
262 JNIEnv
* env
= base::android::AttachCurrentThread();
263 return base::TimeDelta::FromMilliseconds(
264 Java_MediaPlayerBridge_getCurrentPosition(
265 env
, j_media_player_bridge_
.obj()));
268 base::TimeDelta
MediaPlayerBridge::GetDuration() {
271 JNIEnv
* env
= base::android::AttachCurrentThread();
272 return base::TimeDelta::FromMilliseconds(
273 Java_MediaPlayerBridge_getDuration(
274 env
, j_media_player_bridge_
.obj()));
277 void MediaPlayerBridge::Release() {
278 if (j_media_player_bridge_
.is_null())
281 time_update_timer_
.Stop();
283 pending_seek_
= GetCurrentTime();
285 pending_play_
= false;
286 SetVideoSurface(gfx::ScopedJavaSurface());
288 JNIEnv
* env
= base::android::AttachCurrentThread();
289 Java_MediaPlayerBridge_release(env
, j_media_player_bridge_
.obj());
290 j_media_player_bridge_
.Reset();
291 ReleaseMediaResourcesFromManager();
292 listener_
.ReleaseMediaPlayerListenerResources();
295 void MediaPlayerBridge::SetVolume(double volume
) {
296 if (j_media_player_bridge_
.is_null())
299 JNIEnv
* env
= base::android::AttachCurrentThread();
301 Java_MediaPlayerBridge_setVolume(
302 env
, j_media_player_bridge_
.obj(), volume
);
305 void MediaPlayerBridge::OnVideoSizeChanged(int width
, int height
) {
308 MediaPlayerAndroid::OnVideoSizeChanged(width
, height
);
311 void MediaPlayerBridge::OnPlaybackComplete() {
312 time_update_timer_
.Stop();
313 MediaPlayerAndroid::OnPlaybackComplete();
316 void MediaPlayerBridge::OnMediaInterrupted() {
317 time_update_timer_
.Stop();
318 MediaPlayerAndroid::OnMediaInterrupted();
321 void MediaPlayerBridge::OnMediaPrepared() {
322 if (j_media_player_bridge_
.is_null())
326 duration_
= GetDuration();
328 // If media player was recovered from a saved state, consume all the pending
330 PendingSeekInternal(pending_seek_
);
334 pending_play_
= false;
337 GetAllowedOperations();
338 OnMediaMetadataChanged(duration_
, width_
, height_
, true);
341 void MediaPlayerBridge::GetAllowedOperations() {
342 JNIEnv
* env
= base::android::AttachCurrentThread();
345 ScopedJavaLocalRef
<jobject
> allowedOperations
=
346 Java_MediaPlayerBridge_getAllowedOperations(
347 env
, j_media_player_bridge_
.obj());
348 can_pause_
= Java_AllowedOperations_canPause(env
, allowedOperations
.obj());
349 can_seek_forward_
= Java_AllowedOperations_canSeekForward(
350 env
, allowedOperations
.obj());
351 can_seek_backward_
= Java_AllowedOperations_canSeekBackward(
352 env
, allowedOperations
.obj());
355 void MediaPlayerBridge::StartInternal() {
356 JNIEnv
* env
= base::android::AttachCurrentThread();
357 Java_MediaPlayerBridge_start(env
, j_media_player_bridge_
.obj());
358 if (!time_update_timer_
.IsRunning()) {
359 time_update_timer_
.Start(
361 base::TimeDelta::FromMilliseconds(kTimeUpdateInterval
),
362 this, &MediaPlayerBridge::OnTimeUpdated
);
366 void MediaPlayerBridge::PauseInternal() {
367 JNIEnv
* env
= base::android::AttachCurrentThread();
368 Java_MediaPlayerBridge_pause(env
, j_media_player_bridge_
.obj());
369 time_update_timer_
.Stop();
372 void MediaPlayerBridge::PendingSeekInternal(base::TimeDelta time
) {
376 void MediaPlayerBridge::SeekInternal(base::TimeDelta time
) {
377 if (time
> duration_
)
380 // Seeking to an invalid position may cause media player to stuck in an
382 if (time
< base::TimeDelta()) {
383 DCHECK_EQ(-1.0, time
.InMillisecondsF());
387 JNIEnv
* env
= base::android::AttachCurrentThread();
389 int time_msec
= static_cast<int>(time
.InMilliseconds());
390 Java_MediaPlayerBridge_seekTo(
391 env
, j_media_player_bridge_
.obj(), time_msec
);
394 bool MediaPlayerBridge::RegisterMediaPlayerBridge(JNIEnv
* env
) {
395 bool ret
= RegisterNativesImpl(env
);
396 DCHECK(g_MediaPlayerBridge_clazz
);
400 bool MediaPlayerBridge::CanPause() {
404 bool MediaPlayerBridge::CanSeekForward() {
405 return can_seek_forward_
;
408 bool MediaPlayerBridge::CanSeekBackward() {
409 return can_seek_backward_
;
412 bool MediaPlayerBridge::IsPlayerReady() {
416 GURL
MediaPlayerBridge::GetUrl() {
420 GURL
MediaPlayerBridge::GetFirstPartyForCookies() {
421 return first_party_for_cookies_
;