summaryrefslogtreecommitdiffstats
path: root/media/cdm
diff options
context:
space:
mode:
Diffstat (limited to 'media/cdm')
-rw-r--r--media/cdm/aes_decryptor.cc140
-rw-r--r--media/cdm/aes_decryptor.h39
-rw-r--r--media/cdm/aes_decryptor_unittest.cc277
-rw-r--r--media/cdm/ppapi/cdm_adapter.cc345
-rw-r--r--media/cdm/ppapi/cdm_adapter.h108
-rw-r--r--media/cdm/ppapi/cdm_wrapper.h198
-rw-r--r--media/cdm/ppapi/external_clear_key/clear_key_cdm.cc259
-rw-r--r--media/cdm/ppapi/external_clear_key/clear_key_cdm.h59
-rw-r--r--media/cdm/ppapi/external_clear_key/clear_key_cdm_common.h2
-rw-r--r--media/cdm/ppapi/supported_cdm_versions.h6
10 files changed, 1019 insertions, 414 deletions
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc
index 51661fd..9416707 100644
--- a/media/cdm/aes_decryptor.cc
+++ b/media/cdm/aes_decryptor.cc
@@ -13,6 +13,7 @@
#include "crypto/encryptor.h"
#include "crypto/symmetric_key.h"
#include "media/base/audio_decoder_config.h"
+#include "media/base/cdm_promise.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
#include "media/base/video_decoder_config.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,70 @@ 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<NewSessionCdmPromise> 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.
+ // TODO(jrummell): Validate |init_data_type| and |session_type|.
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, GURL());
- return true;
+ promise->resolve(web_session_id);
+
+ session_message_cb_.Run(web_session_id, message, GURL());
}
-void AesDecryptor::LoadSession(uint32 session_id,
- const std::string& web_session_id) {
+void AesDecryptor::LoadSession(const std::string& web_session_id,
+ scoped_ptr<NewSessionCdmPromise> 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(NOT_SUPPORTED_ERROR, 0, "LoadSession() is not supported.");
}
-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<SimpleCdmPromise> promise) {
CHECK(response);
CHECK_GT(response_length, 0);
- DCHECK(valid_sessions_.find(session_id) != valid_sessions_.end());
+
+ // TODO(jrummell): Convert back to a DCHECK once prefixed EME is removed.
+ if (valid_sessions_.find(web_session_id) == valid_sessions_.end()) {
+ promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist.");
+ 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(
+ INVALID_ACCESS_ERROR, 0, "response is not a valid JSON Web Key Set.");
return;
}
// Make sure that at least one key was extracted.
if (keys.empty()) {
- session_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0);
+ promise->reject(
+ INVALID_ACCESS_ERROR, 0, "response does not contain any keys.");
return;
}
@@ -283,11 +290,11 @@ 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(INVALID_ACCESS_ERROR, 0, "Invalid key length.");
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(INVALID_ACCESS_ERROR, 0, "Unable to add key.");
return;
}
}
@@ -302,17 +309,24 @@ void AesDecryptor::UpdateSession(uint32 session_id,
new_video_key_cb_.Run();
}
- session_ready_cb_.Run(session_id);
+ promise->resolve();
}
-void AesDecryptor::ReleaseSession(uint32 session_id) {
+void AesDecryptor::ReleaseSession(const std::string& web_session_id,
+ scoped_ptr<SimpleCdmPromise> 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);
+ // TODO(jrummell): Convert back to a DCHECK once prefixed EME is removed.
+ if (it == valid_sessions_.end()) {
+ promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist.");
+ return;
+ }
+
valid_sessions_.erase(it);
- DeleteKeysForSession(session_id);
- session_closed_cb_.Run(session_id);
+ // Close the session.
+ DeleteKeysForSession(web_session_id);
+ promise->resolve();
}
Decryptor* AesDecryptor::GetDecryptor() {
@@ -404,15 +418,10 @@ 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));
- if (!decryption_key) {
- DVLOG(1) << "Could not create key.";
- return false;
- }
-
if (!decryption_key->Init()) {
DVLOG(1) << "Could not initialize decryption key.";
return false;
@@ -421,14 +430,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 +453,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.
diff --git a/media/cdm/aes_decryptor.h b/media/cdm/aes_decryptor.h
index e2462ca..ab7c980 100644
--- a/media/cdm/aes_decryptor.h
+++ b/media/cdm/aes_decryptor.h
@@ -27,24 +27,23 @@ namespace media {
// encryption must be CTR with a key size of 128bits.
class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor {
public:
- 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);
+ explicit AesDecryptor(const SessionMessageCB& session_message_cb);
virtual ~AesDecryptor();
// MediaKeys implementation.
- virtual bool CreateSession(uint32 session_id,
- const std::string& content_type,
+ virtual void CreateSession(const std::string& init_data_type,
const uint8* init_data,
- int init_data_length) OVERRIDE;
- virtual void LoadSession(uint32 session_id,
- const std::string& web_session_id) OVERRIDE;
- virtual void UpdateSession(uint32 session_id,
+ int init_data_length,
+ SessionType session_type,
+ scoped_ptr<NewSessionCdmPromise> promise) OVERRIDE;
+ virtual void LoadSession(const std::string& web_session_id,
+ scoped_ptr<NewSessionCdmPromise> promise) OVERRIDE;
+ virtual void UpdateSession(const std::string& web_session_id,
const uint8* response,
- int response_length) OVERRIDE;
- virtual void ReleaseSession(uint32 session_id) OVERRIDE;
+ int response_length,
+ scoped_ptr<SimpleCdmPromise> promise) OVERRIDE;
+ virtual void ReleaseSession(const std::string& web_session_id,
+ scoped_ptr<SimpleCdmPromise> promise) OVERRIDE;
virtual Decryptor* GetDecryptor() OVERRIDE;
// Decryptor implementation.
@@ -103,7 +102,7 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor {
// Creates a DecryptionKey using |key_string| and associates it with |key_id|.
// Returns true if successful.
- bool AddDecryptionKey(const uint32 session_id,
+ bool AddDecryptionKey(const std::string& web_session_id,
const std::string& key_id,
const std::string& key_string);
@@ -111,15 +110,11 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor {
// the key. Returns NULL if no key is associated with |key_id|.
DecryptionKey* GetKey(const std::string& key_id) const;
- // Deletes all keys associated with |session_id|.
- void DeleteKeysForSession(const uint32 session_id);
+ // Deletes all keys associated with |web_session_id|.
+ void DeleteKeysForSession(const std::string& web_session_id);
// Callbacks for firing session events.
- SessionCreatedCB session_created_cb_;
SessionMessageCB session_message_cb_;
- SessionReadyCB session_ready_cb_;
- SessionClosedCB session_closed_cb_;
- SessionErrorCB session_error_cb_;
// Since only Decrypt() is called off the renderer thread, we only need to
// protect |key_map_|, the only member variable that is shared between
@@ -127,8 +122,8 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor {
KeyIdToSessionKeysMap key_map_; // Protected by |key_map_lock_|.
mutable base::Lock key_map_lock_; // Protects the |key_map_|.
- // Keeps track of current valid session IDs.
- std::set<uint32> valid_sessions_;
+ // Keeps track of current valid sessions.
+ std::set<std::string> valid_sessions_;
// Make web session ID unique per renderer by making it static. Web session
// IDs seen by the app will be "1", "2", etc.
diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc
index 4ab4fec..8452527 100644
--- a/media/cdm/aes_decryptor_unittest.cc
+++ b/media/cdm/aes_decryptor_unittest.cc
@@ -7,6 +7,7 @@
#include "base/basictypes.h"
#include "base/bind.h"
+#include "media/base/cdm_promise.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
#include "media/base/mock_filters.h"
@@ -22,6 +23,7 @@ using ::testing::SaveArg;
using ::testing::StrNe;
MATCHER(IsEmpty, "") { return arg.empty(); }
+MATCHER(IsNotEmpty, "") { return !arg.empty(); }
class GURL;
@@ -193,18 +195,12 @@ static scoped_refptr<DecoderBuffer> CreateEncryptedBuffer(
return encrypted_buffer;
}
+enum PromiseResult { RESOLVED, REJECTED };
+
class AesDecryptorTest : public testing::Test {
public:
AesDecryptorTest()
- : decryptor_(base::Bind(&AesDecryptorTest::OnSessionCreated,
- base::Unretained(this)),
- base::Bind(&AesDecryptorTest::OnSessionMessage,
- base::Unretained(this)),
- base::Bind(&AesDecryptorTest::OnSessionReady,
- base::Unretained(this)),
- base::Bind(&AesDecryptorTest::OnSessionClosed,
- base::Unretained(this)),
- base::Bind(&AesDecryptorTest::OnSessionError,
+ : decryptor_(base::Bind(&AesDecryptorTest::OnSessionMessage,
base::Unretained(this))),
decrypt_cb_(base::Bind(&AesDecryptorTest::BufferDecrypted,
base::Unretained(this))),
@@ -218,52 +214,79 @@ class AesDecryptorTest : public testing::Test {
iv_(kIv, kIv + arraysize(kIv)),
normal_subsample_entries_(
kSubsampleEntriesNormal,
- kSubsampleEntriesNormal + arraysize(kSubsampleEntriesNormal)),
- next_session_id_(1) {
+ kSubsampleEntriesNormal + arraysize(kSubsampleEntriesNormal)) {
}
protected:
+ void OnResolveWithSession(PromiseResult expected,
+ const std::string& web_session_id) {
+ EXPECT_EQ(expected, RESOLVED);
+ EXPECT_GT(web_session_id.length(), 0ul);
+ web_session_id_ = web_session_id;
+ }
+
+ void OnResolve(PromiseResult expected) {
+ EXPECT_EQ(expected, RESOLVED);
+ }
+
+ void OnReject(PromiseResult expected,
+ MediaKeys::Exception exception_code,
+ uint32 system_code,
+ const std::string& error_message) {
+ EXPECT_EQ(expected, REJECTED);
+ }
+
+ scoped_ptr<SimpleCdmPromise> CreatePromise(PromiseResult expected) {
+ scoped_ptr<SimpleCdmPromise> promise(new SimpleCdmPromise(
+ base::Bind(
+ &AesDecryptorTest::OnResolve, base::Unretained(this), expected),
+ base::Bind(
+ &AesDecryptorTest::OnReject, base::Unretained(this), expected)));
+ return promise.Pass();
+ }
+
+ scoped_ptr<NewSessionCdmPromise> CreateSessionPromise(
+ PromiseResult expected) {
+ scoped_ptr<NewSessionCdmPromise> promise(new NewSessionCdmPromise(
+ base::Bind(&AesDecryptorTest::OnResolveWithSession,
+ base::Unretained(this),
+ expected),
+ base::Bind(
+ &AesDecryptorTest::OnReject, base::Unretained(this), expected)));
+ return promise.Pass();
+ }
+
// Creates a new session using |key_id|. Returns the session ID.
- uint32 CreateSession(const std::vector<uint8>& key_id) {
+ std::string CreateSession(const std::vector<uint8>& key_id) {
DCHECK(!key_id.empty());
- uint32 session_id = next_session_id_++;
- EXPECT_CALL(*this, OnSessionCreated(session_id, StrNe(std::string())));
- EXPECT_CALL(*this, OnSessionMessage(session_id, key_id, GURL::EmptyGURL()));
- EXPECT_TRUE(decryptor_.CreateSession(
- session_id, std::string(), &key_id[0], key_id.size()));
- return session_id;
+ EXPECT_CALL(*this,
+ OnSessionMessage(IsNotEmpty(), key_id, GURL::EmptyGURL()));
+ decryptor_.CreateSession(std::string(),
+ &key_id[0],
+ key_id.size(),
+ MediaKeys::TEMPORARY_SESSION,
+ CreateSessionPromise(RESOLVED));
+ // This expects the promise to be called synchronously, which is the case
+ // for AesDecryptor.
+ return web_session_id_;
}
// Releases the session specified by |session_id|.
- void ReleaseSession(uint32 session_id) {
- EXPECT_CALL(*this, OnSessionClosed(session_id));
- decryptor_.ReleaseSession(session_id);
+ void ReleaseSession(const std::string& session_id) {
+ decryptor_.ReleaseSession(session_id, CreatePromise(RESOLVED));
}
- enum UpdateSessionExpectation {
- SESSION_READY,
- SESSION_ERROR
- };
-
// Updates the session specified by |session_id| with |key|. |result|
// tests that the update succeeds or generates an error.
- void UpdateSessionAndExpect(uint32 session_id,
+ void UpdateSessionAndExpect(std::string session_id,
const std::string& key,
- UpdateSessionExpectation result) {
+ PromiseResult result) {
DCHECK(!key.empty());
- switch (result) {
- case SESSION_READY:
- EXPECT_CALL(*this, OnSessionReady(session_id));
- break;
- case SESSION_ERROR:
- EXPECT_CALL(*this,
- OnSessionError(session_id, MediaKeys::kUnknownError, 0));
- break;
- }
-
- decryptor_.UpdateSession(
- session_id, reinterpret_cast<const uint8*>(key.c_str()), key.length());
+ decryptor_.UpdateSession(session_id,
+ reinterpret_cast<const uint8*>(key.c_str()),
+ key.length(),
+ CreatePromise(result));
}
MOCK_METHOD2(BufferDecrypted, void(Decryptor::Status,
@@ -325,21 +348,14 @@ class AesDecryptorTest : public testing::Test {
}
}
- MOCK_METHOD2(OnSessionCreated,
- void(uint32 session_id, const std::string& web_session_id));
MOCK_METHOD3(OnSessionMessage,
- void(uint32 session_id,
+ void(const std::string& web_session_id,
const std::vector<uint8>& message,
const GURL& destination_url));
- MOCK_METHOD1(OnSessionReady, void(uint32 session_id));
- MOCK_METHOD1(OnSessionClosed, void(uint32 session_id));
- MOCK_METHOD3(OnSessionError,
- void(uint32 session_id,
- MediaKeys::KeyError,
- uint32 system_code));
AesDecryptor decryptor_;
AesDecryptor::DecryptCB decrypt_cb_;
+ std::string web_session_id_;
// Constants for testing.
const std::vector<uint8> original_data_;
@@ -349,42 +365,47 @@ class AesDecryptorTest : public testing::Test {
const std::vector<uint8> iv_;
const std::vector<SubsampleEntry> normal_subsample_entries_;
const std::vector<SubsampleEntry> no_subsample_entries_;
-
- // Generate new session ID every time
- uint32 next_session_id_;
};
TEST_F(AesDecryptorTest, CreateSessionWithNullInitData) {
- uint32 session_id = 8;
EXPECT_CALL(*this,
- OnSessionMessage(session_id, IsEmpty(), GURL::EmptyGURL()));
- EXPECT_CALL(*this, OnSessionCreated(session_id, StrNe(std::string())));
- EXPECT_TRUE(decryptor_.CreateSession(session_id, std::string(), NULL, 0));
+ OnSessionMessage(IsNotEmpty(), IsEmpty(), GURL::EmptyGURL()));
+ decryptor_.CreateSession(std::string(),
+ NULL,
+ 0,
+ MediaKeys::TEMPORARY_SESSION,
+ CreateSessionPromise(RESOLVED));
}
TEST_F(AesDecryptorTest, MultipleCreateSession) {
- uint32 session_id1 = 10;
EXPECT_CALL(*this,
- OnSessionMessage(session_id1, IsEmpty(), GURL::EmptyGURL()));
- EXPECT_CALL(*this, OnSessionCreated(session_id1, StrNe(std::string())));
- EXPECT_TRUE(decryptor_.CreateSession(session_id1, std::string(), NULL, 0));
+ OnSessionMessage(IsNotEmpty(), IsEmpty(), GURL::EmptyGURL()));
+ decryptor_.CreateSession(std::string(),
+ NULL,
+ 0,
+ MediaKeys::TEMPORARY_SESSION,
+ CreateSessionPromise(RESOLVED));
- uint32 session_id2 = 11;
EXPECT_CALL(*this,
- OnSessionMessage(session_id2, IsEmpty(), GURL::EmptyGURL()));
- EXPECT_CALL(*this, OnSessionCreated(session_id2, StrNe(std::string())));
- EXPECT_TRUE(decryptor_.CreateSession(session_id2, std::string(), NULL, 0));
+ OnSessionMessage(IsNotEmpty(), IsEmpty(), GURL::EmptyGURL()));
+ decryptor_.CreateSession(std::string(),
+ NULL,
+ 0,
+ MediaKeys::TEMPORARY_SESSION,
+ CreateSessionPromise(RESOLVED));
- uint32 session_id3 = 23;
EXPECT_CALL(*this,
- OnSessionMessage(session_id3, IsEmpty(), GURL::EmptyGURL()));
- EXPECT_CALL(*this, OnSessionCreated(session_id3, StrNe(std::string())));
- EXPECT_TRUE(decryptor_.CreateSession(session_id3, std::string(), NULL, 0));
+ OnSessionMessage(IsNotEmpty(), IsEmpty(), GURL::EmptyGURL()));
+ decryptor_.CreateSession(std::string(),
+ NULL,
+ 0,
+ MediaKeys::TEMPORARY_SESSION,
+ CreateSessionPromise(RESOLVED));
}
TEST_F(AesDecryptorTest, NormalDecryption) {
- uint32 session_id = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id, kKeyAsJWK, SESSION_READY);
+ std::string session_id = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS);
@@ -398,8 +419,8 @@ TEST_F(AesDecryptorTest, UnencryptedFrame) {
}
TEST_F(AesDecryptorTest, WrongKey) {
- uint32 session_id = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id, kWrongKeyAsJWK, SESSION_READY);
+ std::string session_id = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id, kWrongKeyAsJWK, RESOLVED);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
DecryptAndExpect(encrypted_buffer, original_data_, DATA_MISMATCH);
@@ -413,33 +434,33 @@ TEST_F(AesDecryptorTest, NoKey) {
}
TEST_F(AesDecryptorTest, KeyReplacement) {
- uint32 session_id = CreateSession(key_id_);
+ std::string session_id = CreateSession(key_id_);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
- UpdateSessionAndExpect(session_id, kWrongKeyAsJWK, SESSION_READY);
+ UpdateSessionAndExpect(session_id, kWrongKeyAsJWK, RESOLVED);
ASSERT_NO_FATAL_FAILURE(DecryptAndExpect(
encrypted_buffer, original_data_, DATA_MISMATCH));
- UpdateSessionAndExpect(session_id, kKeyAsJWK, SESSION_READY);
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
ASSERT_NO_FATAL_FAILURE(
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
}
TEST_F(AesDecryptorTest, WrongSizedKey) {
- uint32 session_id = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id, kWrongSizedKeyAsJWK, SESSION_ERROR);
+ std::string session_id = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id, kWrongSizedKeyAsJWK, REJECTED);
}
TEST_F(AesDecryptorTest, MultipleKeysAndFrames) {
- uint32 session_id = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id, kKeyAsJWK, SESSION_READY);
+ std::string session_id = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
ASSERT_NO_FATAL_FAILURE(
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
- UpdateSessionAndExpect(session_id, kKey2AsJWK, SESSION_READY);
+ UpdateSessionAndExpect(session_id, kKey2AsJWK, RESOLVED);
// The first key is still available after we added a second key.
ASSERT_NO_FATAL_FAILURE(
@@ -460,8 +481,8 @@ TEST_F(AesDecryptorTest, MultipleKeysAndFrames) {
}
TEST_F(AesDecryptorTest, CorruptedIv) {
- uint32 session_id = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id, kKeyAsJWK, SESSION_READY);
+ std::string session_id = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
std::vector<uint8> bad_iv = iv_;
bad_iv[1]++;
@@ -473,8 +494,8 @@ TEST_F(AesDecryptorTest, CorruptedIv) {
}
TEST_F(AesDecryptorTest, CorruptedData) {
- uint32 session_id = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id, kKeyAsJWK, SESSION_READY);
+ std::string session_id = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
std::vector<uint8> bad_data = encrypted_data_;
bad_data[1]++;
@@ -485,16 +506,16 @@ TEST_F(AesDecryptorTest, CorruptedData) {
}
TEST_F(AesDecryptorTest, EncryptedAsUnencryptedFailure) {
- uint32 session_id = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id, kKeyAsJWK, SESSION_READY);
+ std::string session_id = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, std::vector<uint8>(), no_subsample_entries_);
DecryptAndExpect(encrypted_buffer, original_data_, DATA_MISMATCH);
}
TEST_F(AesDecryptorTest, SubsampleDecryption) {
- uint32 session_id = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id, kKeyAsJWK, SESSION_READY);
+ std::string session_id = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
subsample_encrypted_data_, key_id_, iv_, normal_subsample_entries_);
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS);
@@ -504,16 +525,16 @@ TEST_F(AesDecryptorTest, SubsampleDecryption) {
// expect to encounter this in the wild, but since the DecryptConfig doesn't
// disallow such a configuration, it should be covered.
TEST_F(AesDecryptorTest, SubsampleDecryptionWithOffset) {
- uint32 session_id = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id, kKeyAsJWK, SESSION_READY);
+ std::string session_id = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
subsample_encrypted_data_, key_id_, iv_, normal_subsample_entries_);
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS);
}
TEST_F(AesDecryptorTest, SubsampleWrongSize) {
- uint32 session_id = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id, kKeyAsJWK, SESSION_READY);
+ std::string session_id = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
std::vector<SubsampleEntry> subsample_entries_wrong_size(
kSubsampleEntriesWrongSize,
@@ -525,8 +546,8 @@ TEST_F(AesDecryptorTest, SubsampleWrongSize) {
}
TEST_F(AesDecryptorTest, SubsampleInvalidTotalSize) {
- uint32 session_id = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id, kKeyAsJWK, SESSION_READY);
+ std::string session_id = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
std::vector<SubsampleEntry> subsample_entries_invalid_total_size(
kSubsampleEntriesInvalidTotalSize,
@@ -541,8 +562,8 @@ TEST_F(AesDecryptorTest, SubsampleInvalidTotalSize) {
// No cypher bytes in any of the subsamples.
TEST_F(AesDecryptorTest, SubsampleClearBytesOnly) {
- uint32 session_id = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id, kKeyAsJWK, SESSION_READY);
+ std::string session_id = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
std::vector<SubsampleEntry> clear_only_subsample_entries(
kSubsampleEntriesClearOnly,
@@ -555,8 +576,8 @@ TEST_F(AesDecryptorTest, SubsampleClearBytesOnly) {
// No clear bytes in any of the subsamples.
TEST_F(AesDecryptorTest, SubsampleCypherBytesOnly) {
- uint32 session_id = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id, kKeyAsJWK, SESSION_READY);
+ std::string session_id = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
std::vector<SubsampleEntry> cypher_only_subsample_entries(
kSubsampleEntriesCypherOnly,
@@ -568,11 +589,11 @@ TEST_F(AesDecryptorTest, SubsampleCypherBytesOnly) {
}
TEST_F(AesDecryptorTest, ReleaseSession) {
- uint32 session_id = CreateSession(key_id_);
+ std::string session_id = CreateSession(key_id_);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
- UpdateSessionAndExpect(session_id, kKeyAsJWK, SESSION_READY);
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
ASSERT_NO_FATAL_FAILURE(
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
@@ -580,11 +601,11 @@ TEST_F(AesDecryptorTest, ReleaseSession) {
}
TEST_F(AesDecryptorTest, NoKeyAfterReleaseSession) {
- uint32 session_id = CreateSession(key_id_);
+ std::string session_id = CreateSession(key_id_);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
- UpdateSessionAndExpect(session_id, kKeyAsJWK, SESSION_READY);
+ UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
ASSERT_NO_FATAL_FAILURE(
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
@@ -594,18 +615,18 @@ TEST_F(AesDecryptorTest, NoKeyAfterReleaseSession) {
}
TEST_F(AesDecryptorTest, LatestKeyUsed) {
- uint32 session_id1 = CreateSession(key_id_);
+ std::string session_id1 = CreateSession(key_id_);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
// Add alternate key, buffer should not be decoded properly.
- UpdateSessionAndExpect(session_id1, kKeyAlternateAsJWK, SESSION_READY);
+ UpdateSessionAndExpect(session_id1, kKeyAlternateAsJWK, RESOLVED);
ASSERT_NO_FATAL_FAILURE(
DecryptAndExpect(encrypted_buffer, original_data_, DATA_MISMATCH));
// Create a second session with a correct key value for key_id_.
- uint32 session_id2 = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id2, kKeyAsJWK, SESSION_READY);
+ std::string session_id2 = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id2, kKeyAsJWK, RESOLVED);
// Should be able to decode with latest key.
ASSERT_NO_FATAL_FAILURE(
@@ -613,16 +634,16 @@ TEST_F(AesDecryptorTest, LatestKeyUsed) {
}
TEST_F(AesDecryptorTest, LatestKeyUsedAfterReleaseSession) {
- uint32 session_id1 = CreateSession(key_id_);
+ std::string session_id1 = CreateSession(key_id_);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
- UpdateSessionAndExpect(session_id1, kKeyAsJWK, SESSION_READY);
+ UpdateSessionAndExpect(session_id1, kKeyAsJWK, RESOLVED);
ASSERT_NO_FATAL_FAILURE(
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
// Create a second session with a different key value for key_id_.
- uint32 session_id2 = CreateSession(key_id_);
- UpdateSessionAndExpect(session_id2, kKeyAlternateAsJWK, SESSION_READY);
+ std::string session_id2 = CreateSession(key_id_);
+ UpdateSessionAndExpect(session_id2, kKeyAlternateAsJWK, RESOLVED);
// Should not be able to decode with new key.
ASSERT_NO_FATAL_FAILURE(
@@ -635,7 +656,7 @@ TEST_F(AesDecryptorTest, LatestKeyUsedAfterReleaseSession) {
}
TEST_F(AesDecryptorTest, JWKKey) {
- uint32 session_id = CreateSession(key_id_);
+ std::string session_id = CreateSession(key_id_);
// Try a simple JWK key (i.e. not in a set)
const std::string kJwkSimple =
@@ -644,7 +665,7 @@ TEST_F(AesDecryptorTest, JWKKey) {
" \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
" \"k\": \"FBUWFxgZGhscHR4fICEiIw\""
"}";
- UpdateSessionAndExpect(session_id, kJwkSimple, SESSION_ERROR);
+ UpdateSessionAndExpect(session_id, kJwkSimple, REJECTED);
// Try a key list with multiple entries.
const std::string kJwksMultipleEntries =
@@ -662,40 +683,38 @@ TEST_F(AesDecryptorTest, JWKKey) {
" }"
" ]"
"}";
- UpdateSessionAndExpect(session_id, kJwksMultipleEntries, SESSION_READY);
+ UpdateSessionAndExpect(session_id, kJwksMultipleEntries, RESOLVED);
// Try a key with no spaces and some \n plus additional fields.
const std::string kJwksNoSpaces =
"\n\n{\"something\":1,\"keys\":[{\n\n\"kty\":\"oct\",\"alg\":\"A128KW\","
"\"kid\":\"AAECAwQFBgcICQoLDA0ODxAREhM\",\"k\":\"GawgguFyGrWKav7AX4VKUg"
"\",\"foo\":\"bar\"}]}\n\n";
- UpdateSessionAndExpect(session_id, kJwksNoSpaces, SESSION_READY);
+ UpdateSessionAndExpect(session_id, kJwksNoSpaces, RESOLVED);
// Try some non-ASCII characters.
- UpdateSessionAndExpect(session_id,
- "This is not ASCII due to \xff\xfe\xfd in it.",
- SESSION_ERROR);
+ UpdateSessionAndExpect(
+ session_id, "This is not ASCII due to \xff\xfe\xfd in it.", REJECTED);
// Try a badly formatted key. Assume that the JSON parser is fully tested,
// so we won't try a lot of combinations. However, need a test to ensure
// that the code doesn't crash if invalid JSON received.
- UpdateSessionAndExpect(session_id, "This is not a JSON key.", SESSION_ERROR);
+ UpdateSessionAndExpect(session_id, "This is not a JSON key.", REJECTED);
// Try passing some valid JSON that is not a dictionary at the top level.
- UpdateSessionAndExpect(session_id, "40", SESSION_ERROR);
+ UpdateSessionAndExpect(session_id, "40", REJECTED);
// Try an empty dictionary.
- UpdateSessionAndExpect(session_id, "{ }", SESSION_ERROR);
+ UpdateSessionAndExpect(session_id, "{ }", REJECTED);
// Try an empty 'keys' dictionary.
- UpdateSessionAndExpect(session_id, "{ \"keys\": [] }", SESSION_ERROR);
+ UpdateSessionAndExpect(session_id, "{ \"keys\": [] }", REJECTED);
// Try with 'keys' not a dictionary.
- UpdateSessionAndExpect(session_id, "{ \"keys\":\"1\" }", SESSION_ERROR);
+ UpdateSessionAndExpect(session_id, "{ \"keys\":\"1\" }", REJECTED);
// Try with 'keys' a list of integers.
- UpdateSessionAndExpect(
- session_id, "{ \"keys\": [ 1, 2, 3 ] }", SESSION_ERROR);
+ UpdateSessionAndExpect(session_id, "{ \"keys\": [ 1, 2, 3 ] }", REJECTED);
// Try padding(=) at end of 'k' base64 string.
const std::string kJwksWithPaddedKey =
@@ -708,7 +727,7 @@ TEST_F(AesDecryptorTest, JWKKey) {
" }"
" ]"
"}";
- UpdateSessionAndExpect(session_id, kJwksWithPaddedKey, SESSION_ERROR);
+ UpdateSessionAndExpect(session_id, kJwksWithPaddedKey, REJECTED);
// Try padding(=) at end of 'kid' base64 string.
const std::string kJwksWithPaddedKeyId =
@@ -721,7 +740,7 @@ TEST_F(AesDecryptorTest, JWKKey) {
" }"
" ]"
"}";
- UpdateSessionAndExpect(session_id, kJwksWithPaddedKeyId, SESSION_ERROR);
+ UpdateSessionAndExpect(session_id, kJwksWithPaddedKeyId, REJECTED);
// Try a key with invalid base64 encoding.
const std::string kJwksWithInvalidBase64 =
@@ -734,7 +753,7 @@ TEST_F(AesDecryptorTest, JWKKey) {
" }"
" ]"
"}";
- UpdateSessionAndExpect(session_id, kJwksWithInvalidBase64, SESSION_ERROR);
+ UpdateSessionAndExpect(session_id, kJwksWithInvalidBase64, REJECTED);
// Try a 3-byte 'kid' where no base64 padding is required.
// |kJwksMultipleEntries| above has 2 'kid's that require 1 and 2 padding
@@ -749,7 +768,7 @@ TEST_F(AesDecryptorTest, JWKKey) {
" }"
" ]"
"}";
- UpdateSessionAndExpect(session_id, kJwksWithNoPadding, SESSION_READY);
+ UpdateSessionAndExpect(session_id, kJwksWithNoPadding, RESOLVED);
// Empty key id.
const std::string kJwksWithEmptyKeyId =
@@ -762,7 +781,7 @@ TEST_F(AesDecryptorTest, JWKKey) {
" }"
" ]"
"}";
- UpdateSessionAndExpect(session_id, kJwksWithEmptyKeyId, SESSION_ERROR);
+ UpdateSessionAndExpect(session_id, kJwksWithEmptyKeyId, REJECTED);
ReleaseSession(session_id);
}
diff --git a/media/cdm/ppapi/cdm_adapter.cc b/media/cdm/ppapi/cdm_adapter.cc
index 3c4d698..10feef7 100644
--- a/media/cdm/ppapi/cdm_adapter.cc
+++ b/media/cdm/ppapi/cdm_adapter.cc
@@ -211,6 +211,40 @@ cdm::StreamType PpDecryptorStreamTypeToCdmStreamType(
return cdm::kStreamTypeVideo;
}
+cdm::SessionType PpSessionTypeToCdmSessionType(PP_SessionType session_type) {
+ switch (session_type) {
+ case PP_SESSIONTYPE_TEMPORARY:
+ return cdm::kTemporary;
+ case PP_SESSIONTYPE_PERSISTENT:
+ return cdm::kPersistent;
+ default:
+ PP_NOTREACHED();
+ return cdm::kTemporary;
+ }
+}
+
+PP_CdmExceptionCode CdmExceptionTypeToPpCdmExceptionType(cdm::Error error) {
+ switch (error) {
+ case cdm::kNotSupportedError:
+ return PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR;
+ case cdm::kInvalidStateError:
+ return PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR;
+ case cdm::kInvalidAccessError:
+ return PP_CDMEXCEPTIONCODE_INVALIDACCESSERROR;
+ case cdm::kQuotaExceededError:
+ return PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR;
+ case cdm::kUnknownError:
+ return PP_CDMEXCEPTIONCODE_UNKNOWNERROR;
+ case cdm::kClientError:
+ return PP_CDMEXCEPTIONCODE_CLIENTERROR;
+ case cdm::kOutputError:
+ return PP_CDMEXCEPTIONCODE_OUTPUTERROR;
+ default:
+ PP_NOTREACHED();
+ return PP_CDMEXCEPTIONCODE_UNKNOWNERROR;
+ }
+}
+
} // namespace
namespace media {
@@ -290,49 +324,70 @@ void CdmAdapter::Initialize(const std::string& key_system) {
key_system_ = key_system;
}
-void CdmAdapter::CreateSession(uint32_t session_id,
- const std::string& content_type,
- pp::VarArrayBuffer init_data) {
+void CdmAdapter::CreateSession(uint32_t promise_id,
+ const std::string& init_data_type,
+ pp::VarArrayBuffer init_data,
+ PP_SessionType session_type) {
// Initialize() doesn't report an error, so CreateSession() can be called
// even if Initialize() failed.
+ // TODO(jrummell): Remove this code when prefixed EME gets removed.
+ // TODO(jrummell): Verify that Initialize() failing does not resolve the
+ // MediaKeys.create() promise.
if (!cdm_) {
- OnSessionError(session_id, cdm::kUnknownError, 0);
+ RejectPromise(promise_id,
+ cdm::kInvalidStateError,
+ 0,
+ "CDM has not been initialized.");
return;
}
- cdm_->CreateSession(session_id,
- content_type.data(),
- content_type.size(),
+ cdm_->CreateSession(promise_id,
+ init_data_type.data(),
+ init_data_type.size(),
static_cast<const uint8_t*>(init_data.Map()),
- init_data.ByteLength());
+ init_data.ByteLength(),
+ PpSessionTypeToCdmSessionType(session_type));
}
-void CdmAdapter::LoadSession(uint32_t session_id,
+void CdmAdapter::LoadSession(uint32_t promise_id,
const std::string& web_session_id) {
// Initialize() doesn't report an error, so LoadSession() can be called
// even if Initialize() failed.
+ // TODO(jrummell): Remove this code when prefixed EME gets removed.
+ // TODO(jrummell): Verify that Initialize() failing does not resolve the
+ // MediaKeys.create() promise.
if (!cdm_) {
- OnSessionError(session_id, cdm::kUnknownError, 0);
+ RejectPromise(promise_id,
+ cdm::kInvalidStateError,
+ 0,
+ "CDM has not been initialized.");
return;
}
- cdm_->LoadSession(session_id, web_session_id.data(), web_session_id.size());
+ cdm_->LoadSession(promise_id, web_session_id.data(), web_session_id.size());
}
-void CdmAdapter::UpdateSession(uint32_t session_id,
+void CdmAdapter::UpdateSession(uint32_t promise_id,
+ const std::string& web_session_id,
pp::VarArrayBuffer response) {
const uint8_t* response_ptr = static_cast<const uint8_t*>(response.Map());
const uint32_t response_size = response.ByteLength();
- if (!response_ptr || response_size <= 0) {
- OnSessionError(session_id, cdm::kUnknownError, 0);
- return;
- }
- cdm_->UpdateSession(session_id, response_ptr, response_size);
+ PP_DCHECK(!web_session_id.empty());
+ PP_DCHECK(response_ptr);
+ PP_DCHECK(response_size > 0);
+
+ cdm_->UpdateSession(promise_id,
+ web_session_id.data(),
+ web_session_id.length(),
+ response_ptr,
+ response_size);
}
-void CdmAdapter::ReleaseSession(uint32_t session_id) {
- cdm_->ReleaseSession(session_id);
+void CdmAdapter::ReleaseSession(uint32_t promise_id,
+ const std::string& web_session_id) {
+ cdm_->ReleaseSession(
+ promise_id, web_session_id.data(), web_session_id.length());
}
// Note: In the following decryption/decoding related functions, errors are NOT
@@ -529,61 +584,219 @@ void CdmAdapter::TimerExpired(int32_t result, void* context) {
cdm_->TimerExpired(context);
}
+// cdm::Host_4 methods
+
double CdmAdapter::GetCurrentWallTimeInSeconds() {
- return pp::Module::Get()->core()->GetTime();
+ return GetCurrentTime();
}
void CdmAdapter::OnSessionCreated(uint32_t session_id,
const char* web_session_id,
uint32_t web_session_id_length) {
+ uint32_t promise_id = cdm_->LookupPromiseId(session_id);
+ cdm_->AssignWebSessionId(session_id, web_session_id, web_session_id_length);
+ OnResolveNewSessionPromise(promise_id, web_session_id, web_session_id_length);
+}
+
+void CdmAdapter::OnSessionMessage(uint32_t session_id,
+ const char* message,
+ uint32_t message_length,
+ const char* destination_url,
+ uint32_t destination_url_length) {
+ std::string web_session_id = cdm_->LookupWebSessionId(session_id);
+ OnSessionMessage(web_session_id.data(),
+ web_session_id.length(),
+ message,
+ message_length,
+ destination_url,
+ destination_url_length);
+}
+
+void CdmAdapter::OnSessionReady(uint32_t session_id) {
+ uint32_t promise_id = cdm_->LookupPromiseId(session_id);
+ if (promise_id) {
+ OnResolvePromise(promise_id);
+ } else {
+ std::string web_session_id = cdm_->LookupWebSessionId(session_id);
+ OnSessionReady(web_session_id.data(), web_session_id.length());
+ }
+}
+
+void CdmAdapter::OnSessionClosed(uint32_t session_id) {
+ uint32_t promise_id = cdm_->LookupPromiseId(session_id);
+ std::string web_session_id = cdm_->LookupWebSessionId(session_id);
+ cdm_->DropWebSessionId(web_session_id);
+ if (promise_id) {
+ OnResolvePromise(promise_id);
+ } else {
+ OnSessionClosed(web_session_id.data(), web_session_id.length());
+ }
+}
+
+void CdmAdapter::OnSessionError(uint32_t session_id,
+ cdm::MediaKeyError error_code,
+ uint32_t system_code) {
+ uint32_t promise_id = cdm_->LookupPromiseId(session_id);
+
+ // Existing cdm::MediaKeyError don't map to DOM error names. Convert them
+ // into non-standard names so that the prefixed API can extract them.
+ // TODO(jrummell): Remove this conversion and the inverse when CDM4 is gone.
+ cdm::Error error;
+ switch (error_code) {
+ case cdm::kPrefixedClientError:
+ error = cdm::kClientError;
+ break;
+ case cdm::kPrefixedOutputError:
+ error = cdm::kOutputError;
+ break;
+ case cdm::kPrefixedUnknownError:
+ default:
+ error = cdm::kUnknownError;
+ break;
+ }
+
+ if (promise_id) {
+ RejectPromise(promise_id, error, system_code, std::string());
+ } else {
+ std::string web_session_id = cdm_->LookupWebSessionId(session_id);
+ OnSessionError(web_session_id.data(),
+ web_session_id.length(),
+ error,
+ system_code,
+ NULL,
+ 0);
+ }
+}
+
+// cdm::Host_5 methods
+
+cdm::Time CdmAdapter::GetCurrentTime() {
+ return pp::Module::Get()->core()->GetTime();
+}
+
+void CdmAdapter::OnResolvePromise(uint32_t promise_id) {
PostOnMain(callback_factory_.NewCallback(
- &CdmAdapter::SendSessionCreatedInternal,
- session_id,
+ &CdmAdapter::SendPromiseResolvedInternal, promise_id));
+}
+
+void CdmAdapter::OnResolveNewSessionPromise(uint32_t promise_id,
+ const char* web_session_id,
+ uint32_t web_session_id_length) {
+ PostOnMain(callback_factory_.NewCallback(
+ &CdmAdapter::SendPromiseResolvedWithSessionInternal,
+ promise_id,
std::string(web_session_id, web_session_id_length)));
}
-void CdmAdapter::OnSessionMessage(uint32_t session_id,
+void CdmAdapter::OnRejectPromise(uint32_t promise_id,
+ cdm::Error error,
+ uint32_t system_code,
+ const char* error_message,
+ uint32_t error_message_length) {
+ RejectPromise(promise_id,
+ error,
+ system_code,
+ std::string(error_message, error_message_length));
+}
+
+void CdmAdapter::RejectPromise(uint32_t promise_id,
+ cdm::Error error,
+ uint32_t system_code,
+ const std::string& error_message) {
+ PostOnMain(callback_factory_.NewCallback(
+ &CdmAdapter::SendPromiseRejectedInternal,
+ promise_id,
+ SessionError(error, system_code, error_message)));
+}
+
+void CdmAdapter::OnSessionMessage(const char* web_session_id,
+ uint32_t web_session_id_length,
const char* message,
uint32_t message_length,
const char* destination_url,
uint32_t destination_url_length) {
PostOnMain(callback_factory_.NewCallback(
&CdmAdapter::SendSessionMessageInternal,
- session_id,
+ std::string(web_session_id, web_session_id_length),
std::vector<uint8>(message, message + message_length),
std::string(destination_url, destination_url_length)));
}
-void CdmAdapter::OnSessionReady(uint32_t session_id) {
+void CdmAdapter::OnSessionKeysChange(const char* web_session_id,
+ uint32_t web_session_id_length,
+ bool has_additional_usable_key) {
+ // TODO(jrummell): Implement this event in subsequent CL
+ // (http://crbug.com/370251).
+ PP_NOTREACHED();
+}
+
+void CdmAdapter::OnExpirationChange(const char* web_session_id,
+ uint32_t web_session_id_length,
+ cdm::Time new_expiry_time) {
+ // TODO(jrummell): Implement this event in subsequent CL
+ // (http://crbug.com/370251).
+ PP_NOTREACHED();
+}
+
+void CdmAdapter::OnSessionReady(const char* web_session_id,
+ uint32_t web_session_id_length) {
PostOnMain(callback_factory_.NewCallback(
- &CdmAdapter::SendSessionReadyInternal, session_id));
+ &CdmAdapter::SendSessionReadyInternal,
+ std::string(web_session_id, web_session_id_length)));
}
-void CdmAdapter::OnSessionClosed(uint32_t session_id) {
+void CdmAdapter::OnSessionClosed(const char* web_session_id,
+ uint32_t web_session_id_length) {
PostOnMain(callback_factory_.NewCallback(
- &CdmAdapter::SendSessionClosedInternal, session_id));
+ &CdmAdapter::SendSessionClosedInternal,
+ std::string(web_session_id, web_session_id_length)));
}
-void CdmAdapter::OnSessionError(uint32_t session_id,
- cdm::MediaKeyError error_code,
- uint32_t system_code) {
+void CdmAdapter::OnSessionError(const char* web_session_id,
+ uint32_t web_session_id_length,
+ cdm::Error error,
+ uint32_t system_code,
+ const char* error_message,
+ uint32_t error_message_length) {
PostOnMain(callback_factory_.NewCallback(
&CdmAdapter::SendSessionErrorInternal,
- session_id,
- error_code,
- system_code));
+ std::string(web_session_id, web_session_id_length),
+ SessionError(error,
+ system_code,
+ std::string(error_message, error_message_length))));
}
-void CdmAdapter::SendSessionCreatedInternal(int32_t result,
- uint32_t session_id,
- const std::string& web_session_id) {
+// Helpers to pass the event to Pepper.
+
+void CdmAdapter::SendPromiseResolvedInternal(int32_t result,
+ uint32_t promise_id) {
PP_DCHECK(result == PP_OK);
- pp::ContentDecryptor_Private::SessionCreated(session_id, web_session_id);
+ pp::ContentDecryptor_Private::PromiseResolved(promise_id);
+}
+
+void CdmAdapter::SendPromiseResolvedWithSessionInternal(
+ int32_t result,
+ uint32_t promise_id,
+ const std::string& web_session_id) {
+ PP_DCHECK(result == PP_OK);
+ pp::ContentDecryptor_Private::PromiseResolvedWithSession(promise_id,
+ web_session_id);
+}
+
+void CdmAdapter::SendPromiseRejectedInternal(int32_t result,
+ uint32_t promise_id,
+ const SessionError& error) {
+ PP_DCHECK(result == PP_OK);
+ pp::ContentDecryptor_Private::PromiseRejected(
+ promise_id,
+ CdmExceptionTypeToPpCdmExceptionType(error.error),
+ error.system_code,
+ error.error_description);
}
void CdmAdapter::SendSessionMessageInternal(
int32_t result,
- uint32_t session_id,
+ const std::string& web_session_id,
const std::vector<uint8>& message,
const std::string& destination_url) {
PP_DCHECK(result == PP_OK);
@@ -594,27 +807,30 @@ void CdmAdapter::SendSessionMessageInternal(
}
pp::ContentDecryptor_Private::SessionMessage(
- session_id, message_array_buffer, destination_url);
+ web_session_id, message_array_buffer, destination_url);
}
-void CdmAdapter::SendSessionReadyInternal(int32_t result, uint32_t session_id) {
+void CdmAdapter::SendSessionReadyInternal(int32_t result,
+ const std::string& web_session_id) {
PP_DCHECK(result == PP_OK);
- pp::ContentDecryptor_Private::SessionReady(session_id);
+ pp::ContentDecryptor_Private::SessionReady(web_session_id);
}
void CdmAdapter::SendSessionClosedInternal(int32_t result,
- uint32_t session_id) {
+ const std::string& web_session_id) {
PP_DCHECK(result == PP_OK);
- pp::ContentDecryptor_Private::SessionClosed(session_id);
+ pp::ContentDecryptor_Private::SessionClosed(web_session_id);
}
void CdmAdapter::SendSessionErrorInternal(int32_t result,
- uint32_t session_id,
- cdm::MediaKeyError error_code,
- uint32_t system_code) {
+ const std::string& web_session_id,
+ const SessionError& error) {
PP_DCHECK(result == PP_OK);
pp::ContentDecryptor_Private::SessionError(
- session_id, error_code, system_code);
+ web_session_id,
+ CdmExceptionTypeToPpCdmExceptionType(error.error),
+ error.system_code,
+ error.error_description);
}
void CdmAdapter::DeliverBlock(int32_t result,
@@ -943,15 +1159,12 @@ void CdmAdapter::SendPlatformChallengeDone(int32_t result) {
platform_key_certificate_output_.AsString();
cdm::PlatformChallengeResponse response = {
- static_cast<uint8_t*>(signed_data_var.Map()),
- signed_data_var.ByteLength(),
-
- static_cast<uint8_t*>(signed_data_signature_var.Map()),
- signed_data_signature_var.ByteLength(),
-
- reinterpret_cast<const uint8_t*>(platform_key_certificate_string.c_str()),
- static_cast<uint32_t>(platform_key_certificate_string.length())
- };
+ static_cast<uint8_t*>(signed_data_var.Map()),
+ signed_data_var.ByteLength(),
+ static_cast<uint8_t*>(signed_data_signature_var.Map()),
+ signed_data_signature_var.ByteLength(),
+ reinterpret_cast<const uint8_t*>(platform_key_certificate_string.data()),
+ static_cast<uint32_t>(platform_key_certificate_string.length())};
cdm_->OnPlatformChallengeResponse(response);
signed_data_var.Unmap();
@@ -979,12 +1192,20 @@ void CdmAdapter::QueryOutputProtectionStatusDone(int32_t result) {
}
#endif
+CdmAdapter::SessionError::SessionError(cdm::Error error,
+ uint32_t system_code,
+ std::string error_description)
+ : error(error),
+ system_code(system_code),
+ error_description(error_description) {
+}
+
void* GetCdmHost(int host_interface_version, void* user_data) {
if (!host_interface_version || !user_data)
return NULL;
COMPILE_ASSERT(
- cdm::ContentDecryptionModule::Host::kVersion == cdm::Host_4::kVersion,
+ cdm::ContentDecryptionModule::Host::kVersion == cdm::Host_5::kVersion,
update_code_below);
// Ensure IsSupportedCdmHostVersion matches implementation of this function.
@@ -994,11 +1215,11 @@ void* GetCdmHost(int host_interface_version, void* user_data) {
PP_DCHECK(
// Future version is not supported.
- !IsSupportedCdmHostVersion(cdm::Host_4::kVersion + 1) &&
+ !IsSupportedCdmHostVersion(cdm::Host_5::kVersion + 1) &&
// Current version is supported.
- IsSupportedCdmHostVersion(cdm::Host_4::kVersion) &&
+ IsSupportedCdmHostVersion(cdm::Host_5::kVersion) &&
// Include all previous supported versions (if any) here.
- // No supported previous versions.
+ IsSupportedCdmHostVersion(cdm::Host_4::kVersion) &&
// One older than the oldest supported version is not supported.
!IsSupportedCdmHostVersion(cdm::Host_4::kVersion - 1));
PP_DCHECK(IsSupportedCdmHostVersion(host_interface_version));
@@ -1008,6 +1229,8 @@ void* GetCdmHost(int host_interface_version, void* user_data) {
switch (host_interface_version) {
case cdm::Host_4::kVersion:
return static_cast<cdm::Host_4*>(cdm_adapter);
+ case cdm::Host_5::kVersion:
+ return static_cast<cdm::Host_5*>(cdm_adapter);
default:
PP_NOTREACHED();
return NULL;
diff --git a/media/cdm/ppapi/cdm_adapter.h b/media/cdm/ppapi/cdm_adapter.h
index daedf9e..cd65b18 100644
--- a/media/cdm/ppapi/cdm_adapter.h
+++ b/media/cdm/ppapi/cdm_adapter.h
@@ -28,6 +28,11 @@
#include "ppapi/cpp/private/platform_verification.h"
#endif
+#if defined(GetCurrentTime)
+// winbase.h defines this which messes up calls to Host_5::GetCurrentTime.
+#undef GetCurrentTime
+#endif
+
namespace media {
// GetCdmHostFunc implementation.
@@ -37,7 +42,8 @@ void* GetCdmHost(int host_interface_version, void* user_data);
// Content Decryption Module (CDM).
class CdmAdapter : public pp::Instance,
public pp::ContentDecryptor_Private,
- public cdm::Host_4 {
+ public cdm::Host_4,
+ public cdm::Host_5 {
public:
CdmAdapter(PP_Instance instance, pp::Module* module);
virtual ~CdmAdapter();
@@ -51,14 +57,17 @@ class CdmAdapter : public pp::Instance,
// Note: Results of calls to these methods must be reported through the
// PPB_ContentDecryptor_Private interface.
virtual void Initialize(const std::string& key_system) OVERRIDE;
- virtual void CreateSession(uint32_t session_id,
- const std::string& content_type,
- pp::VarArrayBuffer init_data) OVERRIDE;
- virtual void LoadSession(uint32_t session_id,
+ virtual void CreateSession(uint32_t promise_id,
+ const std::string& init_data_type,
+ pp::VarArrayBuffer init_data,
+ PP_SessionType session_type) OVERRIDE;
+ virtual void LoadSession(uint32_t promise_id,
const std::string& web_session_id) OVERRIDE;
- virtual void UpdateSession(uint32_t session_id,
+ virtual void UpdateSession(uint32_t promise_id,
+ const std::string& web_session_id,
pp::VarArrayBuffer response) OVERRIDE;
- virtual void ReleaseSession(uint32_t session_id) OVERRIDE;
+ virtual void ReleaseSession(uint32_t promise_id,
+ const std::string& web_session_id) OVERRIDE;
virtual void Decrypt(
pp::Buffer_Dev encrypted_buffer,
const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE;
@@ -77,9 +86,11 @@ class CdmAdapter : public pp::Instance,
pp::Buffer_Dev encrypted_buffer,
const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE;
- // cdm::Host implementation.
+ // cdm::Host_4 and cdm::Host_5 implementation.
virtual cdm::Buffer* Allocate(uint32_t capacity) OVERRIDE;
virtual void SetTimer(int64_t delay_ms, void* context) OVERRIDE;
+
+ // cdm::Host_4 implementation.
virtual double GetCurrentWallTimeInSeconds() OVERRIDE;
virtual void OnSessionCreated(uint32_t session_id,
const char* web_session_id,
@@ -94,9 +105,47 @@ class CdmAdapter : public pp::Instance,
virtual void OnSessionError(uint32_t session_id,
cdm::MediaKeyError error_code,
uint32_t system_code) OVERRIDE;
- virtual void SendPlatformChallenge(
- const char* service_id, uint32_t service_id_length,
- const char* challenge, uint32_t challenge_length) OVERRIDE;
+
+ // cdm::Host_5 implementation.
+ virtual cdm::Time GetCurrentTime() OVERRIDE;
+ virtual void OnResolveNewSessionPromise(
+ uint32_t promise_id,
+ const char* web_session_id,
+ uint32_t web_session_id_length) OVERRIDE;
+ virtual void OnResolvePromise(uint32_t promise_id) OVERRIDE;
+ virtual void OnRejectPromise(uint32_t promise_id,
+ cdm::Error error,
+ uint32_t system_code,
+ const char* error_message,
+ uint32_t error_message_length) OVERRIDE;
+ virtual void OnSessionMessage(const char* web_session_id,
+ uint32_t web_session_id_length,
+ const char* message,
+ uint32_t message_length,
+ const char* destination_url,
+ uint32_t destination_url_length) OVERRIDE;
+ virtual void OnSessionKeysChange(const char* web_session_id,
+ uint32_t web_session_id_length,
+ bool has_additional_usable_key);
+ virtual void OnExpirationChange(const char* web_session_id,
+ uint32_t web_session_id_length,
+ cdm::Time new_expiry_time);
+ virtual void OnSessionReady(const char* web_session_id,
+ uint32_t web_session_id_length) OVERRIDE;
+ virtual void OnSessionClosed(const char* web_session_id,
+ uint32_t web_session_id_length) OVERRIDE;
+ virtual void OnSessionError(const char* web_session_id,
+ uint32_t web_session_id_length,
+ cdm::Error error,
+ uint32_t system_code,
+ const char* error_message,
+ uint32_t error_message_length) OVERRIDE;
+
+ // cdm::Host_4 and cdm::Host_5 implementation.
+ virtual void SendPlatformChallenge(const char* service_id,
+ uint32_t service_id_length,
+ const char* challenge,
+ uint32_t challenge_length) OVERRIDE;
virtual void EnableOutputProtection(
uint32_t desired_protection_mask) OVERRIDE;
virtual void QueryOutputProtectionStatus() OVERRIDE;
@@ -118,24 +167,43 @@ class CdmAdapter : public pp::Instance,
typedef linked_ptr<VideoFrameImpl> LinkedVideoFrame;
typedef linked_ptr<AudioFramesImpl> LinkedAudioFrames;
+ struct SessionError {
+ SessionError(cdm::Error error,
+ uint32_t system_code,
+ std::string error_description);
+ cdm::Error error;
+ uint32_t system_code;
+ std::string error_description;
+ };
+
bool CreateCdmInstance(const std::string& key_system);
// <code>PPB_ContentDecryptor_Private</code> dispatchers. These are passed to
// <code>callback_factory_</code> to ensure that calls into
// <code>PPP_ContentDecryptor_Private</code> are asynchronous.
- void SendSessionCreatedInternal(int32_t result,
- uint32_t session_id,
- const std::string& web_session_id);
+ void SendPromiseResolvedInternal(int32_t result, uint32_t promise_id);
+ void SendPromiseResolvedWithSessionInternal(
+ int32_t result,
+ uint32_t promise_id,
+ const std::string& web_session_id);
+ void SendPromiseRejectedInternal(int32_t result,
+ uint32_t promise_id,
+ const SessionError& error);
void SendSessionMessageInternal(int32_t result,
- uint32_t session_id,
+ const std::string& web_session_id,
const std::vector<uint8>& message,
const std::string& destination_url);
- void SendSessionReadyInternal(int32_t result, uint32_t session_id);
- void SendSessionClosedInternal(int32_t result, uint32_t session_id);
+ void SendSessionReadyInternal(int32_t result,
+ const std::string& web_session_id);
+ void SendSessionClosedInternal(int32_t result,
+ const std::string& web_session_id);
void SendSessionErrorInternal(int32_t result,
- uint32_t session_id,
- cdm::MediaKeyError error_code,
- uint32_t system_code);
+ const std::string& web_session_id,
+ const SessionError& error);
+ void RejectPromise(uint32_t promise_id,
+ cdm::Error error,
+ uint32_t system_code,
+ const std::string& error_message);
void DeliverBlock(int32_t result,
const cdm::Status& status,
diff --git a/media/cdm/ppapi/cdm_wrapper.h b/media/cdm/ppapi/cdm_wrapper.h
index cf8e88b..665b6b6 100644
--- a/media/cdm/ppapi/cdm_wrapper.h
+++ b/media/cdm/ppapi/cdm_wrapper.h
@@ -42,18 +42,23 @@ class CdmWrapper {
virtual ~CdmWrapper() {};
- virtual void CreateSession(uint32_t session_id,
- const char* content_type,
- uint32_t content_type_size,
+ virtual void CreateSession(uint32_t promise_id,
+ const char* init_data_type,
+ uint32_t init_data_type_size,
const uint8_t* init_data,
- uint32_t init_data_size) = 0;
- virtual void LoadSession(uint32_t session_id,
+ uint32_t init_data_size,
+ cdm::SessionType session_type) = 0;
+ virtual void LoadSession(uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) = 0;
- virtual void UpdateSession(uint32_t session_id,
+ virtual void UpdateSession(uint32_t promise_id,
+ const char* web_session_id,
+ uint32_t web_session_id_size,
const uint8_t* response,
uint32_t response_size) = 0;
- virtual void ReleaseSession(uint32_t session_id) = 0;
+ virtual void ReleaseSession(uint32_t promise_id,
+ const char* web_session_id,
+ uint32_t web_session_id_size) = 0;
virtual void TimerExpired(void* context) = 0;
virtual cdm::Status Decrypt(const cdm::InputBuffer& encrypted_buffer,
cdm::DecryptedBlock* decrypted_buffer) = 0;
@@ -75,6 +80,21 @@ class CdmWrapper {
uint32_t link_mask,
uint32_t output_protection_mask) = 0;
+ // Helper function for the cdm::Host_4 methods. Calls to CreateSession(),
+ // LoadSession(), UpdateSession(), and ReleaseSession() pass in promise ids,
+ // but the CDM interface needs session ids. For create and load, we need to
+ // create a new session_id to pass to the CDM. For update and release, we need
+ // to look up |web_session_id| and convert it into the existing |session_id|.
+ // Since the callbacks don't come through this interface, cdm_adapter needs to
+ // create the mapping (and delete it on release).
+ // TODO(jrummell): Remove these once Host_4 interface is removed.
+ virtual uint32_t LookupPromiseId(uint32_t session_id) = 0;
+ virtual void AssignWebSessionId(uint32_t session_id,
+ const char* web_session_id,
+ uint32_t web_session_id_size) = 0;
+ virtual std::string LookupWebSessionId(uint32_t session_id) = 0;
+ virtual void DropWebSessionId(std::string web_session_id) = 0;
+
protected:
CdmWrapper() {}
@@ -106,29 +126,42 @@ class CdmWrapperImpl : public CdmWrapper {
cdm_->Destroy();
}
- virtual void CreateSession(uint32_t session_id,
- const char* content_type,
- uint32_t content_type_size,
+ virtual void CreateSession(uint32_t promise_id,
+ const char* init_data_type,
+ uint32_t init_data_type_size,
const uint8_t* init_data,
- uint32_t init_data_size) OVERRIDE {
- cdm_->CreateSession(
- session_id, content_type, content_type_size, init_data, init_data_size);
+ uint32_t init_data_size,
+ cdm::SessionType session_type) OVERRIDE {
+ cdm_->CreateSession(promise_id,
+ init_data_type,
+ init_data_type_size,
+ init_data,
+ init_data_size,
+ session_type);
}
- virtual void LoadSession(uint32_t session_id,
+ virtual void LoadSession(uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) OVERRIDE {
- cdm_->LoadSession(session_id, web_session_id, web_session_id_size);
+ cdm_->LoadSession(promise_id, web_session_id, web_session_id_size);
}
- virtual void UpdateSession(uint32_t session_id,
+ virtual void UpdateSession(uint32_t promise_id,
+ const char* web_session_id,
+ uint32_t web_session_id_size,
const uint8_t* response,
uint32_t response_size) OVERRIDE {
- cdm_->UpdateSession(session_id, response, response_size);
+ cdm_->UpdateSession(promise_id,
+ web_session_id,
+ web_session_id_size,
+ response,
+ response_size);
}
- virtual void ReleaseSession(uint32_t session_id) OVERRIDE {
- cdm_->ReleaseSession(session_id);
+ virtual void ReleaseSession(uint32_t promise_id,
+ const char* web_session_id,
+ uint32_t web_session_id_size) OVERRIDE {
+ cdm_->ReleaseSession(promise_id, web_session_id, web_session_id_size);
}
virtual void TimerExpired(void* context) OVERRIDE {
@@ -181,22 +214,133 @@ class CdmWrapperImpl : public CdmWrapper {
cdm_->OnQueryOutputProtectionStatus(link_mask, output_protection_mask);
}
+ uint32_t CreateSessionId() {
+ return next_session_id_++;
+ }
+
+ void RegisterPromise(uint32_t session_id, uint32_t promise_id) {
+ PP_DCHECK(promise_to_session_id_map_.find(session_id) ==
+ promise_to_session_id_map_.end());
+ promise_to_session_id_map_.insert(std::make_pair(session_id, promise_id));
+ }
+
+ virtual uint32_t LookupPromiseId(uint32_t session_id) {
+ std::map<uint32_t, uint32_t>::iterator it =
+ promise_to_session_id_map_.find(session_id);
+ if (it == promise_to_session_id_map_.end())
+ return 0;
+ uint32_t promise_id = it->second;
+ promise_to_session_id_map_.erase(it);
+ return promise_id;
+ }
+
+ virtual void AssignWebSessionId(uint32_t session_id,
+ const char* web_session_id,
+ uint32_t web_session_id_size) {
+ web_session_to_session_id_map_.insert(std::make_pair(
+ std::string(web_session_id, web_session_id_size), session_id));
+ }
+
+ uint32_t LookupSessionId(std::string web_session_id) {
+ return web_session_to_session_id_map_.find(web_session_id)->second;
+ }
+
+ virtual std::string LookupWebSessionId(uint32_t session_id) {
+ std::map<std::string, uint32_t>::iterator it;
+ for (it = web_session_to_session_id_map_.begin();
+ it != web_session_to_session_id_map_.end();
+ ++it) {
+ if (it->second == session_id)
+ return it->first;
+ }
+ PP_NOTREACHED();
+ return std::string();
+ }
+
+ virtual void DropWebSessionId(std::string web_session_id) {
+ web_session_to_session_id_map_.erase(web_session_id);
+ }
+
private:
- CdmWrapperImpl(CdmInterface* cdm) : cdm_(cdm) {
+ CdmWrapperImpl(CdmInterface* cdm) : cdm_(cdm), next_session_id_(100) {
PP_DCHECK(cdm_);
}
CdmInterface* cdm_;
+ std::map<uint32_t, uint32_t> promise_to_session_id_map_;
+ uint32_t next_session_id_;
+ std::map<std::string, uint32_t> web_session_to_session_id_map_;
+
DISALLOW_COPY_AND_ASSIGN(CdmWrapperImpl);
};
+// Overrides for the cdm::Host_4 methods. Calls to CreateSession(),
+// LoadSession(), UpdateSession(), and ReleaseSession() pass in promise ids,
+// but the CDM interface needs session ids. For create and load, we need to
+// create a new session_id to pass to the CDM. For update and release, we need
+// to look up |web_session_id| and convert it into the existing |session_id|.
+// Since the callbacks don't come through this interface, cdm_adapter needs to
+// create the mapping (and delete it on release).
+// TODO(jrummell): Remove these once Host_4 interface is removed.
+
+template <>
+void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::CreateSession(
+ uint32_t promise_id,
+ const char* init_data_type,
+ uint32_t init_data_type_size,
+ const uint8_t* init_data,
+ uint32_t init_data_size,
+ cdm::SessionType session_type) {
+ uint32_t session_id = CreateSessionId();
+ RegisterPromise(session_id, promise_id);
+ cdm_->CreateSession(session_id,
+ init_data_type,
+ init_data_type_size,
+ init_data,
+ init_data_size);
+}
+
+template <>
+void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::LoadSession(
+ uint32_t promise_id,
+ const char* web_session_id,
+ uint32_t web_session_id_size) {
+ uint32_t session_id = CreateSessionId();
+ RegisterPromise(session_id, promise_id);
+ cdm_->LoadSession(session_id, web_session_id, web_session_id_size);
+}
+
+template <>
+void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::UpdateSession(
+ uint32_t promise_id,
+ const char* web_session_id,
+ uint32_t web_session_id_size,
+ const uint8_t* response,
+ uint32_t response_size) {
+ std::string web_session_str(web_session_id, web_session_id_size);
+ uint32_t session_id = LookupSessionId(web_session_str);
+ RegisterPromise(session_id, promise_id);
+ cdm_->UpdateSession(session_id, response, response_size);
+}
+
+template <>
+void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::ReleaseSession(
+ uint32_t promise_id,
+ const char* web_session_id,
+ uint32_t web_session_id_size) {
+ std::string web_session_str(web_session_id, web_session_id_size);
+ uint32_t session_id = LookupSessionId(web_session_str);
+ RegisterPromise(session_id, promise_id);
+ cdm_->ReleaseSession(session_id);
+}
+
CdmWrapper* CdmWrapper::Create(const char* key_system,
uint32_t key_system_size,
GetCdmHostFunc get_cdm_host_func,
void* user_data) {
COMPILE_ASSERT(cdm::ContentDecryptionModule::kVersion ==
- cdm::ContentDecryptionModule_4::kVersion,
+ cdm::ContentDecryptionModule_5::kVersion,
update_code_below);
// Ensure IsSupportedCdmInterfaceVersion() matches this implementation.
@@ -207,18 +351,22 @@ CdmWrapper* CdmWrapper::Create(const char* key_system,
!IsSupportedCdmInterfaceVersion(cdm::ContentDecryptionModule::kVersion +
1) &&
IsSupportedCdmInterfaceVersion(cdm::ContentDecryptionModule::kVersion) &&
- !IsSupportedCdmInterfaceVersion(cdm::ContentDecryptionModule::kVersion -
+ IsSupportedCdmInterfaceVersion(
+ cdm::ContentDecryptionModule_4::kVersion) &&
+ !IsSupportedCdmInterfaceVersion(cdm::ContentDecryptionModule_4::kVersion -
1));
// Try to create the CDM using the latest CDM interface version.
CdmWrapper* cdm_wrapper =
CdmWrapperImpl<cdm::ContentDecryptionModule>::Create(
key_system, key_system_size, get_cdm_host_func, user_data);
+ if (cdm_wrapper)
+ return cdm_wrapper;
// If |cdm_wrapper| is NULL, try to create the CDM using older supported
// versions of the CDM interface.
- // No older versions of CDM interface supported.
-
+ cdm_wrapper = CdmWrapperImpl<cdm::ContentDecryptionModule_4>::Create(
+ key_system, key_system_size, get_cdm_host_func, user_data);
return cdm_wrapper;
}
@@ -227,7 +375,7 @@ CdmWrapper* CdmWrapper::Create(const char* key_system,
// does not have.
// Also update supported_cdm_versions.h.
COMPILE_ASSERT(cdm::ContentDecryptionModule::kVersion ==
- cdm::ContentDecryptionModule_4::kVersion,
+ cdm::ContentDecryptionModule_5::kVersion,
ensure_cdm_wrapper_templates_have_old_version_support);
} // namespace media
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
index 82e3b63..b10111e 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
@@ -14,6 +14,7 @@
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/time/time.h"
+#include "media/base/cdm_promise.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
#include "media/cdm/json_web_key.h"
@@ -133,6 +134,39 @@ static std::string GetFileIOTestResultMessage(bool success) {
return message;
}
+static cdm::Error ConvertException(media::MediaKeys::Exception exception_code) {
+ switch (exception_code) {
+ case media::MediaKeys::NOT_SUPPORTED_ERROR:
+ return cdm::kNotSupportedError;
+ case media::MediaKeys::INVALID_STATE_ERROR:
+ return cdm::kInvalidStateError;
+ case media::MediaKeys::INVALID_ACCESS_ERROR:
+ return cdm::kInvalidAccessError;
+ case media::MediaKeys::QUOTA_EXCEEDED_ERROR:
+ return cdm::kQuotaExceededError;
+ case media::MediaKeys::UNKNOWN_ERROR:
+ return cdm::kUnknownError;
+ case media::MediaKeys::CLIENT_ERROR:
+ return cdm::kClientError;
+ case media::MediaKeys::OUTPUT_ERROR:
+ return cdm::kOutputError;
+ }
+ NOTIMPLEMENTED();
+ return cdm::kUnknownError;
+}
+
+static media::MediaKeys::SessionType ConvertSessionType(
+ cdm::SessionType session_type) {
+ switch (session_type) {
+ case cdm::kPersistent:
+ return media::MediaKeys::PERSISTENT_SESSION;
+ case cdm::kTemporary:
+ return media::MediaKeys::TEMPORARY_SESSION;
+ }
+ NOTIMPLEMENTED();
+ return media::MediaKeys::TEMPORARY_SESSION;
+}
+
template<typename Type>
class ScopedResetter {
public:
@@ -187,15 +221,9 @@ namespace media {
ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host, const std::string& key_system)
: decryptor_(
- base::Bind(&ClearKeyCdm::OnSessionCreated, base::Unretained(this)),
- base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)),
- base::Bind(&ClearKeyCdm::OnSessionReady, base::Unretained(this)),
- base::Bind(&ClearKeyCdm::OnSessionClosed, base::Unretained(this)),
- base::Bind(&ClearKeyCdm::OnSessionError, base::Unretained(this))),
+ base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this))),
host_(host),
key_system_(key_system),
- last_session_id_(MediaKeys::kInvalidSessionId),
- session_id_for_emulated_loadsession_(MediaKeys::kInvalidSessionId),
timer_delay_ms_(kInitialTimerDelayMs),
heartbeat_timer_set_(false) {
#if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
@@ -209,17 +237,26 @@ ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host, const std::string& key_system)
ClearKeyCdm::~ClearKeyCdm() {}
-void ClearKeyCdm::CreateSession(uint32 session_id,
- const char* type,
- uint32 type_size,
+void ClearKeyCdm::CreateSession(uint32 promise_id,
+ const char* init_data_type,
+ uint32 init_data_type_size,
const uint8* init_data,
- uint32 init_data_size) {
+ uint32 init_data_size,
+ cdm::SessionType session_type) {
DVLOG(1) << __FUNCTION__;
- decryptor_.CreateSession(
- session_id, std::string(type, type_size), init_data, init_data_size);
- // Save the latest session ID for heartbeat and file IO test messages.
- last_session_id_ = session_id;
+ scoped_ptr<media::NewSessionCdmPromise> promise(
+ new media::NewSessionCdmPromise(base::Bind(&ClearKeyCdm::OnSessionCreated,
+ base::Unretained(this),
+ promise_id),
+ base::Bind(&ClearKeyCdm::OnPromiseFailed,
+ base::Unretained(this),
+ promise_id)));
+ decryptor_.CreateSession(std::string(init_data_type, init_data_type_size),
+ init_data,
+ init_data_size,
+ ConvertSessionType(session_type),
+ promise.Pass());
if (key_system_ == kExternalClearKeyFileIOTestKeySystem)
StartFileIOTest();
@@ -228,28 +265,53 @@ void ClearKeyCdm::CreateSession(uint32 session_id,
// Loads a emulated stored session. Currently only |kLoadableWebSessionId|
// (containing a |kLoadableSessionKey| for |kLoadableSessionKeyId|) is
// supported.
-void ClearKeyCdm::LoadSession(uint32_t session_id,
+void ClearKeyCdm::LoadSession(uint32 promise_id,
const char* web_session_id,
uint32_t web_session_id_length) {
DVLOG(1) << __FUNCTION__;
if (std::string(kLoadableWebSessionId) !=
std::string(web_session_id, web_session_id_length)) {
- // TODO(xhwang): Report "NotFoundError" when we support DOMError style.
- OnSessionError(session_id, MediaKeys::kUnknownError, 0);
+ std::string message("Incorrect session id specified for LoadSession().");
+ host_->OnRejectPromise(promise_id,
+ cdm::kInvalidAccessError,
+ 0,
+ message.data(),
+ message.length());
return;
}
- session_id_for_emulated_loadsession_ = session_id;
-
- decryptor_.CreateSession(session_id, kLoadableSessionContentType, NULL, 0);
-}
-
-void ClearKeyCdm::UpdateSession(uint32 session_id,
+ scoped_ptr<media::NewSessionCdmPromise> promise(
+ new media::NewSessionCdmPromise(base::Bind(&ClearKeyCdm::OnSessionLoaded,
+ base::Unretained(this),
+ promise_id),
+ base::Bind(&ClearKeyCdm::OnPromiseFailed,
+ base::Unretained(this),
+ promise_id)));
+ decryptor_.CreateSession(std::string(kLoadableSessionContentType),
+ NULL,
+ 0,
+ MediaKeys::TEMPORARY_SESSION,
+ promise.Pass());
+}
+
+void ClearKeyCdm::UpdateSession(uint32 promise_id,
+ const char* web_session_id,
+ uint32_t web_session_id_size,
const uint8* response,
uint32 response_size) {
DVLOG(1) << __FUNCTION__;
- decryptor_.UpdateSession(session_id, response, response_size);
+ std::string web_session_str(web_session_id, web_session_id_size);
+
+ scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
+ base::Bind(&ClearKeyCdm::OnSessionUpdated,
+ base::Unretained(this),
+ promise_id,
+ web_session_str),
+ base::Bind(
+ &ClearKeyCdm::OnPromiseFailed, base::Unretained(this), promise_id)));
+ decryptor_.UpdateSession(
+ web_session_str, response, response_size, promise.Pass());
if (!heartbeat_timer_set_) {
ScheduleNextHeartBeat();
@@ -257,9 +319,27 @@ void ClearKeyCdm::UpdateSession(uint32 session_id,
}
}
-void ClearKeyCdm::ReleaseSession(uint32 session_id) {
+void ClearKeyCdm::ReleaseSession(uint32 promise_id,
+ const char* web_session_id,
+ uint32_t web_session_id_size) {
DVLOG(1) << __FUNCTION__;
- decryptor_.ReleaseSession(session_id);
+ std::string web_session_str(web_session_id, web_session_id_size);
+
+ scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
+ base::Bind(&ClearKeyCdm::OnSessionReleased,
+ base::Unretained(this),
+ promise_id,
+ web_session_str),
+ base::Bind(
+ &ClearKeyCdm::OnPromiseFailed, base::Unretained(this), promise_id)));
+ decryptor_.ReleaseSession(web_session_str, promise.Pass());
+}
+
+void ClearKeyCdm::SetServerCertificate(uint32 promise_id,
+ const uint8_t* server_certificate_data,
+ uint32_t server_certificate_data_size) {
+ // ClearKey doesn't use a server certificate.
+ host_->OnResolvePromise(promise_id);
}
void ClearKeyCdm::TimerExpired(void* context) {
@@ -281,9 +361,10 @@ void ClearKeyCdm::TimerExpired(void* context) {
// There is no service at this URL, so applications should ignore it.
const char url[] = "http://test.externalclearkey.chromium.org";
- host_->OnSessionMessage(last_session_id_,
+ host_->OnSessionMessage(last_session_id_.data(),
+ last_session_id_.length(),
heartbeat_message.data(),
- heartbeat_message.size(),
+ heartbeat_message.length(),
url,
arraysize(url) - 1);
@@ -476,7 +557,7 @@ void ClearKeyCdm::ScheduleNextHeartBeat() {
// Prepare the next heartbeat message and set timer.
std::ostringstream msg_stream;
msg_stream << kHeartBeatHeader << " from ClearKey CDM set at time "
- << host_->GetCurrentWallTimeInSeconds() << ".";
+ << host_->GetCurrentTime() << ".";
next_heartbeat_message_ = msg_stream.str();
host_->SetTimer(timer_delay_ms_, &next_heartbeat_message_[0]);
@@ -535,66 +616,102 @@ void ClearKeyCdm::LoadLoadableSession() {
sizeof(kLoadableSessionKeyId) - 1);
// TODO(xhwang): This triggers OnSessionUpdated(). For prefixed EME support,
// this is okay. Check WD EME support.
+ scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
+ base::Bind(&ClearKeyCdm::OnSessionUpdated,
+ base::Unretained(this),
+ promise_id_for_emulated_loadsession_,
+ session_id_for_emulated_loadsession_),
+ base::Bind(&ClearKeyCdm::OnPromiseFailed,
+ base::Unretained(this),
+ promise_id_for_emulated_loadsession_)));
decryptor_.UpdateSession(session_id_for_emulated_loadsession_,
reinterpret_cast<const uint8*>(jwk_set.data()),
- jwk_set.size());
+ jwk_set.size(),
+ promise.Pass());
}
-void ClearKeyCdm::OnSessionCreated(uint32 session_id,
- const std::string& web_session_id) {
- std::string new_web_session_id = web_session_id;
-
- if (session_id == session_id_for_emulated_loadsession_) {
- // Delay LoadLoadableSession() to test the case where Decrypt*() calls are
- // made before the session is fully loaded.
- const int64 kDelayToLoadSessionMs = 500;
- // Use the address of |session_id_for_emulated_loadsession_| as the timer
- // context so that we can call LoadLoadableSession() when the timer expires.
- host_->SetTimer(kDelayToLoadSessionMs,
- &session_id_for_emulated_loadsession_);
- // Defer OnSessionCreated() until the session is loaded.
- return;
- }
-
- host_->OnSessionCreated(
- session_id, web_session_id.data(), web_session_id.size());
-}
-
-void ClearKeyCdm::OnSessionMessage(uint32 session_id,
+void ClearKeyCdm::OnSessionMessage(const std::string& web_session_id,
const std::vector<uint8>& message,
const GURL& destination_url) {
DVLOG(1) << "OnSessionMessage: " << message.size();
// Ignore the message when we are waiting to update the loadable session.
- if (session_id == session_id_for_emulated_loadsession_)
+ if (web_session_id == session_id_for_emulated_loadsession_)
return;
- host_->OnSessionMessage(session_id,
+ // OnSessionMessage() only called during CreateSession(), so no promise
+ // involved (OnSessionCreated() called to resolve the CreateSession()
+ // promise).
+ host_->OnSessionMessage(web_session_id.data(),
+ web_session_id.length(),
reinterpret_cast<const char*>(message.data()),
message.size(),
destination_url.spec().data(),
destination_url.spec().size());
}
-void ClearKeyCdm::OnSessionReady(uint32 session_id) {
- if (session_id == session_id_for_emulated_loadsession_) {
- session_id_for_emulated_loadsession_ = MediaKeys::kInvalidSessionId;
- host_->OnSessionCreated(
- session_id, kLoadableWebSessionId, strlen(kLoadableWebSessionId));
+void ClearKeyCdm::OnSessionCreated(uint32 promise_id,
+ const std::string& web_session_id) {
+ // Save the latest session ID for heartbeat and file IO test messages.
+ last_session_id_ = web_session_id;
+
+ host_->OnResolveNewSessionPromise(
+ promise_id, web_session_id.data(), web_session_id.length());
+}
+
+void ClearKeyCdm::OnSessionLoaded(uint32 promise_id,
+ const std::string& web_session_id) {
+ // Save the latest session ID for heartbeat and file IO test messages.
+ last_session_id_ = web_session_id;
+
+ // |decryptor_| created some session as |web_session_id|, but going forward
+ // we need to map that to |kLoadableWebSessionId|, as that is what callers
+ // expect.
+ session_id_for_emulated_loadsession_ = web_session_id;
+
+ // Delay LoadLoadableSession() to test the case where Decrypt*() calls are
+ // made before the session is fully loaded.
+ const int64 kDelayToLoadSessionMs = 500;
+
+ // Defer resolving the promise until the session is loaded.
+ promise_id_for_emulated_loadsession_ = promise_id;
+
+ // Use the address of |session_id_for_emulated_loadsession_| as the timer
+ // context so that we can call LoadLoadableSession() when the timer expires.
+ host_->SetTimer(kDelayToLoadSessionMs, &session_id_for_emulated_loadsession_);
+}
+
+void ClearKeyCdm::OnSessionUpdated(uint32 promise_id,
+ const std::string& web_session_id) {
+ // OnSessionReady() only called as success for UpdateSession(). However,
+ // UpdateSession() also called to finish loading sessions, so handle
+ // appropriately.
+ if (web_session_id == session_id_for_emulated_loadsession_) {
+ session_id_for_emulated_loadsession_ = std::string();
+ // |promise_id| is the LoadSession() promise, so resolve appropriately.
+ host_->OnResolveNewSessionPromise(
+ promise_id, kLoadableWebSessionId, strlen(kLoadableWebSessionId));
+ host_->OnSessionReady(kLoadableWebSessionId, strlen(kLoadableWebSessionId));
+ return;
}
- host_->OnSessionReady(session_id);
+ host_->OnResolvePromise(promise_id);
}
-void ClearKeyCdm::OnSessionClosed(uint32 session_id) {
- host_->OnSessionClosed(session_id);
+void ClearKeyCdm::OnSessionReleased(uint32 promise_id,
+ const std::string& web_session_id) {
+ host_->OnResolvePromise(promise_id);
}
-void ClearKeyCdm::OnSessionError(uint32 session_id,
- media::MediaKeys::KeyError error_code,
- uint32 system_code) {
- host_->OnSessionError(
- session_id, static_cast<cdm::MediaKeyError>(error_code), system_code);
+void ClearKeyCdm::OnPromiseFailed(uint32 promise_id,
+ MediaKeys::Exception exception_code,
+ uint32 system_code,
+ const std::string& error_message) {
+ host_->OnRejectPromise(promise_id,
+ ConvertException(exception_code),
+ system_code,
+ error_message.data(),
+ error_message.length());
}
#if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
@@ -666,8 +783,12 @@ void ClearKeyCdm::StartFileIOTest() {
void ClearKeyCdm::OnFileIOTestComplete(bool success) {
DVLOG(1) << __FUNCTION__ << ": " << success;
std::string message = GetFileIOTestResultMessage(success);
- host_->OnSessionMessage(
- last_session_id_, message.data(), message.size(), NULL, 0);
+ host_->OnSessionMessage(last_session_id_.data(),
+ last_session_id_.length(),
+ message.data(),
+ message.length(),
+ NULL,
+ 0);
file_io_test_runner_.reset();
}
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
index d0ef3c7..e489c1b 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
@@ -35,17 +35,27 @@ class ClearKeyCdm : public ClearKeyCdmInterface {
virtual ~ClearKeyCdm();
// ContentDecryptionModule implementation.
- virtual void CreateSession(
- uint32 session_id,
- const char* type, uint32 type_size,
- const uint8* init_data, uint32 init_data_size) OVERRIDE;
- virtual void LoadSession(
- uint32_t session_id,
- const char* web_session_id, uint32_t web_session_id_length) OVERRIDE;
- virtual void UpdateSession(
- uint32 session_id,
- const uint8* response, uint32 response_size) OVERRIDE;
- virtual void ReleaseSession(uint32 session_id) OVERRIDE;
+ virtual void CreateSession(uint32 promise_id,
+ const char* init_data_type,
+ uint32 init_data_type_size,
+ const uint8* init_data,
+ uint32 init_data_size,
+ cdm::SessionType session_type) OVERRIDE;
+ virtual void LoadSession(uint32 promise_id,
+ const char* web_session_id,
+ uint32_t web_session_id_length) OVERRIDE;
+ virtual void UpdateSession(uint32 promise_id,
+ const char* web_session_id,
+ uint32_t web_session_id_length,
+ const uint8* response,
+ uint32 response_size) OVERRIDE;
+ virtual void ReleaseSession(uint32 promise_id,
+ const char* web_session_id,
+ uint32_t web_session_id_length) OVERRIDE;
+ virtual void SetServerCertificate(
+ uint32 promise_id,
+ const uint8_t* server_certificate_data,
+ uint32_t server_certificate_data_size) OVERRIDE;
virtual void TimerExpired(void* context) OVERRIDE;
virtual cdm::Status Decrypt(const cdm::InputBuffer& encrypted_buffer,
cdm::DecryptedBlock* decrypted_block) OVERRIDE;
@@ -73,15 +83,20 @@ class ClearKeyCdm : public ClearKeyCdmInterface {
void LoadLoadableSession();
// ContentDecryptionModule callbacks.
- void OnSessionCreated(uint32 session_id, const std::string& web_session_id);
- void OnSessionMessage(uint32 session_id,
+ void OnSessionMessage(const std::string& web_session_id,
const std::vector<uint8>& message,
const GURL& destination_url);
- void OnSessionReady(uint32 session_id);
- void OnSessionClosed(uint32 session_id);
- void OnSessionError(uint32 session_id,
- MediaKeys::KeyError error_code,
- uint32 system_code);
+
+ // Handle the success/failure of a promise. These methods are responsible for
+ // calling |host_| to resolve or reject the promise.
+ void OnSessionCreated(uint32 promise_id, const std::string& web_session_id);
+ void OnSessionLoaded(uint32 promise_id, const std::string& web_session_id);
+ void OnSessionUpdated(uint32 promise_id, const std::string& web_session_id);
+ void OnSessionReleased(uint32 promise_id, const std::string& web_session_id);
+ void OnPromiseFailed(uint32 promise_id,
+ MediaKeys::Exception exception_code,
+ uint32 system_code,
+ const std::string& error_message);
// Prepares next heartbeat message and sets a timer for it.
void ScheduleNextHeartBeat();
@@ -117,18 +132,22 @@ class ClearKeyCdm : public ClearKeyCdmInterface {
// Callback for CDM File IO test.
void OnFileIOTestComplete(bool success);
+ // Keep track of the last session created.
+ void SetSessionId(const std::string& web_session_id);
+
AesDecryptor decryptor_;
ClearKeyCdmHost* host_;
const std::string key_system_;
- uint32 last_session_id_;
+ std::string last_session_id_;
std::string next_heartbeat_message_;
// TODO(xhwang): Extract testing code from main implementation.
// See http://crbug.com/341751
- uint32 session_id_for_emulated_loadsession_;
+ std::string session_id_for_emulated_loadsession_;
+ uint32_t promise_id_for_emulated_loadsession_;
// Timer delay in milliseconds for the next host_->SetTimer() call.
int64 timer_delay_ms_;
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm_common.h b/media/cdm/ppapi/external_clear_key/clear_key_cdm_common.h
index 7c1a8c8..2bbc5b1 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm_common.h
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm_common.h
@@ -10,7 +10,7 @@
namespace media {
// Aliases for the version of the interfaces that this CDM implements.
-typedef cdm::ContentDecryptionModule_4 ClearKeyCdmInterface;
+typedef cdm::ContentDecryptionModule_5 ClearKeyCdmInterface;
typedef ClearKeyCdmInterface::Host ClearKeyCdmHost;
} // namespace media
diff --git a/media/cdm/ppapi/supported_cdm_versions.h b/media/cdm/ppapi/supported_cdm_versions.h
index d2ae5b3..8de7a8c 100644
--- a/media/cdm/ppapi/supported_cdm_versions.h
+++ b/media/cdm/ppapi/supported_cdm_versions.h
@@ -21,10 +21,11 @@ bool IsSupportedCdmModuleVersion(int version) {
bool IsSupportedCdmInterfaceVersion(int version) {
COMPILE_ASSERT(cdm::ContentDecryptionModule::kVersion ==
- cdm::ContentDecryptionModule_4::kVersion,
+ cdm::ContentDecryptionModule_5::kVersion,
update_code_below);
switch(version) {
// Supported versions in decreasing order.
+ case cdm::ContentDecryptionModule_5::kVersion:
case cdm::ContentDecryptionModule_4::kVersion:
return true;
default:
@@ -34,10 +35,11 @@ bool IsSupportedCdmInterfaceVersion(int version) {
bool IsSupportedCdmHostVersion(int version) {
COMPILE_ASSERT(cdm::ContentDecryptionModule::Host::kVersion ==
- cdm::ContentDecryptionModule_4::Host::kVersion,
+ cdm::ContentDecryptionModule_5::Host::kVersion,
update_code_below);
switch(version) {
// Supported versions in decreasing order.
+ case cdm::Host_5::kVersion:
case cdm::Host_4::kVersion:
return true;
default: