Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(986)

Side by Side Diff: chrome/browser/media/android/remote/remote_media_player_bridge.cc

Issue 928643003: Upstream Chrome for Android Cast. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix dependencies (second attempt). Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 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 "chrome/browser/media/android/remote/remote_media_player_bridge.h"
6
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "chrome/browser/media/android/remote/record_cast_action.h"
10 #include "chrome/browser/media/android/remote/remote_media_player_manager.h"
11 #include "content/browser/android/content_view_core_impl.h"
12 #include "jni/RemoteMediaPlayerBridge_jni.h"
13 #include "media/base/android/media_common_android.h"
14 #include "media/base/android/media_resource_getter.h"
15 #include "third_party/skia/include/core/SkBitmap.h"
16 #include "ui/gfx/android/java_bitmap.h"
17
18 using base::android::ConvertUTF8ToJavaString;
19 using base::android::ScopedJavaLocalRef;
20 using base::android::AttachCurrentThread;
21
22 namespace {
23 /*
24 * Dummy function for RequestMediaResources callback. The callback is never
25 * actually called by MediaPlayerAndroid or RemoteMediaPlayer but is needed
26 * to compile the constructor call.
27 */
28 void DoNothing(int /*i*/) {}
29 }
30
31 namespace remote_media {
32
33 RemoteMediaPlayerBridge::RemoteMediaPlayerBridge(
34 MediaPlayerAndroid* local_player, const std::string& user_agent,
35 bool hide_url_log, RemoteMediaPlayerManager* manager)
36 : MediaPlayerAndroid(local_player->player_id(), manager,
37 base::Bind(&DoNothing),
38 local_player->frame_url()),
39 start_position_millis_(0),
40 local_player_(local_player),
41 in_use_(false),
42 prepared_(false),
43 pending_play_(false),
44 width_(0),
45 height_(0),
46 should_seek_on_prepare_(false),
47 hide_url_log_(hide_url_log),
48 volume_(-1.0),
49 url_(local_player->GetUrl()),
50 first_party_for_cookies_(local_player->GetFirstPartyForCookies()),
51 user_agent_(user_agent),
52 weak_factory_(this) {
53 if (local_player->GetCurrentTime().InMilliseconds() > 0)
54 start_position_millis_ = local_player->GetCurrentTime().InMilliseconds();
55 JNIEnv* env = base::android::AttachCurrentThread();
56 CHECK(env);
57 ScopedJavaLocalRef<jstring> j_url_string;
58 if (url_.is_valid()) {
59 // Create a Java String for the URL.
60 j_url_string = ConvertUTF8ToJavaString(env, url_.spec());
61 }
62 ScopedJavaLocalRef<jstring> j_frame_url_string;
63 if (local_player->frame_url().is_valid()) {
64 // Create a Java String for the URL.
65 j_frame_url_string = ConvertUTF8ToJavaString(
66 env, local_player->frame_url().spec());
67 }
68 java_bridge_.Reset(
69 Java_RemoteMediaPlayerBridge_create(env, reinterpret_cast<intptr_t>(this),
70 start_position_millis_,
71 j_url_string.obj(),
72 j_frame_url_string.obj()));
73 }
74
75 RemoteMediaPlayerBridge::~RemoteMediaPlayerBridge() {
76 JNIEnv* env = base::android::AttachCurrentThread();
77 CHECK(env);
78 Java_RemoteMediaPlayerBridge_destroy(env, java_bridge_.obj());
79 Release();
80 }
81
82 int RemoteMediaPlayerBridge::GetVideoWidth() {
83 return local_player_->GetVideoWidth();
84 }
85
86 int RemoteMediaPlayerBridge::GetVideoHeight() {
87 return local_player_->GetVideoHeight();
88 }
89
90 void RemoteMediaPlayerBridge::OnVideoSizeChanged(int width, int height) {
91 width_ = width;
92 height_ = height;
93 MediaPlayerAndroid::OnVideoSizeChanged(width, height);
94 }
95
96 void RemoteMediaPlayerBridge::OnPlaybackComplete() {
97 time_update_timer_.Stop();
98 MediaPlayerAndroid::OnPlaybackComplete();
99 }
100
101 void RemoteMediaPlayerBridge::OnMediaInterrupted() {}
102
103 void RemoteMediaPlayerBridge::OnMediaPrepared() {
104 if (!in_use_)
105 return;
106
107 prepared_ = true;
108 duration_ = GetDuration();
109
110 // If media player was recovered from a saved state, consume all the pending
111 // events.
112 if (should_seek_on_prepare_) {
113 PendingSeekInternal(pending_seek_);
114 pending_seek_ = base::TimeDelta::FromMilliseconds(0);
115 should_seek_on_prepare_ = false;
116 }
117
118 if (pending_play_) {
119 StartInternal();
120 pending_play_ = false;
121 }
122
123 manager()->OnMediaMetadataChanged(
124 player_id(), duration_, width_, height_, true);
125 }
126
127 void RemoteMediaPlayerBridge::StartInternal() {
128 JNIEnv* env = AttachCurrentThread();
129 Java_RemoteMediaPlayerBridge_start(env, java_bridge_.obj());
130 if (!time_update_timer_.IsRunning()) {
131 time_update_timer_.Start(
132 FROM_HERE,
133 base::TimeDelta::FromMilliseconds(media::kTimeUpdateInterval),
134 this, &RemoteMediaPlayerBridge::OnTimeUpdateTimerFired);
135 }
136 }
137
138 void RemoteMediaPlayerBridge::PauseInternal() {
139 JNIEnv* env = AttachCurrentThread();
140 Java_RemoteMediaPlayerBridge_pause(env, java_bridge_.obj());
141 time_update_timer_.Stop();
142 }
143
144 void RemoteMediaPlayerBridge::SeekInternal(base::TimeDelta time) {
145 if (time > duration_)
146 time = duration_;
147
148 // Seeking to an invalid position may cause media player to stuck in an
149 // error state.
150 if (time < base::TimeDelta()) {
151 DCHECK_EQ(-1.0, time.InMillisecondsF());
152 return;
153 }
154
155 JNIEnv* env = AttachCurrentThread();
156 CHECK(env);
157 int time_msec = static_cast<int>(time.InMilliseconds());
158 Java_RemoteMediaPlayerBridge_seekTo(
159 env, java_bridge_.obj(), time_msec);
160 }
161
162 void RemoteMediaPlayerBridge::OnTimeUpdateTimerFired() {
163 manager()->OnTimeUpdate(
164 player_id(), GetCurrentTime(), base::TimeTicks::Now());
165 }
166
167 void RemoteMediaPlayerBridge::PendingSeekInternal(const base::TimeDelta& time) {
168 SeekInternal(time);
169 }
170
171 void RemoteMediaPlayerBridge::Prepare() {
172 DCHECK(!in_use_);
173 DCHECK(IsMediaPlayableRemotely());
174 in_use_ = true;
175 AttachListener(java_bridge_.obj());
176 JNIEnv* env = AttachCurrentThread();
177 CHECK(env);
178
179 if (url_.is_valid()) {
180 // Create a Java String for the URL.
181 ScopedJavaLocalRef<jstring> j_url_string =
182 ConvertUTF8ToJavaString(env, url_.spec());
183
184 jobject j_context = base::android::GetApplicationContext();
185 DCHECK(j_context);
186
187 ScopedJavaLocalRef<jstring> j_cookies = ConvertUTF8ToJavaString(
188 env, cookies_);
189 ScopedJavaLocalRef<jstring> j_user_agent = ConvertUTF8ToJavaString(
190 env, user_agent_);
191
192 if (!Java_RemoteMediaPlayerBridge_setDataSource(
193 env, java_bridge_.obj(), j_context, j_url_string.obj(),
194 j_cookies.obj(), j_user_agent.obj(), hide_url_log_)) {
195 OnMediaError(MEDIA_ERROR_FORMAT);
196 return;
197 }
198 }
199
200 if (!Java_RemoteMediaPlayerBridge_prepareAsync(env, java_bridge_.obj()))
201 OnMediaError(MEDIA_ERROR_FORMAT);
202 }
203
204 void RemoteMediaPlayerBridge::Pause(bool is_media_related_action) {
205 // Ignore the pause if it's not from an event that is explicitly telling
206 // the video to pause. It's possible for Pause() to be called for other
207 // reasons, such as freeing resources, etc. and during those times, the
208 // remote video playback should not be paused.
209 if (is_media_related_action) {
210 if (!in_use_) {
211 pending_play_ = false;
212 } else {
213 if (prepared_ && IsPlaying())
214 PauseInternal();
215 else
216 pending_play_ = false;
217 }
218 }
219 }
220
221 void RemoteMediaPlayerBridge::SetVideoSurface(gfx::ScopedJavaSurface surface) {
222 // The surface is reset whenever the fullscreen view is destroyed or created.
223 // Since the remote player doesn't use it, we forward it to the local player
224 // for the time when user disconnects and resumes local playback
225 // (see crbug.com/420690).
226 local_player_->SetVideoSurface(surface.Pass());
227 }
228
229 base::android::ScopedJavaLocalRef<jstring> RemoteMediaPlayerBridge::GetFrameUrl(
230 JNIEnv* env, jobject obj) {
231 return ConvertUTF8ToJavaString(env, frame_url().spec());
232 }
233
234 void RemoteMediaPlayerBridge::OnPlaying(JNIEnv* env, jobject obj) {
235 static_cast<RemoteMediaPlayerManager *>(manager())->OnPlaying(player_id());
236 }
237
238 void RemoteMediaPlayerBridge::OnPaused(JNIEnv* env, jobject obj) {
239 static_cast<RemoteMediaPlayerManager *>(manager())->OnPaused(player_id());
240 }
241
242 void RemoteMediaPlayerBridge::OnRouteSelected(JNIEnv* env, jobject obj,
243 jstring castingMessage) {
244 casting_message_.reset(
245 new std::string(
246 base::android::ConvertJavaStringToUTF8(env, castingMessage)));
247 static_cast<RemoteMediaPlayerManager *>(manager())->OnRemoteDeviceSelected(
248 player_id());
249 }
250
251 void RemoteMediaPlayerBridge::OnRouteUnselected(JNIEnv* env, jobject obj) {
252 casting_message_.reset();
253 static_cast<RemoteMediaPlayerManager *>(manager())->OnRemoteDeviceUnselected(
254 player_id());
255 }
256
257 void RemoteMediaPlayerBridge::OnPlaybackFinished(JNIEnv* env, jobject obj) {
258 static_cast<RemoteMediaPlayerManager *>(manager())->OnRemotePlaybackFinished(
259 player_id());
260 }
261
262 void RemoteMediaPlayerBridge::OnRouteAvailabilityChanged(JNIEnv* env,
263 jobject obj,
264 jboolean available) {
265 static_cast<RemoteMediaPlayerManager *>(manager())->
266 OnRouteAvailabilityChanged(player_id(), available);
267 }
268
269 // static
270 bool RemoteMediaPlayerBridge::RegisterRemoteMediaPlayerBridge(JNIEnv* env) {
271 bool ret = RegisterNativesImpl(env);
272 DCHECK(g_RemoteMediaPlayerBridge_clazz);
273 return ret;
274 }
275
276 void RemoteMediaPlayerBridge::RequestRemotePlayback() {
277 JNIEnv* env = AttachCurrentThread();
278 CHECK(env);
279
280 Java_RemoteMediaPlayerBridge_requestRemotePlayback(
281 env, java_bridge_.obj());
282 }
283
284 void RemoteMediaPlayerBridge::RequestRemotePlaybackControl() {
285 JNIEnv* env = AttachCurrentThread();
286 CHECK(env);
287
288 Java_RemoteMediaPlayerBridge_requestRemotePlaybackControl(
289 env, java_bridge_.obj());
290 }
291
292 void RemoteMediaPlayerBridge::SetNativePlayer() {
293 JNIEnv* env = AttachCurrentThread();
294 CHECK(env);
295
296 Java_RemoteMediaPlayerBridge_setNativePlayer(
297 env, java_bridge_.obj());
298 }
299
300 void RemoteMediaPlayerBridge::OnPlayerCreated() {
301 JNIEnv* env = AttachCurrentThread();
302 CHECK(env);
303
304 Java_RemoteMediaPlayerBridge_onPlayerCreated(
305 env, java_bridge_.obj());
306 }
307
308 void RemoteMediaPlayerBridge::OnPlayerDestroyed() {
309 JNIEnv* env = AttachCurrentThread();
310 CHECK(env);
311
312 Java_RemoteMediaPlayerBridge_onPlayerDestroyed(
313 env, java_bridge_.obj());
314 }
315
316 bool RemoteMediaPlayerBridge::IsRemotePlaybackAvailable() const {
317 JNIEnv* env = AttachCurrentThread();
318 CHECK(env);
319
320 jboolean result = Java_RemoteMediaPlayerBridge_isRemotePlaybackAvailable(
321 env, java_bridge_.obj());
322
323 return result;
324 }
325
326 bool RemoteMediaPlayerBridge::IsRemotePlaybackPreferredForFrame() const {
327 if (in_use_) {
328 // We have already decided to use remote playback
329 return true;
330 }
331 JNIEnv* env = AttachCurrentThread();
332 CHECK(env);
333
334 jboolean result =
335 Java_RemoteMediaPlayerBridge_isRemotePlaybackPreferredForFrame(
336 env, java_bridge_.obj());
337 return result;
338 }
339
340 std::string RemoteMediaPlayerBridge::GetCastingMessage() {
341 return casting_message_ ?
342 *casting_message_ : std::string();
343 }
344
345 void RemoteMediaPlayerBridge::SetPosterBitmap(
346 const std::vector<SkBitmap>& bitmaps) {
347 JNIEnv* env = AttachCurrentThread();
348 CHECK(env);
349
350 if (bitmaps.empty()) {
351 Java_RemoteMediaPlayerBridge_setPosterBitmap(env, java_bridge_.obj(), NULL);
352 } else {
353 ScopedJavaLocalRef<jobject> j_poster_bitmap;
354 j_poster_bitmap = gfx::ConvertToJavaBitmap(&(bitmaps[0]));
355
356 Java_RemoteMediaPlayerBridge_setPosterBitmap(env, java_bridge_.obj(),
357 j_poster_bitmap.obj());
358 }
359 }
360
361 void RemoteMediaPlayerBridge::Start() {
362 if (!in_use_) {
363 pending_play_ = true;
364 Prepare();
365 } else {
366 if (prepared_)
367 StartInternal();
368 else
369 pending_play_ = true;
370 }
371 }
372
373 void RemoteMediaPlayerBridge::SeekTo(base::TimeDelta timestamp) {
374 // Record the time to seek when OnMediaPrepared() is called.
375 pending_seek_ = timestamp;
376 should_seek_on_prepare_ = true;
377
378 if (!in_use_)
379 Prepare();
380 else if (prepared_)
381 SeekInternal(timestamp);
382 }
383
384 void RemoteMediaPlayerBridge::Release() {
385 if (!in_use_)
386 return;
387 time_update_timer_.Stop();
388 if (prepared_) {
389 pending_seek_ = GetCurrentTime();
390 should_seek_on_prepare_ = true;
391 }
392
393 prepared_ = false;
394 pending_play_ = false;
395 JNIEnv* env = AttachCurrentThread();
396 Java_RemoteMediaPlayerBridge_release(env, java_bridge_.obj());
397 DetachListener();
398 in_use_ = false;
399 }
400
401 void RemoteMediaPlayerBridge::SetVolume(double volume) {
402 if (!in_use_) {
403 volume_ = volume;
404 return;
405 }
406
407 JNIEnv* env = AttachCurrentThread();
408 CHECK(env);
409 Java_RemoteMediaPlayerBridge_setVolume(
410 env, java_bridge_.obj(), volume);
411 }
412
413 base::TimeDelta RemoteMediaPlayerBridge::GetCurrentTime() {
414 if (!prepared_)
415 return pending_seek_;
416 JNIEnv* env = AttachCurrentThread();
417 return base::TimeDelta::FromMilliseconds(
418 Java_RemoteMediaPlayerBridge_getCurrentPosition(
419 env, java_bridge_.obj()));
420 }
421
422 base::TimeDelta RemoteMediaPlayerBridge::GetDuration() {
423 if (!prepared_)
424 return duration_;
425 JNIEnv* env = AttachCurrentThread();
426 const int duration_ms =
427 Java_RemoteMediaPlayerBridge_getDuration(env, java_bridge_.obj());
428 // Sometimes we can't get the duration remotely, but the local media player
429 // knows it.
430 // TODO (aberent) This is for YouTube. Remove it when the YouTube receiver is
431 // fixed.
432 if (duration_ms == 0) {
433 return local_player_->GetDuration();
434 }
435 return duration_ms < 0 ? media::kInfiniteDuration()
436 : base::TimeDelta::FromMilliseconds(duration_ms);
437 }
438
439 bool RemoteMediaPlayerBridge::IsPlaying() {
440 if (!prepared_)
441 return pending_play_;
442
443 JNIEnv* env = AttachCurrentThread();
444 CHECK(env);
445 jboolean result = Java_RemoteMediaPlayerBridge_isPlaying(
446 env, java_bridge_.obj());
447 return result;
448 }
449
450 bool RemoteMediaPlayerBridge::CanPause() {
451 return true;
452 }
453
454 bool RemoteMediaPlayerBridge::CanSeekForward() {
455 return true;
456 }
457
458 bool RemoteMediaPlayerBridge::CanSeekBackward() {
459 return true;
460 }
461
462 bool RemoteMediaPlayerBridge::IsPlayerReady() {
463 return prepared_;
464 }
465
466 GURL RemoteMediaPlayerBridge::GetUrl() {
467 return url_;
468 }
469
470 GURL RemoteMediaPlayerBridge::GetFirstPartyForCookies() {
471 return first_party_for_cookies_;
472 }
473
474 void RemoteMediaPlayerBridge::Initialize() {
475 cookies_.clear();
476 media::MediaResourceGetter* resource_getter =
477 manager()->GetMediaResourceGetter();
478 resource_getter->GetCookies(
479 url_, first_party_for_cookies_,
480 base::Bind(&RemoteMediaPlayerBridge::OnCookiesRetrieved,
481 weak_factory_.GetWeakPtr()));
482 }
483
484 bool RemoteMediaPlayerBridge::IsMediaPlayableRemotely() const {
485 JNIEnv* env = AttachCurrentThread();
486 CHECK(env);
487
488 return Java_RemoteMediaPlayerBridge_isMediaPlayableRemotely(
489 env, java_bridge_.obj());
490 }
491
492 base::android::ScopedJavaLocalRef<jstring> RemoteMediaPlayerBridge::GetTitle(
493 JNIEnv* env, jobject obj) {
494 base::string16 title;
495 content::ContentViewCoreImpl* core =
496 static_cast<RemoteMediaPlayerManager*>(manager())->GetContentViewCore();
497 if (core) {
498 content::WebContents* contents = core->GetWebContents();
499 if (contents) {
500 title = contents->GetTitle();
501 }
502 }
503 return base::android::ConvertUTF16ToJavaString(env, title);
504 }
505
506 void RemoteMediaPlayerBridge::OnCookiesRetrieved(const std::string& cookies) {
507 // TODO(aberent) Do we need to retrieve auth credentials for basic
508 // authentication? MediaPlayerBridge does.
509 cookies_ = cookies;
510 }
511
512 } // namespace remote_media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698