Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / media / android / browser_media_player_manager.cc
blob20fd34e89de28e72e243f44ec986366dcabc57af
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.
5 #include "content/browser/media/android/browser_media_player_manager.h"
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/android/media_players_observer.h"
11 #include "content/browser/media/android/browser_demuxer_android.h"
12 #include "content/browser/media/android/media_resource_getter_impl.h"
13 #include "content/browser/renderer_host/render_view_host_impl.h"
14 #include "content/browser/web_contents/web_contents_view_android.h"
15 #include "content/common/media/media_player_messages_android.h"
16 #include "content/public/browser/android/content_view_core.h"
17 #include "content/public/browser/android/external_video_surface_container.h"
18 #include "content/public/browser/browser_context.h"
19 #include "content/public/browser/content_browser_client.h"
20 #include "content/public/browser/render_frame_host.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/render_view_host.h"
23 #include "content/public/browser/storage_partition.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/browser/web_contents_delegate.h"
26 #include "content/public/common/content_client.h"
27 #include "content/public/common/content_switches.h"
28 #include "media/base/android/media_player_bridge.h"
29 #include "media/base/android/media_source_player.h"
30 #include "media/base/android/media_url_interceptor.h"
31 #include "media/base/media_switches.h"
33 using media::MediaPlayerAndroid;
34 using media::MediaPlayerBridge;
35 using media::MediaPlayerManager;
36 using media::MediaSourcePlayer;
38 namespace content {
40 // Threshold on the number of media players per renderer before we start
41 // attempting to release inactive media players.
42 const int kMediaPlayerThreshold = 1;
43 const int kInvalidMediaPlayerId = -1;
45 static BrowserMediaPlayerManager::Factory g_factory = NULL;
46 static media::MediaUrlInterceptor* media_url_interceptor_ = NULL;
48 // static
49 void BrowserMediaPlayerManager::RegisterFactory(Factory factory) {
50 // TODO(aberent) nullptr test is a temporary fix to simplify upstreaming Cast.
51 // Until Cast is fully upstreamed we want the downstream factory to take
52 // priority over the upstream factory. The downstream call happens first,
53 // so this will ensure that it does.
54 if (g_factory == nullptr)
55 g_factory = factory;
58 // static
59 void BrowserMediaPlayerManager::RegisterMediaUrlInterceptor(
60 media::MediaUrlInterceptor* media_url_interceptor) {
61 media_url_interceptor_ = media_url_interceptor;
64 // static
65 BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
66 RenderFrameHost* rfh,
67 MediaPlayersObserver* audio_monitor) {
68 if (g_factory)
69 return g_factory(rfh, audio_monitor);
70 return new BrowserMediaPlayerManager(rfh, audio_monitor);
73 ContentViewCore* BrowserMediaPlayerManager::GetContentViewCore() const {
74 return ContentViewCoreImpl::FromWebContents(web_contents());
77 MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
78 const MediaPlayerHostMsg_Initialize_Params& media_player_params,
79 bool hide_url_log,
80 MediaPlayerManager* manager,
81 BrowserDemuxerAndroid* demuxer) {
82 switch (media_player_params.type) {
83 case MEDIA_PLAYER_TYPE_URL: {
84 const std::string user_agent = GetContentClient()->GetUserAgent();
85 MediaPlayerBridge* media_player_bridge = new MediaPlayerBridge(
86 media_player_params.player_id,
87 media_player_params.url,
88 media_player_params.first_party_for_cookies,
89 user_agent,
90 hide_url_log,
91 manager,
92 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
93 weak_ptr_factory_.GetWeakPtr()),
94 media_player_params.frame_url,
95 media_player_params.allow_credentials);
96 BrowserMediaPlayerManager* browser_media_player_manager =
97 static_cast<BrowserMediaPlayerManager*>(manager);
98 ContentViewCoreImpl* content_view_core_impl =
99 static_cast<ContentViewCoreImpl*>(ContentViewCore::FromWebContents(
100 browser_media_player_manager->web_contents_));
101 if (!content_view_core_impl) {
102 // May reach here due to prerendering. Don't extract the metadata
103 // since it is expensive.
104 // TODO(qinmin): extract the metadata once the user decided to load
105 // the page.
106 browser_media_player_manager->OnMediaMetadataChanged(
107 media_player_params.player_id, base::TimeDelta(), 0, 0, false);
108 } else if (!content_view_core_impl->ShouldBlockMediaRequest(
109 media_player_params.url)) {
110 media_player_bridge->Initialize();
112 return media_player_bridge;
115 case MEDIA_PLAYER_TYPE_MEDIA_SOURCE: {
116 return new MediaSourcePlayer(
117 media_player_params.player_id,
118 manager,
119 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
120 weak_ptr_factory_.GetWeakPtr()),
121 demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
122 media_player_params.frame_url);
126 NOTREACHED();
127 return NULL;
130 BrowserMediaPlayerManager::BrowserMediaPlayerManager(
131 RenderFrameHost* render_frame_host,
132 MediaPlayersObserver* audio_monitor)
133 : render_frame_host_(render_frame_host),
134 audio_monitor_(audio_monitor),
135 fullscreen_player_id_(kInvalidMediaPlayerId),
136 fullscreen_player_is_released_(false),
137 web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
138 weak_ptr_factory_(this) {
141 BrowserMediaPlayerManager::~BrowserMediaPlayerManager() {
142 // During the tear down process, OnDestroyPlayer() may or may not be called
143 // (e.g. the WebContents may be destroyed before the render process). So
144 // we cannot DCHECK(players_.empty()) here. Instead, all media players in
145 // |players_| will be destroyed here because |player_| is a ScopedVector.
148 void BrowserMediaPlayerManager::ExitFullscreen(bool release_media_player) {
149 if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
150 delegate->ExitFullscreenModeForTab(web_contents_);
151 if (RenderWidgetHostViewAndroid* view_android =
152 static_cast<RenderWidgetHostViewAndroid*>(
153 web_contents_->GetRenderWidgetHostView())) {
154 view_android->SetOverlayVideoMode(false);
157 Send(
158 new MediaPlayerMsg_DidExitFullscreen(RoutingID(), fullscreen_player_id_));
159 video_view_.reset();
160 MediaPlayerAndroid* player = GetFullscreenPlayer();
161 fullscreen_player_id_ = kInvalidMediaPlayerId;
162 if (!player)
163 return;
165 #if defined(VIDEO_HOLE)
166 if (external_video_surface_container_)
167 external_video_surface_container_->OnFrameInfoUpdated();
168 #endif // defined(VIDEO_HOLE)
170 if (release_media_player)
171 ReleaseFullscreenPlayer(player);
172 else
173 player->SetVideoSurface(gfx::ScopedJavaSurface());
176 void BrowserMediaPlayerManager::OnTimeUpdate(
177 int player_id,
178 base::TimeDelta current_timestamp,
179 base::TimeTicks current_time_ticks) {
180 Send(new MediaPlayerMsg_MediaTimeUpdate(
181 RoutingID(), player_id, current_timestamp, current_time_ticks));
184 void BrowserMediaPlayerManager::SetVideoSurface(
185 gfx::ScopedJavaSurface surface) {
186 MediaPlayerAndroid* player = GetFullscreenPlayer();
187 if (!player)
188 return;
190 bool empty_surface = surface.IsEmpty();
191 player->SetVideoSurface(surface.Pass());
192 if (empty_surface)
193 return;
195 if (RenderWidgetHostViewAndroid* view_android =
196 static_cast<RenderWidgetHostViewAndroid*>(
197 web_contents_->GetRenderWidgetHostView())) {
198 view_android->SetOverlayVideoMode(true);
202 void BrowserMediaPlayerManager::OnMediaMetadataChanged(
203 int player_id, base::TimeDelta duration, int width, int height,
204 bool success) {
205 Send(new MediaPlayerMsg_MediaMetadataChanged(
206 RoutingID(), player_id, duration, width, height, success));
207 if (fullscreen_player_id_ == player_id)
208 video_view_->UpdateMediaMetadata();
211 void BrowserMediaPlayerManager::OnPlaybackComplete(int player_id) {
212 Send(new MediaPlayerMsg_MediaPlaybackCompleted(RoutingID(), player_id));
213 if (fullscreen_player_id_ == player_id)
214 video_view_->OnPlaybackComplete();
217 void BrowserMediaPlayerManager::OnMediaInterrupted(int player_id) {
218 // Tell WebKit that the audio should be paused, then release all resources
219 Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(), player_id));
220 OnReleaseResources(player_id);
223 void BrowserMediaPlayerManager::OnBufferingUpdate(
224 int player_id, int percentage) {
225 Send(new MediaPlayerMsg_MediaBufferingUpdate(
226 RoutingID(), player_id, percentage));
227 if (fullscreen_player_id_ == player_id)
228 video_view_->OnBufferingUpdate(percentage);
231 void BrowserMediaPlayerManager::OnSeekRequest(
232 int player_id,
233 const base::TimeDelta& time_to_seek) {
234 Send(new MediaPlayerMsg_SeekRequest(RoutingID(), player_id, time_to_seek));
237 void BrowserMediaPlayerManager::ReleaseAllMediaPlayers() {
238 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
239 it != players_.end(); ++it) {
240 if ((*it)->player_id() == fullscreen_player_id_)
241 fullscreen_player_is_released_ = true;
242 (*it)->Release();
246 void BrowserMediaPlayerManager::OnSeekComplete(
247 int player_id,
248 const base::TimeDelta& current_time) {
249 Send(new MediaPlayerMsg_SeekCompleted(RoutingID(), player_id, current_time));
252 void BrowserMediaPlayerManager::OnError(int player_id, int error) {
253 Send(new MediaPlayerMsg_MediaError(RoutingID(), player_id, error));
254 if (fullscreen_player_id_ == player_id)
255 video_view_->OnMediaPlayerError(error);
258 void BrowserMediaPlayerManager::OnVideoSizeChanged(
259 int player_id, int width, int height) {
260 Send(new MediaPlayerMsg_MediaVideoSizeChanged(RoutingID(), player_id,
261 width, height));
262 if (fullscreen_player_id_ == player_id)
263 video_view_->OnVideoSizeChanged(width, height);
266 void BrowserMediaPlayerManager::OnAudibleStateChanged(
267 int player_id, bool is_audible) {
268 audio_monitor_->OnAudibleStateChanged(
269 render_frame_host_, player_id, is_audible);
272 void BrowserMediaPlayerManager::OnWaitingForDecryptionKey(int player_id) {
273 Send(new MediaPlayerMsg_WaitingForDecryptionKey(RoutingID(), player_id));
276 media::MediaResourceGetter*
277 BrowserMediaPlayerManager::GetMediaResourceGetter() {
278 if (!media_resource_getter_.get()) {
279 RenderProcessHost* host = web_contents()->GetRenderProcessHost();
280 BrowserContext* context = host->GetBrowserContext();
281 StoragePartition* partition = host->GetStoragePartition();
282 storage::FileSystemContext* file_system_context =
283 partition ? partition->GetFileSystemContext() : NULL;
284 // Eventually this needs to be fixed to pass the correct frame rather
285 // than just using the main frame.
286 media_resource_getter_.reset(new MediaResourceGetterImpl(
287 context,
288 file_system_context,
289 host->GetID(),
290 web_contents()->GetMainFrame()->GetRoutingID()));
292 return media_resource_getter_.get();
295 media::MediaUrlInterceptor*
296 BrowserMediaPlayerManager::GetMediaUrlInterceptor() {
297 return media_url_interceptor_;
300 MediaPlayerAndroid* BrowserMediaPlayerManager::GetFullscreenPlayer() {
301 return GetPlayer(fullscreen_player_id_);
304 MediaPlayerAndroid* BrowserMediaPlayerManager::GetPlayer(int player_id) {
305 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
306 it != players_.end(); ++it) {
307 if ((*it)->player_id() == player_id)
308 return *it;
310 return NULL;
313 void BrowserMediaPlayerManager::RequestFullScreen(int player_id) {
314 if (fullscreen_player_id_ == player_id)
315 return;
317 if (fullscreen_player_id_ != kInvalidMediaPlayerId) {
318 // TODO(qinmin): Determine the correct error code we should report to WMPA.
319 OnError(player_id, MediaPlayerAndroid::MEDIA_ERROR_DECODE);
320 return;
323 Send(new MediaPlayerMsg_RequestFullscreen(RoutingID(), player_id));
326 #if defined(VIDEO_HOLE)
327 void BrowserMediaPlayerManager::AttachExternalVideoSurface(int player_id,
328 jobject surface) {
329 MediaPlayerAndroid* player = GetPlayer(player_id);
330 if (player) {
331 player->SetVideoSurface(
332 gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
336 void BrowserMediaPlayerManager::DetachExternalVideoSurface(int player_id) {
337 MediaPlayerAndroid* player = GetPlayer(player_id);
338 if (player)
339 player->SetVideoSurface(gfx::ScopedJavaSurface());
342 void BrowserMediaPlayerManager::OnFrameInfoUpdated() {
343 if (fullscreen_player_id_ != kInvalidMediaPlayerId)
344 return;
346 if (external_video_surface_container_)
347 external_video_surface_container_->OnFrameInfoUpdated();
350 void BrowserMediaPlayerManager::OnNotifyExternalSurface(
351 int player_id, bool is_request, const gfx::RectF& rect) {
352 if (!web_contents_)
353 return;
355 if (is_request) {
356 OnRequestExternalSurface(player_id, rect);
358 if (external_video_surface_container_) {
359 external_video_surface_container_->OnExternalVideoSurfacePositionChanged(
360 player_id, rect);
364 void BrowserMediaPlayerManager::ReleasePlayerOfExternalVideoSurfaceIfNeeded(
365 int future_player) {
366 int current_player = ExternalVideoSurfaceContainer::kInvalidPlayerId;
368 if (external_video_surface_container_)
369 current_player = external_video_surface_container_->GetCurrentPlayerId();
371 if (current_player == ExternalVideoSurfaceContainer::kInvalidPlayerId)
372 return;
374 if (current_player != future_player)
375 OnMediaInterrupted(current_player);
378 void BrowserMediaPlayerManager::OnRequestExternalSurface(
379 int player_id, const gfx::RectF& rect) {
380 if (!external_video_surface_container_) {
381 ContentBrowserClient* client = GetContentClient()->browser();
382 external_video_surface_container_.reset(
383 client->OverrideCreateExternalVideoSurfaceContainer(web_contents_));
385 // It's safe to use base::Unretained(this), because the callbacks will not
386 // be called after running ReleaseExternalVideoSurface().
387 if (external_video_surface_container_) {
388 // In case we're stealing the external surface from another player.
389 ReleasePlayerOfExternalVideoSurfaceIfNeeded(player_id);
390 external_video_surface_container_->RequestExternalVideoSurface(
391 player_id,
392 base::Bind(&BrowserMediaPlayerManager::AttachExternalVideoSurface,
393 base::Unretained(this)),
394 base::Bind(&BrowserMediaPlayerManager::DetachExternalVideoSurface,
395 base::Unretained(this)));
398 #endif // defined(VIDEO_HOLE)
400 void BrowserMediaPlayerManager::OnEnterFullscreen(int player_id) {
401 DCHECK_EQ(fullscreen_player_id_, kInvalidMediaPlayerId);
402 #if defined(VIDEO_HOLE)
403 // If this fullscreen player is started when another player
404 // uses the external surface, release that other player.
405 ReleasePlayerOfExternalVideoSurfaceIfNeeded(player_id);
406 if (external_video_surface_container_)
407 external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
408 #endif // defined(VIDEO_HOLE)
409 if (video_view_.get()) {
410 fullscreen_player_id_ = player_id;
411 video_view_->OpenVideo();
412 return;
413 } else if (!ContentVideoView::GetInstance()) {
414 // In Android WebView, two ContentViewCores could both try to enter
415 // fullscreen video, we just ignore the second one.
416 video_view_.reset(new ContentVideoView(this));
417 base::android::ScopedJavaLocalRef<jobject> j_content_video_view =
418 video_view_->GetJavaObject(base::android::AttachCurrentThread());
419 if (!j_content_video_view.is_null()) {
420 fullscreen_player_id_ = player_id;
421 return;
425 // Force the second video to exit fullscreen.
426 Send(new MediaPlayerMsg_DidExitFullscreen(RoutingID(), player_id));
427 video_view_.reset();
430 void BrowserMediaPlayerManager::OnExitFullscreen(int player_id) {
431 if (fullscreen_player_id_ == player_id) {
432 MediaPlayerAndroid* player = GetPlayer(player_id);
433 if (player)
434 player->SetVideoSurface(gfx::ScopedJavaSurface());
435 video_view_->OnExitFullscreen();
439 void BrowserMediaPlayerManager::OnInitialize(
440 const MediaPlayerHostMsg_Initialize_Params& media_player_params) {
441 DCHECK(media_player_params.type != MEDIA_PLAYER_TYPE_MEDIA_SOURCE ||
442 media_player_params.demuxer_client_id > 0)
443 << "Media source players must have positive demuxer client IDs: "
444 << media_player_params.demuxer_client_id;
446 RemovePlayer(media_player_params.player_id);
448 RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>(
449 web_contents()->GetRenderProcessHost());
450 MediaPlayerAndroid* player =
451 CreateMediaPlayer(media_player_params,
453 host->GetBrowserContext()->IsOffTheRecord(),
454 this,
455 host->browser_demuxer_android().get());
457 if (!player)
458 return;
460 AddPlayer(player);
463 void BrowserMediaPlayerManager::OnStart(int player_id) {
464 MediaPlayerAndroid* player = GetPlayer(player_id);
465 if (!player)
466 return;
467 player->Start();
468 if (fullscreen_player_id_ == player_id && fullscreen_player_is_released_) {
469 video_view_->OpenVideo();
470 fullscreen_player_is_released_ = false;
474 void BrowserMediaPlayerManager::OnSeek(
475 int player_id,
476 const base::TimeDelta& time) {
477 MediaPlayerAndroid* player = GetPlayer(player_id);
478 if (player)
479 player->SeekTo(time);
482 void BrowserMediaPlayerManager::OnPause(
483 int player_id,
484 bool is_media_related_action) {
485 MediaPlayerAndroid* player = GetPlayer(player_id);
486 if (player)
487 player->Pause(is_media_related_action);
490 void BrowserMediaPlayerManager::OnSetVolume(int player_id, double volume) {
491 MediaPlayerAndroid* player = GetPlayer(player_id);
492 if (player)
493 player->SetVolume(volume);
496 void BrowserMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) {
497 // To be overridden by subclasses.
500 void BrowserMediaPlayerManager::OnReleaseResources(int player_id) {
501 MediaPlayerAndroid* player = GetPlayer(player_id);
502 if (player)
503 ReleasePlayer(player);
504 if (player_id == fullscreen_player_id_)
505 fullscreen_player_is_released_ = true;
508 void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) {
509 RemovePlayer(player_id);
510 if (fullscreen_player_id_ == player_id)
511 fullscreen_player_id_ = kInvalidMediaPlayerId;
514 void BrowserMediaPlayerManager::OnRequestRemotePlayback(int /* player_id */) {
515 // Does nothing if we don't have a remote player
518 void BrowserMediaPlayerManager::OnRequestRemotePlaybackControl(
519 int /* player_id */) {
520 // Does nothing if we don't have a remote player
523 void BrowserMediaPlayerManager::AddPlayer(MediaPlayerAndroid* player) {
524 DCHECK(!GetPlayer(player->player_id()));
525 players_.push_back(player);
528 void BrowserMediaPlayerManager::RemovePlayer(int player_id) {
529 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
530 it != players_.end(); ++it) {
531 if ((*it)->player_id() == player_id) {
532 ReleaseMediaResources(player_id);
533 players_.erase(it);
534 audio_monitor_->RemovePlayer(render_frame_host_, player_id);
535 break;
540 scoped_ptr<media::MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer(
541 int player_id, media::MediaPlayerAndroid* player) {
542 media::MediaPlayerAndroid* previous_player = NULL;
543 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
544 it != players_.end(); ++it) {
545 if ((*it)->player_id() == player_id) {
546 previous_player = *it;
547 ReleaseMediaResources(player_id);
548 players_.weak_erase(it);
549 players_.push_back(player);
550 break;
553 return scoped_ptr<media::MediaPlayerAndroid>(previous_player);
556 int BrowserMediaPlayerManager::RoutingID() {
557 return render_frame_host_->GetRoutingID();
560 bool BrowserMediaPlayerManager::Send(IPC::Message* msg) {
561 return render_frame_host_->Send(msg);
564 void BrowserMediaPlayerManager::ReleaseFullscreenPlayer(
565 MediaPlayerAndroid* player) {
566 ReleasePlayer(player);
569 void BrowserMediaPlayerManager::OnMediaResourcesRequested(int player_id) {
570 int num_active_player = 0;
571 ScopedVector<MediaPlayerAndroid>::iterator it;
572 for (it = players_.begin(); it != players_.end(); ++it) {
573 if (!(*it)->IsPlayerReady())
574 continue;
576 // The player is already active, ignore it.
577 if ((*it)->player_id() == player_id)
578 return;
579 else
580 num_active_player++;
583 // Number of active players are less than the threshold, do nothing.
584 if (num_active_player < kMediaPlayerThreshold)
585 return;
587 for (it = players_.begin(); it != players_.end(); ++it) {
588 if ((*it)->IsPlayerReady() && !(*it)->IsPlaying() &&
589 fullscreen_player_id_ != (*it)->player_id()) {
590 ReleasePlayer(*it);
591 Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(),
592 (*it)->player_id()));
597 void BrowserMediaPlayerManager::ReleaseMediaResources(int player_id) {
598 #if defined(VIDEO_HOLE)
599 if (external_video_surface_container_)
600 external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
601 #endif // defined(VIDEO_HOLE)
604 void BrowserMediaPlayerManager::ReleasePlayer(MediaPlayerAndroid* player) {
605 player->Release();
606 ReleaseMediaResources(player->player_id());
609 } // namespace content