resolved conflicts for merge of 7eea20df to master

Change-Id: Ibd8b16745d36b24041856f315fbb09a6c25cf4fb
This commit is contained in:
John "Juce" Bruce
2014-04-02 18:59:05 -07:00
19 changed files with 288 additions and 194 deletions

View File

@@ -28,6 +28,7 @@ LOCAL_SRC_FILES := \
$(CORE_SRC_DIR)/certificate_provisioning.cpp \
$(CORE_SRC_DIR)/crypto_session.cpp \
$(CORE_SRC_DIR)/device_files.cpp \
$(CORE_SRC_DIR)/initialization_data.cpp \
$(CORE_SRC_DIR)/license.cpp \
$(CORE_SRC_DIR)/oemcrypto_adapter_dynamic.cpp \
$(CORE_SRC_DIR)/policy_engine.cpp \

View File

@@ -4,6 +4,7 @@
#define CDM_BASE_CDM_ENGINE_H_
#include "certificate_provisioning.h"
#include "initialization_data.h"
#include "oemcrypto_adapter.h"
#include "wv_cdm_types.h"
@@ -35,8 +36,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 InitializationData& init_data,
const CdmLicenseType license_type,
CdmAppParameterMap& app_parameters,
CdmKeyMessage* key_request,
@@ -110,11 +110,6 @@ class CdmEngine {
bool DetachEventListener(const CdmSessionId& session_id,
WvCdmEventListener* listener);
// Parse a blob of multiple concatenated PSSH atoms to extract the first
// widevine pssh
static bool ExtractWidevinePssh(const CdmInitData& init_data,
CdmInitData* output);
// Timer expiration method
void OnTimerEvent();

View File

@@ -7,6 +7,7 @@
#include "crypto_session.h"
#include "device_files.h"
#include "initialization_data.h"
#include "license.h"
#include "oemcrypto_adapter.h"
#include "policy_engine.h"
@@ -34,10 +35,9 @@ class CdmSession {
const CdmSessionId& session_id() { return session_id_; }
bool VerifySession(const CdmKeySystem& key_system,
const CdmInitData& init_data);
const InitializationData& init_data);
CdmResponseType GenerateKeyRequest(const std::string& mime_type,
const CdmInitData& init_data,
CdmResponseType GenerateKeyRequest(const InitializationData& init_data,
const CdmLicenseType license_type,
const CdmAppParameterMap& app_parameters,
CdmKeyMessage* key_request,

View File

@@ -0,0 +1,47 @@
// Copyright 2014 Google Inc. All Rights Reserved.
#ifndef CORE_INCLUDE_INITIALIZATION_DATA_H_
#define CORE_INCLUDE_INITIALIZATION_DATA_H_
#include <string>
#include "wv_cdm_types.h"
namespace wvcdm {
class WvCdmEngineTest;
class InitializationData {
public:
InitializationData(const std::string& type,
const CdmInitData& data = CdmInitData());
bool is_supported() const { return is_cenc_ || is_webm_; }
bool is_cenc() const { return is_cenc_; }
bool is_webm() const { return is_webm_; }
bool IsEmpty() const { return data_.empty(); }
const std::string& type() const { return type_; }
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);
std::string type_;
CdmInitData data_;
bool is_cenc_;
bool is_webm_;
CORE_DISALLOW_COPY_AND_ASSIGN(InitializationData);
};
} // namespace wvcdm
#endif // CORE_INCLUDE_INITIALIZATION_DATA_H_

View File

@@ -5,6 +5,7 @@
#include <set>
#include "initialization_data.h"
#include "wv_cdm_types.h"
namespace video_widevine_server {
@@ -27,8 +28,7 @@ class CdmLicense {
bool Init(const std::string& token, CryptoSession* session,
PolicyEngine* policy_engine);
bool PrepareKeyRequest(const std::string& mime_type,
const CdmInitData& init_data,
bool PrepareKeyRequest(const InitializationData& init_data,
const CdmLicenseType license_type,
const CdmAppParameterMap& app_parameters,
const CdmSessionId& session_id,

View File

@@ -56,8 +56,10 @@ 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";
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";
} // namespace wvcdm
#endif // CDM_BASE_WV_CDM_CONSTANTS_H_

View File

@@ -5,7 +5,6 @@
#include <iostream>
#include <sstream>
#include "buffer_reader.h"
#include "cdm_session.h"
#include "license_protocol.pb.h"
#include "log.h"
@@ -118,8 +117,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 InitializationData& init_data,
const CdmLicenseType license_type,
CdmAppParameterMap& app_parameters,
CdmKeyMessage* key_request,
@@ -174,7 +172,7 @@ CdmResponseType CdmEngine::GenerateKeyRequest(
}
}
sts = iter->second->GenerateKeyRequest(mime_type, init_data, license_type,
sts = iter->second->GenerateKeyRequest(init_data, license_type,
app_parameters, key_request,
server_url);
@@ -611,97 +609,6 @@ bool CdmEngine::CancelSessions() {
return true;
}
// 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 CdmEngine::ExtractWidevinePssh(
const CdmInitData& init_data, CdmInitData* output) {
BufferReader reader(
reinterpret_cast<const uint8_t*>(init_data.data()), init_data.length());
// TODO(kqyang): Extracted from an actual init_data;
// Need to find out where it comes from.
static const uint8_t kWidevineSystemId[] = {
0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE,
0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED,
};
// one PSSH blob consists of:
// 4 byte size of the PSSH atom, inclusive
// "pssh"
// 4 byte flags, value 0
// 16 byte system id
// 4 byte size of PSSH data, exclusive
while (1) {
// size of PSSH atom, used for skipping
uint32_t size;
if (!reader.Read4(&size)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH atom size");
return false;
}
// "pssh"
std::vector<uint8_t> pssh;
if (!reader.ReadVec(&pssh, 4)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH literal");
return false;
}
if (memcmp(&pssh[0], "pssh", 4)) {
LOGW("CdmEngine::ExtractWidevinePssh: PSSH literal not present");
return false;
}
// flags
uint32_t flags;
if (!reader.Read4(&flags)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH flags");
return false;
}
if (flags != 0) {
LOGW("CdmEngine::ExtractWidevinePssh: PSSH flags not zero");
return false;
}
// system id
std::vector<uint8_t> system_id;
if (!reader.ReadVec(&system_id, sizeof(kWidevineSystemId))) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read system ID");
return false;
}
if (memcmp(&system_id[0], kWidevineSystemId,
sizeof(kWidevineSystemId))) {
// skip the remaining contents of the atom,
// after size field, atom name, flags and system id
if (!reader.SkipBytes(
size - 4 - 4 - 4 - sizeof(kWidevineSystemId))) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to rest of PSSH atom");
return false;
}
continue;
}
// size of PSSH box
uint32_t pssh_length;
if (!reader.Read4(&pssh_length)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH box size");
return false;
}
output->clear();
if (!reader.ReadString(output, pssh_length)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH");
return false;
}
return true;
}
// we did not find a matching record
return false;
}
void CdmEngine::OnTimerEvent() {
for (CdmSessionMap::iterator iter = sessions_.begin();
iter != sessions_.end(); ++iter) {

View File

@@ -115,16 +115,16 @@ CdmResponseType CdmSession::RestoreOfflineSession(
}
bool CdmSession::VerifySession(const CdmKeySystem& key_system,
const CdmInitData& init_data) {
const InitializationData& init_data) {
// TODO(gmorgan): Compare key_system and init_data with value received
// during session startup - they should be the same.
return true;
}
CdmResponseType CdmSession::GenerateKeyRequest(
const std::string& mime_type, const CdmInitData& init_data,
const CdmLicenseType license_type, const CdmAppParameterMap& app_parameters,
CdmKeyMessage* key_request, std::string* server_url) {
const InitializationData& 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,22 +152,16 @@ 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");
if (!init_data.is_supported()) {
LOGW("CdmSession::GenerateKeyRequest: unsupported init data type (%s)",
init_data.type().c_str());
return KEY_ERROR;
}
if (init_data.empty() && !license_parser_.HasInitData()) {
if (init_data.IsEmpty() && !license_parser_.HasInitData()) {
LOGW("CdmSession::GenerateKeyRequest: init data absent");
return KEY_ERROR;
}
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;
}
}
if (Properties::use_certificates_as_identification()) {
if (is_certificate_loaded_ ||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
@@ -178,15 +172,14 @@ CdmResponseType CdmSession::GenerateKeyRequest(
}
}
if (!license_parser_.PrepareKeyRequest(mime_type, extracted_init_data,
license_type, app_parameters,
session_id_, key_request,
server_url)) {
if (!license_parser_.PrepareKeyRequest(init_data, license_type,
app_parameters, session_id_,
key_request, server_url)) {
return KEY_ERROR;
}
if (license_type_ == kLicenseTypeOffline) {
offline_init_data_ = extracted_init_data;
offline_init_data_ = init_data.data();
offline_key_request_ = *key_request;
offline_release_server_url_ = *server_url;
}

View File

@@ -0,0 +1,121 @@
// Copyright 2014 Google Inc. All Rights Reserved.
#include "initialization_data.h"
#include "buffer_reader.h"
#include "log.h"
#include "properties.h"
#include "wv_cdm_constants.h"
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) {
is_cenc_ = true;
} else if (type == WEBM_VIDEO_MIME_TYPE || type == WEBM_AUDIO_MIME_TYPE) {
is_webm_ = true;
}
if (is_supported()) {
if (Properties::extract_pssh_data() && is_cenc()) {
ExtractWidevinePssh(data, &data_);
} else {
data_ = data;
}
}
}
// 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());
// TODO(kqyang): Extracted from an actual init_data;
// Need to find out where it comes from.
static const uint8_t kWidevineSystemId[] = {
0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE,
0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED,
};
// one PSSH blob consists of:
// 4 byte size of the PSSH atom, inclusive
// "pssh"
// 4 byte flags, value 0
// 16 byte system id
// 4 byte size of PSSH data, exclusive
while (1) {
// size of PSSH atom, used for skipping
uint32_t size;
if (!reader.Read4(&size)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH atom size");
return false;
}
// "pssh"
std::vector<uint8_t> pssh;
if (!reader.ReadVec(&pssh, 4)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH literal");
return false;
}
if (memcmp(&pssh[0], "pssh", 4)) {
LOGW("CdmEngine::ExtractWidevinePssh: PSSH literal not present");
return false;
}
// flags
uint32_t flags;
if (!reader.Read4(&flags)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH flags");
return false;
}
if (flags != 0) {
LOGW("CdmEngine::ExtractWidevinePssh: PSSH flags not zero");
return false;
}
// system id
std::vector<uint8_t> system_id;
if (!reader.ReadVec(&system_id, sizeof(kWidevineSystemId))) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read system ID");
return false;
}
if (memcmp(&system_id[0], kWidevineSystemId,
sizeof(kWidevineSystemId))) {
// skip the remaining contents of the atom,
// after size field, atom name, flags and system id
if (!reader.SkipBytes(
size - 4 - 4 - 4 - sizeof(kWidevineSystemId))) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to rest of PSSH atom");
return false;
}
continue;
}
// size of PSSH box
uint32_t pssh_length;
if (!reader.Read4(&pssh_length)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH box size");
return false;
}
output->clear();
if (!reader.ReadString(output, pssh_length)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH");
return false;
}
return true;
}
// we did not find a matching record
return false;
}
} // namespace wvcdm

View File

@@ -158,8 +158,7 @@ bool CdmLicense::Init(const std::string& token, CryptoSession* session,
return true;
}
bool CdmLicense::PrepareKeyRequest(const std::string& mime_type,
const CdmInitData& init_data,
bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
const CdmLicenseType license_type,
const CdmAppParameterMap& app_parameters,
const CdmSessionId& session_id,
@@ -169,12 +168,12 @@ bool CdmLicense::PrepareKeyRequest(const std::string& mime_type,
LOGE("CdmLicense::PrepareKeyRequest: not initialized");
return false;
}
if (mime_type != ISO_BMFF_MIME_TYPE && mime_type != WEBM_MIME_TYPE) {
LOGE("CdmLicense::PrepareKeyRequest: unsupported MIME type %s",
mime_type.c_str());
if (!init_data.is_supported()) {
LOGE("CdmLicense::PrepareKeyRequest: unsupported init data type (%s)",
init_data.type().c_str());
return false;
}
if (init_data.empty() && stored_init_data_.empty()) {
if (init_data.IsEmpty() && stored_init_data_.empty()) {
LOGE("CdmLicense::PrepareKeyRequest: empty init data provided");
return false;
}
@@ -199,7 +198,7 @@ bool CdmLicense::PrepareKeyRequest(const std::string& mime_type,
serialized_service_certificate = service_certificate_;
if (privacy_mode_enabled && serialized_service_certificate.empty()) {
stored_init_data_ = init_data;
stored_init_data_ = init_data.data();
return PrepareServiceCertificateRequest(signed_request, server_url);
}
@@ -315,12 +314,12 @@ bool CdmLicense::PrepareKeyRequest(const std::string& mime_type,
LicenseRequest_ContentIdentification* content_id =
license_request.mutable_content_id();
if (mime_type == ISO_BMFF_MIME_TYPE) {
if (init_data.is_cenc()) {
LicenseRequest_ContentIdentification_CENC* cenc_content_id =
content_id->mutable_cenc_id();
if (!init_data.empty()) {
cenc_content_id->add_pssh(init_data);
if (!init_data.IsEmpty()) {
cenc_content_id->add_pssh(init_data.data());
} else if (privacy_mode_enabled && !stored_init_data_.empty()) {
cenc_content_id->add_pssh(stored_init_data_);
} else {
@@ -331,12 +330,12 @@ bool CdmLicense::PrepareKeyRequest(const std::string& mime_type,
if (!PrepareContentId(license_type, request_id, cenc_content_id)) {
return false;
}
} else if (mime_type == WEBM_MIME_TYPE) {
} else if (init_data.is_webm()) {
LicenseRequest_ContentIdentification_WebM* webm_content_id =
content_id->mutable_webm_id();
if (!init_data.empty()) {
webm_content_id->set_header(init_data);
if (!init_data.IsEmpty()) {
webm_content_id->set_header(init_data.data());
} else if (privacy_mode_enabled && !stored_init_data_.empty()) {
webm_content_id->set_header(stored_init_data_);
} else {
@@ -348,8 +347,8 @@ bool CdmLicense::PrepareKeyRequest(const std::string& mime_type,
return false;
}
} else {
LOGE("CdmLicense::PrepareKeyRequest: no support for MIME type %s",
mime_type.c_str());
LOGE("CdmLicense::PrepareKeyRequest: no support for init data type (%s)",
init_data.type().c_str());
return false;
}

View File

@@ -3,6 +3,8 @@
#include <errno.h>
#include <getopt.h>
#include <string>
#if defined(CHROMIUM_BUILD)
#include "base/at_exit.h"
#include "base/message_loop/message_loop.h"
@@ -10,6 +12,7 @@
#include "cdm_engine.h"
#include "config_test_env.h"
#include "gtest/gtest.h"
#include "initialization_data.h"
#include "license_request.h"
#include "log.h"
#include "properties.h"
@@ -84,6 +87,10 @@ static wvcdm::CdmProvisioningResponse kValidJsonProvisioningResponse =
"gZYLHnFiQLZekZUbUUlWY_CwU9Cv0UtxqQ6Oa835_Ug8_n1BwX6BPbmbcWe2Y19laSnDWg4JBNl"
"F2CyP9N75jPtW9rVfjUSqKEPOwaIgwzNDkyMjM3NDcAAAA=\","
"\"signature\": \"r-LpoZcbbr2KtoPaFnuWTVBh4Gup1k8vn0ClW2qm32A=\"}}";
const std::string kCencMimeType = "video/mp4";
const std::string kWebmMimeType = "video/webm";
} // namespace
namespace wvcdm {
@@ -99,23 +106,26 @@ class WvCdmEngineTest : public testing::Test {
}
protected:
void GenerateKeyRequest(const std::string& key_system,
const std::string& key_id,
const std::string& mime_type) {
void GenerateKeyRequest(const std::string& key_id,
const std::string& init_data_type_string) {
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() || mime_type != ISO_BMFF_MIME_TYPE) {
EXPECT_TRUE(CdmEngine::ExtractWidevinePssh(key_id, &init_data));
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);
EXPECT_EQ(KEY_MESSAGE,
cdm_engine_.GenerateKeyRequest(session_id_,
key_set_id,
mime_type,
init_data,
kLicenseTypeStreaming,
app_parameters,
@@ -123,8 +133,7 @@ class WvCdmEngineTest : public testing::Test {
&server_url));
}
void GenerateRenewalRequest(const std::string& key_system,
const std::string& init_data) {
void GenerateRenewalRequest() {
EXPECT_EQ(KEY_MESSAGE,
cdm_engine_.GenerateRenewalRequest(session_id_,
&key_msg_,
@@ -163,8 +172,7 @@ class WvCdmEngineTest : public testing::Test {
}
void VerifyNewKeyResponse(const std::string& server_url,
const std::string& client_auth,
std::string& init_data){
const std::string& client_auth){
std::string resp = GetKeyRequestResponse(server_url,
client_auth);
CdmKeySetId key_set_id;
@@ -172,8 +180,7 @@ class WvCdmEngineTest : public testing::Test {
}
void VerifyRenewalKeyResponse(const std::string& server_url,
const std::string& client_auth,
std::string& init_data) {
const std::string& client_auth) {
std::string resp = GetKeyRequestResponse(server_url,
client_auth);
EXPECT_EQ(wvcdm::KEY_ADDED, cdm_engine_.RenewKey(session_id_, resp));
@@ -200,19 +207,19 @@ TEST(WvCdmProvisioningTest, ProvisioningTest) {
}
TEST_F(WvCdmEngineTest, BaseIsoBmffMessageTest) {
GenerateKeyRequest(g_key_system, g_key_id, "video/mp4");
GenerateKeyRequest(g_key_id, kCencMimeType);
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");
GenerateKeyRequest(g_key_id, kWebmMimeType);
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, "video/mp4");
GenerateKeyRequest(wrong_message, kCencMimeType);
// We should receive a response with no license, i.e. the extracted license
// response message should be empty.
@@ -220,24 +227,23 @@ TEST_F(WvCdmEngineTest, WrongMessageTest) {
}
TEST_F(WvCdmEngineTest, NormalDecryptionIsoBmff) {
GenerateKeyRequest(g_key_system, g_key_id, "video/mp4");
VerifyNewKeyResponse(g_license_server, g_client_auth, g_key_id);
GenerateKeyRequest(g_key_id, kCencMimeType);
VerifyNewKeyResponse(g_license_server, g_client_auth);
}
// 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);
GenerateKeyRequest(g_key_id, kWebmMimeType);
VerifyNewKeyResponse(g_license_server, g_client_auth);
}
TEST_F(WvCdmEngineTest, LicenseRenewal) {
GenerateKeyRequest(g_key_system, g_key_id, "video/mp4");
VerifyNewKeyResponse(g_license_server, g_client_auth, g_key_id);
GenerateKeyRequest(g_key_id, kCencMimeType);
VerifyNewKeyResponse(g_license_server, g_client_auth);
GenerateRenewalRequest(g_key_system, g_key_id);
GenerateRenewalRequest();
VerifyRenewalKeyResponse(server_url_.empty() ? g_license_server : server_url_,
g_client_auth,
g_key_id);
g_client_auth);
}
} // namespace wvcdm

View File

@@ -3,6 +3,7 @@
#include "crypto_session.h"
#include "license.h"
#include "gtest/gtest.h"
#include "initialization_data.h"
#include "policy_engine.h"
#include "string_conversions.h"
@@ -41,6 +42,10 @@ static const char* kInvalidResponse =
"2E4A47A24C06AC1B1A2061F21836A04E558BEE0244EF41C165F60CF23C580275"
"3175D48BAF1C6CA5759F200220A2BCCA86051A203FD4671075D9DEC6486A9317"
"70669993306831EDD57D77F34EFEB467470BA364";
const std::string kCencMimeType = "video/mp4";
const std::string kWebmMimeType = "video/webm";
}
namespace wvcdm {
@@ -79,8 +84,8 @@ TEST_F(LicenseTest, DISABLED_PrepareIsoBmffKeyRequest) {
CdmAppParameterMap app_parameters;
std::string server_url;
CdmSessionId session_id;
license_.PrepareKeyRequest("video/mp4",
a2bs_hex(kInitData),
InitializationData init_data(kCencMimeType, a2bs_hex(kInitData));
license_.PrepareKeyRequest(init_data,
kLicenseTypeStreaming,
app_parameters,
session_id,
@@ -95,8 +100,8 @@ TEST_F(LicenseTest, DISABLED_PrepareWebmKeyRequest) {
CdmAppParameterMap app_parameters;
std::string server_url;
CdmSessionId session_id;
license_.PrepareKeyRequest("video/webm",
a2bs_hex(kInitData),
InitializationData init_data(kWebmMimeType, a2bs_hex(kInitData));
license_.PrepareKeyRequest(init_data,
kLicenseTypeStreaming,
app_parameters,
session_id,
@@ -111,8 +116,8 @@ TEST_F(LicenseTest, DISABLED_HandleKeyResponseValid) {
CdmAppParameterMap app_parameters;
CdmSessionId session_id;
std::string server_url;
license_.PrepareKeyRequest("video/mp4",
a2bs_hex(kInitData),
InitializationData init_data(kCencMimeType, a2bs_hex(kInitData));
license_.PrepareKeyRequest(init_data,
kLicenseTypeStreaming,
app_parameters,
session_id,
@@ -128,8 +133,8 @@ TEST_F(LicenseTest, DISABLED_HandleKeyResponseInvalid) {
CdmAppParameterMap app_parameters;
CdmSessionId session_id;
std::string server_url;
license_.PrepareKeyRequest("video/mp4",
a2bs_hex(kInitData),
InitializationData init_data(kCencMimeType, a2bs_hex(kInitData));
license_.PrepareKeyRequest(init_data,
kLicenseTypeStreaming,
app_parameters,
session_id,

View File

@@ -20,6 +20,9 @@ class WvContentDecryptionModule : public TimerHandler {
WvContentDecryptionModule();
virtual ~WvContentDecryptionModule();
// Static methods
static bool SupportsInitDataType(const std::string& type);
// Session related methods
virtual CdmResponseType OpenSession(
const CdmKeySystem& key_system,
@@ -30,7 +33,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 std::string& init_data_type,
const CdmInitData& init_data,
const CdmLicenseType license_type,
CdmAppParameterMap& app_parameters,

View File

@@ -6,6 +6,7 @@
#include "cdm_client_property_set.h"
#include "cdm_engine.h"
#include "initialization_data.h"
#include "log.h"
#include "properties.h"
#include "wv_cdm_constants.h"
@@ -26,6 +27,10 @@ WvContentDecryptionModule::~WvContentDecryptionModule() {
DisablePolicyTimer(true);
}
bool WvContentDecryptionModule::SupportsInitDataType(const std::string& type) {
return InitializationData(type).is_supported();
}
CdmResponseType WvContentDecryptionModule::OpenSession(
const CdmKeySystem& key_system,
CdmClientPropertySet* property_set,
@@ -49,7 +54,7 @@ CdmResponseType WvContentDecryptionModule::CloseSession(
CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
const CdmSessionId& session_id,
const CdmKeySetId& key_set_id,
const std::string& mime_type,
const std::string& init_data_type,
const CdmInitData& init_data,
const CdmLicenseType license_type,
CdmAppParameterMap& app_parameters,
@@ -61,8 +66,9 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
if (sts != NO_ERROR)
return sts;
}
sts = cdm_engine_->GenerateKeyRequest(session_id, key_set_id, mime_type,
init_data, license_type,
InitializationData initialization_data(init_data_type, init_data);
sts = cdm_engine_->GenerateKeyRequest(session_id, key_set_id,
initialization_data, license_type,
app_parameters, key_request,
server_url);

View File

@@ -19,7 +19,7 @@ class WVDrmFactory : public android::DrmFactory {
virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
virtual bool isContentTypeSupported(const android::String8 &mimeType);
virtual bool isContentTypeSupported(const android::String8 &initDataType);
virtual android::status_t createDrmPlugin(const uint8_t uuid[16],
android::DrmPlugin** plugin);

View File

@@ -53,7 +53,7 @@ class WVDrmPlugin : public android::DrmPlugin,
virtual status_t getKeyRequest(
const Vector<uint8_t>& scope,
const Vector<uint8_t>& initData,
const String8& mimeType,
const String8& initDataType,
KeyType keyType,
const KeyedVector<String8, String8>& optionalParameters,
Vector<uint8_t>& request,

View File

@@ -128,7 +128,7 @@ status_t WVDrmPlugin::closeSession(const Vector<uint8_t>& sessionId) {
status_t WVDrmPlugin::getKeyRequest(
const Vector<uint8_t>& scope,
const Vector<uint8_t>& initData,
const String8& mimeType,
const String8& initDataType,
KeyType keyType,
const KeyedVector<String8, String8>& optionalParameters,
Vector<uint8_t>& request,
@@ -149,17 +149,20 @@ status_t WVDrmPlugin::getKeyRequest(
return android::ERROR_DRM_CANNOT_HANDLE;
}
string cdmMimeType = mimeType.string();
string cdmMimeType = initDataType.string();
// Provide backwards-compatibility for apps that pass non-EME-compatible MIME
// types.
if (cdmMimeType != wvcdm::ISO_BMFF_MIME_TYPE &&
cdmMimeType != wvcdm::WEBM_MIME_TYPE) {
cdmMimeType = wvcdm::ISO_BMFF_MIME_TYPE;
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;
}
CdmInitData processedInitData;
if (cdmMimeType == wvcdm::ISO_BMFF_MIME_TYPE) {
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.
static const char psshPrefix[] = {
0, 0, 0, 0, // Total size

View File

@@ -11,6 +11,7 @@
#include "utils/Errors.h"
#include "wv_cdm_constants.h"
#include "WVCDMSingleton.h"
#include "wv_content_decryption_module.h"
#include "WVDrmPlugin.h"
#include "WVUUID.h"
@@ -24,10 +25,9 @@ bool WVDrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) {
return isWidevineUUID(uuid);
}
bool WVDrmFactory::isContentTypeSupported(const String8 &mimeType) {
// 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();
bool WVDrmFactory::isContentTypeSupported(const String8 &initDataType) {
return wvcdm::WvContentDecryptionModule::SupportsInitDataType(
initDataType.string());
}
status_t WVDrmFactory::createDrmPlugin(const uint8_t uuid[16],

View File

@@ -45,10 +45,16 @@ TEST(WVDrmFactoryTest, SupportsSupportedContainerFormats) {
WVDrmFactory factory;
EXPECT_TRUE(factory.isContentTypeSupported(String8("video/mp4"))) <<
"WVPluginFactory does not support ISO-BMFF";
"WVPluginFactory does not support ISO-BMFF video";
EXPECT_TRUE(factory.isContentTypeSupported(String8("audio/mp4"))) <<
"WVPluginFactory does not support ISO-BMFF audio";
EXPECT_TRUE(factory.isContentTypeSupported(String8("video/webm"))) <<
"WVPluginFactory does not support WebM";
"WVPluginFactory does not support WebM video";
EXPECT_TRUE(factory.isContentTypeSupported(String8("audio/webm"))) <<
"WVPluginFactory does not support WebM audio";
}
TEST(WVDrmFactoryTest, DoesNotSupportUnsupportedContainerFormats) {