Add Support for Audio MIME Types
The EME spec technically requires CDMs to treat audio/mp4 and video/mp4 equivalently, as well as audio/webm and video/webm. We had only been accepting video/mp4 and video/webm up until now. This change also centralizes handling of init data types in the shared CDM code instead of having it spread across multiple places in the codebase. (This is a merge of https://widevine-internal-review.googlesource.com/9532/ from the Widevine CDM repo.) Bug: 13564917 Change-Id: Ib8bdfb2b003ffb00e8f0559561335abb3c5778b0
This commit is contained in:
@@ -28,6 +28,7 @@ LOCAL_SRC_FILES := \
|
|||||||
$(CORE_SRC_DIR)/certificate_provisioning.cpp \
|
$(CORE_SRC_DIR)/certificate_provisioning.cpp \
|
||||||
$(CORE_SRC_DIR)/crypto_session.cpp \
|
$(CORE_SRC_DIR)/crypto_session.cpp \
|
||||||
$(CORE_SRC_DIR)/device_files.cpp \
|
$(CORE_SRC_DIR)/device_files.cpp \
|
||||||
|
$(CORE_SRC_DIR)/initialization_data.cpp \
|
||||||
$(CORE_SRC_DIR)/license.cpp \
|
$(CORE_SRC_DIR)/license.cpp \
|
||||||
$(CORE_SRC_DIR)/oemcrypto_adapter_dynamic.cpp \
|
$(CORE_SRC_DIR)/oemcrypto_adapter_dynamic.cpp \
|
||||||
$(CORE_SRC_DIR)/policy_engine.cpp \
|
$(CORE_SRC_DIR)/policy_engine.cpp \
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#define CDM_BASE_CDM_ENGINE_H_
|
#define CDM_BASE_CDM_ENGINE_H_
|
||||||
|
|
||||||
#include "certificate_provisioning.h"
|
#include "certificate_provisioning.h"
|
||||||
|
#include "initialization_data.h"
|
||||||
#include "oemcrypto_adapter.h"
|
#include "oemcrypto_adapter.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "wv_cdm_types.h"
|
#include "wv_cdm_types.h"
|
||||||
@@ -35,14 +36,14 @@ class CdmEngine : public TimerHandler {
|
|||||||
|
|
||||||
// License related methods
|
// License related methods
|
||||||
// Construct a valid license request
|
// Construct a valid license request
|
||||||
virtual CdmResponseType GenerateKeyRequest(const CdmSessionId& session_id,
|
virtual CdmResponseType GenerateKeyRequest(
|
||||||
const CdmKeySetId& key_set_id,
|
const CdmSessionId& session_id,
|
||||||
const std::string& mime_type,
|
const CdmKeySetId& key_set_id,
|
||||||
const CdmInitData& init_data,
|
const InitializationData& init_data,
|
||||||
const CdmLicenseType license_type,
|
const CdmLicenseType license_type,
|
||||||
CdmAppParameterMap& app_parameters,
|
CdmAppParameterMap& app_parameters,
|
||||||
CdmKeyMessage* key_request,
|
CdmKeyMessage* key_request,
|
||||||
std::string* server_url);
|
std::string* server_url);
|
||||||
|
|
||||||
// Accept license response and extract key info.
|
// Accept license response and extract key info.
|
||||||
virtual CdmResponseType AddKey(const CdmSessionId& session_id,
|
virtual CdmResponseType AddKey(const CdmSessionId& session_id,
|
||||||
@@ -110,11 +111,6 @@ class CdmEngine : public TimerHandler {
|
|||||||
virtual bool DetachEventListener(const CdmSessionId& session_id,
|
virtual bool DetachEventListener(const CdmSessionId& session_id,
|
||||||
WvCdmEventListener* listener);
|
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);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// private methods
|
// private methods
|
||||||
// Cancel all sessions
|
// Cancel all sessions
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "crypto_session.h"
|
#include "crypto_session.h"
|
||||||
#include "device_files.h"
|
#include "device_files.h"
|
||||||
|
#include "initialization_data.h"
|
||||||
#include "license.h"
|
#include "license.h"
|
||||||
#include "oemcrypto_adapter.h"
|
#include "oemcrypto_adapter.h"
|
||||||
#include "policy_engine.h"
|
#include "policy_engine.h"
|
||||||
@@ -34,10 +35,9 @@ class CdmSession {
|
|||||||
const CdmSessionId& session_id() { return session_id_; }
|
const CdmSessionId& session_id() { return session_id_; }
|
||||||
|
|
||||||
bool VerifySession(const CdmKeySystem& key_system,
|
bool VerifySession(const CdmKeySystem& key_system,
|
||||||
const CdmInitData& init_data);
|
const InitializationData& init_data);
|
||||||
|
|
||||||
CdmResponseType GenerateKeyRequest(const std::string& mime_type,
|
CdmResponseType GenerateKeyRequest(const InitializationData& init_data,
|
||||||
const CdmInitData& init_data,
|
|
||||||
const CdmLicenseType license_type,
|
const CdmLicenseType license_type,
|
||||||
const CdmAppParameterMap& app_parameters,
|
const CdmAppParameterMap& app_parameters,
|
||||||
CdmKeyMessage* key_request,
|
CdmKeyMessage* key_request,
|
||||||
|
|||||||
47
libwvdrmengine/cdm/core/include/initialization_data.h
Normal file
47
libwvdrmengine/cdm/core/include/initialization_data.h
Normal 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_
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
#include "initialization_data.h"
|
||||||
#include "wv_cdm_types.h"
|
#include "wv_cdm_types.h"
|
||||||
|
|
||||||
namespace video_widevine_server {
|
namespace video_widevine_server {
|
||||||
@@ -27,8 +28,7 @@ class CdmLicense {
|
|||||||
bool Init(const std::string& token, CryptoSession* session,
|
bool Init(const std::string& token, CryptoSession* session,
|
||||||
PolicyEngine* policy_engine);
|
PolicyEngine* policy_engine);
|
||||||
|
|
||||||
bool PrepareKeyRequest(const std::string& mime_type,
|
bool PrepareKeyRequest(const InitializationData& init_data,
|
||||||
const CdmInitData& init_data,
|
|
||||||
const CdmLicenseType license_type,
|
const CdmLicenseType license_type,
|
||||||
const CdmAppParameterMap& app_parameters,
|
const CdmAppParameterMap& app_parameters,
|
||||||
const CdmSessionId& session_id,
|
const CdmSessionId& session_id,
|
||||||
|
|||||||
@@ -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_L3 = "L3";
|
||||||
static const std::string QUERY_VALUE_SECURITY_LEVEL_Unknown = "Unknown";
|
static const std::string QUERY_VALUE_SECURITY_LEVEL_Unknown = "Unknown";
|
||||||
|
|
||||||
static const std::string ISO_BMFF_MIME_TYPE = "video/mp4";
|
static const std::string ISO_BMFF_VIDEO_MIME_TYPE = "video/mp4";
|
||||||
static const std::string WEBM_MIME_TYPE = "video/webm";
|
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
|
} // namespace wvcdm
|
||||||
|
|
||||||
#endif // CDM_BASE_WV_CDM_CONSTANTS_H_
|
#endif // CDM_BASE_WV_CDM_CONSTANTS_H_
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "buffer_reader.h"
|
|
||||||
#include "cdm_session.h"
|
#include "cdm_session.h"
|
||||||
#include "license_protocol.pb.h"
|
#include "license_protocol.pb.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@@ -124,8 +123,7 @@ CdmResponseType CdmEngine::CloseKeySetSession(const CdmKeySetId& key_set_id) {
|
|||||||
CdmResponseType CdmEngine::GenerateKeyRequest(
|
CdmResponseType CdmEngine::GenerateKeyRequest(
|
||||||
const CdmSessionId& session_id,
|
const CdmSessionId& session_id,
|
||||||
const CdmKeySetId& key_set_id,
|
const CdmKeySetId& key_set_id,
|
||||||
const std::string& mime_type,
|
const InitializationData& init_data,
|
||||||
const CdmInitData& init_data,
|
|
||||||
const CdmLicenseType license_type,
|
const CdmLicenseType license_type,
|
||||||
CdmAppParameterMap& app_parameters,
|
CdmAppParameterMap& app_parameters,
|
||||||
CdmKeyMessage* key_request,
|
CdmKeyMessage* key_request,
|
||||||
@@ -180,7 +178,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,
|
app_parameters, key_request,
|
||||||
server_url);
|
server_url);
|
||||||
|
|
||||||
@@ -611,97 +609,6 @@ bool CdmEngine::CancelSessions() {
|
|||||||
return true;
|
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::EnablePolicyTimer() {
|
void CdmEngine::EnablePolicyTimer() {
|
||||||
if (!policy_timer_.IsRunning())
|
if (!policy_timer_.IsRunning())
|
||||||
policy_timer_.Start(this, kCdmPolicyTimerDurationSeconds);
|
policy_timer_.Start(this, kCdmPolicyTimerDurationSeconds);
|
||||||
|
|||||||
@@ -112,16 +112,16 @@ CdmResponseType CdmSession::RestoreOfflineSession(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CdmSession::VerifySession(const CdmKeySystem& key_system,
|
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
|
// TODO(gmorgan): Compare key_system and init_data with value received
|
||||||
// during session startup - they should be the same.
|
// during session startup - they should be the same.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CdmSession::GenerateKeyRequest(
|
CdmResponseType CdmSession::GenerateKeyRequest(
|
||||||
const std::string& mime_type, const CdmInitData& init_data,
|
const InitializationData& init_data, const CdmLicenseType license_type,
|
||||||
const CdmLicenseType license_type, const CdmAppParameterMap& app_parameters,
|
const CdmAppParameterMap& app_parameters, CdmKeyMessage* key_request,
|
||||||
CdmKeyMessage* key_request, std::string* server_url) {
|
std::string* server_url) {
|
||||||
if (reinitialize_session_) {
|
if (reinitialize_session_) {
|
||||||
CdmResponseType sts = Init();
|
CdmResponseType sts = Init();
|
||||||
if (sts != NO_ERROR) {
|
if (sts != NO_ERROR) {
|
||||||
@@ -149,22 +149,16 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
|||||||
? UNKNOWN_ERROR
|
? UNKNOWN_ERROR
|
||||||
: GenerateRenewalRequest(key_request, server_url);
|
: GenerateRenewalRequest(key_request, server_url);
|
||||||
} else {
|
} else {
|
||||||
if (mime_type != ISO_BMFF_MIME_TYPE && mime_type != WEBM_MIME_TYPE) {
|
if (!init_data.is_supported()) {
|
||||||
LOGW("CdmSession::GenerateKeyRequest: unknown MIME type");
|
LOGW("CdmSession::GenerateKeyRequest: unsupported init data type (%s)",
|
||||||
|
init_data.type().c_str());
|
||||||
return KEY_ERROR;
|
return KEY_ERROR;
|
||||||
}
|
}
|
||||||
if (init_data.empty() && !license_parser_.HasInitData()) {
|
if (init_data.IsEmpty() && !license_parser_.HasInitData()) {
|
||||||
LOGW("CdmSession::GenerateKeyRequest: init data absent");
|
LOGW("CdmSession::GenerateKeyRequest: init data absent");
|
||||||
return KEY_ERROR;
|
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 (Properties::use_certificates_as_identification()) {
|
||||||
if (is_certificate_loaded_ ||
|
if (is_certificate_loaded_ ||
|
||||||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
|
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
|
||||||
@@ -176,15 +170,14 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!license_parser_.PrepareKeyRequest(mime_type, extracted_init_data,
|
if (!license_parser_.PrepareKeyRequest(init_data, license_type,
|
||||||
license_type, app_parameters,
|
app_parameters, session_id_,
|
||||||
session_id_, key_request,
|
key_request, server_url)) {
|
||||||
server_url)) {
|
|
||||||
return KEY_ERROR;
|
return KEY_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (license_type_ == kLicenseTypeOffline) {
|
if (license_type_ == kLicenseTypeOffline) {
|
||||||
offline_init_data_ = extracted_init_data;
|
offline_init_data_ = init_data.data();
|
||||||
offline_key_request_ = *key_request;
|
offline_key_request_ = *key_request;
|
||||||
offline_release_server_url_ = *server_url;
|
offline_release_server_url_ = *server_url;
|
||||||
}
|
}
|
||||||
|
|||||||
121
libwvdrmengine/cdm/core/src/initialization_data.cpp
Normal file
121
libwvdrmengine/cdm/core/src/initialization_data.cpp
Normal 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
|
||||||
@@ -158,8 +158,7 @@ bool CdmLicense::Init(const std::string& token, CryptoSession* session,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CdmLicense::PrepareKeyRequest(const std::string& mime_type,
|
bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
|
||||||
const CdmInitData& init_data,
|
|
||||||
const CdmLicenseType license_type,
|
const CdmLicenseType license_type,
|
||||||
const CdmAppParameterMap& app_parameters,
|
const CdmAppParameterMap& app_parameters,
|
||||||
const CdmSessionId& session_id,
|
const CdmSessionId& session_id,
|
||||||
@@ -169,12 +168,12 @@ bool CdmLicense::PrepareKeyRequest(const std::string& mime_type,
|
|||||||
LOGE("CdmLicense::PrepareKeyRequest: not initialized");
|
LOGE("CdmLicense::PrepareKeyRequest: not initialized");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mime_type != ISO_BMFF_MIME_TYPE && mime_type != WEBM_MIME_TYPE) {
|
if (!init_data.is_supported()) {
|
||||||
LOGE("CdmLicense::PrepareKeyRequest: unsupported MIME type %s",
|
LOGE("CdmLicense::PrepareKeyRequest: unsupported init data type (%s)",
|
||||||
mime_type.c_str());
|
init_data.type().c_str());
|
||||||
return false;
|
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");
|
LOGE("CdmLicense::PrepareKeyRequest: empty init data provided");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -199,7 +198,7 @@ bool CdmLicense::PrepareKeyRequest(const std::string& mime_type,
|
|||||||
serialized_service_certificate = service_certificate_;
|
serialized_service_certificate = service_certificate_;
|
||||||
|
|
||||||
if (privacy_mode_enabled && serialized_service_certificate.empty()) {
|
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);
|
return PrepareServiceCertificateRequest(signed_request, server_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,12 +314,12 @@ bool CdmLicense::PrepareKeyRequest(const std::string& mime_type,
|
|||||||
LicenseRequest_ContentIdentification* content_id =
|
LicenseRequest_ContentIdentification* content_id =
|
||||||
license_request.mutable_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 =
|
LicenseRequest_ContentIdentification_CENC* cenc_content_id =
|
||||||
content_id->mutable_cenc_id();
|
content_id->mutable_cenc_id();
|
||||||
|
|
||||||
if (!init_data.empty()) {
|
if (!init_data.IsEmpty()) {
|
||||||
cenc_content_id->add_pssh(init_data);
|
cenc_content_id->add_pssh(init_data.data());
|
||||||
} else if (privacy_mode_enabled && !stored_init_data_.empty()) {
|
} else if (privacy_mode_enabled && !stored_init_data_.empty()) {
|
||||||
cenc_content_id->add_pssh(stored_init_data_);
|
cenc_content_id->add_pssh(stored_init_data_);
|
||||||
} else {
|
} else {
|
||||||
@@ -331,12 +330,12 @@ bool CdmLicense::PrepareKeyRequest(const std::string& mime_type,
|
|||||||
if (!PrepareContentId(license_type, request_id, cenc_content_id)) {
|
if (!PrepareContentId(license_type, request_id, cenc_content_id)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (mime_type == WEBM_MIME_TYPE) {
|
} else if (init_data.is_webm()) {
|
||||||
LicenseRequest_ContentIdentification_WebM* webm_content_id =
|
LicenseRequest_ContentIdentification_WebM* webm_content_id =
|
||||||
content_id->mutable_webm_id();
|
content_id->mutable_webm_id();
|
||||||
|
|
||||||
if (!init_data.empty()) {
|
if (!init_data.IsEmpty()) {
|
||||||
webm_content_id->set_header(init_data);
|
webm_content_id->set_header(init_data.data());
|
||||||
} else if (privacy_mode_enabled && !stored_init_data_.empty()) {
|
} else if (privacy_mode_enabled && !stored_init_data_.empty()) {
|
||||||
webm_content_id->set_header(stored_init_data_);
|
webm_content_id->set_header(stored_init_data_);
|
||||||
} else {
|
} else {
|
||||||
@@ -348,8 +347,8 @@ bool CdmLicense::PrepareKeyRequest(const std::string& mime_type,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGE("CdmLicense::PrepareKeyRequest: no support for MIME type %s",
|
LOGE("CdmLicense::PrepareKeyRequest: no support for init data type (%s)",
|
||||||
mime_type.c_str());
|
init_data.type().c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#if defined(CHROMIUM_BUILD)
|
#if defined(CHROMIUM_BUILD)
|
||||||
#include "base/at_exit.h"
|
#include "base/at_exit.h"
|
||||||
#include "base/message_loop.h"
|
#include "base/message_loop.h"
|
||||||
@@ -10,6 +12,7 @@
|
|||||||
#include "cdm_engine.h"
|
#include "cdm_engine.h"
|
||||||
#include "config_test_env.h"
|
#include "config_test_env.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
#include "initialization_data.h"
|
||||||
#include "license_request.h"
|
#include "license_request.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "properties.h"
|
#include "properties.h"
|
||||||
@@ -82,6 +85,10 @@ static wvcdm::CdmProvisioningResponse kValidJsonProvisioningResponse =
|
|||||||
"gZYLHnFiQLZekZUbUUlWY_CwU9Cv0UtxqQ6Oa835_Ug8_n1BwX6BPbmbcWe2Y19laSnDWg4JBNl"
|
"gZYLHnFiQLZekZUbUUlWY_CwU9Cv0UtxqQ6Oa835_Ug8_n1BwX6BPbmbcWe2Y19laSnDWg4JBNl"
|
||||||
"F2CyP9N75jPtW9rVfjUSqKEPOwaIgwzNDkyMjM3NDcAAAA=\","
|
"F2CyP9N75jPtW9rVfjUSqKEPOwaIgwzNDkyMjM3NDcAAAA=\","
|
||||||
"\"signature\": \"r-LpoZcbbr2KtoPaFnuWTVBh4Gup1k8vn0ClW2qm32A=\"}}";
|
"\"signature\": \"r-LpoZcbbr2KtoPaFnuWTVBh4Gup1k8vn0ClW2qm32A=\"}}";
|
||||||
|
|
||||||
|
const std::string kCencMimeType = "video/mp4";
|
||||||
|
const std::string kWebmMimeType = "video/webm";
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
@@ -98,23 +105,26 @@ class WvCdmEngineTest : public testing::Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void GenerateKeyRequest(const std::string& key_system,
|
void GenerateKeyRequest(const std::string& key_id,
|
||||||
const std::string& key_id,
|
const std::string& init_data_type_string) {
|
||||||
const std::string& mime_type) {
|
|
||||||
CdmAppParameterMap app_parameters;
|
CdmAppParameterMap app_parameters;
|
||||||
std::string server_url;
|
std::string server_url;
|
||||||
std::string init_data = key_id;
|
|
||||||
CdmKeySetId key_set_id;
|
CdmKeySetId key_set_id;
|
||||||
|
|
||||||
// TODO(rfrias): Temporary change till b/9465346 is addressed
|
// TODO(rfrias): Temporary change till b/9465346 is addressed
|
||||||
if (!Properties::extract_pssh_data() || mime_type != ISO_BMFF_MIME_TYPE) {
|
CdmInitData extracted_init_data = key_id;
|
||||||
EXPECT_TRUE(CdmEngine::ExtractWidevinePssh(key_id, &init_data));
|
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,
|
EXPECT_EQ(KEY_MESSAGE,
|
||||||
cdm_engine_->GenerateKeyRequest(session_id_,
|
cdm_engine_->GenerateKeyRequest(session_id_,
|
||||||
key_set_id,
|
key_set_id,
|
||||||
mime_type,
|
|
||||||
init_data,
|
init_data,
|
||||||
kLicenseTypeStreaming,
|
kLicenseTypeStreaming,
|
||||||
app_parameters,
|
app_parameters,
|
||||||
@@ -122,8 +132,7 @@ class WvCdmEngineTest : public testing::Test {
|
|||||||
&server_url));
|
&server_url));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateRenewalRequest(const std::string& key_system,
|
void GenerateRenewalRequest() {
|
||||||
const std::string& init_data) {
|
|
||||||
EXPECT_EQ(KEY_MESSAGE,
|
EXPECT_EQ(KEY_MESSAGE,
|
||||||
cdm_engine_->GenerateRenewalRequest(session_id_,
|
cdm_engine_->GenerateRenewalRequest(session_id_,
|
||||||
&key_msg_,
|
&key_msg_,
|
||||||
@@ -162,8 +171,7 @@ class WvCdmEngineTest : public testing::Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VerifyNewKeyResponse(const std::string& server_url,
|
void VerifyNewKeyResponse(const std::string& server_url,
|
||||||
const std::string& client_auth,
|
const std::string& client_auth){
|
||||||
std::string& init_data){
|
|
||||||
std::string resp = GetKeyRequestResponse(server_url,
|
std::string resp = GetKeyRequestResponse(server_url,
|
||||||
client_auth);
|
client_auth);
|
||||||
CdmKeySetId key_set_id;
|
CdmKeySetId key_set_id;
|
||||||
@@ -171,8 +179,7 @@ class WvCdmEngineTest : public testing::Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VerifyRenewalKeyResponse(const std::string& server_url,
|
void VerifyRenewalKeyResponse(const std::string& server_url,
|
||||||
const std::string& client_auth,
|
const std::string& client_auth){
|
||||||
std::string& init_data){
|
|
||||||
std::string resp = GetKeyRequestResponse(server_url,
|
std::string resp = GetKeyRequestResponse(server_url,
|
||||||
client_auth);
|
client_auth);
|
||||||
EXPECT_EQ(KEY_ADDED, cdm_engine_->RenewKey(session_id_, resp));
|
EXPECT_EQ(KEY_ADDED, cdm_engine_->RenewKey(session_id_, resp));
|
||||||
@@ -199,41 +206,40 @@ TEST(WvCdmProvisioningTest, ProvisioningTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WvCdmEngineTest, BaseIsoBmffMessageTest) {
|
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);
|
GetKeyRequestResponse(g_license_server, g_client_auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(juce): Set up with correct test data.
|
// TODO(juce): Set up with correct test data.
|
||||||
TEST_F(WvCdmEngineTest, DISABLED_BaseWebmMessageTest) {
|
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);
|
GetKeyRequestResponse(g_license_server, g_client_auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WvCdmEngineTest, WrongMessageTest) {
|
TEST_F(WvCdmEngineTest, WrongMessageTest) {
|
||||||
std::string wrong_message = a2bs_hex(g_wrong_key_id);
|
std::string wrong_message = a2bs_hex(g_wrong_key_id);
|
||||||
GenerateKeyRequest(g_key_system, wrong_message, "video/mp4");
|
GenerateKeyRequest(wrong_message, kCencMimeType);
|
||||||
GetKeyRequestResponse(g_license_server, g_client_auth);
|
GetKeyRequestResponse(g_license_server, g_client_auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WvCdmEngineTest, NormalDecryptionIsoBmff) {
|
TEST_F(WvCdmEngineTest, NormalDecryptionIsoBmff) {
|
||||||
GenerateKeyRequest(g_key_system, g_key_id, "video/mp4");
|
GenerateKeyRequest(g_key_id, kCencMimeType);
|
||||||
VerifyNewKeyResponse(g_license_server, g_client_auth, g_key_id);
|
VerifyNewKeyResponse(g_license_server, g_client_auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(juce): Set up with correct test data.
|
// TODO(juce): Set up with correct test data.
|
||||||
TEST_F(WvCdmEngineTest, DISABLED_NormalDecryptionWebm) {
|
TEST_F(WvCdmEngineTest, DISABLED_NormalDecryptionWebm) {
|
||||||
GenerateKeyRequest(g_key_system, g_key_id, "video/webm");
|
GenerateKeyRequest(g_key_id, kWebmMimeType);
|
||||||
VerifyNewKeyResponse(g_license_server, g_client_auth, g_key_id);
|
VerifyNewKeyResponse(g_license_server, g_client_auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WvCdmEngineTest, LicenseRenewal) {
|
TEST_F(WvCdmEngineTest, LicenseRenewal) {
|
||||||
GenerateKeyRequest(g_key_system, g_key_id, "video/mp4");
|
GenerateKeyRequest(g_key_id, kCencMimeType);
|
||||||
VerifyNewKeyResponse(g_license_server, g_client_auth, g_key_id);
|
VerifyNewKeyResponse(g_license_server, g_client_auth);
|
||||||
|
|
||||||
GenerateRenewalRequest(g_key_system, g_key_id);
|
GenerateRenewalRequest();
|
||||||
VerifyRenewalKeyResponse(server_url_.empty() ? g_license_server : server_url_,
|
VerifyRenewalKeyResponse(server_url_.empty() ? g_license_server : server_url_,
|
||||||
g_client_auth,
|
g_client_auth);
|
||||||
g_key_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "crypto_session.h"
|
#include "crypto_session.h"
|
||||||
#include "license.h"
|
#include "license.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
#include "initialization_data.h"
|
||||||
#include "policy_engine.h"
|
#include "policy_engine.h"
|
||||||
#include "string_conversions.h"
|
#include "string_conversions.h"
|
||||||
|
|
||||||
@@ -41,6 +42,10 @@ static const char* kInvalidResponse =
|
|||||||
"2E4A47A24C06AC1B1A2061F21836A04E558BEE0244EF41C165F60CF23C580275"
|
"2E4A47A24C06AC1B1A2061F21836A04E558BEE0244EF41C165F60CF23C580275"
|
||||||
"3175D48BAF1C6CA5759F200220A2BCCA86051A203FD4671075D9DEC6486A9317"
|
"3175D48BAF1C6CA5759F200220A2BCCA86051A203FD4671075D9DEC6486A9317"
|
||||||
"70669993306831EDD57D77F34EFEB467470BA364";
|
"70669993306831EDD57D77F34EFEB467470BA364";
|
||||||
|
|
||||||
|
const std::string kCencMimeType = "video/mp4";
|
||||||
|
const std::string kWebmMimeType = "video/webm";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
@@ -79,8 +84,8 @@ TEST_F(LicenseTest, DISABLED_PrepareIsoBmffKeyRequest) {
|
|||||||
CdmAppParameterMap app_parameters;
|
CdmAppParameterMap app_parameters;
|
||||||
std::string server_url;
|
std::string server_url;
|
||||||
CdmSessionId session_id;
|
CdmSessionId session_id;
|
||||||
license_.PrepareKeyRequest("video/mp4",
|
InitializationData init_data(kCencMimeType, a2bs_hex(kInitData));
|
||||||
a2bs_hex(kInitData),
|
license_.PrepareKeyRequest(init_data,
|
||||||
kLicenseTypeStreaming,
|
kLicenseTypeStreaming,
|
||||||
app_parameters,
|
app_parameters,
|
||||||
session_id,
|
session_id,
|
||||||
@@ -95,8 +100,8 @@ TEST_F(LicenseTest, DISABLED_PrepareWebmKeyRequest) {
|
|||||||
CdmAppParameterMap app_parameters;
|
CdmAppParameterMap app_parameters;
|
||||||
std::string server_url;
|
std::string server_url;
|
||||||
CdmSessionId session_id;
|
CdmSessionId session_id;
|
||||||
license_.PrepareKeyRequest("video/webm",
|
InitializationData init_data(kWebmMimeType, a2bs_hex(kInitData));
|
||||||
a2bs_hex(kInitData),
|
license_.PrepareKeyRequest(init_data,
|
||||||
kLicenseTypeStreaming,
|
kLicenseTypeStreaming,
|
||||||
app_parameters,
|
app_parameters,
|
||||||
session_id,
|
session_id,
|
||||||
@@ -111,8 +116,8 @@ TEST_F(LicenseTest, DISABLED_HandleKeyResponseValid) {
|
|||||||
CdmAppParameterMap app_parameters;
|
CdmAppParameterMap app_parameters;
|
||||||
CdmSessionId session_id;
|
CdmSessionId session_id;
|
||||||
std::string server_url;
|
std::string server_url;
|
||||||
license_.PrepareKeyRequest("video/mp4",
|
InitializationData init_data(kCencMimeType, a2bs_hex(kInitData));
|
||||||
a2bs_hex(kInitData),
|
license_.PrepareKeyRequest(init_data,
|
||||||
kLicenseTypeStreaming,
|
kLicenseTypeStreaming,
|
||||||
app_parameters,
|
app_parameters,
|
||||||
session_id,
|
session_id,
|
||||||
@@ -128,8 +133,8 @@ TEST_F(LicenseTest, DISABLED_HandleKeyResponseInvalid) {
|
|||||||
CdmAppParameterMap app_parameters;
|
CdmAppParameterMap app_parameters;
|
||||||
CdmSessionId session_id;
|
CdmSessionId session_id;
|
||||||
std::string server_url;
|
std::string server_url;
|
||||||
license_.PrepareKeyRequest("video/mp4",
|
InitializationData init_data(kCencMimeType, a2bs_hex(kInitData));
|
||||||
a2bs_hex(kInitData),
|
license_.PrepareKeyRequest(init_data,
|
||||||
kLicenseTypeStreaming,
|
kLicenseTypeStreaming,
|
||||||
app_parameters,
|
app_parameters,
|
||||||
session_id,
|
session_id,
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ class WvContentDecryptionModule {
|
|||||||
WvContentDecryptionModule();
|
WvContentDecryptionModule();
|
||||||
virtual ~WvContentDecryptionModule();
|
virtual ~WvContentDecryptionModule();
|
||||||
|
|
||||||
|
// Static methods
|
||||||
|
static bool SupportsInitDataType(const std::string& type);
|
||||||
|
|
||||||
// Session related methods
|
// Session related methods
|
||||||
virtual CdmResponseType OpenSession(
|
virtual CdmResponseType OpenSession(
|
||||||
const CdmKeySystem& key_system,
|
const CdmKeySystem& key_system,
|
||||||
@@ -28,7 +31,7 @@ class WvContentDecryptionModule {
|
|||||||
// Construct a valid license request.
|
// Construct a valid license request.
|
||||||
virtual CdmResponseType GenerateKeyRequest(const CdmSessionId& session_id,
|
virtual CdmResponseType GenerateKeyRequest(const CdmSessionId& session_id,
|
||||||
const CdmKeySetId& key_set_id,
|
const CdmKeySetId& key_set_id,
|
||||||
const std::string& mime_type,
|
const std::string& init_data_type,
|
||||||
const CdmInitData& init_data,
|
const CdmInitData& init_data,
|
||||||
const CdmLicenseType license_type,
|
const CdmLicenseType license_type,
|
||||||
CdmAppParameterMap& app_parameters,
|
CdmAppParameterMap& app_parameters,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "cdm_client_property_set.h"
|
#include "cdm_client_property_set.h"
|
||||||
#include "cdm_engine.h"
|
#include "cdm_engine.h"
|
||||||
|
#include "initialization_data.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "properties.h"
|
#include "properties.h"
|
||||||
#include "wv_cdm_constants.h"
|
#include "wv_cdm_constants.h"
|
||||||
@@ -18,6 +19,10 @@ WvContentDecryptionModule::WvContentDecryptionModule()
|
|||||||
|
|
||||||
WvContentDecryptionModule::~WvContentDecryptionModule() {}
|
WvContentDecryptionModule::~WvContentDecryptionModule() {}
|
||||||
|
|
||||||
|
bool WvContentDecryptionModule::SupportsInitDataType(const std::string& type) {
|
||||||
|
return InitializationData(type).is_supported();
|
||||||
|
}
|
||||||
|
|
||||||
CdmResponseType WvContentDecryptionModule::OpenSession(
|
CdmResponseType WvContentDecryptionModule::OpenSession(
|
||||||
const CdmKeySystem& key_system,
|
const CdmKeySystem& key_system,
|
||||||
CdmClientPropertySet* property_set,
|
CdmClientPropertySet* property_set,
|
||||||
@@ -38,7 +43,7 @@ CdmResponseType WvContentDecryptionModule::CloseSession(
|
|||||||
CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
|
CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
|
||||||
const CdmSessionId& session_id,
|
const CdmSessionId& session_id,
|
||||||
const CdmKeySetId& key_set_id,
|
const CdmKeySetId& key_set_id,
|
||||||
const std::string& mime_type,
|
const std::string& init_data_type,
|
||||||
const CdmInitData& init_data,
|
const CdmInitData& init_data,
|
||||||
const CdmLicenseType license_type,
|
const CdmLicenseType license_type,
|
||||||
CdmAppParameterMap& app_parameters,
|
CdmAppParameterMap& app_parameters,
|
||||||
@@ -50,8 +55,9 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
|
|||||||
if (sts != NO_ERROR)
|
if (sts != NO_ERROR)
|
||||||
return sts;
|
return sts;
|
||||||
}
|
}
|
||||||
sts = cdm_engine_->GenerateKeyRequest(session_id, key_set_id, mime_type,
|
InitializationData initialization_data(init_data_type, init_data);
|
||||||
init_data, license_type,
|
sts = cdm_engine_->GenerateKeyRequest(session_id, key_set_id,
|
||||||
|
initialization_data, license_type,
|
||||||
app_parameters, key_request,
|
app_parameters, key_request,
|
||||||
server_url);
|
server_url);
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class WVDrmFactory : public android::DrmFactory {
|
|||||||
|
|
||||||
virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
|
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],
|
virtual android::status_t createDrmPlugin(const uint8_t uuid[16],
|
||||||
android::DrmPlugin** plugin);
|
android::DrmPlugin** plugin);
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class WVDrmPlugin : public android::DrmPlugin,
|
|||||||
virtual status_t getKeyRequest(
|
virtual status_t getKeyRequest(
|
||||||
const Vector<uint8_t>& scope,
|
const Vector<uint8_t>& scope,
|
||||||
const Vector<uint8_t>& initData,
|
const Vector<uint8_t>& initData,
|
||||||
const String8& mimeType,
|
const String8& initDataType,
|
||||||
KeyType keyType,
|
KeyType keyType,
|
||||||
const KeyedVector<String8, String8>& optionalParameters,
|
const KeyedVector<String8, String8>& optionalParameters,
|
||||||
Vector<uint8_t>& request,
|
Vector<uint8_t>& request,
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ status_t WVDrmPlugin::closeSession(const Vector<uint8_t>& sessionId) {
|
|||||||
status_t WVDrmPlugin::getKeyRequest(
|
status_t WVDrmPlugin::getKeyRequest(
|
||||||
const Vector<uint8_t>& scope,
|
const Vector<uint8_t>& scope,
|
||||||
const Vector<uint8_t>& initData,
|
const Vector<uint8_t>& initData,
|
||||||
const String8& mimeType,
|
const String8& initDataType,
|
||||||
KeyType keyType,
|
KeyType keyType,
|
||||||
const KeyedVector<String8, String8>& optionalParameters,
|
const KeyedVector<String8, String8>& optionalParameters,
|
||||||
Vector<uint8_t>& request,
|
Vector<uint8_t>& request,
|
||||||
@@ -149,17 +149,20 @@ status_t WVDrmPlugin::getKeyRequest(
|
|||||||
return android::ERROR_DRM_CANNOT_HANDLE;
|
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
|
// Provide backwards-compatibility for apps that pass non-EME-compatible MIME
|
||||||
// types.
|
// types.
|
||||||
if (cdmMimeType != wvcdm::ISO_BMFF_MIME_TYPE &&
|
if (cdmMimeType != wvcdm::ISO_BMFF_VIDEO_MIME_TYPE &&
|
||||||
cdmMimeType != wvcdm::WEBM_MIME_TYPE) {
|
cdmMimeType != wvcdm::ISO_BMFF_AUDIO_MIME_TYPE &&
|
||||||
cdmMimeType = wvcdm::ISO_BMFF_MIME_TYPE;
|
cdmMimeType != wvcdm::WEBM_VIDEO_MIME_TYPE &&
|
||||||
|
cdmMimeType != wvcdm::WEBM_AUDIO_MIME_TYPE) {
|
||||||
|
cdmMimeType = wvcdm::ISO_BMFF_VIDEO_MIME_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmInitData processedInitData;
|
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.
|
// For ISO-BMFF, we need to wrap the init data in a new PSSH header.
|
||||||
static const char psshPrefix[] = {
|
static const char psshPrefix[] = {
|
||||||
0, 0, 0, 0, // Total size
|
0, 0, 0, 0, // Total size
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "utils/Errors.h"
|
#include "utils/Errors.h"
|
||||||
#include "wv_cdm_constants.h"
|
#include "wv_cdm_constants.h"
|
||||||
#include "WVCDMSingleton.h"
|
#include "WVCDMSingleton.h"
|
||||||
|
#include "wv_content_decryption_module.h"
|
||||||
#include "WVDrmPlugin.h"
|
#include "WVDrmPlugin.h"
|
||||||
#include "WVUUID.h"
|
#include "WVUUID.h"
|
||||||
|
|
||||||
@@ -24,10 +25,9 @@ bool WVDrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) {
|
|||||||
return isWidevineUUID(uuid);
|
return isWidevineUUID(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WVDrmFactory::isContentTypeSupported(const String8 &mimeType) {
|
bool WVDrmFactory::isContentTypeSupported(const String8 &initDataType) {
|
||||||
// Support ISO-BMFF (video/mp4) and WebM (video/webm).
|
return wvcdm::WvContentDecryptionModule::SupportsInitDataType(
|
||||||
return mimeType == wvcdm::ISO_BMFF_MIME_TYPE.c_str() ||
|
initDataType.string());
|
||||||
mimeType == wvcdm::WEBM_MIME_TYPE.c_str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t WVDrmFactory::createDrmPlugin(const uint8_t uuid[16],
|
status_t WVDrmFactory::createDrmPlugin(const uint8_t uuid[16],
|
||||||
|
|||||||
@@ -45,10 +45,16 @@ TEST(WVDrmFactoryTest, SupportsSupportedContainerFormats) {
|
|||||||
WVDrmFactory factory;
|
WVDrmFactory factory;
|
||||||
|
|
||||||
EXPECT_TRUE(factory.isContentTypeSupported(String8("video/mp4"))) <<
|
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"))) <<
|
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) {
|
TEST(WVDrmFactoryTest, DoesNotSupportUnsupportedContainerFormats) {
|
||||||
|
|||||||
Reference in New Issue
Block a user