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