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"
16 using base::android::ConvertUTF8ToJavaString
;
17 using base::android::ScopedJavaLocalRef
;
19 // Time update happens every 250ms.
20 static const int kTimeUpdateInterval
= 250;
24 MediaPlayerBridge::MediaPlayerBridge(
27 const GURL
& first_party_for_cookies
,
29 MediaPlayerManager
* manager
)
30 : MediaPlayerAndroid(player_id
,
35 first_party_for_cookies_(first_party_for_cookies
),
36 hide_url_log_(hide_url_log
),
40 can_seek_forward_(true),
41 can_seek_backward_(true),
43 listener_(base::MessageLoopProxy::current(),
44 weak_this_
.GetWeakPtr()) {
47 MediaPlayerBridge::~MediaPlayerBridge() {
51 void MediaPlayerBridge::Initialize() {
52 if (url_
.SchemeIsFile()) {
54 ExtractMediaMetadata(url_
.spec());
58 media::MediaResourceGetter
* resource_getter
=
59 manager()->GetMediaResourceGetter();
60 if (url_
.SchemeIsFileSystem()) {
62 resource_getter
->GetPlatformPathFromFileSystemURL(url_
, base::Bind(
63 &MediaPlayerBridge::ExtractMediaMetadata
, weak_this_
.GetWeakPtr()));
67 resource_getter
->GetCookies(url_
, first_party_for_cookies_
, base::Bind(
68 &MediaPlayerBridge::OnCookiesRetrieved
, weak_this_
.GetWeakPtr()));
71 void MediaPlayerBridge::CreateJavaMediaPlayerBridge() {
72 JNIEnv
* env
= base::android::AttachCurrentThread();
75 j_media_player_bridge_
.Reset(Java_MediaPlayerBridge_create(env
));
77 SetMediaPlayerListener();
80 void MediaPlayerBridge::SetJavaMediaPlayerBridge(
81 jobject j_media_player_bridge
) {
82 JNIEnv
* env
= base::android::AttachCurrentThread();
85 j_media_player_bridge_
.Reset(env
, j_media_player_bridge
);
88 void MediaPlayerBridge::SetMediaPlayerListener() {
89 jobject j_context
= base::android::GetApplicationContext();
92 listener_
.CreateMediaPlayerListener(j_context
, j_media_player_bridge_
.obj());
95 void MediaPlayerBridge::SetDuration(base::TimeDelta duration
) {
99 void MediaPlayerBridge::SetVideoSurface(gfx::ScopedJavaSurface surface
) {
100 if (j_media_player_bridge_
.is_null()) {
101 if (surface
.IsEmpty())
106 JNIEnv
* env
= base::android::AttachCurrentThread();
109 Java_MediaPlayerBridge_setSurface(
110 env
, j_media_player_bridge_
.obj(), surface
.j_surface().obj());
113 void MediaPlayerBridge::Prepare() {
114 if (j_media_player_bridge_
.is_null())
115 CreateJavaMediaPlayerBridge();
116 if (url_
.SchemeIsFileSystem()) {
117 manager()->GetMediaResourceGetter()->GetPlatformPathFromFileSystemURL(
118 url_
, base::Bind(&MediaPlayerBridge::SetDataSource
,
119 weak_this_
.GetWeakPtr()));
121 SetDataSource(url_
.spec());
125 void MediaPlayerBridge::SetDataSource(const std::string
& url
) {
126 if (j_media_player_bridge_
.is_null())
129 JNIEnv
* env
= base::android::AttachCurrentThread();
132 // Create a Java String for the URL.
133 ScopedJavaLocalRef
<jstring
> j_url_string
= ConvertUTF8ToJavaString(env
, url
);
134 ScopedJavaLocalRef
<jstring
> j_cookies
= ConvertUTF8ToJavaString(
137 jobject j_context
= base::android::GetApplicationContext();
140 if (Java_MediaPlayerBridge_setDataSource(
141 env
, j_media_player_bridge_
.obj(), j_context
, j_url_string
.obj(),
142 j_cookies
.obj(), hide_url_log_
)) {
143 manager()->RequestMediaResources(player_id());
144 Java_MediaPlayerBridge_prepareAsync(
145 env
, j_media_player_bridge_
.obj());
147 OnMediaError(MEDIA_ERROR_FORMAT
);
151 void MediaPlayerBridge::OnCookiesRetrieved(const std::string
& cookies
) {
153 ExtractMediaMetadata(url_
.spec());
156 void MediaPlayerBridge::ExtractMediaMetadata(const std::string
& url
) {
157 manager()->GetMediaResourceGetter()->ExtractMediaMetadata(
158 url
, cookies_
, base::Bind(&MediaPlayerBridge::OnMediaMetadataExtracted
,
159 weak_this_
.GetWeakPtr()));
162 void MediaPlayerBridge::OnMediaMetadataExtracted(
163 base::TimeDelta duration
, int width
, int height
, bool success
) {
165 duration_
= duration
;
169 manager()->OnMediaMetadataChanged(
170 player_id(), duration_
, width_
, height_
, success
);
173 void MediaPlayerBridge::Start() {
174 if (j_media_player_bridge_
.is_null()) {
175 pending_play_
= true;
181 pending_play_
= true;
185 void MediaPlayerBridge::Pause(bool is_media_related_action
) {
186 if (j_media_player_bridge_
.is_null()) {
187 pending_play_
= false;
189 if (prepared_
&& IsPlaying())
192 pending_play_
= false;
196 bool MediaPlayerBridge::IsPlaying() {
198 return pending_play_
;
200 JNIEnv
* env
= base::android::AttachCurrentThread();
202 jboolean result
= Java_MediaPlayerBridge_isPlaying(
203 env
, j_media_player_bridge_
.obj());
207 int MediaPlayerBridge::GetVideoWidth() {
210 JNIEnv
* env
= base::android::AttachCurrentThread();
211 return Java_MediaPlayerBridge_getVideoWidth(
212 env
, j_media_player_bridge_
.obj());
215 int MediaPlayerBridge::GetVideoHeight() {
218 JNIEnv
* env
= base::android::AttachCurrentThread();
219 return Java_MediaPlayerBridge_getVideoHeight(
220 env
, j_media_player_bridge_
.obj());
223 void MediaPlayerBridge::SeekTo(const base::TimeDelta
& timestamp
) {
224 // Record the time to seek when OnMediaPrepared() is called.
225 pending_seek_
= timestamp
;
227 if (j_media_player_bridge_
.is_null())
230 SeekInternal(timestamp
);
233 base::TimeDelta
MediaPlayerBridge::GetCurrentTime() {
235 return pending_seek_
;
236 JNIEnv
* env
= base::android::AttachCurrentThread();
237 return base::TimeDelta::FromMilliseconds(
238 Java_MediaPlayerBridge_getCurrentPosition(
239 env
, j_media_player_bridge_
.obj()));
242 base::TimeDelta
MediaPlayerBridge::GetDuration() {
245 JNIEnv
* env
= base::android::AttachCurrentThread();
246 return base::TimeDelta::FromMilliseconds(
247 Java_MediaPlayerBridge_getDuration(
248 env
, j_media_player_bridge_
.obj()));
251 void MediaPlayerBridge::Release() {
252 if (j_media_player_bridge_
.is_null())
255 time_update_timer_
.Stop();
257 pending_seek_
= GetCurrentTime();
259 pending_play_
= false;
260 SetVideoSurface(gfx::ScopedJavaSurface());
262 JNIEnv
* env
= base::android::AttachCurrentThread();
263 Java_MediaPlayerBridge_release(env
, j_media_player_bridge_
.obj());
264 j_media_player_bridge_
.Reset();
265 manager()->ReleaseMediaResources(player_id());
266 listener_
.ReleaseMediaPlayerListenerResources();
269 void MediaPlayerBridge::SetVolume(double volume
) {
270 if (j_media_player_bridge_
.is_null())
273 JNIEnv
* env
= base::android::AttachCurrentThread();
275 Java_MediaPlayerBridge_setVolume(
276 env
, j_media_player_bridge_
.obj(), volume
);
279 void MediaPlayerBridge::OnVideoSizeChanged(int width
, int height
) {
282 manager()->OnVideoSizeChanged(player_id(), width
, height
);
285 void MediaPlayerBridge::OnMediaError(int error_type
) {
286 manager()->OnError(player_id(), error_type
);
289 void MediaPlayerBridge::OnBufferingUpdate(int percent
) {
290 manager()->OnBufferingUpdate(player_id(), percent
);
293 void MediaPlayerBridge::OnPlaybackComplete() {
294 time_update_timer_
.Stop();
295 manager()->OnPlaybackComplete(player_id());
298 void MediaPlayerBridge::OnMediaInterrupted() {
299 time_update_timer_
.Stop();
300 manager()->OnMediaInterrupted(player_id());
303 void MediaPlayerBridge::OnSeekComplete() {
304 manager()->OnSeekComplete(player_id(), GetCurrentTime());
307 void MediaPlayerBridge::OnMediaPrepared() {
308 if (j_media_player_bridge_
.is_null())
312 duration_
= GetDuration();
314 // If media player was recovered from a saved state, consume all the pending
316 PendingSeekInternal(pending_seek_
);
320 pending_play_
= false;
323 GetAllowedOperations();
324 manager()->OnMediaMetadataChanged(
325 player_id(), duration_
, width_
, height_
, true);
328 void MediaPlayerBridge::GetAllowedOperations() {
329 JNIEnv
* env
= base::android::AttachCurrentThread();
332 ScopedJavaLocalRef
<jobject
> allowedOperations
=
333 Java_MediaPlayerBridge_getAllowedOperations(
334 env
, j_media_player_bridge_
.obj());
335 can_pause_
= Java_AllowedOperations_canPause(env
, allowedOperations
.obj());
336 can_seek_forward_
= Java_AllowedOperations_canSeekForward(
337 env
, allowedOperations
.obj());
338 can_seek_backward_
= Java_AllowedOperations_canSeekBackward(
339 env
, allowedOperations
.obj());
342 void MediaPlayerBridge::StartInternal() {
343 JNIEnv
* env
= base::android::AttachCurrentThread();
344 Java_MediaPlayerBridge_start(env
, j_media_player_bridge_
.obj());
345 if (!time_update_timer_
.IsRunning()) {
346 time_update_timer_
.Start(
348 base::TimeDelta::FromMilliseconds(kTimeUpdateInterval
),
349 this, &MediaPlayerBridge::OnTimeUpdateTimerFired
);
353 void MediaPlayerBridge::PauseInternal() {
354 JNIEnv
* env
= base::android::AttachCurrentThread();
355 Java_MediaPlayerBridge_pause(env
, j_media_player_bridge_
.obj());
356 time_update_timer_
.Stop();
359 void MediaPlayerBridge::PendingSeekInternal(const base::TimeDelta
& time
) {
363 void MediaPlayerBridge::SeekInternal(base::TimeDelta time
) {
364 if (time
> duration_
)
367 // Seeking to an invalid position may cause media player to stuck in an
369 if (time
< base::TimeDelta()) {
370 DCHECK_EQ(-1.0, time
.InMillisecondsF());
374 JNIEnv
* env
= base::android::AttachCurrentThread();
376 int time_msec
= static_cast<int>(time
.InMilliseconds());
377 Java_MediaPlayerBridge_seekTo(
378 env
, j_media_player_bridge_
.obj(), time_msec
);
381 void MediaPlayerBridge::OnTimeUpdateTimerFired() {
382 manager()->OnTimeUpdate(player_id(), GetCurrentTime());
385 bool MediaPlayerBridge::RegisterMediaPlayerBridge(JNIEnv
* env
) {
386 bool ret
= RegisterNativesImpl(env
);
387 DCHECK(g_MediaPlayerBridge_clazz
);
391 bool MediaPlayerBridge::CanPause() {
395 bool MediaPlayerBridge::CanSeekForward() {
396 return can_seek_forward_
;
399 bool MediaPlayerBridge::CanSeekBackward() {
400 return can_seek_backward_
;
403 bool MediaPlayerBridge::IsPlayerReady() {
407 GURL
MediaPlayerBridge::GetUrl() {
411 GURL
MediaPlayerBridge::GetFirstPartyForCookies() {
412 return first_party_for_cookies_
;