Skip to content

Commit

Permalink
Update Pepper interface for EME
Browse files Browse the repository at this point in the history
To support CDM_6, make the following changes:
- add SetServerCertificate
- add GetUsableKeyIds
- rename ReleaseSession to CloseSession
- add RemoveSession
- add SessionKeysChange event
- add SessionExpirationChange event

Includes changes to cdm_adapter for the new functionality. Changes to
use these new interfaces in blink in a future CL.

BUG=358271
TEST=existing EME tests still pass + manual testing

Review URL: https://codereview.chromium.org/496143002

Cr-Commit-Position: refs/heads/master@{#293672}
  • Loading branch information
jrummell-chromium authored and Commit bot committed Sep 8, 2014
1 parent cd7694a commit 1e9a7b1
Show file tree
Hide file tree
Showing 25 changed files with 1,053 additions and 97 deletions.
2 changes: 1 addition & 1 deletion content/renderer/media/crypto/ppapi_decryptor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ void PpapiDecryptor::ReleaseSession(
return;
}

CdmDelegate()->ReleaseSession(web_session_id, promise.Pass());
CdmDelegate()->CloseSession(web_session_id, promise.Pass());
}

media::Decryptor* PpapiDecryptor::GetDecryptor() {
Expand Down
112 changes: 110 additions & 2 deletions content/renderer/pepper/content_decryptor_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
#include "media/base/data_buffer.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
#include "media/base/limits.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h"
#include "media/base/video_util.h"
#include "ppapi/shared_impl/array_var.h"
#include "ppapi/shared_impl/scoped_pp_resource.h"
#include "ppapi/shared_impl/var.h"
#include "ppapi/shared_impl/var_tracker.h"
Expand All @@ -29,10 +31,12 @@

using media::CdmPromise;
using media::Decryptor;
using media::KeyIdsPromise;
using media::MediaKeys;
using media::NewSessionCdmPromise;
using media::SimpleCdmPromise;
using ppapi::ArrayBufferVar;
using ppapi::ArrayVar;
using ppapi::PpapiGlobals;
using ppapi::ScopedPPResource;
using ppapi::StringVar;
Expand Down Expand Up @@ -330,6 +334,26 @@ void ContentDecryptorDelegate::InstanceCrashed() {
SatisfyAllPendingCallbacksOnError();
}

void ContentDecryptorDelegate::SetServerCertificate(
const uint8_t* certificate,
uint32_t certificate_length,
scoped_ptr<media::SimpleCdmPromise> promise) {
if (!certificate ||
certificate_length < media::limits::kMinCertificateLength ||
certificate_length > media::limits::kMaxCertificateLength) {
promise->reject(
media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect certificate.");
return;
}

uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
PP_Var certificate_array =
PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
certificate_length, certificate);
plugin_decryption_interface_->SetServerCertificate(
pp_instance_, promise_id, certificate_array);
}

void ContentDecryptorDelegate::CreateSession(
const std::string& init_data_type,
const uint8* init_data,
Expand Down Expand Up @@ -372,11 +396,45 @@ void ContentDecryptorDelegate::UpdateSession(
response_array);
}

void ContentDecryptorDelegate::ReleaseSession(
void ContentDecryptorDelegate::CloseSession(
const std::string& web_session_id,
scoped_ptr<SimpleCdmPromise> promise) {
if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) {
promise->reject(
media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
return;
}

uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
plugin_decryption_interface_->CloseSession(
pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
}

void ContentDecryptorDelegate::RemoveSession(
const std::string& web_session_id,
scoped_ptr<SimpleCdmPromise> promise) {
if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) {
promise->reject(
media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
return;
}

uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
plugin_decryption_interface_->RemoveSession(
pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
}

void ContentDecryptorDelegate::GetUsableKeyIds(
const std::string& web_session_id,
scoped_ptr<media::KeyIdsPromise> promise) {
if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) {
promise->reject(
media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
return;
}

uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
plugin_decryption_interface_->ReleaseSession(
plugin_decryption_interface_->GetUsableKeyIds(
pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
}

Expand Down Expand Up @@ -667,6 +725,43 @@ void ContentDecryptorDelegate::OnPromiseResolvedWithSession(
session_promise->resolve(web_session_id_string->value());
}

void ContentDecryptorDelegate::OnPromiseResolvedWithKeyIds(
uint32 promise_id,
PP_Var key_ids_array) {
scoped_ptr<CdmPromise> promise = TakePromise(promise_id);

ArrayVar* key_ids = ArrayVar::FromPPVar(key_ids_array);
DCHECK(key_ids && key_ids->GetLength() <= media::limits::kMaxKeyIds);
media::KeyIdsVector key_ids_vector;
if (key_ids && key_ids->GetLength() <= media::limits::kMaxKeyIds) {
for (size_t i = 0; i < key_ids->GetLength(); ++i) {
ArrayBufferVar* array_buffer = ArrayBufferVar::FromPPVar(key_ids->Get(i));

if (!array_buffer ||
array_buffer->ByteLength() < media::limits::kMinKeyIdLength ||
array_buffer->ByteLength() > media::limits::kMaxKeyIdLength) {
NOTREACHED();
continue;
}

std::vector<uint8> key_id;
const uint8* data = static_cast<const uint8*>(array_buffer->Map());
key_id.assign(data, data + array_buffer->ByteLength());
key_ids_vector.push_back(key_id);
}
}

if (!promise ||
promise->GetResolveParameterType() !=
media::CdmPromise::KEY_IDS_VECTOR_TYPE) {
NOTREACHED();
return;
}

KeyIdsPromise* key_ids_promise(static_cast<KeyIdsPromise*>(promise.get()));
key_ids_promise->resolve(key_ids_vector);
}

void ContentDecryptorDelegate::OnPromiseRejected(
uint32 promise_id,
PP_CdmExceptionCode exception_code,
Expand All @@ -676,6 +771,7 @@ void ContentDecryptorDelegate::OnPromiseRejected(
DCHECK(error_description_string);

scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
DCHECK(promise);
if (promise) {
promise->reject(PpExceptionTypeToMediaException(exception_code),
system_code,
Expand Down Expand Up @@ -713,6 +809,18 @@ void ContentDecryptorDelegate::OnSessionMessage(PP_Var web_session_id,
web_session_id_string->value(), message_vector, verified_gurl);
}

void ContentDecryptorDelegate::OnSessionKeysChange(
PP_Var web_session_id,
PP_Bool has_additional_usable_key) {
// TODO(jrummell): Pass this event on.
}

void ContentDecryptorDelegate::OnSessionExpirationChange(
PP_Var web_session_id,
PP_Time new_expiry_time) {
// TODO(jrummell): Pass this event on.
}

void ContentDecryptorDelegate::OnSessionReady(PP_Var web_session_id) {
if (session_ready_cb_.is_null())
return;
Expand Down
17 changes: 15 additions & 2 deletions content/renderer/pepper/content_decryptor_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "media/base/decryptor.h"
#include "media/base/media_keys.h"
#include "media/base/sample_format.h"
#include "ppapi/c/pp_time.h"
#include "ppapi/c/private/pp_content_decryptor.h"
#include "ppapi/c/private/ppp_content_decryptor_private.h"
#include "ui/gfx/size.h"
Expand Down Expand Up @@ -55,6 +56,9 @@ class ContentDecryptorDelegate {
void InstanceCrashed();

// Provides access to PPP_ContentDecryptor_Private.
void SetServerCertificate(const uint8_t* certificate,
uint32_t certificate_length,
scoped_ptr<media::SimpleCdmPromise> promise);
void CreateSession(const std::string& init_data_type,
const uint8* init_data,
int init_data_length,
Expand All @@ -66,8 +70,12 @@ class ContentDecryptorDelegate {
const uint8* response,
int response_length,
scoped_ptr<media::SimpleCdmPromise> promise);
void ReleaseSession(const std::string& web_session_id,
scoped_ptr<media::SimpleCdmPromise> promise);
void CloseSession(const std::string& web_session_id,
scoped_ptr<media::SimpleCdmPromise> promise);
void RemoveSession(const std::string& web_session_id,
scoped_ptr<media::SimpleCdmPromise> promise);
void GetUsableKeyIds(const std::string& web_session_id,
scoped_ptr<media::KeyIdsPromise> promise);
bool Decrypt(media::Decryptor::StreamType stream_type,
const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
const media::Decryptor::DecryptCB& decrypt_cb);
Expand All @@ -93,13 +101,18 @@ class ContentDecryptorDelegate {
// PPB_ContentDecryptor_Private dispatching methods.
void OnPromiseResolved(uint32 promise_id);
void OnPromiseResolvedWithSession(uint32 promise_id, PP_Var web_session_id);
void OnPromiseResolvedWithKeyIds(uint32 promise_id, PP_Var key_ids_array);
void OnPromiseRejected(uint32 promise_id,
PP_CdmExceptionCode exception_code,
uint32 system_code,
PP_Var error_description);
void OnSessionMessage(PP_Var web_session_id,
PP_Var message,
PP_Var destination_url);
void OnSessionKeysChange(PP_Var web_session_id,
PP_Bool has_additional_usable_key);
void OnSessionExpirationChange(PP_Var web_session_id,
PP_Time new_expiry_time);
void OnSessionReady(PP_Var web_session_id);
void OnSessionClosed(PP_Var web_session_id);
void OnSessionError(PP_Var web_session_id,
Expand Down
23 changes: 23 additions & 0 deletions content/renderer/pepper/pepper_plugin_instance_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2485,6 +2485,13 @@ void PepperPluginInstanceImpl::PromiseResolvedWithSession(
web_session_id_var);
}

void PepperPluginInstanceImpl::PromiseResolvedWithKeyIds(PP_Instance instance,
uint32 promise_id,
PP_Var key_ids_var) {
content_decryptor_delegate_->OnPromiseResolvedWithKeyIds(promise_id,
key_ids_var);
}

void PepperPluginInstanceImpl::PromiseRejected(
PP_Instance instance,
uint32 promise_id,
Expand All @@ -2503,6 +2510,22 @@ void PepperPluginInstanceImpl::SessionMessage(PP_Instance instance,
web_session_id_var, message_var, destination_url_var);
}

void PepperPluginInstanceImpl::SessionKeysChange(
PP_Instance instance,
PP_Var web_session_id_var,
PP_Bool has_additional_usable_key) {
content_decryptor_delegate_->OnSessionKeysChange(web_session_id_var,
has_additional_usable_key);
}

void PepperPluginInstanceImpl::SessionExpirationChange(
PP_Instance instance,
PP_Var web_session_id_var,
PP_Time new_expiry_time) {
content_decryptor_delegate_->OnSessionExpirationChange(web_session_id_var,
new_expiry_time);
}

void PepperPluginInstanceImpl::SessionReady(PP_Instance instance,
PP_Var web_session_id_var) {
content_decryptor_delegate_->OnSessionReady(web_session_id_var);
Expand Down
9 changes: 9 additions & 0 deletions content/renderer/pepper/pepper_plugin_instance_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,9 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
virtual void PromiseResolvedWithSession(PP_Instance instance,
uint32 promise_id,
PP_Var web_session_id_var) OVERRIDE;
virtual void PromiseResolvedWithKeyIds(PP_Instance instance,
uint32 promise_id,
PP_Var key_ids_var) OVERRIDE;
virtual void PromiseRejected(PP_Instance instance,
uint32 promise_id,
PP_CdmExceptionCode exception_code,
Expand All @@ -480,6 +483,12 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
PP_Var web_session_id_var,
PP_Var message_var,
PP_Var destination_url_var) OVERRIDE;
virtual void SessionKeysChange(PP_Instance instance,
PP_Var web_session_id_var,
PP_Bool has_additional_usable_key) OVERRIDE;
virtual void SessionExpirationChange(PP_Instance instance,
PP_Var web_session_id_var,
PP_Time new_expiry_time) OVERRIDE;
virtual void SessionReady(PP_Instance instance,
PP_Var web_session_id_var) OVERRIDE;
virtual void SessionClosed(PP_Instance instance,
Expand Down
10 changes: 10 additions & 0 deletions media/base/limits.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ enum {

// This limit is used by ParamTraits<VideoCaptureParams>.
kMaxFramesPerSecond = 1000,

// Maximum lengths for various EME API parameters. These are checks to
// prevent unnecessarily large parameters from being passed around, and the
// lengths are somewhat arbitrary as the EME spec doesn't specify any limits.
kMinCertificateLength = 128,
kMaxCertificateLength = 16 * 1024,
kMaxWebSessionIdLength = 512,
kMinKeyIdLength = 1,
kMaxKeyIdLength = 512,
kMaxKeyIds = 128,
};

} // namespace limits
Expand Down
48 changes: 40 additions & 8 deletions media/cdm/ppapi/cdm_adapter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "media/cdm/ppapi/cdm_adapter.h"

#include "media/base/limits.h"
#include "media/cdm/ppapi/cdm_file_io_impl.h"
#include "media/cdm/ppapi/cdm_helpers.h"
#include "media/cdm/ppapi/cdm_logging.h"
Expand Down Expand Up @@ -323,6 +324,38 @@ void CdmAdapter::Initialize(const std::string& key_system) {
key_system_ = key_system;
}

void CdmAdapter::SetServerCertificate(uint32_t promise_id,
pp::VarArrayBuffer server_certificate) {
const uint8_t* server_certificate_ptr =
static_cast<const uint8_t*>(server_certificate.Map());
const uint32_t server_certificate_size = server_certificate.ByteLength();

if (!server_certificate_ptr ||
server_certificate_size < media::limits::kMinCertificateLength ||
server_certificate_size > media::limits::kMinCertificateLength) {
RejectPromise(
promise_id, cdm::kInvalidAccessError, 0, "Incorrect certificate.");
return;
}

// Initialize() doesn't report an error, so SetServerCertificate() can be
// called even if Initialize() failed.
// TODO(jrummell): Remove this code when prefixed EME gets removed.
if (!cdm_) {
RejectPromise(promise_id,
cdm::kInvalidStateError,
0,
"CDM has not been initialized.");
return;
}

if (!cdm_->SetServerCertificate(
promise_id, server_certificate_ptr, server_certificate_size)) {
// CDM_4 and CDM_5 don't support this method, so reject the promise.
RejectPromise(promise_id, cdm::kNotSupportedError, 0, "Not implemented.");
}
}

void CdmAdapter::CreateSession(uint32_t promise_id,
const std::string& init_data_type,
pp::VarArrayBuffer init_data,
Expand Down Expand Up @@ -392,8 +425,8 @@ void CdmAdapter::CloseSession(uint32_t promise_id,
}
}

void CdmAdapter::ReleaseSession(uint32_t promise_id,
const std::string& web_session_id) {
void CdmAdapter::RemoveSession(uint32_t promise_id,
const std::string& web_session_id) {
cdm_->RemoveSession(
promise_id, web_session_id.data(), web_session_id.length());
}
Expand Down Expand Up @@ -816,8 +849,7 @@ void CdmAdapter::SendPromiseResolvedWithUsableKeyIdsInternal(
uint32_t promise_id,
std::vector<std::vector<uint8> > key_ids) {
PP_DCHECK(result == PP_OK);
// TODO(jrummell): Implement this event in subsequent CL.
// (http://crbug.com/358271).
pp::ContentDecryptor_Private::PromiseResolvedWithKeyIds(promise_id, key_ids);
}

void CdmAdapter::SendPromiseRejectedInternal(int32_t result,
Expand Down Expand Up @@ -875,16 +907,16 @@ void CdmAdapter::SendSessionUsableKeysChangeInternal(
const std::string& web_session_id,
bool has_additional_usable_key) {
PP_DCHECK(result == PP_OK);
// TODO(jrummell): Implement this event in subsequent CL.
// (http://crbug.com/358271).
pp::ContentDecryptor_Private::SessionKeysChange(web_session_id,
has_additional_usable_key);
}

void CdmAdapter::SendExpirationChangeInternal(int32_t result,
const std::string& web_session_id,
cdm::Time new_expiry_time) {
PP_DCHECK(result == PP_OK);
// TODO(jrummell): Implement this event in subsequent CL.
// (http://crbug.com/358271).
pp::ContentDecryptor_Private::SessionExpirationChange(web_session_id,
new_expiry_time);
}

void CdmAdapter::DeliverBlock(int32_t result,
Expand Down
Loading

0 comments on commit 1e9a7b1

Please sign in to comment.