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/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"
32 using media::MediaPlayerAndroid;
33 using media::MediaPlayerBridge;
34 using media::MediaPlayerManager;
35 using media::MediaSourcePlayer;
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;
43 static BrowserMediaPlayerManager::Factory g_factory = NULL;
44 static media::MediaUrlInterceptor* media_url_interceptor_ = NULL;
47 void BrowserMediaPlayerManager::RegisterFactory(Factory factory) {
52 void BrowserMediaPlayerManager::RegisterMediaUrlInterceptor(
53 media::MediaUrlInterceptor* media_url_interceptor) {
54 media_url_interceptor_ = media_url_interceptor;
58 BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
59 RenderFrameHost* rfh) {
61 return g_factory(rfh);
62 return new BrowserMediaPlayerManager(rfh);
65 ContentViewCoreImpl* BrowserMediaPlayerManager::GetContentViewCore() const {
66 return ContentViewCoreImpl::FromWebContents(web_contents());
69 MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
70 const MediaPlayerHostMsg_Initialize_Params& media_player_params,
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,
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
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();
104 return media_player_bridge;
107 case MEDIA_PLAYER_TYPE_MEDIA_SOURCE: {
108 return new MediaSourcePlayer(
109 media_player_params.player_id,
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);
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) {
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.
138 void BrowserMediaPlayerManager::FullscreenPlayerPlay() {
139 MediaPlayerAndroid* player = GetFullscreenPlayer();
141 if (fullscreen_player_is_released_) {
142 video_view_->OpenVideo();
143 fullscreen_player_is_released_ = false;
146 Send(new MediaPlayerMsg_DidMediaPlayerPlay(RoutingID(),
147 fullscreen_player_id_));
151 void BrowserMediaPlayerManager::FullscreenPlayerPause() {
152 MediaPlayerAndroid* player = GetFullscreenPlayer();
155 Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(),
156 fullscreen_player_id_));
160 void BrowserMediaPlayerManager::FullscreenPlayerSeek(int msec) {
161 MediaPlayerAndroid* player = GetFullscreenPlayer();
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));
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);
181 new MediaPlayerMsg_DidExitFullscreen(RoutingID(), fullscreen_player_id_));
183 MediaPlayerAndroid* player = GetFullscreenPlayer();
184 fullscreen_player_id_ = -1;
187 if (release_media_player)
188 ReleaseFullscreenPlayer(player);
190 player->SetVideoSurface(gfx::ScopedJavaSurface());
193 void BrowserMediaPlayerManager::OnTimeUpdate(
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));
201 void BrowserMediaPlayerManager::SetVideoSurface(
202 gfx::ScopedJavaSurface surface) {
203 MediaPlayerAndroid* player = GetFullscreenPlayer();
207 bool empty_surface = surface.IsEmpty();
208 player->SetVideoSurface(surface.Pass());
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);
220 void BrowserMediaPlayerManager::OnMediaMetadataChanged(
221 int player_id, base::TimeDelta duration, int width, int height,
223 Send(new MediaPlayerMsg_MediaMetadataChanged(
224 RoutingID(), player_id, duration, width, height, success));
225 if (fullscreen_player_id_ == player_id)
226 video_view_->UpdateMediaMetadata();
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();
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);
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);
249 void BrowserMediaPlayerManager::OnSeekRequest(
251 const base::TimeDelta& time_to_seek) {
252 Send(new MediaPlayerMsg_SeekRequest(RoutingID(), player_id, time_to_seek));
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;
264 void BrowserMediaPlayerManager::OnSeekComplete(
266 const base::TimeDelta& current_time) {
267 Send(new MediaPlayerMsg_SeekCompleted(RoutingID(), player_id, current_time));
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);
276 void BrowserMediaPlayerManager::OnVideoSizeChanged(
277 int player_id, int width, int height) {
278 Send(new MediaPlayerMsg_MediaVideoSizeChanged(RoutingID(), player_id,
280 if (fullscreen_player_id_ == player_id)
281 video_view_->OnVideoSizeChanged(width, height);
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(
298 web_contents()->GetMainFrame()->GetRoutingID()));
300 return media_resource_getter_.get();
303 media::MediaUrlInterceptor*
304 BrowserMediaPlayerManager::GetMediaUrlInterceptor() {
305 return media_url_interceptor_;
308 MediaPlayerAndroid* BrowserMediaPlayerManager::GetFullscreenPlayer() {
309 return GetPlayer(fullscreen_player_id_);
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)
321 void BrowserMediaPlayerManager::RequestFullScreen(int player_id) {
322 if (fullscreen_player_id_ == player_id)
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);
331 Send(new MediaPlayerMsg_RequestFullscreen(RoutingID(), player_id));
334 #if defined(VIDEO_HOLE)
336 BrowserMediaPlayerManager::ShouldUseVideoOverlayForEmbeddedEncryptedVideo() {
337 RendererPreferences* prefs = web_contents_->GetMutableRendererPrefs();
338 return prefs->use_video_overlay_for_embedded_encrypted_video;
341 void BrowserMediaPlayerManager::AttachExternalVideoSurface(int player_id,
343 MediaPlayerAndroid* player = GetPlayer(player_id);
345 player->SetVideoSurface(
346 gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
350 void BrowserMediaPlayerManager::DetachExternalVideoSurface(int player_id) {
351 MediaPlayerAndroid* player = GetPlayer(player_id);
353 player->SetVideoSurface(gfx::ScopedJavaSurface());
356 void BrowserMediaPlayerManager::OnFrameInfoUpdated() {
357 if (external_video_surface_container_)
358 external_video_surface_container_->OnFrameInfoUpdated();
361 void BrowserMediaPlayerManager::OnNotifyExternalSurface(
362 int player_id, bool is_request, const gfx::RectF& rect) {
367 OnRequestExternalSurface(player_id, rect);
369 if (external_video_surface_container_) {
370 external_video_surface_container_->OnExternalVideoSurfacePositionChanged(
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_));
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(
387 base::Bind(&BrowserMediaPlayerManager::AttachExternalVideoSurface,
388 base::Unretained(this)),
389 base::Bind(&BrowserMediaPlayerManager::DetachExternalVideoSurface,
390 base::Unretained(this)));
393 #endif // defined(VIDEO_HOLE)
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();
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;
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));
426 void BrowserMediaPlayerManager::OnExitFullscreen(int player_id) {
427 if (fullscreen_player_id_ == player_id) {
428 MediaPlayerAndroid* player = GetPlayer(player_id);
430 player->SetVideoSurface(gfx::ScopedJavaSurface());
431 video_view_->OnExitFullscreen();
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;
442 RemovePlayer(media_player_params.player_id);
444 RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>(
445 web_contents()->GetRenderProcessHost());
446 MediaPlayerAndroid* player = CreateMediaPlayer(
449 host->GetBrowserContext()->IsOffTheRecord(), this,
450 host->browser_demuxer_android());
458 void BrowserMediaPlayerManager::OnStart(int player_id) {
459 MediaPlayerAndroid* player = GetPlayer(player_id);
463 if (fullscreen_player_id_ == player_id && fullscreen_player_is_released_) {
464 video_view_->OpenVideo();
465 fullscreen_player_is_released_ = false;
469 void BrowserMediaPlayerManager::OnSeek(
471 const base::TimeDelta& time) {
472 MediaPlayerAndroid* player = GetPlayer(player_id);
474 player->SeekTo(time);
477 void BrowserMediaPlayerManager::OnPause(
479 bool is_media_related_action) {
480 MediaPlayerAndroid* player = GetPlayer(player_id);
482 player->Pause(is_media_related_action);
485 void BrowserMediaPlayerManager::OnSetVolume(int player_id, double volume) {
486 MediaPlayerAndroid* player = GetPlayer(player_id);
488 player->SetVolume(volume);
491 void BrowserMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) {
492 // To be overridden by subclasses.
495 void BrowserMediaPlayerManager::OnReleaseResources(int player_id) {
496 MediaPlayerAndroid* player = GetPlayer(player_id);
498 ReleasePlayer(player);
499 if (player_id == fullscreen_player_id_)
500 fullscreen_player_is_released_ = true;
503 void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) {
504 RemovePlayer(player_id);
505 if (fullscreen_player_id_ == player_id)
506 fullscreen_player_id_ = -1;
509 void BrowserMediaPlayerManager::OnRequestRemotePlayback(int /* player_id */) {
510 // Does nothing if we don't have a remote player
513 void BrowserMediaPlayerManager::OnRequestRemotePlaybackControl(
514 int /* player_id */) {
515 // Does nothing if we don't have a remote player
518 void BrowserMediaPlayerManager::AddPlayer(MediaPlayerAndroid* player) {
519 DCHECK(!GetPlayer(player->player_id()));
520 players_.push_back(player);
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);
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);
547 return scoped_ptr<media::MediaPlayerAndroid>(previous_player);
550 int BrowserMediaPlayerManager::RoutingID() {
551 return render_frame_host_->GetRoutingID();
554 bool BrowserMediaPlayerManager::Send(IPC::Message* msg) {
555 return render_frame_host_->Send(msg);
558 void BrowserMediaPlayerManager::ReleaseFullscreenPlayer(
559 MediaPlayerAndroid* player) {
560 ReleasePlayer(player);
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())
570 // The player is already active, ignore it.
571 if ((*it)->player_id() == player_id)
577 // Number of active players are less than the threshold, do nothing.
578 if (num_active_player < kMediaPlayerThreshold)
581 for (it = players_.begin(); it != players_.end(); ++it) {
582 if ((*it)->IsPlayerReady() && !(*it)->IsPlaying() &&
583 fullscreen_player_id_ != (*it)->player_id()) {
585 Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(),
586 (*it)->player_id()));
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)
598 void BrowserMediaPlayerManager::ReleasePlayer(MediaPlayerAndroid* player) {
600 ReleaseMediaResources(player->player_id());
603 } // namespace content