Remove PlatformFile from profile_browsertest
[chromium-blink-merge.git] / content / browser / media / android / browser_media_player_manager.cc
blob40e18250858e3ed47ab9fe1dce604d8f34fb4bd2
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/command_line.h"
8 #include "content/browser/android/content_view_core_impl.h"
9 #include "content/browser/media/android/browser_demuxer_android.h"
10 #include "content/browser/media/android/media_resource_getter_impl.h"
11 #include "content/browser/renderer_host/render_view_host_impl.h"
12 #include "content/browser/web_contents/web_contents_view_android.h"
13 #include "content/common/media/cdm_messages.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/render_process_host.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/storage_partition.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/browser/web_contents_delegate.h"
23 #include "content/public/common/content_client.h"
24 #include "content/public/common/content_switches.h"
25 #include "media/base/android/media_drm_bridge.h"
26 #include "media/base/android/media_player_bridge.h"
27 #include "media/base/android/media_source_player.h"
28 #include "media/base/media_switches.h"
30 using media::MediaDrmBridge;
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 // Maximum lengths for various EME API parameters. These are checks to
43 // prevent unnecessarily large parameters from being passed around, and the
44 // lengths are somewhat arbitrary as the EME spec doesn't specify any limits.
45 const size_t kMaxInitDataLength = 64 * 1024; // 64 KB
46 const size_t kMaxSessionResponseLength = 64 * 1024; // 64 KB
47 const size_t kMaxKeySystemLength = 256;
49 static BrowserMediaPlayerManager::Factory g_factory = NULL;
51 // static
52 void BrowserMediaPlayerManager::RegisterFactory(Factory factory) {
53 g_factory = factory;
56 // static
57 BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
58 RenderViewHost* rvh) {
59 if (g_factory)
60 return g_factory(rvh);
61 return new BrowserMediaPlayerManager(rvh);
64 ContentViewCoreImpl* BrowserMediaPlayerManager::GetContentViewCore() const {
65 return ContentViewCoreImpl::FromWebContents(web_contents());
68 MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
69 MediaPlayerHostMsg_Initialize_Type type,
70 int player_id,
71 const GURL& url,
72 const GURL& first_party_for_cookies,
73 int demuxer_client_id,
74 bool hide_url_log,
75 MediaPlayerManager* manager,
76 BrowserDemuxerAndroid* demuxer) {
77 switch (type) {
78 case MEDIA_PLAYER_TYPE_URL: {
79 const std::string user_agent = GetContentClient()->GetUserAgent();
80 MediaPlayerBridge* media_player_bridge = new MediaPlayerBridge(
81 player_id,
82 url,
83 first_party_for_cookies,
84 user_agent,
85 hide_url_log,
86 manager,
87 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
88 weak_ptr_factory_.GetWeakPtr()),
89 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesReleased,
90 weak_ptr_factory_.GetWeakPtr()));
91 BrowserMediaPlayerManager* browser_media_player_manager =
92 static_cast<BrowserMediaPlayerManager*>(manager);
93 ContentViewCoreImpl* content_view_core_impl =
94 static_cast<ContentViewCoreImpl*>(ContentViewCore::FromWebContents(
95 browser_media_player_manager->web_contents_));
96 if (!content_view_core_impl) {
97 // May reach here due to prerendering. Don't extract the metadata
98 // since it is expensive.
99 // TODO(qinmin): extract the metadata once the user decided to load
100 // the page.
101 browser_media_player_manager->OnMediaMetadataChanged(
102 player_id, base::TimeDelta(), 0, 0, false);
103 } else if (!content_view_core_impl->ShouldBlockMediaRequest(url)) {
104 media_player_bridge->Initialize();
106 return media_player_bridge;
109 case MEDIA_PLAYER_TYPE_MEDIA_SOURCE: {
110 return new MediaSourcePlayer(
111 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(demuxer_client_id));
121 NOTREACHED();
122 return NULL;
125 BrowserMediaPlayerManager::BrowserMediaPlayerManager(
126 RenderViewHost* render_view_host)
127 : WebContentsObserver(WebContents::FromRenderViewHost(render_view_host)),
128 fullscreen_player_id_(-1),
129 pending_fullscreen_player_id_(-1),
130 fullscreen_player_is_released_(false),
131 web_contents_(WebContents::FromRenderViewHost(render_view_host)),
132 weak_ptr_factory_(this) {
135 BrowserMediaPlayerManager::~BrowserMediaPlayerManager() {}
137 bool BrowserMediaPlayerManager::OnMessageReceived(const IPC::Message& msg) {
138 bool handled = true;
139 IPC_BEGIN_MESSAGE_MAP(BrowserMediaPlayerManager, msg)
140 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_EnterFullscreen, OnEnterFullscreen)
141 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_ExitFullscreen, OnExitFullscreen)
142 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Initialize, OnInitialize)
143 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Start, OnStart)
144 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Seek, OnSeek)
145 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Pause, OnPause)
146 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_SetVolume, OnSetVolume)
147 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_SetPoster, OnSetPoster)
148 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Release, OnReleaseResources)
149 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_DestroyMediaPlayer, OnDestroyPlayer)
150 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_DestroyAllMediaPlayers,
151 DestroyAllMediaPlayers)
152 IPC_MESSAGE_HANDLER(CdmHostMsg_InitializeCdm, OnInitializeCdm)
153 IPC_MESSAGE_HANDLER(CdmHostMsg_CreateSession, OnCreateSession)
154 IPC_MESSAGE_HANDLER(CdmHostMsg_UpdateSession, OnUpdateSession)
155 IPC_MESSAGE_HANDLER(CdmHostMsg_ReleaseSession, OnReleaseSession)
156 IPC_MESSAGE_HANDLER(CdmHostMsg_DestroyCdm, OnDestroyCdm)
157 #if defined(VIDEO_HOLE)
158 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_NotifyExternalSurface,
159 OnNotifyExternalSurface)
160 #endif // defined(VIDEO_HOLE)
161 IPC_MESSAGE_UNHANDLED(handled = false)
162 IPC_END_MESSAGE_MAP()
163 return handled;
166 void BrowserMediaPlayerManager::FullscreenPlayerPlay() {
167 MediaPlayerAndroid* player = GetFullscreenPlayer();
168 if (player) {
169 if (fullscreen_player_is_released_) {
170 video_view_->OpenVideo();
171 fullscreen_player_is_released_ = false;
173 player->Start();
174 Send(new MediaPlayerMsg_DidMediaPlayerPlay(
175 routing_id(), fullscreen_player_id_));
179 void BrowserMediaPlayerManager::FullscreenPlayerPause() {
180 MediaPlayerAndroid* player = GetFullscreenPlayer();
181 if (player) {
182 player->Pause(true);
183 Send(new MediaPlayerMsg_DidMediaPlayerPause(
184 routing_id(), fullscreen_player_id_));
188 void BrowserMediaPlayerManager::FullscreenPlayerSeek(int msec) {
189 MediaPlayerAndroid* player = GetFullscreenPlayer();
190 if (player) {
191 // TODO(kbalazs): if |fullscreen_player_is_released_| is true
192 // at this point, player->GetCurrentTime() will be wrong until
193 // FullscreenPlayerPlay (http://crbug.com/322798).
194 OnSeekRequest(fullscreen_player_id_,
195 base::TimeDelta::FromMilliseconds(msec));
199 void BrowserMediaPlayerManager::ExitFullscreen(bool release_media_player) {
200 if (!CommandLine::ForCurrentProcess()->HasSwitch(
201 switches::kDisableOverlayFullscreenVideoSubtitle)) {
202 if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
203 delegate->ToggleFullscreenModeForTab(web_contents_, false);
204 if (RenderWidgetHostViewAndroid* view_android =
205 static_cast<RenderWidgetHostViewAndroid*>(
206 web_contents_->GetRenderWidgetHostView())) {
207 view_android->SetOverlayVideoMode(false);
211 Send(new MediaPlayerMsg_DidExitFullscreen(
212 routing_id(), fullscreen_player_id_));
213 video_view_.reset();
214 MediaPlayerAndroid* player = GetFullscreenPlayer();
215 fullscreen_player_id_ = -1;
216 if (!player)
217 return;
218 if (release_media_player)
219 ReleaseFullscreenPlayer(player);
220 else
221 player->SetVideoSurface(gfx::ScopedJavaSurface());
224 void BrowserMediaPlayerManager::OnTimeUpdate(int player_id,
225 base::TimeDelta current_time) {
226 Send(new MediaPlayerMsg_MediaTimeUpdate(
227 routing_id(), player_id, current_time));
230 void BrowserMediaPlayerManager::SetVideoSurface(
231 gfx::ScopedJavaSurface surface) {
232 MediaPlayerAndroid* player = GetFullscreenPlayer();
233 if (!player)
234 return;
236 bool empty_surface = surface.IsEmpty();
237 player->SetVideoSurface(surface.Pass());
238 if (empty_surface)
239 return;
241 Send(new MediaPlayerMsg_DidEnterFullscreen(routing_id(),
242 player->player_id()));
243 if (CommandLine::ForCurrentProcess()->HasSwitch(
244 switches::kDisableOverlayFullscreenVideoSubtitle)) {
245 return;
247 if (RenderWidgetHostViewAndroid* view_android =
248 static_cast<RenderWidgetHostViewAndroid*>(
249 web_contents_->GetRenderWidgetHostView())) {
250 view_android->SetOverlayVideoMode(true);
252 if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
253 delegate->ToggleFullscreenModeForTab(web_contents_, true);
256 void BrowserMediaPlayerManager::OnMediaMetadataChanged(
257 int player_id, base::TimeDelta duration, int width, int height,
258 bool success) {
259 Send(new MediaPlayerMsg_MediaMetadataChanged(
260 routing_id(), player_id, duration, width, height, success));
261 if (fullscreen_player_id_ == player_id)
262 video_view_->UpdateMediaMetadata();
265 void BrowserMediaPlayerManager::OnPlaybackComplete(int player_id) {
266 Send(new MediaPlayerMsg_MediaPlaybackCompleted(routing_id(), player_id));
267 if (fullscreen_player_id_ == player_id)
268 video_view_->OnPlaybackComplete();
271 void BrowserMediaPlayerManager::OnMediaInterrupted(int player_id) {
272 // Tell WebKit that the audio should be paused, then release all resources
273 Send(new MediaPlayerMsg_MediaPlayerReleased(routing_id(), player_id));
274 OnReleaseResources(player_id);
277 void BrowserMediaPlayerManager::OnBufferingUpdate(
278 int player_id, int percentage) {
279 Send(new MediaPlayerMsg_MediaBufferingUpdate(
280 routing_id(), player_id, percentage));
281 if (fullscreen_player_id_ == player_id)
282 video_view_->OnBufferingUpdate(percentage);
285 void BrowserMediaPlayerManager::OnSeekRequest(
286 int player_id,
287 const base::TimeDelta& time_to_seek) {
288 Send(new MediaPlayerMsg_SeekRequest(routing_id(), player_id, time_to_seek));
291 void BrowserMediaPlayerManager::OnSeekComplete(
292 int player_id,
293 const base::TimeDelta& current_time) {
294 Send(new MediaPlayerMsg_SeekCompleted(routing_id(), player_id, current_time));
297 void BrowserMediaPlayerManager::OnError(int player_id, int error) {
298 Send(new MediaPlayerMsg_MediaError(routing_id(), player_id, error));
299 if (fullscreen_player_id_ == player_id)
300 video_view_->OnMediaPlayerError(error);
303 void BrowserMediaPlayerManager::OnVideoSizeChanged(
304 int player_id, int width, int height) {
305 Send(new MediaPlayerMsg_MediaVideoSizeChanged(routing_id(), player_id,
306 width, height));
307 if (fullscreen_player_id_ == player_id)
308 video_view_->OnVideoSizeChanged(width, height);
311 media::MediaResourceGetter*
312 BrowserMediaPlayerManager::GetMediaResourceGetter() {
313 if (!media_resource_getter_.get()) {
314 RenderProcessHost* host = web_contents()->GetRenderProcessHost();
315 BrowserContext* context = host->GetBrowserContext();
316 StoragePartition* partition = host->GetStoragePartition();
317 fileapi::FileSystemContext* file_system_context =
318 partition ? partition->GetFileSystemContext() : NULL;
319 media_resource_getter_.reset(new MediaResourceGetterImpl(
320 context, file_system_context, host->GetID(), routing_id()));
322 return media_resource_getter_.get();
325 MediaPlayerAndroid* BrowserMediaPlayerManager::GetFullscreenPlayer() {
326 return GetPlayer(fullscreen_player_id_);
329 MediaPlayerAndroid* BrowserMediaPlayerManager::GetPlayer(int player_id) {
330 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
331 it != players_.end(); ++it) {
332 if ((*it)->player_id() == player_id)
333 return *it;
335 return NULL;
338 MediaDrmBridge* BrowserMediaPlayerManager::GetDrmBridge(int cdm_id) {
339 for (ScopedVector<MediaDrmBridge>::iterator it = drm_bridges_.begin();
340 it != drm_bridges_.end(); ++it) {
341 if ((*it)->cdm_id() == cdm_id)
342 return *it;
344 return NULL;
347 void BrowserMediaPlayerManager::DestroyAllMediaPlayers() {
348 players_.clear();
349 drm_bridges_.clear();
350 if (fullscreen_player_id_ != -1) {
351 video_view_.reset();
352 fullscreen_player_id_ = -1;
356 void BrowserMediaPlayerManager::OnProtectedSurfaceRequested(int player_id) {
357 if (fullscreen_player_id_ == player_id)
358 return;
360 if (fullscreen_player_id_ != -1) {
361 // TODO(qinmin): Determine the correct error code we should report to WMPA.
362 OnError(player_id, MediaPlayerAndroid::MEDIA_ERROR_DECODE);
363 return;
366 // If the player is pending approval, wait for the approval to happen.
367 if (cdm_ids_pending_approval_.end() !=
368 cdm_ids_pending_approval_.find(player_id)) {
369 pending_fullscreen_player_id_ = player_id;
370 return;
373 // Send an IPC to the render process to request the video element to enter
374 // fullscreen. OnEnterFullscreen() will be called later on success.
375 // This guarantees the fullscreen video will be rendered correctly.
376 // During the process, DisableFullscreenEncryptedMediaPlayback() may get
377 // called before or after OnEnterFullscreen(). If it is called before
378 // OnEnterFullscreen(), the player will not enter fullscreen. And it will
379 // retry the process once CreateSession() is allowed to proceed.
380 // TODO(qinmin): make this flag default on android.
381 if (CommandLine::ForCurrentProcess()->HasSwitch(
382 switches::kDisableGestureRequirementForMediaFullscreen)) {
383 Send(new MediaPlayerMsg_RequestFullscreen(routing_id(), player_id));
387 // The following 5 functions are EME MediaKeySession events.
389 void BrowserMediaPlayerManager::OnSessionCreated(
390 int cdm_id,
391 uint32 session_id,
392 const std::string& web_session_id) {
393 Send(new CdmMsg_SessionCreated(
394 routing_id(), cdm_id, session_id, web_session_id));
397 void BrowserMediaPlayerManager::OnSessionMessage(
398 int cdm_id,
399 uint32 session_id,
400 const std::vector<uint8>& message,
401 const GURL& destination_url) {
402 Send(new CdmMsg_SessionMessage(
403 routing_id(), cdm_id, session_id, message, destination_url));
406 void BrowserMediaPlayerManager::OnSessionReady(int cdm_id, uint32 session_id) {
407 Send(new CdmMsg_SessionReady(routing_id(), cdm_id, session_id));
410 void BrowserMediaPlayerManager::OnSessionClosed(int cdm_id, uint32 session_id) {
411 Send(new CdmMsg_SessionClosed(routing_id(), cdm_id, session_id));
414 void BrowserMediaPlayerManager::OnSessionError(
415 int cdm_id,
416 uint32 session_id,
417 media::MediaKeys::KeyError error_code,
418 uint32 system_code) {
419 Send(new CdmMsg_SessionError(
420 routing_id(), cdm_id, session_id, error_code, system_code));
423 #if defined(VIDEO_HOLE)
424 void BrowserMediaPlayerManager::AttachExternalVideoSurface(int player_id,
425 jobject surface) {
426 MediaPlayerAndroid* player = GetPlayer(player_id);
427 if (player) {
428 player->SetVideoSurface(
429 gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
433 void BrowserMediaPlayerManager::DetachExternalVideoSurface(int player_id) {
434 MediaPlayerAndroid* player = GetPlayer(player_id);
435 if (player)
436 player->SetVideoSurface(gfx::ScopedJavaSurface());
439 void BrowserMediaPlayerManager::OnNotifyExternalSurface(
440 int player_id, bool is_request, const gfx::RectF& rect) {
441 if (!web_contents_)
442 return;
444 ExternalVideoSurfaceContainer::CreateForWebContents(web_contents_);
445 ExternalVideoSurfaceContainer* surface_container =
446 ExternalVideoSurfaceContainer::FromWebContents(web_contents_);
447 if (!surface_container)
448 return;
450 if (is_request) {
451 // It's safe to use base::Unretained(this), because the callbacks will not
452 // be called after running ReleaseExternalVideoSurface().
453 surface_container->RequestExternalVideoSurface(
454 player_id,
455 base::Bind(&BrowserMediaPlayerManager::AttachExternalVideoSurface,
456 base::Unretained(this)),
457 base::Bind(&BrowserMediaPlayerManager::DetachExternalVideoSurface,
458 base::Unretained(this)));
460 surface_container->OnExternalVideoSurfacePositionChanged(player_id, rect);
462 #endif // defined(VIDEO_HOLE)
464 void BrowserMediaPlayerManager::DisableFullscreenEncryptedMediaPlayback() {
465 if (fullscreen_player_id_ == -1)
466 return;
468 // If the fullscreen player is not playing back encrypted video, do nothing.
469 MediaDrmBridge* drm_bridge = GetDrmBridge(fullscreen_player_id_);
470 if (!drm_bridge)
471 return;
473 // Exit fullscreen.
474 pending_fullscreen_player_id_ = fullscreen_player_id_;
475 OnExitFullscreen(fullscreen_player_id_);
478 void BrowserMediaPlayerManager::OnEnterFullscreen(int player_id) {
479 DCHECK_EQ(fullscreen_player_id_, -1);
480 if (cdm_ids_pending_approval_.find(player_id) !=
481 cdm_ids_pending_approval_.end()) {
482 return;
485 #if defined(VIDEO_HOLE)
486 ExternalVideoSurfaceContainer* surface_container =
487 ExternalVideoSurfaceContainer::FromWebContents(web_contents_);
488 if (surface_container)
489 surface_container->ReleaseExternalVideoSurface(player_id);
490 #endif // defined(VIDEO_HOLE)
491 if (video_view_.get()) {
492 fullscreen_player_id_ = player_id;
493 video_view_->OpenVideo();
494 } else if (!ContentVideoView::GetInstance()) {
495 // In Android WebView, two ContentViewCores could both try to enter
496 // fullscreen video, we just ignore the second one.
497 fullscreen_player_id_ = player_id;
498 video_view_.reset(new ContentVideoView(this));
502 void BrowserMediaPlayerManager::OnExitFullscreen(int player_id) {
503 if (fullscreen_player_id_ == player_id) {
504 MediaPlayerAndroid* player = GetPlayer(player_id);
505 if (player)
506 player->SetVideoSurface(gfx::ScopedJavaSurface());
507 video_view_->OnExitFullscreen();
511 void BrowserMediaPlayerManager::OnInitialize(
512 MediaPlayerHostMsg_Initialize_Type type,
513 int player_id,
514 const GURL& url,
515 const GURL& first_party_for_cookies,
516 int demuxer_client_id) {
517 DCHECK(type != MEDIA_PLAYER_TYPE_MEDIA_SOURCE || demuxer_client_id > 0)
518 << "Media source players must have positive demuxer client IDs: "
519 << demuxer_client_id;
521 RemovePlayer(player_id);
523 RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>(
524 web_contents()->GetRenderProcessHost());
525 AddPlayer(CreateMediaPlayer(
526 type, player_id, url, first_party_for_cookies, demuxer_client_id,
527 host->GetBrowserContext()->IsOffTheRecord(), this,
528 host->browser_demuxer_android()));
531 void BrowserMediaPlayerManager::OnStart(int player_id) {
532 MediaPlayerAndroid* player = GetPlayer(player_id);
533 if (player)
534 player->Start();
537 void BrowserMediaPlayerManager::OnSeek(
538 int player_id,
539 const base::TimeDelta& time) {
540 MediaPlayerAndroid* player = GetPlayer(player_id);
541 if (player)
542 player->SeekTo(time);
545 void BrowserMediaPlayerManager::OnPause(
546 int player_id,
547 bool is_media_related_action) {
548 MediaPlayerAndroid* player = GetPlayer(player_id);
549 if (player)
550 player->Pause(is_media_related_action);
553 void BrowserMediaPlayerManager::OnSetVolume(int player_id, double volume) {
554 MediaPlayerAndroid* player = GetPlayer(player_id);
555 if (player)
556 player->SetVolume(volume);
559 void BrowserMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) {
560 // To be overridden by subclasses.
563 void BrowserMediaPlayerManager::OnReleaseResources(int player_id) {
564 MediaPlayerAndroid* player = GetPlayer(player_id);
565 if (player)
566 player->Release();
567 if (player_id == fullscreen_player_id_)
568 fullscreen_player_is_released_ = true;
571 void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) {
572 RemovePlayer(player_id);
573 if (fullscreen_player_id_ == player_id)
574 fullscreen_player_id_ = -1;
577 void BrowserMediaPlayerManager::OnInitializeCdm(int cdm_id,
578 const std::string& key_system,
579 const GURL& frame_url) {
580 if (key_system.size() > kMaxKeySystemLength) {
581 // This failure will be discovered and reported by OnCreateSession()
582 // as GetDrmBridge() will return null.
583 NOTREACHED() << "Invalid key system: " << key_system;
584 return;
587 if (!MediaDrmBridge::IsKeySystemSupportedWithType(key_system, "")) {
588 NOTREACHED() << "Unsupported key system: " << key_system;
589 return;
592 AddDrmBridge(cdm_id, key_system, frame_url);
593 // In EME v0.1b MediaKeys lives in the media element. So the |cdm_id|
594 // is the same as the |player_id|.
595 OnSetMediaKeys(cdm_id, cdm_id);
598 void BrowserMediaPlayerManager::OnCreateSession(
599 int cdm_id,
600 uint32 session_id,
601 CdmHostMsg_CreateSession_ContentType content_type,
602 const std::vector<uint8>& init_data) {
603 if (init_data.size() > kMaxInitDataLength) {
604 LOG(WARNING) << "InitData for ID: " << cdm_id
605 << " too long: " << init_data.size();
606 OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
607 return;
610 // Convert the session content type into a MIME type. "audio" and "video"
611 // don't matter, so using "video" for the MIME type.
612 // Ref:
613 // https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-createsession
614 std::string mime_type;
615 switch (content_type) {
616 case CREATE_SESSION_TYPE_WEBM:
617 mime_type = "video/webm";
618 break;
619 case CREATE_SESSION_TYPE_MP4:
620 mime_type = "video/mp4";
621 break;
622 default:
623 NOTREACHED();
624 return;
627 if (CommandLine::ForCurrentProcess()
628 ->HasSwitch(switches::kDisableInfobarForProtectedMediaIdentifier)) {
629 CreateSessionIfPermitted(cdm_id, session_id, mime_type, init_data, true);
630 return;
633 MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
634 if (!drm_bridge) {
635 DLOG(WARNING) << "No MediaDrmBridge for ID: " << cdm_id << " found";
636 OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
637 return;
640 if (cdm_ids_approved_.find(cdm_id) == cdm_ids_approved_.end()) {
641 cdm_ids_pending_approval_.insert(cdm_id);
644 BrowserContext* context =
645 web_contents()->GetRenderProcessHost()->GetBrowserContext();
647 context->RequestProtectedMediaIdentifierPermission(
648 web_contents()->GetRenderProcessHost()->GetID(),
649 web_contents()->GetRenderViewHost()->GetRoutingID(),
650 static_cast<int>(session_id),
651 cdm_id,
652 drm_bridge->frame_url(),
653 base::Bind(&BrowserMediaPlayerManager::CreateSessionIfPermitted,
654 weak_ptr_factory_.GetWeakPtr(),
655 cdm_id,
656 session_id,
657 mime_type,
658 init_data));
661 void BrowserMediaPlayerManager::OnUpdateSession(
662 int cdm_id,
663 uint32 session_id,
664 const std::vector<uint8>& response) {
665 MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
666 if (!drm_bridge) {
667 DLOG(WARNING) << "No MediaDrmBridge for ID: " << cdm_id << " found";
668 OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
669 return;
672 if (response.size() > kMaxSessionResponseLength) {
673 LOG(WARNING) << "Response for ID: " << cdm_id
674 << " too long: " << response.size();
675 OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
676 return;
679 drm_bridge->UpdateSession(session_id, &response[0], response.size());
680 // In EME v0.1b MediaKeys lives in the media element. So the |cdm_id|
681 // is the same as the |player_id|.
682 // TODO(xhwang): Separate |cdm_id| and |player_id|.
683 MediaPlayerAndroid* player = GetPlayer(cdm_id);
684 if (player)
685 player->OnKeyAdded();
688 void BrowserMediaPlayerManager::OnReleaseSession(int cdm_id,
689 uint32 session_id) {
690 MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
691 if (!drm_bridge) {
692 DLOG(WARNING) << "No MediaDrmBridge for ID: " << cdm_id << " found";
693 OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
694 return;
697 drm_bridge->ReleaseSession(session_id);
700 void BrowserMediaPlayerManager::OnDestroyCdm(int cdm_id) {
701 MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
702 if (!drm_bridge) return;
704 CancelAllPendingSessionCreations(cdm_id);
705 RemoveDrmBridge(cdm_id);
708 void BrowserMediaPlayerManager::CancelAllPendingSessionCreations(int cdm_id) {
709 BrowserContext* context =
710 web_contents()->GetRenderProcessHost()->GetBrowserContext();
711 context->CancelProtectedMediaIdentifierPermissionRequests(cdm_id);
714 void BrowserMediaPlayerManager::AddPlayer(MediaPlayerAndroid* player) {
715 DCHECK(!GetPlayer(player->player_id()));
716 players_.push_back(player);
719 void BrowserMediaPlayerManager::RemovePlayer(int player_id) {
720 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
721 it != players_.end(); ++it) {
722 MediaPlayerAndroid* player = *it;
723 if (player->player_id() == player_id) {
724 players_.erase(it);
725 break;
730 scoped_ptr<media::MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer(
731 int player_id, media::MediaPlayerAndroid* player) {
732 media::MediaPlayerAndroid* previous_player = NULL;
733 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
734 it != players_.end(); ++it) {
735 if ((*it)->player_id() == player_id) {
736 previous_player = *it;
737 players_.weak_erase(it);
738 players_.push_back(player);
739 break;
742 return scoped_ptr<media::MediaPlayerAndroid>(previous_player);
745 void BrowserMediaPlayerManager::AddDrmBridge(int cdm_id,
746 const std::string& key_system,
747 const GURL& frame_url) {
748 DCHECK(!GetDrmBridge(cdm_id));
750 scoped_ptr<MediaDrmBridge> drm_bridge(
751 MediaDrmBridge::Create(cdm_id, key_system, frame_url, this));
752 if (!drm_bridge) {
753 // This failure will be discovered and reported by OnCreateSession()
754 // as GetDrmBridge() will return null.
755 DVLOG(1) << "failed to create drm bridge.";
756 return;
759 // TODO(xhwang/ddorwin): Pass the security level from key system.
760 MediaDrmBridge::SecurityLevel security_level =
761 MediaDrmBridge::SECURITY_LEVEL_3;
762 if (CommandLine::ForCurrentProcess()
763 ->HasSwitch(switches::kMediaDrmEnableNonCompositing)) {
764 security_level = MediaDrmBridge::SECURITY_LEVEL_1;
766 if (!drm_bridge->SetSecurityLevel(security_level)) {
767 DVLOG(1) << "failed to set security level " << security_level;
768 return;
771 drm_bridges_.push_back(drm_bridge.release());
774 void BrowserMediaPlayerManager::RemoveDrmBridge(int cdm_id) {
775 for (ScopedVector<MediaDrmBridge>::iterator it = drm_bridges_.begin();
776 it != drm_bridges_.end(); ++it) {
777 if ((*it)->cdm_id() == cdm_id) {
778 drm_bridges_.erase(it);
779 break;
784 void BrowserMediaPlayerManager::OnSetMediaKeys(int player_id, int cdm_id) {
785 MediaPlayerAndroid* player = GetPlayer(player_id);
786 MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
787 if (!player || !drm_bridge) {
788 DVLOG(1) << "OnSetMediaKeys(): Player and MediaKeys must be present.";
789 return;
791 // TODO(qinmin): add the logic to decide whether we should create the
792 // fullscreen surface for EME lv1.
793 player->SetDrmBridge(drm_bridge);
796 void BrowserMediaPlayerManager::CreateSessionIfPermitted(
797 int cdm_id,
798 uint32 session_id,
799 const std::string& content_type,
800 const std::vector<uint8>& init_data,
801 bool permitted) {
802 if (!permitted) {
803 OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
804 return;
807 MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
808 if (!drm_bridge) {
809 DLOG(WARNING) << "No MediaDrmBridge for ID: " << cdm_id << " found";
810 OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
811 return;
813 cdm_ids_pending_approval_.erase(cdm_id);
814 cdm_ids_approved_.insert(cdm_id);
816 if (!drm_bridge->CreateSession(
817 session_id, content_type, &init_data[0], init_data.size())) {
818 return;
821 // TODO(xhwang): Move the following code to OnSessionReady.
823 // TODO(qinmin): For prefixed EME implementation, |cdm_id| and player_id are
824 // identical. This will not be the case for unpredixed EME. See:
825 // http://crbug.com/338910
826 if (pending_fullscreen_player_id_ != cdm_id)
827 return;
829 pending_fullscreen_player_id_ = -1;
830 MediaPlayerAndroid* player = GetPlayer(cdm_id);
831 if (player->IsPlaying())
832 OnProtectedSurfaceRequested(cdm_id);
835 void BrowserMediaPlayerManager::ReleaseFullscreenPlayer(
836 MediaPlayerAndroid* player) {
837 player->Release();
840 void BrowserMediaPlayerManager::OnMediaResourcesRequested(int player_id) {
841 int num_active_player = 0;
842 ScopedVector<MediaPlayerAndroid>::iterator it;
843 for (it = players_.begin(); it != players_.end(); ++it) {
844 if (!(*it)->IsPlayerReady())
845 continue;
847 // The player is already active, ignore it.
848 if ((*it)->player_id() == player_id)
849 return;
850 else
851 num_active_player++;
854 // Number of active players are less than the threshold, do nothing.
855 if (num_active_player < kMediaPlayerThreshold)
856 return;
858 for (it = players_.begin(); it != players_.end(); ++it) {
859 if ((*it)->IsPlayerReady() && !(*it)->IsPlaying() &&
860 fullscreen_player_id_ != (*it)->player_id()) {
861 (*it)->Release();
862 Send(new MediaPlayerMsg_MediaPlayerReleased(
863 routing_id(), (*it)->player_id()));
868 void BrowserMediaPlayerManager::OnMediaResourcesReleased(int player_id) {
869 #if defined(VIDEO_HOLE)
870 MediaPlayerAndroid* player = GetPlayer(player_id);
871 if (player && player->IsSurfaceInUse())
872 return;
873 ExternalVideoSurfaceContainer* surface_container =
874 ExternalVideoSurfaceContainer::FromWebContents(web_contents_);
875 if (surface_container)
876 surface_container->ReleaseExternalVideoSurface(player_id);
877 #endif // defined(VIDEO_HOLE)
880 } // namespace content