This source file includes following definitions.
- weak_ptr_factory_
- GetDecryptor
- GetCdmId
- InitializeCDM
- HasHeader
- GenerateKeyRequest
- AddKey
- CancelKeyRequest
- CreateMediaKeys
- OnSessionCreated
- OnSessionMessage
- OnSessionReady
- OnSessionClosed
- OnSessionError
- LookupSessionId
- LookupWebSessionId
#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 "content/renderer/media/crypto/content_decryption_module_factory.h"
#include "media/cdm/json_web_key.h"
#include "media/cdm/key_system_names.h"
#if defined(ENABLE_PEPPER_CDMS)
#include "content/renderer/media/crypto/pepper_cdm_wrapper.h"
#endif
#if defined(OS_ANDROID)
#include "content/renderer/media/android/renderer_media_player_manager.h"
#endif
namespace content {
uint32 ProxyDecryptor::next_session_id_ = 100000;
const uint32 kInvalidSessionId = 0;
const int kSessionClosedSystemCode = 29127;
ProxyDecryptor::ProxyDecryptor(
#if defined(ENABLE_PEPPER_CDMS)
const CreatePepperCdmCB& create_pepper_cdm_cb,
#elif defined(OS_ANDROID)
RendererMediaPlayerManager* manager,
#endif
const KeyAddedCB& key_added_cb,
const KeyErrorCB& key_error_cb,
const KeyMessageCB& key_message_cb)
:
#if defined(ENABLE_PEPPER_CDMS)
create_pepper_cdm_cb_(create_pepper_cdm_cb),
#elif defined(OS_ANDROID)
manager_(manager),
cdm_id_(RendererMediaPlayerManager::kInvalidCdmId),
#endif
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) {
#if defined(ENABLE_PEPPER_CDMS)
DCHECK(!create_pepper_cdm_cb_.is_null());
#endif
DCHECK(!key_added_cb_.is_null());
DCHECK(!key_error_cb_.is_null());
DCHECK(!key_message_cb_.is_null());
}
ProxyDecryptor::~ProxyDecryptor() {
media_keys_.reset();
}
media::Decryptor* ProxyDecryptor::GetDecryptor() {
return media_keys_ ? media_keys_->GetDecryptor() : NULL;
}
#if defined(OS_ANDROID)
int ProxyDecryptor::GetCdmId() {
return cdm_id_;
}
#endif
bool ProxyDecryptor::InitializeCDM(const std::string& key_system,
const GURL& security_origin) {
DVLOG(1) << "InitializeCDM: key_system = " << key_system;
DCHECK(!media_keys_);
media_keys_ = CreateMediaKeys(key_system, security_origin);
if (!media_keys_)
return false;
is_clear_key_ =
media::IsClearKey(key_system) || media::IsExternalClearKey(key_system);
return true;
}
bool HasHeader(const uint8* data, int data_length, const std::string& header) {
return static_cast<size_t>(data_length) > header.size() &&
std::equal(data, data + header.size(), header.begin());
}
bool ProxyDecryptor::GenerateKeyRequest(const std::string& content_type,
const uint8* init_data,
int init_data_length) {
uint32 session_id = next_session_id_++;
const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|";
const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|";
if (HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader)) {
persistent_sessions_.insert(session_id);
media_keys_->LoadSession(
session_id,
std::string(reinterpret_cast<const char*>(
init_data + strlen(kPrefixedApiLoadSessionHeader)),
init_data_length - strlen(kPrefixedApiLoadSessionHeader)));
return true;
}
if (HasHeader(
init_data, init_data_length, kPrefixedApiPersistentSessionHeader))
persistent_sessions_.insert(session_id);
return media_keys_->CreateSession(
session_id, content_type, init_data, init_data_length);
}
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()";
uint32 session_id = LookupSessionId(web_session_id);
if (session_id == kInvalidSessionId) {
key_error_cb_.Run(std::string(), media::MediaKeys::kUnknownError, 0);
return;
}
if (is_clear_key_) {
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());
return;
}
media_keys_->UpdateSession(session_id, key, key_length);
}
void ProxyDecryptor::CancelKeyRequest(const std::string& session_id) {
DVLOG(1) << "CancelKeyRequest()";
uint32 session_reference_id = LookupSessionId(session_id);
if (session_reference_id == kInvalidSessionId) {
key_error_cb_.Run(
std::string(), media::MediaKeys::kUnknownError, 0);
}
else {
media_keys_->ReleaseSession(session_reference_id);
}
}
scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys(
const std::string& key_system,
const GURL& security_origin) {
return ContentDecryptionModuleFactory::Create(
key_system,
security_origin,
#if defined(ENABLE_PEPPER_CDMS)
create_pepper_cdm_cb_,
#elif defined(OS_ANDROID)
manager_,
&cdm_id_,
#endif
base::Bind(&ProxyDecryptor::OnSessionCreated,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&ProxyDecryptor::OnSessionMessage,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&ProxyDecryptor::OnSessionReady,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&ProxyDecryptor::OnSessionClosed,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&ProxyDecryptor::OnSessionError,
weak_ptr_factory_.GetWeakPtr()));
}
void ProxyDecryptor::OnSessionCreated(uint32 session_id,
const std::string& web_session_id) {
SessionIdMap::iterator it = sessions_.find(session_id);
DCHECK(it == sessions_.end() || it->second == web_session_id);
if (it == sessions_.end())
sessions_[session_id] = web_session_id;
}
void ProxyDecryptor::OnSessionMessage(uint32 session_id,
const std::vector<uint8>& message,
const std::string& destination_url) {
key_message_cb_.Run(LookupWebSessionId(session_id), message, destination_url);
}
void ProxyDecryptor::OnSessionReady(uint32 session_id) {
key_added_cb_.Run(LookupWebSessionId(session_id));
}
void ProxyDecryptor::OnSessionClosed(uint32 session_id) {
std::set<uint32>::iterator it = persistent_sessions_.find(session_id);
if (it != persistent_sessions_.end()) {
persistent_sessions_.erase(it);
OnSessionError(
session_id, media::MediaKeys::kUnknownError, kSessionClosedSystemCode);
}
sessions_.erase(session_id);
}
void ProxyDecryptor::OnSessionError(uint32 session_id,
media::MediaKeys::KeyError error_code,
uint32 system_code) {
key_error_cb_.Run(LookupWebSessionId(session_id), error_code, system_code);
}
uint32 ProxyDecryptor::LookupSessionId(const std::string& session_id) const {
for (SessionIdMap::const_iterator it = sessions_.begin();
it != sessions_.end();
++it) {
if (it->second == session_id)
return it->first;
}
if (session_id.empty() && sessions_.size() == 1)
return sessions_.begin()->first;
return kInvalidSessionId;
}
const std::string& ProxyDecryptor::LookupWebSessionId(uint32 session_id) const {
DCHECK_NE(session_id, kInvalidSessionId);
SessionIdMap::const_iterator it = sessions_.find(session_id);
return (it != sessions_.end()) ? it->second : base::EmptyString();
}
}