Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / media / android / browser_media_player_manager.cc
blobc847a275b8f37d484775164dd90079ab69a135e7
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;
37 namespace content {
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;
46 // static
47 void BrowserMediaPlayerManager::RegisterFactory(Factory factory) {
48 g_factory = factory;
51 // static
52 void BrowserMediaPlayerManager::RegisterMediaUrlInterceptor(
53 media::MediaUrlInterceptor* media_url_interceptor) {
54 media_url_interceptor_ = media_url_interceptor;
57 // static
58 BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
59 RenderFrameHost* rfh) {
60 if (g_factory)
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,
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 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesReleased,
87 weak_ptr_factory_.GetWeakPtr()),
88 media_player_params.frame_url,
89 media_player_params.allow_credentials);
90 BrowserMediaPlayerManager* browser_media_player_manager =
91 static_cast<BrowserMediaPlayerManager*>(manager);
92 ContentViewCoreImpl* content_view_core_impl =
93 static_cast<ContentViewCoreImpl*>(ContentViewCore::FromWebContents(
94 browser_media_player_manager->web_contents_));
95 if (!content_view_core_impl) {
96 // May reach here due to prerendering. Don't extract the metadata
97 // since it is expensive.
98 // TODO(qinmin): extract the metadata once the user decided to load
99 // the page.
100 browser_media_player_manager->OnMediaMetadataChanged(
101 media_player_params.player_id, base::TimeDelta(), 0, 0, false);
102 } else if (!content_view_core_impl->ShouldBlockMediaRequest(
103 media_player_params.url)) {
104 media_player_bridge->Initialize();
106 return media_player_bridge;
109 case MEDIA_PLAYER_TYPE_MEDIA_SOURCE: {
110 return new MediaSourcePlayer(
111 media_player_params.player_id,
112 manager,
113 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
114 weak_ptr_factory_.GetWeakPtr()),
115 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesReleased,
116 weak_ptr_factory_.GetWeakPtr()),
117 demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
118 media_player_params.frame_url);
122 NOTREACHED();
123 return NULL;
126 BrowserMediaPlayerManager::BrowserMediaPlayerManager(
127 RenderFrameHost* render_frame_host)
128 : render_frame_host_(render_frame_host),
129 fullscreen_player_id_(-1),
130 fullscreen_player_is_released_(false),
131 web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
132 weak_ptr_factory_(this) {
135 BrowserMediaPlayerManager::~BrowserMediaPlayerManager() {
136 // During the tear down process, OnDestroyPlayer() may or may not be called
137 // (e.g. the WebContents may be destroyed before the render process). So
138 // we cannot DCHECK(players_.empty()) here. Instead, all media players in
139 // |players_| will be destroyed here because |player_| is a ScopedVector.
142 void BrowserMediaPlayerManager::FullscreenPlayerPlay() {
143 MediaPlayerAndroid* player = GetFullscreenPlayer();
144 if (player) {
145 if (fullscreen_player_is_released_) {
146 video_view_->OpenVideo();
147 fullscreen_player_is_released_ = false;
149 player->Start();
150 Send(new MediaPlayerMsg_DidMediaPlayerPlay(RoutingID(),
151 fullscreen_player_id_));
155 void BrowserMediaPlayerManager::FullscreenPlayerPause() {
156 MediaPlayerAndroid* player = GetFullscreenPlayer();
157 if (player) {
158 player->Pause(true);
159 Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(),
160 fullscreen_player_id_));
164 void BrowserMediaPlayerManager::FullscreenPlayerSeek(int msec) {
165 MediaPlayerAndroid* player = GetFullscreenPlayer();
166 if (player) {
167 // TODO(kbalazs): if |fullscreen_player_is_released_| is true
168 // at this point, player->GetCurrentTime() will be wrong until
169 // FullscreenPlayerPlay (http://crbug.com/322798).
170 OnSeekRequest(fullscreen_player_id_,
171 base::TimeDelta::FromMilliseconds(msec));
175 void BrowserMediaPlayerManager::ExitFullscreen(bool release_media_player) {
176 if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
177 delegate->ToggleFullscreenModeForTab(web_contents_, false);
178 if (!CommandLine::ForCurrentProcess()->HasSwitch(
179 switches::kDisableOverlayFullscreenVideoSubtitle)) {
180 if (RenderWidgetHostViewAndroid* view_android =
181 static_cast<RenderWidgetHostViewAndroid*>(
182 web_contents_->GetRenderWidgetHostView())) {
183 view_android->SetOverlayVideoMode(false);
187 Send(
188 new MediaPlayerMsg_DidExitFullscreen(RoutingID(), fullscreen_player_id_));
189 video_view_.reset();
190 MediaPlayerAndroid* player = GetFullscreenPlayer();
191 fullscreen_player_id_ = -1;
192 if (!player)
193 return;
194 if (release_media_player)
195 ReleaseFullscreenPlayer(player);
196 else
197 player->SetVideoSurface(gfx::ScopedJavaSurface());
200 void BrowserMediaPlayerManager::OnTimeUpdate(int player_id,
201 base::TimeDelta current_time) {
202 Send(
203 new MediaPlayerMsg_MediaTimeUpdate(RoutingID(), player_id, current_time));
206 void BrowserMediaPlayerManager::SetVideoSurface(
207 gfx::ScopedJavaSurface surface) {
208 MediaPlayerAndroid* player = GetFullscreenPlayer();
209 if (!player)
210 return;
212 bool empty_surface = surface.IsEmpty();
213 player->SetVideoSurface(surface.Pass());
214 if (empty_surface)
215 return;
217 Send(new MediaPlayerMsg_DidEnterFullscreen(RoutingID(), player->player_id()));
218 if (CommandLine::ForCurrentProcess()->HasSwitch(
219 switches::kDisableOverlayFullscreenVideoSubtitle)) {
220 return;
222 if (RenderWidgetHostViewAndroid* view_android =
223 static_cast<RenderWidgetHostViewAndroid*>(
224 web_contents_->GetRenderWidgetHostView())) {
225 view_android->SetOverlayVideoMode(true);
229 void BrowserMediaPlayerManager::OnMediaMetadataChanged(
230 int player_id, base::TimeDelta duration, int width, int height,
231 bool success) {
232 Send(new MediaPlayerMsg_MediaMetadataChanged(
233 RoutingID(), player_id, duration, width, height, success));
234 if (fullscreen_player_id_ == player_id)
235 video_view_->UpdateMediaMetadata();
238 void BrowserMediaPlayerManager::OnPlaybackComplete(int player_id) {
239 Send(new MediaPlayerMsg_MediaPlaybackCompleted(RoutingID(), player_id));
240 if (fullscreen_player_id_ == player_id)
241 video_view_->OnPlaybackComplete();
244 void BrowserMediaPlayerManager::OnMediaInterrupted(int player_id) {
245 // Tell WebKit that the audio should be paused, then release all resources
246 Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(), player_id));
247 OnReleaseResources(player_id);
250 void BrowserMediaPlayerManager::OnBufferingUpdate(
251 int player_id, int percentage) {
252 Send(new MediaPlayerMsg_MediaBufferingUpdate(
253 RoutingID(), player_id, percentage));
254 if (fullscreen_player_id_ == player_id)
255 video_view_->OnBufferingUpdate(percentage);
258 void BrowserMediaPlayerManager::OnSeekRequest(
259 int player_id,
260 const base::TimeDelta& time_to_seek) {
261 Send(new MediaPlayerMsg_SeekRequest(RoutingID(), player_id, time_to_seek));
264 void BrowserMediaPlayerManager::PauseVideo() {
265 Send(new MediaPlayerMsg_PauseVideo(RoutingID()));
268 void BrowserMediaPlayerManager::OnSeekComplete(
269 int player_id,
270 const base::TimeDelta& current_time) {
271 Send(new MediaPlayerMsg_SeekCompleted(RoutingID(), player_id, current_time));
274 void BrowserMediaPlayerManager::OnError(int player_id, int error) {
275 Send(new MediaPlayerMsg_MediaError(RoutingID(), player_id, error));
276 if (fullscreen_player_id_ == player_id)
277 video_view_->OnMediaPlayerError(error);
280 void BrowserMediaPlayerManager::OnVideoSizeChanged(
281 int player_id, int width, int height) {
282 Send(new MediaPlayerMsg_MediaVideoSizeChanged(RoutingID(), player_id,
283 width, height));
284 if (fullscreen_player_id_ == player_id)
285 video_view_->OnVideoSizeChanged(width, height);
288 media::MediaResourceGetter*
289 BrowserMediaPlayerManager::GetMediaResourceGetter() {
290 if (!media_resource_getter_.get()) {
291 RenderProcessHost* host = web_contents()->GetRenderProcessHost();
292 BrowserContext* context = host->GetBrowserContext();
293 StoragePartition* partition = host->GetStoragePartition();
294 storage::FileSystemContext* file_system_context =
295 partition ? partition->GetFileSystemContext() : NULL;
296 // Eventually this needs to be fixed to pass the correct frame rather
297 // than just using the main frame.
298 media_resource_getter_.reset(new MediaResourceGetterImpl(
299 context,
300 file_system_context,
301 host->GetID(),
302 web_contents()->GetMainFrame()->GetRoutingID()));
304 return media_resource_getter_.get();
307 media::MediaUrlInterceptor*
308 BrowserMediaPlayerManager::GetMediaUrlInterceptor() {
309 return media_url_interceptor_;
312 MediaPlayerAndroid* BrowserMediaPlayerManager::GetFullscreenPlayer() {
313 return GetPlayer(fullscreen_player_id_);
316 MediaPlayerAndroid* BrowserMediaPlayerManager::GetPlayer(int player_id) {
317 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
318 it != players_.end(); ++it) {
319 if ((*it)->player_id() == player_id)
320 return *it;
322 return NULL;
325 void BrowserMediaPlayerManager::RequestFullScreen(int player_id) {
326 if (fullscreen_player_id_ == player_id)
327 return;
329 if (fullscreen_player_id_ != -1) {
330 // TODO(qinmin): Determine the correct error code we should report to WMPA.
331 OnError(player_id, MediaPlayerAndroid::MEDIA_ERROR_DECODE);
332 return;
335 Send(new MediaPlayerMsg_RequestFullscreen(RoutingID(), player_id));
338 #if defined(VIDEO_HOLE)
339 bool
340 BrowserMediaPlayerManager::ShouldUseVideoOverlayForEmbeddedEncryptedVideo() {
341 RendererPreferences* prefs = web_contents_->GetMutableRendererPrefs();
342 return prefs->use_video_overlay_for_embedded_encrypted_video;
345 void BrowserMediaPlayerManager::AttachExternalVideoSurface(int player_id,
346 jobject surface) {
347 MediaPlayerAndroid* player = GetPlayer(player_id);
348 if (player) {
349 player->SetVideoSurface(
350 gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
354 void BrowserMediaPlayerManager::DetachExternalVideoSurface(int player_id) {
355 MediaPlayerAndroid* player = GetPlayer(player_id);
356 if (player)
357 player->SetVideoSurface(gfx::ScopedJavaSurface());
360 void BrowserMediaPlayerManager::OnFrameInfoUpdated() {
361 if (external_video_surface_container_)
362 external_video_surface_container_->OnFrameInfoUpdated();
365 void BrowserMediaPlayerManager::OnNotifyExternalSurface(
366 int player_id, bool is_request, const gfx::RectF& rect) {
367 if (!web_contents_)
368 return;
370 if (is_request) {
371 OnRequestExternalSurface(player_id, rect);
373 if (external_video_surface_container_) {
374 external_video_surface_container_->OnExternalVideoSurfacePositionChanged(
375 player_id, rect);
379 void BrowserMediaPlayerManager::OnRequestExternalSurface(
380 int player_id, const gfx::RectF& rect) {
381 if (!external_video_surface_container_) {
382 ContentBrowserClient* client = GetContentClient()->browser();
383 external_video_surface_container_.reset(
384 client->OverrideCreateExternalVideoSurfaceContainer(web_contents_));
386 // It's safe to use base::Unretained(this), because the callbacks will not
387 // be called after running ReleaseExternalVideoSurface().
388 if (external_video_surface_container_) {
389 external_video_surface_container_->RequestExternalVideoSurface(
390 player_id,
391 base::Bind(&BrowserMediaPlayerManager::AttachExternalVideoSurface,
392 base::Unretained(this)),
393 base::Bind(&BrowserMediaPlayerManager::DetachExternalVideoSurface,
394 base::Unretained(this)));
397 #endif // defined(VIDEO_HOLE)
399 void BrowserMediaPlayerManager::OnEnterFullscreen(int player_id) {
400 DCHECK_EQ(fullscreen_player_id_, -1);
401 #if defined(VIDEO_HOLE)
402 if (external_video_surface_container_)
403 external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
404 #endif // defined(VIDEO_HOLE)
405 if (video_view_.get()) {
406 fullscreen_player_id_ = player_id;
407 video_view_->OpenVideo();
408 return;
409 } else if (!ContentVideoView::GetInstance()) {
410 // In Android WebView, two ContentViewCores could both try to enter
411 // fullscreen video, we just ignore the second one.
412 video_view_.reset(new ContentVideoView(this));
413 base::android::ScopedJavaLocalRef<jobject> j_content_video_view =
414 video_view_->GetJavaObject(base::android::AttachCurrentThread());
415 if (!j_content_video_view.is_null()) {
416 fullscreen_player_id_ = player_id;
417 return;
421 // Force the second video to exit fullscreen.
422 // TODO(qinmin): There is no need to send DidEnterFullscreen message.
423 // However, if we don't send the message, page layers will not be
424 // correctly restored. http:crbug.com/367346.
425 Send(new MediaPlayerMsg_DidEnterFullscreen(RoutingID(), player_id));
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 = CreateMediaPlayer(
451 media_player_params,
453 host->GetBrowserContext()->IsOffTheRecord(), this,
454 host->browser_demuxer_android());
456 if (!player)
457 return;
459 AddPlayer(player);
462 void BrowserMediaPlayerManager::OnStart(int player_id) {
463 MediaPlayerAndroid* player = GetPlayer(player_id);
464 if (!player)
465 return;
466 player->Start();
467 if (fullscreen_player_id_ == player_id && fullscreen_player_is_released_) {
468 video_view_->OpenVideo();
469 fullscreen_player_is_released_ = false;
473 void BrowserMediaPlayerManager::OnSeek(
474 int player_id,
475 const base::TimeDelta& time) {
476 MediaPlayerAndroid* player = GetPlayer(player_id);
477 if (player)
478 player->SeekTo(time);
481 void BrowserMediaPlayerManager::OnPause(
482 int player_id,
483 bool is_media_related_action) {
484 MediaPlayerAndroid* player = GetPlayer(player_id);
485 if (player)
486 player->Pause(is_media_related_action);
489 void BrowserMediaPlayerManager::OnSetVolume(int player_id, double volume) {
490 MediaPlayerAndroid* player = GetPlayer(player_id);
491 if (player)
492 player->SetVolume(volume);
495 void BrowserMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) {
496 // To be overridden by subclasses.
499 void BrowserMediaPlayerManager::OnReleaseResources(int player_id) {
500 MediaPlayerAndroid* player = GetPlayer(player_id);
501 if (player)
502 player->Release();
503 if (player_id == fullscreen_player_id_)
504 fullscreen_player_is_released_ = true;
507 void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) {
508 RemovePlayer(player_id);
509 if (fullscreen_player_id_ == player_id)
510 fullscreen_player_id_ = -1;
513 void BrowserMediaPlayerManager::AddPlayer(MediaPlayerAndroid* player) {
514 DCHECK(!GetPlayer(player->player_id()));
515 players_.push_back(player);
518 void BrowserMediaPlayerManager::RemovePlayer(int player_id) {
519 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
520 it != players_.end(); ++it) {
521 MediaPlayerAndroid* player = *it;
522 if (player->player_id() == player_id) {
523 players_.erase(it);
524 break;
529 scoped_ptr<media::MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer(
530 int player_id, media::MediaPlayerAndroid* player) {
531 media::MediaPlayerAndroid* previous_player = NULL;
532 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
533 it != players_.end(); ++it) {
534 if ((*it)->player_id() == player_id) {
535 previous_player = *it;
536 players_.weak_erase(it);
537 players_.push_back(player);
538 break;
541 return scoped_ptr<media::MediaPlayerAndroid>(previous_player);
544 int BrowserMediaPlayerManager::RoutingID() {
545 return render_frame_host_->GetRoutingID();
548 bool BrowserMediaPlayerManager::Send(IPC::Message* msg) {
549 return render_frame_host_->Send(msg);
552 void BrowserMediaPlayerManager::ReleaseFullscreenPlayer(
553 MediaPlayerAndroid* player) {
554 player->Release();
557 void BrowserMediaPlayerManager::OnMediaResourcesRequested(int player_id) {
558 int num_active_player = 0;
559 ScopedVector<MediaPlayerAndroid>::iterator it;
560 for (it = players_.begin(); it != players_.end(); ++it) {
561 if (!(*it)->IsPlayerReady())
562 continue;
564 // The player is already active, ignore it.
565 if ((*it)->player_id() == player_id)
566 return;
567 else
568 num_active_player++;
571 // Number of active players are less than the threshold, do nothing.
572 if (num_active_player < kMediaPlayerThreshold)
573 return;
575 for (it = players_.begin(); it != players_.end(); ++it) {
576 if ((*it)->IsPlayerReady() && !(*it)->IsPlaying() &&
577 fullscreen_player_id_ != (*it)->player_id()) {
578 (*it)->Release();
579 Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(),
580 (*it)->player_id()));
585 void BrowserMediaPlayerManager::OnMediaResourcesReleased(int player_id) {
586 #if defined(VIDEO_HOLE)
587 MediaPlayerAndroid* player = GetPlayer(player_id);
588 if (player && player->IsSurfaceInUse())
589 return;
590 if (external_video_surface_container_)
591 external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
592 #endif // defined(VIDEO_HOLE)
595 } // namespace content