Roll src/third_party/WebKit d10c917:a1123a1 (svn 198729:198730)
[chromium-blink-merge.git] / media / base / android / media_player_bridge.cc
blob5cc8b3933edb223c324775527751bee36b291b4f
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/strings/string_util.h"
12 #include "jni/MediaPlayerBridge_jni.h"
13 #include "media/base/android/media_common_android.h"
14 #include "media/base/android/media_player_manager.h"
15 #include "media/base/android/media_resource_getter.h"
16 #include "media/base/android/media_url_interceptor.h"
17 #include "media/base/buffers.h"
19 using base::android::ConvertUTF8ToJavaString;
20 using base::android::ScopedJavaLocalRef;
22 namespace media {
24 MediaPlayerBridge::MediaPlayerBridge(
25 int player_id,
26 const GURL& url,
27 const GURL& first_party_for_cookies,
28 const std::string& user_agent,
29 bool hide_url_log,
30 MediaPlayerManager* manager,
31 const RequestMediaResourcesCB& request_media_resources_cb,
32 const GURL& frame_url,
33 bool allow_credentials)
34 : MediaPlayerAndroid(player_id,
35 manager,
36 request_media_resources_cb,
37 frame_url),
38 prepared_(false),
39 pending_play_(false),
40 should_seek_on_prepare_(false),
41 url_(url),
42 first_party_for_cookies_(first_party_for_cookies),
43 user_agent_(user_agent),
44 hide_url_log_(hide_url_log),
45 width_(0),
46 height_(0),
47 can_pause_(true),
48 can_seek_forward_(true),
49 can_seek_backward_(true),
50 volume_(-1.0),
51 allow_credentials_(allow_credentials),
52 weak_factory_(this) {
55 MediaPlayerBridge::~MediaPlayerBridge() {
56 if (!j_media_player_bridge_.is_null()) {
57 JNIEnv* env = base::android::AttachCurrentThread();
58 CHECK(env);
59 Java_MediaPlayerBridge_destroy(env, j_media_player_bridge_.obj());
61 Release();
64 void MediaPlayerBridge::Initialize() {
65 cookies_.clear();
66 if (url_.SchemeIsFile() || url_.SchemeIs("data")) {
67 ExtractMediaMetadata(url_.spec());
68 return;
71 media::MediaResourceGetter* resource_getter =
72 manager()->GetMediaResourceGetter();
73 if (url_.SchemeIsFileSystem() || url_.SchemeIsBlob()) {
74 resource_getter->GetPlatformPathFromURL(
75 url_,
76 base::Bind(&MediaPlayerBridge::ExtractMediaMetadata,
77 weak_factory_.GetWeakPtr()));
78 return;
81 // Start extracting the metadata immediately if the request is anonymous.
82 // Otherwise, wait for user credentials to be retrieved first.
83 if (!allow_credentials_) {
84 ExtractMediaMetadata(url_.spec());
85 return;
88 resource_getter->GetCookies(url_,
89 first_party_for_cookies_,
90 base::Bind(&MediaPlayerBridge::OnCookiesRetrieved,
91 weak_factory_.GetWeakPtr()));
94 void MediaPlayerBridge::CreateJavaMediaPlayerBridge() {
95 JNIEnv* env = base::android::AttachCurrentThread();
96 CHECK(env);
98 j_media_player_bridge_.Reset(Java_MediaPlayerBridge_create(
99 env, reinterpret_cast<intptr_t>(this)));
101 if (volume_ >= 0)
102 SetVolume(volume_);
104 AttachListener(j_media_player_bridge_.obj());
107 void MediaPlayerBridge::SetDuration(base::TimeDelta duration) {
108 duration_ = duration;
111 void MediaPlayerBridge::SetVideoSurface(gfx::ScopedJavaSurface surface) {
112 if (j_media_player_bridge_.is_null()) {
113 if (surface.IsEmpty())
114 return;
115 Prepare();
118 JNIEnv* env = base::android::AttachCurrentThread();
119 CHECK(env);
120 Java_MediaPlayerBridge_setSurface(
121 env, j_media_player_bridge_.obj(), surface.j_surface().obj());
124 void MediaPlayerBridge::Prepare() {
125 DCHECK(j_media_player_bridge_.is_null());
126 CreateJavaMediaPlayerBridge();
127 if (url_.SchemeIsFileSystem() || url_.SchemeIsBlob()) {
128 manager()->GetMediaResourceGetter()->GetPlatformPathFromURL(
129 url_,
130 base::Bind(&MediaPlayerBridge::SetDataSource,
131 weak_factory_.GetWeakPtr()));
132 return;
135 SetDataSource(url_.spec());
138 void MediaPlayerBridge::SetDataSource(const std::string& url) {
139 if (j_media_player_bridge_.is_null())
140 return;
142 JNIEnv* env = base::android::AttachCurrentThread();
143 CHECK(env);
145 int fd;
146 int64 offset;
147 int64 size;
148 if (InterceptMediaUrl(url, &fd, &offset, &size)) {
149 if (!Java_MediaPlayerBridge_setDataSourceFromFd(
150 env, j_media_player_bridge_.obj(), fd, offset, size)) {
151 OnMediaError(MEDIA_ERROR_FORMAT);
152 return;
154 } else {
155 // Create a Java String for the URL.
156 ScopedJavaLocalRef<jstring> j_url_string =
157 ConvertUTF8ToJavaString(env, url);
159 jobject j_context = base::android::GetApplicationContext();
160 DCHECK(j_context);
162 const std::string data_uri_prefix("data:");
163 if (base::StartsWithASCII(url, data_uri_prefix, true)) {
164 if (!Java_MediaPlayerBridge_setDataUriDataSource(
165 env, j_media_player_bridge_.obj(), j_context, j_url_string.obj())) {
166 OnMediaError(MEDIA_ERROR_FORMAT);
168 return;
171 ScopedJavaLocalRef<jstring> j_cookies = ConvertUTF8ToJavaString(
172 env, cookies_);
173 ScopedJavaLocalRef<jstring> j_user_agent = ConvertUTF8ToJavaString(
174 env, user_agent_);
176 if (!Java_MediaPlayerBridge_setDataSource(
177 env, j_media_player_bridge_.obj(), j_context, j_url_string.obj(),
178 j_cookies.obj(), j_user_agent.obj(), hide_url_log_)) {
179 OnMediaError(MEDIA_ERROR_FORMAT);
180 return;
184 request_media_resources_cb_.Run(player_id());
185 if (!Java_MediaPlayerBridge_prepareAsync(env, j_media_player_bridge_.obj()))
186 OnMediaError(MEDIA_ERROR_FORMAT);
189 bool MediaPlayerBridge::InterceptMediaUrl(
190 const std::string& url, int* fd, int64* offset, int64* size) {
191 // Sentinel value to check whether the output arguments have been set.
192 const int kUnsetValue = -1;
194 *fd = kUnsetValue;
195 *offset = kUnsetValue;
196 *size = kUnsetValue;
197 media::MediaUrlInterceptor* url_interceptor =
198 manager()->GetMediaUrlInterceptor();
199 if (url_interceptor && url_interceptor->Intercept(url, fd, offset, size)) {
200 DCHECK_NE(kUnsetValue, *fd);
201 DCHECK_NE(kUnsetValue, *offset);
202 DCHECK_NE(kUnsetValue, *size);
203 return true;
205 return false;
208 void MediaPlayerBridge::OnDidSetDataUriDataSource(JNIEnv* env, jobject obj,
209 jboolean success) {
210 if (!success) {
211 OnMediaError(MEDIA_ERROR_FORMAT);
212 return;
215 request_media_resources_cb_.Run(player_id());
216 if (!Java_MediaPlayerBridge_prepareAsync(env, j_media_player_bridge_.obj()))
217 OnMediaError(MEDIA_ERROR_FORMAT);
220 void MediaPlayerBridge::OnCookiesRetrieved(const std::string& cookies) {
221 cookies_ = cookies;
222 manager()->GetMediaResourceGetter()->GetAuthCredentials(
223 url_,
224 base::Bind(&MediaPlayerBridge::OnAuthCredentialsRetrieved,
225 weak_factory_.GetWeakPtr()));
228 void MediaPlayerBridge::OnAuthCredentialsRetrieved(
229 const base::string16& username, const base::string16& password) {
230 GURL::ReplacementsW replacements;
231 if (!username.empty()) {
232 replacements.SetUsernameStr(username);
233 if (!password.empty())
234 replacements.SetPasswordStr(password);
235 url_ = url_.ReplaceComponents(replacements);
237 ExtractMediaMetadata(url_.spec());
240 void MediaPlayerBridge::ExtractMediaMetadata(const std::string& url) {
241 if (url.empty()) {
242 OnMediaError(MEDIA_ERROR_FORMAT);
243 return;
246 int fd;
247 int64 offset;
248 int64 size;
249 if (InterceptMediaUrl(url, &fd, &offset, &size)) {
250 manager()->GetMediaResourceGetter()->ExtractMediaMetadata(
251 fd, offset, size,
252 base::Bind(&MediaPlayerBridge::OnMediaMetadataExtracted,
253 weak_factory_.GetWeakPtr()));
254 } else {
255 manager()->GetMediaResourceGetter()->ExtractMediaMetadata(
256 url, cookies_, user_agent_,
257 base::Bind(&MediaPlayerBridge::OnMediaMetadataExtracted,
258 weak_factory_.GetWeakPtr()));
262 void MediaPlayerBridge::OnMediaMetadataExtracted(
263 base::TimeDelta duration, int width, int height, bool success) {
264 if (success) {
265 duration_ = duration;
266 width_ = width;
267 height_ = height;
269 manager()->OnMediaMetadataChanged(
270 player_id(), duration_, width_, height_, success);
273 void MediaPlayerBridge::Start() {
274 if (j_media_player_bridge_.is_null()) {
275 pending_play_ = true;
276 Prepare();
277 } else {
278 if (prepared_)
279 StartInternal();
280 else
281 pending_play_ = true;
285 void MediaPlayerBridge::Pause(bool is_media_related_action) {
286 if (j_media_player_bridge_.is_null()) {
287 pending_play_ = false;
288 } else {
289 if (prepared_ && IsPlaying())
290 PauseInternal();
291 else
292 pending_play_ = false;
296 bool MediaPlayerBridge::IsPlaying() {
297 if (!prepared_)
298 return pending_play_;
300 JNIEnv* env = base::android::AttachCurrentThread();
301 CHECK(env);
302 jboolean result = Java_MediaPlayerBridge_isPlaying(
303 env, j_media_player_bridge_.obj());
304 return result;
307 int MediaPlayerBridge::GetVideoWidth() {
308 if (!prepared_)
309 return width_;
310 JNIEnv* env = base::android::AttachCurrentThread();
311 return Java_MediaPlayerBridge_getVideoWidth(
312 env, j_media_player_bridge_.obj());
315 int MediaPlayerBridge::GetVideoHeight() {
316 if (!prepared_)
317 return height_;
318 JNIEnv* env = base::android::AttachCurrentThread();
319 return Java_MediaPlayerBridge_getVideoHeight(
320 env, j_media_player_bridge_.obj());
323 void MediaPlayerBridge::SeekTo(base::TimeDelta timestamp) {
324 // Record the time to seek when OnMediaPrepared() is called.
325 pending_seek_ = timestamp;
326 should_seek_on_prepare_ = true;
328 if (j_media_player_bridge_.is_null())
329 Prepare();
330 else if (prepared_)
331 SeekInternal(timestamp);
334 base::TimeDelta MediaPlayerBridge::GetCurrentTime() {
335 if (!prepared_)
336 return pending_seek_;
337 JNIEnv* env = base::android::AttachCurrentThread();
338 return base::TimeDelta::FromMilliseconds(
339 Java_MediaPlayerBridge_getCurrentPosition(
340 env, j_media_player_bridge_.obj()));
343 base::TimeDelta MediaPlayerBridge::GetDuration() {
344 if (!prepared_)
345 return duration_;
346 JNIEnv* env = base::android::AttachCurrentThread();
347 const int duration_ms =
348 Java_MediaPlayerBridge_getDuration(env, j_media_player_bridge_.obj());
349 return duration_ms < 0 ? media::kInfiniteDuration()
350 : base::TimeDelta::FromMilliseconds(duration_ms);
353 void MediaPlayerBridge::Release() {
354 if (j_media_player_bridge_.is_null())
355 return;
357 SetAudible(false);
359 time_update_timer_.Stop();
360 if (prepared_) {
361 pending_seek_ = GetCurrentTime();
362 should_seek_on_prepare_ = true;
365 prepared_ = false;
366 pending_play_ = false;
367 SetVideoSurface(gfx::ScopedJavaSurface());
368 JNIEnv* env = base::android::AttachCurrentThread();
369 Java_MediaPlayerBridge_release(env, j_media_player_bridge_.obj());
370 j_media_player_bridge_.Reset();
371 DetachListener();
374 void MediaPlayerBridge::SetVolume(double volume) {
375 volume_ = volume;
377 if (j_media_player_bridge_.is_null())
378 return;
380 JNIEnv* env = base::android::AttachCurrentThread();
381 CHECK(env);
383 // Update the audible state if we are playing.
384 jboolean is_playing = Java_MediaPlayerBridge_isPlaying(
385 env, j_media_player_bridge_.obj());
386 if (is_playing)
387 SetAudible(volume_ > 0);
389 Java_MediaPlayerBridge_setVolume(
390 env, j_media_player_bridge_.obj(), volume_);
393 void MediaPlayerBridge::OnVideoSizeChanged(int width, int height) {
394 width_ = width;
395 height_ = height;
396 MediaPlayerAndroid::OnVideoSizeChanged(width, height);
399 void MediaPlayerBridge::OnPlaybackComplete() {
400 SetAudible(false);
401 time_update_timer_.Stop();
402 MediaPlayerAndroid::OnPlaybackComplete();
405 void MediaPlayerBridge::OnMediaInterrupted() {
406 SetAudible(false);
407 time_update_timer_.Stop();
408 MediaPlayerAndroid::OnMediaInterrupted();
411 void MediaPlayerBridge::OnMediaPrepared() {
412 if (j_media_player_bridge_.is_null())
413 return;
415 prepared_ = true;
416 duration_ = GetDuration();
418 // If media player was recovered from a saved state, consume all the pending
419 // events.
420 if (should_seek_on_prepare_) {
421 PendingSeekInternal(pending_seek_);
422 pending_seek_ = base::TimeDelta::FromMilliseconds(0);
423 should_seek_on_prepare_ = false;
426 if (pending_play_) {
427 StartInternal();
428 pending_play_ = false;
431 UpdateAllowedOperations();
432 manager()->OnMediaMetadataChanged(
433 player_id(), duration_, width_, height_, true);
436 ScopedJavaLocalRef<jobject> MediaPlayerBridge::GetAllowedOperations() {
437 JNIEnv* env = base::android::AttachCurrentThread();
438 CHECK(env);
440 return Java_MediaPlayerBridge_getAllowedOperations(
441 env, j_media_player_bridge_.obj());
444 void MediaPlayerBridge::UpdateAllowedOperations() {
445 JNIEnv* env = base::android::AttachCurrentThread();
446 CHECK(env);
448 ScopedJavaLocalRef<jobject> allowedOperations = GetAllowedOperations();
450 can_pause_ = Java_AllowedOperations_canPause(env, allowedOperations.obj());
451 can_seek_forward_ = Java_AllowedOperations_canSeekForward(
452 env, allowedOperations.obj());
453 can_seek_backward_ = Java_AllowedOperations_canSeekBackward(
454 env, allowedOperations.obj());
457 void MediaPlayerBridge::StartInternal() {
458 if (!manager()->RequestPlay(player_id())) {
459 Pause(true);
460 return;
463 JNIEnv* env = base::android::AttachCurrentThread();
464 Java_MediaPlayerBridge_start(env, j_media_player_bridge_.obj());
465 if (!time_update_timer_.IsRunning()) {
466 time_update_timer_.Start(
467 FROM_HERE,
468 base::TimeDelta::FromMilliseconds(kTimeUpdateInterval),
469 this, &MediaPlayerBridge::OnTimeUpdateTimerFired);
472 SetAudible(volume_ > 0);
475 void MediaPlayerBridge::PauseInternal() {
476 SetAudible(false);
478 JNIEnv* env = base::android::AttachCurrentThread();
479 Java_MediaPlayerBridge_pause(env, j_media_player_bridge_.obj());
480 time_update_timer_.Stop();
483 void MediaPlayerBridge::PendingSeekInternal(const base::TimeDelta& time) {
484 SeekInternal(time);
487 void MediaPlayerBridge::SeekInternal(base::TimeDelta time) {
488 if (time > duration_)
489 time = duration_;
491 // Seeking to an invalid position may cause media player to stuck in an
492 // error state.
493 if (time < base::TimeDelta()) {
494 DCHECK_EQ(-1.0, time.InMillisecondsF());
495 return;
498 JNIEnv* env = base::android::AttachCurrentThread();
499 CHECK(env);
500 int time_msec = static_cast<int>(time.InMilliseconds());
501 Java_MediaPlayerBridge_seekTo(
502 env, j_media_player_bridge_.obj(), time_msec);
505 void MediaPlayerBridge::OnTimeUpdateTimerFired() {
506 manager()->OnTimeUpdate(
507 player_id(), GetCurrentTime(), base::TimeTicks::Now());
510 bool MediaPlayerBridge::RegisterMediaPlayerBridge(JNIEnv* env) {
511 return RegisterNativesImpl(env);
514 bool MediaPlayerBridge::CanPause() {
515 return can_pause_;
518 bool MediaPlayerBridge::CanSeekForward() {
519 return can_seek_forward_;
522 bool MediaPlayerBridge::CanSeekBackward() {
523 return can_seek_backward_;
526 bool MediaPlayerBridge::IsPlayerReady() {
527 return prepared_;
530 GURL MediaPlayerBridge::GetUrl() {
531 return url_;
534 GURL MediaPlayerBridge::GetFirstPartyForCookies() {
535 return first_party_for_cookies_;
538 } // namespace media