From 107145c693d1544e8392e8fa847dde7d66a5fbf5 Mon Sep 17 00:00:00 2001 From: Kongqun Yang Date: Tue, 15 Apr 2014 15:18:26 -0700 Subject: [PATCH] Refactor EncryptorSource to prepare for live support Remove Initialize() and Add AddKey(). Also remove fixed_encryptor_source.* and move the functionality to encryptor_source.*. Change-Id: I4fb61013177874a8b81854f10b2deda83accc683 --- media/base/encryptor_source.cc | 111 ++++++++++++--- media/base/encryptor_source.h | 79 ++++++----- media/base/media_base.gyp | 2 - media/base/widevine_encryptor_source.cc | 114 ++++++++-------- media/base/widevine_encryptor_source.h | 26 ++-- .../widevine_encryptor_source_unittest.cc | 129 +++++++++++------- 6 files changed, 294 insertions(+), 167 deletions(-) diff --git a/media/base/encryptor_source.cc b/media/base/encryptor_source.cc index 3a122bba1d..4896ba20ad 100644 --- a/media/base/encryptor_source.cc +++ b/media/base/encryptor_source.cc @@ -6,12 +6,11 @@ #include "media/base/encryptor_source.h" +#include "base/strings/string_number_conversions.h" #include "media/base/aes_encryptor.h" +#include "media/base/buffer_writer.h" namespace { -// Generate 64bit IV by default. -const size_t kDefaultIvSize = 8u; - const uint8 kWidevineSystemId[] = {0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, 0x4a, 0xce, 0xa3, 0xc8, 0x27, 0xdc, 0xd5, 0x1d, 0x21, 0xed}; @@ -19,23 +18,103 @@ const uint8 kWidevineSystemId[] = {0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, namespace media { -EncryptorSource::EncryptorSource() - : iv_size_(kDefaultIvSize), - key_system_id_(kWidevineSystemId, - kWidevineSystemId + arraysize(kWidevineSystemId)) {} +EncryptionKey::EncryptionKey() {} +EncryptionKey::~EncryptionKey() {} EncryptorSource::~EncryptorSource() {} -scoped_ptr EncryptorSource::CreateEncryptor() { - scoped_ptr encryptor(new AesCtrEncryptor()); - const bool initialized = - iv_.empty() ? encryptor->InitializeWithRandomIv(key_, iv_size_) - : encryptor->InitializeWithIv(key_, iv_); - if (!initialized) { - LOG(ERROR) << "Failed to the initialize encryptor."; - return scoped_ptr(); +Status EncryptorSource::GetKey(TrackType track_type, EncryptionKey* key) { + DCHECK(key); + DCHECK(encryption_key_); + *key = *encryption_key_; + return Status::OK; +} + +scoped_ptr EncryptorSource::CreateFromHexStrings( + const std::string& key_id_hex, + const std::string& key_hex, + const std::string& pssh_data_hex, + const std::string& iv_hex) { + scoped_ptr encryption_key(new EncryptionKey()); + + if (!base::HexStringToBytes(key_id_hex, &encryption_key->key_id)) { + LOG(ERROR) << "Cannot parse key_id_hex " << key_id_hex; + return scoped_ptr(); } - return encryptor.Pass(); + + if (!base::HexStringToBytes(key_hex, &encryption_key->key)) { + LOG(ERROR) << "Cannot parse key_hex " << key_hex; + return scoped_ptr(); + } + + std::vector pssh_data; + if (!base::HexStringToBytes(pssh_data_hex, &pssh_data)) { + LOG(ERROR) << "Cannot parse pssh_hex " << pssh_data_hex; + return scoped_ptr(); + } + + if (!iv_hex.empty()) { + if (!base::HexStringToBytes(iv_hex, &encryption_key->iv)) { + LOG(ERROR) << "Cannot parse iv_hex " << iv_hex; + return scoped_ptr(); + } + } + + encryption_key->pssh = PsshBoxFromPsshData(pssh_data); + return scoped_ptr( + new EncryptorSource(encryption_key.Pass())); +} + +EncryptorSource::TrackType EncryptorSource::GetTrackTypeFromString( + const std::string& track_type_string) { + if (track_type_string == "SD") + return TRACK_TYPE_SD; + if (track_type_string == "HD") + return TRACK_TYPE_HD; + if (track_type_string == "AUDIO") + return TRACK_TYPE_AUDIO; + LOG(WARNING) << "Unexpected track type: " << track_type_string; + return TRACK_TYPE_UNKNOWN; +} + +std::string EncryptorSource::TrackTypeToString(TrackType track_type) { + switch (track_type) { + case TRACK_TYPE_SD: + return "SD"; + case TRACK_TYPE_HD: + return "HD"; + case TRACK_TYPE_AUDIO: + return "AUDIO"; + default: + NOTIMPLEMENTED() << "Unknown track type: " << track_type; + return "UNKNOWN"; + } +} + +std::vector EncryptorSource::PsshBoxFromPsshData( + const std::vector& pssh_data) { + const uint8 kPsshFourCC[] = {'p', 's', 's', 'h'}; + const uint32 kVersionAndFlags = 0; + + const uint32 pssh_data_size = pssh_data.size(); + const uint32 total_size = + sizeof(total_size) + sizeof(kPsshFourCC) + sizeof(kVersionAndFlags) + + sizeof(kWidevineSystemId) + sizeof(pssh_data_size) + pssh_data_size; + + BufferWriter writer; + writer.AppendInt(total_size); + writer.AppendArray(kPsshFourCC, sizeof(kPsshFourCC)); + writer.AppendInt(kVersionAndFlags); + writer.AppendArray(kWidevineSystemId, sizeof(kWidevineSystemId)); + writer.AppendInt(pssh_data_size); + writer.AppendVector(pssh_data); + return std::vector(writer.Buffer(), writer.Buffer() + writer.Size()); +} + +EncryptorSource::EncryptorSource() {} +EncryptorSource::EncryptorSource(scoped_ptr encryption_key) + : encryption_key_(encryption_key.Pass()) { + DCHECK(encryption_key_); } } // namespace media diff --git a/media/base/encryptor_source.h b/media/base/encryptor_source.h index 54555cd355..27d4ec7bf8 100644 --- a/media/base/encryptor_source.h +++ b/media/base/encryptor_source.h @@ -10,56 +10,73 @@ #include #include "base/memory/scoped_ptr.h" -#include "media/base/aes_encryptor.h" #include "media/base/status.h" namespace media { -class AesCtrEncryptor; +struct EncryptionKey { + EncryptionKey(); + ~EncryptionKey(); + + std::vector key_id; + std::vector key; + std::vector pssh; + std::vector iv; +}; /// EncryptorSource is responsible for encryption key acquisition. class EncryptorSource { public: - EncryptorSource(); + enum TrackType { + TRACK_TYPE_UNKNOWN = 0, + TRACK_TYPE_SD = 1, + TRACK_TYPE_HD = 2, + TRACK_TYPE_AUDIO = 3, + NUM_VALID_TRACK_TYPES = 3 + }; + virtual ~EncryptorSource(); - /// Initialize the encryptor source. Calling other public methods of this - /// class without this method returning OK results in an undefined behavior. - virtual Status Initialize() = 0; + /// Get encryption key of the specified track type. + /// @return OK on success, an error status otherwise. + virtual Status GetKey(TrackType track_type, EncryptionKey* key); - /// Create an encryptor from this encryptor source. The encryptor will be - /// initialized with a random IV of the default size by default. The behavior - /// can be adjusted using set_iv_size or set_iv (exclusive). - scoped_ptr CreateEncryptor(); + /// Create EncryptorSource object from hex strings. + /// @param key_id_hex is the key id in hex string. + /// @param key_hex is the key in hex string. + /// @param pssh_data_hex is the pssh_data in hex string. + /// @param iv_hex is the IV in hex string. If not specified, a randomly + /// generated IV with the default length will be used. + /// Note: GetKey on the created key source will always return the same key + /// for all track types. + static scoped_ptr CreateFromHexStrings( + const std::string& key_id_hex, + const std::string& key_hex, + const std::string& pssh_data_hex, + const std::string& iv_hex); - const std::vector& key_id() const { return key_id_; } - const std::vector& key() const { return key_; } - const std::vector& pssh() const { return pssh_; } - const std::vector& key_system_id() const { return key_system_id_; } - size_t iv_size() const { return iv_.empty() ? iv_size_ : iv_.size(); } + /// Convert string representation of track type to enum representation. + static TrackType GetTrackTypeFromString(const std::string& track_type_string); - /// Set IV size. The encryptor will be initialized with a random IV of the - /// specified size. Mutually exclusive with set_iv. - void set_iv_size(size_t iv_size) { iv_size_ = iv_size; } - /// Set IV. The encryptor will be initialized with the specified IV. - /// Mutually exclusive with set_iv_size. - void set_iv(std::vector& iv) { iv_ = iv; } + /// Convert TrackType to string. + static std::string TrackTypeToString(TrackType track_type); protected: - void set_key_id(const std::vector& key_id) { key_id_ = key_id; } - void set_key(const std::vector& key) { key_ = key; } - void set_pssh(const std::vector& pssh) { pssh_ = pssh; } + EncryptorSource(); + + /// @return the raw bytes of the pssh box with system ID and box header + /// included. + static std::vector PsshBoxFromPsshData( + const std::vector& pssh_data); private: - std::vector key_id_; - std::vector key_; - std::vector pssh_; - size_t iv_size_; - std::vector iv_; - const std::vector key_system_id_; + explicit EncryptorSource(scoped_ptr encryption_key); + + scoped_ptr encryption_key_; DISALLOW_COPY_AND_ASSIGN(EncryptorSource); }; -} + +} // namespace media #endif // MEDIA_BASE_ENCRYPTOR_SOURCE_H_ diff --git a/media/base/media_base.gyp b/media/base/media_base.gyp index 4c38ac2405..aebf02cdcf 100644 --- a/media/base/media_base.gyp +++ b/media/base/media_base.gyp @@ -76,8 +76,6 @@ 'decryptor_source.h', 'encryptor_source.cc', 'encryptor_source.h', - 'fixed_encryptor_source.cc', - 'fixed_encryptor_source.h', 'limits.h', 'media_parser.h', 'media_sample.cc', diff --git a/media/base/widevine_encryptor_source.cc b/media/base/widevine_encryptor_source.cc index 3f43cde920..4eabb6fe57 100644 --- a/media/base/widevine_encryptor_source.cc +++ b/media/base/widevine_encryptor_source.cc @@ -9,6 +9,7 @@ #include "base/base64.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" +#include "base/stl_util.h" #include "base/time/time.h" #include "base/threading/platform_thread.h" #include "base/values.h" @@ -64,9 +65,9 @@ bool GetKeyAndKeyId(const base::DictionaryValue& track_dict, return true; } -bool GetPssh(const base::DictionaryValue& track_dict, - std::vector* pssh) { - DCHECK(pssh); +bool GetPsshData(const base::DictionaryValue& track_dict, + std::vector* pssh_data) { + DCHECK(pssh_data); const base::ListValue* pssh_list; RCHECK(track_dict.GetList("pssh", &pssh_list)); @@ -82,11 +83,11 @@ bool GetPssh(const base::DictionaryValue& track_dict, LOG(ERROR) << "Expecting drm_type 'WIDEVINE', get '" << drm_type << "'."; return false; } - std::string pssh_base64_string; - RCHECK(pssh_dict->GetString("data", &pssh_base64_string)); + std::string pssh_data_base64_string; + RCHECK(pssh_dict->GetString("data", &pssh_data_base64_string)); - VLOG(2) << "Pssh:" << pssh_base64_string; - RCHECK(Base64StringToBytes(pssh_base64_string, pssh)); + VLOG(2) << "Pssh Data:" << pssh_data_base64_string; + RCHECK(Base64StringToBytes(pssh_data_base64_string, pssh_data)); return true; } @@ -97,18 +98,47 @@ namespace media { WidevineEncryptorSource::WidevineEncryptorSource( const std::string& server_url, const std::string& content_id, - TrackType track_type, scoped_ptr signer) : http_fetcher_(new SimpleHttpFetcher()), server_url_(server_url), content_id_(content_id), - track_type_(track_type), - signer_(signer.Pass()) { + signer_(signer.Pass()), + key_fetched_(false) { DCHECK(signer_); } -WidevineEncryptorSource::~WidevineEncryptorSource() {} +WidevineEncryptorSource::~WidevineEncryptorSource() { + STLDeleteValues(&encryption_key_map_); +} -Status WidevineEncryptorSource::Initialize() { +Status WidevineEncryptorSource::GetKey(TrackType track_type, + EncryptionKey* key) { + DCHECK(track_type == TRACK_TYPE_SD || track_type == TRACK_TYPE_HD || + track_type == TRACK_TYPE_AUDIO); + Status status; + if (!key_fetched_) { + base::AutoLock auto_lock(lock_); + if (!key_fetched_) { + status = FetchKeys(); + if (status.ok()) + key_fetched_ = true; + } + } + if (!status.ok()) + return status; + if (encryption_key_map_.find(track_type) == encryption_key_map_.end()) { + return Status(error::INTERNAL_ERROR, + "Cannot find key of type " + TrackTypeToString(track_type)); + } + *key = *encryption_key_map_[track_type]; + return Status::OK; +} + +void WidevineEncryptorSource::set_http_fetcher( + scoped_ptr http_fetcher) { + http_fetcher_ = http_fetcher.Pass(); +} + +Status WidevineEncryptorSource::FetchKeys() { std::string request; FillRequest(content_id_, &request); @@ -156,24 +186,6 @@ Status WidevineEncryptorSource::Initialize() { "Failed to recover from server internal error."); } -WidevineEncryptorSource::TrackType -WidevineEncryptorSource::GetTrackTypeFromString( - const std::string& track_type_string) { - if (track_type_string == "SD") - return TRACK_TYPE_SD; - if (track_type_string == "HD") - return TRACK_TYPE_HD; - if (track_type_string == "AUDIO") - return TRACK_TYPE_AUDIO; - LOG(WARNING) << "Unexpected track type: " << track_type_string; - return TRACK_TYPE_UNKNOWN; -} - -void WidevineEncryptorSource::set_http_fetcher( - scoped_ptr http_fetcher) { - http_fetcher_ = http_fetcher.Pass(); -} - void WidevineEncryptorSource::FillRequest(const std::string& content_id, std::string* request) { DCHECK(request); @@ -252,11 +264,6 @@ bool WidevineEncryptorSource::DecodeResponse(const std::string& raw_response, return true; } -bool WidevineEncryptorSource::IsExpectedTrackType( - const std::string& track_type_string) { - return track_type_ == GetTrackTypeFromString(track_type_string); -} - bool WidevineEncryptorSource::ExtractEncryptionKey(const std::string& response, bool* transient_error) { DCHECK(transient_error); @@ -281,33 +288,28 @@ bool WidevineEncryptorSource::ExtractEncryptionKey(const std::string& response, const base::ListValue* tracks; RCHECK(license_dict->GetList("tracks", &tracks)); + RCHECK(tracks->GetSize() >= NUM_VALID_TRACK_TYPES); - for (base::ListValue::const_iterator it = tracks->begin(); - it != tracks->end(); - ++it) { + for (size_t i = 0; i < tracks->GetSize(); ++i) { const base::DictionaryValue* track_dict; - RCHECK((*it)->GetAsDictionary(&track_dict)); + RCHECK(tracks->GetDictionary(i, &track_dict)); - std::string track_type; - RCHECK(track_dict->GetString("type", &track_type)); - if (!IsExpectedTrackType(track_type)) - continue; + std::string track_type_str; + RCHECK(track_dict->GetString("type", &track_type_str)); + TrackType track_type = GetTrackTypeFromString(track_type_str); + DCHECK_NE(TRACK_TYPE_UNKNOWN, track_type); + RCHECK(encryption_key_map_.find(track_type) == encryption_key_map_.end()); - std::vector key_id; - std::vector key; - std::vector pssh; - if (!GetKeyAndKeyId(*track_dict, &key, &key_id) || - !GetPssh(*track_dict, &pssh)) + scoped_ptr encryption_key(new EncryptionKey()); + std::vector pssh_data; + if (!GetKeyAndKeyId(*track_dict, &encryption_key->key, + &encryption_key->key_id) || + !GetPsshData(*track_dict, &pssh_data)) return false; - - set_key_id(key_id); - set_key(key); - set_pssh(pssh); - return true; + encryption_key->pssh = PsshBoxFromPsshData(pssh_data); + encryption_key_map_[track_type] = encryption_key.release(); } - LOG(ERROR) << "Cannot find key of type " << track_type_ << " from '" - << response << "'."; - return false; + return true; } } // namespace media diff --git a/media/base/widevine_encryptor_source.h b/media/base/widevine_encryptor_source.h index 0a6c8d724b..e6ec07c85b 100644 --- a/media/base/widevine_encryptor_source.h +++ b/media/base/widevine_encryptor_source.h @@ -7,8 +7,11 @@ #ifndef MEDIA_BASE_WIDEVINE_ENCRYPTOR_SOURCE_H_ #define MEDIA_BASE_WIDEVINE_ENCRYPTOR_SOURCE_H_ +#include + #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" +#include "base/synchronization/lock.h" #include "media/base/encryptor_source.h" namespace media { @@ -19,34 +22,25 @@ class RequestSigner; /// Encryptor source which talks to the Widevine encryption service. class WidevineEncryptorSource : public EncryptorSource { public: - enum TrackType { - TRACK_TYPE_UNKNOWN = 0, - TRACK_TYPE_SD, - TRACK_TYPE_HD, - TRACK_TYPE_AUDIO - }; - /// @param server_url is the Widevine common encryption server url. /// @param content_id the unique id identify the content to be encrypted. - /// @param track_type is the content type, can be AUDIO, SD or HD. /// @param signer must not be NULL. WidevineEncryptorSource(const std::string& server_url, const std::string& content_id, - TrackType track_type, scoped_ptr signer); virtual ~WidevineEncryptorSource(); /// EncryptorSource implementation override. - virtual Status Initialize() OVERRIDE; + virtual Status GetKey(TrackType track_type, EncryptionKey* key) OVERRIDE; /// Inject an @b HttpFetcher object, mainly used for testing. /// @param http_fetcher points to the @b HttpFetcher object to be injected. void set_http_fetcher(scoped_ptr http_fetcher); - static WidevineEncryptorSource::TrackType GetTrackTypeFromString( - const std::string& track_type_string); - private: + // Fetch keys from server. + Status FetchKeys(); + // Fill |request| with necessary fields for Widevine encryption request. // |request| should not be NULL. void FillRequest(const std::string& content_id, std::string* request); @@ -56,7 +50,6 @@ class WidevineEncryptorSource : public EncryptorSource { // Decode |response| from JSON formatted |raw_response|. // |response| should not be NULL. bool DecodeResponse(const std::string& raw_response, std::string* response); - bool IsExpectedTrackType(const std::string& track_type_string); // Extract encryption key from |response|, which is expected to be properly // formatted. |transient_error| will be set to true if it fails and the // failure is because of a transient error from the server. |transient_error| @@ -70,9 +63,12 @@ class WidevineEncryptorSource : public EncryptorSource { scoped_ptr http_fetcher_; std::string server_url_; std::string content_id_; - TrackType track_type_; scoped_ptr signer_; + mutable base::Lock lock_; + bool key_fetched_; // Protected by lock_; + std::map encryption_key_map_; + DISALLOW_COPY_AND_ASSIGN(WidevineEncryptorSource); }; diff --git a/media/base/widevine_encryptor_source_unittest.cc b/media/base/widevine_encryptor_source_unittest.cc index cb40cd30c7..3392dd453d 100644 --- a/media/base/widevine_encryptor_source_unittest.cc +++ b/media/base/widevine_encryptor_source_unittest.cc @@ -17,16 +17,11 @@ namespace { const char kServerUrl[] = "http://www.foo.com/getcontentkey"; const char kContentId[] = "ContentFoo"; -const char kTrackType[] = "SD"; const char kSignerName[] = "SignerFoo"; const char kMockSignature[] = "MockSignature"; -const char kMockKeyId[] = "MockKeyId"; -const char kMockKey[] = "MockKey"; -const char kMockPsshData[] = "MockPsshData"; - -// The lisence service may return an error indicating a transient error has +// The license service may return an error indicating a transient error has // just happened in the server, or other types of errors. // WidevineEncryptorSource will perform a number of retries on transient errors; // WidevineEncryptorSource does not know about other errors and retries are not @@ -39,11 +34,11 @@ const char kExpectedRequestMessageFormat[] = "\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"AUDIO\"}]}"; const char kExpectedSignedMessageFormat[] = "{\"request\":\"%s\",\"signature\":\"%s\",\"signer\":\"%s\"}"; -const char kLicenseOkResponseFormat[] = - "{\"status\":\"OK\",\"tracks\":[{\"type\":\"%s\",\"key_id\":\"%s\",\"key\":" - "\"%s\",\"pssh\":[{\"drm_type\":\"WIDEVINE\",\"data\":\"%s\"}]}]}"; -const char kLicenseErrorResponseFormat[] = - "{\"status\":\"%s\",\"drm\":[],\"tracks\":[]}"; +const char kTrackFormat[] = + "{\"type\":\"%s\",\"key_id\":\"%s\",\"key\":" + "\"%s\",\"pssh\":[{\"drm_type\":\"WIDEVINE\",\"data\":\"%s\"}]}"; +const char kLicenseResponseFormat[] = + "{\"status\":\"%s\",\"tracks\":[%s]}"; const char kHttpResponseFormat[] = "{\"response\":\"%s\"}"; std::string Base64Encode(const std::string& input) { @@ -55,6 +50,41 @@ std::string Base64Encode(const std::string& input) { std::string ToString(const std::vector v) { return std::string(v.begin(), v.end()); } + +std::string GetMockKeyId(const std::string& track_type) { + return "MockKeyId" + track_type; +} + +std::string GetMockKey(const std::string& track_type) { + return "MockKey" + track_type; +} + +std::string GetMockPsshData(const std::string& track_type) { + return "MockPsshData" + track_type; +} + +std::string GenerateMockLicenseResponse() { + const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"}; + std::string tracks; + for (size_t i = 0; i < 3; ++i) { + if (!tracks.empty()) + tracks += ","; + tracks += base::StringPrintf( + kTrackFormat, + kTrackTypes[i].c_str(), + Base64Encode(GetMockKeyId(kTrackTypes[i])).c_str(), + Base64Encode(GetMockKey(kTrackTypes[i])).c_str(), + Base64Encode(GetMockPsshData(kTrackTypes[i])).c_str()); + } + return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str()); +} + +std::string GetPsshDataFromPsshBox(const std::string& pssh_box) { + const size_t kPsshDataOffset = 32u; + DCHECK_LT(kPsshDataOffset, pssh_box.size()); + return pssh_box.substr(kPsshDataOffset); +} + } // namespace using ::testing::_; @@ -103,7 +133,6 @@ class WidevineEncryptorSourceTest : public ::testing::Test { widevine_encryptor_source_.reset(new WidevineEncryptorSource( kServerUrl, kContentId, - WidevineEncryptorSource::GetTrackTypeFromString(kTrackType), mock_request_signer_.PassAs())); widevine_encryptor_source_->set_http_fetcher( mock_http_fetcher_.PassAs()); @@ -118,14 +147,14 @@ class WidevineEncryptorSourceTest : public ::testing::Test { }; TEST_F(WidevineEncryptorSourceTest, GetTrackTypeFromString) { - EXPECT_EQ(WidevineEncryptorSource::TRACK_TYPE_SD, - WidevineEncryptorSource::GetTrackTypeFromString("SD")); - EXPECT_EQ(WidevineEncryptorSource::TRACK_TYPE_HD, - WidevineEncryptorSource::GetTrackTypeFromString("HD")); - EXPECT_EQ(WidevineEncryptorSource::TRACK_TYPE_AUDIO, - WidevineEncryptorSource::GetTrackTypeFromString("AUDIO")); - EXPECT_EQ(WidevineEncryptorSource::TRACK_TYPE_UNKNOWN, - WidevineEncryptorSource::GetTrackTypeFromString("FOO")); + EXPECT_EQ(EncryptorSource::TRACK_TYPE_SD, + EncryptorSource::GetTrackTypeFromString("SD")); + EXPECT_EQ(EncryptorSource::TRACK_TYPE_HD, + EncryptorSource::GetTrackTypeFromString("HD")); + EXPECT_EQ(EncryptorSource::TRACK_TYPE_AUDIO, + EncryptorSource::GetTrackTypeFromString("AUDIO")); + EXPECT_EQ(EncryptorSource::TRACK_TYPE_UNKNOWN, + EncryptorSource::GetTrackTypeFromString("FOO")); } TEST_F(WidevineEncryptorSourceTest, GeneratureSignatureFailure) { @@ -133,8 +162,10 @@ TEST_F(WidevineEncryptorSourceTest, GeneratureSignatureFailure) { .WillOnce(Return(false)); CreateWidevineEncryptorSource(); + EncryptionKey encryption_key; ASSERT_EQ(Status(error::INTERNAL_ERROR, "Signature generation failed."), - widevine_encryptor_source_->Initialize()); + widevine_encryptor_source_->GetKey(EncryptorSource::TRACK_TYPE_SD, + &encryption_key)); } // Check whether expected request message and post data was generated and @@ -155,30 +186,35 @@ TEST_F(WidevineEncryptorSourceTest, HttpPostFailure) { .WillOnce(Return(kMockStatus)); CreateWidevineEncryptorSource(); - ASSERT_EQ(kMockStatus, widevine_encryptor_source_->Initialize()); + EncryptionKey encryption_key; + ASSERT_EQ(kMockStatus, + widevine_encryptor_source_->GetKey(EncryptorSource::TRACK_TYPE_SD, + &encryption_key)); } TEST_F(WidevineEncryptorSourceTest, LicenseStatusOK) { EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _)) .WillOnce(Return(true)); - std::string mock_license_status = - base::StringPrintf(kLicenseOkResponseFormat, - kTrackType, - Base64Encode(kMockKeyId).c_str(), - Base64Encode(kMockKey).c_str(), - Base64Encode(kMockPsshData).c_str()); std::string expected_response = base::StringPrintf( - kHttpResponseFormat, Base64Encode(mock_license_status).c_str()); + kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str()); EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _)) .WillOnce(DoAll(SetArgPointee<2>(expected_response), Return(Status::OK))); CreateWidevineEncryptorSource(); - ASSERT_OK(widevine_encryptor_source_->Initialize()); - EXPECT_EQ(kMockKeyId, ToString(widevine_encryptor_source_->key_id())); - EXPECT_EQ(kMockKey, ToString(widevine_encryptor_source_->key())); - EXPECT_EQ(kMockPsshData, ToString(widevine_encryptor_source_->pssh())); + + EncryptionKey encryption_key; + const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"}; + for (size_t i = 0; i < 3; ++i) { + ASSERT_OK(widevine_encryptor_source_->GetKey( + EncryptorSource::GetTrackTypeFromString(kTrackTypes[i]), + &encryption_key)); + EXPECT_EQ(GetMockKeyId(kTrackTypes[i]), ToString(encryption_key.key_id)); + EXPECT_EQ(GetMockKey(kTrackTypes[i]), ToString(encryption_key.key)); + EXPECT_EQ(GetMockPsshData(kTrackTypes[i]), + GetPsshDataFromPsshBox(ToString(encryption_key.pssh))); + } } TEST_F(WidevineEncryptorSourceTest, RetryOnTransientError) { @@ -186,18 +222,12 @@ TEST_F(WidevineEncryptorSourceTest, RetryOnTransientError) { .WillOnce(Return(true)); std::string mock_license_status = base::StringPrintf( - kLicenseErrorResponseFormat, kLicenseStatusTransientError); + kLicenseResponseFormat, kLicenseStatusTransientError, ""); std::string expected_response = base::StringPrintf( kHttpResponseFormat, Base64Encode(mock_license_status).c_str()); - std::string mock_retried_license_status = - base::StringPrintf(kLicenseOkResponseFormat, - kTrackType, - Base64Encode(kMockKeyId).c_str(), - Base64Encode(kMockKey).c_str(), - Base64Encode(kMockPsshData).c_str()); std::string expected_retried_response = base::StringPrintf( - kHttpResponseFormat, Base64Encode(mock_retried_license_status).c_str()); + kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str()); // Retry is expected on transient error. EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _)) @@ -206,10 +236,13 @@ TEST_F(WidevineEncryptorSourceTest, RetryOnTransientError) { Return(Status::OK))); CreateWidevineEncryptorSource(); - ASSERT_OK(widevine_encryptor_source_->Initialize()); - EXPECT_EQ(kMockKeyId, ToString(widevine_encryptor_source_->key_id())); - EXPECT_EQ(kMockKey, ToString(widevine_encryptor_source_->key())); - EXPECT_EQ(kMockPsshData, ToString(widevine_encryptor_source_->pssh())); + EncryptionKey encryption_key; + ASSERT_OK(widevine_encryptor_source_->GetKey(EncryptorSource::TRACK_TYPE_SD, + &encryption_key)); + EXPECT_EQ(GetMockKeyId("SD"), ToString(encryption_key.key_id)); + EXPECT_EQ(GetMockKey("SD"), ToString(encryption_key.key)); + EXPECT_EQ(GetMockPsshData("SD"), + GetPsshDataFromPsshBox(ToString(encryption_key.pssh))); } TEST_F(WidevineEncryptorSourceTest, NoRetryOnUnknownError) { @@ -217,7 +250,7 @@ TEST_F(WidevineEncryptorSourceTest, NoRetryOnUnknownError) { .WillOnce(Return(true)); std::string mock_license_status = base::StringPrintf( - kLicenseErrorResponseFormat, kLicenseStatusUnknownError); + kLicenseResponseFormat, kLicenseStatusUnknownError, ""); std::string mock_response = base::StringPrintf( kHttpResponseFormat, Base64Encode(mock_license_status).c_str()); @@ -225,8 +258,10 @@ TEST_F(WidevineEncryptorSourceTest, NoRetryOnUnknownError) { .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); CreateWidevineEncryptorSource(); + EncryptionKey encryption_key; ASSERT_EQ(error::SERVER_ERROR, - widevine_encryptor_source_->Initialize().error_code()); + widevine_encryptor_source_->GetKey(EncryptorSource::TRACK_TYPE_SD, + &encryption_key).error_code()); } } // namespace media