summaryrefslogtreecommitdiffstats
path: root/media/cdm
diff options
context:
space:
mode:
authorxhwang <xhwang@chromium.org>2015-04-13 16:27:53 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-13 23:28:16 +0000
commit9bd8c733478345d0331fcdfd79e0bc61e22be68a (patch)
treee0f9b48a66b754fd1059b4262139e48355d74677 /media/cdm
parent4750c60c18a430a111920978f82aa476bcb6b1de (diff)
downloadchromium_src-9bd8c733478345d0331fcdfd79e0bc61e22be68a.zip
chromium_src-9bd8c733478345d0331fcdfd79e0bc61e22be68a.tar.gz
chromium_src-9bd8c733478345d0331fcdfd79e0bc61e22be68a.tar.bz2
media: CdmFactory creates CDM (MediaKeys) asynchronously.
This CL fixes the EME stack down to CdmFactory. The real aync CDM creation will be fixed in a separate CL. For unprefixed EME, since it's promise based, async creation of CDM fits easily. For prefixed EME, GenerateKeyRequest() can be called multiple times without waiting for the real CDM to be created/loaded. ProxyDecryptor is modified to handle this case. BUG=469003 TEST=All existing tests pass. Review URL: https://codereview.chromium.org/1070853004 Cr-Commit-Position: refs/heads/master@{#324942}
Diffstat (limited to 'media/cdm')
-rw-r--r--media/cdm/default_cdm_factory.cc26
-rw-r--r--media/cdm/default_cdm_factory.h20
-rw-r--r--media/cdm/proxy_decryptor.cc165
-rw-r--r--media/cdm/proxy_decryptor.h50
4 files changed, 171 insertions, 90 deletions
diff --git a/media/cdm/default_cdm_factory.cc b/media/cdm/default_cdm_factory.cc
index a87760c..202f3cd 100644
--- a/media/cdm/default_cdm_factory.cc
+++ b/media/cdm/default_cdm_factory.cc
@@ -4,6 +4,10 @@
#include "media/cdm/default_cdm_factory.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/message_loop/message_loop_proxy.h"
#include "media/base/key_systems.h"
#include "media/cdm/aes_decryptor.h"
#include "url/gurl.h"
@@ -16,7 +20,7 @@ DefaultCdmFactory::DefaultCdmFactory() {
DefaultCdmFactory::~DefaultCdmFactory() {
}
-scoped_ptr<MediaKeys> DefaultCdmFactory::Create(
+void DefaultCdmFactory::Create(
const std::string& key_system,
bool allow_distinctive_identifier,
bool allow_persistent_state,
@@ -25,17 +29,19 @@ scoped_ptr<MediaKeys> DefaultCdmFactory::Create(
const SessionClosedCB& session_closed_cb,
const LegacySessionErrorCB& legacy_session_error_cb,
const SessionKeysChangeCB& session_keys_change_cb,
- const SessionExpirationUpdateCB& session_expiration_update_cb) {
- if (!security_origin.is_valid())
- return nullptr;
-
- if (CanUseAesDecryptor(key_system)) {
- return make_scoped_ptr(new AesDecryptor(security_origin, session_message_cb,
- session_closed_cb,
- session_keys_change_cb));
+ const SessionExpirationUpdateCB& session_expiration_update_cb,
+ const CdmCreatedCB& cdm_created_cb) {
+ if (!security_origin.is_valid() || !CanUseAesDecryptor(key_system)) {
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE, base::Bind(cdm_created_cb, nullptr));
+ return;
}
- return nullptr;
+ scoped_ptr<MediaKeys> cdm(
+ new AesDecryptor(security_origin, session_message_cb, session_closed_cb,
+ session_keys_change_cb));
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE, base::Bind(cdm_created_cb, base::Passed(&cdm)));
}
} // namespace media
diff --git a/media/cdm/default_cdm_factory.h b/media/cdm/default_cdm_factory.h
index 72e0e8d..7060c7c 100644
--- a/media/cdm/default_cdm_factory.h
+++ b/media/cdm/default_cdm_factory.h
@@ -16,16 +16,16 @@ class DefaultCdmFactory : public CdmFactory {
~DefaultCdmFactory() final;
// CdmFactory implementation.
- scoped_ptr<MediaKeys> Create(
- const std::string& key_system,
- bool allow_distinctive_identifier,
- bool allow_persistent_state,
- const GURL& security_origin,
- const SessionMessageCB& session_message_cb,
- const SessionClosedCB& session_closed_cb,
- const LegacySessionErrorCB& legacy_session_error_cb,
- const SessionKeysChangeCB& session_keys_change_cb,
- const SessionExpirationUpdateCB& session_expiration_update_cb) final;
+ void Create(const std::string& key_system,
+ bool allow_distinctive_identifier,
+ bool allow_persistent_state,
+ const GURL& security_origin,
+ const SessionMessageCB& session_message_cb,
+ const SessionClosedCB& session_closed_cb,
+ const LegacySessionErrorCB& legacy_session_error_cb,
+ const SessionKeysChangeCB& session_keys_change_cb,
+ const SessionExpirationUpdateCB& session_expiration_update_cb,
+ const CdmCreatedCB& cdm_created_cb) final;
private:
DISALLOW_COPY_AND_ASSIGN(DefaultCdmFactory);
diff --git a/media/cdm/proxy_decryptor.cc b/media/cdm/proxy_decryptor.cc
index 944b614..9260e14 100644
--- a/media/cdm/proxy_decryptor.cc
+++ b/media/cdm/proxy_decryptor.cc
@@ -25,11 +25,22 @@ namespace media {
// EME API.
const int kSessionClosedSystemCode = 29127;
+ProxyDecryptor::PendingGenerateKeyRequestData::PendingGenerateKeyRequestData(
+ EmeInitDataType init_data_type,
+ const std::vector<uint8>& init_data)
+ : init_data_type(init_data_type), init_data(init_data) {
+}
+
+ProxyDecryptor::PendingGenerateKeyRequestData::
+ ~PendingGenerateKeyRequestData() {
+}
+
ProxyDecryptor::ProxyDecryptor(MediaPermission* media_permission,
const KeyAddedCB& key_added_cb,
const KeyErrorCB& key_error_cb,
const KeyMessageCB& key_message_cb)
- : media_permission_(media_permission),
+ : is_creating_cdm_(false),
+ media_permission_(media_permission),
key_added_cb_(key_added_cb),
key_error_cb_(key_error_cb),
key_message_cb_(key_message_cb),
@@ -46,33 +57,77 @@ ProxyDecryptor::~ProxyDecryptor() {
media_keys_.reset();
}
-CdmContext* ProxyDecryptor::GetCdmContext() {
- return media_keys_ ? media_keys_->GetCdmContext() : nullptr;
+void ProxyDecryptor::CreateCdm(CdmFactory* cdm_factory,
+ const std::string& key_system,
+ const GURL& security_origin,
+ const CdmContextReadyCB& cdm_context_ready_cb) {
+ DVLOG(1) << __FUNCTION__ << ": key_system = " << key_system;
+ DCHECK(!is_creating_cdm_);
+ DCHECK(!media_keys_);
+
+ // TODO(sandersd): Trigger permissions check here and use it to determine
+ // distinctive identifier support, instead of always requiring the
+ // permission. http://crbug.com/455271
+ bool allow_distinctive_identifier = true;
+ bool allow_persistent_state = true;
+
+ is_creating_cdm_ = true;
+
+ base::WeakPtr<ProxyDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr();
+ cdm_factory->Create(
+ key_system, allow_distinctive_identifier, allow_persistent_state,
+ security_origin, base::Bind(&ProxyDecryptor::OnSessionMessage, weak_this),
+ base::Bind(&ProxyDecryptor::OnSessionClosed, weak_this),
+ base::Bind(&ProxyDecryptor::OnLegacySessionError, weak_this),
+ base::Bind(&ProxyDecryptor::OnSessionKeysChange, weak_this),
+ base::Bind(&ProxyDecryptor::OnSessionExpirationUpdate, weak_this),
+ base::Bind(&ProxyDecryptor::OnCdmCreated, weak_this, key_system,
+ security_origin, cdm_context_ready_cb));
}
-bool ProxyDecryptor::InitializeCDM(CdmFactory* cdm_factory,
- const std::string& key_system,
- const GURL& security_origin) {
- DVLOG(1) << "InitializeCDM: key_system = " << key_system;
+void ProxyDecryptor::OnCdmCreated(const std::string& key_system,
+ const GURL& security_origin,
+ const CdmContextReadyCB& cdm_context_ready_cb,
+ scoped_ptr<MediaKeys> cdm) {
+ is_creating_cdm_ = false;
- DCHECK(!media_keys_);
- media_keys_ = CreateMediaKeys(cdm_factory, key_system, security_origin);
- if (!media_keys_)
- return false;
+ if (!cdm) {
+ cdm_context_ready_cb.Run(nullptr);
+ return;
+ }
key_system_ = key_system;
security_origin_ = security_origin;
+ is_clear_key_ = IsClearKey(key_system) || IsExternalClearKey(key_system);
+ media_keys_ = cdm.Pass();
+
+ cdm_context_ready_cb.Run(media_keys_->GetCdmContext());
+
+ for (const auto& request : pending_requests_)
+ GenerateKeyRequestInternal(request->init_data_type, request->init_data);
+
+ pending_requests_.clear();
+}
+
+void ProxyDecryptor::GenerateKeyRequest(EmeInitDataType init_data_type,
+ const uint8* init_data,
+ int init_data_length) {
+ std::vector<uint8> init_data_vector(init_data, init_data + init_data_length);
+
+ if (is_creating_cdm_) {
+ pending_requests_.push_back(
+ new PendingGenerateKeyRequestData(init_data_type, init_data_vector));
+ return;
+ }
- is_clear_key_ =
- IsClearKey(key_system) || IsExternalClearKey(key_system);
- return true;
+ GenerateKeyRequestInternal(init_data_type, init_data_vector);
}
// Returns true if |data| is prefixed with |header| and has data after the
// |header|.
-bool HasHeader(const uint8* data, int data_length, const std::string& header) {
- return static_cast<size_t>(data_length) > header.size() &&
- std::equal(data, data + header.size(), header.begin());
+bool HasHeader(const std::vector<uint8>& data, const std::string& header) {
+ return data.size() > header.size() &&
+ std::equal(header.begin(), header.end(), data.begin());
}
// Removes the first |length| items from |data|.
@@ -80,23 +135,30 @@ void StripHeader(std::vector<uint8>& data, size_t length) {
data.erase(data.begin(), data.begin() + length);
}
-bool ProxyDecryptor::GenerateKeyRequest(EmeInitDataType init_data_type,
- const uint8* init_data,
- int init_data_length) {
- DVLOG(1) << "GenerateKeyRequest()";
+void ProxyDecryptor::GenerateKeyRequestInternal(
+ EmeInitDataType init_data_type,
+ const std::vector<uint8>& init_data) {
+ DVLOG(1) << __FUNCTION__;
+ DCHECK(!is_creating_cdm_);
+
+ if (!media_keys_) {
+ OnLegacySessionError(std::string(), MediaKeys::NOT_SUPPORTED_ERROR, 0,
+ "CDM creation failed.");
+ return;
+ }
+
const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|";
const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|";
SessionCreationType session_creation_type = TemporarySession;
- std::vector<uint8> init_data_vector(init_data, init_data + init_data_length);
- if (HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader)) {
+ std::vector<uint8> stripped_init_data = init_data;
+ if (HasHeader(init_data, kPrefixedApiLoadSessionHeader)) {
session_creation_type = LoadSession;
- StripHeader(init_data_vector, strlen(kPrefixedApiLoadSessionHeader));
- } else if (HasHeader(init_data,
- init_data_length,
- kPrefixedApiPersistentSessionHeader)) {
+ StripHeader(stripped_init_data, strlen(kPrefixedApiLoadSessionHeader));
+ } else if (HasHeader(init_data, kPrefixedApiPersistentSessionHeader)) {
session_creation_type = PersistentSession;
- StripHeader(init_data_vector, strlen(kPrefixedApiPersistentSessionHeader));
+ StripHeader(stripped_init_data,
+ strlen(kPrefixedApiPersistentSessionHeader));
}
scoped_ptr<NewSessionCdmPromise> promise(new CdmCallbackPromise<std::string>(
@@ -110,10 +172,10 @@ bool ProxyDecryptor::GenerateKeyRequest(EmeInitDataType init_data_type,
media_keys_->LoadSession(
MediaKeys::PERSISTENT_LICENSE_SESSION,
std::string(
- reinterpret_cast<const char*>(vector_as_array(&init_data_vector)),
- init_data_vector.size()),
+ reinterpret_cast<const char*>(vector_as_array(&stripped_init_data)),
+ stripped_init_data.size()),
promise.Pass());
- return true;
+ return;
}
MediaKeys::SessionType session_type =
@@ -125,9 +187,9 @@ bool ProxyDecryptor::GenerateKeyRequest(EmeInitDataType init_data_type,
// external clear key.
DCHECK(!key_system_.empty());
if (CanUseAesDecryptor(key_system_) || IsExternalClearKey(key_system_)) {
- OnPermissionStatus(session_type, init_data_type, init_data_vector,
+ OnPermissionStatus(session_type, init_data_type, stripped_init_data,
promise.Pass(), true /* granted */);
- return true;
+ return;
}
#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
@@ -135,13 +197,11 @@ bool ProxyDecryptor::GenerateKeyRequest(EmeInitDataType init_data_type,
MediaPermission::PROTECTED_MEDIA_IDENTIFIER, security_origin_,
base::Bind(&ProxyDecryptor::OnPermissionStatus,
weak_ptr_factory_.GetWeakPtr(), session_type, init_data_type,
- init_data_vector, base::Passed(&promise)));
+ stripped_init_data, base::Passed(&promise)));
#else
- OnPermissionStatus(session_type, init_data_type, init_data_vector,
+ OnPermissionStatus(session_type, init_data_type, stripped_init_data,
promise.Pass(), true /* granted */);
#endif
-
- return true;
}
void ProxyDecryptor::OnPermissionStatus(
@@ -168,6 +228,12 @@ void ProxyDecryptor::AddKey(const uint8* key,
const std::string& session_id) {
DVLOG(1) << "AddKey()";
+ if (!media_keys_) {
+ OnLegacySessionError(std::string(), MediaKeys::INVALID_STATE_ERROR, 0,
+ "CDM is not available.");
+ return;
+ }
+
// In the prefixed API, the session parameter provided to addKey() is
// optional, so use the single existing session if it exists.
std::string new_session_id(session_id);
@@ -216,6 +282,12 @@ void ProxyDecryptor::AddKey(const uint8* key,
void ProxyDecryptor::CancelKeyRequest(const std::string& session_id) {
DVLOG(1) << "CancelKeyRequest()";
+ if (!media_keys_) {
+ OnLegacySessionError(std::string(), MediaKeys::INVALID_STATE_ERROR, 0,
+ "CDM is not available.");
+ return;
+ }
+
scoped_ptr<SimpleCdmPromise> promise(new CdmCallbackPromise<>(
base::Bind(&ProxyDecryptor::OnSessionClosed,
weak_ptr_factory_.GetWeakPtr(), session_id),
@@ -224,25 +296,6 @@ void ProxyDecryptor::CancelKeyRequest(const std::string& session_id) {
media_keys_->RemoveSession(session_id, promise.Pass());
}
-scoped_ptr<MediaKeys> ProxyDecryptor::CreateMediaKeys(
- CdmFactory* cdm_factory,
- const std::string& key_system,
- const GURL& security_origin) {
- // TODO(sandersd): Trigger permissions check here and use it to determine
- // distinctive identifier support, instead of always requiring the
- // permission. http://crbug.com/455271
- bool allow_distinctive_identifier = true;
- bool allow_persistent_state = true;
- base::WeakPtr<ProxyDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr();
- return cdm_factory->Create(
- key_system, allow_distinctive_identifier, allow_persistent_state,
- security_origin, base::Bind(&ProxyDecryptor::OnSessionMessage, weak_this),
- base::Bind(&ProxyDecryptor::OnSessionClosed, weak_this),
- base::Bind(&ProxyDecryptor::OnLegacySessionError, weak_this),
- base::Bind(&ProxyDecryptor::OnSessionKeysChange, weak_this),
- base::Bind(&ProxyDecryptor::OnSessionExpirationUpdate, weak_this));
-}
-
void ProxyDecryptor::OnSessionMessage(const std::string& session_id,
MediaKeys::MessageType message_type,
const std::vector<uint8>& message,
diff --git a/media/cdm/proxy_decryptor.h b/media/cdm/proxy_decryptor.h
index ff611ad..9a17a98 100644
--- a/media/cdm/proxy_decryptor.h
+++ b/media/cdm/proxy_decryptor.h
@@ -11,7 +11,9 @@
#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
+#include "media/base/cdm_context.h"
#include "media/base/decryptor.h"
#include "media/base/eme_constants.h"
#include "media/base/media_export.h"
@@ -32,6 +34,10 @@ class MediaPermission;
// TODO(xhwang): The ProxyDecryptor is not a Decryptor. Find a better name!
class MEDIA_EXPORT ProxyDecryptor {
public:
+ // Callback to provide a CdmContext when the CDM creation is finished.
+ // If CDM creation failed, |cdm_context| will be null.
+ typedef base::Callback<void(CdmContext* cdm_context)> CdmContextReadyCB;
+
// These are similar to the callbacks in media_keys.h, but pass back the
// session ID rather than the internal session ID.
typedef base::Callback<void(const std::string& session_id)> KeyAddedCB;
@@ -48,16 +54,16 @@ class MEDIA_EXPORT ProxyDecryptor {
const KeyMessageCB& key_message_cb);
virtual ~ProxyDecryptor();
- // Returns the CdmContext associated with this object.
- CdmContext* GetCdmContext();
-
- // Only call this once.
- bool InitializeCDM(CdmFactory* cdm_factory,
- const std::string& key_system,
- const GURL& security_origin);
+ // Creates the CDM and fires |cdm_created_cb|. This method should only be
+ // called once. If CDM creation failed, all following GenerateKeyRequest,
+ // AddKey and CancelKeyRequest calls will result in a KeyError.
+ void CreateCdm(CdmFactory* cdm_factory,
+ const std::string& key_system,
+ const GURL& security_origin,
+ const CdmContextReadyCB& cdm_context_ready_cb);
- // May only be called after InitializeCDM() succeeds.
- bool GenerateKeyRequest(EmeInitDataType init_data_type,
+ // May only be called after CreateCDM().
+ void GenerateKeyRequest(EmeInitDataType init_data_type,
const uint8* init_data,
int init_data_length);
void AddKey(const uint8* key, int key_length,
@@ -66,11 +72,14 @@ class MEDIA_EXPORT ProxyDecryptor {
void CancelKeyRequest(const std::string& session_id);
private:
- // Helper function to create MediaKeys to handle the given |key_system|.
- scoped_ptr<MediaKeys> CreateMediaKeys(
- CdmFactory* cdm_factory,
- const std::string& key_system,
- const GURL& security_origin);
+ // Callback for CreateCdm().
+ void OnCdmCreated(const std::string& key_system,
+ const GURL& security_origin,
+ const CdmContextReadyCB& cdm_context_ready_cb,
+ scoped_ptr<MediaKeys> cdm);
+
+ void GenerateKeyRequestInternal(EmeInitDataType init_data_type,
+ const std::vector<uint8>& init_data);
// Callbacks for firing session events.
void OnSessionMessage(const std::string& session_id,
@@ -106,6 +115,17 @@ class MEDIA_EXPORT ProxyDecryptor {
void SetSessionId(SessionCreationType session_type,
const std::string& session_id);
+ struct PendingGenerateKeyRequestData {
+ PendingGenerateKeyRequestData(EmeInitDataType init_data_type,
+ const std::vector<uint8>& init_data);
+ ~PendingGenerateKeyRequestData();
+
+ const EmeInitDataType init_data_type;
+ const std::vector<uint8> init_data;
+ };
+
+ bool is_creating_cdm_;
+
// The real MediaKeys that manages key operations for the ProxyDecryptor.
scoped_ptr<MediaKeys> media_keys_;
@@ -124,6 +144,8 @@ class MEDIA_EXPORT ProxyDecryptor {
bool is_clear_key_;
+ ScopedVector<PendingGenerateKeyRequestData> pending_requests_;
+
// NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<ProxyDecryptor> weak_ptr_factory_;