| 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); |
| 59 ScopedJavaLocalRef<jstring> j_url_string; | 56 ScopedJavaLocalRef<jstring> j_url_string; |
| 60 if (url_.is_valid()) { | 57 if (url_.is_valid()) { |
| 61 // Create a Java String for the URL. | 58 // Create a Java String for the URL. |
| 62 j_url_string = ConvertUTF8ToJavaString(env, url_.spec()); | 59 j_url_string = ConvertUTF8ToJavaString(env, url_.spec()); |
| 63 } | 60 } |
| 64 ScopedJavaLocalRef<jstring> j_frame_url_string; | 61 ScopedJavaLocalRef<jstring> j_frame_url_string; |
| 65 if (local_player->frame_url().is_valid()) { | 62 if (local_player->frame_url().is_valid()) { |
| 66 // Create a Java String for the URL. | 63 // Create a Java String for the URL. |
| 67 j_frame_url_string = ConvertUTF8ToJavaString( | 64 j_frame_url_string = ConvertUTF8ToJavaString( |
| 68 env, local_player->frame_url().spec()); | 65 env, local_player->frame_url().spec()); |
| 69 } | 66 } |
| 70 java_bridge_.Reset( | 67 java_bridge_.Reset(Java_RemoteMediaPlayerBridge_create( |
| 71 Java_RemoteMediaPlayerBridge_create(env, reinterpret_cast<intptr_t>(this), | 68 env, reinterpret_cast<intptr_t>(this), start_position_millis_, |
| 72 start_position_millis_, | 69 j_url_string.obj(), j_frame_url_string.obj(), |
| 73 j_url_string.obj(), | 70 ConvertUTF8ToJavaString(env, user_agent).obj())); |
| 74 j_frame_url_string.obj())); | |
| 75 } | 71 } |
| 76 | 72 |
| 77 RemoteMediaPlayerBridge::~RemoteMediaPlayerBridge() { | 73 RemoteMediaPlayerBridge::~RemoteMediaPlayerBridge() { |
| 78 JNIEnv* env = base::android::AttachCurrentThread(); | 74 JNIEnv* env = base::android::AttachCurrentThread(); |
| 79 CHECK(env); | 75 CHECK(env); |
| 80 Java_RemoteMediaPlayerBridge_destroy(env, java_bridge_.obj()); | 76 Java_RemoteMediaPlayerBridge_destroy(env, java_bridge_.obj()); |
| 81 Release(); | 77 Release(); |
| 82 } | 78 } |
| 83 | 79 |
| 84 int RemoteMediaPlayerBridge::GetVideoWidth() { | 80 int RemoteMediaPlayerBridge::GetVideoWidth() { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 95 MediaPlayerAndroid::OnVideoSizeChanged(width, height); | 91 MediaPlayerAndroid::OnVideoSizeChanged(width, height); |
| 96 } | 92 } |
| 97 | 93 |
| 98 void RemoteMediaPlayerBridge::OnPlaybackComplete() { | 94 void RemoteMediaPlayerBridge::OnPlaybackComplete() { |
| 99 time_update_timer_.Stop(); | 95 time_update_timer_.Stop(); |
| 100 MediaPlayerAndroid::OnPlaybackComplete(); | 96 MediaPlayerAndroid::OnPlaybackComplete(); |
| 101 } | 97 } |
| 102 | 98 |
| 103 void RemoteMediaPlayerBridge::OnMediaInterrupted() {} | 99 void RemoteMediaPlayerBridge::OnMediaInterrupted() {} |
| 104 | 100 |
| 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() { | 101 void RemoteMediaPlayerBridge::StartInternal() { |
| 130 JNIEnv* env = AttachCurrentThread(); | 102 JNIEnv* env = AttachCurrentThread(); |
| 131 Java_RemoteMediaPlayerBridge_start(env, java_bridge_.obj()); | 103 Java_RemoteMediaPlayerBridge_start(env, java_bridge_.obj()); |
| 132 if (!time_update_timer_.IsRunning()) { | 104 if (!time_update_timer_.IsRunning()) { |
| 133 time_update_timer_.Start( | 105 time_update_timer_.Start( |
| 134 FROM_HERE, | 106 FROM_HERE, |
| 135 base::TimeDelta::FromMilliseconds(media::kTimeUpdateInterval), | 107 base::TimeDelta::FromMilliseconds(media::kTimeUpdateInterval), |
| 136 this, &RemoteMediaPlayerBridge::OnTimeUpdateTimerFired); | 108 this, &RemoteMediaPlayerBridge::OnTimeUpdateTimerFired); |
| 137 } | 109 } |
| 138 } | 110 } |
| 139 | 111 |
| 140 void RemoteMediaPlayerBridge::PauseInternal() { | 112 void RemoteMediaPlayerBridge::PauseInternal() { |
| 141 JNIEnv* env = AttachCurrentThread(); | 113 JNIEnv* env = AttachCurrentThread(); |
| 142 Java_RemoteMediaPlayerBridge_pause(env, java_bridge_.obj()); | 114 Java_RemoteMediaPlayerBridge_pause(env, java_bridge_.obj()); |
| 143 time_update_timer_.Stop(); | 115 time_update_timer_.Stop(); |
| 144 } | 116 } |
| 145 | 117 |
| 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() { | 118 void RemoteMediaPlayerBridge::OnTimeUpdateTimerFired() { |
| 165 manager()->OnTimeUpdate( | 119 manager()->OnTimeUpdate( |
| 166 player_id(), GetCurrentTime(), base::TimeTicks::Now()); | 120 player_id(), GetCurrentTime(), base::TimeTicks::Now()); |
| 167 } | 121 } |
| 168 | 122 |
| 169 void RemoteMediaPlayerBridge::PendingSeekInternal(const base::TimeDelta& time) { | 123 void RemoteMediaPlayerBridge::PauseLocal(JNIEnv* env, jobject obj) { |
| 170 SeekInternal(time); | 124 local_player_->Pause(true); |
| 125 static_cast<RemoteMediaPlayerManager*>(manager())->OnPaused(player_id()); |
| 171 } | 126 } |
| 172 | 127 |
| 173 void RemoteMediaPlayerBridge::Prepare() { | 128 jint RemoteMediaPlayerBridge::GetLocalPosition(JNIEnv* env, jobject obj) { |
| 174 DCHECK(!in_use_); | 129 base::TimeDelta time = local_player_->GetCurrentTime(); |
| 175 DCHECK(IsMediaPlayableRemotely()); | 130 return static_cast<jint>(time.InMilliseconds()); |
| 176 in_use_ = true; | 131 } |
| 177 AttachListener(java_bridge_.obj()); | |
| 178 JNIEnv* env = AttachCurrentThread(); | |
| 179 CHECK(env); | |
| 180 | 132 |
| 181 if (url_.is_valid()) { | 133 void RemoteMediaPlayerBridge::OnCastStarting(JNIEnv* env, |
| 182 // Create a Java String for the URL. | 134 jobject obj, |
| 183 ScopedJavaLocalRef<jstring> j_url_string = | 135 jstring casting_message) { |
| 184 ConvertUTF8ToJavaString(env, url_.spec()); | 136 static_cast<RemoteMediaPlayerManager*>(manager())->SwitchToRemotePlayer( |
| 137 player_id(), ConvertJavaStringToUTF8(env, casting_message)); |
| 138 if (!time_update_timer_.IsRunning()) { |
| 139 time_update_timer_.Start( |
| 140 FROM_HERE, |
| 141 base::TimeDelta::FromMilliseconds(media::kTimeUpdateInterval), this, |
| 142 &RemoteMediaPlayerBridge::OnTimeUpdateTimerFired); |
| 143 } |
| 144 } |
| 185 | 145 |
| 186 jobject j_context = base::android::GetApplicationContext(); | 146 void RemoteMediaPlayerBridge::OnCastStopping(JNIEnv* env, jobject obj) { |
| 187 DCHECK(j_context); | 147 static_cast<RemoteMediaPlayerManager*>(manager()) |
| 188 | 148 ->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 } | 149 } |
| 205 | 150 |
| 206 void RemoteMediaPlayerBridge::Pause(bool is_media_related_action) { | 151 void RemoteMediaPlayerBridge::Pause(bool is_media_related_action) { |
| 207 // Ignore the pause if it's not from an event that is explicitly telling | 152 // 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 | 153 // 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 | 154 // reasons, such as freeing resources, etc. and during those times, the |
| 210 // remote video playback should not be paused. | 155 // remote video playback should not be paused. |
| 211 if (is_media_related_action) { | 156 if (is_media_related_action) { |
| 212 if (!in_use_) { | 157 JNIEnv* env = AttachCurrentThread(); |
| 213 pending_play_ = false; | 158 Java_RemoteMediaPlayerBridge_pause(env, java_bridge_.obj()); |
| 214 } else { | 159 time_update_timer_.Stop(); |
| 215 if (prepared_ && IsPlaying()) | |
| 216 PauseInternal(); | |
| 217 else | |
| 218 pending_play_ = false; | |
| 219 } | |
| 220 } | 160 } |
| 221 } | 161 } |
| 222 | 162 |
| 223 void RemoteMediaPlayerBridge::SetVideoSurface(gfx::ScopedJavaSurface surface) { | 163 void RemoteMediaPlayerBridge::SetVideoSurface(gfx::ScopedJavaSurface surface) { |
| 224 // The surface is reset whenever the fullscreen view is destroyed or created. | 164 // 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 | 165 // 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 | 166 // for the time when user disconnects and resumes local playback |
| 227 // (see crbug.com/420690). | 167 // (see crbug.com/420690). |
| 228 local_player_->SetVideoSurface(surface.Pass()); | 168 local_player_->SetVideoSurface(surface.Pass()); |
| 229 } | 169 } |
| 230 | 170 |
| 231 base::android::ScopedJavaLocalRef<jstring> RemoteMediaPlayerBridge::GetFrameUrl( | 171 base::android::ScopedJavaLocalRef<jstring> RemoteMediaPlayerBridge::GetFrameUrl( |
| 232 JNIEnv* env, jobject obj) { | 172 JNIEnv* env, jobject obj) { |
| 233 return ConvertUTF8ToJavaString(env, frame_url().spec()); | 173 return ConvertUTF8ToJavaString(env, frame_url().spec()); |
| 234 } | 174 } |
| 235 | 175 |
| 236 void RemoteMediaPlayerBridge::OnPlaying(JNIEnv* env, jobject obj) { | 176 void RemoteMediaPlayerBridge::OnPlaying(JNIEnv* env, jobject obj) { |
| 237 static_cast<RemoteMediaPlayerManager *>(manager())->OnPlaying(player_id()); | 177 static_cast<RemoteMediaPlayerManager *>(manager())->OnPlaying(player_id()); |
| 238 } | 178 } |
| 239 | 179 |
| 240 void RemoteMediaPlayerBridge::OnPaused(JNIEnv* env, jobject obj) { | 180 void RemoteMediaPlayerBridge::OnPaused(JNIEnv* env, jobject obj) { |
| 241 static_cast<RemoteMediaPlayerManager *>(manager())->OnPaused(player_id()); | 181 static_cast<RemoteMediaPlayerManager *>(manager())->OnPaused(player_id()); |
| 242 } | 182 } |
| 243 | 183 |
| 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) { | 184 void RemoteMediaPlayerBridge::OnRouteUnselected(JNIEnv* env, jobject obj) { |
| 254 casting_message_.reset(); | 185 casting_message_.reset(); |
| 255 static_cast<RemoteMediaPlayerManager *>(manager())->OnRemoteDeviceUnselected( | 186 static_cast<RemoteMediaPlayerManager *>(manager())->OnRemoteDeviceUnselected( |
| 256 player_id()); | 187 player_id()); |
| 257 } | 188 } |
| 258 | 189 |
| 259 void RemoteMediaPlayerBridge::OnPlaybackFinished(JNIEnv* env, jobject obj) { | 190 void RemoteMediaPlayerBridge::OnPlaybackFinished(JNIEnv* env, jobject obj) { |
| 260 static_cast<RemoteMediaPlayerManager *>(manager())->OnRemotePlaybackFinished( | 191 static_cast<RemoteMediaPlayerManager *>(manager())->OnRemotePlaybackFinished( |
| 261 player_id()); | 192 player_id()); |
| 262 } | 193 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 } | 239 } |
| 309 | 240 |
| 310 void RemoteMediaPlayerBridge::OnPlayerDestroyed() { | 241 void RemoteMediaPlayerBridge::OnPlayerDestroyed() { |
| 311 JNIEnv* env = AttachCurrentThread(); | 242 JNIEnv* env = AttachCurrentThread(); |
| 312 CHECK(env); | 243 CHECK(env); |
| 313 | 244 |
| 314 Java_RemoteMediaPlayerBridge_onPlayerDestroyed( | 245 Java_RemoteMediaPlayerBridge_onPlayerDestroyed( |
| 315 env, java_bridge_.obj()); | 246 env, java_bridge_.obj()); |
| 316 } | 247 } |
| 317 | 248 |
| 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() { | 249 std::string RemoteMediaPlayerBridge::GetCastingMessage() { |
| 343 return casting_message_ ? | 250 return casting_message_ ? |
| 344 *casting_message_ : std::string(); | 251 *casting_message_ : std::string(); |
| 345 } | 252 } |
| 346 | 253 |
| 347 void RemoteMediaPlayerBridge::SetPosterBitmap( | 254 void RemoteMediaPlayerBridge::SetPosterBitmap( |
| 348 const std::vector<SkBitmap>& bitmaps) { | 255 const std::vector<SkBitmap>& bitmaps) { |
| 349 JNIEnv* env = AttachCurrentThread(); | 256 JNIEnv* env = AttachCurrentThread(); |
| 350 CHECK(env); | 257 CHECK(env); |
| 351 | 258 |
| 352 if (bitmaps.empty()) { | 259 if (bitmaps.empty()) { |
| 353 Java_RemoteMediaPlayerBridge_setPosterBitmap(env, java_bridge_.obj(), NULL); | 260 Java_RemoteMediaPlayerBridge_setPosterBitmap(env, java_bridge_.obj(), NULL); |
| 354 } else { | 261 } else { |
| 355 ScopedJavaLocalRef<jobject> j_poster_bitmap; | 262 ScopedJavaLocalRef<jobject> j_poster_bitmap; |
| 356 j_poster_bitmap = gfx::ConvertToJavaBitmap(&(bitmaps[0])); | 263 j_poster_bitmap = gfx::ConvertToJavaBitmap(&(bitmaps[0])); |
| 357 | 264 |
| 358 Java_RemoteMediaPlayerBridge_setPosterBitmap(env, java_bridge_.obj(), | 265 Java_RemoteMediaPlayerBridge_setPosterBitmap(env, java_bridge_.obj(), |
| 359 j_poster_bitmap.obj()); | 266 j_poster_bitmap.obj()); |
| 360 } | 267 } |
| 361 } | 268 } |
| 362 | 269 |
| 363 void RemoteMediaPlayerBridge::Start() { | 270 void RemoteMediaPlayerBridge::Start() { |
| 364 if (!in_use_) { | 271 StartInternal(); |
| 365 pending_play_ = true; | |
| 366 Prepare(); | |
| 367 } else { | |
| 368 if (prepared_) | |
| 369 StartInternal(); | |
| 370 else | |
| 371 pending_play_ = true; | |
| 372 } | |
| 373 } | 272 } |
| 374 | 273 |
| 375 void RemoteMediaPlayerBridge::SeekTo(base::TimeDelta timestamp) { | 274 void RemoteMediaPlayerBridge::SeekTo(base::TimeDelta time) { |
| 376 // Record the time to seek when OnMediaPrepared() is called. | 275 // TODO(aberent) Move the checks to the Java side. |
| 377 pending_seek_ = timestamp; | 276 base::TimeDelta duration = GetDuration(); |
| 378 should_seek_on_prepare_ = true; | |
| 379 | 277 |
| 380 if (!in_use_) | 278 if (time > duration) |
| 381 Prepare(); | 279 time = duration; |
| 382 else if (prepared_) | |
| 383 SeekInternal(timestamp); | |
| 384 } | |
| 385 | 280 |
| 386 void RemoteMediaPlayerBridge::Release() { | 281 // Seeking to an invalid position may cause media player to stuck in an |
| 387 if (!in_use_) | 282 // error state. |
| 388 return; | 283 if (time < base::TimeDelta()) { |
| 389 time_update_timer_.Stop(); | 284 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; | 285 return; |
| 407 } | 286 } |
| 408 | 287 |
| 409 JNIEnv* env = AttachCurrentThread(); | 288 JNIEnv* env = AttachCurrentThread(); |
| 410 CHECK(env); | 289 CHECK(env); |
| 290 int time_msec = static_cast<int>(time.InMilliseconds()); |
| 291 Java_RemoteMediaPlayerBridge_seekTo(env, java_bridge_.obj(), time_msec); |
| 292 } |
| 293 |
| 294 void RemoteMediaPlayerBridge::Release() { |
| 295 time_update_timer_.Stop(); |
| 296 JNIEnv* env = AttachCurrentThread(); |
| 297 Java_RemoteMediaPlayerBridge_release(env, java_bridge_.obj()); |
| 298 DetachListener(); |
| 299 } |
| 300 |
| 301 void RemoteMediaPlayerBridge::SetVolume(double volume) { |
| 302 JNIEnv* env = AttachCurrentThread(); |
| 303 CHECK(env); |
| 411 Java_RemoteMediaPlayerBridge_setVolume( | 304 Java_RemoteMediaPlayerBridge_setVolume( |
| 412 env, java_bridge_.obj(), volume); | 305 env, java_bridge_.obj(), volume); |
| 413 } | 306 } |
| 414 | 307 |
| 415 base::TimeDelta RemoteMediaPlayerBridge::GetCurrentTime() { | 308 base::TimeDelta RemoteMediaPlayerBridge::GetCurrentTime() { |
| 416 if (!prepared_) | |
| 417 return pending_seek_; | |
| 418 JNIEnv* env = AttachCurrentThread(); | 309 JNIEnv* env = AttachCurrentThread(); |
| 419 return base::TimeDelta::FromMilliseconds( | 310 return base::TimeDelta::FromMilliseconds( |
| 420 Java_RemoteMediaPlayerBridge_getCurrentPosition( | 311 Java_RemoteMediaPlayerBridge_getCurrentPosition( |
| 421 env, java_bridge_.obj())); | 312 env, java_bridge_.obj())); |
| 422 } | 313 } |
| 423 | 314 |
| 424 base::TimeDelta RemoteMediaPlayerBridge::GetDuration() { | 315 base::TimeDelta RemoteMediaPlayerBridge::GetDuration() { |
| 425 if (!prepared_) | |
| 426 return duration_; | |
| 427 JNIEnv* env = AttachCurrentThread(); | 316 JNIEnv* env = AttachCurrentThread(); |
| 428 const int duration_ms = | 317 const int duration_ms = |
| 429 Java_RemoteMediaPlayerBridge_getDuration(env, java_bridge_.obj()); | 318 Java_RemoteMediaPlayerBridge_getDuration(env, java_bridge_.obj()); |
| 430 // Sometimes we can't get the duration remotely, but the local media player | 319 // Sometimes we can't get the duration remotely, but the local media player |
| 431 // knows it. | 320 // knows it. |
| 432 // TODO (aberent) This is for YouTube. Remove it when the YouTube receiver is | 321 // TODO (aberent) This is for YouTube. Remove it when the YouTube receiver is |
| 433 // fixed. | 322 // fixed. |
| 434 if (duration_ms == 0) { | 323 if (duration_ms == 0) { |
| 435 return local_player_->GetDuration(); | 324 return local_player_->GetDuration(); |
| 436 } | 325 } |
| 437 return duration_ms < 0 ? media::kInfiniteDuration() | 326 return duration_ms < 0 ? media::kInfiniteDuration() |
| 438 : base::TimeDelta::FromMilliseconds(duration_ms); | 327 : base::TimeDelta::FromMilliseconds(duration_ms); |
| 439 } | 328 } |
| 440 | 329 |
| 441 bool RemoteMediaPlayerBridge::IsPlaying() { | 330 bool RemoteMediaPlayerBridge::IsPlaying() { |
| 442 if (!prepared_) | |
| 443 return pending_play_; | |
| 444 | |
| 445 JNIEnv* env = AttachCurrentThread(); | 331 JNIEnv* env = AttachCurrentThread(); |
| 446 CHECK(env); | 332 CHECK(env); |
| 447 jboolean result = Java_RemoteMediaPlayerBridge_isPlaying( | 333 jboolean result = Java_RemoteMediaPlayerBridge_isPlaying( |
| 448 env, java_bridge_.obj()); | 334 env, java_bridge_.obj()); |
| 449 return result; | 335 return result; |
| 450 } | 336 } |
| 451 | 337 |
| 452 bool RemoteMediaPlayerBridge::CanPause() { | 338 bool RemoteMediaPlayerBridge::CanPause() { |
| 453 return true; | 339 return true; |
| 454 } | 340 } |
| 455 | 341 |
| 456 bool RemoteMediaPlayerBridge::CanSeekForward() { | 342 bool RemoteMediaPlayerBridge::CanSeekForward() { |
| 457 return true; | 343 return true; |
| 458 } | 344 } |
| 459 | 345 |
| 460 bool RemoteMediaPlayerBridge::CanSeekBackward() { | 346 bool RemoteMediaPlayerBridge::CanSeekBackward() { |
| 461 return true; | 347 return true; |
| 462 } | 348 } |
| 463 | 349 |
| 464 bool RemoteMediaPlayerBridge::IsPlayerReady() { | 350 bool RemoteMediaPlayerBridge::IsPlayerReady() { |
| 465 return prepared_; | 351 return true; |
| 466 } | 352 } |
| 467 | 353 |
| 468 GURL RemoteMediaPlayerBridge::GetUrl() { | 354 GURL RemoteMediaPlayerBridge::GetUrl() { |
| 469 return url_; | 355 return url_; |
| 470 } | 356 } |
| 471 | 357 |
| 472 GURL RemoteMediaPlayerBridge::GetFirstPartyForCookies() { | 358 GURL RemoteMediaPlayerBridge::GetFirstPartyForCookies() { |
| 473 return first_party_for_cookies_; | 359 return first_party_for_cookies_; |
| 474 } | 360 } |
| 475 | 361 |
| 476 void RemoteMediaPlayerBridge::Initialize() { | 362 void RemoteMediaPlayerBridge::Initialize() { |
| 477 cookies_.clear(); | 363 cookies_.clear(); |
| 478 media::MediaResourceGetter* resource_getter = | 364 media::MediaResourceGetter* resource_getter = |
| 479 manager()->GetMediaResourceGetter(); | 365 manager()->GetMediaResourceGetter(); |
| 480 resource_getter->GetCookies( | 366 resource_getter->GetCookies( |
| 481 url_, first_party_for_cookies_, | 367 url_, first_party_for_cookies_, |
| 482 base::Bind(&RemoteMediaPlayerBridge::OnCookiesRetrieved, | 368 base::Bind(&RemoteMediaPlayerBridge::OnCookiesRetrieved, |
| 483 weak_factory_.GetWeakPtr())); | 369 weak_factory_.GetWeakPtr())); |
| 484 } | 370 } |
| 485 | 371 |
| 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( | 372 base::android::ScopedJavaLocalRef<jstring> RemoteMediaPlayerBridge::GetTitle( |
| 495 JNIEnv* env, jobject obj) { | 373 JNIEnv* env, jobject obj) { |
| 496 base::string16 title; | 374 base::string16 title; |
| 497 content::ContentViewCore* core = | 375 content::ContentViewCore* core = |
| 498 static_cast<RemoteMediaPlayerManager*>(manager())->GetContentViewCore(); | 376 static_cast<RemoteMediaPlayerManager*>(manager())->GetContentViewCore(); |
| 499 if (core) { | 377 if (core) { |
| 500 content::WebContents* contents = core->GetWebContents(); | 378 content::WebContents* contents = core->GetWebContents(); |
| 501 if (contents) { | 379 if (contents) { |
| 502 title = contents->GetTitle(); | 380 title = contents->GetTitle(); |
| 503 } | 381 } |
| 504 } | 382 } |
| 505 return base::android::ConvertUTF16ToJavaString(env, title); | 383 return base::android::ConvertUTF16ToJavaString(env, title); |
| 506 } | 384 } |
| 507 | 385 |
| 508 void RemoteMediaPlayerBridge::OnCookiesRetrieved(const std::string& cookies) { | 386 void RemoteMediaPlayerBridge::OnCookiesRetrieved(const std::string& cookies) { |
| 509 // TODO(aberent) Do we need to retrieve auth credentials for basic | 387 // TODO(aberent) Do we need to retrieve auth credentials for basic |
| 510 // authentication? MediaPlayerBridge does. | 388 // authentication? MediaPlayerBridge does. |
| 511 cookies_ = cookies; | 389 cookies_ = cookies; |
| 390 JNIEnv* env = AttachCurrentThread(); |
| 391 CHECK(env); |
| 392 Java_RemoteMediaPlayerBridge_setCookies( |
| 393 env, java_bridge_.obj(), ConvertUTF8ToJavaString(env, cookies).obj()); |
| 512 } | 394 } |
| 513 | 395 |
| 514 } // namespace remote_media | 396 bool RemoteMediaPlayerBridge::TakesOverCastDevice() { |
| 397 JNIEnv* env = AttachCurrentThread(); |
| 398 CHECK(env); |
| 399 jboolean result = |
| 400 Java_RemoteMediaPlayerBridge_takesOverCastDevice(env, java_bridge_.obj()); |
| 401 return result; |
| 402 } |
| 403 |
| 404 } // namespace remote_media |
| OLD | NEW |