Include protection_scheme in Widevine CENC request
Widevine license server added support for protection_schemes recently; If CENC request includes protection_scheme in the CENC request, server will return with a PSSH with protection_scheme filled in. Change-Id: I6dcac498b5e039503d6ac0f6e057737f7c53efaf
This commit is contained in:
parent
d9e7e2f1d0
commit
5fc6e540f3
|
@ -496,7 +496,8 @@ bool RunPackager(const StreamDescriptorList& stream_descriptors) {
|
||||||
FLAGS_enable_playready_encryption) {
|
FLAGS_enable_playready_encryption) {
|
||||||
if (encryption_options.protection_scheme == FOURCC_NULL)
|
if (encryption_options.protection_scheme == FOURCC_NULL)
|
||||||
return false;
|
return false;
|
||||||
encryption_key_source = CreateEncryptionKeySource();
|
encryption_key_source =
|
||||||
|
CreateEncryptionKeySource(encryption_options.protection_scheme);
|
||||||
if (!encryption_key_source)
|
if (!encryption_key_source)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,11 +88,12 @@ std::unique_ptr<RequestSigner> CreateSigner() {
|
||||||
return signer;
|
return signer;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<KeySource> CreateEncryptionKeySource() {
|
std::unique_ptr<KeySource> CreateEncryptionKeySource(FourCC protection_scheme) {
|
||||||
std::unique_ptr<KeySource> encryption_key_source;
|
std::unique_ptr<KeySource> encryption_key_source;
|
||||||
if (FLAGS_enable_widevine_encryption) {
|
if (FLAGS_enable_widevine_encryption) {
|
||||||
std::unique_ptr<WidevineKeySource> widevine_key_source(
|
std::unique_ptr<WidevineKeySource> widevine_key_source(
|
||||||
new WidevineKeySource(FLAGS_key_server_url, FLAGS_include_common_pssh));
|
new WidevineKeySource(FLAGS_key_server_url, FLAGS_include_common_pssh));
|
||||||
|
widevine_key_source->set_protection_scheme(protection_scheme);
|
||||||
if (!FLAGS_signer.empty()) {
|
if (!FLAGS_signer.empty()) {
|
||||||
std::unique_ptr<RequestSigner> request_signer(CreateSigner());
|
std::unique_ptr<RequestSigner> request_signer(CreateSigner());
|
||||||
if (!request_signer)
|
if (!request_signer)
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "packager/media/base/fourccs.h"
|
||||||
|
|
||||||
DECLARE_bool(dump_stream_info);
|
DECLARE_bool(dump_stream_info);
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
|
@ -30,9 +32,11 @@ struct MuxerOptions;
|
||||||
|
|
||||||
/// Create KeySource based on provided command line options for content
|
/// Create KeySource based on provided command line options for content
|
||||||
/// encryption. Also fetches keys.
|
/// 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
|
/// @return A std::unique_ptr containing a new KeySource, or nullptr if
|
||||||
/// encryption is not required.
|
/// encryption is not required.
|
||||||
std::unique_ptr<KeySource> CreateEncryptionKeySource();
|
std::unique_ptr<KeySource> CreateEncryptionKeySource(FourCC protection_scheme);
|
||||||
|
|
||||||
/// Create KeySource based on provided command line options for content
|
/// Create KeySource based on provided command line options for content
|
||||||
/// decryption. Does not fetch keys.
|
/// decryption. Does not fetch keys.
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "packager/base/bind.h"
|
#include "packager/base/bind.h"
|
||||||
#include "packager/base/json/json_reader.h"
|
#include "packager/base/json/json_reader.h"
|
||||||
#include "packager/base/json/json_writer.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/fixed_key_source.h"
|
||||||
#include "packager/media/base/http_key_fetcher.h"
|
#include "packager/media/base/http_key_fetcher.h"
|
||||||
#include "packager/media/base/network_util.h"
|
#include "packager/media/base/network_util.h"
|
||||||
|
@ -22,6 +23,7 @@
|
||||||
#include "packager/media/base/widevine_pssh_data.pb.h"
|
#include "packager/media/base/widevine_pssh_data.pb.h"
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
|
namespace media {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const bool kEnableKeyRotation = true;
|
const bool kEnableKeyRotation = true;
|
||||||
|
@ -118,9 +120,12 @@ bool GetPsshDataFromTrack(const base::DictionaryValue& track_dict,
|
||||||
return true;
|
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,
|
WidevineKeySource::WidevineKeySource(const std::string& server_url,
|
||||||
bool add_common_pssh)
|
bool add_common_pssh)
|
||||||
|
@ -130,6 +135,7 @@ WidevineKeySource::WidevineKeySource(const std::string& server_url,
|
||||||
key_fetcher_(new HttpKeyFetcher(kKeyFetchTimeoutInSeconds)),
|
key_fetcher_(new HttpKeyFetcher(kKeyFetchTimeoutInSeconds)),
|
||||||
server_url_(server_url),
|
server_url_(server_url),
|
||||||
crypto_period_count_(kDefaultCryptoPeriodCount),
|
crypto_period_count_(kDefaultCryptoPeriodCount),
|
||||||
|
protection_scheme_(FOURCC_cenc),
|
||||||
add_common_pssh_(add_common_pssh),
|
add_common_pssh_(add_common_pssh),
|
||||||
key_production_started_(false),
|
key_production_started_(false),
|
||||||
start_key_production_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
|
start_key_production_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
|
||||||
|
@ -157,6 +163,18 @@ Status WidevineKeySource::FetchKeys(const std::vector<uint8_t>& content_id,
|
||||||
BytesToBase64String(content_id, &content_id_base64_string);
|
BytesToBase64String(content_id, &content_id_base64_string);
|
||||||
request_dict_.SetString("content_id", content_id_base64_string);
|
request_dict_.SetString("content_id", content_id_base64_string);
|
||||||
request_dict_.SetString("policy", policy);
|
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);
|
return FetchKeysInternal(!kEnableKeyRotation, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "packager/base/synchronization/waitable_event.h"
|
#include "packager/base/synchronization/waitable_event.h"
|
||||||
#include "packager/base/values.h"
|
#include "packager/base/values.h"
|
||||||
#include "packager/media/base/closure_thread.h"
|
#include "packager/media/base/closure_thread.h"
|
||||||
|
#include "packager/media/base/fourccs.h"
|
||||||
#include "packager/media/base/key_source.h"
|
#include "packager/media/base/key_source.h"
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
|
@ -53,6 +54,11 @@ class WidevineKeySource : public KeySource {
|
||||||
Status FetchKeys(const std::vector<uint8_t>& content_id,
|
Status FetchKeys(const std::vector<uint8_t>& content_id,
|
||||||
const std::string& policy);
|
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.
|
/// Set signer for the key source.
|
||||||
/// @param signer signs the request message.
|
/// @param signer signs the request message.
|
||||||
void set_signer(std::unique_ptr<RequestSigner> signer);
|
void set_signer(std::unique_ptr<RequestSigner> signer);
|
||||||
|
@ -61,9 +67,6 @@ class WidevineKeySource : public KeySource {
|
||||||
/// @param key_fetcher points to the @b KeyFetcher object to be injected.
|
/// @param key_fetcher points to the @b KeyFetcher object to be injected.
|
||||||
void set_key_fetcher(std::unique_ptr<KeyFetcher> key_fetcher);
|
void set_key_fetcher(std::unique_ptr<KeyFetcher> key_fetcher);
|
||||||
|
|
||||||
protected:
|
|
||||||
ClosureThread key_production_thread_;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::map<TrackType, std::unique_ptr<EncryptionKey>> EncryptionKeyMap;
|
typedef std::map<TrackType, std::unique_ptr<EncryptionKey>> EncryptionKeyMap;
|
||||||
typedef ProducerConsumerQueue<std::shared_ptr<EncryptionKeyMap>>
|
typedef ProducerConsumerQueue<std::shared_ptr<EncryptionKeyMap>>
|
||||||
|
@ -104,6 +107,7 @@ class WidevineKeySource : public KeySource {
|
||||||
// Push the keys to the key pool.
|
// Push the keys to the key pool.
|
||||||
bool PushToKeyPool(EncryptionKeyMap* encryption_key_map);
|
bool PushToKeyPool(EncryptionKeyMap* encryption_key_map);
|
||||||
|
|
||||||
|
ClosureThread key_production_thread_;
|
||||||
// The fetcher object used to fetch keys from the license service.
|
// The fetcher object used to fetch keys from the license service.
|
||||||
// It is initialized to a default fetcher on class initialization.
|
// It is initialized to a default fetcher on class initialization.
|
||||||
// Can be overridden using set_key_fetcher for testing or other purposes.
|
// Can be overridden using set_key_fetcher for testing or other purposes.
|
||||||
|
@ -113,6 +117,7 @@ class WidevineKeySource : public KeySource {
|
||||||
base::DictionaryValue request_dict_;
|
base::DictionaryValue request_dict_;
|
||||||
|
|
||||||
const uint32_t crypto_period_count_;
|
const uint32_t crypto_period_count_;
|
||||||
|
FourCC protection_scheme_;
|
||||||
base::Lock lock_;
|
base::Lock lock_;
|
||||||
bool add_common_pssh_;
|
bool add_common_pssh_;
|
||||||
bool key_production_started_;
|
bool key_production_started_;
|
||||||
|
|
|
@ -19,13 +19,19 @@
|
||||||
#include "packager/media/base/widevine_key_source.h"
|
#include "packager/media/base/widevine_key_source.h"
|
||||||
|
|
||||||
using ::testing::_;
|
using ::testing::_;
|
||||||
|
using ::testing::Bool;
|
||||||
|
using ::testing::Combine;
|
||||||
using ::testing::DoAll;
|
using ::testing::DoAll;
|
||||||
using ::testing::InSequence;
|
using ::testing::InSequence;
|
||||||
using ::testing::Return;
|
using ::testing::Return;
|
||||||
using ::testing::SetArgPointee;
|
using ::testing::SetArgPointee;
|
||||||
using ::testing::StrEq;
|
using ::testing::StrEq;
|
||||||
|
using ::testing::Test;
|
||||||
|
using ::testing::Values;
|
||||||
|
using ::testing::WithParamInterface;
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
|
namespace media {
|
||||||
namespace {
|
namespace {
|
||||||
const char kServerUrl[] = "http://www.foo.com/getcontentkey";
|
const char kServerUrl[] = "http://www.foo.com/getcontentkey";
|
||||||
const char kContentId[] = "ContentFoo";
|
const char kContentId[] = "ContentFoo";
|
||||||
|
@ -45,6 +51,7 @@ const char kLicenseStatusUnknownError[] = "UNKNOWN_ERROR";
|
||||||
|
|
||||||
const char kExpectedRequestMessageFormat[] =
|
const char kExpectedRequestMessageFormat[] =
|
||||||
"{\"content_id\":\"%s\",\"drm_types\":[\"WIDEVINE\"],\"policy\":\"%s\","
|
"{\"content_id\":\"%s\",\"drm_types\":[\"WIDEVINE\"],\"policy\":\"%s\","
|
||||||
|
"\"protection_scheme\":%d,"
|
||||||
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"UHD1\"},"
|
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"UHD1\"},"
|
||||||
"{\"type\":\"UHD2\"},{\"type\":\"AUDIO\"}]}";
|
"{\"type\":\"UHD2\"},{\"type\":\"AUDIO\"}]}";
|
||||||
const char kExpectedRequestMessageWithAssetIdFormat[] =
|
const char kExpectedRequestMessageWithAssetIdFormat[] =
|
||||||
|
@ -64,11 +71,12 @@ const char kClassicTrackFormat[] = "{\"type\":\"%s\",\"key\":\"%s\"}";
|
||||||
const char kLicenseResponseFormat[] = "{\"status\":\"%s\",\"tracks\":[%s]}";
|
const char kLicenseResponseFormat[] = "{\"status\":\"%s\",\"tracks\":[%s]}";
|
||||||
const char kHttpResponseFormat[] = "{\"response\":\"%s\"}";
|
const char kHttpResponseFormat[] = "{\"response\":\"%s\"}";
|
||||||
const uint8_t kRequestPsshBox[] = {
|
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,
|
0, 0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, 0x4a, 0xce, 0xa3, 0xc8,
|
||||||
0x27, 0xdc, 0xd5, 0x1d, 0x21, 0xed, 0, 0, 0, 0x09, 'P',
|
0x27, 0xdc, 0xd5, 0x1d, 0x21, 0xed, 0, 0, 0, 12, 0x22,
|
||||||
'S', 'S', 'H', ' ', 'd', 'a', 't', 'a'};
|
0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', 'F', 'o', 'o'};
|
||||||
const char kRequestPsshData[] = "PSSH data";
|
const char kRequestPsshData[] = {0x22, 0x0a, 'C', 'o', 'n', 't', 'e',
|
||||||
|
'n', 't', 'F', 'o', 'o', '\0'};
|
||||||
const uint8_t kRequestPsshDataFromKeyIds[] = {0x12, 0x06, 0x00, 0x01,
|
const uint8_t kRequestPsshDataFromKeyIds[] = {0x12, 0x06, 0x00, 0x01,
|
||||||
0x02, 0x03, 0x04, 0x05};
|
0x02, 0x03, 0x04, 0x05};
|
||||||
const uint8_t kRequestKeyId[] = {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;
|
return "MockKey" + track_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetMockPsshData(const std::string& track_type) {
|
std::string GetMockPsshData() {
|
||||||
return "MockPsshData" + track_type;
|
return kRequestPsshData;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GenerateMockLicenseResponse() {
|
std::string GenerateMockLicenseResponse() {
|
||||||
|
@ -108,12 +116,11 @@ std::string GenerateMockLicenseResponse() {
|
||||||
for (size_t i = 0; i < 5; ++i) {
|
for (size_t i = 0; i < 5; ++i) {
|
||||||
if (!tracks.empty())
|
if (!tracks.empty())
|
||||||
tracks += ",";
|
tracks += ",";
|
||||||
tracks += base::StringPrintf(
|
tracks +=
|
||||||
kTrackFormat,
|
base::StringPrintf(kTrackFormat, kTrackTypes[i].c_str(),
|
||||||
kTrackTypes[i].c_str(),
|
Base64Encode(GetMockKeyId(kTrackTypes[i])).c_str(),
|
||||||
Base64Encode(GetMockKeyId(kTrackTypes[i])).c_str(),
|
Base64Encode(GetMockKey(kTrackTypes[i])).c_str(),
|
||||||
Base64Encode(GetMockKey(kTrackTypes[i])).c_str(),
|
Base64Encode(GetMockPsshData()).c_str());
|
||||||
Base64Encode(GetMockPsshData(kTrackTypes[i])).c_str());
|
|
||||||
}
|
}
|
||||||
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str());
|
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str());
|
||||||
}
|
}
|
||||||
|
@ -134,8 +141,6 @@ std::string GenerateMockClassicLicenseResponse() {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace media {
|
|
||||||
|
|
||||||
class MockRequestSigner : public RequestSigner {
|
class MockRequestSigner : public RequestSigner {
|
||||||
public:
|
public:
|
||||||
explicit MockRequestSigner(const std::string& signer_name)
|
explicit MockRequestSigner(const std::string& signer_name)
|
||||||
|
@ -163,8 +168,7 @@ class MockKeyFetcher : public KeyFetcher {
|
||||||
DISALLOW_COPY_AND_ASSIGN(MockKeyFetcher);
|
DISALLOW_COPY_AND_ASSIGN(MockKeyFetcher);
|
||||||
};
|
};
|
||||||
|
|
||||||
class WidevineKeySourceTest : public ::testing::Test,
|
class WidevineKeySourceTest : public Test {
|
||||||
public ::testing::WithParamInterface<bool> {
|
|
||||||
public:
|
public:
|
||||||
WidevineKeySourceTest()
|
WidevineKeySourceTest()
|
||||||
: mock_request_signer_(new MockRequestSigner(kSignerName)),
|
: mock_request_signer_(new MockRequestSigner(kSignerName)),
|
||||||
|
@ -177,8 +181,17 @@ class WidevineKeySourceTest : public ::testing::Test,
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
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() {
|
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_));
|
widevine_key_source_->set_key_fetcher(std::move(mock_key_fetcher_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,13 +204,14 @@ class WidevineKeySourceTest : public ::testing::Test,
|
||||||
&encryption_key));
|
&encryption_key));
|
||||||
EXPECT_EQ(GetMockKey(kTrackTypes[i]), ToString(encryption_key.key));
|
EXPECT_EQ(GetMockKey(kTrackTypes[i]), ToString(encryption_key.key));
|
||||||
if (!classic) {
|
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]),
|
EXPECT_EQ(GetMockKeyId(kTrackTypes[i]),
|
||||||
ToString(encryption_key.key_id));
|
ToString(encryption_key.key_id));
|
||||||
EXPECT_EQ(GetMockPsshData(kTrackTypes[i]),
|
EXPECT_EQ(GetMockPsshData(),
|
||||||
ToString(encryption_key.key_system_info[0].pssh_data()));
|
ToString(encryption_key.key_system_info[0].pssh_data()));
|
||||||
|
|
||||||
if (GetParam()) {
|
if (add_common_pssh_) {
|
||||||
// Each of the keys contains all the key IDs.
|
// Each of the keys contains all the key IDs.
|
||||||
const std::vector<uint8_t> common_system_id(
|
const std::vector<uint8_t> common_system_id(
|
||||||
kCommonSystemId, kCommonSystemId + arraysize(kCommonSystemId));
|
kCommonSystemId, kCommonSystemId + arraysize(kCommonSystemId));
|
||||||
|
@ -222,12 +236,14 @@ class WidevineKeySourceTest : public ::testing::Test,
|
||||||
std::unique_ptr<MockKeyFetcher> mock_key_fetcher_;
|
std::unique_ptr<MockKeyFetcher> mock_key_fetcher_;
|
||||||
std::unique_ptr<WidevineKeySource> widevine_key_source_;
|
std::unique_ptr<WidevineKeySource> widevine_key_source_;
|
||||||
std::vector<uint8_t> content_id_;
|
std::vector<uint8_t> content_id_;
|
||||||
|
bool add_common_pssh_ = false;
|
||||||
|
FourCC protection_scheme_ = FOURCC_cenc;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_COPY_AND_ASSIGN(WidevineKeySourceTest);
|
DISALLOW_COPY_AND_ASSIGN(WidevineKeySourceTest);
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_P(WidevineKeySourceTest, GetTrackTypeFromString) {
|
TEST_F(WidevineKeySourceTest, GetTrackTypeFromString) {
|
||||||
EXPECT_EQ(KeySource::TRACK_TYPE_SD,
|
EXPECT_EQ(KeySource::TRACK_TYPE_SD,
|
||||||
KeySource::GetTrackTypeFromString("SD"));
|
KeySource::GetTrackTypeFromString("SD"));
|
||||||
EXPECT_EQ(KeySource::TRACK_TYPE_HD,
|
EXPECT_EQ(KeySource::TRACK_TYPE_HD,
|
||||||
|
@ -242,7 +258,7 @@ TEST_P(WidevineKeySourceTest, GetTrackTypeFromString) {
|
||||||
KeySource::GetTrackTypeFromString("FOO"));
|
KeySource::GetTrackTypeFromString("FOO"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(WidevineKeySourceTest, GenerateSignatureFailure) {
|
TEST_F(WidevineKeySourceTest, GenerateSignatureFailure) {
|
||||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
||||||
.WillOnce(Return(false));
|
.WillOnce(Return(false));
|
||||||
|
|
||||||
|
@ -252,11 +268,70 @@ TEST_P(WidevineKeySourceTest, GenerateSignatureFailure) {
|
||||||
widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
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<std::tr1::tuple<bool, FourCC>> {
|
||||||
|
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
|
// Check whether expected request message and post data was generated and
|
||||||
// verify the correct behavior on http failure.
|
// verify the correct behavior on http failure.
|
||||||
TEST_P(WidevineKeySourceTest, HttpFetchFailure) {
|
TEST_P(WidevineKeySourceParameterizedTest, HttpFetchFailure) {
|
||||||
std::string expected_message = base::StringPrintf(
|
std::string expected_message = base::StringPrintf(
|
||||||
kExpectedRequestMessageFormat, Base64Encode(kContentId).c_str(), kPolicy);
|
kExpectedRequestMessageFormat, Base64Encode(kContentId).c_str(), kPolicy,
|
||||||
|
GetExpectedProtectionScheme());
|
||||||
EXPECT_CALL(*mock_request_signer_,
|
EXPECT_CALL(*mock_request_signer_,
|
||||||
GenerateSignature(StrEq(expected_message), _))
|
GenerateSignature(StrEq(expected_message), _))
|
||||||
.WillOnce(DoAll(SetArgPointee<1>(kMockSignature), Return(true)));
|
.WillOnce(DoAll(SetArgPointee<1>(kMockSignature), Return(true)));
|
||||||
|
@ -277,7 +352,7 @@ TEST_P(WidevineKeySourceTest, HttpFetchFailure) {
|
||||||
widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(WidevineKeySourceTest, LicenseStatusCencOK) {
|
TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencOK) {
|
||||||
std::string mock_response = base::StringPrintf(
|
std::string mock_response = base::StringPrintf(
|
||||||
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
||||||
|
|
||||||
|
@ -289,7 +364,7 @@ TEST_P(WidevineKeySourceTest, LicenseStatusCencOK) {
|
||||||
VerifyKeys(false);
|
VerifyKeys(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(WidevineKeySourceTest, LicenseStatusCencNotOK) {
|
TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencNotOK) {
|
||||||
std::string mock_response = base::StringPrintf(
|
std::string mock_response = base::StringPrintf(
|
||||||
kHttpResponseFormat, Base64Encode(
|
kHttpResponseFormat, Base64Encode(
|
||||||
GenerateMockClassicLicenseResponse()).c_str());
|
GenerateMockClassicLicenseResponse()).c_str());
|
||||||
|
@ -303,7 +378,7 @@ TEST_P(WidevineKeySourceTest, LicenseStatusCencNotOK) {
|
||||||
.error_code());
|
.error_code());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(WidevineKeySourceTest, LicenseStatusCencWithPsshBoxOK) {
|
TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencWithPsshBoxOK) {
|
||||||
std::string expected_message =
|
std::string expected_message =
|
||||||
base::StringPrintf(kExpectedRequestMessageWithPsshFormat,
|
base::StringPrintf(kExpectedRequestMessageWithPsshFormat,
|
||||||
Base64Encode(kRequestPsshData).c_str());
|
Base64Encode(kRequestPsshData).c_str());
|
||||||
|
@ -324,7 +399,7 @@ TEST_P(WidevineKeySourceTest, LicenseStatusCencWithPsshBoxOK) {
|
||||||
VerifyKeys(false);
|
VerifyKeys(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(WidevineKeySourceTest, LicenseStatusCencWithKeyIdOK) {
|
TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusCencWithKeyIdsOK) {
|
||||||
std::string expected_pssh_data(
|
std::string expected_pssh_data(
|
||||||
kRequestPsshDataFromKeyIds,
|
kRequestPsshDataFromKeyIds,
|
||||||
kRequestPsshDataFromKeyIds + arraysize(kRequestPsshDataFromKeyIds));
|
kRequestPsshDataFromKeyIds + arraysize(kRequestPsshDataFromKeyIds));
|
||||||
|
@ -348,7 +423,7 @@ TEST_P(WidevineKeySourceTest, LicenseStatusCencWithKeyIdOK) {
|
||||||
VerifyKeys(false);
|
VerifyKeys(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(WidevineKeySourceTest, LicenseStatusClassicOK) {
|
TEST_P(WidevineKeySourceParameterizedTest, LicenseStatusClassicOK) {
|
||||||
std::string expected_message = base::StringPrintf(
|
std::string expected_message = base::StringPrintf(
|
||||||
kExpectedRequestMessageWithAssetIdFormat, kClassicAssetId);
|
kExpectedRequestMessageWithAssetIdFormat, kClassicAssetId);
|
||||||
EXPECT_CALL(*mock_request_signer_,
|
EXPECT_CALL(*mock_request_signer_,
|
||||||
|
@ -370,59 +445,12 @@ TEST_P(WidevineKeySourceTest, LicenseStatusClassicOK) {
|
||||||
VerifyKeys(true);
|
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 {
|
namespace {
|
||||||
|
|
||||||
const char kCryptoPeriodRequestMessageFormat[] =
|
const char kCryptoPeriodRequestMessageFormat[] =
|
||||||
"{\"content_id\":\"%s\",\"crypto_period_count\":%u,\"drm_types\":["
|
"{\"content_id\":\"%s\",\"crypto_period_count\":%u,\"drm_types\":["
|
||||||
"\"WIDEVINE\"],\"first_crypto_period_index\":%u,\"policy\":\"%s\","
|
"\"WIDEVINE\"],\"first_crypto_period_index\":%u,\"policy\":\"%s\","
|
||||||
|
"\"protection_scheme\":%d,"
|
||||||
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"UHD1\"},"
|
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"UHD1\"},"
|
||||||
"{\"type\":\"UHD2\"},{\"type\":\"AUDIO\"}]}";
|
"{\"type\":\"UHD2\"},{\"type\":\"AUDIO\"}]}";
|
||||||
|
|
||||||
|
@ -459,7 +487,7 @@ std::string GenerateMockKeyRotationLicenseResponse(
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST_P(WidevineKeySourceTest, KeyRotationTest) {
|
TEST_P(WidevineKeySourceParameterizedTest, KeyRotationTest) {
|
||||||
const uint32_t kFirstCryptoPeriodIndex = 8;
|
const uint32_t kFirstCryptoPeriodIndex = 8;
|
||||||
const uint32_t kCryptoPeriodCount = 10;
|
const uint32_t kCryptoPeriodCount = 10;
|
||||||
// Array of indexes to be checked.
|
// Array of indexes to be checked.
|
||||||
|
@ -482,12 +510,10 @@ TEST_P(WidevineKeySourceTest, KeyRotationTest) {
|
||||||
for (uint32_t i = 0; i < kCryptoIterations; ++i) {
|
for (uint32_t i = 0; i < kCryptoIterations; ++i) {
|
||||||
uint32_t first_crypto_period_index =
|
uint32_t first_crypto_period_index =
|
||||||
kFirstCryptoPeriodIndex - 1 + i * kCryptoPeriodCount;
|
kFirstCryptoPeriodIndex - 1 + i * kCryptoPeriodCount;
|
||||||
std::string expected_message =
|
std::string expected_message = base::StringPrintf(
|
||||||
base::StringPrintf(kCryptoPeriodRequestMessageFormat,
|
kCryptoPeriodRequestMessageFormat, Base64Encode(kContentId).c_str(),
|
||||||
Base64Encode(kContentId).c_str(),
|
kCryptoPeriodCount, first_crypto_period_index, kPolicy,
|
||||||
kCryptoPeriodCount,
|
GetExpectedProtectionScheme());
|
||||||
first_crypto_period_index,
|
|
||||||
kPolicy);
|
|
||||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(expected_message, _))
|
EXPECT_CALL(*mock_request_signer_, GenerateSignature(expected_message, _))
|
||||||
.WillOnce(DoAll(SetArgPointee<1>(kMockSignature), Return(true)));
|
.WillOnce(DoAll(SetArgPointee<1>(kMockSignature), Return(true)));
|
||||||
|
|
||||||
|
@ -526,8 +552,13 @@ TEST_P(WidevineKeySourceTest, KeyRotationTest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANTIATE_TEST_CASE_P(WidevineKeySourceInstance,
|
INSTANTIATE_TEST_CASE_P(WidevineKeySourceInstance,
|
||||||
WidevineKeySourceTest,
|
WidevineKeySourceParameterizedTest,
|
||||||
::testing::Bool());
|
Combine(Bool(),
|
||||||
|
Values(FOURCC_cenc,
|
||||||
|
FOURCC_cbcs,
|
||||||
|
FOURCC_cens,
|
||||||
|
FOURCC_cbc1,
|
||||||
|
kAppleSampleAesProtectionScheme)));
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace shaka
|
} // namespace shaka
|
||||||
|
|
Loading…
Reference in New Issue