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