- add sources.
[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 "jni/MediaPlayerBridge_jni.h"
13 #include "media/base/android/media_player_manager.h"
14 #include "media/base/android/media_resource_getter.h"
15
16 using base::android::ConvertUTF8ToJavaString;
17 using base::android::ScopedJavaLocalRef;
18
19 // Time update happens every 250ms.
20 static const int kTimeUpdateInterval = 250;
21
22 namespace media {
23
24 MediaPlayerBridge::MediaPlayerBridge(
25     int player_id,
26     const GURL& url,
27     const GURL& first_party_for_cookies,
28     bool hide_url_log,
29     MediaPlayerManager* manager)
30     : MediaPlayerAndroid(player_id,
31                          manager),
32       prepared_(false),
33       pending_play_(false),
34       url_(url),
35       first_party_for_cookies_(first_party_for_cookies),
36       hide_url_log_(hide_url_log),
37       width_(0),
38       height_(0),
39       can_pause_(true),
40       can_seek_forward_(true),
41       can_seek_backward_(true),
42       weak_this_(this),
43       listener_(base::MessageLoopProxy::current(),
44                 weak_this_.GetWeakPtr()) {
45 }
46
47 MediaPlayerBridge::~MediaPlayerBridge() {
48   Release();
49 }
50
51 void MediaPlayerBridge::Initialize() {
52   if (url_.SchemeIsFile()) {
53     cookies_.clear();
54     ExtractMediaMetadata(url_.spec());
55     return;
56   }
57
58   media::MediaResourceGetter* resource_getter =
59       manager()->GetMediaResourceGetter();
60   if (url_.SchemeIsFileSystem()) {
61     cookies_.clear();
62     resource_getter->GetPlatformPathFromFileSystemURL(url_, base::Bind(
63         &MediaPlayerBridge::ExtractMediaMetadata, weak_this_.GetWeakPtr()));
64     return;
65   }
66
67   resource_getter->GetCookies(url_, first_party_for_cookies_, base::Bind(
68       &MediaPlayerBridge::OnCookiesRetrieved, weak_this_.GetWeakPtr()));
69 }
70
71 void MediaPlayerBridge::CreateJavaMediaPlayerBridge() {
72   JNIEnv* env = base::android::AttachCurrentThread();
73   CHECK(env);
74
75   j_media_player_bridge_.Reset(Java_MediaPlayerBridge_create(env));
76
77   SetMediaPlayerListener();
78 }
79
80 void MediaPlayerBridge::SetJavaMediaPlayerBridge(
81     jobject j_media_player_bridge) {
82   JNIEnv* env = base::android::AttachCurrentThread();
83   CHECK(env);
84
85   j_media_player_bridge_.Reset(env, j_media_player_bridge);
86 }
87
88 base::android::ScopedJavaLocalRef<jobject> MediaPlayerBridge::
89     GetJavaMediaPlayerBridge() {
90   base::android::ScopedJavaLocalRef<jobject> j_bridge(
91       j_media_player_bridge_);
92   return j_bridge;
93 }
94
95 void MediaPlayerBridge::SetMediaPlayerListener() {
96   jobject j_context = base::android::GetApplicationContext();
97   DCHECK(j_context);
98
99   listener_.CreateMediaPlayerListener(j_context, j_media_player_bridge_.obj());
100 }
101
102 void MediaPlayerBridge::SetDuration(base::TimeDelta duration) {
103   duration_ = duration;
104 }
105
106 void MediaPlayerBridge::SetVideoSurface(gfx::ScopedJavaSurface surface) {
107   if (j_media_player_bridge_.is_null()) {
108     if (surface.IsEmpty())
109       return;
110     Prepare();
111   }
112
113   JNIEnv* env = base::android::AttachCurrentThread();
114   CHECK(env);
115
116   Java_MediaPlayerBridge_setSurface(
117       env, j_media_player_bridge_.obj(), surface.j_surface().obj());
118 }
119
120 void MediaPlayerBridge::Prepare() {
121   if (j_media_player_bridge_.is_null())
122     CreateJavaMediaPlayerBridge();
123   if (url_.SchemeIsFileSystem()) {
124     manager()->GetMediaResourceGetter()->GetPlatformPathFromFileSystemURL(
125             url_, base::Bind(&MediaPlayerBridge::SetDataSource,
126                              weak_this_.GetWeakPtr()));
127   } else {
128     SetDataSource(url_.spec());
129   }
130 }
131
132 void MediaPlayerBridge::SetDataSource(const std::string& url) {
133   if (j_media_player_bridge_.is_null())
134     return;
135
136   JNIEnv* env = base::android::AttachCurrentThread();
137   CHECK(env);
138
139   // Create a Java String for the URL.
140   ScopedJavaLocalRef<jstring> j_url_string = ConvertUTF8ToJavaString(env, url);
141   ScopedJavaLocalRef<jstring> j_cookies = ConvertUTF8ToJavaString(
142       env, cookies_);
143
144   jobject j_context = base::android::GetApplicationContext();
145   DCHECK(j_context);
146
147   if (Java_MediaPlayerBridge_setDataSource(
148       env, j_media_player_bridge_.obj(), j_context, j_url_string.obj(),
149       j_cookies.obj(), hide_url_log_)) {
150     manager()->RequestMediaResources(player_id());
151     Java_MediaPlayerBridge_prepareAsync(
152         env, j_media_player_bridge_.obj());
153   } else {
154     OnMediaError(MEDIA_ERROR_FORMAT);
155   }
156 }
157
158 void MediaPlayerBridge::OnCookiesRetrieved(const std::string& cookies) {
159   cookies_ = cookies;
160   ExtractMediaMetadata(url_.spec());
161 }
162
163 void MediaPlayerBridge::ExtractMediaMetadata(const std::string& url) {
164   manager()->GetMediaResourceGetter()->ExtractMediaMetadata(
165       url, cookies_, base::Bind(&MediaPlayerBridge::OnMediaMetadataExtracted,
166                                 weak_this_.GetWeakPtr()));
167 }
168
169 void MediaPlayerBridge::OnMediaMetadataExtracted(
170     base::TimeDelta duration, int width, int height, bool success) {
171   if (success) {
172     duration_ = duration;
173     width_ = width;
174     height_ = height;
175   }
176   manager()->OnMediaMetadataChanged(
177       player_id(), duration_, width_, height_, success);
178 }
179
180 void MediaPlayerBridge::Start() {
181   if (j_media_player_bridge_.is_null()) {
182     pending_play_ = true;
183     Prepare();
184   } else {
185     if (prepared_)
186       StartInternal();
187     else
188       pending_play_ = true;
189   }
190 }
191
192 void MediaPlayerBridge::Pause(bool is_media_related_action) {
193   if (j_media_player_bridge_.is_null()) {
194     pending_play_ = false;
195   } else {
196     if (prepared_ && IsPlaying())
197       PauseInternal();
198     else
199       pending_play_ = false;
200   }
201 }
202
203 bool MediaPlayerBridge::IsPlaying() {
204   if (!prepared_)
205     return pending_play_;
206
207   JNIEnv* env = base::android::AttachCurrentThread();
208   CHECK(env);
209   jboolean result = Java_MediaPlayerBridge_isPlaying(
210       env, j_media_player_bridge_.obj());
211   return result;
212 }
213
214 int MediaPlayerBridge::GetVideoWidth() {
215   if (!prepared_)
216     return width_;
217   JNIEnv* env = base::android::AttachCurrentThread();
218   return Java_MediaPlayerBridge_getVideoWidth(
219       env, j_media_player_bridge_.obj());
220 }
221
222 int MediaPlayerBridge::GetVideoHeight() {
223   if (!prepared_)
224     return height_;
225   JNIEnv* env = base::android::AttachCurrentThread();
226   return Java_MediaPlayerBridge_getVideoHeight(
227       env, j_media_player_bridge_.obj());
228 }
229
230 void MediaPlayerBridge::SeekTo(const base::TimeDelta& timestamp) {
231   // Record the time to seek when OnMediaPrepared() is called.
232   pending_seek_ = timestamp;
233
234   if (j_media_player_bridge_.is_null())
235     Prepare();
236   else if (prepared_)
237     SeekInternal(timestamp);
238 }
239
240 base::TimeDelta MediaPlayerBridge::GetCurrentTime() {
241   if (!prepared_)
242     return pending_seek_;
243   JNIEnv* env = base::android::AttachCurrentThread();
244   return base::TimeDelta::FromMilliseconds(
245       Java_MediaPlayerBridge_getCurrentPosition(
246           env, j_media_player_bridge_.obj()));
247 }
248
249 base::TimeDelta MediaPlayerBridge::GetDuration() {
250   if (!prepared_)
251     return duration_;
252   JNIEnv* env = base::android::AttachCurrentThread();
253   return base::TimeDelta::FromMilliseconds(
254       Java_MediaPlayerBridge_getDuration(
255           env, j_media_player_bridge_.obj()));
256 }
257
258 void MediaPlayerBridge::Release() {
259   if (j_media_player_bridge_.is_null())
260     return;
261
262   time_update_timer_.Stop();
263   if (prepared_)
264     pending_seek_ = GetCurrentTime();
265   prepared_ = false;
266   pending_play_ = false;
267   SetVideoSurface(gfx::ScopedJavaSurface());
268
269   JNIEnv* env = base::android::AttachCurrentThread();
270   Java_MediaPlayerBridge_release(env, j_media_player_bridge_.obj());
271   j_media_player_bridge_.Reset();
272   manager()->ReleaseMediaResources(player_id());
273   listener_.ReleaseMediaPlayerListenerResources();
274 }
275
276 void MediaPlayerBridge::SetVolume(double volume) {
277   if (j_media_player_bridge_.is_null())
278     return;
279
280   JNIEnv* env = base::android::AttachCurrentThread();
281   CHECK(env);
282   Java_MediaPlayerBridge_setVolume(
283       env, j_media_player_bridge_.obj(), volume);
284 }
285
286 void MediaPlayerBridge::OnVideoSizeChanged(int width, int height) {
287   width_ = width;
288   height_ = height;
289   manager()->OnVideoSizeChanged(player_id(), width, height);
290 }
291
292 void MediaPlayerBridge::OnMediaError(int error_type) {
293   manager()->OnError(player_id(), error_type);
294 }
295
296 void MediaPlayerBridge::OnBufferingUpdate(int percent) {
297   manager()->OnBufferingUpdate(player_id(), percent);
298 }
299
300 void MediaPlayerBridge::OnPlaybackComplete() {
301   time_update_timer_.Stop();
302   manager()->OnPlaybackComplete(player_id());
303 }
304
305 void MediaPlayerBridge::OnMediaInterrupted() {
306   time_update_timer_.Stop();
307   manager()->OnMediaInterrupted(player_id());
308 }
309
310 void MediaPlayerBridge::OnSeekComplete() {
311   manager()->OnSeekComplete(player_id(), GetCurrentTime());
312 }
313
314 void MediaPlayerBridge::OnMediaPrepared() {
315   if (j_media_player_bridge_.is_null())
316     return;
317
318   prepared_ = true;
319   duration_ = GetDuration();
320
321   // If media player was recovered from a saved state, consume all the pending
322   // events.
323   PendingSeekInternal(pending_seek_);
324
325   if (pending_play_) {
326     StartInternal();
327     pending_play_ = false;
328   }
329
330   UpdateAllowedOperations();
331   manager()->OnMediaMetadataChanged(
332       player_id(), duration_, width_, height_, true);
333 }
334
335 ScopedJavaLocalRef<jobject> MediaPlayerBridge::GetAllowedOperations() {
336   JNIEnv* env = base::android::AttachCurrentThread();
337   CHECK(env);
338
339   return Java_MediaPlayerBridge_getAllowedOperations(
340       env, j_media_player_bridge_.obj());
341 }
342
343 void MediaPlayerBridge::UpdateAllowedOperations() {
344   JNIEnv* env = base::android::AttachCurrentThread();
345   CHECK(env);
346
347   ScopedJavaLocalRef<jobject> allowedOperations = GetAllowedOperations();
348
349   can_pause_ = Java_AllowedOperations_canPause(env, allowedOperations.obj());
350   can_seek_forward_ = Java_AllowedOperations_canSeekForward(
351       env, allowedOperations.obj());
352   can_seek_backward_ = Java_AllowedOperations_canSeekBackward(
353       env, allowedOperations.obj());
354 }
355
356 void MediaPlayerBridge::StartInternal() {
357   JNIEnv* env = base::android::AttachCurrentThread();
358   Java_MediaPlayerBridge_start(env, j_media_player_bridge_.obj());
359   if (!time_update_timer_.IsRunning()) {
360     time_update_timer_.Start(
361         FROM_HERE,
362         base::TimeDelta::FromMilliseconds(kTimeUpdateInterval),
363         this, &MediaPlayerBridge::OnTimeUpdateTimerFired);
364   }
365 }
366
367 void MediaPlayerBridge::PauseInternal() {
368   JNIEnv* env = base::android::AttachCurrentThread();
369   Java_MediaPlayerBridge_pause(env, j_media_player_bridge_.obj());
370   time_update_timer_.Stop();
371 }
372
373 void MediaPlayerBridge::PendingSeekInternal(const base::TimeDelta& time) {
374   SeekInternal(time);
375 }
376
377 void MediaPlayerBridge::SeekInternal(base::TimeDelta time) {
378   if (time > duration_)
379     time = duration_;
380
381   // Seeking to an invalid position may cause media player to stuck in an
382   // error state.
383   if (time < base::TimeDelta()) {
384     DCHECK_EQ(-1.0, time.InMillisecondsF());
385     return;
386   }
387
388   JNIEnv* env = base::android::AttachCurrentThread();
389   CHECK(env);
390   int time_msec = static_cast<int>(time.InMilliseconds());
391   Java_MediaPlayerBridge_seekTo(
392       env, j_media_player_bridge_.obj(), time_msec);
393 }
394
395 void MediaPlayerBridge::OnTimeUpdateTimerFired() {
396   manager()->OnTimeUpdate(player_id(), GetCurrentTime());
397 }
398
399 bool MediaPlayerBridge::RegisterMediaPlayerBridge(JNIEnv* env) {
400   bool ret = RegisterNativesImpl(env);
401   DCHECK(g_MediaPlayerBridge_clazz);
402   return ret;
403 }
404
405 bool MediaPlayerBridge::CanPause() {
406   return can_pause_;
407 }
408
409 bool MediaPlayerBridge::CanSeekForward() {
410   return can_seek_forward_;
411 }
412
413 bool MediaPlayerBridge::CanSeekBackward() {
414   return can_seek_backward_;
415 }
416
417 bool MediaPlayerBridge::IsPlayerReady() {
418   return prepared_;
419 }
420
421 GURL MediaPlayerBridge::GetUrl() {
422   return url_;
423 }
424
425 GURL MediaPlayerBridge::GetFirstPartyForCookies() {
426   return first_party_for_cookies_;
427 }
428
429 }  // namespace media