summaryrefslogtreecommitdiffstats
path: root/media
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
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')
-rw-r--r--media/base/cdm_factory.h9
-rw-r--r--media/blink/cdm_session_adapter.cc67
-rw-r--r--media/blink/cdm_session_adapter.h24
-rw-r--r--media/blink/encrypted_media_player_support.cc49
-rw-r--r--media/blink/encrypted_media_player_support.h8
-rw-r--r--media/blink/webcontentdecryptionmodule_impl.cc22
-rw-r--r--media/blink/webcontentdecryptionmodule_impl.h2
-rw-r--r--media/blink/webmediaplayer_impl.cc25
-rw-r--r--media/blink/webmediaplayer_impl.h4
-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
13 files changed, 288 insertions, 183 deletions
diff --git a/media/base/cdm_factory.h b/media/base/cdm_factory.h
index 2a9b42d..f9c5541 100644
--- a/media/base/cdm_factory.h
+++ b/media/base/cdm_factory.h
@@ -17,10 +17,14 @@ namespace media {
class MEDIA_EXPORT CdmFactory {
public:
+ using CdmCreatedCB = base::Callback<void(scoped_ptr<MediaKeys>)>;
+
CdmFactory();
virtual ~CdmFactory();
- virtual scoped_ptr<MediaKeys> Create(
+ // Creates a CDM for |key_system| and returns it through |cdm_created_cb|
+ // asynchronously.
+ virtual void Create(
const std::string& key_system,
bool allow_distinctive_identifier,
bool allow_persistent_state,
@@ -29,7 +33,8 @@ class MEDIA_EXPORT CdmFactory {
const SessionClosedCB& session_closed_cb,
const LegacySessionErrorCB& legacy_session_error_cb,
const SessionKeysChangeCB& session_keys_change_cb,
- const SessionExpirationUpdateCB& session_expiration_update_cb) = 0;
+ const SessionExpirationUpdateCB& session_expiration_update_cb,
+ const CdmCreatedCB& cdm_created_cb) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(CdmFactory);
diff --git a/media/blink/cdm_session_adapter.cc b/media/blink/cdm_session_adapter.cc
index 79f5054..8e62bce 100644
--- a/media/blink/cdm_session_adapter.cc
+++ b/media/blink/cdm_session_adapter.cc
@@ -13,6 +13,7 @@
#include "media/base/cdm_promise.h"
#include "media/base/key_systems.h"
#include "media/base/media_keys.h"
+#include "media/blink/webcontentdecryptionmodule_impl.h"
#include "media/blink/webcontentdecryptionmodulesession_impl.h"
#include "url/gurl.h"
@@ -26,33 +27,34 @@ CdmSessionAdapter::CdmSessionAdapter() : weak_ptr_factory_(this) {
CdmSessionAdapter::~CdmSessionAdapter() {}
-bool CdmSessionAdapter::Initialize(CdmFactory* cdm_factory,
- const std::string& key_system,
- bool allow_distinctive_identifier,
- bool allow_persistent_state,
- const GURL& security_origin) {
- key_system_ = key_system;
- key_system_uma_prefix_ =
- kMediaEME + GetKeySystemNameForUMA(key_system) + kDot;
-
+void CdmSessionAdapter::CreateCdm(
+ CdmFactory* cdm_factory,
+ const std::string& key_system,
+ bool allow_distinctive_identifier,
+ bool allow_persistent_state,
+ const GURL& security_origin,
+ blink::WebContentDecryptionModuleResult result) {
+ // Note: WebContentDecryptionModuleImpl::Create() calls this method without
+ // holding a reference to the CdmSessionAdapter. Bind OnCdmCreated() with
+ // |this| instead of |weak_this| to prevent |this| from being desctructed.
base::WeakPtr<CdmSessionAdapter> weak_this = weak_ptr_factory_.GetWeakPtr();
- media_keys_ = cdm_factory->Create(
+ cdm_factory->Create(
key_system, allow_distinctive_identifier, allow_persistent_state,
security_origin,
base::Bind(&CdmSessionAdapter::OnSessionMessage, weak_this),
base::Bind(&CdmSessionAdapter::OnSessionClosed, weak_this),
base::Bind(&CdmSessionAdapter::OnLegacySessionError, weak_this),
base::Bind(&CdmSessionAdapter::OnSessionKeysChange, weak_this),
- base::Bind(&CdmSessionAdapter::OnSessionExpirationUpdate, weak_this));
- return media_keys_.get() != nullptr;
+ base::Bind(&CdmSessionAdapter::OnSessionExpirationUpdate, weak_this),
+ base::Bind(&CdmSessionAdapter::OnCdmCreated, this, key_system, result));
}
void CdmSessionAdapter::SetServerCertificate(
const uint8* server_certificate,
int server_certificate_length,
scoped_ptr<SimpleCdmPromise> promise) {
- media_keys_->SetServerCertificate(
- server_certificate, server_certificate_length, promise.Pass());
+ cdm_->SetServerCertificate(server_certificate, server_certificate_length,
+ promise.Pass());
}
WebContentDecryptionModuleSessionImpl* CdmSessionAdapter::CreateSession() {
@@ -81,37 +83,35 @@ void CdmSessionAdapter::InitializeNewSession(
int init_data_length,
MediaKeys::SessionType session_type,
scoped_ptr<NewSessionCdmPromise> promise) {
- media_keys_->CreateSessionAndGenerateRequest(session_type, init_data_type,
- init_data, init_data_length,
- promise.Pass());
+ cdm_->CreateSessionAndGenerateRequest(session_type, init_data_type, init_data,
+ init_data_length, promise.Pass());
}
void CdmSessionAdapter::LoadSession(MediaKeys::SessionType session_type,
const std::string& session_id,
scoped_ptr<NewSessionCdmPromise> promise) {
- media_keys_->LoadSession(session_type, session_id, promise.Pass());
+ cdm_->LoadSession(session_type, session_id, promise.Pass());
}
void CdmSessionAdapter::UpdateSession(const std::string& session_id,
const uint8* response,
int response_length,
scoped_ptr<SimpleCdmPromise> promise) {
- media_keys_->UpdateSession(session_id, response, response_length,
- promise.Pass());
+ cdm_->UpdateSession(session_id, response, response_length, promise.Pass());
}
void CdmSessionAdapter::CloseSession(const std::string& session_id,
scoped_ptr<SimpleCdmPromise> promise) {
- media_keys_->CloseSession(session_id, promise.Pass());
+ cdm_->CloseSession(session_id, promise.Pass());
}
void CdmSessionAdapter::RemoveSession(const std::string& session_id,
scoped_ptr<SimpleCdmPromise> promise) {
- media_keys_->RemoveSession(session_id, promise.Pass());
+ cdm_->RemoveSession(session_id, promise.Pass());
}
CdmContext* CdmSessionAdapter::GetCdmContext() {
- return media_keys_->GetCdmContext();
+ return cdm_->GetCdmContext();
}
const std::string& CdmSessionAdapter::GetKeySystem() const {
@@ -122,6 +122,27 @@ const std::string& CdmSessionAdapter::GetKeySystemUMAPrefix() const {
return key_system_uma_prefix_;
}
+void CdmSessionAdapter::OnCdmCreated(
+ const std::string& key_system,
+ blink::WebContentDecryptionModuleResult result,
+ scoped_ptr<MediaKeys> cdm) {
+ DVLOG(2) << __FUNCTION__;
+ if (!cdm) {
+ result.completeWithError(
+ blink::WebContentDecryptionModuleExceptionNotSupportedError, 0,
+ "Failed to create the CDM instance.");
+ return;
+ }
+
+ key_system_ = key_system;
+ key_system_uma_prefix_ =
+ kMediaEME + GetKeySystemNameForUMA(key_system) + kDot;
+ cdm_ = cdm.Pass();
+
+ result.completeWithContentDecryptionModule(
+ new WebContentDecryptionModuleImpl(this));
+}
+
void CdmSessionAdapter::OnSessionMessage(
const std::string& session_id,
MediaKeys::MessageType message_type,
diff --git a/media/blink/cdm_session_adapter.h b/media/blink/cdm_session_adapter.h
index e35c4cb..5ed7550e 100644
--- a/media/blink/cdm_session_adapter.h
+++ b/media/blink/cdm_session_adapter.h
@@ -13,6 +13,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "media/base/media_keys.h"
+#include "third_party/WebKit/public/platform/WebContentDecryptionModuleResult.h"
#include "third_party/WebKit/public/platform/WebContentDecryptionModuleSession.h"
class GURL;
@@ -30,12 +31,14 @@ class CdmSessionAdapter : public base::RefCounted<CdmSessionAdapter> {
public:
CdmSessionAdapter();
- // Returns true on success.
- bool Initialize(CdmFactory* cdm_factory,
- const std::string& key_system,
- bool allow_distinctive_identifier,
- bool allow_persistent_state,
- const GURL& security_origin);
+ // Creates the CDM for |key_system| using |cdm_factory| and returns the result
+ // via |result|.
+ void CreateCdm(CdmFactory* cdm_factory,
+ const std::string& key_system,
+ bool allow_distinctive_identifier,
+ bool allow_persistent_state,
+ const GURL& security_origin,
+ blink::WebContentDecryptionModuleResult result);
// Provides a server certificate to be used to encrypt messages to the
// license server.
@@ -99,12 +102,19 @@ class CdmSessionAdapter : public base::RefCounted<CdmSessionAdapter> {
private:
friend class base::RefCounted<CdmSessionAdapter>;
+
+ // Session ID to WebContentDecryptionModuleSessionImpl mapping.
typedef base::hash_map<std::string,
base::WeakPtr<WebContentDecryptionModuleSessionImpl> >
SessionMap;
~CdmSessionAdapter();
+ // Callback for CreateCdm().
+ void OnCdmCreated(const std::string& key_system,
+ blink::WebContentDecryptionModuleResult result,
+ scoped_ptr<MediaKeys> cdm);
+
// Callbacks for firing session events.
void OnSessionMessage(const std::string& session_id,
MediaKeys::MessageType message_type,
@@ -125,7 +135,7 @@ class CdmSessionAdapter : public base::RefCounted<CdmSessionAdapter> {
WebContentDecryptionModuleSessionImpl* GetSession(
const std::string& session_id);
- scoped_ptr<MediaKeys> media_keys_;
+ scoped_ptr<MediaKeys> cdm_;
SessionMap sessions_;
diff --git a/media/blink/encrypted_media_player_support.cc b/media/blink/encrypted_media_player_support.cc
index a84e24c..cc11a2e 100644
--- a/media/blink/encrypted_media_player_support.cc
+++ b/media/blink/encrypted_media_player_support.cc
@@ -116,12 +116,12 @@ EncryptedMediaPlayerSupport::EncryptedMediaPlayerSupport(
CdmFactory* cdm_factory,
blink::WebMediaPlayerClient* client,
MediaPermission* media_permission,
- const SetCdmContextCB& set_cdm_context_cb)
+ const CdmContextReadyCB& cdm_context_ready_cb)
: cdm_factory_(cdm_factory),
client_(client),
media_permission_(media_permission),
init_data_type_(EmeInitDataType::UNKNOWN),
- set_cdm_context_cb_(set_cdm_context_cb) {
+ cdm_context_ready_cb_(cdm_context_ready_cb) {
}
EncryptedMediaPlayerSupport::~EncryptedMediaPlayerSupport() {
@@ -155,43 +155,32 @@ EncryptedMediaPlayerSupport::GenerateKeyRequestInternal(
if (!PrefixedIsSupportedConcreteKeySystem(key_system))
return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
- // We do not support run-time switching between key systems for now.
- if (current_key_system_.empty()) {
- if (!proxy_decryptor_) {
- proxy_decryptor_.reset(new ProxyDecryptor(
- media_permission_,
- BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyAdded),
- BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyError),
- BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyMessage)));
- }
+ if (!proxy_decryptor_) {
+ DCHECK(current_key_system_.empty());
+ DCHECK(!cdm_context_ready_cb_.is_null());
+ proxy_decryptor_.reset(new ProxyDecryptor(
+ media_permission_,
+ BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyAdded),
+ BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyError),
+ BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyMessage)));
GURL security_origin(frame->document().securityOrigin().toString());
-
- if (!proxy_decryptor_->InitializeCDM(cdm_factory_, key_system,
- security_origin)) {
- return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
- }
-
- if (proxy_decryptor_ && !set_cdm_context_cb_.is_null()) {
- base::ResetAndReturn(&set_cdm_context_cb_)
- .Run(proxy_decryptor_->GetCdmContext(),
- base::Bind(&IgnoreCdmAttached));
- }
-
+ proxy_decryptor_->CreateCdm(cdm_factory_, key_system, security_origin,
+ cdm_context_ready_cb_);
current_key_system_ = key_system;
- } else if (key_system != current_key_system_) {
- return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
}
+ // We do not support run-time switching between key systems for now.
+ DCHECK(!current_key_system_.empty());
+ if (key_system != current_key_system_)
+ return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
+
EmeInitDataType init_data_type = init_data_type_;
if (init_data_type == EmeInitDataType::UNKNOWN)
init_data_type = GuessInitDataType(init_data, init_data_length);
- if (!proxy_decryptor_->GenerateKeyRequest(init_data_type, init_data,
- init_data_length)) {
- current_key_system_.clear();
- return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
- }
+ proxy_decryptor_->GenerateKeyRequest(init_data_type, init_data,
+ init_data_length);
return WebMediaPlayer::MediaKeyExceptionNoError;
}
diff --git a/media/blink/encrypted_media_player_support.h b/media/blink/encrypted_media_player_support.h
index 30d8708..d3fd454 100644
--- a/media/blink/encrypted_media_player_support.h
+++ b/media/blink/encrypted_media_player_support.h
@@ -37,13 +37,13 @@ class WebContentDecryptionModuleImpl;
class EncryptedMediaPlayerSupport
: public base::SupportsWeakPtr<EncryptedMediaPlayerSupport> {
public:
- typedef base::Callback<void(CdmContext*, const CdmAttachedCB&)>
- SetCdmContextCB;
+ using CdmContextReadyCB = ProxyDecryptor::CdmContextReadyCB;
+ // |cdm_context_ready_cb| is called when the CDM instance creation completes.
EncryptedMediaPlayerSupport(CdmFactory* cdm_factory,
blink::WebMediaPlayerClient* client,
MediaPermission* media_permission,
- const SetCdmContextCB& set_cdm_context_cb);
+ const CdmContextReadyCB& cdm_context_ready_cb);
~EncryptedMediaPlayerSupport();
blink::WebMediaPlayer::MediaKeyException GenerateKeyRequest(
@@ -109,7 +109,7 @@ class EncryptedMediaPlayerSupport
// init data type.
EmeInitDataType init_data_type_;
- SetCdmContextCB set_cdm_context_cb_;
+ CdmContextReadyCB cdm_context_ready_cb_;
// Manages decryption keys and decrypts encrypted frames.
scoped_ptr<ProxyDecryptor> proxy_decryptor_;
diff --git a/media/blink/webcontentdecryptionmodule_impl.cc b/media/blink/webcontentdecryptionmodule_impl.cc
index 9d60220..7bdd9c9 100644
--- a/media/blink/webcontentdecryptionmodule_impl.cc
+++ b/media/blink/webcontentdecryptionmodule_impl.cc
@@ -62,21 +62,15 @@ void WebContentDecryptionModuleImpl::Create(
}
GURL security_origin_as_gurl(security_origin.toString());
- scoped_refptr<CdmSessionAdapter> adapter(new CdmSessionAdapter());
- // TODO(jrummell): Pass WebContentDecryptionModuleResult (or similar) to
- // Initialize() so that more specific errors can be reported.
- if (!adapter->Initialize(cdm_factory, key_system_ascii,
- allow_distinctive_identifier,
- allow_persistent_state, security_origin_as_gurl)) {
- result.completeWithError(
- blink::WebContentDecryptionModuleExceptionNotSupportedError, 0,
- "Failed to initialize CDM.");
- return;
- }
-
- result.completeWithContentDecryptionModule(
- new WebContentDecryptionModuleImpl(adapter));
+ // CdmSessionAdapter::CreateCdm() will keep a reference to |adapter|. Then
+ // if WebContentDecryptionModuleImpl is successfully created (returned in
+ // |result|), it will keep a reference to |adapter|. Otherwise, |adapter| will
+ // be destructed.
+ scoped_refptr<CdmSessionAdapter> adapter(new CdmSessionAdapter());
+ adapter->CreateCdm(cdm_factory, key_system_ascii,
+ allow_distinctive_identifier, allow_persistent_state,
+ security_origin_as_gurl, result);
}
WebContentDecryptionModuleImpl::WebContentDecryptionModuleImpl(
diff --git a/media/blink/webcontentdecryptionmodule_impl.h b/media/blink/webcontentdecryptionmodule_impl.h
index 8b38cc6..aa7fa16 100644
--- a/media/blink/webcontentdecryptionmodule_impl.h
+++ b/media/blink/webcontentdecryptionmodule_impl.h
@@ -52,6 +52,8 @@ class MEDIA_EXPORT WebContentDecryptionModuleImpl
CdmContext* GetCdmContext();
private:
+ friend CdmSessionAdapter;
+
// Takes reference to |adapter|.
WebContentDecryptionModuleImpl(scoped_refptr<CdmSessionAdapter> adapter);
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index fe30c5e..ab62772 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -137,11 +137,12 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
compositor_(new VideoFrameCompositor(
BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnNaturalSizeChanged),
BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnOpacityChanged))),
- encrypted_media_support_(
- cdm_factory,
- client,
- params.media_permission(),
- base::Bind(&WebMediaPlayerImpl::SetCdm, AsWeakPtr())),
+ encrypted_media_support_(cdm_factory,
+ client,
+ params.media_permission(),
+ base::Bind(&WebMediaPlayerImpl::SetCdm,
+ AsWeakPtr(),
+ base::Bind(&IgnoreCdmAttached))),
renderer_factory_(renderer_factory.Pass()) {
// Threaded compositing isn't enabled universally yet.
if (!compositor_task_runner_.get())
@@ -151,9 +152,9 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED));
if (params.initial_cdm()) {
- SetCdm(
- ToWebContentDecryptionModuleImpl(params.initial_cdm())->GetCdmContext(),
- base::Bind(&IgnoreCdmAttached));
+ SetCdm(base::Bind(&IgnoreCdmAttached),
+ ToWebContentDecryptionModuleImpl(params.initial_cdm())
+ ->GetCdmContext());
}
// TODO(xhwang): When we use an external Renderer, many methods won't work,
@@ -660,8 +661,8 @@ void WebMediaPlayerImpl::setContentDecryptionModule(
return;
}
- SetCdm(ToWebContentDecryptionModuleImpl(cdm)->GetCdmContext(),
- BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnCdmAttached, result));
+ SetCdm(BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnCdmAttached, result),
+ ToWebContentDecryptionModuleImpl(cdm)->GetCdmContext());
}
void WebMediaPlayerImpl::OnEncryptedMediaInitData(
@@ -695,8 +696,8 @@ void WebMediaPlayerImpl::OnWaitingForDecryptionKey() {
client_->didResumePlaybackBlockedForKey();
}
-void WebMediaPlayerImpl::SetCdm(CdmContext* cdm_context,
- const CdmAttachedCB& cdm_attached_cb) {
+void WebMediaPlayerImpl::SetCdm(const CdmAttachedCB& cdm_attached_cb,
+ CdmContext* cdm_context) {
pipeline_.SetCdm(cdm_context, cdm_attached_cb);
}
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 80bea8f..427357b 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -224,7 +224,9 @@ class MEDIA_EXPORT WebMediaPlayerImpl
// is not available.
void OnWaitingForDecryptionKey();
- void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb);
+ // Sets |cdm_context| on the pipeline and fires |cdm_attached_cb| when done.
+ // Parameter order is reversed for easy binding.
+ void SetCdm(const CdmAttachedCB& cdm_attached_cb, CdmContext* cdm_context);
// Called when a CDM has been attached to the |pipeline_|.
void OnCdmAttached(blink::WebContentDecryptionModuleResult result,
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_;