diff --git a/packager/app/packager_main.cc b/packager/app/packager_main.cc index a7edc35fbf..fd3fd28965 100644 --- a/packager/app/packager_main.cc +++ b/packager/app/packager_main.cc @@ -496,7 +496,8 @@ bool RunPackager(const StreamDescriptorList& stream_descriptors) { FLAGS_enable_playready_encryption) { if (encryption_options.protection_scheme == FOURCC_NULL) return false; - encryption_key_source = CreateEncryptionKeySource(); + encryption_key_source = + CreateEncryptionKeySource(encryption_options.protection_scheme); if (!encryption_key_source) return false; } diff --git a/packager/app/packager_util.cc b/packager/app/packager_util.cc index 323615801d..87b6858daa 100644 --- a/packager/app/packager_util.cc +++ b/packager/app/packager_util.cc @@ -88,11 +88,12 @@ std::unique_ptr CreateSigner() { return signer; } -std::unique_ptr CreateEncryptionKeySource() { +std::unique_ptr CreateEncryptionKeySource(FourCC protection_scheme) { std::unique_ptr encryption_key_source; if (FLAGS_enable_widevine_encryption) { std::unique_ptr widevine_key_source( new WidevineKeySource(FLAGS_key_server_url, FLAGS_include_common_pssh)); + widevine_key_source->set_protection_scheme(protection_scheme); if (!FLAGS_signer.empty()) { std::unique_ptr request_signer(CreateSigner()); if (!request_signer) diff --git a/packager/app/packager_util.h b/packager/app/packager_util.h index 604550dc18..77dd951e77 100644 --- a/packager/app/packager_util.h +++ b/packager/app/packager_util.h @@ -13,6 +13,8 @@ #include +#include "packager/media/base/fourccs.h" + DECLARE_bool(dump_stream_info); namespace shaka { @@ -30,9 +32,11 @@ struct MuxerOptions; /// Create KeySource based on provided command line options for content /// encryption. Also fetches keys. +/// @param protection_scheme specifies the protection scheme to be used for +/// encryption. /// @return A std::unique_ptr containing a new KeySource, or nullptr if /// encryption is not required. -std::unique_ptr CreateEncryptionKeySource(); +std::unique_ptr CreateEncryptionKeySource(FourCC protection_scheme); /// Create KeySource based on provided command line options for content /// decryption. Does not fetch keys. diff --git a/packager/media/base/widevine_key_source.cc b/packager/media/base/widevine_key_source.cc index 0d8f40c037..57df7e7f90 100644 --- a/packager/media/base/widevine_key_source.cc +++ b/packager/media/base/widevine_key_source.cc @@ -12,6 +12,7 @@ #include "packager/base/bind.h" #include "packager/base/json/json_reader.h" #include "packager/base/json/json_writer.h" +#include "packager/base/strings/string_number_conversions.h" #include "packager/media/base/fixed_key_source.h" #include "packager/media/base/http_key_fetcher.h" #include "packager/media/base/network_util.h" @@ -22,6 +23,7 @@ #include "packager/media/base/widevine_pssh_data.pb.h" namespace shaka { +namespace media { namespace { const bool kEnableKeyRotation = true; @@ -118,9 +120,12 @@ bool GetPsshDataFromTrack(const base::DictionaryValue& track_dict, return true; } -} // namespace +bool IsProtectionSchemeValid(FourCC protection_scheme) { + return protection_scheme == FOURCC_cenc || protection_scheme == FOURCC_cbcs || + protection_scheme == FOURCC_cbc1 || protection_scheme == FOURCC_cens; +} -namespace media { +} // namespace WidevineKeySource::WidevineKeySource(const std::string& server_url, bool add_common_pssh) @@ -130,6 +135,7 @@ WidevineKeySource::WidevineKeySource(const std::string& server_url, key_fetcher_(new HttpKeyFetcher(kKeyFetchTimeoutInSeconds)), server_url_(server_url), crypto_period_count_(kDefaultCryptoPeriodCount), + protection_scheme_(FOURCC_cenc), add_common_pssh_(add_common_pssh), key_production_started_(false), start_key_production_(base::WaitableEvent::ResetPolicy::AUTOMATIC, @@ -157,6 +163,18 @@ Status WidevineKeySource::FetchKeys(const std::vector& content_id, BytesToBase64String(content_id, &content_id_base64_string); request_dict_.SetString("content_id", content_id_base64_string); request_dict_.SetString("policy", policy); + + FourCC protection_scheme = protection_scheme_; + // Treat sample aes as a variant of cbcs. + if (protection_scheme == kAppleSampleAesProtectionScheme) + protection_scheme = FOURCC_cbcs; + if (IsProtectionSchemeValid(protection_scheme)) { + request_dict_.SetInteger("protection_scheme", protection_scheme); + } else { + LOG(WARNING) << "Ignore unrecognized protection scheme " + << FourCCToString(protection_scheme); + } + return FetchKeysInternal(!kEnableKeyRotation, 0, false); } diff --git a/packager/media/base/widevine_key_source.h b/packager/media/base/widevine_key_source.h index 92c3022565..65a60f43e3 100644 --- a/packager/media/base/widevine_key_source.h +++ b/packager/media/base/widevine_key_source.h @@ -12,6 +12,7 @@ #include "packager/base/synchronization/waitable_event.h" #include "packager/base/values.h" #include "packager/media/base/closure_thread.h" +#include "packager/media/base/fourccs.h" #include "packager/media/base/key_source.h" namespace shaka { @@ -53,6 +54,11 @@ class WidevineKeySource : public KeySource { Status FetchKeys(const std::vector& content_id, const std::string& policy); + /// Set the protection scheme for the key source. + void set_protection_scheme(FourCC protection_scheme) { + protection_scheme_ = protection_scheme; + } + /// Set signer for the key source. /// @param signer signs the request message. void set_signer(std::unique_ptr signer); @@ -61,9 +67,6 @@ class WidevineKeySource : public KeySource { /// @param key_fetcher points to the @b KeyFetcher object to be injected. void set_key_fetcher(std::unique_ptr key_fetcher); - protected: - ClosureThread key_production_thread_; - private: typedef std::map> EncryptionKeyMap; typedef ProducerConsumerQueue> @@ -104,6 +107,7 @@ class WidevineKeySource : public KeySource { // Push the keys to the key pool. bool PushToKeyPool(EncryptionKeyMap* encryption_key_map); + ClosureThread key_production_thread_; // The fetcher object used to fetch keys from the license service. // It is initialized to a default fetcher on class initialization. // Can be overridden using set_key_fetcher for testing or other purposes. @@ -113,6 +117,7 @@ class WidevineKeySource : public KeySource { base::DictionaryValue request_dict_; const uint32_t crypto_period_count_; + FourCC protection_scheme_; base::Lock lock_; bool add_common_pssh_; bool key_production_started_; diff --git a/packager/media/base/widevine_key_source_unittest.cc b/packager/media/base/widevine_key_source_unittest.cc index 6b19fe4077..b9d8ebf203 100644 --- a/packager/media/base/widevine_key_source_unittest.cc +++ b/packager/media/base/widevine_key_source_unittest.cc @@ -19,13 +19,19 @@ #include "packager/media/base/widevine_key_source.h" using ::testing::_; +using ::testing::Bool; +using ::testing::Combine; using ::testing::DoAll; using ::testing::InSequence; using ::testing::Return; using ::testing::SetArgPointee; using ::testing::StrEq; +using ::testing::Test; +using ::testing::Values; +using ::testing::WithParamInterface; namespace shaka { +namespace media { namespace { const char kServerUrl[] = "http://www.foo.com/getcontentkey"; const char kContentId[] = "ContentFoo"; @@ -45,6 +51,7 @@ const char kLicenseStatusUnknownError[] = "UNKNOWN_ERROR"; const char kExpectedRequestMessageFormat[] = "{\"content_id\":\"%s\",\"drm_types\":[\"WIDEVINE\"],\"policy\":\"%s\"," + "\"protection_scheme\":%d," "\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"UHD1\"}," "{\"type\":\"UHD2\"},{\"type\":\"AUDIO\"}]}"; const char kExpectedRequestMessageWithAssetIdFormat[] = @@ -64,11 +71,12 @@ const char kClassicTrackFormat[] = "{\"type\":\"%s\",\"key\":\"%s\"}"; const char kLicenseResponseFormat[] = "{\"status\":\"%s\",\"tracks\":[%s]}"; const char kHttpResponseFormat[] = "{\"response\":\"%s\"}"; const uint8_t kRequestPsshBox[] = { - 0, 0, 0, 41, 'p', 's', 's', 'h', 0, 0, 0, + 0, 0, 0, 44, 'p', 's', 's', 'h', 0, 0, 0, 0, 0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, 0x4a, 0xce, 0xa3, 0xc8, - 0x27, 0xdc, 0xd5, 0x1d, 0x21, 0xed, 0, 0, 0, 0x09, 'P', - 'S', 'S', 'H', ' ', 'd', 'a', 't', 'a'}; -const char kRequestPsshData[] = "PSSH data"; + 0x27, 0xdc, 0xd5, 0x1d, 0x21, 0xed, 0, 0, 0, 12, 0x22, + 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', 'F', 'o', 'o'}; +const char kRequestPsshData[] = {0x22, 0x0a, 'C', 'o', 'n', 't', 'e', + 'n', 't', 'F', 'o', 'o', '\0'}; const uint8_t kRequestPsshDataFromKeyIds[] = {0x12, 0x06, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; const uint8_t kRequestKeyId[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; @@ -98,8 +106,8 @@ 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 GetMockPsshData() { + return kRequestPsshData; } std::string GenerateMockLicenseResponse() { @@ -108,12 +116,11 @@ std::string GenerateMockLicenseResponse() { for (size_t i = 0; i < 5; ++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()); + tracks += + base::StringPrintf(kTrackFormat, kTrackTypes[i].c_str(), + Base64Encode(GetMockKeyId(kTrackTypes[i])).c_str(), + Base64Encode(GetMockKey(kTrackTypes[i])).c_str(), + Base64Encode(GetMockPsshData()).c_str()); } return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str()); } @@ -134,8 +141,6 @@ std::string GenerateMockClassicLicenseResponse() { } // namespace -namespace media { - class MockRequestSigner : public RequestSigner { public: explicit MockRequestSigner(const std::string& signer_name) @@ -163,8 +168,7 @@ class MockKeyFetcher : public KeyFetcher { DISALLOW_COPY_AND_ASSIGN(MockKeyFetcher); }; -class WidevineKeySourceTest : public ::testing::Test, - public ::testing::WithParamInterface { +class WidevineKeySourceTest : public Test { public: WidevineKeySourceTest() : mock_request_signer_(new MockRequestSigner(kSignerName)), @@ -177,8 +181,17 @@ class WidevineKeySourceTest : public ::testing::Test, } protected: + FourCC GetExpectedProtectionScheme() { + // Apple SAMPLE-AES is considered as a variation of cbcs. + if (protection_scheme_ == kAppleSampleAesProtectionScheme) + return FOURCC_cbcs; + return protection_scheme_; + } + void CreateWidevineKeySource() { - widevine_key_source_.reset(new WidevineKeySource(kServerUrl, GetParam())); + widevine_key_source_.reset( + new WidevineKeySource(kServerUrl, add_common_pssh_)); + widevine_key_source_->set_protection_scheme(protection_scheme_); widevine_key_source_->set_key_fetcher(std::move(mock_key_fetcher_)); } @@ -191,13 +204,14 @@ class WidevineKeySourceTest : public ::testing::Test, &encryption_key)); EXPECT_EQ(GetMockKey(kTrackTypes[i]), ToString(encryption_key.key)); if (!classic) { - ASSERT_EQ(GetParam() ? 2u : 1u, encryption_key.key_system_info.size()); + ASSERT_EQ(add_common_pssh_ ? 2u : 1u, + encryption_key.key_system_info.size()); EXPECT_EQ(GetMockKeyId(kTrackTypes[i]), ToString(encryption_key.key_id)); - EXPECT_EQ(GetMockPsshData(kTrackTypes[i]), + EXPECT_EQ(GetMockPsshData(), ToString(encryption_key.key_system_info[0].pssh_data())); - if (GetParam()) { + if (add_common_pssh_) { // Each of the keys contains all the key IDs. const std::vector common_system_id( kCommonSystemId, kCommonSystemId + arraysize(kCommonSystemId)); @@ -222,12 +236,14 @@ class WidevineKeySourceTest : public ::testing::Test, std::unique_ptr mock_key_fetcher_; std::unique_ptr widevine_key_source_; std::vector content_id_; + bool add_common_pssh_ = false; + FourCC protection_scheme_ = FOURCC_cenc; private: DISALLOW_COPY_AND_ASSIGN(WidevineKeySourceTest); }; -TEST_P(WidevineKeySourceTest, GetTrackTypeFromString) { +TEST_F(WidevineKeySourceTest, GetTrackTypeFromString) { EXPECT_EQ(KeySource::TRACK_TYPE_SD, KeySource::GetTrackTypeFromString("SD")); EXPECT_EQ(KeySource::TRACK_TYPE_HD, @@ -242,7 +258,7 @@ TEST_P(WidevineKeySourceTest, GetTrackTypeFromString) { KeySource::GetTrackTypeFromString("FOO")); } -TEST_P(WidevineKeySourceTest, GenerateSignatureFailure) { +TEST_F(WidevineKeySourceTest, GenerateSignatureFailure) { EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _)) .WillOnce(Return(false)); @@ -252,11 +268,70 @@ TEST_P(WidevineKeySourceTest, GenerateSignatureFailure) { widevine_key_source_->FetchKeys(content_id_, kPolicy)); } +TEST_F(WidevineKeySourceTest, RetryOnHttpTimeout) { + std::string mock_response = base::StringPrintf( + kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str()); + + // Retry is expected on HTTP timeout. + EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) + .WillOnce(Return(Status(error::TIME_OUT, ""))) + .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); + + CreateWidevineKeySource(); + ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy)); + VerifyKeys(false); +} + +TEST_F(WidevineKeySourceTest, RetryOnTransientError) { + std::string mock_license_status = base::StringPrintf( + kLicenseResponseFormat, kLicenseStatusTransientError, ""); + std::string mock_response = base::StringPrintf( + kHttpResponseFormat, Base64Encode(mock_license_status).c_str()); + + std::string expected_retried_response = base::StringPrintf( + kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str()); + + // Retry is expected on transient error. + EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) + .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))) + .WillOnce(DoAll(SetArgPointee<2>(expected_retried_response), + Return(Status::OK))); + + CreateWidevineKeySource(); + ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy)); + VerifyKeys(false); +} + +TEST_F(WidevineKeySourceTest, NoRetryOnUnknownError) { + std::string mock_license_status = base::StringPrintf( + kLicenseResponseFormat, kLicenseStatusUnknownError, ""); + std::string mock_response = base::StringPrintf( + kHttpResponseFormat, Base64Encode(mock_license_status).c_str()); + + EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) + .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); + + CreateWidevineKeySource(); + ASSERT_EQ(error::SERVER_ERROR, + widevine_key_source_->FetchKeys(content_id_, kPolicy).error_code()); +} + +class WidevineKeySourceParameterizedTest + : public WidevineKeySourceTest, + public WithParamInterface> { + public: + WidevineKeySourceParameterizedTest() { + add_common_pssh_ = std::tr1::get<0>(GetParam()); + protection_scheme_ = std::tr1::get<1>(GetParam()); + } +}; + // Check whether expected request message and post data was generated and // verify the correct behavior on http failure. -TEST_P(WidevineKeySourceTest, HttpFetchFailure) { +TEST_P(WidevineKeySourceParameterizedTest, HttpFetchFailure) { std::string expected_message = base::StringPrintf( - kExpectedRequestMessageFormat, Base64Encode(kContentId).c_str(), kPolicy); + kExpectedRequestMessageFormat, Base64Encode(kContentId).c_str(), kPolicy, + GetExpectedProtectionScheme()); EXPECT_CALL(*mock_request_signer_, GenerateSignature(StrEq(expected_message), _)) .WillOnce(DoAll(SetArgPointee<1>(kMockSignature), Return(true))); @@ -277,7 +352,7 @@ TEST_P(WidevineKeySourceTest, HttpFetchFailure) { widevine_key_source_->FetchKeys(content_id_, kPolicy)); } -TEST_P(WidevineKeySourceTest, LicenseStatusCencOK) { +TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencOK) { std::string mock_response = base::StringPrintf( kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str()); @@ -289,7 +364,7 @@ TEST_P(WidevineKeySourceTest, LicenseStatusCencOK) { VerifyKeys(false); } -TEST_P(WidevineKeySourceTest, LicenseStatusCencNotOK) { +TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencNotOK) { std::string mock_response = base::StringPrintf( kHttpResponseFormat, Base64Encode( GenerateMockClassicLicenseResponse()).c_str()); @@ -303,7 +378,7 @@ TEST_P(WidevineKeySourceTest, LicenseStatusCencNotOK) { .error_code()); } -TEST_P(WidevineKeySourceTest, LicenseStatusCencWithPsshBoxOK) { +TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencWithPsshBoxOK) { std::string expected_message = base::StringPrintf(kExpectedRequestMessageWithPsshFormat, Base64Encode(kRequestPsshData).c_str()); @@ -324,7 +399,7 @@ TEST_P(WidevineKeySourceTest, LicenseStatusCencWithPsshBoxOK) { VerifyKeys(false); } -TEST_P(WidevineKeySourceTest, LicenseStatusCencWithKeyIdOK) { +TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencWithKeyIdsOK) { std::string expected_pssh_data( kRequestPsshDataFromKeyIds, kRequestPsshDataFromKeyIds + arraysize(kRequestPsshDataFromKeyIds)); @@ -348,7 +423,7 @@ TEST_P(WidevineKeySourceTest, LicenseStatusCencWithKeyIdOK) { VerifyKeys(false); } -TEST_P(WidevineKeySourceTest, LicenseStatusClassicOK) { +TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusClassicOK) { std::string expected_message = base::StringPrintf( kExpectedRequestMessageWithAssetIdFormat, kClassicAssetId); EXPECT_CALL(*mock_request_signer_, @@ -370,59 +445,12 @@ TEST_P(WidevineKeySourceTest, LicenseStatusClassicOK) { VerifyKeys(true); } -TEST_P(WidevineKeySourceTest, RetryOnHttpTimeout) { - std::string mock_response = base::StringPrintf( - kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str()); - - // Retry is expected on HTTP timeout. - EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) - .WillOnce(Return(Status(error::TIME_OUT, ""))) - .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); - - CreateWidevineKeySource(); - ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy)); - VerifyKeys(false); -} - -TEST_P(WidevineKeySourceTest, RetryOnTransientError) { - std::string mock_license_status = base::StringPrintf( - kLicenseResponseFormat, kLicenseStatusTransientError, ""); - std::string mock_response = base::StringPrintf( - kHttpResponseFormat, Base64Encode(mock_license_status).c_str()); - - std::string expected_retried_response = base::StringPrintf( - kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str()); - - // Retry is expected on transient error. - EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) - .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))) - .WillOnce(DoAll(SetArgPointee<2>(expected_retried_response), - Return(Status::OK))); - - CreateWidevineKeySource(); - ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy)); - VerifyKeys(false); -} - -TEST_P(WidevineKeySourceTest, NoRetryOnUnknownError) { - std::string mock_license_status = base::StringPrintf( - kLicenseResponseFormat, kLicenseStatusUnknownError, ""); - std::string mock_response = base::StringPrintf( - kHttpResponseFormat, Base64Encode(mock_license_status).c_str()); - - EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) - .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); - - CreateWidevineKeySource(); - ASSERT_EQ(error::SERVER_ERROR, - widevine_key_source_->FetchKeys(content_id_, kPolicy).error_code()); -} - namespace { const char kCryptoPeriodRequestMessageFormat[] = "{\"content_id\":\"%s\",\"crypto_period_count\":%u,\"drm_types\":[" "\"WIDEVINE\"],\"first_crypto_period_index\":%u,\"policy\":\"%s\"," + "\"protection_scheme\":%d," "\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"UHD1\"}," "{\"type\":\"UHD2\"},{\"type\":\"AUDIO\"}]}"; @@ -459,7 +487,7 @@ std::string GenerateMockKeyRotationLicenseResponse( } // namespace -TEST_P(WidevineKeySourceTest, KeyRotationTest) { +TEST_P(WidevineKeySourceParameterizedTest, KeyRotationTest) { const uint32_t kFirstCryptoPeriodIndex = 8; const uint32_t kCryptoPeriodCount = 10; // Array of indexes to be checked. @@ -482,12 +510,10 @@ TEST_P(WidevineKeySourceTest, KeyRotationTest) { for (uint32_t i = 0; i < kCryptoIterations; ++i) { uint32_t first_crypto_period_index = kFirstCryptoPeriodIndex - 1 + i * kCryptoPeriodCount; - std::string expected_message = - base::StringPrintf(kCryptoPeriodRequestMessageFormat, - Base64Encode(kContentId).c_str(), - kCryptoPeriodCount, - first_crypto_period_index, - kPolicy); + std::string expected_message = base::StringPrintf( + kCryptoPeriodRequestMessageFormat, Base64Encode(kContentId).c_str(), + kCryptoPeriodCount, first_crypto_period_index, kPolicy, + GetExpectedProtectionScheme()); EXPECT_CALL(*mock_request_signer_, GenerateSignature(expected_message, _)) .WillOnce(DoAll(SetArgPointee<1>(kMockSignature), Return(true))); @@ -526,8 +552,13 @@ TEST_P(WidevineKeySourceTest, KeyRotationTest) { } INSTANTIATE_TEST_CASE_P(WidevineKeySourceInstance, - WidevineKeySourceTest, - ::testing::Bool()); + WidevineKeySourceParameterizedTest, + Combine(Bool(), + Values(FOURCC_cenc, + FOURCC_cbcs, + FOURCC_cens, + FOURCC_cbc1, + kAppleSampleAesProtectionScheme))); } // namespace media } // namespace shaka