...when playing clear parts of encrypted content. Change-Id: I5fb027d22212f07b43deced2da77c98cb3800e7f
214 lines
6.0 KiB
C++
214 lines
6.0 KiB
C++
// Copyright 2012 Google Inc. All Rights Reserved.
|
|
// Author: jfore@google.com (Jeff Fore), rkuroiwa@google.com (Rintaro Kuroiwa)
|
|
|
|
#include "cdm_session.h"
|
|
|
|
#include <iostream>
|
|
|
|
#include "clock.h"
|
|
#include "crypto_engine.h"
|
|
#include "log.h"
|
|
#include "properties.h"
|
|
#include "string_conversions.h"
|
|
#include "wv_cdm_constants.h"
|
|
|
|
namespace wvcdm {
|
|
|
|
typedef std::set<WvCdmEventListener*>::iterator CdmEventListenerIter;
|
|
|
|
bool CdmSession::Init() {
|
|
CryptoEngine* crypto_engine = CryptoEngine::GetInstance();
|
|
if (!crypto_engine) {
|
|
LOGE("CdmSession::Init failed to get CryptoEngine instance.");
|
|
return false;
|
|
}
|
|
|
|
crypto_session_ = crypto_engine->CreateSession(session_id_);
|
|
if (!crypto_session_) {
|
|
return false;
|
|
}
|
|
|
|
std::string token;
|
|
if (!crypto_engine->GetToken(&token)) return false;
|
|
|
|
if (!Properties::GetInstance()->GetProperty(
|
|
kPropertyKeyRequireExplicitRenewRequest,
|
|
require_explicit_renew_request_)) {
|
|
LOGE("CdmSession::Init: Unable to access property - require explicit renew");
|
|
}
|
|
else {
|
|
properties_valid_ = true;
|
|
}
|
|
|
|
return license_parser_.Init(token, crypto_session_, &policy_engine_);
|
|
}
|
|
|
|
bool CdmSession::DestroySession() {
|
|
if (crypto_session_) {
|
|
delete crypto_session_;
|
|
crypto_session_ = NULL;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CdmSession::VerifySession(const CdmKeySystem& key_system,
|
|
const CdmInitData& 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 CdmInitData& init_data,
|
|
CdmKeyMessage* key_request) {
|
|
if (!properties_valid_) {
|
|
LOGW("CdmSession::GenerateKeyRequest: Unable to access properties");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
if (!crypto_session_) {
|
|
LOGW("CdmSession::GenerateKeyRequest: Invalid crypto session");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
if (!crypto_session_->IsOpen()) {
|
|
LOGW("CdmSession::GenerateKeyRequest: Crypto session not open");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
if (license_received_) {
|
|
return require_explicit_renew_request_ ?
|
|
UNKNOWN_ERROR : GenerateRenewalRequest(key_request);
|
|
}
|
|
else {
|
|
if(!license_parser_.PrepareKeyRequest(init_data, key_request)) {
|
|
return KEY_ERROR;
|
|
} else {
|
|
return KEY_MESSAGE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// AddKey() - Accept license response and extract key info.
|
|
CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response) {
|
|
if (!crypto_session_) {
|
|
LOGW("CdmSession::AddKey: Invalid crypto session");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
if (!crypto_session_->IsOpen()) {
|
|
LOGW("CdmSession::AddKey: Crypto session not open");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
if (license_received_) {
|
|
return require_explicit_renew_request_ ?
|
|
UNKNOWN_ERROR : RenewKey(key_response);
|
|
}
|
|
else {
|
|
if (!license_parser_.HandleKeyResponse(key_response)) {
|
|
return KEY_ERROR;
|
|
} else {
|
|
license_received_ = true;
|
|
return KEY_ADDED;
|
|
}
|
|
}
|
|
}
|
|
|
|
CdmResponseType CdmSession::QueryKeyStatus(CdmQueryMap* key_info) {
|
|
return policy_engine_.Query(key_info);
|
|
}
|
|
|
|
// CancelKeyRequest() - Cancel session.
|
|
CdmResponseType CdmSession::CancelKeyRequest() {
|
|
// TODO(gmorgan): cancel and clean up session
|
|
crypto_session_->Close();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
// Decrypt() - Accept encrypted buffer and return decrypted data.
|
|
CdmResponseType CdmSession::Decrypt(bool is_encrypted,
|
|
const KeyId& key_id,
|
|
const uint8_t* encrypt_buffer,
|
|
size_t encrypt_length,
|
|
const std::vector<uint8_t>& iv,
|
|
size_t block_offset,
|
|
void* decrypt_buffer,
|
|
bool is_video) {
|
|
if (!crypto_session_ || !crypto_session_->IsOpen())
|
|
return UNKNOWN_ERROR;
|
|
|
|
// Check if key needs to be selected
|
|
if (is_encrypted) {
|
|
if (key_id_.compare(key_id) != 0) {
|
|
if (crypto_session_->SelectKey(key_id)) {
|
|
key_id_ = key_id;
|
|
}
|
|
else {
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
return crypto_session_->Decrypt(is_encrypted, encrypt_buffer, encrypt_length,
|
|
iv, block_offset, decrypt_buffer, is_video);
|
|
}
|
|
|
|
// License renewal
|
|
// GenerateRenewalRequest() - Construct valid renewal request for the current
|
|
// session keys.
|
|
CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request) {
|
|
if(!license_parser_.PrepareKeyRenewalRequest(key_request)) {
|
|
return KEY_ERROR;
|
|
} else {
|
|
return KEY_MESSAGE;
|
|
}
|
|
}
|
|
|
|
// RenewKey() - Accept renewal response and update key info.
|
|
CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) {
|
|
if (!license_parser_.HandleKeyRenewalResponse(key_response)) {
|
|
return KEY_ERROR;
|
|
} else {
|
|
return KEY_ADDED;
|
|
}
|
|
}
|
|
|
|
bool CdmSession::IsKeyValid(const KeyId& key_id) {
|
|
// TODO(gmorgan): lookup key and determine if valid.
|
|
// return (session_keys_.find(key_id) != session_keys_.end());
|
|
return true;
|
|
}
|
|
|
|
CdmSessionId CdmSession::GenerateSessionId() {
|
|
static const std::string kSessionPrefix("Session");
|
|
static int session_num = 1;
|
|
// TODO(rkuroiwa): Want this to be unique. Probably doing Hash(time+init_data)
|
|
// to get something that is reasonably unique.
|
|
return kSessionPrefix + IntToString(++session_num);
|
|
}
|
|
|
|
bool CdmSession::AttachEventListener(WvCdmEventListener* listener) {
|
|
std::pair<CdmEventListenerIter, bool> result = listeners_.insert(listener);
|
|
return result.second;
|
|
}
|
|
|
|
bool CdmSession::DetachEventListener(WvCdmEventListener* listener) {
|
|
return (listeners_.erase(listener) == 1);
|
|
}
|
|
|
|
void CdmSession::OnTimerEvent() {
|
|
bool event_occurred = false;
|
|
CdmEventType event;
|
|
|
|
policy_engine_.OnTimerEvent(event_occurred, event);
|
|
|
|
if (event_occurred) {
|
|
for (CdmEventListenerIter iter = listeners_.begin();
|
|
iter != listeners_.end(); ++iter) {
|
|
(*iter)->onEvent(session_id(), event);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace wvcdm
|