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/cdm_messages.h"
15 #include "content/common/media/media_player_messages_android.h"
16 #include "content/public/browser/android/content_view_core.h"
17 #include "content/public/browser/android/external_video_surface_container.h"
18 #include "content/public/browser/browser_context.h"
19 #include "content/public/browser/content_browser_client.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_drm_bridge.h"
28 #include "media/base/android/media_player_bridge.h"
29 #include "media/base/android/media_source_player.h"
30 #include "media/base/media_switches.h"
32 using media::MediaDrmBridge;
33 using media::MediaPlayerAndroid;
34 using media::MediaPlayerBridge;
35 using media::MediaPlayerManager;
36 using media::MediaSourcePlayer;
40 // Threshold on the number of media players per renderer before we start
41 // attempting to release inactive media players.
42 const int kMediaPlayerThreshold = 1;
44 // Maximum lengths for various EME API parameters. These are checks to
45 // prevent unnecessarily large parameters from being passed around, and the
46 // lengths are somewhat arbitrary as the EME spec doesn't specify any limits.
47 const size_t kMaxInitDataLength = 64 * 1024; // 64 KB
48 const size_t kMaxSessionResponseLength = 64 * 1024; // 64 KB
49 const size_t kMaxKeySystemLength = 256;
51 static BrowserMediaPlayerManager::Factory g_factory = NULL;
54 void BrowserMediaPlayerManager::RegisterFactory(Factory factory) {
59 BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
60 RenderViewHost* rvh) {
62 return g_factory(rvh);
63 return new BrowserMediaPlayerManager(rvh);
66 ContentViewCoreImpl* BrowserMediaPlayerManager::GetContentViewCore() const {
67 return ContentViewCoreImpl::FromWebContents(web_contents());
70 MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
71 MediaPlayerHostMsg_Initialize_Type type,
74 const GURL& first_party_for_cookies,
75 int demuxer_client_id,
77 MediaPlayerManager* manager,
78 BrowserDemuxerAndroid* demuxer) {
80 case MEDIA_PLAYER_TYPE_URL: {
81 const std::string user_agent = GetContentClient()->GetUserAgent();
82 MediaPlayerBridge* media_player_bridge = new MediaPlayerBridge(
85 first_party_for_cookies,
89 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
90 weak_ptr_factory_.GetWeakPtr()),
91 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesReleased,
92 weak_ptr_factory_.GetWeakPtr()));
93 BrowserMediaPlayerManager* browser_media_player_manager =
94 static_cast<BrowserMediaPlayerManager*>(manager);
95 ContentViewCoreImpl* content_view_core_impl =
96 static_cast<ContentViewCoreImpl*>(ContentViewCore::FromWebContents(
97 browser_media_player_manager->web_contents_));
98 if (!content_view_core_impl) {
99 // May reach here due to prerendering. Don't extract the metadata
100 // since it is expensive.
101 // TODO(qinmin): extract the metadata once the user decided to load
103 browser_media_player_manager->OnMediaMetadataChanged(
104 player_id, base::TimeDelta(), 0, 0, false);
105 } else if (!content_view_core_impl->ShouldBlockMediaRequest(url)) {
106 media_player_bridge->Initialize();
108 return media_player_bridge;
111 case MEDIA_PLAYER_TYPE_MEDIA_SOURCE: {
112 return new MediaSourcePlayer(
115 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
116 weak_ptr_factory_.GetWeakPtr()),
117 base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesReleased,
118 weak_ptr_factory_.GetWeakPtr()),
119 demuxer->CreateDemuxer(demuxer_client_id));
127 BrowserMediaPlayerManager::BrowserMediaPlayerManager(
128 RenderViewHost* render_view_host)
129 : WebContentsObserver(WebContents::FromRenderViewHost(render_view_host)),
130 fullscreen_player_id_(-1),
131 fullscreen_player_is_released_(false),
132 web_contents_(WebContents::FromRenderViewHost(render_view_host)),
133 weak_ptr_factory_(this) {
136 BrowserMediaPlayerManager::~BrowserMediaPlayerManager() {}
138 bool BrowserMediaPlayerManager::OnMessageReceived(const IPC::Message& msg) {
140 IPC_BEGIN_MESSAGE_MAP(BrowserMediaPlayerManager, msg)
141 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_EnterFullscreen, OnEnterFullscreen)
142 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_ExitFullscreen, OnExitFullscreen)
143 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Initialize, OnInitialize)
144 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Start, OnStart)
145 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Seek, OnSeek)
146 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Pause, OnPause)
147 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_SetVolume, OnSetVolume)
148 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_SetPoster, OnSetPoster)
149 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Release, OnReleaseResources)
150 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_DestroyMediaPlayer, OnDestroyPlayer)
151 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_DestroyAllMediaPlayers,
152 DestroyAllMediaPlayers)
153 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_SetCdm, OnSetCdm)
154 IPC_MESSAGE_HANDLER(CdmHostMsg_InitializeCdm, OnInitializeCdm)
155 IPC_MESSAGE_HANDLER(CdmHostMsg_CreateSession, OnCreateSession)
156 IPC_MESSAGE_HANDLER(CdmHostMsg_UpdateSession, OnUpdateSession)
157 IPC_MESSAGE_HANDLER(CdmHostMsg_ReleaseSession, OnReleaseSession)
158 IPC_MESSAGE_HANDLER(CdmHostMsg_DestroyCdm, OnDestroyCdm)
159 #if defined(VIDEO_HOLE)
160 IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_NotifyExternalSurface,
161 OnNotifyExternalSurface)
162 #endif // defined(VIDEO_HOLE)
163 IPC_MESSAGE_UNHANDLED(handled = false)
164 IPC_END_MESSAGE_MAP()
168 void BrowserMediaPlayerManager::FullscreenPlayerPlay() {
169 MediaPlayerAndroid* player = GetFullscreenPlayer();
171 if (fullscreen_player_is_released_) {
172 video_view_->OpenVideo();
173 fullscreen_player_is_released_ = false;
176 Send(new MediaPlayerMsg_DidMediaPlayerPlay(
177 routing_id(), fullscreen_player_id_));
181 void BrowserMediaPlayerManager::FullscreenPlayerPause() {
182 MediaPlayerAndroid* player = GetFullscreenPlayer();
185 Send(new MediaPlayerMsg_DidMediaPlayerPause(
186 routing_id(), fullscreen_player_id_));
190 void BrowserMediaPlayerManager::FullscreenPlayerSeek(int msec) {
191 MediaPlayerAndroid* player = GetFullscreenPlayer();
193 // TODO(kbalazs): if |fullscreen_player_is_released_| is true
194 // at this point, player->GetCurrentTime() will be wrong until
195 // FullscreenPlayerPlay (http://crbug.com/322798).
196 OnSeekRequest(fullscreen_player_id_,
197 base::TimeDelta::FromMilliseconds(msec));
201 void BrowserMediaPlayerManager::ExitFullscreen(bool release_media_player) {
202 if (!CommandLine::ForCurrentProcess()->HasSwitch(
203 switches::kDisableOverlayFullscreenVideoSubtitle)) {
204 if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
205 delegate->ToggleFullscreenModeForTab(web_contents_, false);
206 if (RenderWidgetHostViewAndroid* view_android =
207 static_cast<RenderWidgetHostViewAndroid*>(
208 web_contents_->GetRenderWidgetHostView())) {
209 view_android->SetOverlayVideoMode(false);
213 Send(new MediaPlayerMsg_DidExitFullscreen(
214 routing_id(), fullscreen_player_id_));
216 MediaPlayerAndroid* player = GetFullscreenPlayer();
217 fullscreen_player_id_ = -1;
220 if (release_media_player)
221 ReleaseFullscreenPlayer(player);
223 player->SetVideoSurface(gfx::ScopedJavaSurface());
226 void BrowserMediaPlayerManager::OnTimeUpdate(int player_id,
227 base::TimeDelta current_time) {
228 Send(new MediaPlayerMsg_MediaTimeUpdate(
229 routing_id(), player_id, current_time));
232 void BrowserMediaPlayerManager::SetVideoSurface(
233 gfx::ScopedJavaSurface surface) {
234 MediaPlayerAndroid* player = GetFullscreenPlayer();
238 bool empty_surface = surface.IsEmpty();
239 player->SetVideoSurface(surface.Pass());
243 Send(new MediaPlayerMsg_DidEnterFullscreen(routing_id(),
244 player->player_id()));
245 if (CommandLine::ForCurrentProcess()->HasSwitch(
246 switches::kDisableOverlayFullscreenVideoSubtitle)) {
249 if (RenderWidgetHostViewAndroid* view_android =
250 static_cast<RenderWidgetHostViewAndroid*>(
251 web_contents_->GetRenderWidgetHostView())) {
252 view_android->SetOverlayVideoMode(true);
254 if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
255 delegate->ToggleFullscreenModeForTab(web_contents_, true);
258 void BrowserMediaPlayerManager::OnMediaMetadataChanged(
259 int player_id, base::TimeDelta duration, int width, int height,
261 Send(new MediaPlayerMsg_MediaMetadataChanged(
262 routing_id(), player_id, duration, width, height, success));
263 if (fullscreen_player_id_ == player_id)
264 video_view_->UpdateMediaMetadata();
267 void BrowserMediaPlayerManager::OnPlaybackComplete(int player_id) {
268 Send(new MediaPlayerMsg_MediaPlaybackCompleted(routing_id(), player_id));
269 if (fullscreen_player_id_ == player_id)
270 video_view_->OnPlaybackComplete();
273 void BrowserMediaPlayerManager::OnMediaInterrupted(int player_id) {
274 // Tell WebKit that the audio should be paused, then release all resources
275 Send(new MediaPlayerMsg_MediaPlayerReleased(routing_id(), player_id));
276 OnReleaseResources(player_id);
279 void BrowserMediaPlayerManager::OnBufferingUpdate(
280 int player_id, int percentage) {
281 Send(new MediaPlayerMsg_MediaBufferingUpdate(
282 routing_id(), player_id, percentage));
283 if (fullscreen_player_id_ == player_id)
284 video_view_->OnBufferingUpdate(percentage);
287 void BrowserMediaPlayerManager::OnSeekRequest(
289 const base::TimeDelta& time_to_seek) {
290 Send(new MediaPlayerMsg_SeekRequest(routing_id(), player_id, time_to_seek));
293 void BrowserMediaPlayerManager::OnSeekComplete(
295 const base::TimeDelta& current_time) {
296 Send(new MediaPlayerMsg_SeekCompleted(routing_id(), player_id, current_time));
299 void BrowserMediaPlayerManager::OnError(int player_id, int error) {
300 Send(new MediaPlayerMsg_MediaError(routing_id(), player_id, error));
301 if (fullscreen_player_id_ == player_id)
302 video_view_->OnMediaPlayerError(error);
305 void BrowserMediaPlayerManager::OnVideoSizeChanged(
306 int player_id, int width, int height) {
307 Send(new MediaPlayerMsg_MediaVideoSizeChanged(routing_id(), player_id,
309 if (fullscreen_player_id_ == player_id)
310 video_view_->OnVideoSizeChanged(width, height);
313 media::MediaResourceGetter*
314 BrowserMediaPlayerManager::GetMediaResourceGetter() {
315 if (!media_resource_getter_.get()) {
316 RenderProcessHost* host = web_contents()->GetRenderProcessHost();
317 BrowserContext* context = host->GetBrowserContext();
318 StoragePartition* partition = host->GetStoragePartition();
319 fileapi::FileSystemContext* file_system_context =
320 partition ? partition->GetFileSystemContext() : NULL;
321 // Eventually this needs to be fixed to pass the correct frame rather
322 // than just using the main frame.
323 media_resource_getter_.reset(new MediaResourceGetterImpl(
327 web_contents()->GetMainFrame()->GetRoutingID()));
329 return media_resource_getter_.get();
332 MediaPlayerAndroid* BrowserMediaPlayerManager::GetFullscreenPlayer() {
333 return GetPlayer(fullscreen_player_id_);
336 MediaPlayerAndroid* BrowserMediaPlayerManager::GetPlayer(int player_id) {
337 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
338 it != players_.end(); ++it) {
339 if ((*it)->player_id() == player_id)
345 MediaDrmBridge* BrowserMediaPlayerManager::GetDrmBridge(int cdm_id) {
346 for (ScopedVector<MediaDrmBridge>::iterator it = drm_bridges_.begin();
347 it != drm_bridges_.end(); ++it) {
348 if ((*it)->cdm_id() == cdm_id)
354 void BrowserMediaPlayerManager::DestroyAllMediaPlayers() {
356 drm_bridges_.clear();
357 if (fullscreen_player_id_ != -1) {
359 fullscreen_player_id_ = -1;
363 void BrowserMediaPlayerManager::RequestFullScreen(int player_id) {
364 if (fullscreen_player_id_ == player_id)
367 if (fullscreen_player_id_ != -1) {
368 // TODO(qinmin): Determine the correct error code we should report to WMPA.
369 OnError(player_id, MediaPlayerAndroid::MEDIA_ERROR_DECODE);
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 // TODO(qinmin): make this flag default on android.
377 if (CommandLine::ForCurrentProcess()->HasSwitch(
378 switches::kDisableGestureRequirementForMediaFullscreen)) {
379 Send(new MediaPlayerMsg_RequestFullscreen(routing_id(), player_id));
383 // The following 5 functions are EME MediaKeySession events.
385 void BrowserMediaPlayerManager::OnSessionCreated(
388 const std::string& web_session_id) {
389 Send(new CdmMsg_SessionCreated(
390 routing_id(), cdm_id, session_id, web_session_id));
393 void BrowserMediaPlayerManager::OnSessionMessage(
396 const std::vector<uint8>& message,
397 const GURL& destination_url) {
398 Send(new CdmMsg_SessionMessage(
399 routing_id(), cdm_id, session_id, message, destination_url));
402 void BrowserMediaPlayerManager::OnSessionReady(int cdm_id, uint32 session_id) {
403 Send(new CdmMsg_SessionReady(routing_id(), cdm_id, session_id));
406 void BrowserMediaPlayerManager::OnSessionClosed(int cdm_id, uint32 session_id) {
407 Send(new CdmMsg_SessionClosed(routing_id(), cdm_id, session_id));
410 void BrowserMediaPlayerManager::OnSessionError(
413 media::MediaKeys::KeyError error_code,
414 uint32 system_code) {
415 Send(new CdmMsg_SessionError(
416 routing_id(), cdm_id, session_id, error_code, system_code));
419 #if defined(VIDEO_HOLE)
420 void BrowserMediaPlayerManager::AttachExternalVideoSurface(int player_id,
422 MediaPlayerAndroid* player = GetPlayer(player_id);
424 player->SetVideoSurface(
425 gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
429 void BrowserMediaPlayerManager::DetachExternalVideoSurface(int player_id) {
430 MediaPlayerAndroid* player = GetPlayer(player_id);
432 player->SetVideoSurface(gfx::ScopedJavaSurface());
435 void BrowserMediaPlayerManager::OnFrameInfoUpdated() {
436 if (external_video_surface_container_)
437 external_video_surface_container_->OnFrameInfoUpdated();
440 void BrowserMediaPlayerManager::OnNotifyExternalSurface(
441 int player_id, bool is_request, const gfx::RectF& rect) {
446 OnRequestExternalSurface(player_id, rect);
448 if (external_video_surface_container_) {
449 external_video_surface_container_->OnExternalVideoSurfacePositionChanged(
454 void BrowserMediaPlayerManager::OnRequestExternalSurface(
455 int player_id, const gfx::RectF& rect) {
456 if (!external_video_surface_container_) {
457 ContentBrowserClient* client = GetContentClient()->browser();
458 external_video_surface_container_.reset(
459 client->OverrideCreateExternalVideoSurfaceContainer(web_contents_));
461 // It's safe to use base::Unretained(this), because the callbacks will not
462 // be called after running ReleaseExternalVideoSurface().
463 if (external_video_surface_container_) {
464 external_video_surface_container_->RequestExternalVideoSurface(
466 base::Bind(&BrowserMediaPlayerManager::AttachExternalVideoSurface,
467 base::Unretained(this)),
468 base::Bind(&BrowserMediaPlayerManager::DetachExternalVideoSurface,
469 base::Unretained(this)));
472 #endif // defined(VIDEO_HOLE)
474 void BrowserMediaPlayerManager::OnEnterFullscreen(int player_id) {
475 DCHECK_EQ(fullscreen_player_id_, -1);
476 #if defined(VIDEO_HOLE)
477 if (external_video_surface_container_)
478 external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
479 #endif // defined(VIDEO_HOLE)
480 if (video_view_.get()) {
481 fullscreen_player_id_ = player_id;
482 video_view_->OpenVideo();
484 } else if (!ContentVideoView::GetInstance()) {
485 // In Android WebView, two ContentViewCores could both try to enter
486 // fullscreen video, we just ignore the second one.
487 video_view_.reset(new ContentVideoView(this));
488 base::android::ScopedJavaLocalRef<jobject> j_content_video_view =
489 video_view_->GetJavaObject(base::android::AttachCurrentThread());
490 if (!j_content_video_view.is_null()) {
491 fullscreen_player_id_ = player_id;
496 // Force the second video to exit fullscreen.
497 // TODO(qinmin): There is no need to send DidEnterFullscreen message.
498 // However, if we don't send the message, page layers will not be
499 // correctly restored. http:crbug.com/367346.
500 Send(new MediaPlayerMsg_DidEnterFullscreen(routing_id(), player_id));
501 Send(new MediaPlayerMsg_DidExitFullscreen(routing_id(), player_id));
505 void BrowserMediaPlayerManager::OnExitFullscreen(int player_id) {
506 if (fullscreen_player_id_ == player_id) {
507 MediaPlayerAndroid* player = GetPlayer(player_id);
509 player->SetVideoSurface(gfx::ScopedJavaSurface());
510 video_view_->OnExitFullscreen();
514 void BrowserMediaPlayerManager::OnInitialize(
515 MediaPlayerHostMsg_Initialize_Type type,
518 const GURL& first_party_for_cookies,
519 int demuxer_client_id) {
520 DCHECK(type != MEDIA_PLAYER_TYPE_MEDIA_SOURCE || demuxer_client_id > 0)
521 << "Media source players must have positive demuxer client IDs: "
522 << demuxer_client_id;
524 RemovePlayer(player_id);
526 RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>(
527 web_contents()->GetRenderProcessHost());
528 MediaPlayerAndroid* player = CreateMediaPlayer(
529 type, player_id, url, first_party_for_cookies, demuxer_client_id,
530 host->GetBrowserContext()->IsOffTheRecord(), this,
531 host->browser_demuxer_android());
538 void BrowserMediaPlayerManager::OnStart(int player_id) {
539 MediaPlayerAndroid* player = GetPlayer(player_id);
543 if (fullscreen_player_id_ == player_id && fullscreen_player_is_released_) {
544 video_view_->OpenVideo();
545 fullscreen_player_is_released_ = false;
549 void BrowserMediaPlayerManager::OnSeek(
551 const base::TimeDelta& time) {
552 MediaPlayerAndroid* player = GetPlayer(player_id);
554 player->SeekTo(time);
557 void BrowserMediaPlayerManager::OnPause(
559 bool is_media_related_action) {
560 MediaPlayerAndroid* player = GetPlayer(player_id);
562 player->Pause(is_media_related_action);
565 void BrowserMediaPlayerManager::OnSetVolume(int player_id, double volume) {
566 MediaPlayerAndroid* player = GetPlayer(player_id);
568 player->SetVolume(volume);
571 void BrowserMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) {
572 // To be overridden by subclasses.
575 void BrowserMediaPlayerManager::OnReleaseResources(int player_id) {
576 MediaPlayerAndroid* player = GetPlayer(player_id);
579 if (player_id == fullscreen_player_id_)
580 fullscreen_player_is_released_ = true;
583 void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) {
584 RemovePlayer(player_id);
585 if (fullscreen_player_id_ == player_id)
586 fullscreen_player_id_ = -1;
589 void BrowserMediaPlayerManager::OnInitializeCdm(int cdm_id,
590 const std::string& key_system,
591 const GURL& security_origin) {
592 if (key_system.size() > kMaxKeySystemLength) {
593 // This failure will be discovered and reported by OnCreateSession()
594 // as GetDrmBridge() will return null.
595 NOTREACHED() << "Invalid key system: " << key_system;
599 if (!MediaDrmBridge::IsKeySystemSupported(key_system)) {
600 NOTREACHED() << "Unsupported key system: " << key_system;
604 AddDrmBridge(cdm_id, key_system, security_origin);
607 void BrowserMediaPlayerManager::OnCreateSession(
610 CdmHostMsg_CreateSession_ContentType content_type,
611 const std::vector<uint8>& init_data) {
612 if (init_data.size() > kMaxInitDataLength) {
613 LOG(WARNING) << "InitData for ID: " << cdm_id
614 << " too long: " << init_data.size();
615 OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
619 // Convert the session content type into a MIME type. "audio" and "video"
620 // don't matter, so using "video" for the MIME type.
622 // https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-createsession
623 std::string mime_type;
624 switch (content_type) {
625 case CREATE_SESSION_TYPE_WEBM:
626 mime_type = "video/webm";
628 case CREATE_SESSION_TYPE_MP4:
629 mime_type = "video/mp4";
636 if (CommandLine::ForCurrentProcess()
637 ->HasSwitch(switches::kDisableInfobarForProtectedMediaIdentifier)) {
638 CreateSessionIfPermitted(cdm_id, session_id, mime_type, init_data, true);
642 MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
644 DLOG(WARNING) << "No MediaDrmBridge for ID: " << cdm_id << " found";
645 OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
649 BrowserContext* context =
650 web_contents()->GetRenderProcessHost()->GetBrowserContext();
652 context->RequestProtectedMediaIdentifierPermission(
653 web_contents()->GetRenderProcessHost()->GetID(),
654 web_contents()->GetRenderViewHost()->GetRoutingID(),
655 static_cast<int>(session_id),
657 drm_bridge->security_origin(),
658 base::Bind(&BrowserMediaPlayerManager::CreateSessionIfPermitted,
659 weak_ptr_factory_.GetWeakPtr(),
666 void BrowserMediaPlayerManager::OnUpdateSession(
669 const std::vector<uint8>& response) {
670 MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
672 DLOG(WARNING) << "No MediaDrmBridge for ID: " << cdm_id << " found";
673 OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
677 if (response.size() > kMaxSessionResponseLength) {
678 LOG(WARNING) << "Response for ID: " << cdm_id
679 << " too long: " << response.size();
680 OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
684 drm_bridge->UpdateSession(session_id, &response[0], response.size());
686 DrmBridgePlayerMap::const_iterator iter = drm_bridge_player_map_.find(cdm_id);
687 if (iter == drm_bridge_player_map_.end())
690 int player_id = iter->second;
691 MediaPlayerAndroid* player = GetPlayer(player_id);
693 player->OnKeyAdded();
696 void BrowserMediaPlayerManager::OnReleaseSession(int cdm_id,
698 MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
700 DLOG(WARNING) << "No MediaDrmBridge for ID: " << cdm_id << " found";
701 OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
705 drm_bridge->ReleaseSession(session_id);
708 void BrowserMediaPlayerManager::OnDestroyCdm(int cdm_id) {
709 MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
710 if (!drm_bridge) return;
712 CancelAllPendingSessionCreations(cdm_id);
713 RemoveDrmBridge(cdm_id);
716 void BrowserMediaPlayerManager::CancelAllPendingSessionCreations(int cdm_id) {
717 BrowserContext* context =
718 web_contents()->GetRenderProcessHost()->GetBrowserContext();
719 context->CancelProtectedMediaIdentifierPermissionRequests(cdm_id);
722 void BrowserMediaPlayerManager::AddPlayer(MediaPlayerAndroid* player) {
723 DCHECK(!GetPlayer(player->player_id()));
724 players_.push_back(player);
727 void BrowserMediaPlayerManager::RemovePlayer(int player_id) {
728 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
729 it != players_.end(); ++it) {
730 MediaPlayerAndroid* player = *it;
731 if (player->player_id() == player_id) {
737 for (DrmBridgePlayerMap::iterator it = drm_bridge_player_map_.begin();
738 it != drm_bridge_player_map_.end(); ++it) {
739 if (it->second == player_id) {
740 drm_bridge_player_map_.erase(it);
746 scoped_ptr<media::MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer(
747 int player_id, media::MediaPlayerAndroid* player) {
748 media::MediaPlayerAndroid* previous_player = NULL;
749 for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
750 it != players_.end(); ++it) {
751 if ((*it)->player_id() == player_id) {
752 previous_player = *it;
753 players_.weak_erase(it);
754 players_.push_back(player);
758 return scoped_ptr<media::MediaPlayerAndroid>(previous_player);
761 void BrowserMediaPlayerManager::AddDrmBridge(int cdm_id,
762 const std::string& key_system,
763 const GURL& security_origin) {
764 DCHECK(!GetDrmBridge(cdm_id));
766 scoped_ptr<MediaDrmBridge> drm_bridge(
767 MediaDrmBridge::Create(cdm_id, key_system, security_origin, this));
769 // This failure will be discovered and reported by OnCreateSession()
770 // as GetDrmBridge() will return null.
771 DVLOG(1) << "failed to create drm bridge.";
775 // TODO(xhwang/ddorwin): Pass the security level from key system.
776 MediaDrmBridge::SecurityLevel security_level =
777 MediaDrmBridge::SECURITY_LEVEL_3;
778 if (CommandLine::ForCurrentProcess()
779 ->HasSwitch(switches::kMediaDrmEnableNonCompositing)) {
780 security_level = MediaDrmBridge::SECURITY_LEVEL_1;
782 if (!drm_bridge->SetSecurityLevel(security_level)) {
783 DVLOG(1) << "failed to set security level " << security_level;
787 drm_bridges_.push_back(drm_bridge.release());
790 void BrowserMediaPlayerManager::RemoveDrmBridge(int cdm_id) {
791 // TODO(xhwang): Detach DrmBridge from the player it's set to. In prefixed
792 // EME implementation the current code is fine because we always destroy the
793 // player before we destroy the DrmBridge. This will not always be the case
794 // in unprefixed EME implementation.
795 for (ScopedVector<MediaDrmBridge>::iterator it = drm_bridges_.begin();
796 it != drm_bridges_.end(); ++it) {
797 if ((*it)->cdm_id() == cdm_id) {
798 drm_bridges_.erase(it);
799 drm_bridge_player_map_.erase(cdm_id);
805 void BrowserMediaPlayerManager::OnSetCdm(int player_id, int cdm_id) {
806 MediaPlayerAndroid* player = GetPlayer(player_id);
807 MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
808 if (!drm_bridge || !player) {
809 DVLOG(1) << "Cannot set CDM on the specified player.";
813 // TODO(qinmin): add the logic to decide whether we should create the
814 // fullscreen surface for EME lv1.
815 player->SetDrmBridge(drm_bridge);
816 // Do now support setting one CDM on multiple players.
817 DCHECK(drm_bridge_player_map_.find(cdm_id) == drm_bridge_player_map_.end());
818 drm_bridge_player_map_[cdm_id] = player_id;
821 void BrowserMediaPlayerManager::CreateSessionIfPermitted(
824 const std::string& content_type,
825 const std::vector<uint8>& init_data,
828 OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
832 MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
834 DLOG(WARNING) << "No MediaDrmBridge for ID: " << cdm_id << " found";
835 OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
839 // This could fail, in which case a SessionError will be fired.
840 drm_bridge->CreateSession(
841 session_id, content_type, &init_data[0], init_data.size());
844 void BrowserMediaPlayerManager::ReleaseFullscreenPlayer(
845 MediaPlayerAndroid* player) {
849 void BrowserMediaPlayerManager::OnMediaResourcesRequested(int player_id) {
850 int num_active_player = 0;
851 ScopedVector<MediaPlayerAndroid>::iterator it;
852 for (it = players_.begin(); it != players_.end(); ++it) {
853 if (!(*it)->IsPlayerReady())
856 // The player is already active, ignore it.
857 if ((*it)->player_id() == player_id)
863 // Number of active players are less than the threshold, do nothing.
864 if (num_active_player < kMediaPlayerThreshold)
867 for (it = players_.begin(); it != players_.end(); ++it) {
868 if ((*it)->IsPlayerReady() && !(*it)->IsPlaying() &&
869 fullscreen_player_id_ != (*it)->player_id()) {
871 Send(new MediaPlayerMsg_MediaPlayerReleased(
872 routing_id(), (*it)->player_id()));
877 void BrowserMediaPlayerManager::OnMediaResourcesReleased(int player_id) {
878 #if defined(VIDEO_HOLE)
879 MediaPlayerAndroid* player = GetPlayer(player_id);
880 if (player && player->IsSurfaceInUse())
882 if (external_video_surface_container_)
883 external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
884 #endif // defined(VIDEO_HOLE)
887 } // namespace content