Support Latest Version of EME Spec Init Data Specification

(This is a merge of
https://widevine-internal-review.googlesource.com/9711 from the
Widevine CDM repo.)

This change updates the CDM's handling of init data types, previously
known as MIME types, to comply with the latest version of the EME
spec.

Following this change, in addition to accepting the deprecated MIME
types "video/mp4", "audio/mp4", "video/webm", and "audio/webm", the
CDM will accept the new standard: Init data types "cenc" and "webm".

Furthermore, this removes the non-PSSH-parsing path from the CDM. All
platforms have unified on the CDM being responsible for parsing the
concatenated PSSH box list, as outlined in the latest EME spec.

As Android has shipped code that expects pre-unwrapped PSSH boxes and
must maintain backwards-compatibility, code has been inserted on that
platform to detect pre-unwrapped data and re-wrap it with a PSSH
header before sending it to the CDM.

There are some small changes to unit tests because of this change:

1) The CDM Engine unit test now no longer needs to unwrap the PSSH on
   any platforms when testing ISO-BMFF. It now pre-caches the
   unwrapped key ID for use when testing WebM.

2) Several substantially-similar unit tests in the Android code have
   been rolled into one test.

Bug: 13564917
Bug: 13570595
Bug: 9465346
Bug: 13570288
Change-Id: I7f27b16b8503f24a26746b5dce71fb61b6fd1bb2
This commit is contained in:
John "Juce" Bruce
2014-04-09 17:51:42 -07:00
committed by John Bruce
parent de6f6f6324
commit 951f08c2da
13 changed files with 166 additions and 213 deletions

View File

@@ -26,14 +26,9 @@ class InitializationData {
const CdmInitData& data() const { return data_; }
private:
friend WvCdmEngineTest;
// Parse a blob of multiple concatenated PSSH atoms to extract the first
// Widevine PSSH.
// TODO(juce): Make this non-static and remove the friend above once the unit
// test is rewritten to not need this.
static bool ExtractWidevinePssh(const CdmInitData& init_data,
CdmInitData* output);
bool ExtractWidevinePssh(const CdmInitData& init_data, CdmInitData* output);
std::string type_;
CdmInitData data_;

View File

@@ -42,7 +42,6 @@ class Properties {
static inline bool use_certificates_as_identification() {
return use_certificates_as_identification_;
}
static inline bool extract_pssh_data() { return extract_pssh_data_; }
static inline bool decrypt_with_empty_session_support() {
return decrypt_with_empty_session_support_;
}
@@ -91,8 +90,6 @@ class Properties {
static void set_use_certificates_as_identification(bool flag) {
use_certificates_as_identification_ = flag;
}
static void set_extract_pssh_data(bool flag) { extract_pssh_data_ = flag; }
static void set_decrypt_with_empty_session_support(bool flag) {
decrypt_with_empty_session_support_ = flag;
}
@@ -108,7 +105,6 @@ class Properties {
static bool oem_crypto_use_fifo_;
static bool oem_crypto_use_userspace_buffers_;
static bool use_certificates_as_identification_;
static bool extract_pssh_data_;
static bool decrypt_with_empty_session_support_;
static bool security_level_path_backward_compatibility_support_;
static scoped_ptr<CdmClientPropertySetMap> session_property_set_;

View File

@@ -60,6 +60,8 @@ static const std::string ISO_BMFF_VIDEO_MIME_TYPE = "video/mp4";
static const std::string ISO_BMFF_AUDIO_MIME_TYPE = "audio/mp4";
static const std::string WEBM_VIDEO_MIME_TYPE = "video/webm";
static const std::string WEBM_AUDIO_MIME_TYPE = "audio/webm";
static const std::string CENC_INIT_DATA_FORMAT = "cenc";
static const std::string WEBM_INIT_DATA_FORMAT = "webm";
} // namespace wvcdm
#endif // CDM_BASE_WV_CDM_CONSTANTS_H_

View File

@@ -2,6 +2,8 @@
#include "initialization_data.h"
#include <string.h>
#include "buffer_reader.h"
#include "log.h"
#include "properties.h"
@@ -12,14 +14,18 @@ namespace wvcdm {
InitializationData::InitializationData(const std::string& type,
const CdmInitData& data)
: type_(type), is_cenc_(false), is_webm_(false) {
if (type == ISO_BMFF_VIDEO_MIME_TYPE || type == ISO_BMFF_AUDIO_MIME_TYPE) {
if (type == ISO_BMFF_VIDEO_MIME_TYPE ||
type == ISO_BMFF_AUDIO_MIME_TYPE ||
type == CENC_INIT_DATA_FORMAT) {
is_cenc_ = true;
} else if (type == WEBM_VIDEO_MIME_TYPE || type == WEBM_AUDIO_MIME_TYPE) {
} else if (type == WEBM_VIDEO_MIME_TYPE ||
type == WEBM_AUDIO_MIME_TYPE ||
type == WEBM_INIT_DATA_FORMAT) {
is_webm_ = true;
}
if (is_supported()) {
if (Properties::extract_pssh_data() && is_cenc()) {
if (is_cenc()) {
ExtractWidevinePssh(data, &data_);
} else {
data_ = data;
@@ -29,10 +35,8 @@ InitializationData::InitializationData(const std::string& type,
// Parse a blob of multiple concatenated PSSH atoms to extract the first
// Widevine PSSH.
// TODO(kqyang): temporary workaround - remove after b/7928472 is resolved
bool InitializationData::ExtractWidevinePssh(
const CdmInitData& init_data, CdmInitData* output) {
BufferReader reader(
reinterpret_cast<const uint8_t*>(init_data.data()), init_data.length());

View File

@@ -15,7 +15,6 @@ bool Properties::oem_crypto_use_secure_buffers_;
bool Properties::oem_crypto_use_fifo_;
bool Properties::oem_crypto_use_userspace_buffers_;
bool Properties::use_certificates_as_identification_;
bool Properties::extract_pssh_data_;
bool Properties::decrypt_with_empty_session_support_;
bool Properties::security_level_path_backward_compatibility_support_;
scoped_ptr<CdmClientPropertySetMap> Properties::session_property_set_;
@@ -28,7 +27,6 @@ void Properties::Init() {
oem_crypto_use_userspace_buffers_ = kPropertyOemCryptoUseUserSpaceBuffers;
use_certificates_as_identification_ =
kPropertyUseCertificatesAsIdentification;
extract_pssh_data_ = kExtractPsshData;
decrypt_with_empty_session_support_ = kDecryptWithEmptySessionSupport;
security_level_path_backward_compatibility_support_ =
kSecurityLevelPathBackwardCompatibilitySupport;

View File

@@ -29,7 +29,8 @@ const int kHttpOk = 200;
// Default license server, can be configured using --server command line option
// Default key id (pssh), can be configured using --keyid command line option
std::string g_client_auth;
wvcdm::KeyId g_key_id;
wvcdm::KeyId g_key_id_pssh;
wvcdm::KeyId g_key_id_unwrapped;
wvcdm::CdmKeySystem g_key_system;
std::string g_license_server;
std::string g_port;
@@ -112,16 +113,7 @@ class WvCdmEngineTest : public testing::Test {
std::string server_url;
CdmKeySetId key_set_id;
// TODO(rfrias): Temporary change till b/9465346 is addressed
CdmInitData extracted_init_data = key_id;
InitializationData init_data_type(init_data_type_string);
if (!Properties::extract_pssh_data() || !init_data_type.is_cenc()) {
EXPECT_TRUE(InitializationData::ExtractWidevinePssh(
key_id,
&extracted_init_data));
}
InitializationData init_data(init_data_type_string, extracted_init_data);
InitializationData init_data(init_data_type_string, key_id);
EXPECT_EQ(KEY_MESSAGE,
cdm_engine_.GenerateKeyRequest(session_id_,
@@ -207,13 +199,13 @@ TEST(WvCdmProvisioningTest, ProvisioningTest) {
}
TEST_F(WvCdmEngineTest, BaseIsoBmffMessageTest) {
GenerateKeyRequest(g_key_id, kCencMimeType);
GenerateKeyRequest(g_key_id_pssh, kCencMimeType);
GetKeyRequestResponse(g_license_server, g_client_auth);
}
// TODO(juce): Set up with correct test data.
TEST_F(WvCdmEngineTest, DISABLED_BaseWebmMessageTest) {
GenerateKeyRequest(g_key_id, kWebmMimeType);
GenerateKeyRequest(g_key_id_unwrapped, kWebmMimeType);
GetKeyRequestResponse(g_license_server, g_client_auth);
}
@@ -227,18 +219,18 @@ TEST_F(WvCdmEngineTest, WrongMessageTest) {
}
TEST_F(WvCdmEngineTest, NormalDecryptionIsoBmff) {
GenerateKeyRequest(g_key_id, kCencMimeType);
GenerateKeyRequest(g_key_id_pssh, kCencMimeType);
VerifyNewKeyResponse(g_license_server, g_client_auth);
}
// TODO(juce): Set up with correct test data.
TEST_F(WvCdmEngineTest, DISABLED_NormalDecryptionWebm) {
GenerateKeyRequest(g_key_id, kWebmMimeType);
GenerateKeyRequest(g_key_id_unwrapped, kWebmMimeType);
VerifyNewKeyResponse(g_license_server, g_client_auth);
}
TEST_F(WvCdmEngineTest, LicenseRenewal) {
GenerateKeyRequest(g_key_id, kCencMimeType);
GenerateKeyRequest(g_key_id_pssh, kCencMimeType);
VerifyNewKeyResponse(g_license_server, g_client_auth);
GenerateRenewalRequest();
@@ -259,7 +251,7 @@ int main(int argc, char **argv) {
// The following variables are configurable through command line options.
g_license_server.assign(config.license_server());
g_key_id.assign(config.key_id());
g_key_id_pssh.assign(config.key_id());
g_port.assign(config.port());
std::string license_server(g_license_server);
@@ -279,8 +271,8 @@ int main(int argc, char **argv) {
while ((opt = getopt_long(argc, argv, "k:p:s:u", long_options, &option_index)) != -1) {
switch (opt) {
case 'k': {
g_key_id.clear();
g_key_id.assign(optarg);
g_key_id_pssh.clear();
g_key_id_pssh.assign(optarg);
break;
}
case 'p': {
@@ -323,7 +315,7 @@ int main(int argc, char **argv) {
std::cout << std::setw(30) << std::left << " --keyid=<key_id>";
std::cout << "configure the key id or pssh, in hex format" << std::endl;
std::cout << std::setw(30) << std::left << " default keyid:";
std::cout << g_key_id << std::endl;
std::cout << g_key_id_pssh << std::endl;
std::cout << std::setw(30) << std::left << " --use_full_path";
std::cout << "specify server url is not a proxy server" << std::endl;
@@ -334,12 +326,17 @@ int main(int argc, char **argv) {
std::cout << std::endl;
std::cout << "Server: " << g_license_server << std::endl;
std::cout << "Port: " << g_port << std::endl;
std::cout << "KeyID: " << g_key_id << std::endl << std::endl;
std::cout << "KeyID: " << g_key_id_pssh << std::endl << std::endl;
g_key_id = wvcdm::a2bs_hex(g_key_id);
g_key_id_pssh = wvcdm::a2bs_hex(g_key_id_pssh);
config.set_license_server(g_license_server);
config.set_port(g_port);
config.set_key_id(g_key_id);
config.set_key_id(g_key_id_pssh);
// Extract the key ID from the PSSH box.
wvcdm::InitializationData extractor(wvcdm::CENC_INIT_DATA_FORMAT,
g_key_id_pssh);
g_key_id_unwrapped = extractor.data();
#if defined(CHROMIUM_BUILD)
base::AtExitManager exit;

View File

@@ -26,11 +26,6 @@ const bool kPropertyOemCryptoUseUserSpaceBuffers = false;
// and passed as the token in the license request
const bool kPropertyUseCertificatesAsIdentification = true;
// If false, extraction of widevine PSSH information from the PSSH box
// takes place external to the CDM. This will become the default behaviour
// once all platforms support it (b/9465346)
const bool kExtractPsshData = true;
// If true, session_id parameter to CdmEngine::Decrypt can be empty; the
// function will try to find out the session_id from the key_id.
const bool kDecryptWithEmptySessionSupport = false;

View File

@@ -21,7 +21,9 @@ class WvContentDecryptionModule : public TimerHandler {
virtual ~WvContentDecryptionModule();
// Static methods
static bool SupportsInitDataType(const std::string& type);
static bool IsSupported(const std::string& init_data_type);
static bool IsCenc(const std::string& init_data_type);
static bool IsWebm(const std::string& init_data_type);
// Session related methods
virtual CdmResponseType OpenSession(

View File

@@ -27,8 +27,16 @@ WvContentDecryptionModule::~WvContentDecryptionModule() {
DisablePolicyTimer(true);
}
bool WvContentDecryptionModule::SupportsInitDataType(const std::string& type) {
return InitializationData(type).is_supported();
bool WvContentDecryptionModule::IsSupported(const std::string& init_data_type) {
return InitializationData(init_data_type).is_supported();
}
bool WvContentDecryptionModule::IsCenc(const std::string& init_data_type) {
return InitializationData(init_data_type).is_cenc();
}
bool WvContentDecryptionModule::IsWebm(const std::string& init_data_type) {
return InitializationData(init_data_type).is_webm();
}
CdmResponseType WvContentDecryptionModule::OpenSession(

View File

@@ -236,6 +236,8 @@ class WVDrmPlugin : public android::DrmPlugin,
OEMCryptoResult res);
status_t mapOEMCryptoResult(OEMCryptoResult res);
bool InitDataResemblesPSSH(const Vector<uint8_t>& initData);
};
} // namespace wvdrm

View File

@@ -19,16 +19,20 @@
#include "utils/Errors.h"
#include "wv_cdm_constants.h"
namespace {
static const char* const kResetSecurityLevel = "";
static const char* const kEnable = "enable";
static const char* const kDisable = "disable";
static const std::string kPsshTag = "pssh";
}
namespace wvdrm {
using namespace android;
using namespace std;
using namespace wvcdm;
static const char* const kResetSecurityLevel = "";
static const char* const kEnable = "enable";
static const char* const kDisable = "disable";
WVDrmPlugin::WVDrmPlugin(WvContentDecryptionModule* cdm,
WVGenericCryptoInterface* crypto)
: mCDM(cdm), mCrypto(crypto) {}
@@ -149,21 +153,18 @@ status_t WVDrmPlugin::getKeyRequest(
return android::ERROR_DRM_CANNOT_HANDLE;
}
string cdmMimeType = initDataType.string();
string cdmInitDataType = initDataType.string();
// Provide backwards-compatibility for apps that pass non-EME-compatible MIME
// types.
if (cdmMimeType != wvcdm::ISO_BMFF_VIDEO_MIME_TYPE &&
cdmMimeType != wvcdm::ISO_BMFF_AUDIO_MIME_TYPE &&
cdmMimeType != wvcdm::WEBM_VIDEO_MIME_TYPE &&
cdmMimeType != wvcdm::WEBM_AUDIO_MIME_TYPE) {
cdmMimeType = wvcdm::ISO_BMFF_VIDEO_MIME_TYPE;
if (!WvContentDecryptionModule::IsSupported(cdmInitDataType)) {
cdmInitDataType = wvcdm::ISO_BMFF_VIDEO_MIME_TYPE;
}
CdmInitData processedInitData;
if (cdmMimeType == wvcdm::ISO_BMFF_VIDEO_MIME_TYPE ||
cdmMimeType == wvcdm::ISO_BMFF_AUDIO_MIME_TYPE) {
// For ISO-BMFF, we need to wrap the init data in a new PSSH header.
if (WvContentDecryptionModule::IsCenc(cdmInitDataType) &&
!InitDataResemblesPSSH(initData)) {
// This data was passed in the old format, pre-unwrapped. We need to wrap
// the init data in a new PSSH header.
static const char psshPrefix[] = {
0, 0, 0, 0, // Total size
'p', 's', 's', 'h', // "PSSH"
@@ -204,7 +205,8 @@ status_t WVDrmPlugin::getKeyRequest(
CdmKeyMessage keyRequest;
string cdmDefaultUrl;
CdmResponseType res = mCDM->GenerateKeyRequest(cdmSessionId, cdmKeySetId,
cdmMimeType, processedInitData,
cdmInitDataType,
processedInitData,
cdmLicenseType, cdmParameters,
&keyRequest, &cdmDefaultUrl);
@@ -929,4 +931,24 @@ status_t WVDrmPlugin::mapOEMCryptoResult(OEMCryptoResult res) {
}
}
bool WVDrmPlugin::InitDataResemblesPSSH(const Vector<uint8_t>& initData) {
const uint8_t* const initDataArray = initData.array();
// Extract the size field
const uint8_t* const sizeField = &initDataArray[0];
uint32_t nboSize;
memcpy(&nboSize, sizeField, sizeof(nboSize));
uint32_t size = ntohl(nboSize);
if (size > initData.size()) {
return false;
}
// Extract the ID field
const char* const idField =
reinterpret_cast<const char* const>(&initDataArray[sizeof(nboSize)]);
string id(idField, kPsshTag.size());
return id == kPsshTag;
}
} // namespace wvdrm

View File

@@ -189,7 +189,7 @@ TEST_F(WVDrmPluginTest, ClosesSessions) {
ASSERT_EQ(OK, res);
}
TEST_F(WVDrmPluginTest, GeneratesIsoBmffKeyRequests) {
TEST_F(WVDrmPluginTest, GeneratesKeyRequests) {
StrictMock<MockCDM> cdm;
StrictMock<MockCrypto> crypto;
WVDrmPlugin plugin(&cdm, &crypto);
@@ -207,10 +207,11 @@ TEST_F(WVDrmPluginTest, GeneratesIsoBmffKeyRequests) {
fclose(fp);
memcpy(keySetIdRaw, KEY_SET_ID_PREFIX, sizeof(KEY_SET_ID_PREFIX) - 1);
CdmKeySetId cdmKeySetId(reinterpret_cast<char *>(keySetIdRaw), kKeySetIdSize);
CdmKeySetId cdmKeySetId(reinterpret_cast<char*>(keySetIdRaw), kKeySetIdSize);
Vector<uint8_t> keySetId;
keySetId.appendArray(keySetIdRaw, kKeySetIdSize);
CdmInitData cdmInitData(reinterpret_cast<char*>(initDataRaw), kInitDataSize);
Vector<uint8_t> initData;
initData.appendArray(initDataRaw, kInitDataSize);
@@ -224,174 +225,106 @@ TEST_F(WVDrmPluginTest, GeneratesIsoBmffKeyRequests) {
};
static const size_t kPsshPrefixSize = sizeof(psshPrefix);
static const size_t kPsshBoxSize = kPsshPrefixSize + kInitDataSize;
uint8_t psshBox[kPsshBoxSize];
memcpy(psshBox, psshPrefix, kPsshPrefixSize);
memcpy(psshBox + kPsshPrefixSize, initDataRaw, kInitDataSize);
uint8_t psshBoxRaw[kPsshBoxSize];
memcpy(psshBoxRaw, psshPrefix, kPsshPrefixSize);
memcpy(psshBoxRaw + kPsshPrefixSize, initDataRaw, kInitDataSize);
CdmInitData cdmPsshBox(reinterpret_cast<char*>(psshBoxRaw), kPsshBoxSize);
Vector<uint8_t> psshBox;
psshBox.appendArray(psshBoxRaw, kPsshBoxSize);
CdmKeyMessage cdmRequest(requestRaw, requestRaw + kRequestSize);
KeyedVector<String8, String8> parameters;
CdmAppParameterMap cdmParameters;
parameters.add(String8("paddingScheme"), String8("PKCS7"));
cdmParameters["paddingScheme"] = "PKCS7";
parameters.add(String8("favoriteParticle"), String8("tetraquark"));
cdmParameters["favoriteParticle"] = "tetraquark";
parameters.add(String8("answer"), String8("42"));
cdmParameters["answer"] = "42";
static const char* kDefaultUrl = "http://google.com/";
static const char* kMimeType = "video/mp4";
{
InSequence calls;
EXPECT_CALL(cdm, GenerateKeyRequest(cdmSessionId, "", kMimeType,
ElementsAreArray(psshBox, kPsshBoxSize),
kLicenseTypeOffline, cdmParameters, _,
_))
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
SetArgPointee<7>(kDefaultUrl),
Return(wvcdm::KEY_MESSAGE)));
EXPECT_CALL(cdm, GenerateKeyRequest(cdmSessionId, "", kMimeType,
ElementsAreArray(psshBox, kPsshBoxSize),
kLicenseTypeStreaming, cdmParameters, _,
_))
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
SetArgPointee<7>(kDefaultUrl),
Return(wvcdm::KEY_MESSAGE)));
EXPECT_CALL(cdm, GenerateKeyRequest("", cdmKeySetId, kMimeType,
ElementsAreArray(psshBox, kPsshBoxSize),
kLicenseTypeRelease, cdmParameters, _,
_))
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
SetArgPointee<7>(kDefaultUrl),
Return(wvcdm::KEY_MESSAGE)));
}
Vector<uint8_t> request;
String8 defaultUrl;
status_t res = plugin.getKeyRequest(sessionId, initData,
String8(kMimeType),
DrmPlugin::kKeyType_Offline,
parameters, request, defaultUrl);
ASSERT_EQ(OK, res);
EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize));
EXPECT_STREQ(kDefaultUrl, defaultUrl.string());
res = plugin.getKeyRequest(sessionId, initData, String8(kMimeType),
DrmPlugin::kKeyType_Streaming, parameters,
request, defaultUrl);
ASSERT_EQ(OK, res);
EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize));
EXPECT_STREQ(kDefaultUrl, defaultUrl.string());
res = plugin.getKeyRequest(keySetId, initData, String8(kMimeType),
DrmPlugin::kKeyType_Release, parameters,
request, defaultUrl);
ASSERT_EQ(OK, res);
EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize));
EXPECT_STREQ(kDefaultUrl, defaultUrl.string());
}
TEST_F(WVDrmPluginTest, GeneratesWebmKeyRequests) {
StrictMock<MockCDM> cdm;
StrictMock<MockCrypto> crypto;
WVDrmPlugin plugin(&cdm, &crypto);
static const size_t kInitDataSize = 128;
uint8_t initDataRaw[kInitDataSize];
static const size_t kRequestSize = 256;
uint8_t requestRaw[kRequestSize];
static const uint32_t kKeySetIdSize = 32;
uint8_t keySetIdRaw[kKeySetIdSize];
FILE* fp = fopen("/dev/urandom", "r");
fread(initDataRaw, sizeof(uint8_t), kInitDataSize, fp);
fread(requestRaw, sizeof(uint8_t), kRequestSize, fp);
fread(keySetIdRaw, sizeof(uint8_t), kKeySetIdSize, fp);
fclose(fp);
memcpy(keySetIdRaw, KEY_SET_ID_PREFIX, sizeof(KEY_SET_ID_PREFIX) - 1);
CdmKeySetId cdmKeySetId(reinterpret_cast<char *>(keySetIdRaw), kKeySetIdSize);
Vector<uint8_t> keySetId;
keySetId.appendArray(keySetIdRaw, kKeySetIdSize);
Vector<uint8_t> initData;
initData.appendArray(initDataRaw, kInitDataSize);
CdmKeyMessage cdmRequest(requestRaw, requestRaw + kRequestSize);
KeyedVector<String8, String8> parameters;
CdmAppParameterMap cdmParameters;
parameters.add(String8("paddingScheme"), String8("BUBBLE WRAP"));
cdmParameters["paddingScheme"] = "BUBBLE WRAP";
parameters.add(String8("favoriteParticle"), String8("higgs boson"));
cdmParameters["favoriteParticle"] = "higgs boson";
parameters.add(String8("favorite-particle"), String8("tetraquark"));
cdmParameters["favorite-particle"] = "tetraquark";
parameters.add(String8("answer"), String8("6 * 9"));
cdmParameters["answer"] = "6 * 9";
static const char* kDefaultUrl = "http://google.com/";
static const char* kMimeType = "video/webm";
static const char* kIsoBmffMimeType = "cenc";
static const char* kWebmMimeType = "webm";
struct TestSet {
const char* mimeType;
const Vector<uint8_t>& initDataIn;
const CdmInitData& initDataOut;
};
// We run the same set of operations on several sets of data, simulating
// different valid calling patterns.
TestSet testSets[] = {
{kIsoBmffMimeType, psshBox, cdmPsshBox}, // ISO-BMFF, EME passing style
{kIsoBmffMimeType, initData, cdmPsshBox}, // ISO-BMFF, old passing style
{kWebmMimeType, initData, cdmInitData} // WebM
};
size_t testSetCount = sizeof(testSets) / sizeof(TestSet);
// Set up the expected calls. Per gMock rules, this must be done for all test
// sets prior to testing any of them.
{
InSequence calls;
EXPECT_CALL(cdm, GenerateKeyRequest(cdmSessionId, "", kMimeType,
ElementsAreArray(initDataRaw,
kInitDataSize),
kLicenseTypeOffline, cdmParameters, _,
_))
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
SetArgPointee<7>(kDefaultUrl),
Return(wvcdm::KEY_MESSAGE)));
for (size_t i = 0; i < testSetCount; ++i)
{
const char* mimeType = testSets[i].mimeType;
const CdmInitData& initData = testSets[i].initDataOut;
EXPECT_CALL(cdm, GenerateKeyRequest(cdmSessionId, "", kMimeType,
ElementsAreArray(initDataRaw,
kInitDataSize),
kLicenseTypeStreaming, cdmParameters, _,
_))
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
SetArgPointee<7>(kDefaultUrl),
Return(wvcdm::KEY_MESSAGE)));
EXPECT_CALL(cdm, GenerateKeyRequest(cdmSessionId, "", mimeType, initData,
kLicenseTypeOffline, cdmParameters, _,
_))
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
SetArgPointee<7>(kDefaultUrl),
Return(wvcdm::KEY_MESSAGE)));
EXPECT_CALL(cdm, GenerateKeyRequest("", cdmKeySetId, kMimeType,
ElementsAreArray(initDataRaw,
kInitDataSize),
kLicenseTypeRelease, cdmParameters, _,
_))
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
SetArgPointee<7>(kDefaultUrl),
Return(wvcdm::KEY_MESSAGE)));
EXPECT_CALL(cdm, GenerateKeyRequest(cdmSessionId, "", mimeType, initData,
kLicenseTypeStreaming, cdmParameters, _,
_))
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
SetArgPointee<7>(kDefaultUrl),
Return(wvcdm::KEY_MESSAGE)));
EXPECT_CALL(cdm, GenerateKeyRequest("", cdmKeySetId, mimeType, initData,
kLicenseTypeRelease, cdmParameters, _,
_))
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
SetArgPointee<7>(kDefaultUrl),
Return(wvcdm::KEY_MESSAGE)));
}
}
Vector<uint8_t> request;
String8 defaultUrl;
// Performs the actual tests
for (size_t i = 0; i < testSetCount; ++i)
{
const String8 mimeType(testSets[i].mimeType);
const Vector<uint8_t>& initData = testSets[i].initDataIn;
status_t res = plugin.getKeyRequest(sessionId, initData,
String8(kMimeType),
DrmPlugin::kKeyType_Offline,
parameters, request, defaultUrl);
ASSERT_EQ(OK, res);
EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize));
EXPECT_STREQ(kDefaultUrl, defaultUrl.string());
Vector<uint8_t> request;
String8 defaultUrl;
res = plugin.getKeyRequest(sessionId, initData, String8(kMimeType),
DrmPlugin::kKeyType_Streaming, parameters,
request, defaultUrl);
ASSERT_EQ(OK, res);
EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize));
EXPECT_STREQ(kDefaultUrl, defaultUrl.string());
status_t res = plugin.getKeyRequest(sessionId, initData, mimeType,
DrmPlugin::kKeyType_Offline,
parameters, request, defaultUrl);
ASSERT_EQ(OK, res);
EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize));
EXPECT_STREQ(kDefaultUrl, defaultUrl.string());
res = plugin.getKeyRequest(keySetId, initData, String8(kMimeType),
DrmPlugin::kKeyType_Release, parameters,
request, defaultUrl);
ASSERT_EQ(OK, res);
EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize));
EXPECT_STREQ(kDefaultUrl, defaultUrl.string());
res = plugin.getKeyRequest(sessionId, initData, mimeType,
DrmPlugin::kKeyType_Streaming, parameters,
request, defaultUrl);
ASSERT_EQ(OK, res);
EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize));
EXPECT_STREQ(kDefaultUrl, defaultUrl.string());
res = plugin.getKeyRequest(keySetId, initData, mimeType,
DrmPlugin::kKeyType_Release, parameters,
request, defaultUrl);
ASSERT_EQ(OK, res);
EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize));
EXPECT_STREQ(kDefaultUrl, defaultUrl.string());
}
}
TEST_F(WVDrmPluginTest, AddsKeys) {

View File

@@ -26,8 +26,7 @@ bool WVDrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) {
}
bool WVDrmFactory::isContentTypeSupported(const String8 &initDataType) {
return wvcdm::WvContentDecryptionModule::SupportsInitDataType(
initDataType.string());
return wvcdm::WvContentDecryptionModule::IsSupported(initDataType.string());
}
status_t WVDrmFactory::createDrmPlugin(const uint8_t uuid[16],