| Index: content/renderer/media/crypto/proxy_decryptor.cc
|
| diff --git a/content/renderer/media/crypto/proxy_decryptor.cc b/content/renderer/media/crypto/proxy_decryptor.cc
|
| index be9893b584e57bf93b073fc8d2bce29f933e13de..7d790706f1a7ca979651ddfbb210b8991fed8793 100644
|
| --- a/content/renderer/media/crypto/proxy_decryptor.cc
|
| +++ b/content/renderer/media/crypto/proxy_decryptor.cc
|
| @@ -11,6 +11,7 @@
|
| #include "base/logging.h"
|
| #include "base/strings/string_util.h"
|
| #include "content/renderer/media/crypto/content_decryption_module_factory.h"
|
| +#include "media/base/cdm_promise.h"
|
| #include "media/cdm/json_web_key.h"
|
| #include "media/cdm/key_system_names.h"
|
|
|
| @@ -24,14 +25,6 @@
|
|
|
| namespace content {
|
|
|
| -// Since these reference IDs may conflict with the ones generated in
|
| -// WebContentDecryptionModuleSessionImpl for the short time both paths are
|
| -// active, start with 100000 and generate the IDs from there.
|
| -// TODO(jrummell): Only allow one path http://crbug.com/306680.
|
| -uint32 ProxyDecryptor::next_session_id_ = 100000;
|
| -
|
| -const uint32 kInvalidSessionId = 0;
|
| -
|
| // 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.
|
| @@ -105,28 +98,39 @@ bool HasHeader(const uint8* data, int data_length, const std::string& header) {
|
| bool ProxyDecryptor::GenerateKeyRequest(const std::string& content_type,
|
| const uint8* init_data,
|
| int init_data_length) {
|
| - // Use a unique reference id for this request.
|
| - uint32 session_id = next_session_id_++;
|
| -
|
| + DVLOG(1) << "GenerateKeyRequest()";
|
| const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|";
|
| const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|";
|
|
|
| - if (HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader)) {
|
| - persistent_sessions_.insert(session_id);
|
| + bool loadSession =
|
| + HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader);
|
| + bool persistent = HasHeader(
|
| + init_data, init_data_length, kPrefixedApiPersistentSessionHeader);
|
| +
|
| + scoped_ptr<media::NewSessionCdmPromise> promise(
|
| + new media::NewSessionCdmPromise(
|
| + base::Bind(&ProxyDecryptor::SetSessionId,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + persistent || loadSession),
|
| + base::Bind(&ProxyDecryptor::OnSessionError,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + std::string()))); // No session id until created.
|
| +
|
| + if (loadSession) {
|
| media_keys_->LoadSession(
|
| - session_id,
|
| std::string(reinterpret_cast<const char*>(
|
| init_data + strlen(kPrefixedApiLoadSessionHeader)),
|
| - init_data_length - strlen(kPrefixedApiLoadSessionHeader)));
|
| + init_data_length - strlen(kPrefixedApiLoadSessionHeader)),
|
| + promise.Pass());
|
| 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);
|
| + media::MediaKeys::SessionType session_type =
|
| + persistent ? media::MediaKeys::PERSISTENT_SESSION
|
| + : media::MediaKeys::TEMPORARY_SESSION;
|
| + media_keys_->CreateSession(
|
| + content_type, init_data, init_data_length, session_type, promise.Pass());
|
| + return true;
|
| }
|
|
|
| void ProxyDecryptor::AddKey(const uint8* key,
|
| @@ -136,18 +140,31 @@ void ProxyDecryptor::AddKey(const uint8* key,
|
| const std::string& web_session_id) {
|
| DVLOG(1) << "AddKey()";
|
|
|
| - // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called.
|
| - uint32 session_id = LookupSessionId(web_session_id);
|
| - if (session_id == kInvalidSessionId) {
|
| - // Session hasn't been referenced before, so it is an error.
|
| - // Note that the specification says "If sessionId is not null and is
|
| - // unrecognized, throw an INVALID_ACCESS_ERR." However, for backwards
|
| - // compatibility the error is not thrown, but rather reported as a
|
| - // KeyError.
|
| - key_error_cb_.Run(std::string(), media::MediaKeys::kUnknownError, 0);
|
| - return;
|
| + // 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::SimpleCdmPromise(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,
|
| @@ -164,27 +181,27 @@ void ProxyDecryptor::AddKey(const uint8* key,
|
| 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());
|
| + media_keys_->UpdateSession(session_id,
|
| + reinterpret_cast<const uint8*>(jwk.data()),
|
| + jwk.size(),
|
| + promise.Pass());
|
| return;
|
| }
|
|
|
| - media_keys_->UpdateSession(session_id, key, key_length);
|
| + media_keys_->UpdateSession(session_id, key, key_length, promise.Pass());
|
| }
|
|
|
| -void ProxyDecryptor::CancelKeyRequest(const std::string& session_id) {
|
| +void ProxyDecryptor::CancelKeyRequest(const std::string& web_session_id) {
|
| DVLOG(1) << "CancelKeyRequest()";
|
|
|
| - // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called.
|
| - uint32 session_reference_id = LookupSessionId(session_id);
|
| - if (session_reference_id == kInvalidSessionId) {
|
| - // Session hasn't been created, so it is an error.
|
| - key_error_cb_.Run(
|
| - std::string(), media::MediaKeys::kUnknownError, 0);
|
| - }
|
| - else {
|
| - media_keys_->ReleaseSession(session_reference_id);
|
| - }
|
| + scoped_ptr<media::SimpleCdmPromise> promise(
|
| + new media::SimpleCdmPromise(base::Bind(&ProxyDecryptor::OnSessionClosed,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + web_session_id),
|
| + base::Bind(&ProxyDecryptor::OnSessionError,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + web_session_id)));
|
| + media_keys_->ReleaseSession(web_session_id, promise.Pass());
|
| }
|
|
|
| scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys(
|
| @@ -199,8 +216,6 @@ scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys(
|
| manager_,
|
| &cdm_id_,
|
| #endif // defined(ENABLE_PEPPER_CDMS)
|
| - base::Bind(&ProxyDecryptor::OnSessionCreated,
|
| - weak_ptr_factory_.GetWeakPtr()),
|
| base::Bind(&ProxyDecryptor::OnSessionMessage,
|
| weak_ptr_factory_.GetWeakPtr()),
|
| base::Bind(&ProxyDecryptor::OnSessionReady,
|
| @@ -211,68 +226,56 @@ scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys(
|
| weak_ptr_factory_.GetWeakPtr()));
|
| }
|
|
|
| -void ProxyDecryptor::OnSessionCreated(uint32 session_id,
|
| - const std::string& web_session_id) {
|
| - // Due to heartbeat messages, OnSessionCreated() can get called multiple
|
| - // times.
|
| - 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,
|
| +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.
|
| - key_message_cb_.Run(
|
| - LookupWebSessionId(session_id), message, destination_url);
|
| + key_message_cb_.Run(web_session_id, message, destination_url);
|
| }
|
|
|
| -void ProxyDecryptor::OnSessionReady(uint32 session_id) {
|
| - // Assumes that OnSessionCreated() has been called before this.
|
| - key_added_cb_.Run(LookupWebSessionId(session_id));
|
| +void ProxyDecryptor::OnSessionReady(const std::string& web_session_id) {
|
| + key_added_cb_.Run(web_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);
|
| +void ProxyDecryptor::OnSessionClosed(const std::string& web_session_id) {
|
| + base::hash_map<std::string, bool>::iterator it =
|
| + active_sessions_.find(web_session_id);
|
| + if (it->second) {
|
| + OnSessionError(web_session_id,
|
| + media::MediaKeys::NOT_SUPPORTED_ERROR,
|
| + kSessionClosedSystemCode,
|
| + "Do not close persistent sessions.");
|
| }
|
| -
|
| - sessions_.erase(session_id);
|
| -}
|
| -
|
| -void ProxyDecryptor::OnSessionError(uint32 session_id,
|
| - media::MediaKeys::KeyError error_code,
|
| - uint32 system_code) {
|
| - // Assumes that OnSessionCreated() has been called before this.
|
| - key_error_cb_.Run(LookupWebSessionId(session_id), error_code, system_code);
|
| + active_sessions_.erase(it);
|
| }
|
|
|
| -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;
|
| +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;
|
| }
|
| -
|
| - // If |session_id| is null, then use the single reference id.
|
| - if (session_id.empty() && sessions_.size() == 1)
|
| - return sessions_.begin()->first;
|
| -
|
| - return kInvalidSessionId;
|
| + key_error_cb_.Run(web_session_id, error_code, system_code);
|
| }
|
|
|
| -const std::string& ProxyDecryptor::LookupWebSessionId(uint32 session_id) const {
|
| - DCHECK_NE(session_id, kInvalidSessionId);
|
| -
|
| - // Session may not exist if error happens during GenerateKeyRequest().
|
| - SessionIdMap::const_iterator it = sessions_.find(session_id);
|
| - return (it != sessions_.end()) ? it->second : base::EmptyString();
|
| +void ProxyDecryptor::SetSessionId(bool persistent,
|
| + const std::string& web_session_id) {
|
| + active_sessions_.insert(std::make_pair(web_session_id, persistent));
|
| }
|
|
|
| } // namespace content
|
|
|