summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/content_renderer.gypi2
-rw-r--r--content/renderer/media/cdm_result_promise.cc121
-rw-r--r--content/renderer/media/cdm_result_promise.h72
-rw-r--r--content/renderer/media/cdm_session_adapter.cc49
-rw-r--r--content/renderer/media/cdm_session_adapter.h32
-rw-r--r--content/renderer/media/crypto/content_decryption_module_factory.cc16
-rw-r--r--content/renderer/media/crypto/content_decryption_module_factory.h4
-rw-r--r--content/renderer/media/crypto/ppapi_decryptor.cc87
-rw-r--r--content/renderer/media/crypto/ppapi_decryptor.h37
-rw-r--r--content/renderer/media/crypto/proxy_decryptor.cc17
-rw-r--r--content/renderer/media/crypto/proxy_decryptor.h4
-rw-r--r--content/renderer/media/crypto/proxy_media_keys.cc30
-rw-r--r--content/renderer/media/crypto/proxy_media_keys.h16
-rw-r--r--content/renderer/media/webcontentdecryptionmodule_impl.cc16
-rw-r--r--content/renderer/media/webcontentdecryptionmodule_impl.h5
-rw-r--r--content/renderer/media/webcontentdecryptionmodulesession_impl.cc282
-rw-r--r--content/renderer/media/webcontentdecryptionmodulesession_impl.h32
-rw-r--r--content/renderer/pepper/content_decryptor_delegate.cc23
-rw-r--r--content/renderer/pepper/content_decryptor_delegate.h17
-rw-r--r--media/base/media_keys.h34
-rw-r--r--media/cdm/aes_decryptor.cc69
-rw-r--r--media/cdm/aes_decryptor.h19
-rw-r--r--media/cdm/aes_decryptor_unittest.cc58
-rw-r--r--media/cdm/ppapi/external_clear_key/clear_key_cdm.cc43
-rw-r--r--media/cdm/ppapi/external_clear_key/clear_key_cdm.h4
-rw-r--r--media/filters/pipeline_integration_test.cc31
26 files changed, 803 insertions, 317 deletions
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index cdec14c..e2c7388 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -245,6 +245,8 @@
'renderer/media/audio_message_filter.h',
'renderer/media/audio_renderer_mixer_manager.cc',
'renderer/media/audio_renderer_mixer_manager.h',
+ 'renderer/media/cdm_result_promise.cc',
+ 'renderer/media/cdm_result_promise.h',
'renderer/media/cdm_session_adapter.cc',
'renderer/media/cdm_session_adapter.h',
'renderer/media/crypto/content_decryption_module_factory.cc',
diff --git a/content/renderer/media/cdm_result_promise.cc b/content/renderer/media/cdm_result_promise.cc
new file mode 100644
index 0000000..ad59167
--- /dev/null
+++ b/content/renderer/media/cdm_result_promise.cc
@@ -0,0 +1,121 @@
+// 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/renderer/media/cdm_result_promise.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+
+namespace content {
+
+static blink::WebContentDecryptionModuleException ConvertException(
+ media::MediaKeys::Exception exception_code) {
+ switch (exception_code) {
+ case media::MediaKeys::NOT_SUPPORTED_ERROR:
+ return blink::WebContentDecryptionModuleExceptionNotSupportedError;
+ case media::MediaKeys::INVALID_STATE_ERROR:
+ return blink::WebContentDecryptionModuleExceptionInvalidStateError;
+ case media::MediaKeys::INVALID_ACCESS_ERROR:
+ return blink::WebContentDecryptionModuleExceptionInvalidAccessError;
+ case media::MediaKeys::QUOTA_EXCEEDED_ERROR:
+ return blink::WebContentDecryptionModuleExceptionQuotaExceededError;
+ case media::MediaKeys::UNKNOWN_ERROR:
+ return blink::WebContentDecryptionModuleExceptionUnknownError;
+ case media::MediaKeys::CLIENT_ERROR:
+ return blink::WebContentDecryptionModuleExceptionClientError;
+ case media::MediaKeys::OUTPUT_ERROR:
+ return blink::WebContentDecryptionModuleExceptionOutputError;
+ default:
+ NOTREACHED();
+ return blink::WebContentDecryptionModuleExceptionUnknownError;
+ }
+}
+
+template <typename T>
+CdmResultPromise<T>::CdmResultPromise(
+ const blink::WebContentDecryptionModuleResult& result)
+ : media::CdmPromiseTemplate<T>(
+ base::Bind(&CdmResultPromise::OnResolve, base::Unretained(this)),
+ base::Bind(&CdmResultPromise::OnReject, base::Unretained(this))),
+ web_cdm_result_(result) {
+}
+
+template <typename T>
+CdmResultPromise<T>::CdmResultPromise(
+ const blink::WebContentDecryptionModuleResult& result,
+ const std::string& uma_name)
+ : media::CdmPromiseTemplate<T>(
+ base::Bind(&CdmResultPromise::OnResolve, base::Unretained(this)),
+ base::Bind(&CdmResultPromise::OnReject, base::Unretained(this)),
+ uma_name),
+ web_cdm_result_(result) {
+}
+
+template <typename T>
+CdmResultPromise<T>::~CdmResultPromise() {
+}
+
+template <>
+void CdmResultPromise<std::string>::OnResolve(const std::string& result) {
+ // This must be overridden in a subclass.
+ NOTREACHED();
+}
+
+template <>
+void CdmResultPromise<media::KeyIdsVector>::OnResolve(
+ const media::KeyIdsVector& result) {
+ // TODO(jrummell): Update blink::WebContentDecryptionModuleResult to
+ // handle the set of keys.
+ OnReject(media::MediaKeys::NOT_SUPPORTED_ERROR, 0, "Not implemented.");
+}
+
+template <typename T>
+void CdmResultPromise<T>::OnReject(media::MediaKeys::Exception exception_code,
+ uint32 system_code,
+ const std::string& error_message) {
+ web_cdm_result_.completeWithError(ConvertException(exception_code),
+ system_code,
+ blink::WebString::fromUTF8(error_message));
+}
+
+CdmResultPromise<void>::CdmResultPromise(
+ const blink::WebContentDecryptionModuleResult& result)
+ : media::CdmPromiseTemplate<void>(
+ base::Bind(&CdmResultPromise::OnResolve, base::Unretained(this)),
+ base::Bind(&CdmResultPromise::OnReject, base::Unretained(this))),
+ web_cdm_result_(result) {
+}
+
+CdmResultPromise<void>::CdmResultPromise(
+ const blink::WebContentDecryptionModuleResult& result,
+ const std::string& uma_name)
+ : media::CdmPromiseTemplate<void>(
+ base::Bind(&CdmResultPromise::OnResolve, base::Unretained(this)),
+ base::Bind(&CdmResultPromise::OnReject, base::Unretained(this)),
+ uma_name),
+ web_cdm_result_(result) {
+}
+
+CdmResultPromise<void>::~CdmResultPromise() {
+}
+
+void CdmResultPromise<void>::OnResolve() {
+ web_cdm_result_.complete();
+}
+
+void CdmResultPromise<void>::OnReject(
+ media::MediaKeys::Exception exception_code,
+ uint32 system_code,
+ const std::string& error_message) {
+ web_cdm_result_.completeWithError(ConvertException(exception_code),
+ system_code,
+ blink::WebString::fromUTF8(error_message));
+}
+
+// Explicit template instantiation for the templates needed.
+template class CdmResultPromise<std::string>;
+template class CdmResultPromise<media::KeyIdsVector>;
+
+} // namespace content
diff --git a/content/renderer/media/cdm_result_promise.h b/content/renderer/media/cdm_result_promise.h
new file mode 100644
index 0000000..39bcc0d
--- /dev/null
+++ b/content/renderer/media/cdm_result_promise.h
@@ -0,0 +1,72 @@
+// 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_RENDERER_MEDIA_CDM_RESULT_PROMISE_H_
+#define CONTENT_RENDERER_MEDIA_CDM_RESULT_PROMISE_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "media/base/cdm_promise.h"
+#include "third_party/WebKit/public/platform/WebContentDecryptionModuleResult.h"
+
+namespace content {
+
+// Used to convert a WebContentDecryptionModuleResult into a CdmPromise so that
+// it can be passed through Chromium. When CdmPromise::resolve(T) is called,
+// OnResolve(T) will be called and will call the appropriate complete...()
+// method on WebContentDecryptionModuleResult. If CdmPromise::reject() is called
+// instead, WebContentDecryptionModuleResult::completeWithError() is called.
+// If constructed with a |uma_name| (which must be the name of a
+// CdmPromiseResult UMA), CdmResultPromise will report the promise result
+// (success or rejection code).
+template <typename T>
+class CdmResultPromise : public media::CdmPromiseTemplate<T> {
+ public:
+ explicit CdmResultPromise(
+ const blink::WebContentDecryptionModuleResult& result);
+ CdmResultPromise(const blink::WebContentDecryptionModuleResult& result,
+ const std::string& uma_name);
+ virtual ~CdmResultPromise();
+
+ protected:
+ // OnResolve() is virtual as it may need special handling in derived classes.
+ virtual void OnResolve(const T& result);
+ void OnReject(media::MediaKeys::Exception exception_code,
+ uint32 system_code,
+ const std::string& error_message);
+
+ blink::WebContentDecryptionModuleResult web_cdm_result_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CdmResultPromise);
+};
+
+// Specialization for no parameter to resolve().
+template <>
+class CdmResultPromise<void> : public media::CdmPromiseTemplate<void> {
+ public:
+ explicit CdmResultPromise(
+ const blink::WebContentDecryptionModuleResult& result);
+ CdmResultPromise(const blink::WebContentDecryptionModuleResult& result,
+ const std::string& uma_name);
+ virtual ~CdmResultPromise();
+
+ protected:
+ virtual void OnResolve();
+ void OnReject(media::MediaKeys::Exception exception_code,
+ uint32 system_code,
+ const std::string& error_message);
+
+ blink::WebContentDecryptionModuleResult web_cdm_result_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CdmResultPromise);
+};
+
+typedef CdmResultPromise<void> SimpleCdmResultPromise;
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_MEDIA_CDM_RESULT_PROMISE_H_
diff --git a/content/renderer/media/cdm_session_adapter.cc b/content/renderer/media/cdm_session_adapter.cc
index de3d162..ddee4f5 100644
--- a/content/renderer/media/cdm_session_adapter.cc
+++ b/content/renderer/media/cdm_session_adapter.cc
@@ -50,12 +50,22 @@ bool CdmSessionAdapter::Initialize(
base::Bind(&CdmSessionAdapter::OnSessionMessage, weak_this),
base::Bind(&CdmSessionAdapter::OnSessionReady, weak_this),
base::Bind(&CdmSessionAdapter::OnSessionClosed, weak_this),
- base::Bind(&CdmSessionAdapter::OnSessionError, weak_this));
+ base::Bind(&CdmSessionAdapter::OnSessionError, weak_this),
+ base::Bind(&CdmSessionAdapter::OnSessionKeysChange, weak_this),
+ base::Bind(&CdmSessionAdapter::OnSessionExpirationUpdate, weak_this));
// Success if |media_keys_| created.
return media_keys_;
}
+void CdmSessionAdapter::SetServerCertificate(
+ const uint8* server_certificate,
+ int server_certificate_length,
+ scoped_ptr<media::SimpleCdmPromise> promise) {
+ media_keys_->SetServerCertificate(
+ server_certificate, server_certificate_length, promise.Pass());
+}
+
WebContentDecryptionModuleSessionImpl* CdmSessionAdapter::CreateSession() {
return new WebContentDecryptionModuleSessionImpl(this);
}
@@ -71,7 +81,7 @@ bool CdmSessionAdapter::RegisterSession(
return true;
}
-void CdmSessionAdapter::RemoveSession(const std::string& web_session_id) {
+void CdmSessionAdapter::UnregisterSession(const std::string& web_session_id) {
DCHECK(ContainsKey(sessions_, web_session_id));
sessions_.erase(web_session_id);
}
@@ -98,10 +108,22 @@ void CdmSessionAdapter::UpdateSession(
web_session_id, response, response_length, promise.Pass());
}
-void CdmSessionAdapter::ReleaseSession(
+void CdmSessionAdapter::CloseSession(
+ const std::string& web_session_id,
+ scoped_ptr<media::SimpleCdmPromise> promise) {
+ media_keys_->CloseSession(web_session_id, promise.Pass());
+}
+
+void CdmSessionAdapter::RemoveSession(
const std::string& web_session_id,
scoped_ptr<media::SimpleCdmPromise> promise) {
- media_keys_->ReleaseSession(web_session_id, promise.Pass());
+ media_keys_->RemoveSession(web_session_id, promise.Pass());
+}
+
+void CdmSessionAdapter::GetUsableKeyIds(
+ const std::string& web_session_id,
+ scoped_ptr<media::KeyIdsPromise> promise) {
+ media_keys_->GetUsableKeyIds(web_session_id, promise.Pass());
}
media::Decryptor* CdmSessionAdapter::GetDecryptor() {
@@ -128,6 +150,25 @@ void CdmSessionAdapter::OnSessionMessage(const std::string& web_session_id,
session->OnSessionMessage(message, destination_url);
}
+void CdmSessionAdapter::OnSessionKeysChange(const std::string& web_session_id,
+ bool has_additional_usable_key) {
+ WebContentDecryptionModuleSessionImpl* session = GetSession(web_session_id);
+ DLOG_IF(WARNING, !session) << __FUNCTION__ << " for unknown session "
+ << web_session_id;
+ if (session)
+ session->OnSessionKeysChange(has_additional_usable_key);
+}
+
+void CdmSessionAdapter::OnSessionExpirationUpdate(
+ const std::string& web_session_id,
+ const base::Time& new_expiry_time) {
+ WebContentDecryptionModuleSessionImpl* session = GetSession(web_session_id);
+ DLOG_IF(WARNING, !session) << __FUNCTION__ << " for unknown session "
+ << web_session_id;
+ if (session)
+ session->OnSessionExpirationUpdate(new_expiry_time);
+}
+
void CdmSessionAdapter::OnSessionReady(const std::string& web_session_id) {
WebContentDecryptionModuleSessionImpl* session = GetSession(web_session_id);
DLOG_IF(WARNING, !session) << __FUNCTION__ << " for unknown session "
diff --git a/content/renderer/media/cdm_session_adapter.h b/content/renderer/media/cdm_session_adapter.h
index 7e32669..a8be20d 100644
--- a/content/renderer/media/cdm_session_adapter.h
+++ b/content/renderer/media/cdm_session_adapter.h
@@ -47,6 +47,12 @@ class CdmSessionAdapter : public base::RefCounted<CdmSessionAdapter> {
const std::string& key_system,
const GURL& security_origin);
+ // Provides a server certificate to be used to encrypt messages to the
+ // license server.
+ void SetServerCertificate(const uint8* server_certificate,
+ int server_certificate_length,
+ scoped_ptr<media::SimpleCdmPromise> promise);
+
// Creates a new session and adds it to the internal map. The caller owns the
// created session. RemoveSession() must be called when destroying it, if
// RegisterSession() was called.
@@ -60,10 +66,10 @@ class CdmSessionAdapter : public base::RefCounted<CdmSessionAdapter> {
base::WeakPtr<WebContentDecryptionModuleSessionImpl> session);
// Removes a session from the internal map.
- void RemoveSession(const std::string& web_session_id);
+ void UnregisterSession(const std::string& web_session_id);
// Initializes a session with the |init_data_type|, |init_data| and
- // |session_type| provided. Takes ownership of |promise|.
+ // |session_type| provided.
void InitializeNewSession(const std::string& init_data_type,
const uint8* init_data,
int init_data_length,
@@ -71,16 +77,24 @@ class CdmSessionAdapter : public base::RefCounted<CdmSessionAdapter> {
scoped_ptr<media::NewSessionCdmPromise> promise);
// Updates the session specified by |web_session_id| with |response|.
- // Takes ownership of |promise|.
void UpdateSession(const std::string& web_session_id,
const uint8* response,
int response_length,
scoped_ptr<media::SimpleCdmPromise> promise);
- // Releases the session specified by |web_session_id|.
- // Takes ownership of |promise|.
- void ReleaseSession(const std::string& web_session_id,
- scoped_ptr<media::SimpleCdmPromise> promise);
+ // Closes the session specified by |web_session_id|.
+ void CloseSession(const std::string& web_session_id,
+ scoped_ptr<media::SimpleCdmPromise> promise);
+
+ // Removes stored session data associated with the session specified by
+ // |web_session_id|.
+ void RemoveSession(const std::string& web_session_id,
+ scoped_ptr<media::SimpleCdmPromise> promise);
+
+ // Retrieves the key IDs for keys in the session that the CDM knows are
+ // currently usable to decrypt media data.
+ void GetUsableKeyIds(const std::string& web_session_id,
+ scoped_ptr<media::KeyIdsPromise> promise);
// Returns the Decryptor associated with this CDM. May be NULL if no
// Decryptor is associated with the MediaKeys object.
@@ -109,6 +123,10 @@ class CdmSessionAdapter : public base::RefCounted<CdmSessionAdapter> {
void OnSessionMessage(const std::string& web_session_id,
const std::vector<uint8>& message,
const GURL& destination_url);
+ void OnSessionKeysChange(const std::string& web_session_id,
+ bool has_additional_usable_key);
+ void OnSessionExpirationUpdate(const std::string& web_session_id,
+ const base::Time& new_expiry_time);
void OnSessionReady(const std::string& web_session_id);
void OnSessionClosed(const std::string& web_session_id);
void OnSessionError(const std::string& web_session_id,
diff --git a/content/renderer/media/crypto/content_decryption_module_factory.cc b/content/renderer/media/crypto/content_decryption_module_factory.cc
index e56962f..0730238 100644
--- a/content/renderer/media/crypto/content_decryption_module_factory.cc
+++ b/content/renderer/media/crypto/content_decryption_module_factory.cc
@@ -30,7 +30,9 @@ scoped_ptr<media::MediaKeys> ContentDecryptionModuleFactory::Create(
const media::SessionMessageCB& session_message_cb,
const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb) {
+ const media::SessionErrorCB& session_error_cb,
+ const media::SessionKeysChangeCB& session_keys_change_cb,
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb) {
// TODO(jrummell): Pass |security_origin| to all constructors.
// TODO(jrummell): Enable the following line once blink code updated to
// check the security origin before calling.
@@ -41,8 +43,8 @@ scoped_ptr<media::MediaKeys> ContentDecryptionModuleFactory::Create(
#endif
if (CanUseAesDecryptor(key_system)) {
- return scoped_ptr<media::MediaKeys>(
- new media::AesDecryptor(session_message_cb, session_closed_cb));
+ return scoped_ptr<media::MediaKeys>(new media::AesDecryptor(
+ session_message_cb, session_closed_cb, session_keys_change_cb));
}
#if defined(ENABLE_PEPPER_CDMS)
return scoped_ptr<media::MediaKeys>(
@@ -52,7 +54,9 @@ scoped_ptr<media::MediaKeys> ContentDecryptionModuleFactory::Create(
session_message_cb,
session_ready_cb,
session_closed_cb,
- session_error_cb));
+ session_error_cb,
+ session_keys_change_cb,
+ session_expiration_update_cb));
#elif defined(ENABLE_BROWSER_CDMS)
scoped_ptr<ProxyMediaKeys> proxy_media_keys =
ProxyMediaKeys::Create(key_system,
@@ -61,7 +65,9 @@ scoped_ptr<media::MediaKeys> ContentDecryptionModuleFactory::Create(
session_message_cb,
session_ready_cb,
session_closed_cb,
- session_error_cb);
+ session_error_cb,
+ session_keys_change_cb,
+ session_expiration_update_cb);
if (proxy_media_keys)
*cdm_id = proxy_media_keys->GetCdmId();
return proxy_media_keys.PassAs<media::MediaKeys>();
diff --git a/content/renderer/media/crypto/content_decryption_module_factory.h b/content/renderer/media/crypto/content_decryption_module_factory.h
index c18bf9d..be91112 100644
--- a/content/renderer/media/crypto/content_decryption_module_factory.h
+++ b/content/renderer/media/crypto/content_decryption_module_factory.h
@@ -38,7 +38,9 @@ class ContentDecryptionModuleFactory {
const media::SessionMessageCB& session_message_cb,
const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb);
+ const media::SessionErrorCB& session_error_cb,
+ const media::SessionKeysChangeCB& session_keys_change_cb,
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb);
};
} // namespace content
diff --git a/content/renderer/media/crypto/ppapi_decryptor.cc b/content/renderer/media/crypto/ppapi_decryptor.cc
index 8b88362..0a6c14c 100644
--- a/content/renderer/media/crypto/ppapi_decryptor.cc
+++ b/content/renderer/media/crypto/ppapi_decryptor.cc
@@ -93,7 +93,9 @@ scoped_ptr<PpapiDecryptor> PpapiDecryptor::Create(
const media::SessionMessageCB& session_message_cb,
const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb) {
+ const media::SessionErrorCB& session_error_cb,
+ const media::SessionKeysChangeCB& session_keys_change_cb,
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb) {
std::string plugin_type = GetPepperType(key_system);
DCHECK(!plugin_type.empty());
scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper =
@@ -109,7 +111,9 @@ scoped_ptr<PpapiDecryptor> PpapiDecryptor::Create(
session_message_cb,
session_ready_cb,
session_closed_cb,
- session_error_cb));
+ session_error_cb,
+ session_keys_change_cb,
+ session_expiration_update_cb));
}
PpapiDecryptor::PpapiDecryptor(
@@ -118,12 +122,16 @@ PpapiDecryptor::PpapiDecryptor(
const media::SessionMessageCB& session_message_cb,
const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb)
+ const media::SessionErrorCB& session_error_cb,
+ const media::SessionKeysChangeCB& session_keys_change_cb,
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb)
: pepper_cdm_wrapper_(pepper_cdm_wrapper.Pass()),
session_message_cb_(session_message_cb),
session_ready_cb_(session_ready_cb),
session_closed_cb_(session_closed_cb),
session_error_cb_(session_error_cb),
+ session_keys_change_cb_(session_keys_change_cb),
+ session_expiration_update_cb_(session_expiration_update_cb),
render_loop_proxy_(base::MessageLoopProxy::current()),
weak_ptr_factory_(this) {
DCHECK(pepper_cdm_wrapper_.get());
@@ -131,6 +139,8 @@ PpapiDecryptor::PpapiDecryptor(
DCHECK(!session_ready_cb_.is_null());
DCHECK(!session_closed_cb_.is_null());
DCHECK(!session_error_cb_.is_null());
+ DCHECK(!session_keys_change_cb.is_null());
+ DCHECK(!session_expiration_update_cb.is_null());
base::WeakPtr<PpapiDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr();
CdmDelegate()->Initialize(
@@ -139,6 +149,8 @@ PpapiDecryptor::PpapiDecryptor(
base::Bind(&PpapiDecryptor::OnSessionReady, weak_this),
base::Bind(&PpapiDecryptor::OnSessionClosed, weak_this),
base::Bind(&PpapiDecryptor::OnSessionError, weak_this),
+ base::Bind(&PpapiDecryptor::OnSessionKeysChange, weak_this),
+ base::Bind(&PpapiDecryptor::OnSessionExpirationUpdate, weak_this),
base::Bind(&PpapiDecryptor::OnFatalPluginError, weak_this));
}
@@ -146,6 +158,22 @@ PpapiDecryptor::~PpapiDecryptor() {
pepper_cdm_wrapper_.reset();
}
+void PpapiDecryptor::SetServerCertificate(
+ const uint8* certificate_data,
+ int certificate_data_length,
+ scoped_ptr<media::SimpleCdmPromise> promise) {
+ DVLOG(2) << __FUNCTION__;
+ DCHECK(render_loop_proxy_->BelongsToCurrentThread());
+
+ if (!CdmDelegate()) {
+ promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
+ return;
+ }
+
+ CdmDelegate()->SetServerCertificate(
+ certificate_data, certificate_data_length, promise.Pass());
+}
+
void PpapiDecryptor::CreateSession(
const std::string& init_data_type,
const uint8* init_data,
@@ -178,6 +206,8 @@ void PpapiDecryptor::LoadSession(
return;
}
+ // TODO(jrummell): Intercepting the promise should not be necessary once
+ // OnSessionKeysChange() is called in all cases. http://crbug.com/413413.
scoped_ptr<SessionLoadedPromise> session_loaded_promise(
new SessionLoadedPromise(promise.Pass(),
base::Bind(&PpapiDecryptor::ResumePlayback,
@@ -200,6 +230,8 @@ void PpapiDecryptor::UpdateSession(
return;
}
+ // TODO(jrummell): Intercepting the promise should not be necessary once
+ // OnSessionKeysChange() is called in all cases. http://crbug.com/413413.
scoped_ptr<SessionUpdatedPromise> session_updated_promise(
new SessionUpdatedPromise(promise.Pass(),
base::Bind(&PpapiDecryptor::ResumePlayback,
@@ -211,7 +243,19 @@ void PpapiDecryptor::UpdateSession(
session_updated_promise.PassAs<media::SimpleCdmPromise>());
}
-void PpapiDecryptor::ReleaseSession(
+void PpapiDecryptor::CloseSession(const std::string& web_session_id,
+ scoped_ptr<media::SimpleCdmPromise> promise) {
+ DCHECK(render_loop_proxy_->BelongsToCurrentThread());
+
+ if (!CdmDelegate()) {
+ promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
+ return;
+ }
+
+ CdmDelegate()->CloseSession(web_session_id, promise.Pass());
+}
+
+void PpapiDecryptor::RemoveSession(
const std::string& web_session_id,
scoped_ptr<media::SimpleCdmPromise> promise) {
DCHECK(render_loop_proxy_->BelongsToCurrentThread());
@@ -221,7 +265,19 @@ void PpapiDecryptor::ReleaseSession(
return;
}
- CdmDelegate()->CloseSession(web_session_id, promise.Pass());
+ CdmDelegate()->RemoveSession(web_session_id, promise.Pass());
+}
+
+void PpapiDecryptor::GetUsableKeyIds(const std::string& web_session_id,
+ scoped_ptr<media::KeyIdsPromise> promise) {
+ DCHECK(render_loop_proxy_->BelongsToCurrentThread());
+
+ if (!CdmDelegate()) {
+ promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
+ return;
+ }
+
+ CdmDelegate()->GetUsableKeyIds(web_session_id, promise.Pass());
}
media::Decryptor* PpapiDecryptor::GetDecryptor() {
@@ -436,9 +492,30 @@ void PpapiDecryptor::OnSessionMessage(const std::string& web_session_id,
session_message_cb_.Run(web_session_id, message, destination_url);
}
+void PpapiDecryptor::OnSessionKeysChange(const std::string& web_session_id,
+ bool has_additional_usable_key) {
+ DCHECK(render_loop_proxy_->BelongsToCurrentThread());
+
+ // TODO(jrummell): Handling resume playback should be done in the media
+ // player, not in the Decryptors. http://crbug.com/413413.
+ if (has_additional_usable_key)
+ ResumePlayback();
+
+ session_keys_change_cb_.Run(web_session_id, has_additional_usable_key);
+}
+
+void PpapiDecryptor::OnSessionExpirationUpdate(
+ const std::string& web_session_id,
+ const base::Time& new_expiry_time) {
+ DCHECK(render_loop_proxy_->BelongsToCurrentThread());
+ session_expiration_update_cb_.Run(web_session_id, new_expiry_time);
+}
+
void PpapiDecryptor::OnSessionReady(const std::string& web_session_id) {
DCHECK(render_loop_proxy_->BelongsToCurrentThread());
+ // TODO(jrummell): Calling ResumePlayback() here should not be necessary once
+ // OnSessionKeysChange() is called in all cases. http://crbug.com/413413.
ResumePlayback();
session_ready_cb_.Run(web_session_id);
}
diff --git a/content/renderer/media/crypto/ppapi_decryptor.h b/content/renderer/media/crypto/ppapi_decryptor.h
index c09e4b0..4f215e1 100644
--- a/content/renderer/media/crypto/ppapi_decryptor.h
+++ b/content/renderer/media/crypto/ppapi_decryptor.h
@@ -38,11 +38,17 @@ class PpapiDecryptor : public media::MediaKeys, public media::Decryptor {
const media::SessionMessageCB& session_message_cb,
const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb);
+ const media::SessionErrorCB& session_error_cb,
+ const media::SessionKeysChangeCB& session_keys_change_cb,
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb);
virtual ~PpapiDecryptor();
// media::MediaKeys implementation.
+ virtual void SetServerCertificate(
+ const uint8* certificate_data,
+ int certificate_data_length,
+ scoped_ptr<media::SimpleCdmPromise> promise) OVERRIDE;
virtual void CreateSession(
const std::string& init_data_type,
const uint8* init_data,
@@ -57,9 +63,15 @@ class PpapiDecryptor : public media::MediaKeys, public media::Decryptor {
const uint8* response,
int response_length,
scoped_ptr<media::SimpleCdmPromise> promise) OVERRIDE;
- virtual void ReleaseSession(
+ virtual void CloseSession(
+ const std::string& web_session_id,
+ scoped_ptr<media::SimpleCdmPromise> promise) OVERRIDE;
+ virtual void RemoveSession(
const std::string& web_session_id,
scoped_ptr<media::SimpleCdmPromise> promise) OVERRIDE;
+ virtual void GetUsableKeyIds(
+ const std::string& web_session_id,
+ scoped_ptr<media::KeyIdsPromise> promise) OVERRIDE;
virtual Decryptor* GetDecryptor() OVERRIDE;
// media::Decryptor implementation.
@@ -83,12 +95,15 @@ class PpapiDecryptor : public media::MediaKeys, public media::Decryptor {
virtual void DeinitializeDecoder(StreamType stream_type) OVERRIDE;
private:
- PpapiDecryptor(const std::string& key_system,
- scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper,
- const media::SessionMessageCB& session_message_cb,
- const media::SessionReadyCB& session_ready_cb,
- const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb);
+ PpapiDecryptor(
+ const std::string& key_system,
+ scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper,
+ const media::SessionMessageCB& session_message_cb,
+ const media::SessionReadyCB& session_ready_cb,
+ const media::SessionClosedCB& session_closed_cb,
+ const media::SessionErrorCB& session_error_cb,
+ const media::SessionKeysChangeCB& session_keys_change_cb,
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb);
void OnDecoderInitialized(StreamType stream_type, bool success);
@@ -96,6 +111,10 @@ class PpapiDecryptor : public media::MediaKeys, public media::Decryptor {
void OnSessionMessage(const std::string& web_session_id,
const std::vector<uint8>& message,
const GURL& destination_url);
+ void OnSessionKeysChange(const std::string& web_session_id,
+ bool has_additional_usable_key);
+ void OnSessionExpirationUpdate(const std::string& web_session_id,
+ const base::Time& new_expiry_time);
void OnSessionReady(const std::string& web_session_id);
void OnSessionClosed(const std::string& web_session_id);
void OnSessionError(const std::string& web_session_id,
@@ -122,6 +141,8 @@ class PpapiDecryptor : public media::MediaKeys, public media::Decryptor {
media::SessionReadyCB session_ready_cb_;
media::SessionClosedCB session_closed_cb_;
media::SessionErrorCB session_error_cb_;
+ media::SessionKeysChangeCB session_keys_change_cb_;
+ media::SessionExpirationUpdateCB session_expiration_update_cb_;
scoped_refptr<base::MessageLoopProxy> render_loop_proxy_;
diff --git a/content/renderer/media/crypto/proxy_decryptor.cc b/content/renderer/media/crypto/proxy_decryptor.cc
index 8a9a757..98c301c 100644
--- a/content/renderer/media/crypto/proxy_decryptor.cc
+++ b/content/renderer/media/crypto/proxy_decryptor.cc
@@ -218,7 +218,7 @@ void ProxyDecryptor::CancelKeyRequest(const std::string& web_session_id) {
base::Bind(&ProxyDecryptor::OnSessionError,
weak_ptr_factory_.GetWeakPtr(),
web_session_id)));
- media_keys_->ReleaseSession(web_session_id, promise.Pass());
+ media_keys_->RemoveSession(web_session_id, promise.Pass());
}
scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys(
@@ -240,6 +240,10 @@ scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys(
base::Bind(&ProxyDecryptor::OnSessionClosed,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&ProxyDecryptor::OnSessionError,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&ProxyDecryptor::OnSessionKeysChange,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&ProxyDecryptor::OnSessionExpirationUpdate,
weak_ptr_factory_.GetWeakPtr()));
}
@@ -261,6 +265,17 @@ void ProxyDecryptor::OnSessionMessage(const std::string& web_session_id,
key_message_cb_.Run(web_session_id, message, destination_url);
}
+void ProxyDecryptor::OnSessionKeysChange(const std::string& web_session_id,
+ bool has_additional_usable_key) {
+ // EME v0.1b doesn't support this event.
+}
+
+void ProxyDecryptor::OnSessionExpirationUpdate(
+ const std::string& web_session_id,
+ const base::Time& new_expiry_time) {
+ // EME v0.1b doesn't support this event.
+}
+
void ProxyDecryptor::OnSessionReady(const std::string& web_session_id) {
key_added_cb_.Run(web_session_id);
}
diff --git a/content/renderer/media/crypto/proxy_decryptor.h b/content/renderer/media/crypto/proxy_decryptor.h
index b1e736d..0a6c298 100644
--- a/content/renderer/media/crypto/proxy_decryptor.h
+++ b/content/renderer/media/crypto/proxy_decryptor.h
@@ -89,6 +89,10 @@ class ProxyDecryptor {
void OnSessionMessage(const std::string& web_session_id,
const std::vector<uint8>& message,
const GURL& default_url);
+ void OnSessionKeysChange(const std::string& web_session_id,
+ bool has_additional_usable_key);
+ void OnSessionExpirationUpdate(const std::string& web_session_id,
+ const base::Time& new_expiry_time);
void OnSessionReady(const std::string& web_session_id);
void OnSessionClosed(const std::string& web_session_id);
void OnSessionError(const std::string& web_session_id,
diff --git a/content/renderer/media/crypto/proxy_media_keys.cc b/content/renderer/media/crypto/proxy_media_keys.cc
index 17e918d..267a0d1 100644
--- a/content/renderer/media/crypto/proxy_media_keys.cc
+++ b/content/renderer/media/crypto/proxy_media_keys.cc
@@ -22,8 +22,13 @@ scoped_ptr<ProxyMediaKeys> ProxyMediaKeys::Create(
const media::SessionMessageCB& session_message_cb,
const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb) {
+ const media::SessionErrorCB& session_error_cb,
+ const media::SessionKeysChangeCB& session_keys_change_cb,
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb) {
DCHECK(manager);
+
+ // TODO(jrummell): Add support for SessionKeysChangeCB and
+ // SessionExpirationUpdateCB.
scoped_ptr<ProxyMediaKeys> proxy_media_keys(
new ProxyMediaKeys(manager,
session_message_cb,
@@ -48,6 +53,13 @@ ProxyMediaKeys::~ProxyMediaKeys() {
session_id_to_promise_map_.clear();
}
+void ProxyMediaKeys::SetServerCertificate(
+ const uint8* certificate_data,
+ int certificate_data_length,
+ scoped_ptr<media::SimpleCdmPromise> promise) {
+ promise->reject(NOT_SUPPORTED_ERROR, 0, "Not yet implemented.");
+}
+
void ProxyMediaKeys::CreateSession(
const std::string& init_data_type,
const uint8* init_data,
@@ -107,9 +119,8 @@ void ProxyMediaKeys::UpdateSession(
std::vector<uint8>(response, response + response_length));
}
-void ProxyMediaKeys::ReleaseSession(
- const std::string& web_session_id,
- scoped_ptr<media::SimpleCdmPromise> promise) {
+void ProxyMediaKeys::CloseSession(const std::string& web_session_id,
+ scoped_ptr<media::SimpleCdmPromise> promise) {
uint32 session_id = LookupSessionId(web_session_id);
if (!session_id) {
promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist.");
@@ -120,6 +131,17 @@ void ProxyMediaKeys::ReleaseSession(
manager_->ReleaseSession(cdm_id_, session_id);
}
+void ProxyMediaKeys::RemoveSession(
+ const std::string& web_session_id,
+ scoped_ptr<media::SimpleCdmPromise> promise) {
+ promise->reject(NOT_SUPPORTED_ERROR, 0, "Not yet implemented.");
+}
+
+void ProxyMediaKeys::GetUsableKeyIds(const std::string& web_session_id,
+ scoped_ptr<media::KeyIdsPromise> promise) {
+ promise->reject(NOT_SUPPORTED_ERROR, 0, "Not yet implemented.");
+}
+
void ProxyMediaKeys::OnSessionCreated(uint32 session_id,
const std::string& web_session_id) {
AssignWebSessionId(session_id, web_session_id);
diff --git a/content/renderer/media/crypto/proxy_media_keys.h b/content/renderer/media/crypto/proxy_media_keys.h
index 4ebd4c1..c0c790e 100644
--- a/content/renderer/media/crypto/proxy_media_keys.h
+++ b/content/renderer/media/crypto/proxy_media_keys.h
@@ -30,11 +30,17 @@ class ProxyMediaKeys : public media::MediaKeys {
const media::SessionMessageCB& session_message_cb,
const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb);
+ const media::SessionErrorCB& session_error_cb,
+ const media::SessionKeysChangeCB& session_keys_change_cb,
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb);
virtual ~ProxyMediaKeys();
// MediaKeys implementation.
+ virtual void SetServerCertificate(
+ const uint8* certificate_data,
+ int certificate_data_length,
+ scoped_ptr<media::SimpleCdmPromise> promise) OVERRIDE;
virtual void CreateSession(
const std::string& init_data_type,
const uint8* init_data,
@@ -49,9 +55,15 @@ class ProxyMediaKeys : public media::MediaKeys {
const uint8* response,
int response_length,
scoped_ptr<media::SimpleCdmPromise> promise) OVERRIDE;
- virtual void ReleaseSession(
+ virtual void CloseSession(
+ const std::string& web_session_id,
+ scoped_ptr<media::SimpleCdmPromise> promise) OVERRIDE;
+ virtual void RemoveSession(
const std::string& web_session_id,
scoped_ptr<media::SimpleCdmPromise> promise) OVERRIDE;
+ virtual void GetUsableKeyIds(
+ const std::string& web_session_id,
+ scoped_ptr<media::KeyIdsPromise> promise) OVERRIDE;
// Callbacks.
void OnSessionCreated(uint32 session_id, const std::string& web_session_id);
diff --git a/content/renderer/media/webcontentdecryptionmodule_impl.cc b/content/renderer/media/webcontentdecryptionmodule_impl.cc
index 9dcb39e..60b2d04 100644
--- a/content/renderer/media/webcontentdecryptionmodule_impl.cc
+++ b/content/renderer/media/webcontentdecryptionmodule_impl.cc
@@ -12,9 +12,11 @@
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "content/renderer/media/cdm_result_promise.h"
#include "content/renderer/media/cdm_session_adapter.h"
#include "content/renderer/media/crypto/key_systems.h"
#include "content/renderer/media/webcontentdecryptionmodulesession_impl.h"
+#include "media/base/cdm_promise.h"
#include "media/base/media_keys.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
@@ -78,7 +80,8 @@ WebContentDecryptionModuleImpl* WebContentDecryptionModuleImpl::Create(
WebContentDecryptionModuleImpl::WebContentDecryptionModuleImpl(
scoped_refptr<CdmSessionAdapter> adapter)
- : adapter_(adapter) {}
+ : adapter_(adapter) {
+}
WebContentDecryptionModuleImpl::~WebContentDecryptionModuleImpl() {
}
@@ -97,6 +100,17 @@ WebContentDecryptionModuleImpl::createSession(
return session;
}
+void WebContentDecryptionModuleImpl::setServerCertificate(
+ const uint8* server_certificate,
+ size_t server_certificate_length,
+ blink::WebContentDecryptionModuleResult result) {
+ DCHECK(server_certificate);
+ adapter_->SetServerCertificate(
+ server_certificate,
+ server_certificate_length,
+ scoped_ptr<media::SimpleCdmPromise>(new SimpleCdmResultPromise(result)));
+}
+
media::Decryptor* WebContentDecryptionModuleImpl::GetDecryptor() {
return adapter_->GetDecryptor();
}
diff --git a/content/renderer/media/webcontentdecryptionmodule_impl.h b/content/renderer/media/webcontentdecryptionmodule_impl.h
index 2619e56..fd724a69 100644
--- a/content/renderer/media/webcontentdecryptionmodule_impl.h
+++ b/content/renderer/media/webcontentdecryptionmodule_impl.h
@@ -64,6 +64,11 @@ class WebContentDecryptionModuleImpl
virtual blink::WebContentDecryptionModuleSession* createSession(
blink::WebContentDecryptionModuleSession::Client* client);
+ virtual void setServerCertificate(
+ const uint8* server_certificate,
+ size_t server_certificate_length,
+ blink::WebContentDecryptionModuleResult result);
+
private:
// Takes reference to |adapter|.
WebContentDecryptionModuleImpl(scoped_refptr<CdmSessionAdapter> adapter);
diff --git a/content/renderer/media/webcontentdecryptionmodulesession_impl.cc b/content/renderer/media/webcontentdecryptionmodulesession_impl.cc
index 527720f..7cd33b4 100644
--- a/content/renderer/media/webcontentdecryptionmodulesession_impl.cc
+++ b/content/renderer/media/webcontentdecryptionmodulesession_impl.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "content/renderer/media/cdm_result_promise.h"
#include "content/renderer/media/cdm_session_adapter.h"
#include "media/base/cdm_promise.h"
#include "third_party/WebKit/public/platform/WebURL.h"
@@ -17,62 +18,39 @@ namespace content {
const char kCreateSessionUMAName[] = "CreateSession";
-// For backwards compatibility with blink not using
-// WebContentDecryptionModuleResult, reserve an index for |outstanding_results_|
-// that will not be used when adding a WebContentDecryptionModuleResult.
-// TODO(jrummell): Remove once blink always uses
-// WebContentDecryptionModuleResult.
-const uint32 kReservedIndex = 0;
-
-static blink::WebContentDecryptionModuleException ConvertException(
- media::MediaKeys::Exception exception_code) {
- switch (exception_code) {
- case media::MediaKeys::NOT_SUPPORTED_ERROR:
- return blink::WebContentDecryptionModuleExceptionNotSupportedError;
- case media::MediaKeys::INVALID_STATE_ERROR:
- return blink::WebContentDecryptionModuleExceptionInvalidStateError;
- case media::MediaKeys::INVALID_ACCESS_ERROR:
- return blink::WebContentDecryptionModuleExceptionInvalidAccessError;
- case media::MediaKeys::QUOTA_EXCEEDED_ERROR:
- return blink::WebContentDecryptionModuleExceptionQuotaExceededError;
- case media::MediaKeys::UNKNOWN_ERROR:
- return blink::WebContentDecryptionModuleExceptionUnknownError;
- case media::MediaKeys::CLIENT_ERROR:
- return blink::WebContentDecryptionModuleExceptionClientError;
- case media::MediaKeys::OUTPUT_ERROR:
- return blink::WebContentDecryptionModuleExceptionOutputError;
- default:
- NOTREACHED();
- return blink::WebContentDecryptionModuleExceptionUnknownError;
+typedef base::Callback<blink::WebContentDecryptionModuleResult::SessionStatus(
+ const std::string& web_session_id)> SessionInitializedCB;
+
+class NewSessionCdmResultPromise : public CdmResultPromise<std::string> {
+ public:
+ NewSessionCdmResultPromise(blink::WebContentDecryptionModuleResult result,
+ std::string uma_name,
+ const SessionInitializedCB& new_session_created_cb)
+ : CdmResultPromise<std::string>(result, uma_name),
+ new_session_created_cb_(new_session_created_cb) {}
+
+ protected:
+ virtual void OnResolve(const std::string& web_session_id) OVERRIDE {
+ blink::WebContentDecryptionModuleResult::SessionStatus status =
+ new_session_created_cb_.Run(web_session_id);
+ web_cdm_result_.completeWithSession(status);
}
-}
+
+ private:
+ SessionInitializedCB new_session_created_cb_;
+};
WebContentDecryptionModuleSessionImpl::WebContentDecryptionModuleSessionImpl(
const scoped_refptr<CdmSessionAdapter>& adapter)
: adapter_(adapter),
is_closed_(false),
- next_available_result_index_(1),
weak_ptr_factory_(this) {
}
WebContentDecryptionModuleSessionImpl::
~WebContentDecryptionModuleSessionImpl() {
if (!web_session_id_.empty())
- adapter_->RemoveSession(web_session_id_);
-
- // Release any WebContentDecryptionModuleResult objects that are left. Their
- // index will have been passed down via a CdmPromise, but it uses a WeakPtr.
- DLOG_IF(WARNING, outstanding_results_.size() > 0)
- << "Clearing " << outstanding_results_.size() << " results";
- for (ResultMap::iterator it = outstanding_results_.begin();
- it != outstanding_results_.end();
- ++it) {
- it->second.completeWithError(
- blink::WebContentDecryptionModuleExceptionInvalidStateError,
- 0,
- "Outstanding request being cancelled.");
- }
- outstanding_results_.clear();
+ adapter_->UnregisterSession(web_session_id_);
}
void WebContentDecryptionModuleSessionImpl::setClientInterface(Client* client) {
@@ -87,57 +65,19 @@ void WebContentDecryptionModuleSessionImpl::initializeNewSession(
const blink::WebString& init_data_type,
const uint8* init_data,
size_t init_data_length) {
- DCHECK(base::IsStringASCII(init_data_type));
-
- std::string init_data_type_as_ascii = base::UTF16ToASCII(init_data_type);
- DLOG_IF(WARNING, init_data_type_as_ascii.find('/') != std::string::npos)
- << "init_data_type '" << init_data_type_as_ascii
- << "' may be a MIME type";
-
- // Attempt to translate content types.
- // TODO(sandersd): Remove once tests stop using content types.
- // http://crbug.com/385874
- std::string content_type = base::StringToLowerASCII(init_data_type_as_ascii);
- if (content_type == "audio/mp4" || content_type == "video/mp4") {
- init_data_type_as_ascii = "cenc";
- } else if (content_type == "audio/webm" || content_type == "video/webm") {
- init_data_type_as_ascii = "webm";
- }
-
- scoped_ptr<media::NewSessionCdmPromise> promise(
- new media::NewSessionCdmPromise(
- base::Bind(&WebContentDecryptionModuleSessionImpl::SessionCreated,
- weak_ptr_factory_.GetWeakPtr(),
- kReservedIndex),
- base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionError,
- weak_ptr_factory_.GetWeakPtr()),
- adapter_->GetKeySystemUMAPrefix() + kCreateSessionUMAName));
- adapter_->InitializeNewSession(init_data_type_as_ascii,
- init_data,
- init_data_length,
- media::MediaKeys::TEMPORARY_SESSION,
- promise.Pass());
+ // TODO(jrummell): Remove once blink updated.
+ NOTREACHED();
}
void WebContentDecryptionModuleSessionImpl::update(const uint8* response,
size_t response_length) {
- DCHECK(response);
- scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
- base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionReady,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionError,
- weak_ptr_factory_.GetWeakPtr())));
- adapter_->UpdateSession(
- web_session_id_, response, response_length, promise.Pass());
+ // TODO(jrummell): Remove once blink updated.
+ NOTREACHED();
}
void WebContentDecryptionModuleSessionImpl::release() {
- scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
- base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionClosed,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionError,
- weak_ptr_factory_.GetWeakPtr())));
- adapter_->ReleaseSession(web_session_id_, promise.Pass());
+ // TODO(jrummell): Remove once blink updated.
+ NOTREACHED();
}
void WebContentDecryptionModuleSessionImpl::initializeNewSession(
@@ -146,17 +86,18 @@ void WebContentDecryptionModuleSessionImpl::initializeNewSession(
size_t init_data_length,
const blink::WebString& session_type,
blink::WebContentDecryptionModuleResult result) {
- uint32 result_index = AddResult(result);
// TODO(ddorwin): Guard against this in supported types check and remove this.
// Chromium only supports ASCII MIME types.
if (!base::IsStringASCII(init_data_type)) {
NOTREACHED();
- SessionError(result_index,
- media::MediaKeys::NOT_SUPPORTED_ERROR,
- 0,
- "The initialization data type " + init_data_type.utf8() +
- " is not supported by the key system.");
+ std::string message = "The initialization data type " +
+ init_data_type.utf8() +
+ " is not supported by the key system.";
+ result.completeWithError(
+ blink::WebContentDecryptionModuleExceptionNotSupportedError,
+ 0,
+ blink::WebString::fromUTF8(message));
return;
}
@@ -165,20 +106,17 @@ void WebContentDecryptionModuleSessionImpl::initializeNewSession(
<< "init_data_type '" << init_data_type_as_ascii
<< "' may be a MIME type";
- scoped_ptr<media::NewSessionCdmPromise> promise(
- new media::NewSessionCdmPromise(
- base::Bind(&WebContentDecryptionModuleSessionImpl::SessionCreated,
- weak_ptr_factory_.GetWeakPtr(),
- result_index),
- base::Bind(&WebContentDecryptionModuleSessionImpl::SessionError,
- weak_ptr_factory_.GetWeakPtr(),
- result_index),
- adapter_->GetKeySystemUMAPrefix() + kCreateSessionUMAName));
- adapter_->InitializeNewSession(init_data_type_as_ascii,
- init_data,
- init_data_length,
- media::MediaKeys::TEMPORARY_SESSION,
- promise.Pass());
+ adapter_->InitializeNewSession(
+ init_data_type_as_ascii,
+ init_data,
+ init_data_length,
+ media::MediaKeys::TEMPORARY_SESSION,
+ scoped_ptr<media::NewSessionCdmPromise>(new NewSessionCdmResultPromise(
+ result,
+ adapter_->GetKeySystemUMAPrefix() + kCreateSessionUMAName,
+ base::Bind(
+ &WebContentDecryptionModuleSessionImpl::OnSessionInitialized,
+ base::Unretained(this)))));
}
void WebContentDecryptionModuleSessionImpl::update(
@@ -186,31 +124,42 @@ void WebContentDecryptionModuleSessionImpl::update(
size_t response_length,
blink::WebContentDecryptionModuleResult result) {
DCHECK(response);
- uint32 result_index = AddResult(result);
- scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
- base::Bind(
- &WebContentDecryptionModuleSessionImpl::SessionUpdatedOrReleased,
- weak_ptr_factory_.GetWeakPtr(),
- result_index),
- base::Bind(&WebContentDecryptionModuleSessionImpl::SessionError,
- weak_ptr_factory_.GetWeakPtr(),
- result_index)));
+ DCHECK(!web_session_id_.empty());
adapter_->UpdateSession(
- web_session_id_, response, response_length, promise.Pass());
+ web_session_id_,
+ response,
+ response_length,
+ scoped_ptr<media::SimpleCdmPromise>(new SimpleCdmResultPromise(result)));
+}
+
+void WebContentDecryptionModuleSessionImpl::close(
+ blink::WebContentDecryptionModuleResult result) {
+ DCHECK(!web_session_id_.empty());
+ adapter_->CloseSession(
+ web_session_id_,
+ scoped_ptr<media::SimpleCdmPromise>(new SimpleCdmResultPromise(result)));
+}
+
+void WebContentDecryptionModuleSessionImpl::remove(
+ blink::WebContentDecryptionModuleResult result) {
+ DCHECK(!web_session_id_.empty());
+ adapter_->RemoveSession(
+ web_session_id_,
+ scoped_ptr<media::SimpleCdmPromise>(new SimpleCdmResultPromise(result)));
+}
+
+void WebContentDecryptionModuleSessionImpl::getUsableKeyIds(
+ blink::WebContentDecryptionModuleResult result) {
+ DCHECK(!web_session_id_.empty());
+ adapter_->GetUsableKeyIds(
+ web_session_id_,
+ scoped_ptr<media::KeyIdsPromise>(
+ new CdmResultPromise<media::KeyIdsVector>(result)));
}
void WebContentDecryptionModuleSessionImpl::release(
blink::WebContentDecryptionModuleResult result) {
- uint32 result_index = AddResult(result);
- scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
- base::Bind(
- &WebContentDecryptionModuleSessionImpl::SessionUpdatedOrReleased,
- weak_ptr_factory_.GetWeakPtr(),
- result_index),
- base::Bind(&WebContentDecryptionModuleSessionImpl::SessionError,
- weak_ptr_factory_.GetWeakPtr(),
- result_index)));
- adapter_->ReleaseSession(web_session_id_, promise.Pass());
+ close(result);
}
void WebContentDecryptionModuleSessionImpl::OnSessionMessage(
@@ -221,6 +170,18 @@ void WebContentDecryptionModuleSessionImpl::OnSessionMessage(
message.empty() ? NULL : &message[0], message.size(), destination_url);
}
+void WebContentDecryptionModuleSessionImpl::OnSessionKeysChange(
+ bool has_additional_usable_key) {
+ // TODO(jrummell): Update this once Blink client supports this.
+}
+
+void WebContentDecryptionModuleSessionImpl::OnSessionExpirationUpdate(
+ const base::Time& new_expiry_time) {
+ // TODO(jrummell): Update this once Blink client supports this.
+ // The EME spec has expiration attribute as the time in milliseconds, so use
+ // InMillisecondsF() to convert.
+}
+
void WebContentDecryptionModuleSessionImpl::OnSessionReady() {
client_->ready();
}
@@ -251,62 +212,19 @@ void WebContentDecryptionModuleSessionImpl::OnSessionError(
}
}
-void WebContentDecryptionModuleSessionImpl::SessionCreated(
- uint32 result_index,
+blink::WebContentDecryptionModuleResult::SessionStatus
+WebContentDecryptionModuleSessionImpl::OnSessionInitialized(
const std::string& web_session_id) {
- blink::WebContentDecryptionModuleResult::SessionStatus status;
-
// CDM will return NULL if the session to be loaded can't be found.
- if (web_session_id.empty()) {
- status = blink::WebContentDecryptionModuleResult::SessionNotFound;
- } else {
- DCHECK(web_session_id_.empty())
- << "Session ID may not be changed once set.";
- web_session_id_ = web_session_id;
- status =
- adapter_->RegisterSession(web_session_id_,
- weak_ptr_factory_.GetWeakPtr())
- ? blink::WebContentDecryptionModuleResult::NewSession
- : blink::WebContentDecryptionModuleResult::SessionAlreadyExists;
- }
-
- ResultMap::iterator it = outstanding_results_.find(result_index);
- if (it != outstanding_results_.end()) {
- blink::WebContentDecryptionModuleResult& result = it->second;
- result.completeWithSession(status);
- outstanding_results_.erase(result_index);
- }
-}
-
-void WebContentDecryptionModuleSessionImpl::SessionUpdatedOrReleased(
- uint32 result_index) {
- ResultMap::iterator it = outstanding_results_.find(result_index);
- DCHECK(it != outstanding_results_.end());
- blink::WebContentDecryptionModuleResult& result = it->second;
- result.complete();
- outstanding_results_.erase(it);
-}
-
-void WebContentDecryptionModuleSessionImpl::SessionError(
- uint32 result_index,
- media::MediaKeys::Exception exception_code,
- uint32 system_code,
- const std::string& error_message) {
- ResultMap::iterator it = outstanding_results_.find(result_index);
- DCHECK(it != outstanding_results_.end());
- blink::WebContentDecryptionModuleResult& result = it->second;
- result.completeWithError(ConvertException(exception_code),
- system_code,
- blink::WebString::fromUTF8(error_message));
- outstanding_results_.erase(it);
-}
-
-uint32 WebContentDecryptionModuleSessionImpl::AddResult(
- blink::WebContentDecryptionModuleResult result) {
- uint32 result_index = next_available_result_index_++;
- DCHECK(result_index != kReservedIndex);
- outstanding_results_.insert(std::make_pair(result_index, result));
- return result_index;
+ if (web_session_id.empty())
+ return blink::WebContentDecryptionModuleResult::SessionNotFound;
+
+ DCHECK(web_session_id_.empty()) << "Session ID may not be changed once set.";
+ web_session_id_ = web_session_id;
+ return adapter_->RegisterSession(web_session_id_,
+ weak_ptr_factory_.GetWeakPtr())
+ ? blink::WebContentDecryptionModuleResult::NewSession
+ : blink::WebContentDecryptionModuleResult::SessionAlreadyExists;
}
} // namespace content
diff --git a/content/renderer/media/webcontentdecryptionmodulesession_impl.h b/content/renderer/media/webcontentdecryptionmodulesession_impl.h
index 05a358b..bb1cedd 100644
--- a/content/renderer/media/webcontentdecryptionmodulesession_impl.h
+++ b/content/renderer/media/webcontentdecryptionmodulesession_impl.h
@@ -49,11 +49,18 @@ class WebContentDecryptionModuleSessionImpl
virtual void update(const uint8* response,
size_t response_length,
blink::WebContentDecryptionModuleResult result);
+ virtual void close(blink::WebContentDecryptionModuleResult result);
+ virtual void remove(blink::WebContentDecryptionModuleResult result);
+ virtual void getUsableKeyIds(blink::WebContentDecryptionModuleResult result);
+
+ // TODO(jrummell): Remove the next method once blink updated.
virtual void release(blink::WebContentDecryptionModuleResult result);
// Callbacks.
void OnSessionMessage(const std::vector<uint8>& message,
const GURL& destination_url);
+ void OnSessionKeysChange(bool has_additional_usable_key);
+ void OnSessionExpirationUpdate(const base::Time& new_expiry_time);
void OnSessionReady();
void OnSessionClosed();
void OnSessionError(media::MediaKeys::Exception exception_code,
@@ -61,24 +68,9 @@ class WebContentDecryptionModuleSessionImpl
const std::string& error_message);
private:
- typedef std::map<uint32, blink::WebContentDecryptionModuleResult> ResultMap;
-
- // These function are used as callbacks when CdmPromise resolves/rejects.
- // |result_index| = kReservedIndex means that there is no
- // WebContentDecryptionModuleResult.
- void SessionCreated(uint32 result_index, const std::string& web_session_id);
- void SessionUpdatedOrReleased(uint32 result_index);
- void SessionError(uint32 result_index,
- media::MediaKeys::Exception exception_code,
- uint32 system_code,
- const std::string& error_message);
-
- // As initializeNewSession(), update(), and release() get passed a
- // WebContentDecryptionModuleResult, keep track of them since this class owns
- // it and needs to keep them around until completed. Returns the index used
- // to locate the WebContentDecryptionModuleResult when the operation is
- // complete.
- uint32 AddResult(blink::WebContentDecryptionModuleResult result);
+ // Called when a new session is created.
+ blink::WebContentDecryptionModuleResult::SessionStatus OnSessionInitialized(
+ const std::string& web_session_id);
scoped_refptr<CdmSessionAdapter> adapter_;
@@ -95,10 +87,6 @@ class WebContentDecryptionModuleSessionImpl
// closed() event.
bool is_closed_;
- // Keep track of all the outstanding WebContentDecryptionModuleResult objects.
- uint32 next_available_result_index_;
- ResultMap outstanding_results_;
-
// Since promises will live until they are fired, use a weak reference when
// creating a promise in case this class disappears before the promise
// actually fires.
diff --git a/content/renderer/pepper/content_decryptor_delegate.cc b/content/renderer/pepper/content_decryptor_delegate.cc
index 64aa297..0ac46c1 100644
--- a/content/renderer/pepper/content_decryptor_delegate.cc
+++ b/content/renderer/pepper/content_decryptor_delegate.cc
@@ -25,6 +25,7 @@
#include "media/base/video_util.h"
#include "ppapi/shared_impl/array_var.h"
#include "ppapi/shared_impl/scoped_pp_resource.h"
+#include "ppapi/shared_impl/time_conversion.h"
#include "ppapi/shared_impl/var.h"
#include "ppapi/shared_impl/var_tracker.h"
#include "ppapi/thunk/enter.h"
@@ -326,6 +327,8 @@ void ContentDecryptorDelegate::Initialize(
const media::SessionReadyCB& session_ready_cb,
const media::SessionClosedCB& session_closed_cb,
const media::SessionErrorCB& session_error_cb,
+ const media::SessionKeysChangeCB& session_keys_change_cb,
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb,
const base::Closure& fatal_plugin_error_cb) {
DCHECK(!key_system.empty());
DCHECK(key_system_.empty());
@@ -335,6 +338,8 @@ void ContentDecryptorDelegate::Initialize(
session_ready_cb_ = session_ready_cb;
session_closed_cb_ = session_closed_cb;
session_error_cb_ = session_error_cb;
+ session_keys_change_cb_ = session_keys_change_cb;
+ session_expiration_update_cb_ = session_expiration_update_cb;
fatal_plugin_error_cb_ = fatal_plugin_error_cb;
plugin_decryption_interface_->Initialize(
@@ -826,13 +831,27 @@ void ContentDecryptorDelegate::OnSessionMessage(PP_Var web_session_id,
void ContentDecryptorDelegate::OnSessionKeysChange(
PP_Var web_session_id,
PP_Bool has_additional_usable_key) {
- // TODO(jrummell): Pass this event on.
+ if (session_keys_change_cb_.is_null())
+ return;
+
+ StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
+ DCHECK(web_session_id_string);
+
+ session_keys_change_cb_.Run(web_session_id_string->value(),
+ PP_ToBool(has_additional_usable_key));
}
void ContentDecryptorDelegate::OnSessionExpirationChange(
PP_Var web_session_id,
PP_Time new_expiry_time) {
- // TODO(jrummell): Pass this event on.
+ if (session_expiration_update_cb_.is_null())
+ return;
+
+ StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
+ DCHECK(web_session_id_string);
+
+ session_expiration_update_cb_.Run(web_session_id_string->value(),
+ ppapi::PPTimeToTime(new_expiry_time));
}
void ContentDecryptorDelegate::OnSessionReady(PP_Var web_session_id) {
diff --git a/content/renderer/pepper/content_decryptor_delegate.h b/content/renderer/pepper/content_decryptor_delegate.h
index fb58cb5..5fb3fb2 100644
--- a/content/renderer/pepper/content_decryptor_delegate.h
+++ b/content/renderer/pepper/content_decryptor_delegate.h
@@ -46,12 +46,15 @@ class ContentDecryptorDelegate {
~ContentDecryptorDelegate();
// This object should not be accessed after |fatal_plugin_error_cb| is called.
- void Initialize(const std::string& key_system,
- const media::SessionMessageCB& session_message_cb,
- const media::SessionReadyCB& session_ready_cb,
- const media::SessionClosedCB& session_closed_cb,
- const media::SessionErrorCB& session_error_cb,
- const base::Closure& fatal_plugin_error_cb);
+ void Initialize(
+ const std::string& key_system,
+ const media::SessionMessageCB& session_message_cb,
+ const media::SessionReadyCB& session_ready_cb,
+ const media::SessionClosedCB& session_closed_cb,
+ const media::SessionErrorCB& session_error_cb,
+ const media::SessionKeysChangeCB& session_keys_change_cb,
+ const media::SessionExpirationUpdateCB& session_expiration_update_cb,
+ const base::Closure& fatal_plugin_error_cb);
void InstanceCrashed();
@@ -219,6 +222,8 @@ class ContentDecryptorDelegate {
media::SessionReadyCB session_ready_cb_;
media::SessionClosedCB session_closed_cb_;
media::SessionErrorCB session_error_cb_;
+ media::SessionKeysChangeCB session_keys_change_cb_;
+ media::SessionExpirationUpdateCB session_expiration_update_cb_;
// Callback to notify that unexpected error happened and |this| should not
// be used anymore.
diff --git a/media/base/media_keys.h b/media/base/media_keys.h
index 063e54b..ec81571 100644
--- a/media/base/media_keys.h
+++ b/media/base/media_keys.h
@@ -14,6 +14,10 @@
#include "media/base/media_export.h"
#include "url/gurl.h"
+namespace base {
+class Time;
+}
+
namespace media {
class Decryptor;
@@ -72,6 +76,12 @@ class MEDIA_EXPORT MediaKeys {
MediaKeys();
virtual ~MediaKeys();
+ // Provides a server certificate to be used to encrypt messages to the
+ // license server.
+ virtual void SetServerCertificate(const uint8* certificate_data,
+ int certificate_data_length,
+ scoped_ptr<SimpleCdmPromise> promise) = 0;
+
// Creates a session with the |init_data_type|, |init_data| and |session_type|
// provided.
// Note: UpdateSession() and ReleaseSession() should only be called after
@@ -94,9 +104,19 @@ class MEDIA_EXPORT MediaKeys {
int response_length,
scoped_ptr<SimpleCdmPromise> promise) = 0;
- // Releases the session specified by |web_session_id|.
- virtual void ReleaseSession(const std::string& web_session_id,
- scoped_ptr<SimpleCdmPromise> promise) = 0;
+ // Closes the session specified by |web_session_id|.
+ virtual void CloseSession(const std::string& web_session_id,
+ scoped_ptr<SimpleCdmPromise> promise) = 0;
+
+ // Removes stored session data associated with the session specified by
+ // |web_session_id|.
+ virtual void RemoveSession(const std::string& web_session_id,
+ scoped_ptr<SimpleCdmPromise> promise) = 0;
+
+ // Retrieves the key IDs for keys in the session that the CDM knows are
+ // currently usable to decrypt media data.
+ virtual void GetUsableKeyIds(const std::string& web_session_id,
+ scoped_ptr<KeyIdsPromise> promise) = 0;
// Gets the Decryptor object associated with the MediaKeys. Returns NULL if
// no Decryptor object is associated. The returned object is only guaranteed
@@ -122,6 +142,14 @@ typedef base::Callback<void(const std::string& web_session_id,
uint32 system_code,
const std::string& error_message)> SessionErrorCB;
+typedef base::Callback<void(const std::string& web_session_id,
+ bool has_additional_usable_key)>
+ SessionKeysChangeCB;
+
+typedef base::Callback<void(const std::string& web_session_id,
+ const base::Time& new_expiry_time)>
+ SessionExpirationUpdateCB;
+
} // namespace media
#endif // MEDIA_BASE_MEDIA_KEYS_H_
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc
index b83c9b1..23f41d7 100644
--- a/media/cdm/aes_decryptor.cc
+++ b/media/cdm/aes_decryptor.cc
@@ -224,17 +224,27 @@ static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input,
}
AesDecryptor::AesDecryptor(const SessionMessageCB& session_message_cb,
- const SessionClosedCB& session_closed_cb)
+ const SessionClosedCB& session_closed_cb,
+ const SessionKeysChangeCB& session_keys_change_cb)
: session_message_cb_(session_message_cb),
- session_closed_cb_(session_closed_cb) {
+ session_closed_cb_(session_closed_cb),
+ session_keys_change_cb_(session_keys_change_cb) {
DCHECK(!session_message_cb_.is_null());
DCHECK(!session_closed_cb_.is_null());
+ DCHECK(!session_keys_change_cb_.is_null());
}
AesDecryptor::~AesDecryptor() {
key_map_.clear();
}
+void AesDecryptor::SetServerCertificate(const uint8* certificate_data,
+ int certificate_data_length,
+ scoped_ptr<SimpleCdmPromise> promise) {
+ promise->reject(
+ NOT_SUPPORTED_ERROR, 0, "SetServerCertificate() is not supported.");
+}
+
void AesDecryptor::CreateSession(const std::string& init_data_type,
const uint8* init_data,
int init_data_length,
@@ -318,6 +328,43 @@ void AesDecryptor::UpdateSession(const std::string& web_session_id,
}
promise->resolve();
+
+ // Assume that at least 1 new key has been successfully added and thus
+ // sending true.
+ session_keys_change_cb_.Run(web_session_id, true);
+}
+
+void AesDecryptor::CloseSession(const std::string& web_session_id,
+ scoped_ptr<SimpleCdmPromise> promise) {
+ // Validate that this is a reference to an active session and then forget it.
+ std::set<std::string>::iterator it = valid_sessions_.find(web_session_id);
+ DCHECK(it != valid_sessions_.end());
+
+ valid_sessions_.erase(it);
+
+ // Close the session.
+ DeleteKeysForSession(web_session_id);
+ promise->resolve();
+ session_closed_cb_.Run(web_session_id);
+}
+
+void AesDecryptor::RemoveSession(const std::string& web_session_id,
+ scoped_ptr<SimpleCdmPromise> promise) {
+ // AesDecryptor doesn't keep any persistent data, so this should be
+ // NOT_REACHED().
+ // TODO(jrummell): Make sure persistent session types are rejected.
+ // http://crbug.com/384152.
+ //
+ // However, v0.1b calls to CancelKeyRequest() will call this, so close the
+ // session, if it exists.
+ // TODO(jrummell): Remove the close() call when prefixed EME is removed.
+ // http://crbug.com/249976.
+ if (valid_sessions_.find(web_session_id) != valid_sessions_.end()) {
+ CloseSession(web_session_id, promise.Pass());
+ return;
+ }
+
+ promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist.");
}
void AesDecryptor::GetUsableKeyIds(const std::string& web_session_id,
@@ -337,24 +384,6 @@ void AesDecryptor::GetUsableKeyIds(const std::string& web_session_id,
promise->resolve(keyids);
}
-void AesDecryptor::ReleaseSession(const std::string& web_session_id,
- scoped_ptr<SimpleCdmPromise> promise) {
- // Validate that this is a reference to an active session and then forget it.
- std::set<std::string>::iterator it = valid_sessions_.find(web_session_id);
- // TODO(jrummell): Convert back to a DCHECK once prefixed EME is removed.
- if (it == valid_sessions_.end()) {
- promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist.");
- return;
- }
-
- valid_sessions_.erase(it);
-
- // Close the session.
- DeleteKeysForSession(web_session_id);
- promise->resolve();
- session_closed_cb_.Run(web_session_id);
-}
-
Decryptor* AesDecryptor::GetDecryptor() {
return this;
}
diff --git a/media/cdm/aes_decryptor.h b/media/cdm/aes_decryptor.h
index dc08bb3..98a79dd 100644
--- a/media/cdm/aes_decryptor.h
+++ b/media/cdm/aes_decryptor.h
@@ -28,10 +28,15 @@ namespace media {
class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor {
public:
AesDecryptor(const SessionMessageCB& session_message_cb,
- const SessionClosedCB& session_closed_cb);
+ const SessionClosedCB& session_closed_cb,
+ const SessionKeysChangeCB& session_keys_change_cb);
virtual ~AesDecryptor();
// MediaKeys implementation.
+ virtual void SetServerCertificate(
+ const uint8* certificate_data,
+ int certificate_data_length,
+ scoped_ptr<SimpleCdmPromise> promise) OVERRIDE;
virtual void CreateSession(const std::string& init_data_type,
const uint8* init_data,
int init_data_length,
@@ -43,8 +48,12 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor {
const uint8* response,
int response_length,
scoped_ptr<SimpleCdmPromise> promise) OVERRIDE;
- virtual void ReleaseSession(const std::string& web_session_id,
- scoped_ptr<SimpleCdmPromise> promise) OVERRIDE;
+ virtual void CloseSession(const std::string& web_session_id,
+ scoped_ptr<SimpleCdmPromise> promise) OVERRIDE;
+ virtual void RemoveSession(const std::string& web_session_id,
+ scoped_ptr<SimpleCdmPromise> promise) OVERRIDE;
+ virtual void GetUsableKeyIds(const std::string& web_session_id,
+ scoped_ptr<KeyIdsPromise> promise) OVERRIDE;
virtual Decryptor* GetDecryptor() OVERRIDE;
// Decryptor implementation.
@@ -67,9 +76,6 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor {
virtual void ResetDecoder(StreamType stream_type) OVERRIDE;
virtual void DeinitializeDecoder(StreamType stream_type) OVERRIDE;
- void GetUsableKeyIds(const std::string& web_session_id,
- scoped_ptr<KeyIdsPromise> promise);
-
private:
// TODO(fgalligan): Remove this and change KeyMap to use crypto::SymmetricKey
// as there are no decryptors that are performing an integrity check.
@@ -120,6 +126,7 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor {
// Callbacks for firing session events.
SessionMessageCB session_message_cb_;
SessionClosedCB session_closed_cb_;
+ SessionKeysChangeCB session_keys_change_cb_;
// Since only Decrypt() is called off the renderer thread, we only need to
// protect |key_map_|, the only member variable that is shared between
diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc
index a40867e7..de52d69 100644
--- a/media/cdm/aes_decryptor_unittest.cc
+++ b/media/cdm/aes_decryptor_unittest.cc
@@ -211,6 +211,8 @@ class AesDecryptorTest : public testing::Test {
: decryptor_(base::Bind(&AesDecryptorTest::OnSessionMessage,
base::Unretained(this)),
base::Bind(&AesDecryptorTest::OnSessionClosed,
+ base::Unretained(this)),
+ base::Bind(&AesDecryptorTest::OnSessionKeysChange,
base::Unretained(this))),
decrypt_cb_(base::Bind(&AesDecryptorTest::BufferDecrypted,
base::Unretained(this))),
@@ -307,23 +309,38 @@ class AesDecryptorTest : public testing::Test {
return web_session_id_;
}
- // Releases the session specified by |session_id|.
- void ReleaseSession(const std::string& session_id) {
+ // Closes the session specified by |session_id|.
+ void CloseSession(const std::string& session_id) {
EXPECT_CALL(*this, OnSessionClosed(session_id));
- decryptor_.ReleaseSession(session_id, CreatePromise(RESOLVED));
+ decryptor_.CloseSession(session_id, CreatePromise(RESOLVED));
+ }
+
+ // Removes the session specified by |session_id|. This should simply do a
+ // CloseSession().
+ // TODO(jrummell): Clean this up when the prefixed API is removed.
+ // http://crbug.com/249976.
+ void RemoveSession(const std::string& session_id) {
+ EXPECT_CALL(*this, OnSessionClosed(session_id));
+ decryptor_.RemoveSession(session_id, CreatePromise(RESOLVED));
}
// Updates the session specified by |session_id| with |key|. |result|
// tests that the update succeeds or generates an error.
void UpdateSessionAndExpect(std::string session_id,
const std::string& key,
- PromiseResult result) {
+ PromiseResult expected_result) {
DCHECK(!key.empty());
+ if (expected_result == RESOLVED) {
+ EXPECT_CALL(*this, OnSessionKeysChange(session_id, true));
+ } else {
+ EXPECT_CALL(*this, OnSessionKeysChange(_, _)).Times(0);
+ }
+
decryptor_.UpdateSession(session_id,
reinterpret_cast<const uint8*>(key.c_str()),
key.length(),
- CreatePromise(result));
+ CreatePromise(expected_result));
}
void GetUsableKeyIdsAndExpect(const std::string& session_id,
@@ -406,6 +423,9 @@ class AesDecryptorTest : public testing::Test {
void(const std::string& web_session_id,
const std::vector<uint8>& message,
const GURL& destination_url));
+ MOCK_METHOD2(OnSessionKeysChange,
+ void(const std::string& web_session_id,
+ bool has_additional_usable_key));
MOCK_METHOD1(OnSessionClosed, void(const std::string& web_session_id));
AesDecryptor decryptor_;
@@ -647,7 +667,21 @@ TEST_F(AesDecryptorTest, SubsampleCypherBytesOnly) {
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS);
}
-TEST_F(AesDecryptorTest, ReleaseSession) {
+TEST_F(AesDecryptorTest, CloseSession) {
+ std::string session_id = CreateSession(key_id_);
+ scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
+ encrypted_data_, key_id_, iv_, no_subsample_entries_);
+
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
+ ASSERT_NO_FATAL_FAILURE(
+ DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
+
+ CloseSession(session_id);
+}
+
+TEST_F(AesDecryptorTest, RemoveSession) {
+ // TODO(jrummell): Clean this up when the prefixed API is removed.
+ // http://crbug.com/249976.
std::string session_id = CreateSession(key_id_);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
@@ -656,10 +690,10 @@ TEST_F(AesDecryptorTest, ReleaseSession) {
ASSERT_NO_FATAL_FAILURE(
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
- ReleaseSession(session_id);
+ RemoveSession(session_id);
}
-TEST_F(AesDecryptorTest, NoKeyAfterReleaseSession) {
+TEST_F(AesDecryptorTest, NoKeyAfterCloseSession) {
std::string session_id = CreateSession(key_id_);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
@@ -668,7 +702,7 @@ TEST_F(AesDecryptorTest, NoKeyAfterReleaseSession) {
ASSERT_NO_FATAL_FAILURE(
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
- ReleaseSession(session_id);
+ CloseSession(session_id);
ASSERT_NO_FATAL_FAILURE(
DecryptAndExpect(encrypted_buffer, original_data_, NO_KEY));
}
@@ -692,7 +726,7 @@ TEST_F(AesDecryptorTest, LatestKeyUsed) {
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
}
-TEST_F(AesDecryptorTest, LatestKeyUsedAfterReleaseSession) {
+TEST_F(AesDecryptorTest, LatestKeyUsedAfterCloseSession) {
std::string session_id1 = CreateSession(key_id_);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
@@ -709,7 +743,7 @@ TEST_F(AesDecryptorTest, LatestKeyUsedAfterReleaseSession) {
DecryptAndExpect(encrypted_buffer, original_data_, DATA_MISMATCH));
// Close second session, should revert to original key.
- ReleaseSession(session_id2);
+ CloseSession(session_id2);
ASSERT_NO_FATAL_FAILURE(
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
}
@@ -841,7 +875,7 @@ TEST_F(AesDecryptorTest, JWKKey) {
" ]"
"}";
UpdateSessionAndExpect(session_id, kJwksWithEmptyKeyId, REJECTED);
- ReleaseSession(session_id);
+ CloseSession(session_id);
}
TEST_F(AesDecryptorTest, GetKeyIds) {
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
index e06f41b..a49b6c2 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
@@ -220,8 +220,10 @@ namespace media {
ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host, const std::string& key_system)
: decryptor_(
- base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)),
- base::Bind(&ClearKeyCdm::OnSessionClosed, base::Unretained(this))),
+ base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)),
+ base::Bind(&ClearKeyCdm::OnSessionClosed, base::Unretained(this)),
+ base::Bind(&ClearKeyCdm::OnSessionKeysChange,
+ base::Unretained(this))),
host_(host),
key_system_(key_system),
timer_delay_ms_(kInitialTimerDelayMs),
@@ -327,13 +329,11 @@ void ClearKeyCdm::CloseSession(uint32 promise_id,
std::string web_session_str(web_session_id, web_session_id_length);
scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
- base::Bind(&ClearKeyCdm::OnSessionReleased,
- base::Unretained(this),
- promise_id,
- web_session_str),
+ base::Bind(
+ &ClearKeyCdm::OnPromiseResolved, base::Unretained(this), promise_id),
base::Bind(
&ClearKeyCdm::OnPromiseFailed, base::Unretained(this), promise_id)));
- decryptor_.ReleaseSession(web_session_str, promise.Pass());
+ decryptor_.CloseSession(web_session_str, promise.Pass());
}
void ClearKeyCdm::RemoveSession(uint32 promise_id,
@@ -345,8 +345,19 @@ void ClearKeyCdm::RemoveSession(uint32 promise_id,
std::string(kLoadableWebSessionId) ==
std::string(web_session_id, web_session_id_length);
if (is_persistent_session) {
- host_->OnResolvePromise(promise_id);
+ std::string web_session_str(web_session_id, web_session_id_length);
+
+ scoped_ptr<media::SimpleCdmPromise> promise(
+ new media::SimpleCdmPromise(base::Bind(&ClearKeyCdm::OnPromiseResolved,
+ base::Unretained(this),
+ promise_id),
+ base::Bind(&ClearKeyCdm::OnPromiseFailed,
+ base::Unretained(this),
+ promise_id)));
+ decryptor_.RemoveSession(web_session_str, promise.Pass());
} else {
+ // TODO(jrummell): This should be a DCHECK once blink does the proper
+ // checks.
std::string message("Not supported for non-persistent sessions.");
host_->OnRejectPromise(promise_id,
cdm::kInvalidAccessError,
@@ -683,6 +694,13 @@ void ClearKeyCdm::OnSessionMessage(const std::string& web_session_id,
destination_url.spec().size());
}
+void ClearKeyCdm::OnSessionKeysChange(const std::string& web_session_id,
+ bool has_additional_usable_key) {
+ host_->OnSessionUsableKeysChange(web_session_id.data(),
+ web_session_id.length(),
+ has_additional_usable_key);
+}
+
void ClearKeyCdm::OnSessionClosed(const std::string& web_session_id) {
host_->OnSessionClosed(web_session_id.data(), web_session_id.length());
}
@@ -733,11 +751,6 @@ void ClearKeyCdm::OnSessionUpdated(uint32 promise_id,
host_->OnResolvePromise(promise_id);
}
-void ClearKeyCdm::OnSessionReleased(uint32 promise_id,
- const std::string& web_session_id) {
- host_->OnResolvePromise(promise_id);
-}
-
void ClearKeyCdm::OnUsableKeyIdsObtained(uint32 promise_id,
const KeyIdsVector& key_ids) {
scoped_ptr<cdm::BinaryData[]> result(new cdm::BinaryData[key_ids.size()]);
@@ -748,6 +761,10 @@ void ClearKeyCdm::OnUsableKeyIdsObtained(uint32 promise_id,
host_->OnResolveKeyIdsPromise(promise_id, result.get(), key_ids.size());
}
+void ClearKeyCdm::OnPromiseResolved(uint32 promise_id) {
+ host_->OnResolvePromise(promise_id);
+}
+
void ClearKeyCdm::OnPromiseFailed(uint32 promise_id,
MediaKeys::Exception exception_code,
uint32 system_code,
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
index c491cd7..19d41f8 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
@@ -92,6 +92,8 @@ class ClearKeyCdm : public ClearKeyCdmInterface {
void OnSessionMessage(const std::string& web_session_id,
const std::vector<uint8>& message,
const GURL& destination_url);
+ void OnSessionKeysChange(const std::string& web_session_id,
+ bool has_additional_usable_key);
void OnSessionClosed(const std::string& web_session_id);
// Handle the success/failure of a promise. These methods are responsible for
@@ -99,8 +101,8 @@ class ClearKeyCdm : public ClearKeyCdmInterface {
void OnSessionCreated(uint32 promise_id, const std::string& web_session_id);
void OnSessionLoaded(uint32 promise_id, const std::string& web_session_id);
void OnSessionUpdated(uint32 promise_id, const std::string& web_session_id);
- void OnSessionReleased(uint32 promise_id, const std::string& web_session_id);
void OnUsableKeyIdsObtained(uint32 promise_id, const KeyIdsVector& key_ids);
+ void OnPromiseResolved(uint32 promise_id);
void OnPromiseFailed(uint32 promise_id,
MediaKeys::Exception exception_code,
uint32 system_code,
diff --git a/media/filters/pipeline_integration_test.cc b/media/filters/pipeline_integration_test.cc
index d85a7ff..d9904f6 100644
--- a/media/filters/pipeline_integration_test.cc
+++ b/media/filters/pipeline_integration_test.cc
@@ -121,10 +121,11 @@ class FakeEncryptedMedia {
const std::vector<uint8>& message,
const GURL& destination_url) = 0;
- virtual void OnSessionReady(const std::string& web_session_id) = 0;
-
virtual void OnSessionClosed(const std::string& web_session_id) = 0;
+ virtual void OnSessionKeysChange(const std::string& web_session_id,
+ bool has_additional_usable_key) = 0;
+
// Errors are not expected unless overridden.
virtual void OnSessionError(const std::string& web_session_id,
const std::string& error_name,
@@ -142,6 +143,8 @@ class FakeEncryptedMedia {
: decryptor_(base::Bind(&FakeEncryptedMedia::OnSessionMessage,
base::Unretained(this)),
base::Bind(&FakeEncryptedMedia::OnSessionClosed,
+ base::Unretained(this)),
+ base::Bind(&FakeEncryptedMedia::OnSessionKeysChange,
base::Unretained(this))),
app_(app) {}
@@ -156,14 +159,15 @@ class FakeEncryptedMedia {
app_->OnSessionMessage(web_session_id, message, destination_url);
}
- void OnSessionReady(const std::string& web_session_id) {
- app_->OnSessionReady(web_session_id);
- }
-
void OnSessionClosed(const std::string& web_session_id) {
app_->OnSessionClosed(web_session_id);
}
+ void OnSessionKeysChange(const std::string& web_session_id,
+ bool has_additional_usable_key) {
+ app_->OnSessionKeysChange(web_session_id, has_additional_usable_key);
+ }
+
void OnSessionError(const std::string& web_session_id,
const std::string& error_name,
uint32 system_code,
@@ -236,12 +240,14 @@ class KeyProvidingApp : public FakeEncryptedMedia::AppBase {
EXPECT_EQ(current_session_id_, web_session_id);
}
- virtual void OnSessionReady(const std::string& web_session_id) OVERRIDE {
+ virtual void OnSessionClosed(const std::string& web_session_id) OVERRIDE {
EXPECT_EQ(current_session_id_, web_session_id);
}
- virtual void OnSessionClosed(const std::string& web_session_id) OVERRIDE {
+ virtual void OnSessionKeysChange(const std::string& web_session_id,
+ bool has_additional_usable_key) OVERRIDE {
EXPECT_EQ(current_session_id_, web_session_id);
+ EXPECT_EQ(has_additional_usable_key, true);
}
virtual void NeedKey(const std::string& type,
@@ -361,14 +367,15 @@ class NoResponseApp : public FakeEncryptedMedia::AppBase {
FAIL() << "Unexpected Message";
}
- virtual void OnSessionReady(const std::string& web_session_id) OVERRIDE {
+ virtual void OnSessionClosed(const std::string& web_session_id) OVERRIDE {
EXPECT_FALSE(web_session_id.empty());
- FAIL() << "Unexpected Ready";
+ FAIL() << "Unexpected Closed";
}
- virtual void OnSessionClosed(const std::string& web_session_id) OVERRIDE {
+ virtual void OnSessionKeysChange(const std::string& web_session_id,
+ bool has_additional_usable_key) OVERRIDE {
EXPECT_FALSE(web_session_id.empty());
- FAIL() << "Unexpected Closed";
+ EXPECT_EQ(has_additional_usable_key, true);
}
virtual void NeedKey(const std::string& type,