Chromium Code Reviews| Index: media/cdm/aes_decryptor.cc |
| diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc |
| index 82c899dece597c392a7f8386038b9726a988f437..ddf6ba1ec9615a63c9c0238ba924f9a0ff83c9ec 100644 |
| --- a/media/cdm/aes_decryptor.cc |
| +++ b/media/cdm/aes_decryptor.cc |
| @@ -15,6 +15,7 @@ |
| #include "media/base/audio_decoder_config.h" |
| #include "media/base/decoder_buffer.h" |
| #include "media/base/decrypt_config.h" |
| +#include "media/base/media_keys_session_promise.h" |
| #include "media/base/video_decoder_config.h" |
| #include "media/base/video_frame.h" |
| #include "media/cdm/json_web_key.h" |
| @@ -28,7 +29,7 @@ class AesDecryptor::SessionIdDecryptionKeyMap { |
| // Use a std::list to actually hold the data. Insertion is always done |
| // at the front, so the "latest" decryption key is always the first one |
| // in the list. |
| - typedef std::list<std::pair<uint32, DecryptionKey*> > KeyList; |
| + typedef std::list<std::pair<std::string, DecryptionKey*> > KeyList; |
| public: |
| SessionIdDecryptionKeyMap() {} |
| @@ -37,10 +38,11 @@ class AesDecryptor::SessionIdDecryptionKeyMap { |
| // Replaces value if |session_id| is already present, or adds it if not. |
| // This |decryption_key| becomes the latest until another insertion or |
| // |session_id| is erased. |
| - void Insert(uint32 session_id, scoped_ptr<DecryptionKey> decryption_key); |
| + void Insert(const std::string& web_session_id, |
| + scoped_ptr<DecryptionKey> decryption_key); |
| // Deletes the entry for |session_id| if present. |
| - void Erase(const uint32 session_id); |
| + void Erase(const std::string& web_session_id); |
| // Returns whether the list is empty |
| bool Empty() const { return key_list_.empty(); } |
| @@ -52,8 +54,8 @@ class AesDecryptor::SessionIdDecryptionKeyMap { |
| } |
| private: |
| - // Searches the list for an element with |session_id|. |
| - KeyList::iterator Find(const uint32 session_id); |
| + // Searches the list for an element with |web_session_id|. |
| + KeyList::iterator Find(const std::string& web_session_id); |
| // Deletes the entry pointed to by |position|. |
| void Erase(KeyList::iterator position); |
| @@ -64,26 +66,28 @@ class AesDecryptor::SessionIdDecryptionKeyMap { |
| }; |
| void AesDecryptor::SessionIdDecryptionKeyMap::Insert( |
| - uint32 session_id, |
| + const std::string& web_session_id, |
| scoped_ptr<DecryptionKey> decryption_key) { |
| - KeyList::iterator it = Find(session_id); |
| + KeyList::iterator it = Find(web_session_id); |
| if (it != key_list_.end()) |
| Erase(it); |
| DecryptionKey* raw_ptr = decryption_key.release(); |
| - key_list_.push_front(std::make_pair(session_id, raw_ptr)); |
| + key_list_.push_front(std::make_pair(web_session_id, raw_ptr)); |
| } |
| -void AesDecryptor::SessionIdDecryptionKeyMap::Erase(const uint32 session_id) { |
| - KeyList::iterator it = Find(session_id); |
| +void AesDecryptor::SessionIdDecryptionKeyMap::Erase( |
| + const std::string& web_session_id) { |
| + KeyList::iterator it = Find(web_session_id); |
| if (it == key_list_.end()) |
| return; |
| Erase(it); |
| } |
| AesDecryptor::SessionIdDecryptionKeyMap::KeyList::iterator |
| -AesDecryptor::SessionIdDecryptionKeyMap::Find(const uint32 session_id) { |
| +AesDecryptor::SessionIdDecryptionKeyMap::Find( |
| + const std::string& web_session_id) { |
| for (KeyList::iterator it = key_list_.begin(); it != key_list_.end(); ++it) { |
| - if (it->first == session_id) |
| + if (it->first == web_session_id) |
| return it; |
| } |
| return key_list_.end(); |
| @@ -215,67 +219,72 @@ static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input, |
| return output; |
| } |
| -AesDecryptor::AesDecryptor(const SessionCreatedCB& session_created_cb, |
| - const SessionMessageCB& session_message_cb, |
| - const SessionReadyCB& session_ready_cb, |
| - const SessionClosedCB& session_closed_cb, |
| - const SessionErrorCB& session_error_cb) |
| - : session_created_cb_(session_created_cb), |
| - session_message_cb_(session_message_cb), |
| - session_ready_cb_(session_ready_cb), |
| - session_closed_cb_(session_closed_cb), |
| - session_error_cb_(session_error_cb) {} |
| +AesDecryptor::AesDecryptor(const SessionMessageCB& session_message_cb) |
| + : session_message_cb_(session_message_cb) { |
| + DCHECK(!session_message_cb_.is_null()); |
| +} |
| AesDecryptor::~AesDecryptor() { |
| key_map_.clear(); |
| } |
| -bool AesDecryptor::CreateSession(uint32 session_id, |
| - const std::string& content_type, |
| +void AesDecryptor::CreateSession(const std::string& init_data_type, |
| const uint8* init_data, |
| - int init_data_length) { |
| - // Validate that this is a new session. |
| - DCHECK(valid_sessions_.find(session_id) == valid_sessions_.end()); |
| - valid_sessions_.insert(session_id); |
| - |
| - std::string web_session_id_string(base::UintToString(next_web_session_id_++)); |
| - |
| - // For now, the AesDecryptor does not care about |content_type|; |
| - // just fire the event with the |init_data| as the request. |
| + int init_data_length, |
| + SessionType session_type, |
| + scoped_ptr<MediaKeysSessionPromise> promise) { |
| + std::string web_session_id(base::UintToString(next_web_session_id_++)); |
| + valid_sessions_.insert(web_session_id); |
| + |
| + // For now, the AesDecryptor does not care about |init_data_type| or |
| + // |session_type|; just resolve the promise and then fire a message event |
| + // with the |init_data| as the request. |
| std::vector<uint8> message; |
| if (init_data && init_data_length) |
| message.assign(init_data, init_data + init_data_length); |
| - session_created_cb_.Run(session_id, web_session_id_string); |
| - session_message_cb_.Run(session_id, message, std::string()); |
| - return true; |
| + promise->resolve(web_session_id); |
| + promise.reset(); |
| + |
| + session_message_cb_.Run(web_session_id, message, std::string()); |
| } |
| -void AesDecryptor::LoadSession(uint32 session_id, |
| - const std::string& web_session_id) { |
| +void AesDecryptor::LoadSession(const std::string& web_session_id, |
| + scoped_ptr<MediaKeysSessionPromise> promise) { |
| // TODO(xhwang): Change this to NOTREACHED() when blink checks for key systems |
| // that do not support loadSession. See http://crbug.com/342481 |
| - session_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0); |
| + promise->reject("NotSupportedError", 0, "LoadSession() is not implemented."); |
| + promise.reset(); |
| } |
| -void AesDecryptor::UpdateSession(uint32 session_id, |
| +void AesDecryptor::UpdateSession(const std::string& web_session_id, |
| const uint8* response, |
| - int response_length) { |
| + int response_length, |
| + scoped_ptr<MediaKeysSessionPromise> promise) { |
| CHECK(response); |
| CHECK_GT(response_length, 0); |
| - DCHECK(valid_sessions_.find(session_id) != valid_sessions_.end()); |
| + |
| + if (valid_sessions_.find(web_session_id) == valid_sessions_.end()) { |
| + promise->reject("InvalidStateError", 0, "Session does not exist."); |
| + promise.reset(); |
|
xhwang
2014/05/05 20:46:42
The |promise| will go out of scope automatically,
jrummell
2014/05/08 23:37:45
Done.
|
| + return; |
| + } |
| std::string key_string(reinterpret_cast<const char*>(response), |
| response_length); |
| + |
| KeyIdAndKeyPairs keys; |
| if (!ExtractKeysFromJWKSet(key_string, &keys)) { |
| - session_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0); |
| + promise->reject( |
| + "EncodingError", 0, "response is not a valid JSON Web Key Set."); |
| + promise.reset(); |
| return; |
| } |
| // Make sure that at least one key was extracted. |
| if (keys.empty()) { |
| - session_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0); |
| + promise->reject("SyntaxError", 0, "response does not contain any keys."); |
| + promise.reset(); |
| return; |
| } |
| @@ -283,11 +292,13 @@ void AesDecryptor::UpdateSession(uint32 session_id, |
| if (it->second.length() != |
| static_cast<size_t>(DecryptConfig::kDecryptionKeySize)) { |
| DVLOG(1) << "Invalid key length: " << key_string.length(); |
| - session_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0); |
| + promise->reject("SyntaxError", 0, "Invalid key length."); |
| + promise.reset(); |
| return; |
| } |
| - if (!AddDecryptionKey(session_id, it->first, it->second)) { |
| - session_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0); |
| + if (!AddDecryptionKey(web_session_id, it->first, it->second)) { |
| + promise->reject("InvalidModificationError", 0, "Unable to add key."); |
| + promise.reset(); |
| return; |
| } |
| } |
| @@ -302,17 +313,25 @@ void AesDecryptor::UpdateSession(uint32 session_id, |
| new_video_key_cb_.Run(); |
| } |
| - session_ready_cb_.Run(session_id); |
| + promise->resolve(); |
| + promise.reset(); |
| } |
| -void AesDecryptor::ReleaseSession(uint32 session_id) { |
| +void AesDecryptor::ReleaseSession(const std::string& web_session_id, |
| + scoped_ptr<MediaKeysSessionPromise> promise) { |
| // Validate that this is a reference to an active session and then forget it. |
| - std::set<uint32>::iterator it = valid_sessions_.find(session_id); |
| - DCHECK(it != valid_sessions_.end()); |
| + std::set<std::string>::iterator it = valid_sessions_.find(web_session_id); |
| + if (it == valid_sessions_.end()) { |
| + promise->reject("InvalidStateError", 0, "Session does not exist."); |
| + promise.reset(); |
| + return; |
| + } |
| + |
| valid_sessions_.erase(it); |
| - DeleteKeysForSession(session_id); |
| - session_closed_cb_.Run(session_id); |
| + DeleteKeysForSession(web_session_id); |
| + promise->resolve(); |
| + promise.reset(); |
| } |
| Decryptor* AesDecryptor::GetDecryptor() { |
| @@ -404,7 +423,7 @@ void AesDecryptor::DeinitializeDecoder(StreamType stream_type) { |
| NOTREACHED() << "AesDecryptor does not support audio/video decoding"; |
| } |
| -bool AesDecryptor::AddDecryptionKey(const uint32 session_id, |
| +bool AesDecryptor::AddDecryptionKey(const std::string& web_session_id, |
| const std::string& key_id, |
| const std::string& key_string) { |
| scoped_ptr<DecryptionKey> decryption_key(new DecryptionKey(key_string)); |
| @@ -421,14 +440,14 @@ bool AesDecryptor::AddDecryptionKey(const uint32 session_id, |
| base::AutoLock auto_lock(key_map_lock_); |
| KeyIdToSessionKeysMap::iterator key_id_entry = key_map_.find(key_id); |
| if (key_id_entry != key_map_.end()) { |
| - key_id_entry->second->Insert(session_id, decryption_key.Pass()); |
| + key_id_entry->second->Insert(web_session_id, decryption_key.Pass()); |
| return true; |
| } |
| // |key_id| not found, so need to create new entry. |
| scoped_ptr<SessionIdDecryptionKeyMap> inner_map( |
| new SessionIdDecryptionKeyMap()); |
| - inner_map->Insert(session_id, decryption_key.Pass()); |
| + inner_map->Insert(web_session_id, decryption_key.Pass()); |
| key_map_.add(key_id, inner_map.Pass()); |
| return true; |
| } |
| @@ -444,14 +463,15 @@ AesDecryptor::DecryptionKey* AesDecryptor::GetKey( |
| return key_id_found->second->LatestDecryptionKey(); |
| } |
| -void AesDecryptor::DeleteKeysForSession(const uint32 session_id) { |
| +void AesDecryptor::DeleteKeysForSession(const std::string& web_session_id) { |
| base::AutoLock auto_lock(key_map_lock_); |
| - // Remove all keys associated with |session_id|. Since the data is optimized |
| - // for access in GetKey(), we need to look at each entry in |key_map_|. |
| + // Remove all keys associated with |web_session_id|. Since the data is |
| + // optimized for access in GetKey(), we need to look at each entry in |
| + // |key_map_|. |
| KeyIdToSessionKeysMap::iterator it = key_map_.begin(); |
| while (it != key_map_.end()) { |
| - it->second->Erase(session_id); |
| + it->second->Erase(web_session_id); |
| if (it->second->Empty()) { |
| // Need to get rid of the entry for this key_id. This will mess up the |
| // iterator, so we need to increment it first. |