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
;
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
;
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)
59 void BrowserMediaPlayerManager::RegisterMediaUrlInterceptor(
60 media::MediaUrlInterceptor
* media_url_interceptor
) {
61 media_url_interceptor_
= media_url_interceptor
;
65 BrowserMediaPlayerManager
* BrowserMediaPlayerManager::Create(
67 MediaPlayersObserver
* audio_monitor
) {
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
,
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
,
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
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
,
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
);
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);
158 new MediaPlayerMsg_DidExitFullscreen(RoutingID(), fullscreen_player_id_
));
160 MediaPlayerAndroid
* player
= GetFullscreenPlayer();
161 fullscreen_player_id_
= kInvalidMediaPlayerId
;
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
);
173 player
->SetVideoSurface(gfx::ScopedJavaSurface());
176 void BrowserMediaPlayerManager::OnTimeUpdate(
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();
190 bool empty_surface
= surface
.IsEmpty();
191 player
->SetVideoSurface(surface
.Pass());
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
,
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(
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;
246 void BrowserMediaPlayerManager::OnSeekComplete(
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
,
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(
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
)
313 void BrowserMediaPlayerManager::RequestFullScreen(int player_id
) {
314 if (fullscreen_player_id_
== player_id
)
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
);
323 Send(new MediaPlayerMsg_RequestFullscreen(RoutingID(), player_id
));
326 #if defined(VIDEO_HOLE)
327 void BrowserMediaPlayerManager::AttachExternalVideoSurface(int player_id
,
329 MediaPlayerAndroid
* player
= GetPlayer(player_id
);
331 player
->SetVideoSurface(
332 gfx::ScopedJavaSurface::AcquireExternalSurface(surface
));
336 void BrowserMediaPlayerManager::DetachExternalVideoSurface(int player_id
) {
337 MediaPlayerAndroid
* player
= GetPlayer(player_id
);
339 player
->SetVideoSurface(gfx::ScopedJavaSurface());
342 void BrowserMediaPlayerManager::OnFrameInfoUpdated() {
343 if (fullscreen_player_id_
!= kInvalidMediaPlayerId
)
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
) {
356 OnRequestExternalSurface(player_id
, rect
);
358 if (external_video_surface_container_
) {
359 external_video_surface_container_
->OnExternalVideoSurfacePositionChanged(
364 void BrowserMediaPlayerManager::ReleasePlayerOfExternalVideoSurfaceIfNeeded(
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
)
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(
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();
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
;
425 // Force the second video to exit fullscreen.
426 Send(new MediaPlayerMsg_DidExitFullscreen(RoutingID(), player_id
));
430 void BrowserMediaPlayerManager::OnExitFullscreen(int player_id
) {
431 if (fullscreen_player_id_
== player_id
) {
432 MediaPlayerAndroid
* player
= GetPlayer(player_id
);
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(),
455 host
->browser_demuxer_android().get());
463 void BrowserMediaPlayerManager::OnStart(int player_id
) {
464 MediaPlayerAndroid
* player
= GetPlayer(player_id
);
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(
476 const base::TimeDelta
& time
) {
477 MediaPlayerAndroid
* player
= GetPlayer(player_id
);
479 player
->SeekTo(time
);
482 void BrowserMediaPlayerManager::OnPause(
484 bool is_media_related_action
) {
485 MediaPlayerAndroid
* player
= GetPlayer(player_id
);
487 player
->Pause(is_media_related_action
);
490 void BrowserMediaPlayerManager::OnSetVolume(int player_id
, double volume
) {
491 MediaPlayerAndroid
* player
= GetPlayer(player_id
);
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
);
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
);
534 audio_monitor_
->RemovePlayer(render_frame_host_
, player_id
);
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
);
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())
576 // The player is already active, ignore it.
577 if ((*it
)->player_id() == player_id
)
583 // Number of active players are less than the threshold, do nothing.
584 if (num_active_player
< kMediaPlayerThreshold
)
587 for (it
= players_
.begin(); it
!= players_
.end(); ++it
) {
588 if ((*it
)->IsPlayerReady() && !(*it
)->IsPlaying() &&
589 fullscreen_player_id_
!= (*it
)->player_id()) {
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
) {
606 ReleaseMediaResources(player
->player_id());
609 } // namespace content