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 "content/browser/media/android/browser_media_player_manager.h" 6 7 #include "base/android/scoped_java_ref.h" 8 #include "base/command_line.h" 9 #include "content/browser/android/content_view_core_impl.h" 10 #include "content/browser/media/android/browser_demuxer_android.h" 11 #include "content/browser/media/android/media_resource_getter_impl.h" 12 #include "content/browser/renderer_host/render_view_host_impl.h" 13 #include "content/browser/web_contents/web_contents_view_android.h" 14 #include "content/common/media/media_player_messages_android.h" 15 #include "content/public/browser/android/content_view_core.h" 16 #include "content/public/browser/android/external_video_surface_container.h" 17 #include "content/public/browser/browser_context.h" 18 #include "content/public/browser/content_browser_client.h" 19 #include "content/public/browser/render_frame_host.h" 20 #include "content/public/browser/render_process_host.h" 21 #include "content/public/browser/render_view_host.h" 22 #include "content/public/browser/storage_partition.h" 23 #include "content/public/browser/web_contents.h" 24 #include "content/public/browser/web_contents_delegate.h" 25 #include "content/public/common/content_client.h" 26 #include "content/public/common/content_switches.h" 27 #include "media/base/android/media_player_bridge.h" 28 #include "media/base/android/media_source_player.h" 29 #include "media/base/android/media_url_interceptor.h" 30 #include "media/base/media_switches.h" 31 32 using media::MediaPlayerAndroid; 33 using media::MediaPlayerBridge; 34 using media::MediaPlayerManager; 35 using media::MediaSourcePlayer; 36 37 namespace content { 38 39 // Threshold on the number of media players per renderer before we start 40 // attempting to release inactive media players. 41 const int kMediaPlayerThreshold = 1; 42 43 static BrowserMediaPlayerManager::Factory g_factory = NULL; 44 static media::MediaUrlInterceptor* media_url_interceptor_ = NULL; 45 46 // static 47 void BrowserMediaPlayerManager::RegisterFactory(Factory factory) { 48 g_factory = factory; 49 } 50 51 // static 52 void BrowserMediaPlayerManager::RegisterMediaUrlInterceptor( 53 media::MediaUrlInterceptor* media_url_interceptor) { 54 media_url_interceptor_ = media_url_interceptor; 55 } 56 57 // static 58 BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create( 59 RenderFrameHost* rfh) { 60 if (g_factory) 61 return g_factory(rfh); 62 return new BrowserMediaPlayerManager(rfh); 63 } 64 65 ContentViewCoreImpl* BrowserMediaPlayerManager::GetContentViewCore() const { 66 return ContentViewCoreImpl::FromWebContents(web_contents()); 67 } 68 69 MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer( 70 const MediaPlayerHostMsg_Initialize_Params& media_player_params, 71 bool hide_url_log, 72 MediaPlayerManager* manager, 73 BrowserDemuxerAndroid* demuxer) { 74 switch (media_player_params.type) { 75 case MEDIA_PLAYER_TYPE_URL: { 76 const std::string user_agent = GetContentClient()->GetUserAgent(); 77 MediaPlayerBridge* media_player_bridge = new MediaPlayerBridge( 78 media_player_params.player_id, 79 media_player_params.url, 80 media_player_params.first_party_for_cookies, 81 user_agent, 82 hide_url_log, 83 manager, 84 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested, 85 weak_ptr_factory_.GetWeakPtr()), 86 media_player_params.frame_url, 87 media_player_params.allow_credentials); 88 BrowserMediaPlayerManager* browser_media_player_manager = 89 static_cast<BrowserMediaPlayerManager*>(manager); 90 ContentViewCoreImpl* content_view_core_impl = 91 static_cast<ContentViewCoreImpl*>(ContentViewCore::FromWebContents( 92 browser_media_player_manager->web_contents_)); 93 if (!content_view_core_impl) { 94 // May reach here due to prerendering. Don't extract the metadata 95 // since it is expensive. 96 // TODO(qinmin): extract the metadata once the user decided to load 97 // the page. 98 browser_media_player_manager->OnMediaMetadataChanged( 99 media_player_params.player_id, base::TimeDelta(), 0, 0, false); 100 } else if (!content_view_core_impl->ShouldBlockMediaRequest( 101 media_player_params.url)) { 102 media_player_bridge->Initialize(); 103 } 104 return media_player_bridge; 105 } 106 107 case MEDIA_PLAYER_TYPE_MEDIA_SOURCE: { 108 return new MediaSourcePlayer( 109 media_player_params.player_id, 110 manager, 111 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested, 112 weak_ptr_factory_.GetWeakPtr()), 113 demuxer->CreateDemuxer(media_player_params.demuxer_client_id), 114 media_player_params.frame_url); 115 } 116 } 117 118 NOTREACHED(); 119 return NULL; 120 } 121 122 BrowserMediaPlayerManager::BrowserMediaPlayerManager( 123 RenderFrameHost* render_frame_host) 124 : render_frame_host_(render_frame_host), 125 fullscreen_player_id_(-1), 126 fullscreen_player_is_released_(false), 127 web_contents_(WebContents::FromRenderFrameHost(render_frame_host)), 128 weak_ptr_factory_(this) { 129 } 130 131 BrowserMediaPlayerManager::~BrowserMediaPlayerManager() { 132 // During the tear down process, OnDestroyPlayer() may or may not be called 133 // (e.g. the WebContents may be destroyed before the render process). So 134 // we cannot DCHECK(players_.empty()) here. Instead, all media players in 135 // |players_| will be destroyed here because |player_| is a ScopedVector. 136 } 137 138 void BrowserMediaPlayerManager::FullscreenPlayerPlay() { 139 MediaPlayerAndroid* player = GetFullscreenPlayer(); 140 if (player) { 141 if (fullscreen_player_is_released_) { 142 video_view_->OpenVideo(); 143 fullscreen_player_is_released_ = false; 144 } 145 player->Start(); 146 Send(new MediaPlayerMsg_DidMediaPlayerPlay(RoutingID(), 147 fullscreen_player_id_)); 148 } 149 } 150 151 void BrowserMediaPlayerManager::FullscreenPlayerPause() { 152 MediaPlayerAndroid* player = GetFullscreenPlayer(); 153 if (player) { 154 player->Pause(true); 155 Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(), 156 fullscreen_player_id_)); 157 } 158 } 159 160 void BrowserMediaPlayerManager::FullscreenPlayerSeek(int msec) { 161 MediaPlayerAndroid* player = GetFullscreenPlayer(); 162 if (player) { 163 // TODO(kbalazs): if |fullscreen_player_is_released_| is true 164 // at this point, player->GetCurrentTime() will be wrong until 165 // FullscreenPlayerPlay (http://crbug.com/322798). 166 OnSeekRequest(fullscreen_player_id_, 167 base::TimeDelta::FromMilliseconds(msec)); 168 } 169 } 170 171 void BrowserMediaPlayerManager::ExitFullscreen(bool release_media_player) { 172 if (WebContentsDelegate* delegate = web_contents_->GetDelegate()) 173 delegate->ToggleFullscreenModeForTab(web_contents_, false); 174 if (RenderWidgetHostViewAndroid* view_android = 175 static_cast<RenderWidgetHostViewAndroid*>( 176 web_contents_->GetRenderWidgetHostView())) { 177 view_android->SetOverlayVideoMode(false); 178 } 179 180 Send( 181 new MediaPlayerMsg_DidExitFullscreen(RoutingID(), fullscreen_player_id_)); 182 video_view_.reset(); 183 MediaPlayerAndroid* player = GetFullscreenPlayer(); 184 fullscreen_player_id_ = -1; 185 if (!player) 186 return; 187 if (release_media_player) 188 ReleaseFullscreenPlayer(player); 189 else 190 player->SetVideoSurface(gfx::ScopedJavaSurface()); 191 } 192 193 void BrowserMediaPlayerManager::OnTimeUpdate( 194 int player_id, 195 base::TimeDelta current_timestamp, 196 base::TimeTicks current_time_ticks) { 197 Send(new MediaPlayerMsg_MediaTimeUpdate( 198 RoutingID(), player_id, current_timestamp, current_time_ticks)); 199 } 200 201 void BrowserMediaPlayerManager::SetVideoSurface( 202 gfx::ScopedJavaSurface surface) { 203 MediaPlayerAndroid* player = GetFullscreenPlayer(); 204 if (!player) 205 return; 206 207 bool empty_surface = surface.IsEmpty(); 208 player->SetVideoSurface(surface.Pass()); 209 if (empty_surface) 210 return; 211 212 Send(new MediaPlayerMsg_DidEnterFullscreen(RoutingID(), player->player_id())); 213 if (RenderWidgetHostViewAndroid* view_android = 214 static_cast<RenderWidgetHostViewAndroid*>( 215 web_contents_->GetRenderWidgetHostView())) { 216 view_android->SetOverlayVideoMode(true); 217 } 218 } 219 220 void BrowserMediaPlayerManager::OnMediaMetadataChanged( 221 int player_id, base::TimeDelta duration, int width, int height, 222 bool success) { 223 Send(new MediaPlayerMsg_MediaMetadataChanged( 224 RoutingID(), player_id, duration, width, height, success)); 225 if (fullscreen_player_id_ == player_id) 226 video_view_->UpdateMediaMetadata(); 227 } 228 229 void BrowserMediaPlayerManager::OnPlaybackComplete(int player_id) { 230 Send(new MediaPlayerMsg_MediaPlaybackCompleted(RoutingID(), player_id)); 231 if (fullscreen_player_id_ == player_id) 232 video_view_->OnPlaybackComplete(); 233 } 234 235 void BrowserMediaPlayerManager::OnMediaInterrupted(int player_id) { 236 // Tell WebKit that the audio should be paused, then release all resources 237 Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(), player_id)); 238 OnReleaseResources(player_id); 239 } 240 241 void BrowserMediaPlayerManager::OnBufferingUpdate( 242 int player_id, int percentage) { 243 Send(new MediaPlayerMsg_MediaBufferingUpdate( 244 RoutingID(), player_id, percentage)); 245 if (fullscreen_player_id_ == player_id) 246 video_view_->OnBufferingUpdate(percentage); 247 } 248 249 void BrowserMediaPlayerManager::OnSeekRequest( 250 int player_id, 251 const base::TimeDelta& time_to_seek) { 252 Send(new MediaPlayerMsg_SeekRequest(RoutingID(), player_id, time_to_seek)); 253 } 254 255 void BrowserMediaPlayerManager::ReleaseAllMediaPlayers() { 256 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin(); 257 it != players_.end(); ++it) { 258 if ((*it)->player_id() == fullscreen_player_id_) 259 fullscreen_player_is_released_ = true; 260 (*it)->Release(); 261 } 262 } 263 264 void BrowserMediaPlayerManager::OnSeekComplete( 265 int player_id, 266 const base::TimeDelta& current_time) { 267 Send(new MediaPlayerMsg_SeekCompleted(RoutingID(), player_id, current_time)); 268 } 269 270 void BrowserMediaPlayerManager::OnError(int player_id, int error) { 271 Send(new MediaPlayerMsg_MediaError(RoutingID(), player_id, error)); 272 if (fullscreen_player_id_ == player_id) 273 video_view_->OnMediaPlayerError(error); 274 } 275 276 void BrowserMediaPlayerManager::OnVideoSizeChanged( 277 int player_id, int width, int height) { 278 Send(new MediaPlayerMsg_MediaVideoSizeChanged(RoutingID(), player_id, 279 width, height)); 280 if (fullscreen_player_id_ == player_id) 281 video_view_->OnVideoSizeChanged(width, height); 282 } 283 284 media::MediaResourceGetter* 285 BrowserMediaPlayerManager::GetMediaResourceGetter() { 286 if (!media_resource_getter_.get()) { 287 RenderProcessHost* host = web_contents()->GetRenderProcessHost(); 288 BrowserContext* context = host->GetBrowserContext(); 289 StoragePartition* partition = host->GetStoragePartition(); 290 storage::FileSystemContext* file_system_context = 291 partition ? partition->GetFileSystemContext() : NULL; 292 // Eventually this needs to be fixed to pass the correct frame rather 293 // than just using the main frame. 294 media_resource_getter_.reset(new MediaResourceGetterImpl( 295 context, 296 file_system_context, 297 host->GetID(), 298 web_contents()->GetMainFrame()->GetRoutingID())); 299 } 300 return media_resource_getter_.get(); 301 } 302 303 media::MediaUrlInterceptor* 304 BrowserMediaPlayerManager::GetMediaUrlInterceptor() { 305 return media_url_interceptor_; 306 } 307 308 MediaPlayerAndroid* BrowserMediaPlayerManager::GetFullscreenPlayer() { 309 return GetPlayer(fullscreen_player_id_); 310 } 311 312 MediaPlayerAndroid* BrowserMediaPlayerManager::GetPlayer(int player_id) { 313 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin(); 314 it != players_.end(); ++it) { 315 if ((*it)->player_id() == player_id) 316 return *it; 317 } 318 return NULL; 319 } 320 321 void BrowserMediaPlayerManager::RequestFullScreen(int player_id) { 322 if (fullscreen_player_id_ == player_id) 323 return; 324 325 if (fullscreen_player_id_ != -1) { 326 // TODO(qinmin): Determine the correct error code we should report to WMPA. 327 OnError(player_id, MediaPlayerAndroid::MEDIA_ERROR_DECODE); 328 return; 329 } 330 331 Send(new MediaPlayerMsg_RequestFullscreen(RoutingID(), player_id)); 332 } 333 334 #if defined(VIDEO_HOLE) 335 bool 336 BrowserMediaPlayerManager::ShouldUseVideoOverlayForEmbeddedEncryptedVideo() { 337 RendererPreferences* prefs = web_contents_->GetMutableRendererPrefs(); 338 return prefs->use_video_overlay_for_embedded_encrypted_video; 339 } 340 341 void BrowserMediaPlayerManager::AttachExternalVideoSurface(int player_id, 342 jobject surface) { 343 MediaPlayerAndroid* player = GetPlayer(player_id); 344 if (player) { 345 player->SetVideoSurface( 346 gfx::ScopedJavaSurface::AcquireExternalSurface(surface)); 347 } 348 } 349 350 void BrowserMediaPlayerManager::DetachExternalVideoSurface(int player_id) { 351 MediaPlayerAndroid* player = GetPlayer(player_id); 352 if (player) 353 player->SetVideoSurface(gfx::ScopedJavaSurface()); 354 } 355 356 void BrowserMediaPlayerManager::OnFrameInfoUpdated() { 357 if (external_video_surface_container_) 358 external_video_surface_container_->OnFrameInfoUpdated(); 359 } 360 361 void BrowserMediaPlayerManager::OnNotifyExternalSurface( 362 int player_id, bool is_request, const gfx::RectF& rect) { 363 if (!web_contents_) 364 return; 365 366 if (is_request) { 367 OnRequestExternalSurface(player_id, rect); 368 } 369 if (external_video_surface_container_) { 370 external_video_surface_container_->OnExternalVideoSurfacePositionChanged( 371 player_id, rect); 372 } 373 } 374 375 void BrowserMediaPlayerManager::OnRequestExternalSurface( 376 int player_id, const gfx::RectF& rect) { 377 if (!external_video_surface_container_) { 378 ContentBrowserClient* client = GetContentClient()->browser(); 379 external_video_surface_container_.reset( 380 client->OverrideCreateExternalVideoSurfaceContainer(web_contents_)); 381 } 382 // It's safe to use base::Unretained(this), because the callbacks will not 383 // be called after running ReleaseExternalVideoSurface(). 384 if (external_video_surface_container_) { 385 external_video_surface_container_->RequestExternalVideoSurface( 386 player_id, 387 base::Bind(&BrowserMediaPlayerManager::AttachExternalVideoSurface, 388 base::Unretained(this)), 389 base::Bind(&BrowserMediaPlayerManager::DetachExternalVideoSurface, 390 base::Unretained(this))); 391 } 392 } 393 #endif // defined(VIDEO_HOLE) 394 395 void BrowserMediaPlayerManager::OnEnterFullscreen(int player_id) { 396 DCHECK_EQ(fullscreen_player_id_, -1); 397 #if defined(VIDEO_HOLE) 398 if (external_video_surface_container_) 399 external_video_surface_container_->ReleaseExternalVideoSurface(player_id); 400 #endif // defined(VIDEO_HOLE) 401 if (video_view_.get()) { 402 fullscreen_player_id_ = player_id; 403 video_view_->OpenVideo(); 404 return; 405 } else if (!ContentVideoView::GetInstance()) { 406 // In Android WebView, two ContentViewCores could both try to enter 407 // fullscreen video, we just ignore the second one. 408 video_view_.reset(new ContentVideoView(this)); 409 base::android::ScopedJavaLocalRef<jobject> j_content_video_view = 410 video_view_->GetJavaObject(base::android::AttachCurrentThread()); 411 if (!j_content_video_view.is_null()) { 412 fullscreen_player_id_ = player_id; 413 return; 414 } 415 } 416 417 // Force the second video to exit fullscreen. 418 // TODO(qinmin): There is no need to send DidEnterFullscreen message. 419 // However, if we don't send the message, page layers will not be 420 // correctly restored. http:crbug.com/367346. 421 Send(new MediaPlayerMsg_DidEnterFullscreen(RoutingID(), player_id)); 422 Send(new MediaPlayerMsg_DidExitFullscreen(RoutingID(), player_id)); 423 video_view_.reset(); 424 } 425 426 void BrowserMediaPlayerManager::OnExitFullscreen(int player_id) { 427 if (fullscreen_player_id_ == player_id) { 428 MediaPlayerAndroid* player = GetPlayer(player_id); 429 if (player) 430 player->SetVideoSurface(gfx::ScopedJavaSurface()); 431 video_view_->OnExitFullscreen(); 432 } 433 } 434 435 void BrowserMediaPlayerManager::OnInitialize( 436 const MediaPlayerHostMsg_Initialize_Params& media_player_params) { 437 DCHECK(media_player_params.type != MEDIA_PLAYER_TYPE_MEDIA_SOURCE || 438 media_player_params.demuxer_client_id > 0) 439 << "Media source players must have positive demuxer client IDs: " 440 << media_player_params.demuxer_client_id; 441 442 RemovePlayer(media_player_params.player_id); 443 444 RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>( 445 web_contents()->GetRenderProcessHost()); 446 MediaPlayerAndroid* player = CreateMediaPlayer( 447 media_player_params, 448 449 host->GetBrowserContext()->IsOffTheRecord(), this, 450 host->browser_demuxer_android()); 451 452 if (!player) 453 return; 454 455 AddPlayer(player); 456 } 457 458 void BrowserMediaPlayerManager::OnStart(int player_id) { 459 MediaPlayerAndroid* player = GetPlayer(player_id); 460 if (!player) 461 return; 462 player->Start(); 463 if (fullscreen_player_id_ == player_id && fullscreen_player_is_released_) { 464 video_view_->OpenVideo(); 465 fullscreen_player_is_released_ = false; 466 } 467 } 468 469 void BrowserMediaPlayerManager::OnSeek( 470 int player_id, 471 const base::TimeDelta& time) { 472 MediaPlayerAndroid* player = GetPlayer(player_id); 473 if (player) 474 player->SeekTo(time); 475 } 476 477 void BrowserMediaPlayerManager::OnPause( 478 int player_id, 479 bool is_media_related_action) { 480 MediaPlayerAndroid* player = GetPlayer(player_id); 481 if (player) 482 player->Pause(is_media_related_action); 483 } 484 485 void BrowserMediaPlayerManager::OnSetVolume(int player_id, double volume) { 486 MediaPlayerAndroid* player = GetPlayer(player_id); 487 if (player) 488 player->SetVolume(volume); 489 } 490 491 void BrowserMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) { 492 // To be overridden by subclasses. 493 } 494 495 void BrowserMediaPlayerManager::OnReleaseResources(int player_id) { 496 MediaPlayerAndroid* player = GetPlayer(player_id); 497 if (player) 498 ReleasePlayer(player); 499 if (player_id == fullscreen_player_id_) 500 fullscreen_player_is_released_ = true; 501 } 502 503 void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) { 504 RemovePlayer(player_id); 505 if (fullscreen_player_id_ == player_id) 506 fullscreen_player_id_ = -1; 507 } 508 509 void BrowserMediaPlayerManager::OnRequestRemotePlayback(int /* player_id */) { 510 // Does nothing if we don't have a remote player 511 } 512 513 void BrowserMediaPlayerManager::OnRequestRemotePlaybackControl( 514 int /* player_id */) { 515 // Does nothing if we don't have a remote player 516 } 517 518 void BrowserMediaPlayerManager::AddPlayer(MediaPlayerAndroid* player) { 519 DCHECK(!GetPlayer(player->player_id())); 520 players_.push_back(player); 521 } 522 523 void BrowserMediaPlayerManager::RemovePlayer(int player_id) { 524 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin(); 525 it != players_.end(); ++it) { 526 if ((*it)->player_id() == player_id) { 527 ReleaseMediaResources(player_id); 528 players_.erase(it); 529 break; 530 } 531 } 532 } 533 534 scoped_ptr<media::MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer( 535 int player_id, media::MediaPlayerAndroid* player) { 536 media::MediaPlayerAndroid* previous_player = NULL; 537 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin(); 538 it != players_.end(); ++it) { 539 if ((*it)->player_id() == player_id) { 540 previous_player = *it; 541 ReleaseMediaResources(player_id); 542 players_.weak_erase(it); 543 players_.push_back(player); 544 break; 545 } 546 } 547 return scoped_ptr<media::MediaPlayerAndroid>(previous_player); 548 } 549 550 int BrowserMediaPlayerManager::RoutingID() { 551 return render_frame_host_->GetRoutingID(); 552 } 553 554 bool BrowserMediaPlayerManager::Send(IPC::Message* msg) { 555 return render_frame_host_->Send(msg); 556 } 557 558 void BrowserMediaPlayerManager::ReleaseFullscreenPlayer( 559 MediaPlayerAndroid* player) { 560 ReleasePlayer(player); 561 } 562 563 void BrowserMediaPlayerManager::OnMediaResourcesRequested(int player_id) { 564 int num_active_player = 0; 565 ScopedVector<MediaPlayerAndroid>::iterator it; 566 for (it = players_.begin(); it != players_.end(); ++it) { 567 if (!(*it)->IsPlayerReady()) 568 continue; 569 570 // The player is already active, ignore it. 571 if ((*it)->player_id() == player_id) 572 return; 573 else 574 num_active_player++; 575 } 576 577 // Number of active players are less than the threshold, do nothing. 578 if (num_active_player < kMediaPlayerThreshold) 579 return; 580 581 for (it = players_.begin(); it != players_.end(); ++it) { 582 if ((*it)->IsPlayerReady() && !(*it)->IsPlaying() && 583 fullscreen_player_id_ != (*it)->player_id()) { 584 ReleasePlayer(*it); 585 Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(), 586 (*it)->player_id())); 587 } 588 } 589 } 590 591 void BrowserMediaPlayerManager::ReleaseMediaResources(int player_id) { 592 #if defined(VIDEO_HOLE) 593 if (external_video_surface_container_) 594 external_video_surface_container_->ReleaseExternalVideoSurface(player_id); 595 #endif // defined(VIDEO_HOLE) 596 } 597 598 void BrowserMediaPlayerManager::ReleasePlayer(MediaPlayerAndroid* player) { 599 player->Release(); 600 ReleaseMediaResources(player->player_id()); 601 } 602 603 } // namespace content 604