diff options
author | jrummell@chromium.org <jrummell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-30 05:24:47 +0000 |
---|---|---|
committer | jrummell@chromium.org <jrummell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-30 05:24:47 +0000 |
commit | da34aa7be7368dc1327a8129b7db0f13b24f5c2b (patch) | |
tree | 6340efd5e30735b0bf7352a79dd8e08b54366d6d /media/cdm | |
parent | a6b2aa58719366e64a7fdbde719707304a993a33 (diff) | |
download | chromium_src-da34aa7be7368dc1327a8129b7db0f13b24f5c2b.zip chromium_src-da34aa7be7368dc1327a8129b7db0f13b24f5c2b.tar.gz chromium_src-da34aa7be7368dc1327a8129b7db0f13b24f5c2b.tar.bz2 |
Add support for CDM_3.
Changes for CDM_3:
- CreateSession() replaces GenerateKeyRequest()
- UpdateSession/1 replaces AddKey/2
- ReleaseSession() replaces CancelKeyRequest()
- closed event (OnSessionClosed) added.
- callbacks renamed (SetSessionId -> OnSessionCreated, SendMessage -> OnSessionMessage, SendReady -> OnSessionReady, SendError -> OnSessionError)
Android function names still need to be updated in a separate CL.
BUG=224786
TEST=encrypted-media layout tests and browser_tests for encrypted media pass
TBR=dmichael
Review URL: https://codereview.chromium.org/81803003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@237973 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/cdm')
-rw-r--r-- | media/cdm/aes_decryptor.cc | 66 | ||||
-rw-r--r-- | media/cdm/aes_decryptor.h | 38 | ||||
-rw-r--r-- | media/cdm/aes_decryptor_unittest.cc | 110 | ||||
-rw-r--r-- | media/cdm/ppapi/cdm_adapter.cc | 169 | ||||
-rw-r--r-- | media/cdm/ppapi/cdm_adapter.h | 63 | ||||
-rw-r--r-- | media/cdm/ppapi/cdm_wrapper.h | 297 | ||||
-rw-r--r-- | media/cdm/ppapi/clear_key_cdm.cc | 81 | ||||
-rw-r--r-- | media/cdm/ppapi/clear_key_cdm.h | 34 | ||||
-rw-r--r-- | media/cdm/ppapi/clear_key_cdm_common.h | 2 | ||||
-rw-r--r-- | media/cdm/ppapi/supported_cdm_versions.h | 15 |
10 files changed, 499 insertions, 376 deletions
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc index 10f0499..ee4b987 100644 --- a/media/cdm/aes_decryptor.cc +++ b/media/cdm/aes_decryptor.cc @@ -142,23 +142,25 @@ static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input, return output; } -AesDecryptor::AesDecryptor(const KeyAddedCB& key_added_cb, - const KeyErrorCB& key_error_cb, - const KeyMessageCB& key_message_cb, - const SetSessionIdCB& set_session_id_cb) - : key_added_cb_(key_added_cb), - key_error_cb_(key_error_cb), - key_message_cb_(key_message_cb), - set_session_id_cb_(set_session_id_cb) {} +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() { STLDeleteValues(&key_map_); } -bool AesDecryptor::GenerateKeyRequest(uint32 reference_id, - const std::string& type, - const uint8* init_data, - int init_data_length) { +bool AesDecryptor::CreateSession(uint32 reference_id, + const std::string& type, + const uint8* init_data, + int init_data_length) { std::string session_id_string(base::UintToString(next_session_id_++)); // For now, the AesDecryptor does not care about |type|; @@ -167,35 +169,28 @@ bool AesDecryptor::GenerateKeyRequest(uint32 reference_id, if (init_data && init_data_length) message.assign(init_data, init_data + init_data_length); - set_session_id_cb_.Run(reference_id, session_id_string); - key_message_cb_.Run(reference_id, message, std::string()); + session_created_cb_.Run(reference_id, session_id_string); + session_message_cb_.Run(reference_id, message, std::string()); return true; } -void AesDecryptor::AddKey(uint32 reference_id, - const uint8* key, - int key_length, - const uint8* init_data, - int init_data_length) { - CHECK(key); - CHECK_GT(key_length, 0); - DCHECK(!init_data); - DCHECK_EQ(init_data_length, 0); - - // AddKey() is called from update(), where the key(s) are passed as a JSON - // Web Key (JWK) set. Each JWK needs to be a symmetric key ('kty' = "oct"), - // with 'kid' being the base64-encoded key id, and 'k' being the - // base64-encoded key. - std::string key_string(reinterpret_cast<const char*>(key), key_length); +void AesDecryptor::UpdateSession(uint32 reference_id, + const uint8* response, + int response_length) { + CHECK(response); + CHECK_GT(response_length, 0); + + std::string key_string(reinterpret_cast<const char*>(response), + response_length); KeyIdAndKeyPairs keys; if (!ExtractKeysFromJWKSet(key_string, &keys)) { - key_error_cb_.Run(reference_id, MediaKeys::kUnknownError, 0); + session_error_cb_.Run(reference_id, MediaKeys::kUnknownError, 0); return; } // Make sure that at least one key was extracted. if (keys.empty()) { - key_error_cb_.Run(reference_id, MediaKeys::kUnknownError, 0); + session_error_cb_.Run(reference_id, MediaKeys::kUnknownError, 0); return; } @@ -203,11 +198,11 @@ void AesDecryptor::AddKey(uint32 reference_id, if (it->second.length() != static_cast<size_t>(DecryptConfig::kDecryptionKeySize)) { DVLOG(1) << "Invalid key length: " << key_string.length(); - key_error_cb_.Run(reference_id, MediaKeys::kUnknownError, 0); + session_error_cb_.Run(reference_id, MediaKeys::kUnknownError, 0); return; } if (!AddDecryptionKey(it->first, it->second)) { - key_error_cb_.Run(reference_id, MediaKeys::kUnknownError, 0); + session_error_cb_.Run(reference_id, MediaKeys::kUnknownError, 0); return; } } @@ -218,10 +213,11 @@ void AesDecryptor::AddKey(uint32 reference_id, if (!new_video_key_cb_.is_null()) new_video_key_cb_.Run(); - key_added_cb_.Run(reference_id); + session_ready_cb_.Run(reference_id); } -void AesDecryptor::CancelKeyRequest(uint32 reference_id) { +void AesDecryptor::ReleaseSession(uint32 reference_id) { + // TODO: Implement: http://crbug.com/313412. } Decryptor* AesDecryptor::GetDecryptor() { diff --git a/media/cdm/aes_decryptor.h b/media/cdm/aes_decryptor.h index d1f9341..8e03106 100644 --- a/media/cdm/aes_decryptor.h +++ b/media/cdm/aes_decryptor.h @@ -27,23 +27,22 @@ namespace media { // encryption must be CTR with a key size of 128bits. class MEDIA_EXPORT AesDecryptor : public MediaKeys, public Decryptor { public: - AesDecryptor(const KeyAddedCB& key_added_cb, - const KeyErrorCB& key_error_cb, - const KeyMessageCB& key_message_cb, - const SetSessionIdCB& set_session_id_cb); + 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); virtual ~AesDecryptor(); // MediaKeys implementation. - virtual bool GenerateKeyRequest(uint32 reference_id, - const std::string& type, - const uint8* init_data, - int init_data_length) OVERRIDE; - virtual void AddKey(uint32 reference_id, - const uint8* key, - int key_length, - const uint8* init_data, - int init_data_length) OVERRIDE; - virtual void CancelKeyRequest(uint32 reference_id) OVERRIDE; + virtual bool CreateSession(uint32 reference_id, + const std::string& type, + const uint8* init_data, + int init_data_length) OVERRIDE; + virtual void UpdateSession(uint32 reference_id, + const uint8* response, + int response_length) OVERRIDE; + virtual void ReleaseSession(uint32 reference_id) OVERRIDE; virtual Decryptor* GetDecryptor() OVERRIDE; // Decryptor implementation. @@ -99,11 +98,12 @@ 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; - // Callbacks for firing key events. - KeyAddedCB key_added_cb_; - KeyErrorCB key_error_cb_; - KeyMessageCB key_message_cb_; - SetSessionIdCB set_session_id_cb_; + // 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_; // KeyMap owns the DecryptionKey* and must delete them when they are // not needed any more. diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc index d9730a2..cd0d460 100644 --- a/media/cdm/aes_decryptor_unittest.cc +++ b/media/cdm/aes_decryptor_unittest.cc @@ -185,11 +185,16 @@ static scoped_refptr<DecoderBuffer> CreateEncryptedBuffer( class AesDecryptorTest : public testing::Test { public: AesDecryptorTest() - : decryptor_( - base::Bind(&AesDecryptorTest::KeyAdded, base::Unretained(this)), - base::Bind(&AesDecryptorTest::KeyError, base::Unretained(this)), - base::Bind(&AesDecryptorTest::KeyMessage, base::Unretained(this)), - base::Bind(&AesDecryptorTest::SetSession, base::Unretained(this))), + : 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, + base::Unretained(this))), reference_id_(MediaKeys::kInvalidReferenceId), decrypt_cb_(base::Bind(&AesDecryptorTest::BufferDecrypted, base::Unretained(this))), @@ -207,12 +212,12 @@ class AesDecryptorTest : public testing::Test { } protected: - void GenerateKeyRequest(const std::vector<uint8>& key_id) { + void CreateSession(const std::vector<uint8>& key_id) { reference_id_ = 6; DCHECK(!key_id.empty()); - EXPECT_CALL(*this, SetSession(reference_id_, StrNe(std::string()))); - EXPECT_CALL(*this, KeyMessage(reference_id_, key_id, "")); - EXPECT_TRUE(decryptor_.GenerateKeyRequest( + EXPECT_CALL(*this, OnSessionCreated(reference_id_, StrNe(std::string()))); + EXPECT_CALL(*this, OnSessionMessage(reference_id_, key_id, "")); + EXPECT_TRUE(decryptor_.CreateSession( reference_id_, std::string(), &key_id[0], key_id.size())); } @@ -225,18 +230,17 @@ class AesDecryptorTest : public testing::Test { DCHECK(!key.empty()); if (result == KEY_ADDED) { - EXPECT_CALL(*this, KeyAdded(reference_id_)); + EXPECT_CALL(*this, OnSessionReady(reference_id_)); } else if (result == KEY_ERROR) { - EXPECT_CALL(*this, KeyError(reference_id_, MediaKeys::kUnknownError, 0)); + EXPECT_CALL(*this, + OnSessionError(reference_id_, MediaKeys::kUnknownError, 0)); } else { NOTREACHED(); } - decryptor_.AddKey(reference_id_, - reinterpret_cast<const uint8*>(key.c_str()), - key.length(), - NULL, - 0); + decryptor_.UpdateSession(reference_id_, + reinterpret_cast<const uint8*>(key.c_str()), + key.length()); } MOCK_METHOD2(BufferDecrypted, void(Decryptor::Status, @@ -287,14 +291,16 @@ class AesDecryptorTest : public testing::Test { } } - MOCK_METHOD1(KeyAdded, void(uint32 reference_id)); - MOCK_METHOD3(KeyError, void(uint32 reference_id, MediaKeys::KeyError, int)); - MOCK_METHOD3(KeyMessage, + MOCK_METHOD2(OnSessionCreated, + void(uint32 reference_id, const std::string& session_id)); + MOCK_METHOD3(OnSessionMessage, void(uint32 reference_id, const std::vector<uint8>& message, const std::string& default_url)); - MOCK_METHOD2(SetSession, - void(uint32 reference_id, const std::string& session_id)); + MOCK_METHOD1(OnSessionReady, void(uint32 reference_id)); + MOCK_METHOD1(OnSessionClosed, void(uint32 reference_id)); + MOCK_METHOD3(OnSessionError, + void(uint32 reference_id, MediaKeys::KeyError, int system_code)); AesDecryptor decryptor_; uint32 reference_id_; @@ -310,36 +316,32 @@ class AesDecryptorTest : public testing::Test { const std::vector<SubsampleEntry> no_subsample_entries_; }; -TEST_F(AesDecryptorTest, GenerateKeyRequestWithNullInitData) { +TEST_F(AesDecryptorTest, CreateSessionWithNullInitData) { reference_id_ = 8; - EXPECT_CALL(*this, KeyMessage(reference_id_, IsEmpty(), "")); - EXPECT_CALL(*this, SetSession(reference_id_, StrNe(std::string()))); - EXPECT_TRUE( - decryptor_.GenerateKeyRequest(reference_id_, std::string(), NULL, 0)); + EXPECT_CALL(*this, OnSessionMessage(reference_id_, IsEmpty(), "")); + EXPECT_CALL(*this, OnSessionCreated(reference_id_, StrNe(std::string()))); + EXPECT_TRUE(decryptor_.CreateSession(reference_id_, std::string(), NULL, 0)); } -TEST_F(AesDecryptorTest, MultipleGenerateKeyRequest) { +TEST_F(AesDecryptorTest, MultipleCreateSession) { uint32 reference_id1 = 10; - EXPECT_CALL(*this, KeyMessage(reference_id1, IsEmpty(), "")); - EXPECT_CALL(*this, SetSession(reference_id1, StrNe(std::string()))); - EXPECT_TRUE( - decryptor_.GenerateKeyRequest(reference_id1, std::string(), NULL, 0)); + EXPECT_CALL(*this, OnSessionMessage(reference_id1, IsEmpty(), "")); + EXPECT_CALL(*this, OnSessionCreated(reference_id1, StrNe(std::string()))); + EXPECT_TRUE(decryptor_.CreateSession(reference_id1, std::string(), NULL, 0)); uint32 reference_id2 = 11; - EXPECT_CALL(*this, KeyMessage(reference_id2, IsEmpty(), "")); - EXPECT_CALL(*this, SetSession(reference_id2, StrNe(std::string()))); - EXPECT_TRUE( - decryptor_.GenerateKeyRequest(reference_id2, std::string(), NULL, 0)); + EXPECT_CALL(*this, OnSessionMessage(reference_id2, IsEmpty(), "")); + EXPECT_CALL(*this, OnSessionCreated(reference_id2, StrNe(std::string()))); + EXPECT_TRUE(decryptor_.CreateSession(reference_id2, std::string(), NULL, 0)); uint32 reference_id3 = 23; - EXPECT_CALL(*this, KeyMessage(reference_id3, IsEmpty(), "")); - EXPECT_CALL(*this, SetSession(reference_id3, StrNe(std::string()))); - EXPECT_TRUE( - decryptor_.GenerateKeyRequest(reference_id3, std::string(), NULL, 0)); + EXPECT_CALL(*this, OnSessionMessage(reference_id3, IsEmpty(), "")); + EXPECT_CALL(*this, OnSessionCreated(reference_id3, StrNe(std::string()))); + EXPECT_TRUE(decryptor_.CreateSession(reference_id3, std::string(), NULL, 0)); } TEST_F(AesDecryptorTest, NormalDecryption) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); AddKeyAndExpect(kKeyAsJWK, KEY_ADDED); scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer( encrypted_data_, key_id_, iv_, 0, no_subsample_entries_); @@ -347,7 +349,7 @@ TEST_F(AesDecryptorTest, NormalDecryption) { } TEST_F(AesDecryptorTest, DecryptionWithOffset) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); AddKeyAndExpect(kKeyAsJWK, KEY_ADDED); scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer( encrypted_data_, key_id_, iv_, 23, no_subsample_entries_); @@ -362,7 +364,7 @@ TEST_F(AesDecryptorTest, UnencryptedFrame) { } TEST_F(AesDecryptorTest, WrongKey) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); AddKeyAndExpect(kWrongKeyAsJWK, KEY_ADDED); scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer( encrypted_data_, key_id_, iv_, 0, no_subsample_entries_); @@ -377,7 +379,7 @@ TEST_F(AesDecryptorTest, NoKey) { } TEST_F(AesDecryptorTest, KeyReplacement) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer( encrypted_data_, key_id_, iv_, 0, no_subsample_entries_); @@ -391,12 +393,12 @@ TEST_F(AesDecryptorTest, KeyReplacement) { } TEST_F(AesDecryptorTest, WrongSizedKey) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); AddKeyAndExpect(kWrongSizedKeyAsJWK, KEY_ERROR); } TEST_F(AesDecryptorTest, MultipleKeysAndFrames) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); AddKeyAndExpect(kKeyAsJWK, KEY_ADDED); scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer( encrypted_data_, key_id_, iv_, 10, no_subsample_entries_); @@ -425,7 +427,7 @@ TEST_F(AesDecryptorTest, MultipleKeysAndFrames) { } TEST_F(AesDecryptorTest, CorruptedIv) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); AddKeyAndExpect(kKeyAsJWK, KEY_ADDED); std::vector<uint8> bad_iv = iv_; @@ -438,7 +440,7 @@ TEST_F(AesDecryptorTest, CorruptedIv) { } TEST_F(AesDecryptorTest, CorruptedData) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); AddKeyAndExpect(kKeyAsJWK, KEY_ADDED); std::vector<uint8> bad_data = encrypted_data_; @@ -450,7 +452,7 @@ TEST_F(AesDecryptorTest, CorruptedData) { } TEST_F(AesDecryptorTest, EncryptedAsUnencryptedFailure) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); AddKeyAndExpect(kKeyAsJWK, KEY_ADDED); scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer( encrypted_data_, key_id_, std::vector<uint8>(), 0, no_subsample_entries_); @@ -458,7 +460,7 @@ TEST_F(AesDecryptorTest, EncryptedAsUnencryptedFailure) { } TEST_F(AesDecryptorTest, SubsampleDecryption) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); AddKeyAndExpect(kKeyAsJWK, KEY_ADDED); scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer( subsample_encrypted_data_, key_id_, iv_, 0, normal_subsample_entries_); @@ -469,7 +471,7 @@ 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) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); AddKeyAndExpect(kKeyAsJWK, KEY_ADDED); scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer( subsample_encrypted_data_, key_id_, iv_, 23, normal_subsample_entries_); @@ -477,7 +479,7 @@ TEST_F(AesDecryptorTest, SubsampleDecryptionWithOffset) { } TEST_F(AesDecryptorTest, SubsampleWrongSize) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); AddKeyAndExpect(kKeyAsJWK, KEY_ADDED); std::vector<SubsampleEntry> subsample_entries_wrong_size( @@ -490,7 +492,7 @@ TEST_F(AesDecryptorTest, SubsampleWrongSize) { } TEST_F(AesDecryptorTest, SubsampleInvalidTotalSize) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); AddKeyAndExpect(kKeyAsJWK, KEY_ADDED); std::vector<SubsampleEntry> subsample_entries_invalid_total_size( @@ -506,7 +508,7 @@ TEST_F(AesDecryptorTest, SubsampleInvalidTotalSize) { // No cypher bytes in any of the subsamples. TEST_F(AesDecryptorTest, SubsampleClearBytesOnly) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); AddKeyAndExpect(kKeyAsJWK, KEY_ADDED); std::vector<SubsampleEntry> clear_only_subsample_entries( @@ -520,7 +522,7 @@ TEST_F(AesDecryptorTest, SubsampleClearBytesOnly) { // No clear bytes in any of the subsamples. TEST_F(AesDecryptorTest, SubsampleCypherBytesOnly) { - GenerateKeyRequest(key_id_); + CreateSession(key_id_); AddKeyAndExpect(kKeyAsJWK, KEY_ADDED); std::vector<SubsampleEntry> cypher_only_subsample_entries( diff --git a/media/cdm/ppapi/cdm_adapter.cc b/media/cdm/ppapi/cdm_adapter.cc index 1d9200a..489eb1d 100644 --- a/media/cdm/ppapi/cdm_adapter.cc +++ b/media/cdm/ppapi/cdm_adapter.cc @@ -235,7 +235,7 @@ bool CdmAdapter::CreateCdmInstance(const std::string& key_system) { // No KeyErrors should be reported in this function because they cannot be // bubbled up in the WD EME API. Those errors will be reported during session -// creation (aka GenerateKeyRequest). +// creation (CreateSession). void CdmAdapter::Initialize(const std::string& key_system) { PP_DCHECK(!key_system.empty()); PP_DCHECK(key_system_.empty() || (key_system_ == key_system && cdm_)); @@ -247,13 +247,13 @@ void CdmAdapter::Initialize(const std::string& key_system) { key_system_ = key_system; } -void CdmAdapter::GenerateKeyRequest(uint32_t reference_id, - const std::string& type, - pp::VarArrayBuffer init_data) { - // Initialize() doesn't report an error, so GenerateKeyRequest() can be called +void CdmAdapter::CreateSession(uint32_t reference_id, + const std::string& type, + pp::VarArrayBuffer init_data) { + // Initialize() doesn't report an error, so CreateSession() can be called // even if Initialize() failed. if (!cdm_) { - SendUnknownKeyError(reference_id); + OnSessionError(reference_id, cdm::kUnknownError, 0); return; } @@ -261,7 +261,7 @@ void CdmAdapter::GenerateKeyRequest(uint32_t reference_id, PP_URLComponents_Dev url_components = {}; const pp::URLUtil_Dev* url_util = pp::URLUtil_Dev::Get(); if (!url_util) { - SendUnknownKeyError(reference_id); + OnSessionError(reference_id, cdm::kUnknownError, 0); return; } pp::Var href = url_util->GetDocumentURL( @@ -272,56 +272,52 @@ void CdmAdapter::GenerateKeyRequest(uint32_t reference_id, PP_DCHECK(0 < url_components.host.len); #endif // defined(CHECK_DOCUMENT_URL) - cdm_->GenerateKeyRequest(reference_id, - type.data(), - type.size(), - static_cast<const uint8_t*>(init_data.Map()), - init_data.ByteLength()); + cdm_->CreateSession(reference_id, + type.data(), + type.size(), + static_cast<const uint8_t*>(init_data.Map()), + init_data.ByteLength()); } -void CdmAdapter::AddKey(uint32_t reference_id, - pp::VarArrayBuffer key, - pp::VarArrayBuffer init_data) { +void CdmAdapter::UpdateSession(uint32_t reference_id, + pp::VarArrayBuffer response) { // TODO(jrummell): In EME WD, AddKey() can only be called on valid sessions. // We should be able to DCHECK(cdm_) when addressing http://crbug.com/249976. if (!cdm_) { - SendUnknownKeyError(reference_id); + OnSessionError(reference_id, cdm::kUnknownError, 0); return; } - const uint8_t* key_ptr = static_cast<const uint8_t*>(key.Map()); - const uint32_t key_size = key.ByteLength(); - const uint8_t* init_data_ptr = static_cast<const uint8_t*>(init_data.Map()); - const uint32_t init_data_size = init_data.ByteLength(); - PP_DCHECK(!init_data_ptr == !init_data_size); + const uint8_t* response_ptr = static_cast<const uint8_t*>(response.Map()); + const uint32_t response_size = response.ByteLength(); - if (!key_ptr || key_size <= 0) { - SendUnknownKeyError(reference_id); + if (!response_ptr || response_size <= 0) { + OnSessionError(reference_id, cdm::kUnknownError, 0); return; } - CdmWrapper::Result result = cdm_->AddKey( - reference_id, key_ptr, key_size, init_data_ptr, init_data_size); + CdmWrapper::Result result = + cdm_->UpdateSession(reference_id, response_ptr, response_size); switch (result) { case CdmWrapper::NO_ACTION: break; case CdmWrapper::CALL_KEY_ADDED: - SendKeyAdded(reference_id); + OnSessionReady(reference_id); break; case CdmWrapper::CALL_KEY_ERROR: - SendUnknownKeyError(reference_id); + OnSessionError(reference_id, cdm::kUnknownError, 0); break; } } -void CdmAdapter::CancelKeyRequest(uint32_t reference_id) { +void CdmAdapter::ReleaseSession(uint32_t reference_id) { // TODO(jrummell): In EME WD, AddKey() can only be called on valid sessions. // We should be able to DCHECK(cdm_) when addressing http://crbug.com/249976. if (!cdm_) { - SendUnknownKeyError(reference_id); + OnSessionError(reference_id, cdm::kUnknownError, 0); return; } - CdmWrapper::Result result = cdm_->CancelKeyRequest(reference_id); + CdmWrapper::Result result = cdm_->ReleaseSession(reference_id); switch (result) { case CdmWrapper::NO_ACTION: break; @@ -329,7 +325,7 @@ void CdmAdapter::CancelKeyRequest(uint32_t reference_id) { PP_NOTREACHED(); break; case CdmWrapper::CALL_KEY_ERROR: - SendUnknownKeyError(reference_id); + OnSessionError(reference_id, cdm::kUnknownError, 0); break; } } @@ -542,14 +538,9 @@ void CdmAdapter::SendKeyMessage( PP_DCHECK(!session_id_str.empty()); uint32_t reference_id = cdm_->DetermineReferenceId(session_id_str); - PostOnMain(callback_factory_.NewCallback( - &CdmAdapter::SetSessionId, reference_id, session_id_str)); - - PostOnMain(callback_factory_.NewCallback( - &CdmAdapter::KeyMessage, - reference_id, - std::vector<uint8>(message, message + message_length), - std::string(default_url, default_url_length))); + OnSessionCreated(reference_id, session_id, session_id_length); + OnSessionMessage( + reference_id, message, message_length, default_url, default_url_length); } void CdmAdapter::SendKeyError(const char* session_id, @@ -558,8 +549,7 @@ void CdmAdapter::SendKeyError(const char* session_id, uint32_t system_code) { std::string session_id_str(session_id, session_id_length); uint32_t reference_id = cdm_->DetermineReferenceId(session_id_str); - - SendKeyErrorInternal(reference_id, error_code, system_code); + OnSessionError(reference_id, error_code, system_code); } void CdmAdapter::GetPrivateData(int32_t* instance, @@ -568,31 +558,58 @@ void CdmAdapter::GetPrivateData(int32_t* instance, *get_interface = pp::Module::Get()->get_browser_interface(); } -void CdmAdapter::SendUnknownKeyError(uint32_t reference_id) { - SendKeyErrorInternal(reference_id, cdm::kUnknownError, 0); +void CdmAdapter::OnSessionCreated(uint32_t reference_id, + const char* session_id, + uint32_t session_id_length) { + PostOnMain(callback_factory_.NewCallback( + &CdmAdapter::SendSessionCreatedInternal, + reference_id, + std::string(session_id, session_id_length))); +} + +void CdmAdapter::OnSessionMessage(uint32_t reference_id, + const char* message, + uint32_t message_length, + const char* destination_url, + uint32_t destination_url_length) { + PostOnMain(callback_factory_.NewCallback( + &CdmAdapter::SendSessionMessageInternal, + reference_id, + std::vector<uint8>(message, message + message_length), + std::string(destination_url, destination_url_length))); +} + +void CdmAdapter::OnSessionReady(uint32_t reference_id) { + PostOnMain(callback_factory_.NewCallback( + &CdmAdapter::SendSessionReadyInternal, reference_id)); } -void CdmAdapter::SendKeyAdded(uint32_t reference_id) { - PostOnMain( - callback_factory_.NewCallback(&CdmAdapter::KeyAdded, reference_id)); +void CdmAdapter::OnSessionClosed(uint32_t reference_id) { + PostOnMain(callback_factory_.NewCallback( + &CdmAdapter::SendSessionClosedInternal, reference_id)); } -void CdmAdapter::SendKeyErrorInternal(uint32_t reference_id, - cdm::MediaKeyError error_code, - uint32_t system_code) { +void CdmAdapter::OnSessionError(uint32_t reference_id, + cdm::MediaKeyError error_code, + uint32_t system_code) { PostOnMain(callback_factory_.NewCallback( - &CdmAdapter::KeyError, reference_id, error_code, system_code)); + &CdmAdapter::SendSessionErrorInternal, + reference_id, + error_code, + system_code)); } -void CdmAdapter::KeyAdded(int32_t result, uint32_t reference_id) { +void CdmAdapter::SendSessionCreatedInternal(int32_t result, + uint32_t reference_id, + const std::string& session_id) { PP_DCHECK(result == PP_OK); - pp::ContentDecryptor_Private::KeyAdded(reference_id); + pp::ContentDecryptor_Private::SessionCreated(reference_id, session_id); } -void CdmAdapter::KeyMessage(int32_t result, - uint32_t reference_id, - const std::vector<uint8>& message, - const std::string& default_url) { +void CdmAdapter::SendSessionMessageInternal(int32_t result, + uint32_t reference_id, + const std::vector<uint8>& message, + const std::string& default_url) { PP_DCHECK(result == PP_OK); pp::VarArrayBuffer message_array_buffer(message.size()); @@ -600,25 +617,29 @@ void CdmAdapter::KeyMessage(int32_t result, memcpy(message_array_buffer.Map(), message.data(), message.size()); } - pp::ContentDecryptor_Private::KeyMessage( - reference_id, - message_array_buffer, - default_url); + pp::ContentDecryptor_Private::SessionMessage( + reference_id, message_array_buffer, default_url); +} + +void CdmAdapter::SendSessionReadyInternal(int32_t result, + uint32_t reference_id) { + PP_DCHECK(result == PP_OK); + pp::ContentDecryptor_Private::SessionReady(reference_id); } -void CdmAdapter::KeyError(int32_t result, - uint32_t reference_id, - cdm::MediaKeyError error_code, - uint32_t system_code) { +void CdmAdapter::SendSessionClosedInternal(int32_t result, + uint32_t reference_id) { PP_DCHECK(result == PP_OK); - pp::ContentDecryptor_Private::KeyError(reference_id, error_code, system_code); + pp::ContentDecryptor_Private::SessionClosed(reference_id); } -void CdmAdapter::SetSessionId(int32_t result, - uint32_t reference_id, - const std::string& session_id) { +void CdmAdapter::SendSessionErrorInternal(int32_t result, + uint32_t reference_id, + cdm::MediaKeyError error_code, + uint32_t system_code) { PP_DCHECK(result == PP_OK); - pp::ContentDecryptor_Private::SetSessionId(reference_id, session_id); + pp::ContentDecryptor_Private::SessionError( + reference_id, error_code, system_code); } void CdmAdapter::DeliverBlock(int32_t result, @@ -928,7 +949,7 @@ void* GetCdmHost(int host_interface_version, void* user_data) { return NULL; COMPILE_ASSERT(cdm::ContentDecryptionModule::Host::kVersion == - cdm::ContentDecryptionModule_2::Host::kVersion, + cdm::ContentDecryptionModule_3::Host::kVersion, update_code_below); // Ensure IsSupportedCdmHostVersion matches implementation of this function. @@ -949,10 +970,10 @@ void* GetCdmHost(int host_interface_version, void* user_data) { CdmAdapter* cdm_adapter = static_cast<CdmAdapter*>(user_data); switch (host_interface_version) { - // The latest CDM host version. - case cdm::ContentDecryptionModule::Host::kVersion: - return static_cast<cdm::ContentDecryptionModule::Host*>(cdm_adapter); - // Older supported version(s) of the CDM host. + case cdm::Host_3::kVersion: + return static_cast<cdm::Host_3*>(cdm_adapter); + case cdm::Host_2::kVersion: + return static_cast<cdm::Host_2*>(cdm_adapter); case cdm::Host_1::kVersion: return static_cast<cdm::Host_1*>(cdm_adapter); default: diff --git a/media/cdm/ppapi/cdm_adapter.h b/media/cdm/ppapi/cdm_adapter.h index 0542c5d..57e7524 100644 --- a/media/cdm/ppapi/cdm_adapter.h +++ b/media/cdm/ppapi/cdm_adapter.h @@ -38,7 +38,8 @@ void* GetCdmHost(int host_interface_version, void* user_data); class CdmAdapter : public pp::Instance, public pp::ContentDecryptor_Private, public cdm::Host_1, - public cdm::Host_2 { + public cdm::Host_2, + public cdm::Host_3 { public: CdmAdapter(PP_Instance instance, pp::Module* module); virtual ~CdmAdapter(); @@ -52,13 +53,12 @@ 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 GenerateKeyRequest(uint32_t reference_id, - const std::string& type, - pp::VarArrayBuffer init_data) OVERRIDE; - virtual void AddKey(uint32_t reference_id, - pp::VarArrayBuffer key, - pp::VarArrayBuffer init_data) OVERRIDE; - virtual void CancelKeyRequest(uint32_t reference_id) OVERRIDE; + virtual void CreateSession(uint32_t reference_id, + const std::string& type, + pp::VarArrayBuffer init_data) OVERRIDE; + virtual void UpdateSession(uint32_t reference_id, + pp::VarArrayBuffer response) OVERRIDE; + virtual void ReleaseSession(uint32_t reference_id) OVERRIDE; virtual void Decrypt( pp::Buffer_Dev encrypted_buffer, const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE; @@ -103,6 +103,21 @@ class CdmAdapter : public pp::Instance, cdm::StreamType stream_type, cdm::Status decoder_status) OVERRIDE; + // cdm::Host_3 implementation. + virtual void OnSessionCreated(uint32_t reference_id, + const char* session_id, + uint32_t session_id_length) OVERRIDE; + virtual void OnSessionMessage(uint32_t reference_id, + const char* message, + uint32_t message_length, + const char* destination_url, + uint32_t destination_url_length) OVERRIDE; + virtual void OnSessionReady(uint32_t reference_id) OVERRIDE; + virtual void OnSessionClosed(uint32_t reference_id) OVERRIDE; + virtual void OnSessionError(uint32_t reference_id, + cdm::MediaKeyError error_code, + uint32_t system_code) OVERRIDE; + private: typedef linked_ptr<DecryptedBlockImpl> LinkedDecryptedBlock; typedef linked_ptr<VideoFrameImpl> LinkedVideoFrame; @@ -110,27 +125,23 @@ class CdmAdapter : public pp::Instance, bool CreateCdmInstance(const std::string& key_system); - void SendUnknownKeyError(uint32_t reference_id); - void SendKeyAdded(uint32_t reference_id); - void SendKeyErrorInternal(uint32_t reference_id, - cdm::MediaKeyError error_code, - uint32_t system_code); - // <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 KeyAdded(int32_t result, uint32_t reference_id); - void KeyMessage(int32_t result, - uint32_t reference_id, - const std::vector<uint8>& message, - const std::string& default_url); - void KeyError(int32_t result, - uint32_t reference_id, - cdm::MediaKeyError error_code, - uint32_t system_code); - void SetSessionId(int32_t result, - uint32_t reference_id, - const std::string& session_id); + void SendSessionCreatedInternal(int32_t result, + uint32_t reference_id, + const std::string& session_id); + void SendSessionMessageInternal(int32_t result, + uint32_t reference_id, + const std::vector<uint8>& message, + const std::string& default_url); + void SendSessionReadyInternal(int32_t result, uint32_t reference_id); + void SendSessionClosedInternal(int32_t result, uint32_t reference_id); + void SendSessionErrorInternal(int32_t result, + uint32_t reference_id, + cdm::MediaKeyError error_code, + uint32_t system_code); + void DeliverBlock(int32_t result, const cdm::Status& status, const LinkedDecryptedBlock& decrypted_block, diff --git a/media/cdm/ppapi/cdm_wrapper.h b/media/cdm/ppapi/cdm_wrapper.h index 8d3003a..63d8bbf 100644 --- a/media/cdm/ppapi/cdm_wrapper.h +++ b/media/cdm/ppapi/cdm_wrapper.h @@ -52,17 +52,15 @@ class CdmWrapper { virtual ~CdmWrapper() {}; - virtual void GenerateKeyRequest(uint32_t reference_id, - const char* type, - uint32_t type_size, - const uint8_t* init_data, - uint32_t init_data_size) = 0; - virtual Result AddKey(uint32_t reference_id, - const uint8_t* key, - uint32_t key_size, - const uint8_t* key_id, - uint32_t key_id_size) = 0; - virtual Result CancelKeyRequest(uint32_t reference_id) = 0; + virtual void CreateSession(uint32_t reference_id, + const char* type, + uint32_t type_size, + const uint8_t* init_data, + uint32_t init_data_size) = 0; + virtual Result UpdateSession(uint32_t reference_id, + const uint8_t* response, + uint32_t response_size) = 0; + virtual Result ReleaseSession(uint32_t reference_id) = 0; virtual void TimerExpired(void* context) = 0; virtual cdm::Status Decrypt(const cdm::InputBuffer& encrypted_buffer, cdm::DecryptedBlock* decrypted_buffer) = 0; @@ -85,10 +83,11 @@ class CdmWrapper { uint32_t output_protection_mask) = 0; // ContentDecryptionModule_1 and ContentDecryptionModule_2 interface methods - // AddKey() and CancelKeyRequest() (older versions of Update() and Close(), - // respectively) pass in the session_id rather than the reference_id. As well, - // Host_1 and Host_2 callbacks SendKeyMessage() and SendKeyError() include the - // session ID, but the actual callbacks need the reference ID. + // AddKey() and CancelKeyRequest() (older versions of UpdateSession() and + // ReleaseSession(), respectively) pass in the session_id rather than the + // reference_id. As well, Host_1 and Host_2 callbacks SendKeyMessage() and + // SendKeyError() include the session ID, but the actual callbacks need the + // reference ID. // // The following functions maintain the reference_id <-> session_id mapping. // These can be removed once _1 and _2 interfaces are no longer supported. @@ -99,16 +98,15 @@ class CdmWrapper { // Determine the corresponding session_id for |reference_id|. virtual const std::string LookupSessionId(uint32_t reference_id) = 0; - protected: + // TODO(jrummell): The following can be removed once CDM_1 and CDM_2 are + // no longer supported. typedef std::map<uint32_t, std::string> SessionMap; static const uint32_t kInvalidReferenceId = 0; - CdmWrapper() : current_key_request_reference_id_(kInvalidReferenceId) {} - // Map between session_id and reference_id. SessionMap session_map_; - // As the response from GenerateKeyRequest() may be synchronous or + // As the response from PrefixedGenerateKeyRequest() may be synchronous or // asynchronous, keep track of the current request during the call to handle // synchronous responses or errors. If no response received, add this request // to a queue and assume that the subsequent responses come back in the order @@ -118,6 +116,9 @@ class CdmWrapper { uint32_t current_key_request_reference_id_; std::queue<uint32_t> pending_key_request_reference_ids_; + protected: + CdmWrapper() : current_key_request_reference_id_(kInvalidReferenceId) {} + private: DISALLOW_COPY_AND_ASSIGN(CdmWrapper); }; @@ -146,91 +147,24 @@ class CdmWrapperImpl : public CdmWrapper { cdm_->Destroy(); } - // TODO(jrummell): In CDM_3 all key callbacks will use reference_id, so there - // is no need to keep track of the current/pending request IDs. As well, the - // definition for AddKey() and CancelKeyRequest() require the CDM to always - // send a response (success or error), so the callbacks are not required. - // Simplify the following 3 routines when CDM_3 is supported. - - virtual void GenerateKeyRequest(uint32_t reference_id, - const char* type, - uint32_t type_size, - const uint8_t* init_data, - uint32_t init_data_size) OVERRIDE { - // As it is possible for CDMs to reply synchronously during the call to - // GenerateKeyRequest(), keep track of |reference_id|. - current_key_request_reference_id_ = reference_id; - - cdm::Status status = - cdm_->GenerateKeyRequest(type, type_size, init_data, init_data_size); - PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError); - if (status != cdm::kSuccess) { - // If GenerateKeyRequest() failed, no subsequent asynchronous replies - // will be sent. Verify that a response was sent synchronously. - PP_DCHECK(current_key_request_reference_id_ == kInvalidReferenceId); - current_key_request_reference_id_ = kInvalidReferenceId; - return; - } - - if (current_key_request_reference_id_) { - // If this request is still pending (SendKeyMessage() or SendKeyError() - // not called synchronously), add |reference_id| to the end of the queue. - // Without CDM support, it is impossible to match SendKeyMessage() - // (or SendKeyError()) responses to the |reference_id|. Doing the best - // we can by keeping track of this in a queue, and assuming the responses - // come back in order. - pending_key_request_reference_ids_.push(reference_id); - current_key_request_reference_id_ = kInvalidReferenceId; - } + virtual void CreateSession(uint32_t reference_id, + const char* type, + uint32_t type_size, + const uint8_t* init_data, + uint32_t init_data_size) OVERRIDE { + cdm_->CreateSession( + reference_id, type, type_size, init_data, init_data_size); } - virtual Result AddKey(uint32_t reference_id, - const uint8_t* key, - uint32_t key_size, - const uint8_t* key_id, - uint32_t key_id_size) OVERRIDE { - const std::string session_id = LookupSessionId(reference_id); - if (session_id.empty()) { - // Possible if AddKey() called before GenerateKeyRequest(). - return CALL_KEY_ERROR; - } - - cdm::Status status = cdm_->AddKey(session_id.data(), - session_id.size(), - key, - key_size, - key_id, - key_id_size); - PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError); - if (status != cdm::kSuccess) { - // http://crbug.com/310345: CDMs should send a KeyError message if they - // return a failure, so no need to do it twice. Remove this once all CDMs - // have been updated. - return CALL_KEY_ERROR; - } - - return CALL_KEY_ADDED; + virtual Result UpdateSession(uint32_t reference_id, + const uint8_t* response, + uint32_t response_size) OVERRIDE { + cdm_->UpdateSession(reference_id, response, response_size); + return NO_ACTION; } - virtual Result CancelKeyRequest(uint32_t reference_id) OVERRIDE { - const std::string session_id = LookupSessionId(reference_id); - if (session_id.empty()) { - // Possible if CancelKeyRequest() called before GenerateKeyRequest(). - return CALL_KEY_ERROR; - } - - session_map_.erase(reference_id); - cdm::Status status = - cdm_->CancelKeyRequest(session_id.data(), session_id.size()); - - PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError); - if (status != cdm::kSuccess) { - // http://crbug.com/310345: CDMs should send a KeyError message if they - // return a failure, so no need to do it twice. Remove this once all CDMs - // have been updated. - return CALL_KEY_ERROR; - } - + virtual Result ReleaseSession(uint32_t reference_id) OVERRIDE { + cdm_->ReleaseSession(reference_id); return NO_ACTION; } @@ -293,11 +227,12 @@ class CdmWrapperImpl : public CdmWrapper { } // There is no entry in the map; assume it came from the current - // GenerateKeyRequest() call (if possible). If no current request, - // assume it came from the oldest GenerateKeyRequest() call. + // PrefixedGenerateKeyRequest() call (if possible). If no current request, + // assume it came from the oldest PrefixedGenerateKeyRequest() call. uint32_t reference_id = current_key_request_reference_id_; if (current_key_request_reference_id_) { - // Only 1 response is allowed for the current GenerateKeyRequest(). + // Only 1 response is allowed for the current + // PrefixedGenerateKeyRequest(). current_key_request_reference_id_ = kInvalidReferenceId; } else { PP_DCHECK(!pending_key_request_reference_ids_.empty()); @@ -318,7 +253,7 @@ class CdmWrapperImpl : public CdmWrapper { } const std::string LookupSessionId(uint32_t reference_id) { - // Session may not exist if error happens during GenerateKeyRequest(). + // Session may not exist if error happens during CreateSession(). SessionMap::iterator it = session_map_.find(reference_id); return (it != session_map_.end()) ? it->second : std::string(); } @@ -333,8 +268,124 @@ class CdmWrapperImpl : public CdmWrapper { DISALLOW_COPY_AND_ASSIGN(CdmWrapperImpl); }; +// For ContentDecryptionModule_1 and ContentDecryptionModule_2, +// CreateSession(), UpdateSession(), and ReleaseSession() call methods +// are incompatible with ContentDecryptionModule_3. Use the following +// templated functions to handle this. + +template <class CdmInterface> +void PrefixedGenerateKeyRequest(CdmWrapper* wrapper, + CdmInterface* cdm, + uint32_t reference_id, + const char* type, + uint32_t type_size, + const uint8_t* init_data, + uint32_t init_data_size) { + // As it is possible for CDMs to reply synchronously during the call to + // GenerateKeyRequest(), keep track of |reference_id|. + wrapper->current_key_request_reference_id_ = reference_id; + + cdm::Status status = + cdm->GenerateKeyRequest(type, type_size, init_data, init_data_size); + PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError); + if (status != cdm::kSuccess) { + // If GenerateKeyRequest() failed, no subsequent asynchronous replies + // will be sent. Verify that a response was sent synchronously. + PP_DCHECK(wrapper->current_key_request_reference_id_ == + CdmWrapper::kInvalidReferenceId); + wrapper->current_key_request_reference_id_ = + CdmWrapper::kInvalidReferenceId; + return; + } + + if (wrapper->current_key_request_reference_id_) { + // If this request is still pending (SendKeyMessage() or SendKeyError() + // not called synchronously), add |reference_id| to the end of the queue. + // Without CDM support, it is impossible to match SendKeyMessage() + // (or SendKeyError()) responses to the |reference_id|. Doing the best + // we can by keeping track of this in a queue, and assuming the responses + // come back in order. + wrapper->pending_key_request_reference_ids_.push(reference_id); + wrapper->current_key_request_reference_id_ = + CdmWrapper::kInvalidReferenceId; + } +} + +template <class CdmInterface> +CdmWrapper::Result PrefixedAddKey(CdmWrapper* wrapper, + CdmInterface* cdm, + uint32_t reference_id, + const uint8_t* response, + uint32_t response_size) { + const std::string session_id = wrapper->LookupSessionId(reference_id); + if (session_id.empty()) { + // Possible if UpdateSession() called before CreateSession(). + return CdmWrapper::CALL_KEY_ERROR; + } + + // CDM_1 and CDM_2 accept initdata, which is no longer needed. + // In it's place pass in NULL. + cdm::Status status = cdm->AddKey( + session_id.data(), session_id.size(), response, response_size, NULL, 0); + PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError); + if (status != cdm::kSuccess) { + // Some CDMs using Host_1/2 don't call keyerror, so send one. + return CdmWrapper::CALL_KEY_ERROR; + } + + return CdmWrapper::CALL_KEY_ADDED; +} + +template <class CdmInterface> +CdmWrapper::Result PrefixedCancelKeyRequest(CdmWrapper* wrapper, + CdmInterface* cdm, + uint32_t reference_id) { + const std::string session_id = wrapper->LookupSessionId(reference_id); + if (session_id.empty()) { + // Possible if ReleaseSession() called before CreateSession(). + return CdmWrapper::CALL_KEY_ERROR; + } + + wrapper->session_map_.erase(reference_id); + cdm::Status status = + cdm->CancelKeyRequest(session_id.data(), session_id.size()); + + PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError); + if (status != cdm::kSuccess) { + // Some CDMs using Host_1/2 don't call keyerror, so send one. + return CdmWrapper::CALL_KEY_ERROR; + } + + return CdmWrapper::NO_ACTION; +} + // Specializations for ContentDecryptionModule_1. +template <> +void CdmWrapperImpl<cdm::ContentDecryptionModule_1>::CreateSession( + uint32_t reference_id, + const char* type, + uint32_t type_size, + const uint8_t* init_data, + uint32_t init_data_size) { + PrefixedGenerateKeyRequest( + this, cdm_, reference_id, type, type_size, init_data, init_data_size); +} + +template <> +CdmWrapper::Result CdmWrapperImpl< + cdm::ContentDecryptionModule_1>::UpdateSession(uint32_t reference_id, + const uint8_t* response, + uint32_t response_size) { + return PrefixedAddKey(this, cdm_, reference_id, response, response_size); +} + +template <> +CdmWrapper::Result CdmWrapperImpl< + cdm::ContentDecryptionModule_1>::ReleaseSession(uint32_t reference_id) { + return PrefixedCancelKeyRequest(this, cdm_, reference_id); +} + template <> void CdmWrapperImpl<cdm::ContentDecryptionModule_1>:: OnPlatformChallengeResponse( const cdm::PlatformChallengeResponse& response) { @@ -361,12 +412,39 @@ template <> cdm::Status CdmWrapperImpl<cdm::ContentDecryptionModule_1>:: return cdm::kSuccess; } +// Specializations for ContentDecryptionModule_2. + +template <> +void CdmWrapperImpl<cdm::ContentDecryptionModule_2>::CreateSession( + uint32_t reference_id, + const char* type, + uint32_t type_size, + const uint8_t* init_data, + uint32_t init_data_size) { + PrefixedGenerateKeyRequest( + this, cdm_, reference_id, type, type_size, init_data, init_data_size); +} + +template <> +CdmWrapper::Result CdmWrapperImpl< + cdm::ContentDecryptionModule_2>::UpdateSession(uint32_t reference_id, + const uint8_t* response, + uint32_t response_size) { + return PrefixedAddKey(this, cdm_, reference_id, response, response_size); +} + +template <> +CdmWrapper::Result CdmWrapperImpl< + cdm::ContentDecryptionModule_2>::ReleaseSession(uint32_t reference_id) { + return PrefixedCancelKeyRequest(this, cdm_, reference_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_2::kVersion, + cdm::ContentDecryptionModule_3::kVersion, update_code_below); // Ensure IsSupportedCdmInterfaceVersion matches this implementation. @@ -378,6 +456,8 @@ CdmWrapper* CdmWrapper::Create(const char* key_system, cdm::ContentDecryptionModule::kVersion + 1) && IsSupportedCdmInterfaceVersion(cdm::ContentDecryptionModule::kVersion) && IsSupportedCdmInterfaceVersion( + cdm::ContentDecryptionModule_2::kVersion) && + IsSupportedCdmInterfaceVersion( cdm::ContentDecryptionModule_1::kVersion) && !IsSupportedCdmInterfaceVersion( cdm::ContentDecryptionModule_1::kVersion - 1)); @@ -390,6 +470,11 @@ CdmWrapper* CdmWrapper::Create(const char* key_system, return cdm_wrapper; // Try to see if the CDM supports older version(s) of the CDM interface. + cdm_wrapper = CdmWrapperImpl<cdm::ContentDecryptionModule_2>::Create( + key_system, key_system_size, get_cdm_host_func, user_data); + if (cdm_wrapper) + return cdm_wrapper; + cdm_wrapper = CdmWrapperImpl<cdm::ContentDecryptionModule_1>::Create( key_system, key_system_size, get_cdm_host_func, user_data); return cdm_wrapper; @@ -400,7 +485,7 @@ CdmWrapper* CdmWrapper::Create(const char* key_system, // does not have. // Also update supported_cdm_versions.h. COMPILE_ASSERT(cdm::ContentDecryptionModule::kVersion == - cdm::ContentDecryptionModule_2::kVersion, + cdm::ContentDecryptionModule_3::kVersion, ensure_cdm_wrapper_templates_have_old_version_support); } // namespace media diff --git a/media/cdm/ppapi/clear_key_cdm.cc b/media/cdm/ppapi/clear_key_cdm.cc index 044cbb2..3fc10e1 100644 --- a/media/cdm/ppapi/clear_key_cdm.cc +++ b/media/cdm/ppapi/clear_key_cdm.cc @@ -171,43 +171,49 @@ ClearKeyCdm::Client::~Client() {} void ClearKeyCdm::Client::Reset() { status_ = kNone; session_id_.clear(); - key_message_.clear(); - default_url_.clear(); + message_.clear(); + destination_url_.clear(); error_code_ = MediaKeys::kUnknownError; system_code_ = 0; } -void ClearKeyCdm::Client::KeyAdded(uint32 reference_id) { - status_ = static_cast<Status>(status_ | kKeyAdded); +void ClearKeyCdm::Client::OnSessionCreated(uint32 reference_id, + const std::string& session_id) { + status_ = static_cast<Status>(status_ | kCreated); + session_id_ = session_id; } -void ClearKeyCdm::Client::KeyError(uint32 reference_id, - media::MediaKeys::KeyError error_code, - int system_code) { - status_ = static_cast<Status>(status_ | kKeyError); - error_code_ = error_code; - system_code_ = system_code; +void ClearKeyCdm::Client::OnSessionMessage(uint32 reference_id, + const std::vector<uint8>& message, + const std::string& destination_url) { + status_ = static_cast<Status>(status_ | kMessage); + message_ = message; + destination_url_ = destination_url; } -void ClearKeyCdm::Client::KeyMessage(uint32 reference_id, - const std::vector<uint8>& message, - const std::string& default_url) { - status_ = static_cast<Status>(status_ | kKeyMessage); - key_message_ = message; - default_url_ = default_url; +void ClearKeyCdm::Client::OnSessionReady(uint32 reference_id) { + status_ = static_cast<Status>(status_ | kReady); } -void ClearKeyCdm::Client::SetSessionId(uint32 reference_id, - const std::string& session_id) { - status_ = static_cast<Status>(status_ | kSetSessionId); - session_id_ = session_id; +void ClearKeyCdm::Client::OnSessionClosed(uint32 reference_id) { + status_ = static_cast<Status>(status_ | kClosed); +} + +void ClearKeyCdm::Client::OnSessionError(uint32 reference_id, + media::MediaKeys::KeyError error_code, + int system_code) { + status_ = static_cast<Status>(status_ | kError); + error_code_ = error_code; + system_code_ = system_code; } ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host, bool is_decrypt_only) - : decryptor_(base::Bind(&Client::KeyAdded, base::Unretained(&client_)), - base::Bind(&Client::KeyError, base::Unretained(&client_)), - base::Bind(&Client::KeyMessage, base::Unretained(&client_)), - base::Bind(&Client::SetSessionId, base::Unretained(&client_))), + : decryptor_( + base::Bind(&Client::OnSessionCreated, base::Unretained(&client_)), + base::Bind(&Client::OnSessionMessage, base::Unretained(&client_)), + base::Bind(&Client::OnSessionReady, base::Unretained(&client_)), + base::Bind(&Client::OnSessionClosed, base::Unretained(&client_)), + base::Bind(&Client::OnSessionError, base::Unretained(&client_))), host_(host), is_decrypt_only_(is_decrypt_only), timer_delay_ms_(kInitialTimerDelayMs), @@ -230,11 +236,11 @@ cdm::Status ClearKeyCdm::GenerateKeyRequest(const char* type, DVLOG(1) << "GenerateKeyRequest()"; base::AutoLock auto_lock(client_lock_); ScopedResetter<Client> auto_resetter(&client_); - decryptor_.GenerateKeyRequest(MediaKeys::kInvalidReferenceId, - std::string(type, type_size), - init_data, init_data_size); + decryptor_.CreateSession(MediaKeys::kInvalidReferenceId, + std::string(type, type_size), + init_data, init_data_size); - if (client_.status() != (Client::kKeyMessage | Client::kSetSessionId)) { + if (client_.status() != (Client::kMessage | Client::kCreated)) { // Use values returned to client if possible. host_->SendKeyError(client_.session_id().data(), client_.session_id().size(), @@ -245,9 +251,9 @@ cdm::Status ClearKeyCdm::GenerateKeyRequest(const char* type, host_->SendKeyMessage( client_.session_id().data(), client_.session_id().size(), - reinterpret_cast<const char*>(&client_.key_message()[0]), - client_.key_message().size(), - client_.default_url().data(), client_.default_url().size()); + reinterpret_cast<const char*>(&client_.message()[0]), + client_.message().size(), + client_.destination_url().data(), client_.destination_url().size()); // Only save the latest session ID for heartbeat messages. heartbeat_session_id_ = client_.session_id(); @@ -262,13 +268,12 @@ cdm::Status ClearKeyCdm::AddKey(const char* session_id, const uint8_t* key_id, uint32_t key_id_size) { DVLOG(1) << "AddKey()"; + DCHECK(!key_id && !key_id_size); base::AutoLock auto_lock(client_lock_); ScopedResetter<Client> auto_resetter(&client_); - decryptor_.AddKey(MediaKeys::kInvalidReferenceId, - key, key_size, - key_id, key_id_size); + decryptor_.UpdateSession(MediaKeys::kInvalidReferenceId, key, key_size); - if (client_.status() != Client::kKeyAdded) { + if (client_.status() != Client::kReady) { host_->SendKeyError(session_id, session_id_size, static_cast<cdm::MediaKeyError>(client_.error_code()), client_.system_code()); @@ -288,11 +293,11 @@ cdm::Status ClearKeyCdm::CancelKeyRequest(const char* session_id, DVLOG(1) << "CancelKeyRequest()"; base::AutoLock auto_lock(client_lock_); ScopedResetter<Client> auto_resetter(&client_); - decryptor_.CancelKeyRequest(MediaKeys::kInvalidReferenceId); + decryptor_.ReleaseSession(MediaKeys::kInvalidReferenceId); - // No message normally sent by CancelKeyRequest(), but if an error occurred, + // No message normally sent by Release(), but if an error occurred, // report it as a failure. - if (client_.status() == Client::kKeyError) { + if (client_.status() == Client::kError) { host_->SendKeyError(session_id, session_id_size, static_cast<cdm::MediaKeyError>(client_.error_code()), client_.system_code()); diff --git a/media/cdm/ppapi/clear_key_cdm.h b/media/cdm/ppapi/clear_key_cdm.h index 6ef4e04..4c5cb34 100644 --- a/media/cdm/ppapi/clear_key_cdm.h +++ b/media/cdm/ppapi/clear_key_cdm.h @@ -75,10 +75,11 @@ class ClearKeyCdm : public ClearKeyCdmInterface { // interface supports reference_id passing completely. enum Status { kNone = 0, - kKeyAdded = 1 << 0, - kKeyError = 1 << 1, - kKeyMessage = 1 << 2, - kSetSessionId = 1 << 3 + kCreated = 1 << 0, + kMessage = 1 << 1, + kReady = 1 << 2, + kClosed = 1 << 3, + kError = 1 << 4 }; Client(); @@ -86,28 +87,29 @@ class ClearKeyCdm : public ClearKeyCdmInterface { Status status() { return status_; } const std::string& session_id() { return session_id_; } - const std::vector<uint8>& key_message() { return key_message_; } - const std::string& default_url() { return default_url_; } + const std::vector<uint8>& message() { return message_; } + const std::string& destination_url() { return destination_url_; } MediaKeys::KeyError error_code() { return error_code_; } int system_code() { return system_code_; } // Resets the Client to a clean state. void Reset(); - void KeyAdded(uint32 reference_id); - void KeyError(uint32 reference_id, - MediaKeys::KeyError error_code, - int system_code); - void KeyMessage(uint32 reference_id, - const std::vector<uint8>& message, - const std::string& default_url); - void SetSessionId(uint32 reference_id, const std::string& session_id); + void OnSessionCreated(uint32 reference_id, const std::string& session_id); + void OnSessionMessage(uint32 reference_id, + const std::vector<uint8>& message, + const std::string& destination_url); + void OnSessionReady(uint32 reference_id); + void OnSessionClosed(uint32 reference_id); + void OnSessionError(uint32 reference_id, + MediaKeys::KeyError error_code, + int system_code); private: Status status_; std::string session_id_; - std::vector<uint8> key_message_; - std::string default_url_; + std::vector<uint8> message_; + std::string destination_url_; MediaKeys::KeyError error_code_; int system_code_; }; diff --git a/media/cdm/ppapi/clear_key_cdm_common.h b/media/cdm/ppapi/clear_key_cdm_common.h index d6ed59b..8f84397 100644 --- a/media/cdm/ppapi/clear_key_cdm_common.h +++ b/media/cdm/ppapi/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 ClearKeyCdmInterface; +typedef cdm::ContentDecryptionModule_2 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 085eaf44..04723d8 100644 --- a/media/cdm/ppapi/supported_cdm_versions.h +++ b/media/cdm/ppapi/supported_cdm_versions.h @@ -21,12 +21,12 @@ bool IsSupportedCdmModuleVersion(int version) { bool IsSupportedCdmInterfaceVersion(int version) { COMPILE_ASSERT(cdm::ContentDecryptionModule::kVersion == - cdm::ContentDecryptionModule_2::kVersion, + cdm::ContentDecryptionModule_3::kVersion, update_code_below); switch(version) { - // Latest. - case cdm::ContentDecryptionModule::kVersion: - // Older supported versions. + // Supported versions in decreasing order. + case cdm::ContentDecryptionModule_3::kVersion: + case cdm::ContentDecryptionModule_2::kVersion: case cdm::ContentDecryptionModule_1::kVersion: return true; default: @@ -36,12 +36,13 @@ bool IsSupportedCdmInterfaceVersion(int version) { bool IsSupportedCdmHostVersion(int version) { COMPILE_ASSERT(cdm::ContentDecryptionModule::Host::kVersion == - cdm::ContentDecryptionModule_2::Host::kVersion, + cdm::ContentDecryptionModule_3::Host::kVersion, update_code_below); switch(version) { - // Supported versions in increasing order (there is no default). - case cdm::Host_1::kVersion: + // Supported versions in decreasing order. + case cdm::Host_3::kVersion: case cdm::Host_2::kVersion: + case cdm::Host_1::kVersion: return true; default: return false; |