Upstream version 11.39.250.0
[platform/framework/web/crosswalk.git] / src / media / base / android / media_player_bridge.cc
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.
4
5 #include "media/base/android/media_player_bridge.h"
6
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 "base/strings/string_util.h"
13 #include "jni/MediaPlayerBridge_jni.h"
14 #include "media/base/android/media_common_android.h"
15 #include "media/base/android/media_player_manager.h"
16 #include "media/base/android/media_resource_getter.h"
17 #include "media/base/android/media_url_interceptor.h"
18
19 using base::android::ConvertUTF8ToJavaString;
20 using base::android::ScopedJavaLocalRef;
21
22 namespace media {
23
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) {
53 }
54
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());
60   }
61   Release();
62 }
63
64 void MediaPlayerBridge::Initialize() {
65   cookies_.clear();
66   if (url_.SchemeIsFile() || url_.SchemeIs("app")) {
67     ExtractMediaMetadata(url_.spec());
68     return;
69   }
70
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;
79   }
80
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;
86   }
87
88   resource_getter->GetCookies(url_,
89                               first_party_for_cookies_,
90                               base::Bind(&MediaPlayerBridge::OnCookiesRetrieved,
91                                          weak_factory_.GetWeakPtr()));
92 }
93
94 void MediaPlayerBridge::CreateJavaMediaPlayerBridge() {
95   JNIEnv* env = base::android::AttachCurrentThread();
96   CHECK(env);
97
98   j_media_player_bridge_.Reset(Java_MediaPlayerBridge_create(
99       env, reinterpret_cast<intptr_t>(this)));
100
101   if (volume_ >= 0)
102     SetVolume(volume_);
103
104   AttachListener(j_media_player_bridge_.obj());
105 }
106
107 void MediaPlayerBridge::SetJavaMediaPlayerBridge(
108     jobject j_media_player_bridge) {
109   JNIEnv* env = base::android::AttachCurrentThread();
110   CHECK(env);
111
112   j_media_player_bridge_.Reset(env, j_media_player_bridge);
113 }
114
115 base::android::ScopedJavaLocalRef<jobject> MediaPlayerBridge::
116     GetJavaMediaPlayerBridge() {
117   base::android::ScopedJavaLocalRef<jobject> j_bridge(
118       j_media_player_bridge_);
119   return j_bridge;
120 }
121
122 void MediaPlayerBridge::SetDuration(base::TimeDelta duration) {
123   duration_ = duration;
124 }
125
126 void MediaPlayerBridge::SetVideoSurface(gfx::ScopedJavaSurface surface) {
127   if (j_media_player_bridge_.is_null()) {
128     if (surface.IsEmpty())
129       return;
130     Prepare();
131   }
132
133   JNIEnv* env = base::android::AttachCurrentThread();
134   CHECK(env);
135   Java_MediaPlayerBridge_setSurface(
136       env, j_media_player_bridge_.obj(), surface.j_surface().obj());
137 }
138
139 void MediaPlayerBridge::Prepare() {
140   DCHECK(j_media_player_bridge_.is_null());
141   CreateJavaMediaPlayerBridge();
142   if (url_.SchemeIsFileSystem() || url_.SchemeIsBlob()) {
143     manager()->GetMediaResourceGetter()->GetPlatformPathFromURL(
144         url_,
145         base::Bind(&MediaPlayerBridge::SetDataSource,
146                    weak_factory_.GetWeakPtr()));
147     return;
148   }
149
150   SetDataSource(url_.spec());
151 }
152
153 void MediaPlayerBridge::SetDataSource(const std::string& url) {
154   if (j_media_player_bridge_.is_null())
155     return;
156
157   JNIEnv* env = base::android::AttachCurrentThread();
158   CHECK(env);
159
160   int fd;
161   int64 offset;
162   int64 size;
163   if (InterceptMediaUrl(url, &fd, &offset, &size)) {
164     if (!Java_MediaPlayerBridge_setDataSourceFromFd(
165         env, j_media_player_bridge_.obj(), fd, offset, size)) {
166       OnMediaError(MEDIA_ERROR_FORMAT);
167       return;
168     }
169   } else {
170     // Create a Java String for the URL.
171     ScopedJavaLocalRef<jstring> j_url_string =
172         ConvertUTF8ToJavaString(env, url);
173
174     jobject j_context = base::android::GetApplicationContext();
175     DCHECK(j_context);
176
177     const std::string data_uri_prefix("data:");
178     if (StartsWithASCII(url, data_uri_prefix, true)) {
179       if (!Java_MediaPlayerBridge_setDataUriDataSource(
180           env, j_media_player_bridge_.obj(), j_context, j_url_string.obj())) {
181         OnMediaError(MEDIA_ERROR_FORMAT);
182       }
183       return;
184     }
185
186     ScopedJavaLocalRef<jstring> j_cookies = ConvertUTF8ToJavaString(
187         env, cookies_);
188     ScopedJavaLocalRef<jstring> j_user_agent = ConvertUTF8ToJavaString(
189         env, user_agent_);
190
191     if (!Java_MediaPlayerBridge_setDataSource(
192         env, j_media_player_bridge_.obj(), j_context, j_url_string.obj(),
193         j_cookies.obj(), j_user_agent.obj(), hide_url_log_)) {
194       OnMediaError(MEDIA_ERROR_FORMAT);
195       return;
196     }
197   }
198
199   request_media_resources_cb_.Run(player_id());
200   if (!Java_MediaPlayerBridge_prepareAsync(env, j_media_player_bridge_.obj()))
201     OnMediaError(MEDIA_ERROR_FORMAT);
202 }
203
204 bool MediaPlayerBridge::InterceptMediaUrl(
205     const std::string& url, int* fd, int64* offset, int64* size) {
206   // Sentinel value to check whether the output arguments have been set.
207   const int kUnsetValue = -1;
208
209   *fd = kUnsetValue;
210   *offset = kUnsetValue;
211   *size = kUnsetValue;
212   media::MediaUrlInterceptor* url_interceptor =
213       manager()->GetMediaUrlInterceptor();
214   if (url_interceptor && url_interceptor->Intercept(url, fd, offset, size)) {
215     DCHECK_NE(kUnsetValue, *fd);
216     DCHECK_NE(kUnsetValue, *offset);
217     DCHECK_NE(kUnsetValue, *size);
218     return true;
219   }
220   return false;
221 }
222
223 void MediaPlayerBridge::OnDidSetDataUriDataSource(JNIEnv* env, jobject obj,
224     jboolean success) {
225   if (!success) {
226     OnMediaError(MEDIA_ERROR_FORMAT);
227     return;
228   }
229
230   request_media_resources_cb_.Run(player_id());
231   if (!Java_MediaPlayerBridge_prepareAsync(env, j_media_player_bridge_.obj()))
232     OnMediaError(MEDIA_ERROR_FORMAT);
233 }
234
235 void MediaPlayerBridge::OnCookiesRetrieved(const std::string& cookies) {
236   cookies_ = cookies;
237   manager()->GetMediaResourceGetter()->GetAuthCredentials(
238       url_,
239       base::Bind(&MediaPlayerBridge::OnAuthCredentialsRetrieved,
240                  weak_factory_.GetWeakPtr()));
241 }
242
243 void MediaPlayerBridge::OnAuthCredentialsRetrieved(
244     const base::string16& username, const base::string16& password) {
245   GURL::ReplacementsW replacements;
246   if (!username.empty()) {
247     replacements.SetUsernameStr(username);
248     if (!password.empty())
249       replacements.SetPasswordStr(password);
250     url_ = url_.ReplaceComponents(replacements);
251   }
252   ExtractMediaMetadata(url_.spec());
253 }
254
255 void MediaPlayerBridge::ExtractMediaMetadata(const std::string& url) {
256   if (url.empty()) {
257     OnMediaError(MEDIA_ERROR_FORMAT);
258     return;
259   }
260
261   int fd;
262   int64 offset;
263   int64 size;
264   if (InterceptMediaUrl(url, &fd, &offset, &size)) {
265     manager()->GetMediaResourceGetter()->ExtractMediaMetadata(
266         fd, offset, size,
267         base::Bind(&MediaPlayerBridge::OnMediaMetadataExtracted,
268                    weak_factory_.GetWeakPtr()));
269   } else {
270     manager()->GetMediaResourceGetter()->ExtractMediaMetadata(
271         url, cookies_, user_agent_,
272         base::Bind(&MediaPlayerBridge::OnMediaMetadataExtracted,
273                    weak_factory_.GetWeakPtr()));
274   }
275 }
276
277 void MediaPlayerBridge::OnMediaMetadataExtracted(
278     base::TimeDelta duration, int width, int height, bool success) {
279   if (success) {
280     duration_ = duration;
281     width_ = width;
282     height_ = height;
283   }
284   manager()->OnMediaMetadataChanged(
285       player_id(), duration_, width_, height_, success);
286 }
287
288 void MediaPlayerBridge::Start() {
289   if (j_media_player_bridge_.is_null()) {
290     pending_play_ = true;
291     Prepare();
292   } else {
293     if (prepared_)
294       StartInternal();
295     else
296       pending_play_ = true;
297   }
298 }
299
300 void MediaPlayerBridge::Pause(bool is_media_related_action) {
301   if (j_media_player_bridge_.is_null()) {
302     pending_play_ = false;
303   } else {
304     if (prepared_ && IsPlaying())
305       PauseInternal();
306     else
307       pending_play_ = false;
308   }
309 }
310
311 bool MediaPlayerBridge::IsPlaying() {
312   if (!prepared_)
313     return pending_play_;
314
315   JNIEnv* env = base::android::AttachCurrentThread();
316   CHECK(env);
317   jboolean result = Java_MediaPlayerBridge_isPlaying(
318       env, j_media_player_bridge_.obj());
319   return result;
320 }
321
322 int MediaPlayerBridge::GetVideoWidth() {
323   if (!prepared_)
324     return width_;
325   JNIEnv* env = base::android::AttachCurrentThread();
326   return Java_MediaPlayerBridge_getVideoWidth(
327       env, j_media_player_bridge_.obj());
328 }
329
330 int MediaPlayerBridge::GetVideoHeight() {
331   if (!prepared_)
332     return height_;
333   JNIEnv* env = base::android::AttachCurrentThread();
334   return Java_MediaPlayerBridge_getVideoHeight(
335       env, j_media_player_bridge_.obj());
336 }
337
338 void MediaPlayerBridge::SeekTo(base::TimeDelta timestamp) {
339   // Record the time to seek when OnMediaPrepared() is called.
340   pending_seek_ = timestamp;
341   should_seek_on_prepare_ = true;
342
343   if (j_media_player_bridge_.is_null())
344     Prepare();
345   else if (prepared_)
346     SeekInternal(timestamp);
347 }
348
349 base::TimeDelta MediaPlayerBridge::GetCurrentTime() {
350   if (!prepared_)
351     return pending_seek_;
352   JNIEnv* env = base::android::AttachCurrentThread();
353   return base::TimeDelta::FromMilliseconds(
354       Java_MediaPlayerBridge_getCurrentPosition(
355           env, j_media_player_bridge_.obj()));
356 }
357
358 base::TimeDelta MediaPlayerBridge::GetDuration() {
359   if (!prepared_)
360     return duration_;
361   JNIEnv* env = base::android::AttachCurrentThread();
362   return base::TimeDelta::FromMilliseconds(
363       Java_MediaPlayerBridge_getDuration(
364           env, j_media_player_bridge_.obj()));
365 }
366
367 void MediaPlayerBridge::Release() {
368   if (j_media_player_bridge_.is_null())
369     return;
370
371   time_update_timer_.Stop();
372   if (prepared_) {
373     pending_seek_ = GetCurrentTime();
374     should_seek_on_prepare_ = true;
375   }
376
377   prepared_ = false;
378   pending_play_ = false;
379   SetVideoSurface(gfx::ScopedJavaSurface());
380   JNIEnv* env = base::android::AttachCurrentThread();
381   Java_MediaPlayerBridge_release(env, j_media_player_bridge_.obj());
382   j_media_player_bridge_.Reset();
383   DetachListener();
384 }
385
386 void MediaPlayerBridge::SetVolume(double volume) {
387   if (j_media_player_bridge_.is_null()) {
388     volume_ = volume;
389     return;
390   }
391
392   JNIEnv* env = base::android::AttachCurrentThread();
393   CHECK(env);
394   Java_MediaPlayerBridge_setVolume(
395       env, j_media_player_bridge_.obj(), volume);
396 }
397
398 void MediaPlayerBridge::OnVideoSizeChanged(int width, int height) {
399   width_ = width;
400   height_ = height;
401   MediaPlayerAndroid::OnVideoSizeChanged(width, height);
402 }
403
404 void MediaPlayerBridge::OnPlaybackComplete() {
405   time_update_timer_.Stop();
406   MediaPlayerAndroid::OnPlaybackComplete();
407 }
408
409 void MediaPlayerBridge::OnMediaInterrupted() {
410   time_update_timer_.Stop();
411   MediaPlayerAndroid::OnMediaInterrupted();
412 }
413
414 void MediaPlayerBridge::OnMediaPrepared() {
415   if (j_media_player_bridge_.is_null())
416     return;
417
418   prepared_ = true;
419   duration_ = GetDuration();
420
421   // If media player was recovered from a saved state, consume all the pending
422   // events.
423   if (should_seek_on_prepare_) {
424     PendingSeekInternal(pending_seek_);
425     pending_seek_ = base::TimeDelta::FromMilliseconds(0);
426     should_seek_on_prepare_ = false;
427   }
428
429   if (pending_play_) {
430     StartInternal();
431     pending_play_ = false;
432   }
433
434   UpdateAllowedOperations();
435   manager()->OnMediaMetadataChanged(
436       player_id(), duration_, width_, height_, true);
437 }
438
439 ScopedJavaLocalRef<jobject> MediaPlayerBridge::GetAllowedOperations() {
440   JNIEnv* env = base::android::AttachCurrentThread();
441   CHECK(env);
442
443   return Java_MediaPlayerBridge_getAllowedOperations(
444       env, j_media_player_bridge_.obj());
445 }
446
447 void MediaPlayerBridge::UpdateAllowedOperations() {
448   JNIEnv* env = base::android::AttachCurrentThread();
449   CHECK(env);
450
451   ScopedJavaLocalRef<jobject> allowedOperations = GetAllowedOperations();
452
453   can_pause_ = Java_AllowedOperations_canPause(env, allowedOperations.obj());
454   can_seek_forward_ = Java_AllowedOperations_canSeekForward(
455       env, allowedOperations.obj());
456   can_seek_backward_ = Java_AllowedOperations_canSeekBackward(
457       env, allowedOperations.obj());
458 }
459
460 void MediaPlayerBridge::StartInternal() {
461   JNIEnv* env = base::android::AttachCurrentThread();
462   Java_MediaPlayerBridge_start(env, j_media_player_bridge_.obj());
463   if (!time_update_timer_.IsRunning()) {
464     time_update_timer_.Start(
465         FROM_HERE,
466         base::TimeDelta::FromMilliseconds(kTimeUpdateInterval),
467         this, &MediaPlayerBridge::OnTimeUpdateTimerFired);
468   }
469 }
470
471 void MediaPlayerBridge::PauseInternal() {
472   JNIEnv* env = base::android::AttachCurrentThread();
473   Java_MediaPlayerBridge_pause(env, j_media_player_bridge_.obj());
474   time_update_timer_.Stop();
475 }
476
477 void MediaPlayerBridge::PendingSeekInternal(const base::TimeDelta& time) {
478   SeekInternal(time);
479 }
480
481 void MediaPlayerBridge::SeekInternal(base::TimeDelta time) {
482   if (time > duration_)
483     time = duration_;
484
485   // Seeking to an invalid position may cause media player to stuck in an
486   // error state.
487   if (time < base::TimeDelta()) {
488     DCHECK_EQ(-1.0, time.InMillisecondsF());
489     return;
490   }
491
492   JNIEnv* env = base::android::AttachCurrentThread();
493   CHECK(env);
494   int time_msec = static_cast<int>(time.InMilliseconds());
495   Java_MediaPlayerBridge_seekTo(
496       env, j_media_player_bridge_.obj(), time_msec);
497 }
498
499 void MediaPlayerBridge::OnTimeUpdateTimerFired() {
500   manager()->OnTimeUpdate(
501       player_id(), GetCurrentTime(), base::TimeTicks::Now());
502 }
503
504 bool MediaPlayerBridge::RegisterMediaPlayerBridge(JNIEnv* env) {
505   bool ret = RegisterNativesImpl(env);
506   DCHECK(g_MediaPlayerBridge_clazz);
507   return ret;
508 }
509
510 bool MediaPlayerBridge::CanPause() {
511   return can_pause_;
512 }
513
514 bool MediaPlayerBridge::CanSeekForward() {
515   return can_seek_forward_;
516 }
517
518 bool MediaPlayerBridge::CanSeekBackward() {
519   return can_seek_backward_;
520 }
521
522 bool MediaPlayerBridge::IsPlayerReady() {
523   return prepared_;
524 }
525
526 GURL MediaPlayerBridge::GetUrl() {
527   return url_;
528 }
529
530 GURL MediaPlayerBridge::GetFirstPartyForCookies() {
531   return first_party_for_cookies_;
532 }
533
534 }  // namespace media