diff options
Diffstat (limited to 'content/renderer/media/crypto/proxy_decryptor.cc')
-rw-r--r-- | content/renderer/media/crypto/proxy_decryptor.cc | 312 |
1 files changed, 0 insertions, 312 deletions
diff --git a/content/renderer/media/crypto/proxy_decryptor.cc b/content/renderer/media/crypto/proxy_decryptor.cc deleted file mode 100644 index 44a30fd..0000000 --- a/content/renderer/media/crypto/proxy_decryptor.cc +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2013 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/crypto/proxy_decryptor.h" - -#include <cstring> - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/logging.h" -#include "base/strings/string_util.h" -#include "media/base/cdm_callback_promise.h" -#include "media/base/cdm_factory.h" -#include "media/cdm/json_web_key.h" -#include "media/cdm/key_system_names.h" - -namespace content { - -// Special system code to signal a closed persistent session in a SessionError() -// call. This is needed because there is no SessionClosed() call in the prefixed -// EME API. -const int kSessionClosedSystemCode = 29127; - -ProxyDecryptor::ProxyDecryptor(const KeyAddedCB& key_added_cb, - const KeyErrorCB& key_error_cb, - const KeyMessageCB& key_message_cb) - : key_added_cb_(key_added_cb), - key_error_cb_(key_error_cb), - key_message_cb_(key_message_cb), - is_clear_key_(false), - weak_ptr_factory_(this) { - DCHECK(!key_added_cb_.is_null()); - DCHECK(!key_error_cb_.is_null()); - DCHECK(!key_message_cb_.is_null()); -} - -ProxyDecryptor::~ProxyDecryptor() { - // Destroy the decryptor explicitly before destroying the plugin. - media_keys_.reset(); -} - -media::Decryptor* ProxyDecryptor::GetDecryptor() { - return media_keys_ ? media_keys_->GetDecryptor() : NULL; -} - -#if defined(ENABLE_BROWSER_CDMS) -int ProxyDecryptor::GetCdmId() { - return media_keys_->GetCdmId(); -} -#endif - -bool ProxyDecryptor::InitializeCDM(media::CdmFactory* cdm_factory, - const std::string& key_system, - const GURL& security_origin) { - DVLOG(1) << "InitializeCDM: key_system = " << key_system; - - DCHECK(!media_keys_); - media_keys_ = CreateMediaKeys(cdm_factory, key_system, security_origin); - if (!media_keys_) - return false; - - is_clear_key_ = - media::IsClearKey(key_system) || media::IsExternalClearKey(key_system); - return true; -} - -// Returns true if |data| is prefixed with |header| and has data after the -// |header|. -bool HasHeader(const uint8* data, int data_length, const std::string& header) { - return static_cast<size_t>(data_length) > header.size() && - std::equal(data, data + header.size(), header.begin()); -} - -// Removes the first |length| items from |data|. -void StripHeader(std::vector<uint8>& data, size_t length) { - data.erase(data.begin(), data.begin() + length); -} - -bool ProxyDecryptor::GenerateKeyRequest(const std::string& init_data_type, - const uint8* init_data, - int init_data_length) { - DVLOG(1) << "GenerateKeyRequest()"; - const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|"; - const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|"; - - SessionCreationType session_creation_type = TemporarySession; - std::vector<uint8> init_data_vector(init_data, init_data + init_data_length); - if (HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader)) { - session_creation_type = LoadSession; - StripHeader(init_data_vector, strlen(kPrefixedApiLoadSessionHeader)); - } else if (HasHeader(init_data, - init_data_length, - kPrefixedApiPersistentSessionHeader)) { - session_creation_type = PersistentSession; - StripHeader(init_data_vector, strlen(kPrefixedApiPersistentSessionHeader)); - } - - scoped_ptr<media::NewSessionCdmPromise> promise( - new media::CdmCallbackPromise<std::string>( - base::Bind(&ProxyDecryptor::SetSessionId, - weak_ptr_factory_.GetWeakPtr(), - session_creation_type), - base::Bind(&ProxyDecryptor::OnSessionError, - weak_ptr_factory_.GetWeakPtr(), - std::string()))); // No session id until created. - uint8* init_data_vector_data = - (init_data_vector.size() > 0) ? &init_data_vector[0] : nullptr; - - if (session_creation_type == LoadSession) { - media_keys_->LoadSession( - std::string(reinterpret_cast<const char*>(init_data_vector_data), - init_data_vector.size()), - promise.Pass()); - return true; - } - - media::MediaKeys::SessionType session_type = - session_creation_type == PersistentSession - ? media::MediaKeys::PERSISTENT_SESSION - : media::MediaKeys::TEMPORARY_SESSION; - - media_keys_->CreateSession(init_data_type, - init_data_vector_data, - init_data_vector.size(), - session_type, - promise.Pass()); - return true; -} - -void ProxyDecryptor::AddKey(const uint8* key, - int key_length, - const uint8* init_data, - int init_data_length, - const std::string& web_session_id) { - DVLOG(1) << "AddKey()"; - - // In the prefixed API, the session parameter provided to addKey() is - // optional, so use the single existing session if it exists. - // TODO(jrummell): remove when the prefixed API is removed. - std::string session_id(web_session_id); - if (session_id.empty()) { - if (active_sessions_.size() == 1) { - base::hash_map<std::string, bool>::iterator it = active_sessions_.begin(); - session_id = it->first; - } else { - OnSessionError(std::string(), - media::MediaKeys::NOT_SUPPORTED_ERROR, - 0, - "SessionId not specified."); - return; - } - } - - scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>( - base::Bind(&ProxyDecryptor::OnSessionReady, - weak_ptr_factory_.GetWeakPtr(), - web_session_id), - base::Bind(&ProxyDecryptor::OnSessionError, - weak_ptr_factory_.GetWeakPtr(), - web_session_id))); - - // EME WD spec only supports a single array passed to the CDM. For - // Clear Key using v0.1b, both arrays are used (|init_data| is key_id). - // Since the EME WD spec supports the key as a JSON Web Key, - // convert the 2 arrays to a JWK and pass it as the single array. - if (is_clear_key_) { - // Decryptor doesn't support empty key ID (see http://crbug.com/123265). - // So ensure a non-empty value is passed. - if (!init_data) { - static const uint8 kDummyInitData[1] = {0}; - init_data = kDummyInitData; - init_data_length = arraysize(kDummyInitData); - } - - std::string jwk = - media::GenerateJWKSet(key, key_length, init_data, init_data_length); - DCHECK(!jwk.empty()); - media_keys_->UpdateSession(session_id, - reinterpret_cast<const uint8*>(jwk.data()), - jwk.size(), - promise.Pass()); - return; - } - - media_keys_->UpdateSession(session_id, key, key_length, promise.Pass()); -} - -void ProxyDecryptor::CancelKeyRequest(const std::string& web_session_id) { - DVLOG(1) << "CancelKeyRequest()"; - - scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>( - base::Bind(&ProxyDecryptor::OnSessionClosed, - weak_ptr_factory_.GetWeakPtr(), - web_session_id), - base::Bind(&ProxyDecryptor::OnSessionError, - weak_ptr_factory_.GetWeakPtr(), - web_session_id))); - media_keys_->RemoveSession(web_session_id, promise.Pass()); -} - -scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys( - media::CdmFactory* cdm_factory, - const std::string& key_system, - const GURL& security_origin) { - base::WeakPtr<ProxyDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr(); - return cdm_factory->Create( - key_system, - security_origin, - base::Bind(&ProxyDecryptor::OnSessionMessage, weak_this), - base::Bind(&ProxyDecryptor::OnSessionReady, weak_this), - base::Bind(&ProxyDecryptor::OnSessionClosed, weak_this), - base::Bind(&ProxyDecryptor::OnSessionError, weak_this), - base::Bind(&ProxyDecryptor::OnSessionKeysChange, weak_this), - base::Bind(&ProxyDecryptor::OnSessionExpirationUpdate, weak_this)); -} - -void ProxyDecryptor::OnSessionMessage(const std::string& web_session_id, - const std::vector<uint8>& message, - const GURL& destination_url) { - // Assumes that OnSessionCreated() has been called before this. - - // For ClearKey, convert the message from JSON into just passing the key - // as the message. If unable to extract the key, return the message unchanged. - if (is_clear_key_) { - std::vector<uint8> key; - if (media::ExtractFirstKeyIdFromLicenseRequest(message, &key)) { - key_message_cb_.Run(web_session_id, key, destination_url); - return; - } - } - - 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); -} - -void ProxyDecryptor::OnSessionClosed(const std::string& web_session_id) { - base::hash_map<std::string, bool>::iterator it = - active_sessions_.find(web_session_id); - - // Latest EME spec separates closing a session ("allows an application to - // indicate that it no longer needs the session") and actually closing the - // session (done by the CDM at any point "such as in response to a close() - // call, when the session is no longer needed, or when system resources are - // lost.") Thus the CDM may cause 2 close() events -- one to resolve the - // close() promise, and a second to actually close the session. Prefixed EME - // only expects 1 close event, so drop the second (and subsequent) events. - // However, this means we can't tell if the CDM is generating spurious close() - // events. - if (it == active_sessions_.end()) - return; - - if (it->second) { - OnSessionError(web_session_id, - media::MediaKeys::NOT_SUPPORTED_ERROR, - kSessionClosedSystemCode, - "Do not close persistent sessions."); - } - active_sessions_.erase(it); -} - -void ProxyDecryptor::OnSessionError(const std::string& web_session_id, - media::MediaKeys::Exception exception_code, - uint32 system_code, - const std::string& error_message) { - // Convert |error_name| back to MediaKeys::KeyError if possible. Prefixed - // EME has different error message, so all the specific error events will - // get lost. - media::MediaKeys::KeyError error_code; - switch (exception_code) { - case media::MediaKeys::CLIENT_ERROR: - error_code = media::MediaKeys::kClientError; - break; - case media::MediaKeys::OUTPUT_ERROR: - error_code = media::MediaKeys::kOutputError; - break; - default: - // This will include all other CDM4 errors and any error generated - // by CDM5 or later. - error_code = media::MediaKeys::kUnknownError; - break; - } - key_error_cb_.Run(web_session_id, error_code, system_code); -} - -void ProxyDecryptor::SetSessionId(SessionCreationType session_type, - const std::string& web_session_id) { - // Loaded sessions are considered persistent. - bool is_persistent = - session_type == PersistentSession || session_type == LoadSession; - active_sessions_.insert(std::make_pair(web_session_id, is_persistent)); - - // For LoadSession(), generate the SessionReady event. - if (session_type == LoadSession) - OnSessionReady(web_session_id); -} - -} // namespace content |