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
;
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
;
52 void BrowserMediaPlayerManager::RegisterFactory(Factory factory
) {
57 BrowserMediaPlayerManager
* BrowserMediaPlayerManager::Create(
58 RenderViewHost
* rvh
) {
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
,
72 const GURL
& first_party_for_cookies
,
73 int demuxer_client_id
,
75 MediaPlayerManager
* manager
,
76 BrowserDemuxerAndroid
* demuxer
) {
78 case MEDIA_PLAYER_TYPE_URL
: {
79 const std::string user_agent
= GetContentClient()->GetUserAgent();
80 MediaPlayerBridge
* media_player_bridge
= new MediaPlayerBridge(
83 first_party_for_cookies
,
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
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(
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
));
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
) {
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()
166 void BrowserMediaPlayerManager::FullscreenPlayerPlay() {
167 MediaPlayerAndroid
* player
= GetFullscreenPlayer();
169 if (fullscreen_player_is_released_
) {
170 video_view_
->OpenVideo();
171 fullscreen_player_is_released_
= false;
174 Send(new MediaPlayerMsg_DidMediaPlayerPlay(
175 routing_id(), fullscreen_player_id_
));
179 void BrowserMediaPlayerManager::FullscreenPlayerPause() {
180 MediaPlayerAndroid
* player
= GetFullscreenPlayer();
183 Send(new MediaPlayerMsg_DidMediaPlayerPause(
184 routing_id(), fullscreen_player_id_
));
188 void BrowserMediaPlayerManager::FullscreenPlayerSeek(int msec
) {
189 MediaPlayerAndroid
* player
= GetFullscreenPlayer();
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_
));
214 MediaPlayerAndroid
* player
= GetFullscreenPlayer();
215 fullscreen_player_id_
= -1;
218 if (release_media_player
)
219 ReleaseFullscreenPlayer(player
);
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();
236 bool empty_surface
= surface
.IsEmpty();
237 player
->SetVideoSurface(surface
.Pass());
241 Send(new MediaPlayerMsg_DidEnterFullscreen(routing_id(),
242 player
->player_id()));
243 if (CommandLine::ForCurrentProcess()->HasSwitch(
244 switches::kDisableOverlayFullscreenVideoSubtitle
)) {
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
,
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(
287 const base::TimeDelta
& time_to_seek
) {
288 Send(new MediaPlayerMsg_SeekRequest(routing_id(), player_id
, time_to_seek
));
291 void BrowserMediaPlayerManager::OnSeekComplete(
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
,
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
)
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
)
347 void BrowserMediaPlayerManager::DestroyAllMediaPlayers() {
349 drm_bridges_
.clear();
350 if (fullscreen_player_id_
!= -1) {
352 fullscreen_player_id_
= -1;
356 void BrowserMediaPlayerManager::OnProtectedSurfaceRequested(int player_id
) {
357 if (fullscreen_player_id_
== player_id
)
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
);
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
;
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(
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(
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(
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
,
426 MediaPlayerAndroid
* player
= GetPlayer(player_id
);
428 player
->SetVideoSurface(
429 gfx::ScopedJavaSurface::AcquireExternalSurface(surface
));
433 void BrowserMediaPlayerManager::DetachExternalVideoSurface(int player_id
) {
434 MediaPlayerAndroid
* player
= GetPlayer(player_id
);
436 player
->SetVideoSurface(gfx::ScopedJavaSurface());
439 void BrowserMediaPlayerManager::OnNotifyExternalSurface(
440 int player_id
, bool is_request
, const gfx::RectF
& rect
) {
444 ExternalVideoSurfaceContainer::CreateForWebContents(web_contents_
);
445 ExternalVideoSurfaceContainer
* surface_container
=
446 ExternalVideoSurfaceContainer::FromWebContents(web_contents_
);
447 if (!surface_container
)
451 // It's safe to use base::Unretained(this), because the callbacks will not
452 // be called after running ReleaseExternalVideoSurface().
453 surface_container
->RequestExternalVideoSurface(
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)
468 // If the fullscreen player is not playing back encrypted video, do nothing.
469 MediaDrmBridge
* drm_bridge
= GetDrmBridge(fullscreen_player_id_
);
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()) {
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
);
506 player
->SetVideoSurface(gfx::ScopedJavaSurface());
507 video_view_
->OnExitFullscreen();
511 void BrowserMediaPlayerManager::OnInitialize(
512 MediaPlayerHostMsg_Initialize_Type type
,
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
);
537 void BrowserMediaPlayerManager::OnSeek(
539 const base::TimeDelta
& time
) {
540 MediaPlayerAndroid
* player
= GetPlayer(player_id
);
542 player
->SeekTo(time
);
545 void BrowserMediaPlayerManager::OnPause(
547 bool is_media_related_action
) {
548 MediaPlayerAndroid
* player
= GetPlayer(player_id
);
550 player
->Pause(is_media_related_action
);
553 void BrowserMediaPlayerManager::OnSetVolume(int player_id
, double volume
) {
554 MediaPlayerAndroid
* player
= GetPlayer(player_id
);
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
);
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
;
587 if (!MediaDrmBridge::IsKeySystemSupportedWithType(key_system
, "")) {
588 NOTREACHED() << "Unsupported key system: " << key_system
;
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(
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);
610 // Convert the session content type into a MIME type. "audio" and "video"
611 // don't matter, so using "video" for the MIME type.
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";
619 case CREATE_SESSION_TYPE_MP4
:
620 mime_type
= "video/mp4";
627 if (CommandLine::ForCurrentProcess()
628 ->HasSwitch(switches::kDisableInfobarForProtectedMediaIdentifier
)) {
629 CreateSessionIfPermitted(cdm_id
, session_id
, mime_type
, init_data
, true);
633 MediaDrmBridge
* drm_bridge
= GetDrmBridge(cdm_id
);
635 DLOG(WARNING
) << "No MediaDrmBridge for ID: " << cdm_id
<< " found";
636 OnSessionError(cdm_id
, session_id
, media::MediaKeys::kUnknownError
, 0);
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
),
652 drm_bridge
->frame_url(),
653 base::Bind(&BrowserMediaPlayerManager::CreateSessionIfPermitted
,
654 weak_ptr_factory_
.GetWeakPtr(),
661 void BrowserMediaPlayerManager::OnUpdateSession(
664 const std::vector
<uint8
>& response
) {
665 MediaDrmBridge
* drm_bridge
= GetDrmBridge(cdm_id
);
667 DLOG(WARNING
) << "No MediaDrmBridge for ID: " << cdm_id
<< " found";
668 OnSessionError(cdm_id
, session_id
, media::MediaKeys::kUnknownError
, 0);
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);
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
);
685 player
->OnKeyAdded();
688 void BrowserMediaPlayerManager::OnReleaseSession(int cdm_id
,
690 MediaDrmBridge
* drm_bridge
= GetDrmBridge(cdm_id
);
692 DLOG(WARNING
) << "No MediaDrmBridge for ID: " << cdm_id
<< " found";
693 OnSessionError(cdm_id
, session_id
, media::MediaKeys::kUnknownError
, 0);
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
) {
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
);
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));
753 // This failure will be discovered and reported by OnCreateSession()
754 // as GetDrmBridge() will return null.
755 DVLOG(1) << "failed to create drm bridge.";
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
;
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
);
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.";
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(
799 const std::string
& content_type
,
800 const std::vector
<uint8
>& init_data
,
803 OnSessionError(cdm_id
, session_id
, media::MediaKeys::kUnknownError
, 0);
807 MediaDrmBridge
* drm_bridge
= GetDrmBridge(cdm_id
);
809 DLOG(WARNING
) << "No MediaDrmBridge for ID: " << cdm_id
<< " found";
810 OnSessionError(cdm_id
, session_id
, media::MediaKeys::kUnknownError
, 0);
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())) {
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
)
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
) {
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())
847 // The player is already active, ignore it.
848 if ((*it
)->player_id() == player_id
)
854 // Number of active players are less than the threshold, do nothing.
855 if (num_active_player
< kMediaPlayerThreshold
)
858 for (it
= players_
.begin(); it
!= players_
.end(); ++it
) {
859 if ((*it
)->IsPlayerReady() && !(*it
)->IsPlaying() &&
860 fullscreen_player_id_
!= (*it
)->player_id()) {
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())
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