summaryrefslogtreecommitdiffstats
path: root/media/cdm
diff options
context:
space:
mode:
Diffstat (limited to 'media/cdm')
-rw-r--r--media/cdm/aes_decryptor.cc69
-rw-r--r--media/cdm/aes_decryptor.h19
-rw-r--r--media/cdm/aes_decryptor_unittest.cc58
-rw-r--r--media/cdm/ppapi/external_clear_key/clear_key_cdm.cc43
-rw-r--r--media/cdm/ppapi/external_clear_key/clear_key_cdm.h4
5 files changed, 141 insertions, 52 deletions
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc
index b83c9b1..23f41d7 100644
--- a/media/cdm/aes_decryptor.cc
+++ b/media/cdm/aes_decryptor.cc
@@ -224,17 +224,27 @@ static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input,
}
AesDecryptor::AesDecryptor(const SessionMessageCB& session_message_cb,
- const SessionClosedCB& session_closed_cb)
+ const SessionClosedCB& session_closed_cb,
+ const SessionKeysChangeCB& session_keys_change_cb)
: session_message_cb_(session_message_cb),
- session_closed_cb_(session_closed_cb) {
+ session_closed_cb_(session_closed_cb),
+ session_keys_change_cb_(session_keys_change_cb) {
DCHECK(!session_message_cb_.is_null());
DCHECK(!session_closed_cb_.is_null());
+ DCHECK(!session_keys_change_cb_.is_null());
}
AesDecryptor::~AesDecryptor() {
key_map_.clear();
}
+void AesDecryptor::SetServerCertificate(const uint8* certificate_data,
+ int certificate_data_length,
+ scoped_ptr<SimpleCdmPromise> promise) {
+ promise->reject(
+ NOT_SUPPORTED_ERROR, 0, "SetServerCertificate() is not supported.");
+}
+
void AesDecryptor::CreateSession(const std::string& init_data_type,
const uint8* init_data,
int init_data_length,
@@ -318,6 +328,43 @@ void AesDecryptor::UpdateSession(const std::string& web_session_id,
}
promise->resolve();
+
+ // Assume that at least 1 new key has been successfully added and thus
+ // sending true.
+ session_keys_change_cb_.Run(web_session_id, true);
+}
+
+void AesDecryptor::CloseSession(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<std::string>::iterator it = valid_sessions_.find(web_session_id);
+ DCHECK(it != valid_sessions_.end());
+
+ valid_sessions_.erase(it);
+
+ // Close the session.
+ DeleteKeysForSession(web_session_id);
+ promise->resolve();
+ session_closed_cb_.Run(web_session_id);
+}
+
+void AesDecryptor::RemoveSession(const std::string& web_session_id,
+ scoped_ptr<SimpleCdmPromise> promise) {
+ // AesDecryptor doesn't keep any persistent data, so this should be
+ // NOT_REACHED().
+ // TODO(jrummell): Make sure persistent session types are rejected.
+ // http://crbug.com/384152.
+ //
+ // However, v0.1b calls to CancelKeyRequest() will call this, so close the
+ // session, if it exists.
+ // TODO(jrummell): Remove the close() call when prefixed EME is removed.
+ // http://crbug.com/249976.
+ if (valid_sessions_.find(web_session_id) != valid_sessions_.end()) {
+ CloseSession(web_session_id, promise.Pass());
+ return;
+ }
+
+ promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist.");
}
void AesDecryptor::GetUsableKeyIds(const std::string& web_session_id,
@@ -337,24 +384,6 @@ void AesDecryptor::GetUsableKeyIds(const std::string& web_session_id,
promise->resolve(keyids);
}
-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<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);
-
- // Close the session.
- DeleteKeysForSession(web_session_id);
- promise->resolve();
- session_closed_cb_.Run(web_session_id);
-}
-
Decryptor* AesDecryptor::GetDecryptor() {
return this;
}
diff --git a/media/cdm/aes_decryptor.h b/media/cdm/aes_decryptor.h
index dc08bb3..98a79dd 100644
--- a/media/cdm/aes_decryptor.h
+++ b/media/cdm/aes_decryptor.h
@@ -28,10 +28,15 @@ namespace media {
class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor {
public:
AesDecryptor(const SessionMessageCB& session_message_cb,
- const SessionClosedCB& session_closed_cb);
+ const SessionClosedCB& session_closed_cb,
+ const SessionKeysChangeCB& session_keys_change_cb);
virtual ~AesDecryptor();
// MediaKeys implementation.
+ virtual void SetServerCertificate(
+ const uint8* certificate_data,
+ int certificate_data_length,
+ scoped_ptr<SimpleCdmPromise> promise) OVERRIDE;
virtual void CreateSession(const std::string& init_data_type,
const uint8* init_data,
int init_data_length,
@@ -43,8 +48,12 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor {
const uint8* response,
int response_length,
scoped_ptr<SimpleCdmPromise> promise) OVERRIDE;
- virtual void ReleaseSession(const std::string& web_session_id,
- scoped_ptr<SimpleCdmPromise> promise) OVERRIDE;
+ virtual void CloseSession(const std::string& web_session_id,
+ scoped_ptr<SimpleCdmPromise> promise) OVERRIDE;
+ virtual void RemoveSession(const std::string& web_session_id,
+ scoped_ptr<SimpleCdmPromise> promise) OVERRIDE;
+ virtual void GetUsableKeyIds(const std::string& web_session_id,
+ scoped_ptr<KeyIdsPromise> promise) OVERRIDE;
virtual Decryptor* GetDecryptor() OVERRIDE;
// Decryptor implementation.
@@ -67,9 +76,6 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor {
virtual void ResetDecoder(StreamType stream_type) OVERRIDE;
virtual void DeinitializeDecoder(StreamType stream_type) OVERRIDE;
- void GetUsableKeyIds(const std::string& web_session_id,
- scoped_ptr<KeyIdsPromise> promise);
-
private:
// TODO(fgalligan): Remove this and change KeyMap to use crypto::SymmetricKey
// as there are no decryptors that are performing an integrity check.
@@ -120,6 +126,7 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor {
// Callbacks for firing session events.
SessionMessageCB session_message_cb_;
SessionClosedCB session_closed_cb_;
+ SessionKeysChangeCB session_keys_change_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
diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc
index a40867e7..de52d69 100644
--- a/media/cdm/aes_decryptor_unittest.cc
+++ b/media/cdm/aes_decryptor_unittest.cc
@@ -211,6 +211,8 @@ class AesDecryptorTest : public testing::Test {
: decryptor_(base::Bind(&AesDecryptorTest::OnSessionMessage,
base::Unretained(this)),
base::Bind(&AesDecryptorTest::OnSessionClosed,
+ base::Unretained(this)),
+ base::Bind(&AesDecryptorTest::OnSessionKeysChange,
base::Unretained(this))),
decrypt_cb_(base::Bind(&AesDecryptorTest::BufferDecrypted,
base::Unretained(this))),
@@ -307,23 +309,38 @@ class AesDecryptorTest : public testing::Test {
return web_session_id_;
}
- // Releases the session specified by |session_id|.
- void ReleaseSession(const std::string& session_id) {
+ // Closes the session specified by |session_id|.
+ void CloseSession(const std::string& session_id) {
EXPECT_CALL(*this, OnSessionClosed(session_id));
- decryptor_.ReleaseSession(session_id, CreatePromise(RESOLVED));
+ decryptor_.CloseSession(session_id, CreatePromise(RESOLVED));
+ }
+
+ // Removes the session specified by |session_id|. This should simply do a
+ // CloseSession().
+ // TODO(jrummell): Clean this up when the prefixed API is removed.
+ // http://crbug.com/249976.
+ void RemoveSession(const std::string& session_id) {
+ EXPECT_CALL(*this, OnSessionClosed(session_id));
+ decryptor_.RemoveSession(session_id, CreatePromise(RESOLVED));
}
// Updates the session specified by |session_id| with |key|. |result|
// tests that the update succeeds or generates an error.
void UpdateSessionAndExpect(std::string session_id,
const std::string& key,
- PromiseResult result) {
+ PromiseResult expected_result) {
DCHECK(!key.empty());
+ if (expected_result == RESOLVED) {
+ EXPECT_CALL(*this, OnSessionKeysChange(session_id, true));
+ } else {
+ EXPECT_CALL(*this, OnSessionKeysChange(_, _)).Times(0);
+ }
+
decryptor_.UpdateSession(session_id,
reinterpret_cast<const uint8*>(key.c_str()),
key.length(),
- CreatePromise(result));
+ CreatePromise(expected_result));
}
void GetUsableKeyIdsAndExpect(const std::string& session_id,
@@ -406,6 +423,9 @@ class AesDecryptorTest : public testing::Test {
void(const std::string& web_session_id,
const std::vector<uint8>& message,
const GURL& destination_url));
+ MOCK_METHOD2(OnSessionKeysChange,
+ void(const std::string& web_session_id,
+ bool has_additional_usable_key));
MOCK_METHOD1(OnSessionClosed, void(const std::string& web_session_id));
AesDecryptor decryptor_;
@@ -647,7 +667,21 @@ TEST_F(AesDecryptorTest, SubsampleCypherBytesOnly) {
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS);
}
-TEST_F(AesDecryptorTest, ReleaseSession) {
+TEST_F(AesDecryptorTest, CloseSession) {
+ 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, RESOLVED);
+ ASSERT_NO_FATAL_FAILURE(
+ DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
+
+ CloseSession(session_id);
+}
+
+TEST_F(AesDecryptorTest, RemoveSession) {
+ // TODO(jrummell): Clean this up when the prefixed API is removed.
+ // http://crbug.com/249976.
std::string session_id = CreateSession(key_id_);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
@@ -656,10 +690,10 @@ TEST_F(AesDecryptorTest, ReleaseSession) {
ASSERT_NO_FATAL_FAILURE(
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
- ReleaseSession(session_id);
+ RemoveSession(session_id);
}
-TEST_F(AesDecryptorTest, NoKeyAfterReleaseSession) {
+TEST_F(AesDecryptorTest, NoKeyAfterCloseSession) {
std::string session_id = CreateSession(key_id_);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
@@ -668,7 +702,7 @@ TEST_F(AesDecryptorTest, NoKeyAfterReleaseSession) {
ASSERT_NO_FATAL_FAILURE(
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
- ReleaseSession(session_id);
+ CloseSession(session_id);
ASSERT_NO_FATAL_FAILURE(
DecryptAndExpect(encrypted_buffer, original_data_, NO_KEY));
}
@@ -692,7 +726,7 @@ TEST_F(AesDecryptorTest, LatestKeyUsed) {
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
}
-TEST_F(AesDecryptorTest, LatestKeyUsedAfterReleaseSession) {
+TEST_F(AesDecryptorTest, LatestKeyUsedAfterCloseSession) {
std::string session_id1 = CreateSession(key_id_);
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
@@ -709,7 +743,7 @@ TEST_F(AesDecryptorTest, LatestKeyUsedAfterReleaseSession) {
DecryptAndExpect(encrypted_buffer, original_data_, DATA_MISMATCH));
// Close second session, should revert to original key.
- ReleaseSession(session_id2);
+ CloseSession(session_id2);
ASSERT_NO_FATAL_FAILURE(
DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
}
@@ -841,7 +875,7 @@ TEST_F(AesDecryptorTest, JWKKey) {
" ]"
"}";
UpdateSessionAndExpect(session_id, kJwksWithEmptyKeyId, REJECTED);
- ReleaseSession(session_id);
+ CloseSession(session_id);
}
TEST_F(AesDecryptorTest, GetKeyIds) {
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 e06f41b..a49b6c2 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
@@ -220,8 +220,10 @@ namespace media {
ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host, const std::string& key_system)
: decryptor_(
- base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)),
- base::Bind(&ClearKeyCdm::OnSessionClosed, base::Unretained(this))),
+ base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)),
+ base::Bind(&ClearKeyCdm::OnSessionClosed, base::Unretained(this)),
+ base::Bind(&ClearKeyCdm::OnSessionKeysChange,
+ base::Unretained(this))),
host_(host),
key_system_(key_system),
timer_delay_ms_(kInitialTimerDelayMs),
@@ -327,13 +329,11 @@ void ClearKeyCdm::CloseSession(uint32 promise_id,
std::string web_session_str(web_session_id, web_session_id_length);
scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
- base::Bind(&ClearKeyCdm::OnSessionReleased,
- base::Unretained(this),
- promise_id,
- web_session_str),
+ base::Bind(
+ &ClearKeyCdm::OnPromiseResolved, base::Unretained(this), promise_id),
base::Bind(
&ClearKeyCdm::OnPromiseFailed, base::Unretained(this), promise_id)));
- decryptor_.ReleaseSession(web_session_str, promise.Pass());
+ decryptor_.CloseSession(web_session_str, promise.Pass());
}
void ClearKeyCdm::RemoveSession(uint32 promise_id,
@@ -345,8 +345,19 @@ void ClearKeyCdm::RemoveSession(uint32 promise_id,
std::string(kLoadableWebSessionId) ==
std::string(web_session_id, web_session_id_length);
if (is_persistent_session) {
- host_->OnResolvePromise(promise_id);
+ std::string web_session_str(web_session_id, web_session_id_length);
+
+ scoped_ptr<media::SimpleCdmPromise> promise(
+ new media::SimpleCdmPromise(base::Bind(&ClearKeyCdm::OnPromiseResolved,
+ base::Unretained(this),
+ promise_id),
+ base::Bind(&ClearKeyCdm::OnPromiseFailed,
+ base::Unretained(this),
+ promise_id)));
+ decryptor_.RemoveSession(web_session_str, promise.Pass());
} else {
+ // TODO(jrummell): This should be a DCHECK once blink does the proper
+ // checks.
std::string message("Not supported for non-persistent sessions.");
host_->OnRejectPromise(promise_id,
cdm::kInvalidAccessError,
@@ -683,6 +694,13 @@ void ClearKeyCdm::OnSessionMessage(const std::string& web_session_id,
destination_url.spec().size());
}
+void ClearKeyCdm::OnSessionKeysChange(const std::string& web_session_id,
+ bool has_additional_usable_key) {
+ host_->OnSessionUsableKeysChange(web_session_id.data(),
+ web_session_id.length(),
+ has_additional_usable_key);
+}
+
void ClearKeyCdm::OnSessionClosed(const std::string& web_session_id) {
host_->OnSessionClosed(web_session_id.data(), web_session_id.length());
}
@@ -733,11 +751,6 @@ void ClearKeyCdm::OnSessionUpdated(uint32 promise_id,
host_->OnResolvePromise(promise_id);
}
-void ClearKeyCdm::OnSessionReleased(uint32 promise_id,
- const std::string& web_session_id) {
- host_->OnResolvePromise(promise_id);
-}
-
void ClearKeyCdm::OnUsableKeyIdsObtained(uint32 promise_id,
const KeyIdsVector& key_ids) {
scoped_ptr<cdm::BinaryData[]> result(new cdm::BinaryData[key_ids.size()]);
@@ -748,6 +761,10 @@ void ClearKeyCdm::OnUsableKeyIdsObtained(uint32 promise_id,
host_->OnResolveKeyIdsPromise(promise_id, result.get(), key_ids.size());
}
+void ClearKeyCdm::OnPromiseResolved(uint32 promise_id) {
+ host_->OnResolvePromise(promise_id);
+}
+
void ClearKeyCdm::OnPromiseFailed(uint32 promise_id,
MediaKeys::Exception exception_code,
uint32 system_code,
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 c491cd7..19d41f8 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
@@ -92,6 +92,8 @@ class ClearKeyCdm : public ClearKeyCdmInterface {
void OnSessionMessage(const std::string& web_session_id,
const std::vector<uint8>& message,
const GURL& destination_url);
+ void OnSessionKeysChange(const std::string& web_session_id,
+ bool has_additional_usable_key);
void OnSessionClosed(const std::string& web_session_id);
// Handle the success/failure of a promise. These methods are responsible for
@@ -99,8 +101,8 @@ class ClearKeyCdm : public ClearKeyCdmInterface {
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 OnUsableKeyIdsObtained(uint32 promise_id, const KeyIdsVector& key_ids);
+ void OnPromiseResolved(uint32 promise_id);
void OnPromiseFailed(uint32 promise_id,
MediaKeys::Exception exception_code,
uint32 system_code,