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

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

Powered by Google App Engine
This is Rietveld 408576698