resolved conflicts for merge of f111bea1 to master
Change-Id: I7f95eba8d5fb1e9a20800b9c1ef7fcb813eff41c
This commit is contained in:
@@ -35,6 +35,7 @@ class CdmEngine {
|
||||
// Construct a valid license request
|
||||
CdmResponseType GenerateKeyRequest(const CdmSessionId& session_id,
|
||||
const CdmKeySetId& key_set_id,
|
||||
const std::string& mime_type,
|
||||
const CdmInitData& init_data,
|
||||
const CdmLicenseType license_type,
|
||||
CdmAppParameterMap& app_parameters,
|
||||
|
||||
@@ -36,7 +36,8 @@ class CdmSession {
|
||||
bool VerifySession(const CdmKeySystem& key_system,
|
||||
const CdmInitData& init_data);
|
||||
|
||||
CdmResponseType GenerateKeyRequest(const CdmInitData& init_data,
|
||||
CdmResponseType GenerateKeyRequest(const std::string& mime_type,
|
||||
const CdmInitData& init_data,
|
||||
const CdmLicenseType license_type,
|
||||
const CdmAppParameterMap& app_parameters,
|
||||
CdmKeyMessage* key_request,
|
||||
@@ -109,7 +110,7 @@ class CdmSession {
|
||||
CdmLicenseType license_type_;
|
||||
|
||||
// license type offline related information
|
||||
CdmInitData offline_pssh_data_;
|
||||
CdmInitData offline_init_data_;
|
||||
CdmKeyMessage offline_key_request_;
|
||||
CdmKeyResponse offline_key_response_;
|
||||
CdmKeyMessage offline_key_renewal_request_;
|
||||
|
||||
@@ -27,7 +27,8 @@ class CdmLicense {
|
||||
bool Init(const std::string& token, CryptoSession* session,
|
||||
PolicyEngine* policy_engine);
|
||||
|
||||
bool PrepareKeyRequest(const CdmInitData& pssh_data,
|
||||
bool PrepareKeyRequest(const std::string& mime_type,
|
||||
const CdmInitData& init_data,
|
||||
const CdmLicenseType license_type,
|
||||
const CdmAppParameterMap& app_parameters,
|
||||
const CdmSessionId& session_id,
|
||||
@@ -42,7 +43,7 @@ class CdmLicense {
|
||||
bool RestoreOfflineLicense(CdmKeyMessage& license_request,
|
||||
CdmKeyResponse& license_response,
|
||||
CdmKeyResponse& license_renewal_response);
|
||||
bool HasInitData() { return !init_data_.empty(); }
|
||||
bool HasInitData() { return !stored_init_data_.empty(); }
|
||||
bool IsKeyLoaded(const KeyId& key_id);
|
||||
|
||||
private:
|
||||
@@ -54,12 +55,16 @@ class CdmLicense {
|
||||
CdmResponseType HandleKeyErrorResponse(
|
||||
const video_widevine_server::sdk::SignedMessage& signed_message);
|
||||
|
||||
template<typename T> bool PrepareContentId(const CdmLicenseType license_type,
|
||||
const std::string& request_id,
|
||||
T* content_id);
|
||||
|
||||
CryptoSession* session_;
|
||||
PolicyEngine* policy_engine_;
|
||||
std::string server_url_;
|
||||
std::string token_;
|
||||
std::string service_certificate_;
|
||||
std::string init_data_;
|
||||
std::string stored_init_data_;
|
||||
bool initialized_;
|
||||
std::set<KeyId> loaded_keys_;
|
||||
|
||||
|
||||
@@ -56,6 +56,8 @@ static const std::string QUERY_VALUE_SECURITY_LEVEL_L2 = "L2";
|
||||
static const std::string QUERY_VALUE_SECURITY_LEVEL_L3 = "L3";
|
||||
static const std::string QUERY_VALUE_SECURITY_LEVEL_UNKNOWN = "Unknown";
|
||||
|
||||
static const std::string ISO_BMFF_MIME_TYPE = "video/mp4";
|
||||
static const std::string WEBM_MIME_TYPE = "video/webm";
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_WV_CDM_CONSTANTS_H_
|
||||
|
||||
@@ -118,6 +118,7 @@ CdmResponseType CdmEngine::CloseKeySetSession(const CdmKeySetId& key_set_id) {
|
||||
CdmResponseType CdmEngine::GenerateKeyRequest(
|
||||
const CdmSessionId& session_id,
|
||||
const CdmKeySetId& key_set_id,
|
||||
const std::string& mime_type,
|
||||
const CdmInitData& init_data,
|
||||
const CdmLicenseType license_type,
|
||||
CdmAppParameterMap& app_parameters,
|
||||
@@ -173,7 +174,7 @@ CdmResponseType CdmEngine::GenerateKeyRequest(
|
||||
}
|
||||
}
|
||||
|
||||
sts = iter->second->GenerateKeyRequest(init_data, license_type,
|
||||
sts = iter->second->GenerateKeyRequest(mime_type, init_data, license_type,
|
||||
app_parameters, key_request,
|
||||
server_url);
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ CdmResponseType CdmSession::RestoreOfflineSession(
|
||||
|
||||
DeviceFiles::LicenseState license_state;
|
||||
|
||||
if (!handle.RetrieveLicense(key_set_id, &license_state, &offline_pssh_data_,
|
||||
if (!handle.RetrieveLicense(key_set_id, &license_state, &offline_init_data_,
|
||||
&offline_key_request_, &offline_key_response_,
|
||||
&offline_key_renewal_request_,
|
||||
&offline_key_renewal_response_,
|
||||
@@ -122,9 +122,9 @@ bool CdmSession::VerifySession(const CdmKeySystem& key_system,
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
const CdmInitData& init_data, const CdmLicenseType license_type,
|
||||
const CdmAppParameterMap& app_parameters, CdmKeyMessage* key_request,
|
||||
std::string* server_url) {
|
||||
const std::string& mime_type, const CdmInitData& init_data,
|
||||
const CdmLicenseType license_type, const CdmAppParameterMap& app_parameters,
|
||||
CdmKeyMessage* key_request, std::string* server_url) {
|
||||
if (reinitialize_session_) {
|
||||
CdmResponseType sts = Init();
|
||||
if (sts != NO_ERROR) {
|
||||
@@ -152,14 +152,18 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
? UNKNOWN_ERROR
|
||||
: GenerateRenewalRequest(key_request, server_url);
|
||||
} else {
|
||||
if (mime_type != ISO_BMFF_MIME_TYPE && mime_type != WEBM_MIME_TYPE) {
|
||||
LOGW("CdmSession::GenerateKeyRequest: unknown MIME type");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
if (init_data.empty() && !license_parser_.HasInitData()) {
|
||||
LOGW("CdmSession::GenerateKeyRequest: init data absent");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
CdmInitData pssh_data = init_data;
|
||||
if (Properties::extract_pssh_data()) {
|
||||
if (!CdmEngine::ExtractWidevinePssh(init_data, &pssh_data)) {
|
||||
CdmInitData extracted_init_data = init_data;
|
||||
if (Properties::extract_pssh_data() && mime_type == ISO_BMFF_MIME_TYPE) {
|
||||
if (!CdmEngine::ExtractWidevinePssh(init_data, &extracted_init_data)) {
|
||||
return KEY_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -174,14 +178,15 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
}
|
||||
}
|
||||
|
||||
if (!license_parser_.PrepareKeyRequest(pssh_data, license_type,
|
||||
app_parameters, session_id_,
|
||||
key_request, server_url)) {
|
||||
if (!license_parser_.PrepareKeyRequest(mime_type, extracted_init_data,
|
||||
license_type, app_parameters,
|
||||
session_id_, key_request,
|
||||
server_url)) {
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
if (license_type_ == kLicenseTypeOffline) {
|
||||
offline_pssh_data_ = pssh_data;
|
||||
offline_init_data_ = extracted_init_data;
|
||||
offline_key_request_ = *key_request;
|
||||
offline_release_server_url_ = *server_url;
|
||||
}
|
||||
@@ -415,7 +420,7 @@ bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) {
|
||||
return false;
|
||||
|
||||
return handle.StoreLicense(
|
||||
key_set_id_, state, offline_pssh_data_, offline_key_request_,
|
||||
key_set_id_, state, offline_init_data_, offline_key_request_,
|
||||
offline_key_response_, offline_key_renewal_request_,
|
||||
offline_key_renewal_response_, offline_release_server_url_);
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ using video_widevine_server::sdk::EncryptedClientIdentification;
|
||||
using video_widevine_server::sdk::LicenseRequest;
|
||||
using video_widevine_server::sdk::LicenseRequest_ContentIdentification;
|
||||
using video_widevine_server::sdk::LicenseRequest_ContentIdentification_CENC;
|
||||
using video_widevine_server::sdk::LicenseRequest_ContentIdentification_WebM;
|
||||
using video_widevine_server::sdk::
|
||||
LicenseRequest_ContentIdentification_ExistingLicense;
|
||||
using video_widevine_server::sdk::License;
|
||||
@@ -157,7 +158,8 @@ bool CdmLicense::Init(const std::string& token, CryptoSession* session,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
bool CdmLicense::PrepareKeyRequest(const std::string& mime_type,
|
||||
const CdmInitData& init_data,
|
||||
const CdmLicenseType license_type,
|
||||
const CdmAppParameterMap& app_parameters,
|
||||
const CdmSessionId& session_id,
|
||||
@@ -167,7 +169,12 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
LOGE("CdmLicense::PrepareKeyRequest: not initialized");
|
||||
return false;
|
||||
}
|
||||
if (init_data.empty() && init_data_.empty()) {
|
||||
if (mime_type != ISO_BMFF_MIME_TYPE && mime_type != WEBM_MIME_TYPE) {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: unsupported MIME type %s",
|
||||
mime_type.c_str());
|
||||
return false;
|
||||
}
|
||||
if (init_data.empty() && stored_init_data_.empty()) {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: empty init data provided");
|
||||
return false;
|
||||
}
|
||||
@@ -192,7 +199,7 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
serialized_service_certificate = service_certificate_;
|
||||
|
||||
if (privacy_mode_enabled && serialized_service_certificate.empty()) {
|
||||
init_data_ = init_data;
|
||||
stored_init_data_ = init_data;
|
||||
return PrepareServiceCertificateRequest(signed_request, server_url);
|
||||
}
|
||||
|
||||
@@ -308,33 +315,44 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
LicenseRequest_ContentIdentification* content_id =
|
||||
license_request.mutable_content_id();
|
||||
|
||||
LicenseRequest_ContentIdentification_CENC* cenc_content_id =
|
||||
content_id->mutable_cenc_id();
|
||||
if (mime_type == ISO_BMFF_MIME_TYPE) {
|
||||
LicenseRequest_ContentIdentification_CENC* cenc_content_id =
|
||||
content_id->mutable_cenc_id();
|
||||
|
||||
if (!init_data.empty()) {
|
||||
cenc_content_id->add_pssh(init_data);
|
||||
} else if (privacy_mode_enabled && !init_data_.empty()) {
|
||||
cenc_content_id->add_pssh(init_data_);
|
||||
if (!init_data.empty()) {
|
||||
cenc_content_id->add_pssh(init_data);
|
||||
} else if (privacy_mode_enabled && !stored_init_data_.empty()) {
|
||||
cenc_content_id->add_pssh(stored_init_data_);
|
||||
} else {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: ISO-CENC init data not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!PrepareContentId(license_type, request_id, cenc_content_id)) {
|
||||
return false;
|
||||
}
|
||||
} else if (mime_type == WEBM_MIME_TYPE) {
|
||||
LicenseRequest_ContentIdentification_WebM* webm_content_id =
|
||||
content_id->mutable_webm_id();
|
||||
|
||||
if (!init_data.empty()) {
|
||||
webm_content_id->set_header(init_data);
|
||||
} else if (privacy_mode_enabled && !stored_init_data_.empty()) {
|
||||
webm_content_id->set_header(stored_init_data_);
|
||||
} else {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: WebM init data not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!PrepareContentId(license_type, request_id, webm_content_id)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOGD("CdmLicense::PrepareKeyRequest: init data not available");
|
||||
LOGE("CdmLicense::PrepareKeyRequest: no support for MIME type %s",
|
||||
mime_type.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (license_type) {
|
||||
case kLicenseTypeOffline:
|
||||
cenc_content_id->set_license_type(video_widevine_server::sdk::OFFLINE);
|
||||
break;
|
||||
case kLicenseTypeStreaming:
|
||||
cenc_content_id->set_license_type(video_widevine_server::sdk::STREAMING);
|
||||
break;
|
||||
default:
|
||||
LOGD("CdmLicense::PrepareKeyRequest: Unknown license type = %d",
|
||||
license_type);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
cenc_content_id->set_request_id(request_id);
|
||||
|
||||
// TODO(jfore): The time field will be updated once the cdm wrapper
|
||||
// has been updated to pass us in the time.
|
||||
license_request.set_request_time(0);
|
||||
@@ -766,6 +784,28 @@ CdmResponseType CdmLicense::HandleKeyErrorResponse(
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool CdmLicense::PrepareContentId(const CdmLicenseType license_type,
|
||||
const std::string& request_id,
|
||||
T* content_id) {
|
||||
switch (license_type) {
|
||||
case kLicenseTypeOffline:
|
||||
content_id->set_license_type(video_widevine_server::sdk::OFFLINE);
|
||||
break;
|
||||
case kLicenseTypeStreaming:
|
||||
content_id->set_license_type(
|
||||
video_widevine_server::sdk::STREAMING);
|
||||
break;
|
||||
default:
|
||||
LOGD("CdmLicense::PrepareKeyRequest: Unknown license type = %d",
|
||||
license_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
content_id->set_request_id(request_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CdmLicense::IsKeyLoaded(const KeyId& key_id) {
|
||||
return loaded_keys_.find(key_id) != loaded_keys_.end();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "scoped_ptr.h"
|
||||
#include "string_conversions.h"
|
||||
#include "url_request.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace {
|
||||
@@ -99,20 +100,22 @@ class WvCdmEngineTest : public testing::Test {
|
||||
|
||||
protected:
|
||||
void GenerateKeyRequest(const std::string& key_system,
|
||||
const std::string& key_id) {
|
||||
const std::string& key_id,
|
||||
const std::string& mime_type) {
|
||||
CdmAppParameterMap app_parameters;
|
||||
std::string server_url;
|
||||
std::string init_data = key_id;
|
||||
CdmKeySetId key_set_id;
|
||||
|
||||
// TODO(rfrias): Temporary change till b/9465346 is addressed
|
||||
if (!Properties::extract_pssh_data()) {
|
||||
if (!Properties::extract_pssh_data() || mime_type != ISO_BMFF_MIME_TYPE) {
|
||||
EXPECT_TRUE(CdmEngine::ExtractWidevinePssh(key_id, &init_data));
|
||||
}
|
||||
|
||||
EXPECT_EQ(KEY_MESSAGE,
|
||||
cdm_engine_.GenerateKeyRequest(session_id_,
|
||||
key_set_id,
|
||||
mime_type,
|
||||
init_data,
|
||||
kLicenseTypeStreaming,
|
||||
app_parameters,
|
||||
@@ -165,7 +168,7 @@ class WvCdmEngineTest : public testing::Test {
|
||||
std::string resp = GetKeyRequestResponse(server_url,
|
||||
client_auth);
|
||||
CdmKeySetId key_set_id;
|
||||
EXPECT_EQ(cdm_engine_.AddKey(session_id_, resp, &key_set_id), KEY_ADDED);
|
||||
EXPECT_EQ(wvcdm::KEY_ADDED, cdm_engine_.AddKey(session_id_, resp, &key_set_id));
|
||||
}
|
||||
|
||||
void VerifyRenewalKeyResponse(const std::string& server_url,
|
||||
@@ -173,7 +176,7 @@ class WvCdmEngineTest : public testing::Test {
|
||||
std::string& init_data) {
|
||||
std::string resp = GetKeyRequestResponse(server_url,
|
||||
client_auth);
|
||||
EXPECT_EQ(cdm_engine_.RenewKey(session_id_, resp), wvcdm::KEY_ADDED);
|
||||
EXPECT_EQ(wvcdm::KEY_ADDED, cdm_engine_.RenewKey(session_id_, resp));
|
||||
}
|
||||
|
||||
CdmEngine cdm_engine_;
|
||||
@@ -191,27 +194,39 @@ TEST(WvCdmProvisioningTest, ProvisioningTest) {
|
||||
cdm_engine.HandleProvisioningResponse(kValidJsonProvisioningResponse);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmEngineTest, BaseMessageTest) {
|
||||
GenerateKeyRequest(g_key_system, g_key_id);
|
||||
TEST_F(WvCdmEngineTest, BaseIsoBmffMessageTest) {
|
||||
GenerateKeyRequest(g_key_system, g_key_id, "video/mp4");
|
||||
GetKeyRequestResponse(g_license_server, g_client_auth);
|
||||
}
|
||||
|
||||
// TODO(juce): Set up with correct test data.
|
||||
TEST_F(WvCdmEngineTest, DISABLED_BaseWebmMessageTest) {
|
||||
GenerateKeyRequest(g_key_system, g_key_id, "video/webm");
|
||||
GetKeyRequestResponse(g_license_server, g_client_auth);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmEngineTest, WrongMessageTest) {
|
||||
std::string wrong_message = a2bs_hex(g_wrong_key_id);
|
||||
GenerateKeyRequest(g_key_system, wrong_message);
|
||||
GenerateKeyRequest(g_key_system, wrong_message, "video/mp4");
|
||||
|
||||
// We should receive a response with no license, i.e. the extracted license
|
||||
// response message should be empty.
|
||||
ASSERT_EQ("", GetKeyRequestResponse(g_license_server, g_client_auth));
|
||||
}
|
||||
|
||||
TEST_F(WvCdmEngineTest, NormalDecryption) {
|
||||
GenerateKeyRequest(g_key_system, g_key_id);
|
||||
TEST_F(WvCdmEngineTest, NormalDecryptionIsoBmff) {
|
||||
GenerateKeyRequest(g_key_system, g_key_id, "video/mp4");
|
||||
VerifyNewKeyResponse(g_license_server, g_client_auth, g_key_id);
|
||||
}
|
||||
|
||||
// TODO(juce): Set up with correct test data.
|
||||
TEST_F(WvCdmEngineTest, DISABLED_NormalDecryptionWebm) {
|
||||
GenerateKeyRequest(g_key_system, g_key_id, "video/webm");
|
||||
VerifyNewKeyResponse(g_license_server, g_client_auth, g_key_id);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmEngineTest, LicenseRenewal) {
|
||||
GenerateKeyRequest(g_key_system, g_key_id);
|
||||
GenerateKeyRequest(g_key_system, g_key_id, "video/mp4");
|
||||
VerifyNewKeyResponse(g_license_server, g_client_auth, g_key_id);
|
||||
|
||||
GenerateRenewalRequest(g_key_system, g_key_id);
|
||||
|
||||
@@ -74,12 +74,29 @@ TEST(LicenseTestSession, InitNullSession) {
|
||||
}
|
||||
|
||||
// TODO(rfrias): Fix or remove test.
|
||||
TEST_F(LicenseTest, DISABLED_PrepareKeyRequest) {
|
||||
TEST_F(LicenseTest, DISABLED_PrepareIsoBmffKeyRequest) {
|
||||
std::string signed_request;
|
||||
CdmAppParameterMap app_parameters;
|
||||
std::string server_url;
|
||||
CdmSessionId session_id;
|
||||
license_.PrepareKeyRequest(a2bs_hex(kInitData),
|
||||
license_.PrepareKeyRequest("video/mp4",
|
||||
a2bs_hex(kInitData),
|
||||
kLicenseTypeStreaming,
|
||||
app_parameters,
|
||||
session_id,
|
||||
&signed_request,
|
||||
&server_url);
|
||||
EXPECT_EQ(signed_request, a2bs_hex(kSignedRequest));
|
||||
}
|
||||
|
||||
// TODO(rfrias): Fix or remove test.
|
||||
TEST_F(LicenseTest, DISABLED_PrepareWebmKeyRequest) {
|
||||
std::string signed_request;
|
||||
CdmAppParameterMap app_parameters;
|
||||
std::string server_url;
|
||||
CdmSessionId session_id;
|
||||
license_.PrepareKeyRequest("video/webm",
|
||||
a2bs_hex(kInitData),
|
||||
kLicenseTypeStreaming,
|
||||
app_parameters,
|
||||
session_id,
|
||||
@@ -94,7 +111,8 @@ TEST_F(LicenseTest, DISABLED_HandleKeyResponseValid) {
|
||||
CdmAppParameterMap app_parameters;
|
||||
CdmSessionId session_id;
|
||||
std::string server_url;
|
||||
license_.PrepareKeyRequest(a2bs_hex(kInitData),
|
||||
license_.PrepareKeyRequest("video/mp4",
|
||||
a2bs_hex(kInitData),
|
||||
kLicenseTypeStreaming,
|
||||
app_parameters,
|
||||
session_id,
|
||||
@@ -110,7 +128,8 @@ TEST_F(LicenseTest, DISABLED_HandleKeyResponseInvalid) {
|
||||
CdmAppParameterMap app_parameters;
|
||||
CdmSessionId session_id;
|
||||
std::string server_url;
|
||||
license_.PrepareKeyRequest(a2bs_hex(kInitData),
|
||||
license_.PrepareKeyRequest("video/mp4",
|
||||
a2bs_hex(kInitData),
|
||||
kLicenseTypeStreaming,
|
||||
app_parameters,
|
||||
session_id,
|
||||
|
||||
@@ -30,6 +30,7 @@ class WvContentDecryptionModule : public TimerHandler {
|
||||
// Construct a valid license request.
|
||||
virtual CdmResponseType GenerateKeyRequest(const CdmSessionId& session_id,
|
||||
const CdmKeySetId& key_set_id,
|
||||
const std::string& mime_type,
|
||||
const CdmInitData& init_data,
|
||||
const CdmLicenseType license_type,
|
||||
CdmAppParameterMap& app_parameters,
|
||||
|
||||
@@ -49,6 +49,7 @@ CdmResponseType WvContentDecryptionModule::CloseSession(
|
||||
CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
|
||||
const CdmSessionId& session_id,
|
||||
const CdmKeySetId& key_set_id,
|
||||
const std::string& mime_type,
|
||||
const CdmInitData& init_data,
|
||||
const CdmLicenseType license_type,
|
||||
CdmAppParameterMap& app_parameters,
|
||||
@@ -60,7 +61,7 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
|
||||
if (sts != NO_ERROR)
|
||||
return sts;
|
||||
}
|
||||
sts = cdm_engine_->GenerateKeyRequest(session_id, key_set_id,
|
||||
sts = cdm_engine_->GenerateKeyRequest(session_id, key_set_id, mime_type,
|
||||
init_data, license_type,
|
||||
app_parameters, key_request,
|
||||
server_url);
|
||||
|
||||
@@ -301,7 +301,8 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
||||
std::string server_url;
|
||||
std::string key_set_id;
|
||||
EXPECT_EQ(wvcdm::KEY_MESSAGE,
|
||||
decryptor_.GenerateKeyRequest(session_id_, key_set_id, init_data,
|
||||
decryptor_.GenerateKeyRequest(session_id_, key_set_id,
|
||||
"video/mp4", init_data,
|
||||
license_type, app_parameters,
|
||||
&key_msg_, &server_url));
|
||||
EXPECT_EQ(0u, server_url.size());
|
||||
@@ -315,7 +316,8 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
||||
std::string init_data;
|
||||
wvcdm::CdmAppParameterMap app_parameters;
|
||||
EXPECT_EQ(wvcdm::KEY_MESSAGE,
|
||||
decryptor_.GenerateKeyRequest(session_id_, key_set_id_, init_data,
|
||||
decryptor_.GenerateKeyRequest(session_id_, key_set_id_,
|
||||
"video/mp4", init_data,
|
||||
license_type, app_parameters,
|
||||
&key_msg_, server_url));
|
||||
// TODO(edwinwong, rfrias): Add tests cases for when license server url
|
||||
@@ -329,9 +331,10 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
||||
wvcdm::CdmAppParameterMap app_parameters;
|
||||
std::string server_url;
|
||||
EXPECT_EQ(wvcdm::KEY_MESSAGE,
|
||||
decryptor_.GenerateKeyRequest(session_id, key_set_id, init_data,
|
||||
kLicenseTypeRelease, app_parameters,
|
||||
&key_msg_, &server_url));
|
||||
decryptor_.GenerateKeyRequest(session_id, key_set_id, "video/mp4",
|
||||
init_data, kLicenseTypeRelease,
|
||||
app_parameters, &key_msg_,
|
||||
&server_url));
|
||||
}
|
||||
|
||||
// Post a request and extract the drm message from the response
|
||||
@@ -879,12 +882,12 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
|
||||
wvcdm::CdmAppParameterMap app_parameters;
|
||||
std::string server_url;
|
||||
EXPECT_EQ(wvcdm::NEED_PROVISIONING,
|
||||
|
||||
decryptor_.GenerateKeyRequest(session_id_, key_set_id, g_key_id,
|
||||
kLicenseTypeStreaming, app_parameters,
|
||||
&key_msg_, &server_url));
|
||||
decryptor_.GenerateKeyRequest(session_id_, key_set_id, "video/mp4",
|
||||
g_key_id, kLicenseTypeStreaming,
|
||||
app_parameters, &key_msg_,
|
||||
&server_url));
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest(
|
||||
&key_msg_, &provisioning_server_url));
|
||||
&key_msg_, &provisioning_server_url));
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url());
|
||||
|
||||
@@ -149,22 +149,51 @@ status_t WVDrmPlugin::getKeyRequest(
|
||||
return android::ERROR_DRM_CANNOT_HANDLE;
|
||||
}
|
||||
|
||||
// Build PSSH box for PSSH data in initData.
|
||||
static const char psshPrefix[] = {
|
||||
0, 0, 0, 0, // Total size
|
||||
'p', 's', 's', 'h', // "PSSH"
|
||||
0, 0, 0, 0, // Flags - must be zero
|
||||
0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, // Widevine UUID
|
||||
0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED,
|
||||
0, 0, 0, 0 // Size of initData
|
||||
};
|
||||
CdmInitData psshBox(psshPrefix, sizeof(psshPrefix) / sizeof(uint8_t));
|
||||
psshBox.append(reinterpret_cast<const char*>(initData.array()),
|
||||
initData.size());
|
||||
uint32_t* psshBoxSize = reinterpret_cast<uint32_t*>(&psshBox[0]);
|
||||
uint32_t* initDataSize = reinterpret_cast<uint32_t*>(&psshBox[28]);
|
||||
*initDataSize = htonl(initData.size());
|
||||
*psshBoxSize = htonl(psshBox.size());
|
||||
string cdmMimeType = mimeType.string();
|
||||
|
||||
// Provide backwards-compatibility for versions of apps that pass the wrong
|
||||
// MIME type.
|
||||
// TODO(b/13731637) - Remove this.
|
||||
if (cdmMimeType == "") {
|
||||
ALOGW("ALERT: Empty MIME type is supported for backwards-compatibility "
|
||||
"only and may go away in the future. Switch to \"video/mp4\" to "
|
||||
"become compliant.");
|
||||
cdmMimeType = "video/mp4";
|
||||
} else if (cdmMimeType == "video/avc") {
|
||||
ALOGW("ALERT: MIME type \"video/avc\" is supported for backwards-"
|
||||
"compatibility only and may go away in the future. Switch to "
|
||||
"\"video/mp4\" to become compliant.");
|
||||
cdmMimeType = "video/mp4";
|
||||
}
|
||||
|
||||
CdmInitData processedInitData;
|
||||
if (cdmMimeType == wvcdm::ISO_BMFF_MIME_TYPE) {
|
||||
// For ISO-BMFF, 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"
|
||||
0, 0, 0, 0, // Flags - must be zero
|
||||
0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, // Widevine UUID
|
||||
0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED,
|
||||
0, 0, 0, 0 // Size of initData
|
||||
};
|
||||
processedInitData.assign(psshPrefix, sizeof(psshPrefix) / sizeof(char));
|
||||
processedInitData.append(reinterpret_cast<const char*>(initData.array()),
|
||||
initData.size());
|
||||
const size_t kPsshBoxSizeLocation = 0;
|
||||
const size_t kInitDataSizeLocation =
|
||||
sizeof(psshPrefix) - sizeof(uint32_t);
|
||||
uint32_t psshBoxSize = htonl(processedInitData.size());
|
||||
uint32_t initDataSize = htonl(initData.size());
|
||||
memcpy(&processedInitData[kPsshBoxSizeLocation], &psshBoxSize,
|
||||
sizeof(uint32_t));
|
||||
memcpy(&processedInitData[kInitDataSizeLocation], &initDataSize,
|
||||
sizeof(uint32_t));
|
||||
} else {
|
||||
// For other formats, we can pass the init data through unmodified.
|
||||
processedInitData.assign(reinterpret_cast<const char*>(initData.array()),
|
||||
initData.size());
|
||||
}
|
||||
|
||||
CdmAppParameterMap cdmParameters;
|
||||
for (size_t i = 0; i < optionalParameters.size(); ++i) {
|
||||
@@ -179,11 +208,10 @@ status_t WVDrmPlugin::getKeyRequest(
|
||||
|
||||
CdmKeyMessage keyRequest;
|
||||
string cdmDefaultUrl;
|
||||
|
||||
CdmResponseType res = mCDM->GenerateKeyRequest(cdmSessionId, cdmKeySetId,
|
||||
psshBox, cdmLicenseType,
|
||||
cdmParameters, &keyRequest,
|
||||
&cdmDefaultUrl);
|
||||
cdmMimeType, processedInitData,
|
||||
cdmLicenseType, cdmParameters,
|
||||
&keyRequest, &cdmDefaultUrl);
|
||||
|
||||
if (isCdmResponseTypeSuccess(res)) {
|
||||
defaultUrl.clear();
|
||||
|
||||
@@ -31,8 +31,9 @@ class MockCDM : public WvContentDecryptionModule {
|
||||
|
||||
MOCK_METHOD1(CloseSession, CdmResponseType(const CdmSessionId&));
|
||||
|
||||
MOCK_METHOD7(GenerateKeyRequest, CdmResponseType(const CdmSessionId&,
|
||||
MOCK_METHOD8(GenerateKeyRequest, CdmResponseType(const CdmSessionId&,
|
||||
const CdmKeySetId&,
|
||||
const std::string&,
|
||||
const CdmInitData&,
|
||||
const CdmLicenseType,
|
||||
CdmAppParameterMap&,
|
||||
@@ -174,7 +175,7 @@ TEST_F(WVDrmPluginTest, ClosesSessions) {
|
||||
ASSERT_EQ(OK, res);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, GeneratesKeyRequests) {
|
||||
TEST_F(WVDrmPluginTest, GeneratesIsoBmffKeyRequests) {
|
||||
StrictMock<MockCDM> cdm;
|
||||
StrictMock<MockCrypto> crypto;
|
||||
WVDrmPlugin plugin(&cdm, &crypto);
|
||||
@@ -226,32 +227,33 @@ TEST_F(WVDrmPluginTest, GeneratesKeyRequests) {
|
||||
cdmParameters["answer"] = "42";
|
||||
|
||||
static const char* kDefaultUrl = "http://google.com/";
|
||||
static const char* kMimeType = "video/mp4";
|
||||
|
||||
{
|
||||
InSequence calls;
|
||||
|
||||
EXPECT_CALL(cdm, GenerateKeyRequest(cdmSessionId, "",
|
||||
EXPECT_CALL(cdm, GenerateKeyRequest(cdmSessionId, "", kMimeType,
|
||||
ElementsAreArray(psshBox, kPsshBoxSize),
|
||||
kLicenseTypeOffline, cdmParameters, _,
|
||||
_))
|
||||
.WillOnce(DoAll(SetArgPointee<5>(cdmRequest),
|
||||
SetArgPointee<6>(kDefaultUrl),
|
||||
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
|
||||
SetArgPointee<7>(kDefaultUrl),
|
||||
Return(wvcdm::KEY_MESSAGE)));
|
||||
|
||||
EXPECT_CALL(cdm, GenerateKeyRequest(cdmSessionId, "",
|
||||
EXPECT_CALL(cdm, GenerateKeyRequest(cdmSessionId, "", kMimeType,
|
||||
ElementsAreArray(psshBox, kPsshBoxSize),
|
||||
kLicenseTypeStreaming, cdmParameters, _,
|
||||
_))
|
||||
.WillOnce(DoAll(SetArgPointee<5>(cdmRequest),
|
||||
SetArgPointee<6>(kDefaultUrl),
|
||||
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
|
||||
SetArgPointee<7>(kDefaultUrl),
|
||||
Return(wvcdm::KEY_MESSAGE)));
|
||||
|
||||
EXPECT_CALL(cdm, GenerateKeyRequest("", cdmKeySetId,
|
||||
EXPECT_CALL(cdm, GenerateKeyRequest("", cdmKeySetId, kMimeType,
|
||||
ElementsAreArray(psshBox, kPsshBoxSize),
|
||||
kLicenseTypeRelease, cdmParameters, _,
|
||||
_))
|
||||
.WillOnce(DoAll(SetArgPointee<5>(cdmRequest),
|
||||
SetArgPointee<6>(kDefaultUrl),
|
||||
.WillOnce(DoAll(SetArgPointee<6>(cdmRequest),
|
||||
SetArgPointee<7>(kDefaultUrl),
|
||||
Return(wvcdm::KEY_MESSAGE)));
|
||||
}
|
||||
|
||||
@@ -259,21 +261,118 @@ TEST_F(WVDrmPluginTest, GeneratesKeyRequests) {
|
||||
String8 defaultUrl;
|
||||
|
||||
status_t res = plugin.getKeyRequest(sessionId, initData,
|
||||
String8("video/h264"),
|
||||
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("video/h264"),
|
||||
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("video/h264"),
|
||||
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("answer"), String8("6 * 9"));
|
||||
cdmParameters["answer"] = "6 * 9";
|
||||
|
||||
static const char* kDefaultUrl = "http://google.com/";
|
||||
static const char* kMimeType = "video/webm";
|
||||
|
||||
{
|
||||
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)));
|
||||
|
||||
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("", cdmKeySetId, kMimeType,
|
||||
ElementsAreArray(initDataRaw,
|
||||
kInitDataSize),
|
||||
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);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "WVDrmFactory.h"
|
||||
|
||||
#include "utils/Errors.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "WVCDMSingleton.h"
|
||||
#include "WVDrmPlugin.h"
|
||||
#include "WVUUID.h"
|
||||
@@ -24,8 +25,9 @@ bool WVDrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) {
|
||||
}
|
||||
|
||||
bool WVDrmFactory::isContentTypeSupported(const String8 &mimeType) {
|
||||
// For now, only ISO-BMFF is supported, which has MIME-type video/mp4
|
||||
return mimeType == "video/mp4";
|
||||
// Support ISO-BMFF (video/mp4) and WebM (video/webm).
|
||||
return mimeType == wvcdm::ISO_BMFF_MIME_TYPE.c_str() ||
|
||||
mimeType == wvcdm::WEBM_MIME_TYPE.c_str();
|
||||
}
|
||||
|
||||
status_t WVDrmFactory::createDrmPlugin(const uint8_t uuid[16],
|
||||
|
||||
@@ -46,14 +46,14 @@ TEST(WVDrmFactoryTest, SupportsSupportedContainerFormats) {
|
||||
|
||||
EXPECT_TRUE(factory.isContentTypeSupported(String8("video/mp4"))) <<
|
||||
"WVPluginFactory does not support ISO-BMFF";
|
||||
|
||||
EXPECT_TRUE(factory.isContentTypeSupported(String8("video/webm"))) <<
|
||||
"WVPluginFactory does not support WebM";
|
||||
}
|
||||
|
||||
TEST(WVDrmFactoryTest, DoesNotSupportUnsupportedContainerFormats) {
|
||||
WVDrmFactory factory;
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/webm"))) <<
|
||||
"WVPluginFactory incorrectly claims to support Web-M";
|
||||
|
||||
// Taken from Encoding.com's list of the most common internet video MIME-types
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/x-matroska"))) <<
|
||||
"WVPluginFactory incorrectly claims to support Matroska";
|
||||
|
||||
Reference in New Issue
Block a user