Source release v2.2.0-0-903 + third_party libs

Change-Id: I03f670eaeb052bc741abb347be06f8ddc58418e7
This commit is contained in:
Joey Parrish
2014-12-15 10:35:08 -08:00
parent 5318232d46
commit 1955c9c2c9
85 changed files with 5594 additions and 2830 deletions

View File

@@ -0,0 +1,48 @@
// Copyright 2014 Google Inc. All Rights Reserved.
#include <assert.h>
#include "wv_content_decryption_module_1.h"
#include "wv_content_decryption_module_4.h"
#include "wv_cdm_version.h"
void InitializeCdmModule() {}
void DeinitializeCdmModule() {}
void* CreateCdmInstance(int cdm_interface_version, const char* key_system,
uint32_t key_system_size,
GetCdmHostFunc get_cdm_host_func, void* user_data) {
void *host = NULL;
switch (cdm_interface_version) {
case cdm::ContentDecryptionModule_1::kVersion:
host = get_cdm_host_func(cdm::Host_1::kVersion, user_data);
break;
case cdm::ContentDecryptionModule_4::kVersion:
host = get_cdm_host_func(cdm::Host_4::kVersion, user_data);
break;
}
if (!host)
return NULL;
switch (cdm_interface_version) {
case cdm::ContentDecryptionModule_1::kVersion:
return new wvcdm::WvContentDecryptionModule_1(
static_cast<cdm::Host_1*>(host));
case cdm::ContentDecryptionModule_4::kVersion:
return new wvcdm::WvContentDecryptionModule_4(
static_cast<cdm::Host_4*>(host));
}
assert(false); // NOT REACHED
return NULL;
}
const char* GetCdmVersion() {
return WV_CDM_VERSION;
}

View File

@@ -1,73 +1,168 @@
// Copyright 2013 Google Inc. All Rights Reserved.
#include <string.h>
#include <string>
#include "cdm_host_file.h"
#include <string.h>
#include <algorithm>
#include <string>
namespace wvcdm {
IFileFactory* File::Impl::factory_ = NULL;
// File::Impl() Section
// The file handler for cert.bin, aka DeviceCertificate is all we're
// setting up for now.
// The file handler for cert.bin, aka DeviceCertificate, and usage.bin,
// aka UsageTable, are all we're setting up for now.
bool File::Impl::Exists(const std::string& name) {
namespace {
const char* const kDeviceCertificateKey = "DeviceCertificate";
const char* const kUsageInfoKey = "UsageInfo";
const char* const kUsageTableKey = "MockOemCryptoUsageTable";
const char* const kGenerationNumberKey = "MockOemCryptoGenerationNumber";
const char* GetKeyForFileName(const std::string& name) {
if (name == "cert.bin") {
return kDeviceCertificateKey;
} else if (name == "usage.bin") {
return kUsageInfoKey;
} else if (name == "UsageTable.dat") {
return kUsageTableKey;
} else if (name == "GenerationNumber.dat") {
return kGenerationNumberKey;
} else {
return "";
}
}
} // namespace
// File1 implmentation.
bool File1Impl::Open(const std::string& name) {
if (name.empty())
return false;
fname_ = name;
return true;
}
ssize_t File1Impl::Read(char* buffer, size_t bytes) {
std::string key(GetKeyForFileName(fname_));
if (key.length() > 0) {
std::string value;
host_->GetPlatformString("DeviceCertificate", &value);
return !value.empty();
host_1_->GetPlatformString(key, &value);
size_t bytes_to_copy = std::min(bytes, value.size());
memcpy(buffer, value.data(), bytes_to_copy);
return value.size() ? bytes_to_copy : -1;
} else {
return -1;
}
return false;
}
bool File::Impl::Open(const std::string& name) {
if (name == "cert.bin") {
fname_ = name;
bool File1Impl::Remove(const std::string& name) {
std::string key(GetKeyForFileName(name));
if (key.length() > 0) {
host_1_->SetPlatformString(key, "");
return true;
} else {
return false;
}
return false;
}
bool File::Impl::Close() {
ssize_t File1Impl::FileSize(const std::string& name) {
std::string key(GetKeyForFileName(name));
if (key.length() > 0) {
std::string value;
host_1_->GetPlatformString(key, &value);
return value.empty() ? -1 : value.size();
} else {
return -1;
}
}
ssize_t File1Impl::Write(const char* buffer, size_t bytes) {
std::string key(GetKeyForFileName(fname_));
if (key.length() > 0) {
std::string value(buffer, bytes);
host_1_->SetPlatformString(key, value);
return bytes;
} else {
return -1;
}
}
bool File1Impl::Close() {
fname_.clear();
return true;
}
bool File::Impl::Remove(const std::string& name) {
if (name == "cert.bin") {
host_->SetPlatformString("DeviceCertificate", "");
return true;
// File 4 Implementation.
bool File4Impl::Open(const std::string& name) {
return host_4_file_io_client_.Open(name);
}
ssize_t File4Impl::Read(char* buffer, size_t bytes) {
if (host_4_file_io_client_.Read(buffer, bytes) &&
host_4_file_io_client_.data_size() > 0) {
return std::min<size_t>(host_4_file_io_client_.data_size(), bytes);
} else {
return -1;
}
return false;
}
ssize_t File4Impl::Write(const char* buffer, size_t bytes) {
if (host_4_file_io_client_.Write(buffer, bytes)) {
return bytes;
} else {
return -1;
}
}
bool File4Impl::Close() {
return host_4_file_io_client_.Close();
}
bool File4Impl::Remove(const std::string& name) {
Host4FileIOClient file_io_client(host_4_);
return file_io_client.Open(name) && file_io_client.Write("", 0);
}
ssize_t File4Impl::FileSize(const std::string& name) {
Host4FileIOClient file_io_client(host_4_);
if (file_io_client.Open(name) && file_io_client.ReadFileSize() &&
file_io_client.data_size() > 0) {
return file_io_client.data_size();
} else {
return -1;
}
}
// Common file implementation.
bool File::Impl::Open(const std::string& name) {
return file_api_->Open(name);
}
ssize_t File::Impl::Read(char* buffer, size_t bytes) {
if (fname_ == "cert.bin") {
std::string value;
host_->GetPlatformString("DeviceCertificate", &value);
memcpy(buffer, value.data(), std::min(bytes, value.size()));
return value.size() ? value.size() : -1;
}
return -1;
return file_api_->Read(buffer, bytes);
}
ssize_t File::Impl::Write(const char* buffer, size_t bytes) {
if (fname_ == "cert.bin") {
std::string value(buffer, bytes);
host_->SetPlatformString("DeviceCertificate", value);
return bytes;
}
return -1;
return file_api_->Write(buffer, bytes);
}
bool File::Impl::Close() {
return file_api_->Close();
}
bool File::Impl::Exists(const std::string& name) {
return FileSize(name) > 0;
}
bool File::Impl::Remove(const std::string& name) {
return file_api_->Remove(name);
}
ssize_t File::Impl::FileSize(const std::string& name) {
if (name == "cert.bin") {
std::string value;
host_->GetPlatformString("DeviceCertificate", &value);
return value.size() ? value.size() : -1;
}
return -1;
return file_api_->FileSize(name);
}
File::File() : impl_(File::Impl::factory_->NewFileImpl()) {}
@@ -81,9 +176,7 @@ bool File::Open(const std::string& name, int flags) {
return impl_->Open(name);
}
void File::Close() {
impl_->Close();
}
void File::Close() { impl_->Close(); }
ssize_t File::Read(char* buffer, size_t bytes) {
return impl_->Read(buffer, bytes);
@@ -93,13 +186,9 @@ ssize_t File::Write(const char* buffer, size_t bytes) {
return impl_->Write(buffer, bytes);
}
bool File::Exists(const std::string& path) {
return impl_->Exists(path);
}
bool File::Exists(const std::string& path) { return impl_->Exists(path); }
bool File::Remove(const std::string& path) {
return impl_->Remove(path);
}
bool File::Remove(const std::string& path) { return impl_->Remove(path); }
bool File::Copy(const std::string& from, const std::string& to) {
// Required for linkage only - no API implementation is needed by the CDM

View File

@@ -0,0 +1,66 @@
// Copyright 2013 Google Inc. All Rights Reserved.
#include "host_4_file_io_client.h"
#include <string.h>
#include <algorithm>
namespace wvcdm {
Host4FileIOClient::~Host4FileIOClient() {
if (file_io_ != NULL) Close();
}
bool Host4FileIOClient::Open(const std::string& name) {
if (host_ == NULL) return false;
if (file_io_ != NULL) return false;
file_io_ = host_->CreateFileIO(this);
file_io_->Open(name.data(), name.length());
return status_ == kSuccess;
}
bool Host4FileIOClient::Read(char* buffer, size_t buffer_size) {
if (file_io_ == NULL) return false;
buffer_ = buffer;
buffer_size_ = buffer_size;
file_io_->Read();
return status_ == kSuccess;
}
bool Host4FileIOClient::Write(const char* data, size_t data_size) {
if (file_io_ == NULL) return false;
file_io_->Write(reinterpret_cast<const uint8_t*>(data), data_size);
return status_ == kSuccess;
}
bool Host4FileIOClient::Close() {
if (file_io_ == NULL) return false;
file_io_->Close();
file_io_ = NULL;
status_ = kSuccess;
data_size_ = 0;
return true;
}
void Host4FileIOClient::OnOpenComplete(Status status) {
status_ = status;
data_size_ = 0;
}
void Host4FileIOClient::OnReadComplete(Status status, const uint8_t* data,
uint32_t data_size) {
status_ = status;
data_size_ = data_size;
if (buffer_ != NULL) {
memcpy(buffer_, data, std::min<size_t>(data_size, buffer_size_));
buffer_ = NULL;
buffer_size_ = 0;
}
}
void Host4FileIOClient::OnWriteComplete(Status status) {
status_ = status;
data_size_ = 0;
}
} // namespace wvcdm

View File

@@ -1,20 +1,19 @@
// Copyright 2013 Google Inc. All Rights Reserved.
#include "wv_content_decryption_module.h"
#include "wv_content_decryption_module_1.h"
#include <assert.h>
#include <string.h>
#include <iostream>
#include "initialization_data.h"
#include "log.h"
#include "OEMCryptoCENC.h"
#include "properties.h"
#include "wv_cdm_constants.h"
#include "wv_cdm_types.h"
#include "wv_cdm_version.h"
namespace {
enum {
// individual error codes
kAttachEventListenerError = 0x0001,
@@ -24,31 +23,6 @@ enum {
kGenerateKeyRequestErrorBase = 0x0200,
kAddKeyErrorBase = 0x0300,
};
} // namespace
void INITIALIZE_CDM_MODULE() {}
void DeinitializeCdmModule() {}
void* CreateCdmInstance(int cdm_interface_version, const char* key_system,
int key_system_size, GetCdmHostFunc get_cdm_host_func,
void* user_data) {
if (cdm_interface_version != cdm::kCdmInterfaceVersion) return NULL;
cdm::Host* host = static_cast<cdm::Host*>(
get_cdm_host_func(cdm::kHostInterfaceVersion, user_data));
if (!host) return NULL;
return static_cast<cdm::ContentDecryptionModule*>(
new wvcdm::WvContentDecryptionModule(host));
}
int GetCdmVersion() { return cdm::kCdmInterfaceVersion; }
namespace {
static const std::string kWvCdmVersionString(WV_CDM_VERSION);
const int kCdmPolicyTimerDurationSeconds = 5;
@@ -58,10 +32,8 @@ const uint32_t kCencIvSize = 8;
const uint32_t kIvSize = 16;
bool Ctr128Add(size_t block_count, uint8_t* counter) {
if (NULL == counter)
return false;
if (0 == block_count)
return true;
if (NULL == counter) return false;
if (0 == block_count) return true;
uint8_t carry = 0;
uint8_t n = kIvSize - 1;
while (n >= kCencIvSize) {
@@ -79,35 +51,33 @@ bool Ctr128Add(size_t block_count, uint8_t* counter) {
return true;
}
} // namespace
} // namespace
namespace wvcdm {
// An empty iv string signals that the frame is unencrypted.
bool IsBufferEncrypted(const cdm::InputBuffer& input_buffer) {
return input_buffer.iv_size != 0;
}
// cdm::ContentDecryptionModule_1 implementation.
// cdm::ContentDecryptionModule implementation.
WvContentDecryptionModule::WvContentDecryptionModule(cdm::Host* host)
WvContentDecryptionModule_1::WvContentDecryptionModule_1(cdm::Host_1* host)
: host_(host),
host_event_listener_(host, &cdm_engine_),
cdm_engine_(),
property_set_(),
timer_enabled_(false) {
HostClock::SetClockInterface(this);
}
WvContentDecryptionModule::~WvContentDecryptionModule() {
WvContentDecryptionModule_1::~WvContentDecryptionModule_1() {
DisablePolicyTimer();
}
cdm::Status WvContentDecryptionModule::GenerateKeyRequest(
cdm::Status WvContentDecryptionModule_1::GenerateKeyRequest(
const char* type, int type_size, const uint8_t* init_data,
int init_data_size) {
LOGI("WvContentDecryptionModule::GenerateKeyRequest()");
LOGI("WvContentDecryptionModule_1::GenerateKeyRequest()");
CdmInitData init_data_internal(reinterpret_cast<const char*>(init_data),
init_data_size);
InitializationData initialization_data(ISO_BMFF_VIDEO_MIME_TYPE,
std::string type_string(type, type_size);
InitializationData initialization_data(type_string,
init_data_internal);
CdmKeyMessage key_request;
CdmSessionId session_id;
@@ -124,8 +94,8 @@ cdm::Status WvContentDecryptionModule::GenerateKeyRequest(
property_set_.set_use_privacy_mode(privacy_mode == "True" ? 1 : 0);
property_set_.set_service_certificate(service_certificate);
CdmResponseType result =
cdm_engine_.OpenSession("com.widevine.alpha", &property_set_, &session_id);
CdmResponseType result = cdm_engine_.OpenSession("com.widevine.alpha",
&property_set_, &session_id);
if (result == NEED_PROVISIONING) {
LOGI("Need to aquire a Device Certificate from the Provisioning Server");
@@ -150,7 +120,7 @@ cdm::Status WvContentDecryptionModule::GenerateKeyRequest(
result = cdm_engine_.GenerateKeyRequest(
session_id, key_set_id, initialization_data, kLicenseTypeStreaming,
app_parameters, &key_request, &server_url);
app_parameters, &key_request, &server_url, NULL);
if (KEY_MESSAGE != result) {
cdm_engine_.CloseSession(session_id);
host_->SendKeyError("", 0, cdm::kClientError,
@@ -164,18 +134,16 @@ cdm::Status WvContentDecryptionModule::GenerateKeyRequest(
return cdm::kSuccess;
}
cdm::Status WvContentDecryptionModule::AddKey(const char* session_id,
int session_id_size,
const uint8_t* key, int key_size,
const uint8_t* key_id,
int key_id_size) {
LOGI("WvContentDecryptionModule::AddKey()");
cdm::Status WvContentDecryptionModule_1::AddKey(
const char* session_id, int session_id_size, const uint8_t* key,
int key_size, const uint8_t* key_id, int key_id_size) {
LOGI("WvContentDecryptionModule_1::AddKey()");
CdmSessionId session_id_internal(session_id, session_id_size);
CdmKeyResponse key_data((const char*)key, key_size);
CdmKeySetId key_set_id;
CdmResponseType response = cdm_engine_.AddKey(session_id_internal,
key_data, &key_set_id);
CdmResponseType response =
cdm_engine_.AddKey(session_id_internal, key_data, &key_set_id);
if (response == KEY_ADDED) {
EnablePolicyTimer();
@@ -187,66 +155,58 @@ cdm::Status WvContentDecryptionModule::AddKey(const char* session_id,
return cdm::kSessionError;
}
bool WvContentDecryptionModule::IsKeyValid(const uint8_t* key_id,
int key_id_size) {
bool WvContentDecryptionModule_1::IsKeyValid(const uint8_t* key_id,
int key_id_size) {
KeyId key(reinterpret_cast<const char*>(key_id), key_id_size);
return cdm_engine_.IsKeyLoaded(key);
}
cdm::Status WvContentDecryptionModule::CloseSession(const char* session_id,
int session_id_size) {
LOGI("WvContentDecryptionModule::CloseSession()");
cdm::Status WvContentDecryptionModule_1::CloseSession(const char* session_id,
int session_id_size) {
LOGI("WvContentDecryptionModule_1::CloseSession()");
CdmSessionId session_id_internal(session_id, session_id_size);
return cdm_engine_.CloseSession(session_id_internal) == NO_ERROR
? cdm::kSuccess
: cdm::kSessionError;
}
void WvContentDecryptionModule::TimerExpired(void* context) {
LOGI("WvContentDecryptionModule::TimerExpired()");
void WvContentDecryptionModule_1::TimerExpired(void* context) {
LOGI("WvContentDecryptionModule_1::TimerExpired()");
if (timer_enabled_) {
cdm_engine_.OnTimerEvent();
host_->SetTimer(kCdmPolicyTimerDurationSeconds * 1000, NULL);
}
}
cdm::Status WvContentDecryptionModule::Decrypt(
cdm::Status WvContentDecryptionModule_1::Decrypt(
const cdm::InputBuffer& encrypted_buffer,
cdm::DecryptedBlock* decrypted_block) {
LOGI("WvContentDecryptionModule::Decrypt()");
LOGI("WvContentDecryptionModule_1::Decrypt()");
if (static_cast<size_t>(encrypted_buffer.iv_size) != KEY_IV_SIZE)
return cdm::kDecryptError;
std::vector < uint8_t > iv(KEY_IV_SIZE);
std::vector<uint8_t> iv(KEY_IV_SIZE);
memcpy(&iv[0], encrypted_buffer.iv, encrypted_buffer.iv_size);
KeyId key_id(reinterpret_cast<const char*>(encrypted_buffer.key_id),
encrypted_buffer.key_id_size);
CdmSessionId session_id; // it's empty but cdm_engine will locate via key_id?
if (!encrypted_buffer.subsamples ||
encrypted_buffer.num_subsamples <= 0)
return cdm::kDecryptError;
CdmDecryptionParameters parameters(&key_id,
encrypted_buffer.data, 0, &iv, 0,
CdmDecryptionParameters parameters(&key_id, encrypted_buffer.data, 0, &iv, 0,
NULL);
parameters.is_secure = Properties::oem_crypto_use_secure_buffers();
return DoSubsampleDecrypt(parameters,
iv,
encrypted_buffer,
decrypted_block);
if (encrypted_buffer.num_subsamples)
return DoSubsampleDecrypt(parameters, iv, encrypted_buffer, decrypted_block);
else
return DoDecrypt(parameters, iv, encrypted_buffer, decrypted_block);
}
// This is the Level 1 API. When the host application calls the CDM's
// DecryptDecodeAndRenderFrame(), rather than the CDM's Decrypt(),
// OEMCrypto_DecryptCTR() will be told to use direct rendering with no
// cleartext in the return.
cdm::Status WvContentDecryptionModule::DecryptDecodeAndRenderFrame(
cdm::Status WvContentDecryptionModule_1::DecryptDecodeAndRenderFrame(
const cdm::InputBuffer& encrypted_buffer) {
LOGI("WvContentDecryptionModule::DecryptDecodeAndRenderFrame()");
LOGI("WvContentDecryptionModule_1::DecryptDecodeAndRenderFrame()");
if (static_cast<size_t>(encrypted_buffer.iv_size) != KEY_IV_SIZE)
return cdm::kDecryptError;
@@ -255,24 +215,23 @@ cdm::Status WvContentDecryptionModule::DecryptDecodeAndRenderFrame(
memcpy(&iv[0], encrypted_buffer.iv, encrypted_buffer.iv_size);
KeyId key_id(reinterpret_cast<const char*>(encrypted_buffer.key_id),
encrypted_buffer.key_id_size);
CdmSessionId session_id; // it's empty but cdm_engine will locate via key_id.
if (!encrypted_buffer.subsamples ||
encrypted_buffer.num_subsamples <= 0)
return cdm::kDecryptError;
CdmDecryptionParameters parameters(&key_id, encrypted_buffer.data, 0, &iv, 0,
NULL);
return DoSubsampleDecrypt(parameters, iv, encrypted_buffer, NULL);
if (encrypted_buffer.num_subsamples)
return DoSubsampleDecrypt(parameters, iv, encrypted_buffer, NULL);
else
return DoDecrypt(parameters, iv, encrypted_buffer, NULL);
}
// This is the Level 1 API. When the host application calls the CDM's
// DecryptDecodeAndRenderSamples(), rather than the CDM's Decrypt(),
// OEMCrypto_DecryptCTR() will be told to use direct rendering with no cleartext
// in the return.
cdm::Status WvContentDecryptionModule::DecryptDecodeAndRenderSamples(
cdm::Status WvContentDecryptionModule_1::DecryptDecodeAndRenderSamples(
const cdm::InputBuffer& encrypted_buffer) {
LOGI("WvContentDecryptionModule::DecryptDecodeAndRenderSamples()");
LOGI("WvContentDecryptionModule_1::DecryptDecodeAndRenderSamples()");
if (static_cast<size_t>(encrypted_buffer.iv_size) != KEY_IV_SIZE)
return cdm::kDecryptError;
@@ -281,92 +240,78 @@ cdm::Status WvContentDecryptionModule::DecryptDecodeAndRenderSamples(
memcpy(&iv[0], encrypted_buffer.iv, encrypted_buffer.iv_size);
KeyId key_id(reinterpret_cast<const char*>(encrypted_buffer.key_id),
encrypted_buffer.key_id_size);
CdmSessionId session_id; // it's empty but cdm_engine will locate via key_id.
if (!encrypted_buffer.subsamples ||
encrypted_buffer.num_subsamples <= 0)
return cdm::kDecryptError;
CdmDecryptionParameters parameters(&key_id, encrypted_buffer.data, 0, &iv, 0,
NULL);
parameters.is_video = false; // override the default true value for audio.
return DoSubsampleDecrypt(parameters, iv, encrypted_buffer, NULL);
if (encrypted_buffer.num_subsamples)
return DoSubsampleDecrypt(parameters, iv, encrypted_buffer, NULL);
else
return DoDecrypt(parameters, iv, encrypted_buffer, NULL);
}
void WvContentDecryptionModule::Destroy() { delete this; }
void WvContentDecryptionModule_1::Destroy() { delete this; }
// Provisioning related methods
cdm::Status WvContentDecryptionModule::GetProvisioningRequest(
cdm::Status WvContentDecryptionModule_1::GetProvisioningRequest(
std::string* request, std::string* provisioning_server_url) {
CdmCertificateType cert_type = kCertificateWidevine;
std::string cert_authority;
if (cdm_engine_.GetProvisioningRequest(cert_type, cert_authority,
static_cast<CdmProvisioningRequest*>(request),
provisioning_server_url) == NO_ERROR) {
if (cdm_engine_.GetProvisioningRequest(
cert_type, cert_authority,
static_cast<CdmProvisioningRequest*>(request),
provisioning_server_url) == NO_ERROR) {
return cdm::kSuccess;
}
return cdm::kSessionError;
}
cdm::Status WvContentDecryptionModule::HandleProvisioningResponse(
cdm::Status WvContentDecryptionModule_1::HandleProvisioningResponse(
std::string& response) {
std::string cert, wrapped_key;
if (cdm_engine_.HandleProvisioningResponse(
static_cast<CdmProvisioningRequest&>(response), &cert, &wrapped_key) ==
NO_ERROR) {
static_cast<CdmProvisioningRequest&>(response), &cert,
&wrapped_key) == NO_ERROR) {
return cdm::kSuccess;
}
return cdm::kSessionError;
}
void WvContentDecryptionModule::EnablePolicyTimer() {
LOGI("WvContentDecryptionModule::EnablePolicyTimer()");
void WvContentDecryptionModule_1::EnablePolicyTimer() {
LOGI("WvContentDecryptionModule_1::EnablePolicyTimer()");
if (!timer_enabled_) {
timer_enabled_ = true;
host_->SetTimer(kCdmPolicyTimerDurationSeconds * 1000, NULL);
}
}
void WvContentDecryptionModule::DisablePolicyTimer() {
LOGI("WvContentDecryptionModule::DisablePolicyTimer()");
void WvContentDecryptionModule_1::DisablePolicyTimer() {
LOGI("WvContentDecryptionModule_1::DisablePolicyTimer()");
timer_enabled_ = false;
}
cdm::Status WvContentDecryptionModule::DoSubsampleDecrypt(
CdmDecryptionParameters& parameters,
std::vector < uint8_t >& iv,
cdm::Status WvContentDecryptionModule_1::DoSubsampleDecrypt(
CdmDecryptionParameters& parameters, std::vector<uint8_t>& iv,
const cdm::InputBuffer& encrypted_buffer,
cdm::DecryptedBlock* decrypted_block) {
/* This routine assumes session_id and iv have already
been initialized by the caller and encrypted_buffer contains subsample
information. Also, parameters is expected to be pre-initialized with any
needed parameters not related to subsample parsing.
decrypted_block may be NULL. */
CdmSessionId session_id; // it's empty but cdm_engine will locate via key_id.
CdmResponseType status = NO_ERROR;
if (!encrypted_buffer.subsamples)
return cdm::kDecryptError;
size_t output_size = 0;
for (int i = 0; i < encrypted_buffer.num_subsamples; ++i) {
const cdm::SubsampleEntry& subsample = encrypted_buffer.subsamples[i];
output_size += subsample.cipher_bytes + subsample.clear_bytes;
}
parameters.decrypt_buffer_length = output_size;
assert(output_size ==
encrypted_buffer.data_size - encrypted_buffer.data_offset);
if (decrypted_block) {
cdm::Buffer* buffer = host_->Allocate(output_size);
decrypted_block->SetDecryptedBuffer(buffer);
parameters.decrypt_buffer = buffer->Data();
} else {
parameters.decrypt_buffer = NULL;
}
SetSizesAndAllocate(output_size, parameters, decrypted_block);
size_t offset = 0;
size_t encrypted_offset = 0;
uint32_t block_ctr = 0;
const cdm::SubsampleEntry *subsamples = encrypted_buffer.subsamples;
bool first = true;
const cdm::SubsampleEntry* subsamples = encrypted_buffer.subsamples;
for (int i = 0; i < encrypted_buffer.num_subsamples; ++i) {
const cdm::SubsampleEntry& subsample = subsamples[i];
@@ -374,53 +319,103 @@ cdm::Status WvContentDecryptionModule::DoSubsampleDecrypt(
for (int is_encrypted = 0; is_encrypted < 2; ++is_encrypted) {
size_t bytes =
is_encrypted ? subsample.cipher_bytes : subsample.clear_bytes;
if (0 == bytes)
continue;
if (is_encrypted) {
uint32_t counter = encrypted_offset / kIvSize;
Ctr128Add(counter - block_ctr, &iv[0]);
block_ctr = counter;
}
parameters.encrypt_buffer =
&encrypted_buffer.data[encrypted_buffer.data_offset + offset];
parameters.decrypt_buffer_offset = offset;
parameters.encrypt_length = bytes;
parameters.block_offset = encrypted_offset % kIvSize;
offset += bytes;
if (is_encrypted)
encrypted_offset += bytes;
if (bytes == 0) continue;
parameters.is_encrypted = is_encrypted;
parameters.subsample_flags =
first ? OEMCrypto_FirstSubsample : 0;
parameters.subsample_flags |= (
offset == static_cast<size_t>(encrypted_buffer.data_size)
? OEMCrypto_LastSubsample : 0);
((offset == 0) ? OEMCrypto_FirstSubsample : 0) |
((offset + bytes == output_size) ? OEMCrypto_LastSubsample : 0);
first = false;
status = cdm_engine_.Decrypt(session_id, parameters);
switch (status) {
case wvcdm::NEED_KEY:
return cdm::kNoKey;
case wvcdm::NO_ERROR:
break;
default:
return cdm::kDecryptError;
}
cdm::Status status =
DecryptAndUpdateCounters(parameters, iv, encrypted_buffer,
bytes, decrypted_block, offset,
encrypted_offset, block_ctr);
if (status != cdm::kSuccess)
return status;
}
}
return cdm::kSuccess;
}
int64_t WvContentDecryptionModule::GetCurrentTimeInSeconds() {
cdm::Status WvContentDecryptionModule_1::DoDecrypt(
CdmDecryptionParameters& parameters, std::vector<uint8_t>& iv,
const cdm::InputBuffer& encrypted_buffer,
cdm::DecryptedBlock* decrypted_block) {
assert(!encrypted_buffer.subsamples);
size_t output_size =
encrypted_buffer.data_size - encrypted_buffer.data_offset;
SetSizesAndAllocate(output_size, parameters, decrypted_block);
size_t offset = 0;
size_t encrypted_offset = 0;
uint32_t block_ctr = 0;
parameters.is_encrypted = true;
parameters.subsample_flags =
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample;
return DecryptAndUpdateCounters(parameters, iv, encrypted_buffer,
output_size, decrypted_block, offset,
encrypted_offset, block_ctr);
}
void WvContentDecryptionModule_1::SetSizesAndAllocate(
size_t output_size,
CdmDecryptionParameters& parameters,
cdm::DecryptedBlock* decrypted_block) {
parameters.decrypt_buffer_length = output_size;
if (decrypted_block) {
cdm::Buffer* buffer = host_->Allocate(output_size);
buffer->SetSize(output_size);
decrypted_block->SetDecryptedBuffer(buffer);
parameters.decrypt_buffer = buffer->Data();
} else {
parameters.decrypt_buffer = NULL;
}
}
cdm::Status WvContentDecryptionModule_1::DecryptAndUpdateCounters(
CdmDecryptionParameters& parameters,
std::vector<uint8_t>& iv,
const cdm::InputBuffer& encrypted_buffer,
const size_t bytes,
cdm::DecryptedBlock* decrypted_block,
size_t& offset,
size_t& encrypted_offset,
uint32_t& block_ctr) {
if (parameters.is_encrypted) {
uint32_t counter = encrypted_offset / kIvSize;
Ctr128Add(counter - block_ctr, &iv[0]);
block_ctr = counter;
}
parameters.encrypt_buffer =
&encrypted_buffer.data[encrypted_buffer.data_offset + offset];
parameters.decrypt_buffer_offset = offset;
parameters.encrypt_length = bytes;
parameters.block_offset = encrypted_offset % kIvSize;
offset += bytes;
if (parameters.is_encrypted) encrypted_offset += bytes;
CdmSessionId session_id; // cdm_engine will locate via key_id.
CdmResponseType status = cdm_engine_.Decrypt(session_id, parameters);
switch (status) {
case wvcdm::NEED_KEY:
return cdm::kNoKey;
case wvcdm::NO_ERROR:
return cdm::kSuccess;
default:
return cdm::kDecryptError;
}
}
int64_t WvContentDecryptionModule_1::GetCurrentTimeInSeconds() {
return host_->GetCurrentWallTimeInSeconds();
}
File::Impl* WvContentDecryptionModule::NewFileImpl() {
File::Impl* WvContentDecryptionModule_1::NewFileImpl() {
return new File::Impl(host_);
}

View File

@@ -0,0 +1,597 @@
// Copyright 2014 Google Inc. All Rights Reserved.
#include "wv_content_decryption_module_4.h"
#include <assert.h>
#include "log.h"
#include "properties.h"
#include "wv_cdm_constants.h"
namespace {
enum {
// individual error codes
kAttachEventListenerError = 0x0001,
kLicenseExpiredNotification = 0x0002,
kSessionNotFoundError = 0x0003,
kSessionAlreadyExistsError = 0x0004,
kInvalidParameter = 0x0005,
kNotImplemented = 0x0006,
// error classes to be OR'd with cdm engine result values
kOpenSessionErrorBase = 0x0100,
kGenerateKeyRequestErrorBase = 0x0200,
kGenerateRenewalRequestErrorBase = 0x0300,
kUpdateSessionErrorBase = 0x0400,
kRestoreKeyErrorBase = 0x0500,
kOpenKeySetSessionErrorBase = 0x0600,
kGetProvisioningRequestErrorBase = 0x0700,
kHandleProvisioningResponseErrorBase = 0x0800,
};
const int kCdmPolicyTimerDurationSeconds = 5;
// The iso spec only uses the lower 8 bytes of the iv as
// the counter.
const uint32_t kCencIvSize = 8;
const uint32_t kIvSize = 16;
void Ctr128Add(size_t block_count, uint8_t* counter) {
assert(NULL != counter);
if (0 == block_count) return;
uint8_t carry = 0;
uint8_t n = kIvSize - 1;
while (n >= kCencIvSize) {
uint32_t temp = block_count & 0xff;
temp += counter[n];
temp += carry;
counter[n] = temp & 0xff;
carry = (temp & 0x100) ? 1 : 0;
block_count = block_count >> 8;
n--;
if (!block_count && !carry) {
break;
}
}
}
} // namespace
namespace wvcdm {
// cdm::ContentDecryptionModule_4 implementation.
WvContentDecryptionModule_4::WvContentDecryptionModule_4(cdm::Host_4* host)
: host_(host), timer_enabled_(false) {
HostClock::SetClockInterface(this);
}
WvContentDecryptionModule_4::~WvContentDecryptionModule_4() {
DisablePolicyTimer();
}
void WvContentDecryptionModule_4::CreateSession(uint32_t session_id,
const char* mime_type,
uint32_t mime_type_size,
const uint8_t* init_data,
uint32_t init_data_size,
cdm::SessionType session_type) {
if (session_type == cdm::kProvisioning) {
// CreateProvisionSession() dispatches its own errors to the host.
CreateProvisionSession(session_id);
} else {
CdmLicenseType license_type;
switch (session_type) {
case cdm::kTemporary:
license_type = kLicenseTypeStreaming;
break;
case cdm::kPersistent:
license_type = kLicenseTypeOffline;
break;
default:
LOGE(
"WvContentDecryptionModule_4::CreateSession: Unsupported session "
"type ",
session_type);
host_->OnSessionError(session_id, cdm::kSessionError,
kInvalidParameter);
return;
}
if (!CallOpenSession(session_id)) {
// CallOpenSession() dispatches its own errors to the host.
return;
}
CdmSessionId internal_session_id = session_map_[session_id].webid();
CdmKeySetId empty_key_set_id;
std::string mime_type_string(mime_type, mime_type_size);
CdmInitData init_data_internal(reinterpret_cast<const char*>(init_data),
init_data_size);
InitializationData initialization_data(mime_type_string,
init_data_internal);
CdmAppParameterMap empty_app_parameters;
CdmKeyMessage key_request;
std::string server_url;
CdmKeySetId key_set_id;
CdmResponseType result = cdm_engine_.GenerateKeyRequest(
internal_session_id, empty_key_set_id, initialization_data,
license_type, empty_app_parameters, &key_request, &server_url,
&key_set_id);
if (KEY_MESSAGE == result) {
if (session_type == cdm::kPersistent) {
host_->OnSessionCreated(session_id, key_set_id.c_str(),
key_set_id.length());
} else {
host_->OnSessionCreated(session_id, internal_session_id.c_str(),
internal_session_id.length());
}
host_->OnSessionMessage(session_id, key_request.c_str(),
key_request.length(), server_url.c_str(),
server_url.length());
} else {
cdm_engine_.CloseSession(internal_session_id);
session_map_.erase(session_id);
host_->OnSessionError(session_id, cdm::kSessionError,
kGenerateKeyRequestErrorBase | result);
}
}
}
void WvContentDecryptionModule_4::LoadSession(uint32_t session_id,
const char* web_session_id,
uint32_t web_session_id_length) {
if (!CallOpenSession(session_id)) {
// CallOpenSession() dispatches its own errors to the host.
return;
}
CdmSessionId internal_session_id = session_map_[session_id].webid();
CdmKeySetId key_set_id(web_session_id, web_session_id_length);
CdmResponseType result =
cdm_engine_.RestoreKey(internal_session_id, key_set_id);
if (result != KEY_ADDED) {
cdm_engine_.CloseSession(internal_session_id);
session_map_.erase(session_id);
host_->OnSessionError(session_id, cdm::kSessionError,
kRestoreKeyErrorBase | result);
return;
}
host_->OnSessionCreated(session_id, web_session_id, web_session_id_length);
}
void WvContentDecryptionModule_4::UpdateSession(uint32_t session_id,
const uint8_t* response,
uint32_t response_size) {
LOGI("WvContentDecryptionModule_4::UpdateSession()");
if (session_map_.count(session_id) == 0) {
host_->OnSessionError(session_id, cdm::kSessionError,
kSessionNotFoundError);
return;
}
const InternalSession& session = session_map_[session_id];
if (session.is_provision()) {
// UpdateProvisionSession() dispatches its own errors to the host.
UpdateProvisionSession(session_id, response, response_size);
} else {
bool is_release = session.is_release();
CdmSessionId session_id_internal;
CdmKeySetId key_set_id;
if (!is_release) {
session_id_internal = session.webid();
} else {
key_set_id = session.webid();
}
CdmKeyResponse key_data((const char*)response, response_size);
CdmResponseType status =
cdm_engine_.AddKey(session_id_internal, key_data, &key_set_id);
if (status != KEY_ADDED) {
host_->OnSessionError(session_id, cdm::kSessionError,
status | kUpdateSessionErrorBase);
return;
}
if (!is_release) EnablePolicyTimer();
host_->OnSessionUpdated(session_id);
}
}
bool WvContentDecryptionModule_4::IsKeyValid(const uint8_t* key_id,
int key_id_size) {
KeyId cdm_key_id(reinterpret_cast<const char*>(key_id), key_id_size);
return cdm_engine_.IsKeyLoaded(cdm_key_id);
}
void WvContentDecryptionModule_4::ReleaseSession(uint32_t session_id) {
if (session_map_.count(session_id) == 0) {
host_->OnSessionError(session_id, cdm::kSessionError,
kSessionNotFoundError);
return;
}
if (session_map_[session_id].is_release()) {
cdm_engine_.CloseKeySetSession(session_map_[session_id].webid());
} else if (session_map_[session_id].is_decrypt()) {
cdm_engine_.CloseSession(session_map_[session_id].webid());
}
host_->OnSessionClosed(session_id);
session_map_.erase(session_id);
}
void WvContentDecryptionModule_4::RemoveSession(
uint32_t session_id, const char* web_session_id,
uint32_t web_session_id_length) {
if (session_map_.count(session_id) != 0) {
host_->OnSessionError(session_id, cdm::kSessionError,
kSessionAlreadyExistsError);
return;
}
CdmKeySetId key_set_id(web_session_id, web_session_id_length);
CdmResponseType result = cdm_engine_.OpenKeySetSession(key_set_id);
if (result != NO_ERROR) {
host_->OnSessionError(session_id, cdm::kSessionError,
kOpenKeySetSessionErrorBase | result);
return;
}
session_map_[session_id] =
InternalSession(key_set_id, InternalSession::kRelease);
CdmSessionId empty_session_id;
InitializationData empty_initialization_data;
CdmAppParameterMap empty_app_parameters;
CdmKeyMessage key_request;
std::string server_url;
result = cdm_engine_.GenerateKeyRequest(
empty_session_id, key_set_id, empty_initialization_data,
kLicenseTypeRelease, empty_app_parameters, &key_request, &server_url,
NULL);
if (KEY_MESSAGE == result) {
host_->OnSessionCreated(session_id, key_set_id.c_str(),
key_set_id.length());
host_->OnSessionMessage(session_id, key_request.c_str(),
key_request.length(), server_url.c_str(),
server_url.length());
} else {
cdm_engine_.CloseKeySetSession(key_set_id);
host_->OnSessionError(session_id, cdm::kSessionError,
kGenerateKeyRequestErrorBase | result);
}
}
cdm::Status WvContentDecryptionModule_4::UsePrivacyMode() {
if (!session_map_.empty()) return cdm::kSessionError;
property_set_.set_use_privacy_mode(true);
return cdm::kSuccess;
}
cdm::Status WvContentDecryptionModule_4::SetServerCertificate(
const uint8_t* server_certificate_data,
uint32_t server_certificate_data_size) {
if (!session_map_.empty()) return cdm::kSessionError;
cdm::Status result = UsePrivacyMode();
if (result != cdm::kSuccess) return result;
std::string server_certificate(
reinterpret_cast<const char*>(server_certificate_data),
server_certificate_data_size);
property_set_.set_service_certificate(server_certificate);
return cdm::kSuccess;
}
void WvContentDecryptionModule_4::TimerExpired(void* context) {
LOGI("WvContentDecryptionModule_4::TimerExpired()");
if (timer_enabled_) {
cdm_engine_.OnTimerEvent();
host_->SetTimer(kCdmPolicyTimerDurationSeconds * 1000, NULL);
}
}
cdm::Status WvContentDecryptionModule_4::Decrypt(
const cdm::InputBuffer& encrypted_buffer,
cdm::DecryptedBlock* decrypted_block) {
LOGI("WvContentDecryptionModule_4::Decrypt()");
if (static_cast<size_t>(encrypted_buffer.iv_size) != KEY_IV_SIZE)
return cdm::kDecryptError;
std::vector<uint8_t> iv(encrypted_buffer.iv,
encrypted_buffer.iv + encrypted_buffer.iv_size);
KeyId key_id(reinterpret_cast<const char*>(encrypted_buffer.key_id),
encrypted_buffer.key_id_size);
CdmDecryptionParameters parameters(&key_id, encrypted_buffer.data, 0, &iv, 0,
NULL);
parameters.is_secure = Properties::oem_crypto_use_secure_buffers();
if (encrypted_buffer.num_subsamples)
return DoSubsampleDecrypt(parameters, iv, encrypted_buffer,
decrypted_block);
else
return DoDecrypt(parameters, iv, encrypted_buffer, decrypted_block);
}
cdm::Status WvContentDecryptionModule_4::DecryptDecodeAndRender(
const cdm::InputBuffer& encrypted_buffer, cdm::StreamType stream_type) {
LOGI("WvContentDecryptionModule_4::DecryptDecodeAndRender()");
if (static_cast<size_t>(encrypted_buffer.iv_size) != KEY_IV_SIZE)
return cdm::kDecryptError;
std::vector<uint8_t> iv(encrypted_buffer.iv,
encrypted_buffer.iv + encrypted_buffer.iv_size);
KeyId key_id(reinterpret_cast<const char*>(encrypted_buffer.key_id),
encrypted_buffer.key_id_size);
CdmDecryptionParameters parameters(&key_id, encrypted_buffer.data, 0, &iv, 0,
NULL);
parameters.is_video = (stream_type == cdm::kStreamTypeVideo);
if (encrypted_buffer.num_subsamples)
return DoSubsampleDecrypt(parameters, iv, encrypted_buffer, NULL);
else
return DoDecrypt(parameters, iv, encrypted_buffer, NULL);
}
void WvContentDecryptionModule_4::Destroy() { delete this; }
File::Impl* WvContentDecryptionModule_4::NewFileImpl() {
return new File::Impl(host_);
}
cdm::Status WvContentDecryptionModule_4::DoSubsampleDecrypt(
CdmDecryptionParameters& parameters, std::vector<uint8_t>& iv,
const cdm::InputBuffer& encrypted_buffer,
cdm::DecryptedBlock* decrypted_block) {
if (!encrypted_buffer.subsamples) return cdm::kDecryptError;
size_t output_size = 0;
for (int i = 0; i < encrypted_buffer.num_subsamples; ++i) {
const cdm::SubsampleEntry& subsample = encrypted_buffer.subsamples[i];
output_size += subsample.cipher_bytes + subsample.clear_bytes;
}
assert(output_size ==
encrypted_buffer.data_size - encrypted_buffer.data_offset);
SetSizesAndAllocate(output_size, parameters, decrypted_block);
size_t offset = 0;
size_t encrypted_offset = 0;
uint32_t block_ctr = 0;
const cdm::SubsampleEntry* subsamples = encrypted_buffer.subsamples;
for (int i = 0; i < encrypted_buffer.num_subsamples; ++i) {
const cdm::SubsampleEntry& subsample = subsamples[i];
for (int is_encrypted = 0; is_encrypted < 2; ++is_encrypted) {
size_t bytes =
is_encrypted ? subsample.cipher_bytes : subsample.clear_bytes;
if (bytes == 0) continue;
parameters.is_encrypted = is_encrypted;
parameters.subsample_flags =
((offset == 0) ? OEMCrypto_FirstSubsample : 0) |
((offset + bytes == output_size) ? OEMCrypto_LastSubsample : 0);
cdm::Status status = DecryptAndUpdateCounters(
parameters, iv, encrypted_buffer, bytes, decrypted_block, offset,
encrypted_offset, block_ctr);
if (status != cdm::kSuccess) return status;
}
}
return cdm::kSuccess;
}
cdm::Status WvContentDecryptionModule_4::DoDecrypt(
CdmDecryptionParameters& parameters, std::vector<uint8_t>& iv,
const cdm::InputBuffer& encrypted_buffer,
cdm::DecryptedBlock* decrypted_block) {
assert(!encrypted_buffer.subsamples);
size_t output_size =
encrypted_buffer.data_size - encrypted_buffer.data_offset;
SetSizesAndAllocate(output_size, parameters, decrypted_block);
size_t offset = 0;
size_t encrypted_offset = 0;
uint32_t block_ctr = 0;
parameters.is_encrypted = true;
parameters.subsample_flags =
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample;
return DecryptAndUpdateCounters(parameters, iv, encrypted_buffer, output_size,
decrypted_block, offset, encrypted_offset,
block_ctr);
}
void WvContentDecryptionModule_4::SetSizesAndAllocate(
size_t output_size, CdmDecryptionParameters& parameters,
cdm::DecryptedBlock* decrypted_block) {
parameters.decrypt_buffer_length = output_size;
if (decrypted_block) {
cdm::Buffer* buffer = host_->Allocate(output_size);
buffer->SetSize(output_size);
decrypted_block->SetDecryptedBuffer(buffer);
parameters.decrypt_buffer = buffer->Data();
} else {
parameters.decrypt_buffer = NULL;
}
}
cdm::Status WvContentDecryptionModule_4::DecryptAndUpdateCounters(
CdmDecryptionParameters& parameters, std::vector<uint8_t>& iv,
const cdm::InputBuffer& encrypted_buffer, const size_t bytes,
cdm::DecryptedBlock* decrypted_block, size_t& offset,
size_t& encrypted_offset, uint32_t& block_ctr) {
if (parameters.is_encrypted) {
uint32_t counter = encrypted_offset / kIvSize;
Ctr128Add(counter - block_ctr, &iv[0]);
block_ctr = counter;
}
parameters.encrypt_buffer =
&encrypted_buffer.data[encrypted_buffer.data_offset + offset];
parameters.decrypt_buffer_offset = offset;
parameters.encrypt_length = bytes;
parameters.block_offset = encrypted_offset % kIvSize;
offset += bytes;
if (parameters.is_encrypted) encrypted_offset += bytes;
CdmSessionId session_id; // cdm_engine will locate via key_id.
CdmResponseType status = cdm_engine_.Decrypt(session_id, parameters);
switch (status) {
case wvcdm::NEED_KEY:
return cdm::kNoKey;
case wvcdm::NO_ERROR:
return cdm::kSuccess;
default:
return cdm::kDecryptError;
}
}
void WvContentDecryptionModule_4::EnablePolicyTimer() {
LOGI("WvContentDecryptionModule_4::EnablePolicyTimer()");
if (!timer_enabled_) {
timer_enabled_ = true;
host_->SetTimer(kCdmPolicyTimerDurationSeconds * 1000, NULL);
}
}
void WvContentDecryptionModule_4::DisablePolicyTimer() {
LOGI("WvContentDecryptionModule_4::DisablePolicyTimer()");
timer_enabled_ = false;
}
void WvContentDecryptionModule_4::CreateProvisionSession(uint32_t session_id) {
CdmCertificateType cert_type = kCertificateWidevine;
std::string cert_authority;
CdmProvisioningRequest request;
std::string default_url;
CdmResponseType status = cdm_engine_.GetProvisioningRequest(
cert_type, cert_authority, &request, &default_url);
if (status != NO_ERROR) {
host_->OnSessionError(session_id, cdm::kSessionError,
kGetProvisioningRequestErrorBase | status);
return;
}
std::string blank_web_id;
session_map_[session_id] =
InternalSession(blank_web_id, InternalSession::kProvision);
host_->OnSessionCreated(session_id, blank_web_id.c_str(),
blank_web_id.length());
host_->OnSessionMessage(session_id, request.c_str(), request.length(),
default_url.c_str(), default_url.length());
}
void WvContentDecryptionModule_4::UpdateProvisionSession(
uint32_t session_id, const uint8_t* response, uint32_t response_size) {
CdmProvisioningResponse cdm_response(reinterpret_cast<const char*>(response),
response_size);
std::string cert;
std::string wrapped_key;
CdmResponseType status =
cdm_engine_.HandleProvisioningResponse(cdm_response, &cert, &wrapped_key);
if (status != NO_ERROR) {
host_->OnSessionError(session_id, cdm::kSessionError,
kHandleProvisioningResponseErrorBase | status);
return;
}
host_->OnSessionUpdated(session_id);
}
bool WvContentDecryptionModule_4::CallOpenSession(uint32_t session_id) {
CdmSessionId internal_session_id;
if (session_map_.count(session_id) != 0) {
host_->OnSessionError(session_id, cdm::kSessionError,
kSessionAlreadyExistsError);
return false;
}
CdmResponseType result = cdm_engine_.OpenSession(
"com.widevine.alpha", &property_set_, &internal_session_id);
if (result != NO_ERROR) {
if (result == NEED_PROVISIONING) {
host_->OnSessionError(session_id, cdm::kNeedsDeviceCertificate,
kOpenSessionErrorBase | result);
} else {
host_->OnSessionError(session_id, cdm::kSessionError,
kOpenSessionErrorBase | result);
}
return false;
}
if (!cdm_engine_.AttachEventListener(internal_session_id, this)) {
cdm_engine_.CloseSession(internal_session_id);
host_->OnSessionError(session_id, cdm::kSessionError,
kAttachEventListenerError);
return false;
}
session_map_[session_id] =
InternalSession(internal_session_id, InternalSession::kDecrypt);
return true;
}
int64_t WvContentDecryptionModule_4::GetCurrentTimeInSeconds() {
return host_->GetCurrentWallTimeInSeconds();
}
void WvContentDecryptionModule_4::OnEvent(const CdmSessionId& session_id,
CdmEventType cdm_event) {
bool found = false;
std::map<uint32_t, InternalSession>::iterator session_pair_iterator;
uint32_t external_session_id = 0;
for (session_pair_iterator = session_map_.begin();
session_pair_iterator != session_map_.end(); ++session_pair_iterator) {
if (session_pair_iterator->second.webid() == session_id) {
found = true;
external_session_id = session_pair_iterator->first;
break;
}
}
if (!found) {
LOGE("Unmapped Session Event on Session %s", session_id.c_str());
host_->OnSessionError(0, cdm::kSessionError, kSessionNotFoundError);
return;
}
switch (cdm_event) {
case LICENSE_RENEWAL_NEEDED_EVENT: {
wvcdm::CdmKeyMessage cdm_message;
std::string server_url;
CdmResponseType result = cdm_engine_.GenerateRenewalRequest(
session_id, &cdm_message, &server_url);
if (result == wvcdm::KEY_MESSAGE) {
LOGI("Renewal created");
host_->OnSessionMessage(external_session_id, cdm_message.c_str(),
cdm_message.length(), server_url.c_str(),
server_url.length());
} else {
LOGD("Error on Generating a Renewal Request!");
host_->OnSessionError(external_session_id, cdm::kSessionError,
kGenerateRenewalRequestErrorBase | result);
}
break;
}
case LICENSE_EXPIRED_EVENT: {
LOGD("License Expired Event");
host_->OnSessionError(external_session_id, cdm::kSessionError,
kLicenseExpiredNotification);
break;
}
}
}
} // namespace wvcdm