| Index: media/cdm/proxy_decryptor.cc
|
| diff --git a/media/cdm/proxy_decryptor.cc b/media/cdm/proxy_decryptor.cc
|
| deleted file mode 100644
|
| index 8d0085b58513ef1848f0c8cc33a3ed0862f25703..0000000000000000000000000000000000000000
|
| --- a/media/cdm/proxy_decryptor.cc
|
| +++ /dev/null
|
| @@ -1,415 +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 "media/cdm/proxy_decryptor.h"
|
| -
|
| -#include <stddef.h>
|
| -#include <cstring>
|
| -#include <utility>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/callback_helpers.h"
|
| -#include "base/logging.h"
|
| -#include "base/macros.h"
|
| -#include "base/strings/string_util.h"
|
| -#include "build/build_config.h"
|
| -#include "media/base/cdm_callback_promise.h"
|
| -#include "media/base/cdm_config.h"
|
| -#include "media/base/cdm_factory.h"
|
| -#include "media/base/cdm_key_information.h"
|
| -#include "media/base/key_systems.h"
|
| -#include "media/base/media_permission.h"
|
| -#include "media/cdm/json_web_key.h"
|
| -#include "media/cdm/key_system_names.h"
|
| -
|
| -namespace media {
|
| -
|
| -// 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::PendingGenerateKeyRequestData::PendingGenerateKeyRequestData(
|
| - EmeInitDataType init_data_type,
|
| - const std::vector<uint8_t>& init_data)
|
| - : init_data_type(init_data_type), init_data(init_data) {}
|
| -
|
| -ProxyDecryptor::PendingGenerateKeyRequestData::
|
| - ~PendingGenerateKeyRequestData() {
|
| -}
|
| -
|
| -ProxyDecryptor::ProxyDecryptor(MediaPermission* media_permission,
|
| - bool use_hw_secure_codecs,
|
| - const KeyAddedCB& key_added_cb,
|
| - const KeyErrorCB& key_error_cb,
|
| - const KeyMessageCB& key_message_cb)
|
| - : is_creating_cdm_(false),
|
| -#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
|
| - media_permission_(media_permission),
|
| -#endif
|
| - use_hw_secure_codecs_(use_hw_secure_codecs),
|
| - 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(media_permission);
|
| - 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_ = nullptr;
|
| -}
|
| -
|
| -void ProxyDecryptor::CreateCdm(CdmFactory* cdm_factory,
|
| - const std::string& key_system,
|
| - const GURL& security_origin,
|
| - const CdmContextReadyCB& cdm_context_ready_cb) {
|
| - DVLOG(1) << __FUNCTION__ << ": key_system = " << key_system;
|
| - DCHECK(!is_creating_cdm_);
|
| - DCHECK(!media_keys_);
|
| -
|
| - // TODO(sandersd): Trigger permissions check here and use it to determine
|
| - // distinctive identifier support, instead of always requiring the
|
| - // permission. http://crbug.com/455271
|
| - CdmConfig cdm_config;
|
| - cdm_config.allow_distinctive_identifier = true;
|
| - cdm_config.allow_persistent_state = true;
|
| - cdm_config.use_hw_secure_codecs = use_hw_secure_codecs_;
|
| -
|
| - is_creating_cdm_ = true;
|
| -
|
| - base::WeakPtr<ProxyDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr();
|
| - cdm_factory->Create(
|
| - key_system, security_origin, cdm_config,
|
| - base::Bind(&ProxyDecryptor::OnSessionMessage, weak_this),
|
| - base::Bind(&ProxyDecryptor::OnSessionClosed, weak_this),
|
| - base::Bind(&ProxyDecryptor::OnLegacySessionError, weak_this),
|
| - base::Bind(&ProxyDecryptor::OnSessionKeysChange, weak_this),
|
| - base::Bind(&ProxyDecryptor::OnSessionExpirationUpdate, weak_this),
|
| - base::Bind(&ProxyDecryptor::OnCdmCreated, weak_this, key_system,
|
| - security_origin, cdm_context_ready_cb));
|
| -}
|
| -
|
| -void ProxyDecryptor::OnCdmCreated(const std::string& key_system,
|
| - const GURL& security_origin,
|
| - const CdmContextReadyCB& cdm_context_ready_cb,
|
| - const scoped_refptr<MediaKeys>& cdm,
|
| - const std::string& /* error_message */) {
|
| - is_creating_cdm_ = false;
|
| -
|
| - if (!cdm) {
|
| - cdm_context_ready_cb.Run(nullptr);
|
| - } else {
|
| - key_system_ = key_system;
|
| - security_origin_ = security_origin;
|
| - is_clear_key_ = IsClearKey(key_system) || IsExternalClearKey(key_system);
|
| - media_keys_ = cdm;
|
| -
|
| - cdm_context_ready_cb.Run(media_keys_->GetCdmContext());
|
| - }
|
| -
|
| - for (const auto& request : pending_requests_)
|
| - GenerateKeyRequestInternal(request->init_data_type, request->init_data);
|
| -
|
| - pending_requests_.clear();
|
| -}
|
| -
|
| -void ProxyDecryptor::GenerateKeyRequest(EmeInitDataType init_data_type,
|
| - const uint8_t* init_data,
|
| - int init_data_length) {
|
| - std::vector<uint8_t> init_data_vector(init_data,
|
| - init_data + init_data_length);
|
| -
|
| - if (is_creating_cdm_) {
|
| - pending_requests_.push_back(
|
| - new PendingGenerateKeyRequestData(init_data_type, init_data_vector));
|
| - return;
|
| - }
|
| -
|
| - GenerateKeyRequestInternal(init_data_type, init_data_vector);
|
| -}
|
| -
|
| -// Returns true if |data| is prefixed with |header| and has data after the
|
| -// |header|.
|
| -static bool HasHeader(const std::vector<uint8_t>& data,
|
| - const std::string& header) {
|
| - return data.size() > header.size() &&
|
| - std::equal(header.begin(), header.end(), data.begin());
|
| -}
|
| -
|
| -// Removes the first |length| items from |data|.
|
| -static void StripHeader(std::vector<uint8_t>& data, size_t length) {
|
| - data.erase(data.begin(), data.begin() + length);
|
| -}
|
| -
|
| -void ProxyDecryptor::GenerateKeyRequestInternal(
|
| - EmeInitDataType init_data_type,
|
| - const std::vector<uint8_t>& init_data) {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(!is_creating_cdm_);
|
| -
|
| - if (!media_keys_) {
|
| - OnLegacySessionError(std::string(), MediaKeys::NOT_SUPPORTED_ERROR, 0,
|
| - "CDM creation failed.");
|
| - return;
|
| - }
|
| -
|
| - const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|";
|
| - const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|";
|
| -
|
| - SessionCreationType session_creation_type = TemporarySession;
|
| - std::vector<uint8_t> stripped_init_data = init_data;
|
| - if (HasHeader(init_data, kPrefixedApiLoadSessionHeader)) {
|
| - session_creation_type = LoadSession;
|
| - StripHeader(stripped_init_data, strlen(kPrefixedApiLoadSessionHeader));
|
| - } else if (HasHeader(init_data, kPrefixedApiPersistentSessionHeader)) {
|
| - session_creation_type = PersistentSession;
|
| - StripHeader(stripped_init_data,
|
| - strlen(kPrefixedApiPersistentSessionHeader));
|
| - }
|
| -
|
| - scoped_ptr<NewSessionCdmPromise> promise(new CdmCallbackPromise<std::string>(
|
| - base::Bind(&ProxyDecryptor::SetSessionId, weak_ptr_factory_.GetWeakPtr(),
|
| - session_creation_type),
|
| - base::Bind(&ProxyDecryptor::OnLegacySessionError,
|
| - weak_ptr_factory_.GetWeakPtr(),
|
| - std::string()))); // No session id until created.
|
| -
|
| - if (session_creation_type == LoadSession) {
|
| - media_keys_->LoadSession(
|
| - MediaKeys::PERSISTENT_LICENSE_SESSION,
|
| - std::string(reinterpret_cast<const char*>(stripped_init_data.data()),
|
| - stripped_init_data.size()),
|
| - std::move(promise));
|
| - return;
|
| - }
|
| -
|
| - MediaKeys::SessionType session_type =
|
| - session_creation_type == PersistentSession
|
| - ? MediaKeys::PERSISTENT_LICENSE_SESSION
|
| - : MediaKeys::TEMPORARY_SESSION;
|
| -
|
| - // No permission required when AesDecryptor is used or when the key system is
|
| - // external clear key.
|
| - DCHECK(!key_system_.empty());
|
| - if (CanUseAesDecryptor(key_system_) || IsExternalClearKey(key_system_)) {
|
| - OnPermissionStatus(session_type, init_data_type, stripped_init_data,
|
| - std::move(promise), true /* granted */);
|
| - return;
|
| - }
|
| -
|
| -#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
|
| - media_permission_->RequestPermission(
|
| - MediaPermission::PROTECTED_MEDIA_IDENTIFIER, security_origin_,
|
| - base::Bind(&ProxyDecryptor::OnPermissionStatus,
|
| - weak_ptr_factory_.GetWeakPtr(), session_type, init_data_type,
|
| - stripped_init_data, base::Passed(&promise)));
|
| -#else
|
| - OnPermissionStatus(session_type, init_data_type, stripped_init_data,
|
| - std::move(promise), true /* granted */);
|
| -#endif
|
| -}
|
| -
|
| -void ProxyDecryptor::OnPermissionStatus(
|
| - MediaKeys::SessionType session_type,
|
| - EmeInitDataType init_data_type,
|
| - const std::vector<uint8_t>& init_data,
|
| - scoped_ptr<NewSessionCdmPromise> promise,
|
| - bool granted) {
|
| - // ProxyDecryptor is only used by Prefixed EME, where RequestPermission() is
|
| - // only for triggering the permission UI. Later CheckPermission() will be
|
| - // called (e.g. in PlatformVerificationFlow on ChromeOS; in BrowserCdmManager
|
| - // on Android) and the permission status will be evaluated then.
|
| - DVLOG_IF(1, !granted) << "Permission request rejected.";
|
| -
|
| - media_keys_->CreateSessionAndGenerateRequest(session_type, init_data_type,
|
| - init_data, std::move(promise));
|
| -}
|
| -
|
| -void ProxyDecryptor::AddKey(const uint8_t* key,
|
| - int key_length,
|
| - const uint8_t* init_data,
|
| - int init_data_length,
|
| - const std::string& session_id) {
|
| - DVLOG(1) << "AddKey()";
|
| -
|
| - if (!media_keys_) {
|
| - OnLegacySessionError(std::string(), MediaKeys::INVALID_STATE_ERROR, 0,
|
| - "CDM is not available.");
|
| - return;
|
| - }
|
| -
|
| - // In the prefixed API, the session parameter provided to addKey() is
|
| - // optional, so use the single existing session if it exists.
|
| - std::string new_session_id(session_id);
|
| - if (new_session_id.empty()) {
|
| - if (active_sessions_.size() == 1) {
|
| - base::hash_map<std::string, bool>::iterator it = active_sessions_.begin();
|
| - new_session_id = it->first;
|
| - } else {
|
| - OnLegacySessionError(std::string(), MediaKeys::NOT_SUPPORTED_ERROR, 0,
|
| - "SessionId not specified.");
|
| - return;
|
| - }
|
| - }
|
| -
|
| - scoped_ptr<SimpleCdmPromise> promise(new CdmCallbackPromise<>(
|
| - base::Bind(&ProxyDecryptor::GenerateKeyAdded,
|
| - weak_ptr_factory_.GetWeakPtr(), session_id),
|
| - base::Bind(&ProxyDecryptor::OnLegacySessionError,
|
| - weak_ptr_factory_.GetWeakPtr(), 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_t kDummyInitData[1] = {0};
|
| - init_data = kDummyInitData;
|
| - init_data_length = arraysize(kDummyInitData);
|
| - }
|
| -
|
| - std::string jwk =
|
| - GenerateJWKSet(key, key_length, init_data, init_data_length);
|
| - DCHECK(!jwk.empty());
|
| - media_keys_->UpdateSession(new_session_id,
|
| - std::vector<uint8_t>(jwk.begin(), jwk.end()),
|
| - std::move(promise));
|
| - return;
|
| - }
|
| -
|
| - media_keys_->UpdateSession(new_session_id,
|
| - std::vector<uint8_t>(key, key + key_length),
|
| - std::move(promise));
|
| -}
|
| -
|
| -void ProxyDecryptor::CancelKeyRequest(const std::string& session_id) {
|
| - DVLOG(1) << "CancelKeyRequest()";
|
| -
|
| - if (!media_keys_) {
|
| - OnLegacySessionError(std::string(), MediaKeys::INVALID_STATE_ERROR, 0,
|
| - "CDM is not available.");
|
| - return;
|
| - }
|
| -
|
| - scoped_ptr<SimpleCdmPromise> promise(new CdmCallbackPromise<>(
|
| - base::Bind(&ProxyDecryptor::OnSessionClosed,
|
| - weak_ptr_factory_.GetWeakPtr(), session_id),
|
| - base::Bind(&ProxyDecryptor::OnLegacySessionError,
|
| - weak_ptr_factory_.GetWeakPtr(), session_id)));
|
| - media_keys_->RemoveSession(session_id, std::move(promise));
|
| -}
|
| -
|
| -void ProxyDecryptor::OnSessionMessage(const std::string& session_id,
|
| - MediaKeys::MessageType message_type,
|
| - const std::vector<uint8_t>& message,
|
| - const GURL& legacy_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_t> key;
|
| - if (ExtractFirstKeyIdFromLicenseRequest(message, &key)) {
|
| - key_message_cb_.Run(session_id, key, legacy_destination_url);
|
| - return;
|
| - }
|
| - }
|
| -
|
| - key_message_cb_.Run(session_id, message, legacy_destination_url);
|
| -}
|
| -
|
| -void ProxyDecryptor::OnSessionKeysChange(const std::string& session_id,
|
| - bool has_additional_usable_key,
|
| - CdmKeysInfo keys_info) {
|
| - // EME v0.1b doesn't support this event.
|
| -}
|
| -
|
| -void ProxyDecryptor::OnSessionExpirationUpdate(
|
| - const std::string& session_id,
|
| - const base::Time& new_expiry_time) {
|
| - // EME v0.1b doesn't support this event.
|
| -}
|
| -
|
| -void ProxyDecryptor::GenerateKeyAdded(const std::string& session_id) {
|
| - // EME WD doesn't support this event, but it is needed for EME v0.1b.
|
| - key_added_cb_.Run(session_id);
|
| -}
|
| -
|
| -void ProxyDecryptor::OnSessionClosed(const std::string& session_id) {
|
| - base::hash_map<std::string, bool>::iterator it =
|
| - active_sessions_.find(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) {
|
| - OnLegacySessionError(session_id, MediaKeys::NOT_SUPPORTED_ERROR,
|
| - kSessionClosedSystemCode,
|
| - "Do not close persistent sessions.");
|
| - }
|
| - active_sessions_.erase(it);
|
| -}
|
| -
|
| -void ProxyDecryptor::OnLegacySessionError(const std::string& session_id,
|
| - MediaKeys::Exception exception_code,
|
| - uint32_t 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.
|
| - MediaKeys::KeyError error_code;
|
| - switch (exception_code) {
|
| - case MediaKeys::CLIENT_ERROR:
|
| - error_code = MediaKeys::kClientError;
|
| - break;
|
| - case MediaKeys::OUTPUT_ERROR:
|
| - error_code = MediaKeys::kOutputError;
|
| - break;
|
| - default:
|
| - // This will include all other CDM4 errors and any error generated
|
| - // by CDM5 or later.
|
| - error_code = MediaKeys::kUnknownError;
|
| - break;
|
| - }
|
| - key_error_cb_.Run(session_id, error_code, system_code);
|
| -}
|
| -
|
| -void ProxyDecryptor::SetSessionId(SessionCreationType session_type,
|
| - const std::string& session_id) {
|
| - // LoadSession() returns empty |session_id| if the session is not found, so
|
| - // convert this into an error.
|
| - if (session_type == LoadSession && session_id.empty()) {
|
| - OnLegacySessionError(session_id, MediaKeys::INVALID_ACCESS_ERROR, 0,
|
| - "Incorrect session id specified for LoadSession().");
|
| - return;
|
| - }
|
| -
|
| - // Loaded sessions are considered persistent.
|
| - bool is_persistent =
|
| - session_type == PersistentSession || session_type == LoadSession;
|
| - active_sessions_.insert(std::make_pair(session_id, is_persistent));
|
| -
|
| - // For LoadSession(), generate the KeyAdded event.
|
| - if (session_type == LoadSession)
|
| - GenerateKeyAdded(session_id);
|
| -}
|
| -
|
| -} // namespace media
|
|
|