Allow overlapping sync and async startup requests
[chromium-blink-merge.git] / media / base / android / media_player_bridge.cc
blob49c3563c12af780fb8743074045069ada66e2d0f
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;
23 namespace media {
25 #if !defined(GOOGLE_TV)
26 // static
27 MediaPlayerAndroid* MediaPlayerAndroid::Create(
28 int player_id,
29 const GURL& url,
30 SourceType source_type,
31 const GURL& first_party_for_cookies,
32 bool hide_url_log,
33 MediaPlayerManager* manager) {
34 if (source_type == SOURCE_TYPE_URL) {
35 MediaPlayerBridge* media_player_bridge = new MediaPlayerBridge(
36 player_id,
37 url,
38 first_party_for_cookies,
39 hide_url_log,
40 manager);
41 media_player_bridge->Initialize();
42 return media_player_bridge;
43 } else {
44 return new MediaSourcePlayer(
45 player_id,
46 manager);
49 #endif
51 MediaPlayerBridge::MediaPlayerBridge(
52 int player_id,
53 const GURL& url,
54 const GURL& first_party_for_cookies,
55 bool hide_url_log,
56 MediaPlayerManager* manager)
57 : MediaPlayerAndroid(player_id,
58 manager),
59 prepared_(false),
60 pending_play_(false),
61 url_(url),
62 first_party_for_cookies_(first_party_for_cookies),
63 hide_url_log_(hide_url_log),
64 width_(0),
65 height_(0),
66 can_pause_(true),
67 can_seek_forward_(true),
68 can_seek_backward_(true),
69 weak_this_(this),
70 listener_(base::MessageLoopProxy::current(),
71 weak_this_.GetWeakPtr()) {
74 MediaPlayerBridge::~MediaPlayerBridge() {
75 Release();
78 void MediaPlayerBridge::Initialize() {
79 if (url_.SchemeIsFile()) {
80 cookies_.clear();
81 ExtractMediaMetadata(url_.spec());
82 return;
85 media::MediaResourceGetter* resource_getter =
86 manager()->GetMediaResourceGetter();
87 if (url_.SchemeIsFileSystem()) {
88 cookies_.clear();
89 resource_getter->GetPlatformPathFromFileSystemURL(url_, base::Bind(
90 &MediaPlayerBridge::ExtractMediaMetadata, weak_this_.GetWeakPtr()));
91 return;
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();
100 CHECK(env);
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();
110 CHECK(env);
112 j_media_player_bridge_.Reset(env, j_media_player_bridge);
115 void MediaPlayerBridge::SetMediaPlayerListener() {
116 jobject j_context = base::android::GetApplicationContext();
117 DCHECK(j_context);
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())
129 return;
130 Prepare();
133 JNIEnv* env = base::android::AttachCurrentThread();
134 CHECK(env);
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()));
147 } else {
148 SetDataSource(url_.spec());
152 void MediaPlayerBridge::SetDataSource(const std::string& url) {
153 if (j_media_player_bridge_.is_null())
154 return;
156 JNIEnv* env = base::android::AttachCurrentThread();
157 CHECK(env);
159 // Create a Java String for the URL.
160 ScopedJavaLocalRef<jstring> j_url_string = ConvertUTF8ToJavaString(env, url);
161 ScopedJavaLocalRef<jstring> j_cookies = ConvertUTF8ToJavaString(
162 env, cookies_);
164 jobject j_context = base::android::GetApplicationContext();
165 DCHECK(j_context);
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());
173 } else {
174 OnMediaError(MEDIA_ERROR_FORMAT);
178 void MediaPlayerBridge::OnCookiesRetrieved(const std::string& cookies) {
179 cookies_ = 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) {
191 if (success) {
192 duration_ = duration;
193 width_ = width;
194 height_ = height;
196 OnMediaMetadataChanged(duration_, width_, height_, success);
199 void MediaPlayerBridge::Start() {
200 if (j_media_player_bridge_.is_null()) {
201 pending_play_ = true;
202 Prepare();
203 } else {
204 if (prepared_)
205 StartInternal();
206 else
207 pending_play_ = true;
211 void MediaPlayerBridge::Pause() {
212 if (j_media_player_bridge_.is_null()) {
213 pending_play_ = false;
214 } else {
215 if (prepared_ && IsPlaying())
216 PauseInternal();
217 else
218 pending_play_ = false;
222 bool MediaPlayerBridge::IsPlaying() {
223 if (!prepared_)
224 return pending_play_;
226 JNIEnv* env = base::android::AttachCurrentThread();
227 CHECK(env);
228 jboolean result = Java_MediaPlayerBridge_isPlaying(
229 env, j_media_player_bridge_.obj());
230 return result;
233 int MediaPlayerBridge::GetVideoWidth() {
234 if (!prepared_)
235 return width_;
236 JNIEnv* env = base::android::AttachCurrentThread();
237 return Java_MediaPlayerBridge_getVideoWidth(
238 env, j_media_player_bridge_.obj());
241 int MediaPlayerBridge::GetVideoHeight() {
242 if (!prepared_)
243 return height_;
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())
254 Prepare();
255 else if (prepared_)
256 SeekInternal(time);
259 base::TimeDelta MediaPlayerBridge::GetCurrentTime() {
260 if (!prepared_)
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() {
269 if (!prepared_)
270 return duration_;
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())
279 return;
281 time_update_timer_.Stop();
282 if (prepared_)
283 pending_seek_ = GetCurrentTime();
284 prepared_ = false;
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())
297 return;
299 JNIEnv* env = base::android::AttachCurrentThread();
300 CHECK(env);
301 Java_MediaPlayerBridge_setVolume(
302 env, j_media_player_bridge_.obj(), volume);
305 void MediaPlayerBridge::OnVideoSizeChanged(int width, int height) {
306 width_ = width;
307 height_ = 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())
323 return;
325 prepared_ = true;
326 duration_ = GetDuration();
328 // If media player was recovered from a saved state, consume all the pending
329 // events.
330 PendingSeekInternal(pending_seek_);
332 if (pending_play_) {
333 StartInternal();
334 pending_play_ = false;
337 GetAllowedOperations();
338 OnMediaMetadataChanged(duration_, width_, height_, true);
341 void MediaPlayerBridge::GetAllowedOperations() {
342 JNIEnv* env = base::android::AttachCurrentThread();
343 CHECK(env);
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(
360 FROM_HERE,
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) {
373 SeekInternal(time);
376 void MediaPlayerBridge::SeekInternal(base::TimeDelta time) {
377 if (time > duration_)
378 time = duration_;
380 // Seeking to an invalid position may cause media player to stuck in an
381 // error state.
382 if (time < base::TimeDelta()) {
383 DCHECK_EQ(-1.0, time.InMillisecondsF());
384 return;
387 JNIEnv* env = base::android::AttachCurrentThread();
388 CHECK(env);
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);
397 return ret;
400 bool MediaPlayerBridge::CanPause() {
401 return can_pause_;
404 bool MediaPlayerBridge::CanSeekForward() {
405 return can_seek_forward_;
408 bool MediaPlayerBridge::CanSeekBackward() {
409 return can_seek_backward_;
412 bool MediaPlayerBridge::IsPlayerReady() {
413 return prepared_;
416 GURL MediaPlayerBridge::GetUrl() {
417 return url_;
420 GURL MediaPlayerBridge::GetFirstPartyForCookies() {
421 return first_party_for_cookies_;
424 } // namespace media