Add a FrameHostMsg_BeginNavigation IPC
[chromium-blink-merge.git] / content / browser / media / android / browser_media_player_manager.cc
blob79b7983145b8f9b54e1d53c0c18a5edb29fe4e4d
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/media_switches.h"
31 using media::MediaPlayerAndroid;
32 using media::MediaPlayerBridge;
33 using media::MediaPlayerManager;
34 using media::MediaSourcePlayer;
36 namespace content {
38 // Threshold on the number of media players per renderer before we start
39 // attempting to release inactive media players.
40 const int kMediaPlayerThreshold = 1;
42 static BrowserMediaPlayerManager::Factory g_factory = NULL;
44 // static
45 void BrowserMediaPlayerManager::RegisterFactory(Factory factory) {
46 g_factory = factory;
49 // static
50 BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
51 RenderFrameHost* rfh) {
52 if (g_factory)
53 return g_factory(rfh);
54 return new BrowserMediaPlayerManager(rfh);
57 ContentViewCoreImpl* BrowserMediaPlayerManager::GetContentViewCore() const {
58 return ContentViewCoreImpl::FromWebContents(web_contents());
61 MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
62 const MediaPlayerHostMsg_Initialize_Params& media_player_params,
63 bool hide_url_log,
64 MediaPlayerManager* manager,
65 BrowserDemuxerAndroid* demuxer) {
66 switch (media_player_params.type) {
67 case MEDIA_PLAYER_TYPE_URL: {
68 const std::string user_agent = GetContentClient()->GetUserAgent();
69 MediaPlayerBridge* media_player_bridge = new MediaPlayerBridge(
70 media_player_params.player_id,
71 media_player_params.url,
72 media_player_params.first_party_for_cookies,
73 user_agent,
74 hide_url_log,
75 manager,
76 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
77 weak_ptr_factory_.GetWeakPtr()),
78 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesReleased,
79 weak_ptr_factory_.GetWeakPtr()),
80 media_player_params.frame_url);
81 BrowserMediaPlayerManager* browser_media_player_manager =
82 static_cast<BrowserMediaPlayerManager*>(manager);
83 ContentViewCoreImpl* content_view_core_impl =
84 static_cast<ContentViewCoreImpl*>(ContentViewCore::FromWebContents(
85 browser_media_player_manager->web_contents_));
86 if (!content_view_core_impl) {
87 // May reach here due to prerendering. Don't extract the metadata
88 // since it is expensive.
89 // TODO(qinmin): extract the metadata once the user decided to load
90 // the page.
91 browser_media_player_manager->OnMediaMetadataChanged(
92 media_player_params.player_id, base::TimeDelta(), 0, 0, false);
93 } else if (!content_view_core_impl->ShouldBlockMediaRequest(
94 media_player_params.url)) {
95 media_player_bridge->Initialize();
97 return media_player_bridge;
100 case MEDIA_PLAYER_TYPE_MEDIA_SOURCE: {
101 return new MediaSourcePlayer(
102 media_player_params.player_id,
103 manager,
104 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
105 weak_ptr_factory_.GetWeakPtr()),
106 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesReleased,
107 weak_ptr_factory_.GetWeakPtr()),
108 demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
109 media_player_params.frame_url);
113 NOTREACHED();
114 return NULL;
117 BrowserMediaPlayerManager::BrowserMediaPlayerManager(
118 RenderFrameHost* render_frame_host)
119 : render_frame_host_(render_frame_host),
120 fullscreen_player_id_(-1),
121 fullscreen_player_is_released_(false),
122 web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
123 weak_ptr_factory_(this) {
126 BrowserMediaPlayerManager::~BrowserMediaPlayerManager() {
127 // During the tear down process, OnDestroyPlayer() may or may not be called
128 // (e.g. the WebContents may be destroyed before the render process). So
129 // we cannot DCHECK(players_.empty()) here. Instead, all media players in
130 // |players_| will be destroyed here because |player_| is a ScopedVector.
133 void BrowserMediaPlayerManager::FullscreenPlayerPlay() {
134 MediaPlayerAndroid* player = GetFullscreenPlayer();
135 if (player) {
136 if (fullscreen_player_is_released_) {
137 video_view_->OpenVideo();
138 fullscreen_player_is_released_ = false;
140 player->Start();
141 Send(new MediaPlayerMsg_DidMediaPlayerPlay(RoutingID(),
142 fullscreen_player_id_));
146 void BrowserMediaPlayerManager::FullscreenPlayerPause() {
147 MediaPlayerAndroid* player = GetFullscreenPlayer();
148 if (player) {
149 player->Pause(true);
150 Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(),
151 fullscreen_player_id_));
155 void BrowserMediaPlayerManager::FullscreenPlayerSeek(int msec) {
156 MediaPlayerAndroid* player = GetFullscreenPlayer();
157 if (player) {
158 // TODO(kbalazs): if |fullscreen_player_is_released_| is true
159 // at this point, player->GetCurrentTime() will be wrong until
160 // FullscreenPlayerPlay (http://crbug.com/322798).
161 OnSeekRequest(fullscreen_player_id_,
162 base::TimeDelta::FromMilliseconds(msec));
166 void BrowserMediaPlayerManager::ExitFullscreen(bool release_media_player) {
167 if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
168 delegate->ToggleFullscreenModeForTab(web_contents_, false);
169 if (!CommandLine::ForCurrentProcess()->HasSwitch(
170 switches::kDisableOverlayFullscreenVideoSubtitle)) {
171 if (RenderWidgetHostViewAndroid* view_android =
172 static_cast<RenderWidgetHostViewAndroid*>(
173 web_contents_->GetRenderWidgetHostView())) {
174 view_android->SetOverlayVideoMode(false);
178 Send(
179 new MediaPlayerMsg_DidExitFullscreen(RoutingID(), fullscreen_player_id_));
180 video_view_.reset();
181 MediaPlayerAndroid* player = GetFullscreenPlayer();
182 fullscreen_player_id_ = -1;
183 if (!player)
184 return;
185 if (release_media_player)
186 ReleaseFullscreenPlayer(player);
187 else
188 player->SetVideoSurface(gfx::ScopedJavaSurface());
191 void BrowserMediaPlayerManager::OnTimeUpdate(int player_id,
192 base::TimeDelta current_time) {
193 Send(
194 new MediaPlayerMsg_MediaTimeUpdate(RoutingID(), player_id, current_time));
197 void BrowserMediaPlayerManager::SetVideoSurface(
198 gfx::ScopedJavaSurface surface) {
199 MediaPlayerAndroid* player = GetFullscreenPlayer();
200 if (!player)
201 return;
203 bool empty_surface = surface.IsEmpty();
204 player->SetVideoSurface(surface.Pass());
205 if (empty_surface)
206 return;
208 Send(new MediaPlayerMsg_DidEnterFullscreen(RoutingID(), player->player_id()));
209 if (CommandLine::ForCurrentProcess()->HasSwitch(
210 switches::kDisableOverlayFullscreenVideoSubtitle)) {
211 return;
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,
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();
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(
250 int player_id,
251 const base::TimeDelta& time_to_seek) {
252 Send(new MediaPlayerMsg_SeekRequest(RoutingID(), player_id, time_to_seek));
255 void BrowserMediaPlayerManager::PauseVideo() {
256 Send(new MediaPlayerMsg_PauseVideo(RoutingID()));
259 void BrowserMediaPlayerManager::OnSeekComplete(
260 int player_id,
261 const base::TimeDelta& current_time) {
262 Send(new MediaPlayerMsg_SeekCompleted(RoutingID(), player_id, current_time));
265 void BrowserMediaPlayerManager::OnError(int player_id, int error) {
266 Send(new MediaPlayerMsg_MediaError(RoutingID(), player_id, error));
267 if (fullscreen_player_id_ == player_id)
268 video_view_->OnMediaPlayerError(error);
271 void BrowserMediaPlayerManager::OnVideoSizeChanged(
272 int player_id, int width, int height) {
273 Send(new MediaPlayerMsg_MediaVideoSizeChanged(RoutingID(), player_id,
274 width, height));
275 if (fullscreen_player_id_ == player_id)
276 video_view_->OnVideoSizeChanged(width, height);
279 media::MediaResourceGetter*
280 BrowserMediaPlayerManager::GetMediaResourceGetter() {
281 if (!media_resource_getter_.get()) {
282 RenderProcessHost* host = web_contents()->GetRenderProcessHost();
283 BrowserContext* context = host->GetBrowserContext();
284 StoragePartition* partition = host->GetStoragePartition();
285 fileapi::FileSystemContext* file_system_context =
286 partition ? partition->GetFileSystemContext() : NULL;
287 // Eventually this needs to be fixed to pass the correct frame rather
288 // than just using the main frame.
289 media_resource_getter_.reset(new MediaResourceGetterImpl(
290 context,
291 file_system_context,
292 host->GetID(),
293 web_contents()->GetMainFrame()->GetRoutingID()));
295 return media_resource_getter_.get();
298 MediaPlayerAndroid* BrowserMediaPlayerManager::GetFullscreenPlayer() {
299 return GetPlayer(fullscreen_player_id_);
302 MediaPlayerAndroid* BrowserMediaPlayerManager::GetPlayer(int player_id) {
303 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
304 it != players_.end(); ++it) {
305 if ((*it)->player_id() == player_id)
306 return *it;
308 return NULL;
311 void BrowserMediaPlayerManager::RequestFullScreen(int player_id) {
312 if (fullscreen_player_id_ == player_id)
313 return;
315 if (fullscreen_player_id_ != -1) {
316 // TODO(qinmin): Determine the correct error code we should report to WMPA.
317 OnError(player_id, MediaPlayerAndroid::MEDIA_ERROR_DECODE);
318 return;
321 Send(new MediaPlayerMsg_RequestFullscreen(RoutingID(), player_id));
324 #if defined(VIDEO_HOLE)
325 bool
326 BrowserMediaPlayerManager::ShouldUseVideoOverlayForEmbeddedEncryptedVideo() {
327 RendererPreferences* prefs = web_contents_->GetMutableRendererPrefs();
328 return prefs->use_video_overlay_for_embedded_encrypted_video;
331 void BrowserMediaPlayerManager::AttachExternalVideoSurface(int player_id,
332 jobject surface) {
333 MediaPlayerAndroid* player = GetPlayer(player_id);
334 if (player) {
335 player->SetVideoSurface(
336 gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
340 void BrowserMediaPlayerManager::DetachExternalVideoSurface(int player_id) {
341 MediaPlayerAndroid* player = GetPlayer(player_id);
342 if (player)
343 player->SetVideoSurface(gfx::ScopedJavaSurface());
346 void BrowserMediaPlayerManager::OnFrameInfoUpdated() {
347 if (external_video_surface_container_)
348 external_video_surface_container_->OnFrameInfoUpdated();
351 void BrowserMediaPlayerManager::OnNotifyExternalSurface(
352 int player_id, bool is_request, const gfx::RectF& rect) {
353 if (!web_contents_)
354 return;
356 if (is_request) {
357 OnRequestExternalSurface(player_id, rect);
359 if (external_video_surface_container_) {
360 external_video_surface_container_->OnExternalVideoSurfacePositionChanged(
361 player_id, rect);
365 void BrowserMediaPlayerManager::OnRequestExternalSurface(
366 int player_id, const gfx::RectF& rect) {
367 if (!external_video_surface_container_) {
368 ContentBrowserClient* client = GetContentClient()->browser();
369 external_video_surface_container_.reset(
370 client->OverrideCreateExternalVideoSurfaceContainer(web_contents_));
372 // It's safe to use base::Unretained(this), because the callbacks will not
373 // be called after running ReleaseExternalVideoSurface().
374 if (external_video_surface_container_) {
375 external_video_surface_container_->RequestExternalVideoSurface(
376 player_id,
377 base::Bind(&BrowserMediaPlayerManager::AttachExternalVideoSurface,
378 base::Unretained(this)),
379 base::Bind(&BrowserMediaPlayerManager::DetachExternalVideoSurface,
380 base::Unretained(this)));
383 #endif // defined(VIDEO_HOLE)
385 void BrowserMediaPlayerManager::OnEnterFullscreen(int player_id) {
386 DCHECK_EQ(fullscreen_player_id_, -1);
387 #if defined(VIDEO_HOLE)
388 if (external_video_surface_container_)
389 external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
390 #endif // defined(VIDEO_HOLE)
391 if (video_view_.get()) {
392 fullscreen_player_id_ = player_id;
393 video_view_->OpenVideo();
394 return;
395 } else if (!ContentVideoView::GetInstance()) {
396 // In Android WebView, two ContentViewCores could both try to enter
397 // fullscreen video, we just ignore the second one.
398 video_view_.reset(new ContentVideoView(this));
399 base::android::ScopedJavaLocalRef<jobject> j_content_video_view =
400 video_view_->GetJavaObject(base::android::AttachCurrentThread());
401 if (!j_content_video_view.is_null()) {
402 fullscreen_player_id_ = player_id;
403 return;
407 // Force the second video to exit fullscreen.
408 // TODO(qinmin): There is no need to send DidEnterFullscreen message.
409 // However, if we don't send the message, page layers will not be
410 // correctly restored. http:crbug.com/367346.
411 Send(new MediaPlayerMsg_DidEnterFullscreen(RoutingID(), player_id));
412 Send(new MediaPlayerMsg_DidExitFullscreen(RoutingID(), player_id));
413 video_view_.reset();
416 void BrowserMediaPlayerManager::OnExitFullscreen(int player_id) {
417 if (fullscreen_player_id_ == player_id) {
418 MediaPlayerAndroid* player = GetPlayer(player_id);
419 if (player)
420 player->SetVideoSurface(gfx::ScopedJavaSurface());
421 video_view_->OnExitFullscreen();
425 void BrowserMediaPlayerManager::OnInitialize(
426 const MediaPlayerHostMsg_Initialize_Params& media_player_params) {
427 DCHECK(media_player_params.type != MEDIA_PLAYER_TYPE_MEDIA_SOURCE ||
428 media_player_params.demuxer_client_id > 0)
429 << "Media source players must have positive demuxer client IDs: "
430 << media_player_params.demuxer_client_id;
432 RemovePlayer(media_player_params.player_id);
434 RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>(
435 web_contents()->GetRenderProcessHost());
436 MediaPlayerAndroid* player = CreateMediaPlayer(
437 media_player_params,
439 host->GetBrowserContext()->IsOffTheRecord(), this,
440 host->browser_demuxer_android());
442 if (!player)
443 return;
445 AddPlayer(player);
448 void BrowserMediaPlayerManager::OnStart(int player_id) {
449 MediaPlayerAndroid* player = GetPlayer(player_id);
450 if (!player)
451 return;
452 player->Start();
453 if (fullscreen_player_id_ == player_id && fullscreen_player_is_released_) {
454 video_view_->OpenVideo();
455 fullscreen_player_is_released_ = false;
459 void BrowserMediaPlayerManager::OnSeek(
460 int player_id,
461 const base::TimeDelta& time) {
462 MediaPlayerAndroid* player = GetPlayer(player_id);
463 if (player)
464 player->SeekTo(time);
467 void BrowserMediaPlayerManager::OnPause(
468 int player_id,
469 bool is_media_related_action) {
470 MediaPlayerAndroid* player = GetPlayer(player_id);
471 if (player)
472 player->Pause(is_media_related_action);
475 void BrowserMediaPlayerManager::OnSetVolume(int player_id, double volume) {
476 MediaPlayerAndroid* player = GetPlayer(player_id);
477 if (player)
478 player->SetVolume(volume);
481 void BrowserMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) {
482 // To be overridden by subclasses.
485 void BrowserMediaPlayerManager::OnReleaseResources(int player_id) {
486 MediaPlayerAndroid* player = GetPlayer(player_id);
487 if (player)
488 player->Release();
489 if (player_id == fullscreen_player_id_)
490 fullscreen_player_is_released_ = true;
493 void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) {
494 RemovePlayer(player_id);
495 if (fullscreen_player_id_ == player_id)
496 fullscreen_player_id_ = -1;
499 void BrowserMediaPlayerManager::AddPlayer(MediaPlayerAndroid* player) {
500 DCHECK(!GetPlayer(player->player_id()));
501 players_.push_back(player);
504 void BrowserMediaPlayerManager::RemovePlayer(int player_id) {
505 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
506 it != players_.end(); ++it) {
507 MediaPlayerAndroid* player = *it;
508 if (player->player_id() == player_id) {
509 players_.erase(it);
510 break;
515 scoped_ptr<media::MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer(
516 int player_id, media::MediaPlayerAndroid* player) {
517 media::MediaPlayerAndroid* previous_player = NULL;
518 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
519 it != players_.end(); ++it) {
520 if ((*it)->player_id() == player_id) {
521 previous_player = *it;
522 players_.weak_erase(it);
523 players_.push_back(player);
524 break;
527 return scoped_ptr<media::MediaPlayerAndroid>(previous_player);
530 int BrowserMediaPlayerManager::RoutingID() {
531 return render_frame_host_->GetRoutingID();
534 bool BrowserMediaPlayerManager::Send(IPC::Message* msg) {
535 return render_frame_host_->Send(msg);
538 void BrowserMediaPlayerManager::ReleaseFullscreenPlayer(
539 MediaPlayerAndroid* player) {
540 player->Release();
543 void BrowserMediaPlayerManager::OnMediaResourcesRequested(int player_id) {
544 int num_active_player = 0;
545 ScopedVector<MediaPlayerAndroid>::iterator it;
546 for (it = players_.begin(); it != players_.end(); ++it) {
547 if (!(*it)->IsPlayerReady())
548 continue;
550 // The player is already active, ignore it.
551 if ((*it)->player_id() == player_id)
552 return;
553 else
554 num_active_player++;
557 // Number of active players are less than the threshold, do nothing.
558 if (num_active_player < kMediaPlayerThreshold)
559 return;
561 for (it = players_.begin(); it != players_.end(); ++it) {
562 if ((*it)->IsPlayerReady() && !(*it)->IsPlaying() &&
563 fullscreen_player_id_ != (*it)->player_id()) {
564 (*it)->Release();
565 Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(),
566 (*it)->player_id()));
571 void BrowserMediaPlayerManager::OnMediaResourcesReleased(int player_id) {
572 #if defined(VIDEO_HOLE)
573 MediaPlayerAndroid* player = GetPlayer(player_id);
574 if (player && player->IsSurfaceInUse())
575 return;
576 if (external_video_surface_container_)
577 external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
578 #endif // defined(VIDEO_HOLE)
581 } // namespace content