diff --git a/libwvdrmengine/cdm/Android.mk b/libwvdrmengine/cdm/Android.mk index 237366e9..84e9d3c7 100644 --- a/libwvdrmengine/cdm/Android.mk +++ b/libwvdrmengine/cdm/Android.mk @@ -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 \ diff --git a/libwvdrmengine/cdm/core/include/cdm_engine.h b/libwvdrmengine/cdm/core/include/cdm_engine.h index dc5b7825..a9d79b1f 100644 --- a/libwvdrmengine/cdm/core/include/cdm_engine.h +++ b/libwvdrmengine/cdm/core/include/cdm_engine.h @@ -4,6 +4,7 @@ #define CDM_BASE_CDM_ENGINE_H_ #include "certificate_provisioning.h" +#include "initialization_data.h" #include "oemcrypto_adapter.h" #include "timer.h" #include "wv_cdm_types.h" @@ -35,14 +36,14 @@ class CdmEngine : public TimerHandler { // License related methods // 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, - CdmKeyMessage* key_request, - std::string* server_url); + virtual CdmResponseType GenerateKeyRequest( + const CdmSessionId& session_id, + const CdmKeySetId& key_set_id, + const InitializationData& init_data, + const CdmLicenseType license_type, + CdmAppParameterMap& app_parameters, + CdmKeyMessage* key_request, + std::string* server_url); // Accept license response and extract key info. virtual CdmResponseType AddKey(const CdmSessionId& session_id, @@ -110,11 +111,6 @@ class CdmEngine : public TimerHandler { virtual 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); - private: // private methods // Cancel all sessions diff --git a/libwvdrmengine/cdm/core/include/cdm_session.h b/libwvdrmengine/cdm/core/include/cdm_session.h index ac57f844..fa06a7e3 100644 --- a/libwvdrmengine/cdm/core/include/cdm_session.h +++ b/libwvdrmengine/cdm/core/include/cdm_session.h @@ -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, diff --git a/libwvdrmengine/cdm/core/include/initialization_data.h b/libwvdrmengine/cdm/core/include/initialization_data.h new file mode 100644 index 00000000..5d3a16f7 --- /dev/null +++ b/libwvdrmengine/cdm/core/include/initialization_data.h @@ -0,0 +1,47 @@ +// Copyright 2014 Google Inc. All Rights Reserved. + +#ifndef CORE_INCLUDE_INITIALIZATION_DATA_H_ +#define CORE_INCLUDE_INITIALIZATION_DATA_H_ + +#include + +#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_ diff --git a/libwvdrmengine/cdm/core/include/license.h b/libwvdrmengine/cdm/core/include/license.h index f888c9a0..5f94521e 100644 --- a/libwvdrmengine/cdm/core/include/license.h +++ b/libwvdrmengine/cdm/core/include/license.h @@ -5,6 +5,7 @@ #include +#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, diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h index 58cbdf38..f4874ebd 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h @@ -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_ diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index dd61c4ab..3514a192 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -5,7 +5,6 @@ #include #include -#include "buffer_reader.h" #include "cdm_session.h" #include "license_protocol.pb.h" #include "log.h" @@ -124,8 +123,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, @@ -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, 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(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 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 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() { if (!policy_timer_.IsRunning()) policy_timer_.Start(this, kCdmPolicyTimerDurationSeconds); diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index b88358c0..6dc3ba2d 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -112,16 +112,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) { @@ -149,22 +149,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_)) { @@ -176,15 +170,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; } diff --git a/libwvdrmengine/cdm/core/src/initialization_data.cpp b/libwvdrmengine/cdm/core/src/initialization_data.cpp new file mode 100644 index 00000000..dc34e8af --- /dev/null +++ b/libwvdrmengine/cdm/core/src/initialization_data.cpp @@ -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(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 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 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 diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index 3085a070..ee9662cf 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -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; } diff --git a/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp b/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp index 286c2658..ee6ae1ef 100644 --- a/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp @@ -3,6 +3,8 @@ #include #include +#include + #if defined(CHROMIUM_BUILD) #include "base/at_exit.h" #include "base/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" @@ -82,6 +85,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 { @@ -98,23 +105,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, @@ -122,8 +132,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_, @@ -162,8 +171,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; @@ -171,8 +179,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(KEY_ADDED, cdm_engine_->RenewKey(session_id_, resp)); @@ -199,41 +206,40 @@ 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); GetKeyRequestResponse(g_license_server, g_client_auth); } 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 diff --git a/libwvdrmengine/cdm/core/test/license_unittest.cpp b/libwvdrmengine/cdm/core/test/license_unittest.cpp index dbdae3a7..55326873 100644 --- a/libwvdrmengine/cdm/core/test/license_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/license_unittest.cpp @@ -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, diff --git a/libwvdrmengine/cdm/include/wv_content_decryption_module.h b/libwvdrmengine/cdm/include/wv_content_decryption_module.h index 9c85b2b2..53ead0ed 100644 --- a/libwvdrmengine/cdm/include/wv_content_decryption_module.h +++ b/libwvdrmengine/cdm/include/wv_content_decryption_module.h @@ -18,6 +18,9 @@ class WvContentDecryptionModule { WvContentDecryptionModule(); virtual ~WvContentDecryptionModule(); + // Static methods + static bool SupportsInitDataType(const std::string& type); + // Session related methods virtual CdmResponseType OpenSession( const CdmKeySystem& key_system, @@ -28,7 +31,7 @@ class WvContentDecryptionModule { // 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, diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index 8ed59bb2..251e3f7f 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -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" @@ -18,6 +19,10 @@ WvContentDecryptionModule::WvContentDecryptionModule() WvContentDecryptionModule::~WvContentDecryptionModule() {} +bool WvContentDecryptionModule::SupportsInitDataType(const std::string& type) { + return InitializationData(type).is_supported(); +} + CdmResponseType WvContentDecryptionModule::OpenSession( const CdmKeySystem& key_system, CdmClientPropertySet* property_set, @@ -38,7 +43,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, @@ -50,8 +55,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); diff --git a/libwvdrmengine/include/WVDrmFactory.h b/libwvdrmengine/include/WVDrmFactory.h index 7f09e417..b284b94f 100644 --- a/libwvdrmengine/include/WVDrmFactory.h +++ b/libwvdrmengine/include/WVDrmFactory.h @@ -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); diff --git a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h index 69be54ac..85e34055 100644 --- a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h @@ -53,7 +53,7 @@ class WVDrmPlugin : public android::DrmPlugin, virtual status_t getKeyRequest( const Vector& scope, const Vector& initData, - const String8& mimeType, + const String8& initDataType, KeyType keyType, const KeyedVector& optionalParameters, Vector& request, diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index 993f7770..c3db9119 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -128,7 +128,7 @@ status_t WVDrmPlugin::closeSession(const Vector& sessionId) { status_t WVDrmPlugin::getKeyRequest( const Vector& scope, const Vector& initData, - const String8& mimeType, + const String8& initDataType, KeyType keyType, const KeyedVector& optionalParameters, Vector& 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 diff --git a/libwvdrmengine/src/WVDrmFactory.cpp b/libwvdrmengine/src/WVDrmFactory.cpp index 50979e7d..b78b0892 100644 --- a/libwvdrmengine/src/WVDrmFactory.cpp +++ b/libwvdrmengine/src/WVDrmFactory.cpp @@ -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], diff --git a/libwvdrmengine/test/unit/WVDrmFactory_test.cpp b/libwvdrmengine/test/unit/WVDrmFactory_test.cpp index d6cfd1fa..e258f0e8 100644 --- a/libwvdrmengine/test/unit/WVDrmFactory_test.cpp +++ b/libwvdrmengine/test/unit/WVDrmFactory_test.cpp @@ -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) {