diff options
Diffstat (limited to 'content/renderer/media')
16 files changed, 578 insertions, 242 deletions
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. |