diff options
author | xhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-07 20:28:18 +0000 |
---|---|---|
committer | xhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-07 20:28:18 +0000 |
commit | 8fc0f5be02eee83d34830fe0605b30ab36a06d18 (patch) | |
tree | 55ee9fd848fbc5e24452b153f77a2bba453ccf84 /content | |
parent | 03406ba721ebad5e4c6a1dba17a0b3f7fbe0ec4c (diff) | |
download | chromium_src-8fc0f5be02eee83d34830fe0605b30ab36a06d18.zip chromium_src-8fc0f5be02eee83d34830fe0605b30ab36a06d18.tar.gz chromium_src-8fc0f5be02eee83d34830fe0605b30ab36a06d18.tar.bz2 |
Separate BrowserCdmManager from BrowserMediaPlayerManager.
BUG=315312
TEST=Test pages still work.
Review URL: https://codereview.chromium.org/315733003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@275695 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r-- | content/browser/media/android/browser_cdm_manager.cc | 294 | ||||
-rw-r--r-- | content/browser/media/android/browser_cdm_manager.h | 125 | ||||
-rw-r--r-- | content/browser/media/android/browser_media_player_manager.cc | 270 | ||||
-rw-r--r-- | content/browser/media/android/browser_media_player_manager.h | 73 | ||||
-rw-r--r-- | content/browser/media/android/media_web_contents_observer.cc | 135 | ||||
-rw-r--r-- | content/browser/media/android/media_web_contents_observer.h | 20 | ||||
-rw-r--r-- | content/content_browser.gypi | 2 |
7 files changed, 546 insertions, 373 deletions
diff --git a/content/browser/media/android/browser_cdm_manager.cc b/content/browser/media/android/browser_cdm_manager.cc new file mode 100644 index 0000000..20013ec --- /dev/null +++ b/content/browser/media/android/browser_cdm_manager.cc @@ -0,0 +1,294 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/media/android/browser_cdm_manager.h" + +#include "base/command_line.h" +#include "base/stl_util.h" +#include "content/common/media/cdm_messages.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/content_client.h" +#include "content/public/common/content_switches.h" +#include "media/base/browser_cdm.h" +#include "media/base/browser_cdm_factory.h" +#include "media/base/media_switches.h" + +namespace content { + +using media::BrowserCdm; +using media::MediaKeys; + +// Maximum lengths for various EME API parameters. These are checks to +// prevent unnecessarily large parameters from being passed around, and the +// lengths are somewhat arbitrary as the EME spec doesn't specify any limits. +const size_t kMaxInitDataLength = 64 * 1024; // 64 KB +const size_t kMaxSessionResponseLength = 64 * 1024; // 64 KB +const size_t kMaxKeySystemLength = 256; + +// static +BrowserCdmManager* BrowserCdmManager::Create(RenderFrameHost* rfh) { + return new BrowserCdmManager(rfh); +} + +BrowserCdmManager::BrowserCdmManager(RenderFrameHost* render_frame_host) + : render_frame_host_(render_frame_host), + web_contents_(WebContents::FromRenderFrameHost(render_frame_host)), + weak_ptr_factory_(this) { +} + +BrowserCdmManager::~BrowserCdmManager() { + STLDeleteValues(&cdm_map_); +} + +BrowserCdm* BrowserCdmManager::GetCdm(int cdm_id) { + CdmMap::const_iterator iter = cdm_map_.find(cdm_id); + return (iter == cdm_map_.end()) ? NULL : iter->second; +} + +void BrowserCdmManager::OnSessionCreated( + int cdm_id, + uint32 session_id, + const std::string& web_session_id) { + Send(new CdmMsg_SessionCreated( + RoutingID(), cdm_id, session_id, web_session_id)); +} + +void BrowserCdmManager::OnSessionMessage( + int cdm_id, + uint32 session_id, + const std::vector<uint8>& message, + const GURL& destination_url) { + GURL verified_gurl = destination_url; + if (!verified_gurl.is_valid() && !verified_gurl.is_empty()) { + DLOG(WARNING) << "SessionMessage destination_url is invalid : " + << destination_url.possibly_invalid_spec(); + verified_gurl = GURL::EmptyGURL(); // Replace invalid destination_url. + } + + Send(new CdmMsg_SessionMessage( + RoutingID(), cdm_id, session_id, message, verified_gurl)); +} + +void BrowserCdmManager::OnSessionReady(int cdm_id, uint32 session_id) { + Send(new CdmMsg_SessionReady(RoutingID(), cdm_id, session_id)); +} + +void BrowserCdmManager::OnSessionClosed(int cdm_id, uint32 session_id) { + Send(new CdmMsg_SessionClosed(RoutingID(), cdm_id, session_id)); +} + +void BrowserCdmManager::OnSessionError(int cdm_id, + uint32 session_id, + MediaKeys::KeyError error_code, + uint32 system_code) { + Send(new CdmMsg_SessionError( + RoutingID(), cdm_id, session_id, error_code, system_code)); +} + +void BrowserCdmManager::OnInitializeCdm(int cdm_id, + const std::string& key_system, + const GURL& security_origin) { + if (key_system.size() > kMaxKeySystemLength) { + // This failure will be discovered and reported by OnCreateSession() + // as GetCdm() will return null. + NOTREACHED() << "Invalid key system: " << key_system; + return; + } + + AddCdm(cdm_id, key_system, security_origin); +} + +void BrowserCdmManager::OnCreateSession( + int cdm_id, + uint32 session_id, + CdmHostMsg_CreateSession_ContentType content_type, + const std::vector<uint8>& init_data) { + if (init_data.size() > kMaxInitDataLength) { + LOG(WARNING) << "InitData for ID: " << cdm_id + << " too long: " << init_data.size(); + OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); + return; + } + + // Convert the session content type into a MIME type. "audio" and "video" + // don't matter, so using "video" for the MIME type. + // Ref: + // https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-createsession + std::string mime_type; + switch (content_type) { + case CREATE_SESSION_TYPE_WEBM: + mime_type = "video/webm"; + break; + case CREATE_SESSION_TYPE_MP4: + mime_type = "video/mp4"; + break; + default: + NOTREACHED(); + return; + } + +#if defined(OS_ANDROID) + if (CommandLine::ForCurrentProcess() + ->HasSwitch(switches::kDisableInfobarForProtectedMediaIdentifier)) { + CreateSessionIfPermitted(cdm_id, session_id, mime_type, init_data, true); + return; + } +#endif + + BrowserCdm* cdm = GetCdm(cdm_id); + if (!cdm) { + DLOG(WARNING) << "No CDM for ID " << cdm_id << " found"; + OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); + return; + } + + BrowserContext* context = + web_contents_->GetRenderProcessHost()->GetBrowserContext(); + + std::map<int, GURL>::const_iterator iter = + cdm_security_origin_map_.find(cdm_id); + if (iter == cdm_security_origin_map_.end()) { + NOTREACHED(); + OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); + return; + } + + context->RequestProtectedMediaIdentifierPermission( + web_contents_->GetRenderProcessHost()->GetID(), + web_contents_->GetRenderViewHost()->GetRoutingID(), + iter->second, + base::Bind(&BrowserCdmManager::CreateSessionIfPermitted, + weak_ptr_factory_.GetWeakPtr(), + cdm_id, + session_id, + mime_type, + init_data)); +} + +void BrowserCdmManager::OnUpdateSession( + int cdm_id, + uint32 session_id, + const std::vector<uint8>& response) { + BrowserCdm* cdm = GetCdm(cdm_id); + if (!cdm) { + DLOG(WARNING) << "No CDM for ID " << cdm_id << " found"; + OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); + return; + } + + if (response.size() > kMaxSessionResponseLength) { + LOG(WARNING) << "Response for ID " << cdm_id + << " is too long: " << response.size(); + OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); + return; + } + + cdm->UpdateSession(session_id, &response[0], response.size()); +} + +void BrowserCdmManager::OnReleaseSession(int cdm_id, uint32 session_id) { + BrowserCdm* cdm = GetCdm(cdm_id); + if (!cdm) { + DLOG(WARNING) << "No CDM for ID " << cdm_id << " found"; + OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); + return; + } + + cdm->ReleaseSession(session_id); +} + +void BrowserCdmManager::OnDestroyCdm(int cdm_id) { + BrowserCdm* cdm = GetCdm(cdm_id); + if (!cdm) + return; + + CancelAllPendingSessionCreations(cdm_id); + RemoveCdm(cdm_id); +} + +void BrowserCdmManager::CancelAllPendingSessionCreations(int cdm_id) { + BrowserContext* context = + web_contents_->GetRenderProcessHost()->GetBrowserContext(); + std::map<int, GURL>::const_iterator iter = + cdm_security_origin_map_.find(cdm_id); + if (iter == cdm_security_origin_map_.end()) + return; + context->CancelProtectedMediaIdentifierPermissionRequests( + web_contents_->GetRenderProcessHost()->GetID(), + web_contents_->GetRenderViewHost()->GetRoutingID(), + iter->second); +} + +void BrowserCdmManager::AddCdm(int cdm_id, + const std::string& key_system, + const GURL& security_origin) { + DCHECK(!GetCdm(cdm_id)); + base::WeakPtr<BrowserCdmManager> weak_this = weak_ptr_factory_.GetWeakPtr(); + scoped_ptr<BrowserCdm> cdm(media::CreateBrowserCdm( + key_system, + base::Bind(&BrowserCdmManager::OnSessionCreated, weak_this, cdm_id), + base::Bind(&BrowserCdmManager::OnSessionMessage, weak_this, cdm_id), + base::Bind(&BrowserCdmManager::OnSessionReady, weak_this, cdm_id), + base::Bind(&BrowserCdmManager::OnSessionClosed, weak_this, cdm_id), + base::Bind(&BrowserCdmManager::OnSessionError, weak_this, cdm_id))); + + if (!cdm) { + // This failure will be discovered and reported by OnCreateSession() + // as GetCdm() will return null. + DVLOG(1) << "failed to create CDM."; + return; + } + + cdm_map_[cdm_id] = cdm.release(); + cdm_security_origin_map_[cdm_id] = security_origin; +} + +void BrowserCdmManager::RemoveCdm(int cdm_id) { + // TODO(xhwang): Detach CDM from the player it's set to. In prefixed + // EME implementation the current code is fine because we always destroy the + // player before we destroy the DrmBridge. This will not always be the case + // in unprefixed EME implementation. + CdmMap::iterator iter = cdm_map_.find(cdm_id); + if (iter != cdm_map_.end()) { + delete iter->second; + cdm_map_.erase(iter); + } + cdm_security_origin_map_.erase(cdm_id); +} + +int BrowserCdmManager::RoutingID() { + return render_frame_host_->GetRoutingID(); +} + +bool BrowserCdmManager::Send(IPC::Message* msg) { + return render_frame_host_->Send(msg); +} + +void BrowserCdmManager::CreateSessionIfPermitted( + int cdm_id, + uint32 session_id, + const std::string& content_type, + const std::vector<uint8>& init_data, + bool permitted) { + if (!permitted) { + OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); + return; + } + + BrowserCdm* cdm = GetCdm(cdm_id); + if (!cdm) { + DLOG(WARNING) << "No CDM for ID: " << cdm_id << " found"; + OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); + return; + } + + // This could fail, in which case a SessionError will be fired. + cdm->CreateSession(session_id, content_type, &init_data[0], init_data.size()); +} + +} // namespace content diff --git a/content/browser/media/android/browser_cdm_manager.h b/content/browser/media/android/browser_cdm_manager.h new file mode 100644 index 0000000..d55c50c --- /dev/null +++ b/content/browser/media/android/browser_cdm_manager.h @@ -0,0 +1,125 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_CDM_MANAGER_H_ +#define CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_CDM_MANAGER_H_ + +#include <map> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "content/common/content_export.h" +#include "content/common/media/cdm_messages_enums.h" +#include "ipc/ipc_message.h" +// TODO(xhwang): Drop this when KeyError is moved to a common header. +#include "media/base/media_keys.h" +#include "url/gurl.h" + +namespace media { +class BrowserCdm; +} + +namespace content { + +class RenderFrameHost; +class WebContents; + +// This class manages all CDM objects. It receives control operations from the +// the render process, and forwards them to corresponding CDM object. Callbacks +// from CDM objects are converted to IPCs and then sent to the render process. +class CONTENT_EXPORT BrowserCdmManager { + public: + // Creates a new BrowserCdmManager for |rfh|. + static BrowserCdmManager* Create(RenderFrameHost* rfh); + + ~BrowserCdmManager(); + + media::BrowserCdm* GetCdm(int cdm_id); + + // CDM callbacks. + void OnSessionCreated(int cdm_id, + uint32 session_id, + const std::string& web_session_id); + void OnSessionMessage(int cdm_id, + uint32 session_id, + const std::vector<uint8>& message, + const GURL& destination_url); + void OnSessionReady(int cdm_id, uint32 session_id); + void OnSessionClosed(int cdm_id, uint32 session_id); + void OnSessionError(int cdm_id, + uint32 session_id, + media::MediaKeys::KeyError error_code, + uint32 system_code); + + // Message handlers. + void OnInitializeCdm(int cdm_id, + const std::string& key_system, + const GURL& frame_url); + void OnCreateSession(int cdm_id, + uint32 session_id, + CdmHostMsg_CreateSession_ContentType content_type, + const std::vector<uint8>& init_data); + void OnUpdateSession(int cdm_id, + uint32 session_id, + const std::vector<uint8>& response); + void OnReleaseSession(int cdm_id, uint32 session_id); + void OnSetCdm(int player_id, int cdm_id); + void OnDestroyCdm(int cdm_id); + + private: + // Clients must use Create() or subclass constructor. + explicit BrowserCdmManager(RenderFrameHost* render_frame_host); + + // Cancels all pending session creations associated with |cdm_id|. + void CancelAllPendingSessionCreations(int cdm_id); + + // Adds a new CDM identified by |cdm_id| for the given |key_system| and + // |security_origin|. + void AddCdm(int cdm_id, + const std::string& key_system, + const GURL& security_origin); + + // Removes the CDM with the specified id. + void RemoveCdm(int cdm_id); + + int RoutingID(); + + // Helper function to send messages to RenderFrameObserver. + bool Send(IPC::Message* msg); + + // If |permitted| is false, it does nothing but send + // |CdmMsg_SessionError| IPC message. + // The primary use case is infobar permission callback, i.e., when infobar + // can decide user's intention either from interacting with the actual info + // bar or from the saved preference. + void CreateSessionIfPermitted(int cdm_id, + uint32 session_id, + const std::string& content_type, + const std::vector<uint8>& init_data, + bool permitted); + + RenderFrameHost* const render_frame_host_; + + WebContents* const web_contents_; + + // A map from CDM IDs to managed CDMs. + // TODO(xhwang): Use ScopedPtrHashMap for CdmMap. + typedef std::map<int, media::BrowserCdm*> CdmMap; + CdmMap cdm_map_; + + // Map from CDM ID to CDM's security origin. + std::map<int, GURL> cdm_security_origin_map_; + + // NOTE: Weak pointers must be invalidated before all other member variables. + base::WeakPtrFactory<BrowserCdmManager> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(BrowserCdmManager); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_CDM_MANAGER_H_ diff --git a/content/browser/media/android/browser_media_player_manager.cc b/content/browser/media/android/browser_media_player_manager.cc index a4c5e0a..c2e4df6 100644 --- a/content/browser/media/android/browser_media_player_manager.cc +++ b/content/browser/media/android/browser_media_player_manager.cc @@ -6,13 +6,11 @@ #include "base/android/scoped_java_ref.h" #include "base/command_line.h" -#include "base/stl_util.h" #include "content/browser/android/content_view_core_impl.h" #include "content/browser/media/android/browser_demuxer_android.h" #include "content/browser/media/android/media_resource_getter_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_view_android.h" -#include "content/common/media/cdm_messages.h" #include "content/common/media/media_player_messages_android.h" #include "content/public/browser/android/content_view_core.h" #include "content/public/browser/android/external_video_surface_container.h" @@ -28,12 +26,8 @@ #include "content/public/common/content_switches.h" #include "media/base/android/media_player_bridge.h" #include "media/base/android/media_source_player.h" -#include "media/base/browser_cdm.h" -#include "media/base/browser_cdm_factory.h" #include "media/base/media_switches.h" -using media::BrowserCdm; -using media::MediaKeys; using media::MediaPlayerAndroid; using media::MediaPlayerBridge; using media::MediaPlayerManager; @@ -45,13 +39,6 @@ namespace content { // attempting to release inactive media players. const int kMediaPlayerThreshold = 1; -// Maximum lengths for various EME API parameters. These are checks to -// prevent unnecessarily large parameters from being passed around, and the -// lengths are somewhat arbitrary as the EME spec doesn't specify any limits. -const size_t kMaxInitDataLength = 64 * 1024; // 64 KB -const size_t kMaxSessionResponseLength = 64 * 1024; // 64 KB -const size_t kMaxKeySystemLength = 256; - static BrowserMediaPlayerManager::Factory g_factory = NULL; // static @@ -319,14 +306,8 @@ MediaPlayerAndroid* BrowserMediaPlayerManager::GetPlayer(int player_id) { return NULL; } -BrowserCdm* BrowserMediaPlayerManager::GetCdm(int cdm_id) { - CdmMap::const_iterator iter = cdm_map_.find(cdm_id); - return (iter == cdm_map_.end()) ? NULL : iter->second; -} - void BrowserMediaPlayerManager::DestroyAllMediaPlayers() { players_.clear(); - STLDeleteValues(&cdm_map_); if (fullscreen_player_id_ != -1) { video_view_.reset(); fullscreen_player_id_ = -1; @@ -344,48 +325,6 @@ void BrowserMediaPlayerManager::RequestFullScreen(int player_id) { } } -// The following 5 functions are EME MediaKeySession events. - -void BrowserMediaPlayerManager::OnSessionCreated( - int cdm_id, - uint32 session_id, - const std::string& web_session_id) { - Send(new CdmMsg_SessionCreated( - RoutingID(), cdm_id, session_id, web_session_id)); -} - -void BrowserMediaPlayerManager::OnSessionMessage( - int cdm_id, - uint32 session_id, - const std::vector<uint8>& message, - const GURL& destination_url) { - GURL verified_gurl = destination_url; - if (!verified_gurl.is_valid() && !verified_gurl.is_empty()) { - DLOG(WARNING) << "SessionMessage destination_url is invalid : " - << destination_url.possibly_invalid_spec(); - verified_gurl = GURL::EmptyGURL(); // Replace invalid destination_url. - } - - Send(new CdmMsg_SessionMessage( - RoutingID(), cdm_id, session_id, message, verified_gurl)); -} - -void BrowserMediaPlayerManager::OnSessionReady(int cdm_id, uint32 session_id) { - Send(new CdmMsg_SessionReady(RoutingID(), cdm_id, session_id)); -} - -void BrowserMediaPlayerManager::OnSessionClosed(int cdm_id, uint32 session_id) { - Send(new CdmMsg_SessionClosed(RoutingID(), cdm_id, session_id)); -} - -void BrowserMediaPlayerManager::OnSessionError(int cdm_id, - uint32 session_id, - MediaKeys::KeyError error_code, - uint32 system_code) { - Send(new CdmMsg_SessionError( - RoutingID(), cdm_id, session_id, error_code, system_code)); -} - #if defined(VIDEO_HOLE) void BrowserMediaPlayerManager::AttachExternalVideoSurface(int player_id, jobject surface) { @@ -556,139 +495,6 @@ void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) { fullscreen_player_id_ = -1; } -void BrowserMediaPlayerManager::OnInitializeCdm(int cdm_id, - const std::string& key_system, - const GURL& security_origin) { - if (key_system.size() > kMaxKeySystemLength) { - // This failure will be discovered and reported by OnCreateSession() - // as GetCdm() will return null. - NOTREACHED() << "Invalid key system: " << key_system; - return; - } - - AddCdm(cdm_id, key_system, security_origin); -} - -void BrowserMediaPlayerManager::OnCreateSession( - int cdm_id, - uint32 session_id, - CdmHostMsg_CreateSession_ContentType content_type, - const std::vector<uint8>& init_data) { - if (init_data.size() > kMaxInitDataLength) { - LOG(WARNING) << "InitData for ID: " << cdm_id - << " too long: " << init_data.size(); - OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); - return; - } - - // Convert the session content type into a MIME type. "audio" and "video" - // don't matter, so using "video" for the MIME type. - // Ref: - // https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-createsession - std::string mime_type; - switch (content_type) { - case CREATE_SESSION_TYPE_WEBM: - mime_type = "video/webm"; - break; - case CREATE_SESSION_TYPE_MP4: - mime_type = "video/mp4"; - break; - default: - NOTREACHED(); - return; - } - - if (CommandLine::ForCurrentProcess() - ->HasSwitch(switches::kDisableInfobarForProtectedMediaIdentifier)) { - CreateSessionIfPermitted(cdm_id, session_id, mime_type, init_data, true); - return; - } - - BrowserCdm* cdm = GetCdm(cdm_id); - if (!cdm) { - DLOG(WARNING) << "No CDM for ID " << cdm_id << " found"; - OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); - return; - } - - BrowserContext* context = - web_contents()->GetRenderProcessHost()->GetBrowserContext(); - - std::map<int, GURL>::const_iterator iter = - cdm_security_origin_map_.find(cdm_id); - if (iter == cdm_security_origin_map_.end()) { - NOTREACHED(); - OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); - return; - } - - context->RequestProtectedMediaIdentifierPermission( - web_contents()->GetRenderProcessHost()->GetID(), - web_contents()->GetRenderViewHost()->GetRoutingID(), - iter->second, - base::Bind(&BrowserMediaPlayerManager::CreateSessionIfPermitted, - weak_ptr_factory_.GetWeakPtr(), - cdm_id, - session_id, - mime_type, - init_data)); -} - -void BrowserMediaPlayerManager::OnUpdateSession( - int cdm_id, - uint32 session_id, - const std::vector<uint8>& response) { - BrowserCdm* cdm = GetCdm(cdm_id); - if (!cdm) { - DLOG(WARNING) << "No CDM for ID " << cdm_id << " found"; - OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); - return; - } - - if (response.size() > kMaxSessionResponseLength) { - LOG(WARNING) << "Response for ID " << cdm_id - << " is too long: " << response.size(); - OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); - return; - } - - cdm->UpdateSession(session_id, &response[0], response.size()); -} - -void BrowserMediaPlayerManager::OnReleaseSession(int cdm_id, - uint32 session_id) { - BrowserCdm* cdm = GetCdm(cdm_id); - if (!cdm) { - DLOG(WARNING) << "No CDM for ID " << cdm_id << " found"; - OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); - return; - } - - cdm->ReleaseSession(session_id); -} - -void BrowserMediaPlayerManager::OnDestroyCdm(int cdm_id) { - BrowserCdm* cdm = GetCdm(cdm_id); - if (!cdm) - return; - - CancelAllPendingSessionCreations(cdm_id); - RemoveCdm(cdm_id); -} - -void BrowserMediaPlayerManager::CancelAllPendingSessionCreations(int cdm_id) { - BrowserContext* context = - web_contents()->GetRenderProcessHost()->GetBrowserContext(); - std::map<int, GURL>::const_iterator iter = - cdm_security_origin_map_.find(cdm_id); - if (iter == cdm_security_origin_map_.end()) - return; - context->CancelProtectedMediaIdentifierPermissionRequests( - web_contents()->GetRenderProcessHost()->GetID(), - web_contents()->GetRenderViewHost()->GetRoutingID(), - iter->second); -} - void BrowserMediaPlayerManager::AddPlayer(MediaPlayerAndroid* player) { DCHECK(!GetPlayer(player->player_id())); players_.push_back(player); @@ -720,60 +526,6 @@ scoped_ptr<media::MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer( return scoped_ptr<media::MediaPlayerAndroid>(previous_player); } -void BrowserMediaPlayerManager::AddCdm(int cdm_id, - const std::string& key_system, - const GURL& security_origin) { - DCHECK(!GetCdm(cdm_id)); - base::WeakPtr<BrowserMediaPlayerManager> weak_this = - weak_ptr_factory_.GetWeakPtr(); - - int id = cdm_id; - scoped_ptr<BrowserCdm> cdm(media::CreateBrowserCdm( - key_system, - base::Bind(&BrowserMediaPlayerManager::OnSessionCreated, weak_this, id), - base::Bind(&BrowserMediaPlayerManager::OnSessionMessage, weak_this, id), - base::Bind(&BrowserMediaPlayerManager::OnSessionReady, weak_this, id), - base::Bind(&BrowserMediaPlayerManager::OnSessionClosed, weak_this, id), - base::Bind(&BrowserMediaPlayerManager::OnSessionError, weak_this, id))); - - if (!cdm) { - // This failure will be discovered and reported by OnCreateSession() - // as GetCdm() will return null. - DVLOG(1) << "failed to create CDM."; - return; - } - - cdm_map_[cdm_id] = cdm.release(); - cdm_security_origin_map_[cdm_id] = security_origin; -} - -void BrowserMediaPlayerManager::RemoveCdm(int cdm_id) { - // TODO(xhwang): Detach CDM from the player it's set to. In prefixed - // EME implementation the current code is fine because we always destroy the - // player before we destroy the DrmBridge. This will not always be the case - // in unprefixed EME implementation. - CdmMap::iterator iter = cdm_map_.find(cdm_id); - if (iter != cdm_map_.end()) { - delete iter->second; - cdm_map_.erase(iter); - } - cdm_security_origin_map_.erase(cdm_id); -} - -void BrowserMediaPlayerManager::OnSetCdm(int player_id, int cdm_id) { - MediaPlayerAndroid* player = GetPlayer(player_id); - BrowserCdm* cdm = GetCdm(cdm_id); - // Currently we do not support detaching CDM from a player. - if (!cdm || !player) { - NOTREACHED() << "Cannot set CDM on the specified player."; - return; - } - - // TODO(qinmin): add the logic to decide whether we should create the - // fullscreen surface for EME lv1. - player->SetCdm(cdm); -} - int BrowserMediaPlayerManager::RoutingID() { return render_frame_host_->GetRoutingID(); } @@ -782,28 +534,6 @@ bool BrowserMediaPlayerManager::Send(IPC::Message* msg) { return render_frame_host_->Send(msg); } -void BrowserMediaPlayerManager::CreateSessionIfPermitted( - int cdm_id, - uint32 session_id, - const std::string& content_type, - const std::vector<uint8>& init_data, - bool permitted) { - if (!permitted) { - OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); - return; - } - - BrowserCdm* cdm = GetCdm(cdm_id); - if (!cdm) { - DLOG(WARNING) << "No CDM for ID: " << cdm_id << " found"; - OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0); - return; - } - - // This could fail, in which case a SessionError will be fired. - cdm->CreateSession(session_id, content_type, &init_data[0], init_data.size()); -} - void BrowserMediaPlayerManager::ReleaseFullscreenPlayer( MediaPlayerAndroid* player) { player->Release(); diff --git a/content/browser/media/android/browser_media_player_manager.h b/content/browser/media/android/browser_media_player_manager.h index b313b39..4da685e 100644 --- a/content/browser/media/android/browser_media_player_manager.h +++ b/content/browser/media/android/browser_media_player_manager.h @@ -5,11 +5,6 @@ #ifndef CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_MEDIA_PLAYER_MANAGER_H_ #define CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_MEDIA_PLAYER_MANAGER_H_ -#include <map> -#include <set> -#include <string> -#include <vector> - #include "base/basictypes.h" #include "base/callback.h" #include "base/memory/scoped_ptr.h" @@ -17,17 +12,14 @@ #include "base/time/time.h" #include "content/browser/android/content_video_view.h" #include "content/common/content_export.h" -#include "content/common/media/cdm_messages_enums.h" #include "content/common/media/media_player_messages_enums_android.h" #include "ipc/ipc_message.h" #include "media/base/android/media_player_android.h" #include "media/base/android/media_player_manager.h" -#include "media/base/media_keys.h" #include "ui/gfx/rect_f.h" #include "url/gurl.h" namespace media { -class BrowserCdm; class DemuxerAndroid; } @@ -38,11 +30,11 @@ class ExternalVideoSurfaceContainer; class RenderFrameHost; class WebContents; -// This class manages all the MediaPlayerAndroid and CDM objects. +// This class manages all the MediaPlayerAndroid objects. // It receives control operations from the the render process, and forwards -// them to corresponding MediaPlayerAndroid or CDM object. Callbacks from -// MediaPlayerAndroid and CDM objects are converted to IPCs and then sent to -// the render process. +// them to corresponding MediaPlayerAndroid object. Callbacks from +// MediaPlayerAndroid objects are converted to IPCs and then sent to the render +// process. class CONTENT_EXPORT BrowserMediaPlayerManager : public media::MediaPlayerManager { public: @@ -92,22 +84,8 @@ class CONTENT_EXPORT BrowserMediaPlayerManager virtual media::MediaResourceGetter* GetMediaResourceGetter() OVERRIDE; virtual media::MediaPlayerAndroid* GetFullscreenPlayer() OVERRIDE; virtual media::MediaPlayerAndroid* GetPlayer(int player_id) OVERRIDE; - virtual media::BrowserCdm* GetCdm(int cdm_id) OVERRIDE; virtual void DestroyAllMediaPlayers() OVERRIDE; virtual void RequestFullScreen(int player_id) OVERRIDE; - virtual void OnSessionCreated(int cdm_id, - uint32 session_id, - const std::string& web_session_id) OVERRIDE; - virtual void OnSessionMessage(int cdm_id, - uint32 session_id, - const std::vector<uint8>& message, - const GURL& destination_url) OVERRIDE; - virtual void OnSessionReady(int cdm_id, uint32 session_id) OVERRIDE; - virtual void OnSessionClosed(int cdm_id, uint32 session_id) OVERRIDE; - virtual void OnSessionError(int cdm_id, - uint32 session_id, - media::MediaKeys::KeyError error_code, - uint32 system_code) OVERRIDE; #if defined(VIDEO_HOLE) void AttachExternalVideoSurface(int player_id, jobject surface); @@ -132,19 +110,6 @@ class CONTENT_EXPORT BrowserMediaPlayerManager virtual void OnReleaseResources(int player_id); virtual void OnDestroyPlayer(int player_id); virtual void ReleaseFullscreenPlayer(media::MediaPlayerAndroid* player); - void OnInitializeCdm(int cdm_id, - const std::string& key_system, - const GURL& frame_url); - void OnCreateSession(int cdm_id, - uint32 session_id, - CdmHostMsg_CreateSession_ContentType content_type, - const std::vector<uint8>& init_data); - void OnUpdateSession(int cdm_id, - uint32 session_id, - const std::vector<uint8>& response); - void OnReleaseSession(int cdm_id, uint32 session_id); - void OnSetCdm(int player_id, int cdm_id); - void OnDestroyCdm(int cdm_id); #if defined(VIDEO_HOLE) void OnNotifyExternalSurface( int player_id, bool is_request, const gfx::RectF& rect); @@ -156,9 +121,6 @@ class CONTENT_EXPORT BrowserMediaPlayerManager WebContents* web_contents() const { return web_contents_; } - // Cancels all pending session creations associated with |cdm_id|. - void CancelAllPendingSessionCreations(int cdm_id); - // Adds a given player to the list. void AddPlayer(media::MediaPlayerAndroid* player); @@ -172,32 +134,12 @@ class CONTENT_EXPORT BrowserMediaPlayerManager int player_id, media::MediaPlayerAndroid* player); - // Adds a new CDM identified by |cdm_id| for the given |key_system| and - // |security_origin|. - void AddCdm(int cdm_id, - const std::string& key_system, - const GURL& security_origin); - - // Removes the CDM with the specified id. - void RemoveCdm(int cdm_id); - int RoutingID(); // Helper function to send messages to RenderFrameObserver. bool Send(IPC::Message* msg); private: - // If |permitted| is false, it does nothing but send - // |CdmMsg_SessionError| IPC message. - // The primary use case is infobar permission callback, i.e., when infobar - // can decide user's intention either from interacting with the actual info - // bar or from the saved preference. - void CreateSessionIfPermitted(int cdm_id, - uint32 session_id, - const std::string& content_type, - const std::vector<uint8>& init_data, - bool permitted); - // Constructs a MediaPlayerAndroid object. media::MediaPlayerAndroid* CreateMediaPlayer( MediaPlayerHostMsg_Initialize_Type type, @@ -229,13 +171,6 @@ class CONTENT_EXPORT BrowserMediaPlayerManager // An array of managed players. ScopedVector<media::MediaPlayerAndroid> players_; - // A map from CDM IDs to managed CDMs. - typedef std::map<int, media::BrowserCdm*> CdmMap; - CdmMap cdm_map_; - - // Map from CDM ID to CDM's security origin. - std::map<int, GURL> cdm_security_origin_map_; - // The fullscreen video view object or NULL if video is not played in // fullscreen. scoped_ptr<ContentVideoView> video_view_; diff --git a/content/browser/media/android/media_web_contents_observer.cc b/content/browser/media/android/media_web_contents_observer.cc index 711375c..063085b 100644 --- a/content/browser/media/android/media_web_contents_observer.cc +++ b/content/browser/media/android/media_web_contents_observer.cc @@ -4,16 +4,22 @@ #include "content/browser/media/android/media_web_contents_observer.h" +#include "base/memory/scoped_ptr.h" #include "base/stl_util.h" +#include "content/browser/media/android/browser_cdm_manager.h" #include "content/browser/media/android/browser_media_player_manager.h" #include "content/common/media/cdm_messages.h" #include "content/common/media/media_player_messages_android.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "ipc/ipc_message_macros.h" +#include "media/base/android/media_player_android.h" namespace content { +using media::BrowserCdm; +using media::MediaPlayerAndroid; + MediaWebContentsObserver::MediaWebContentsObserver( RenderViewHost* render_view_host) : WebContentsObserver(WebContents::FromRenderViewHost(render_view_host)) { @@ -26,90 +32,151 @@ void MediaWebContentsObserver::RenderFrameDeleted( RenderFrameHost* render_frame_host) { uintptr_t key = reinterpret_cast<uintptr_t>(render_frame_host); media_player_managers_.erase(key); + cdm_managers_.erase(key); } bool MediaWebContentsObserver::OnMessageReceived( const IPC::Message& msg, RenderFrameHost* render_frame_host) { - BrowserMediaPlayerManager* player_manager = - GetMediaPlayerManager(render_frame_host); - DCHECK(player_manager); + if (OnMediaPlayerMessageReceived(msg, render_frame_host)) + return true; + + if (OnCdmMessageReceived(msg, render_frame_host)) + return true; + + if (OnMediaPlayerSetCdmMessageReceived(msg, render_frame_host)) + return true; + return false; +} + +bool MediaWebContentsObserver::OnMediaPlayerMessageReceived( + const IPC::Message& msg, + RenderFrameHost* render_frame_host) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(MediaWebContentsObserver, msg) IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_EnterFullscreen, - player_manager, + GetMediaPlayerManager(render_frame_host), BrowserMediaPlayerManager::OnEnterFullscreen) IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_ExitFullscreen, - player_manager, + GetMediaPlayerManager(render_frame_host), BrowserMediaPlayerManager::OnExitFullscreen) IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Initialize, - player_manager, + GetMediaPlayerManager(render_frame_host), BrowserMediaPlayerManager::OnInitialize) IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Start, - player_manager, + GetMediaPlayerManager(render_frame_host), BrowserMediaPlayerManager::OnStart) IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Seek, - player_manager, + GetMediaPlayerManager(render_frame_host), BrowserMediaPlayerManager::OnSeek) IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Pause, - player_manager, + GetMediaPlayerManager(render_frame_host), BrowserMediaPlayerManager::OnPause) IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_SetVolume, - player_manager, + GetMediaPlayerManager(render_frame_host), BrowserMediaPlayerManager::OnSetVolume) IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_SetPoster, - player_manager, + GetMediaPlayerManager(render_frame_host), BrowserMediaPlayerManager::OnSetPoster) IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Release, - player_manager, + GetMediaPlayerManager(render_frame_host), BrowserMediaPlayerManager::OnReleaseResources) IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_DestroyMediaPlayer, - player_manager, + GetMediaPlayerManager(render_frame_host), BrowserMediaPlayerManager::OnDestroyPlayer) IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_DestroyAllMediaPlayers, - player_manager, + GetMediaPlayerManager(render_frame_host), BrowserMediaPlayerManager::DestroyAllMediaPlayers) - IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_SetCdm, - player_manager, - BrowserMediaPlayerManager::OnSetCdm) +#if defined(VIDEO_HOLE) + IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_NotifyExternalSurface, + GetMediaPlayerManager(render_frame_host), + BrowserMediaPlayerManager::OnNotifyExternalSurface) +#endif // defined(VIDEO_HOLE) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +bool MediaWebContentsObserver::OnCdmMessageReceived( + const IPC::Message& msg, + RenderFrameHost* render_frame_host) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(MediaWebContentsObserver, msg) IPC_MESSAGE_FORWARD(CdmHostMsg_InitializeCdm, - player_manager, - BrowserMediaPlayerManager::OnInitializeCdm) + GetCdmManager(render_frame_host), + BrowserCdmManager::OnInitializeCdm) IPC_MESSAGE_FORWARD(CdmHostMsg_CreateSession, - player_manager, - BrowserMediaPlayerManager::OnCreateSession) + GetCdmManager(render_frame_host), + BrowserCdmManager::OnCreateSession) IPC_MESSAGE_FORWARD(CdmHostMsg_UpdateSession, - player_manager, - BrowserMediaPlayerManager::OnUpdateSession) + GetCdmManager(render_frame_host), + BrowserCdmManager::OnUpdateSession) IPC_MESSAGE_FORWARD(CdmHostMsg_ReleaseSession, - player_manager, - BrowserMediaPlayerManager::OnReleaseSession) + GetCdmManager(render_frame_host), + BrowserCdmManager::OnReleaseSession) IPC_MESSAGE_FORWARD(CdmHostMsg_DestroyCdm, - player_manager, - BrowserMediaPlayerManager::OnDestroyCdm) -#if defined(VIDEO_HOLE) - IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_NotifyExternalSurface, - player_manager, - BrowserMediaPlayerManager::OnNotifyExternalSurface) -#endif // defined(VIDEO_HOLE) + GetCdmManager(render_frame_host), + BrowserCdmManager::OnDestroyCdm) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } +bool MediaWebContentsObserver::OnMediaPlayerSetCdmMessageReceived( + const IPC::Message& msg, + RenderFrameHost* render_frame_host) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP_WITH_PARAM( + MediaWebContentsObserver, msg, render_frame_host) + IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_SetCdm, OnSetCdm) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void MediaWebContentsObserver::OnSetCdm(RenderFrameHost* render_frame_host, + int player_id, + int cdm_id) { + MediaPlayerAndroid* media_player = + GetMediaPlayerManager(render_frame_host)->GetPlayer(player_id); + if (!media_player) { + NOTREACHED() << "OnSetCdm: MediaPlayer not found for " << player_id; + return; + } + + BrowserCdm* cdm = GetCdmManager(render_frame_host)->GetCdm(cdm_id); + if (!cdm) { + NOTREACHED() << "OnSetCdm: CDM not found for " << cdm_id; + return; + } + + // TODO(xhwang): This could possibly fail. In that case we should reject the + // promise. + media_player->SetCdm(cdm); +} + BrowserMediaPlayerManager* MediaWebContentsObserver::GetMediaPlayerManager( RenderFrameHost* render_frame_host) { uintptr_t key = reinterpret_cast<uintptr_t>(render_frame_host); if (!media_player_managers_.contains(key)) { media_player_managers_.set( key, - scoped_ptr<BrowserMediaPlayerManager>( - BrowserMediaPlayerManager::Create(render_frame_host))); + make_scoped_ptr(BrowserMediaPlayerManager::Create(render_frame_host))); } return media_player_managers_.get(key); } +BrowserCdmManager* MediaWebContentsObserver::GetCdmManager( + RenderFrameHost* render_frame_host) { + uintptr_t key = reinterpret_cast<uintptr_t>(render_frame_host); + if (!cdm_managers_.contains(key)) { + cdm_managers_.set( + key, make_scoped_ptr(BrowserCdmManager::Create(render_frame_host))); + } + return cdm_managers_.get(key); +} + void MediaWebContentsObserver::PauseVideo() { for (MediaPlayerManagerMap::iterator iter = media_player_managers_.begin(); iter != media_player_managers_.end(); ++iter) { diff --git a/content/browser/media/android/media_web_contents_observer.h b/content/browser/media/android/media_web_contents_observer.h index 126bbfb..38b82b2 100644 --- a/content/browser/media/android/media_web_contents_observer.h +++ b/content/browser/media/android/media_web_contents_observer.h @@ -12,6 +12,7 @@ namespace content { +class BrowserCdmManager; class BrowserMediaPlayerManager; class RenderViewHost; @@ -29,11 +30,26 @@ class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver { virtual bool OnMessageReceived(const IPC::Message& message, RenderFrameHost* render_frame_host) OVERRIDE; + // Helper functions to handle various IPC messages. Returns whether the + // |message| is handled in the function. + bool OnMediaPlayerMessageReceived(const IPC::Message& message, + RenderFrameHost* render_frame_host); + bool OnCdmMessageReceived(const IPC::Message& message, + RenderFrameHost* render_frame_host); + bool OnMediaPlayerSetCdmMessageReceived(const IPC::Message& message, + RenderFrameHost* render_frame_host); + // Gets the media player manager associated with |render_frame_host|. Creates // a new one if it doesn't exist. The caller doesn't own the returned pointer. BrowserMediaPlayerManager* GetMediaPlayerManager( RenderFrameHost* render_frame_host); + // Gets the CDM manager associated with |render_frame_host|. Creates + // a new one if it doesn't exist. The caller doesn't own the returned pointer. + BrowserCdmManager* GetCdmManager(RenderFrameHost* render_frame_host); + + void OnSetCdm(RenderFrameHost* render_frame_host, int player_id, int cdm_id); + // Pauses all media player. void PauseVideo(); @@ -47,6 +63,10 @@ class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver { MediaPlayerManagerMap; MediaPlayerManagerMap media_player_managers_; + // Map from RenderFrameHost* to BrowserCdmManager. + typedef base::ScopedPtrHashMap<uintptr_t, BrowserCdmManager> CdmManagerMap; + CdmManagerMap cdm_managers_; + DISALLOW_COPY_AND_ASSIGN(MediaWebContentsObserver); }; diff --git a/content/content_browser.gypi b/content/content_browser.gypi index e4d5803..4758aeb 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -781,6 +781,8 @@ 'browser/loader/upload_data_stream_builder.h', 'browser/mach_broker_mac.h', 'browser/mach_broker_mac.mm', + 'browser/media/android/browser_cdm_manager.cc', + 'browser/media/android/browser_cdm_manager.h', 'browser/media/android/browser_demuxer_android.cc', 'browser/media/android/browser_demuxer_android.h', 'browser/media/android/browser_media_player_manager.cc', |