Index: content/renderer/pepper/content_decryptor_delegate.cc |
diff --git a/content/renderer/pepper/content_decryptor_delegate.cc b/content/renderer/pepper/content_decryptor_delegate.cc |
index a36cf6f353965d041c421e3f538bd81c708c6b0b..d997ffcb4c9c3c7f27f22008026a9a4ddaa89e0d 100644 |
--- a/content/renderer/pepper/content_decryptor_delegate.cc |
+++ b/content/renderer/pepper/content_decryptor_delegate.cc |
@@ -12,6 +12,7 @@ |
#include "media/base/audio_buffer.h" |
#include "media/base/audio_decoder_config.h" |
#include "media/base/bind_to_current_loop.h" |
+#include "media/base/cdm_promise.h" |
#include "media/base/channel_layout.h" |
#include "media/base/data_buffer.h" |
#include "media/base/decoder_buffer.h" |
@@ -245,6 +246,65 @@ media::SampleFormat PpDecryptedSampleFormatToMediaSampleFormat( |
} |
} |
+PP_SessionType MediaSessionTypeToPpSessionType( |
+ media::MediaKeys::SessionType session_type) { |
+ switch (session_type) { |
+ case media::MediaKeys::SESSION_TYPE_TEMPORARY: |
+ return PP_SESSIONTYPE_TEMPORARY; |
+ case media::MediaKeys::SESSION_TYPE_PERSISTENT: |
+ return PP_SESSIONTYPE_PERSISTENT; |
+ default: |
+ NOTREACHED(); |
+ return PP_SESSIONTYPE_TEMPORARY; |
+ } |
+} |
+ |
+media::MediaKeys::MediaKeysException PpExceptionTypeToMediaException( |
+ PP_ExceptionCodeType exception_code) { |
+ switch (exception_code) { |
+ case PP_EXCEPTIONCODETYPE_NOMODIFICATIONALLOWEDERROR: |
+ return media::MediaKeys:: |
+ MEDIA_KEYS_EXCEPTION_NO_MODIFICATION_ALLOWED_ERROR; |
+ case PP_EXCEPTIONCODETYPE_NOTFOUNDERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_NOT_FOUND_ERROR; |
+ case PP_EXCEPTIONCODETYPE_NOTSUPPORTEDERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_NOT_SUPPORTED_ERROR; |
+ case PP_EXCEPTIONCODETYPE_INVALIDSTATEERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_INVALID_STATE_ERROR; |
+ case PP_EXCEPTIONCODETYPE_SYNTAXERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_SYNTAX_ERROR; |
+ case PP_EXCEPTIONCODETYPE_INVALIDMODIFICATIONERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_INVALID_MODIFICATION_ERROR; |
+ case PP_EXCEPTIONCODETYPE_INVALIDACCESSERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_INVALID_ACCESS_ERROR; |
+ case PP_EXCEPTIONCODETYPE_SECURITYERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_SECURITY_ERROR; |
+ case PP_EXCEPTIONCODETYPE_ABORTERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_ABORT_ERROR; |
+ case PP_EXCEPTIONCODETYPE_QUOTAEXCEEDEDERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_QUOTA_EXCEEDED_ERROR; |
+ case PP_EXCEPTIONCODETYPE_TIMEOUTERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_TIMEOUT_ERROR; |
+ case PP_EXCEPTIONCODETYPE_UNKNOWNERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_UNKNOWN_ERROR; |
+ case PP_EXCEPTIONCODETYPE_DATAERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_DATA_ERROR; |
+ case PP_EXCEPTIONCODETYPE_VERSIONERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_VERSION_ERROR; |
+ case PP_EXCEPTIONCODETYPE_NOTREADABLEERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_NOT_READABLE_ERROR; |
+ case PP_EXCEPTIONCODETYPE_OPERATIONERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_OPERATION_ERROR; |
+ case PP_EXCEPTIONCODETYPE_CLIENTERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_CLIENT_ERROR; |
+ case PP_EXCEPTIONCODETYPE_OUTPUTERROR: |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_OUTPUT_ERROR; |
+ default: |
+ NOTREACHED(); |
+ return media::MediaKeys::MEDIA_KEYS_EXCEPTION_UNKNOWN_ERROR; |
+ } |
+} |
+ |
} // namespace |
ContentDecryptorDelegate::ContentDecryptorDelegate( |
@@ -256,6 +316,7 @@ ContentDecryptorDelegate::ContentDecryptorDelegate( |
audio_samples_per_second_(0), |
audio_channel_count_(0), |
audio_channel_layout_(media::CHANNEL_LAYOUT_NONE), |
+ next_promise_id_(0), |
weak_ptr_factory_(this) { |
weak_this_ = weak_ptr_factory_.GetWeakPtr(); |
} |
@@ -266,7 +327,6 @@ ContentDecryptorDelegate::~ContentDecryptorDelegate() { |
void ContentDecryptorDelegate::Initialize( |
const std::string& key_system, |
- const media::SessionCreatedCB& session_created_cb, |
const media::SessionMessageCB& session_message_cb, |
const media::SessionReadyCB& session_ready_cb, |
const media::SessionClosedCB& session_closed_cb, |
@@ -276,7 +336,6 @@ void ContentDecryptorDelegate::Initialize( |
DCHECK(key_system_.empty()); |
key_system_ = key_system; |
- session_created_cb_ = session_created_cb; |
session_message_cb_ = session_message_cb; |
session_ready_cb_ = session_ready_cb; |
session_closed_cb_ = session_closed_cb; |
@@ -292,42 +351,54 @@ void ContentDecryptorDelegate::InstanceCrashed() { |
SatisfyAllPendingCallbacksOnError(); |
} |
-bool ContentDecryptorDelegate::CreateSession(uint32 session_id, |
- const std::string& content_type, |
- const uint8* init_data, |
- int init_data_length) { |
+void ContentDecryptorDelegate::CreateSession( |
+ const std::string& init_data_type, |
+ const uint8* init_data, |
+ int init_data_length, |
+ media::MediaKeys::SessionType session_type, |
+ scoped_ptr<media::CdmNewSessionPromise> promise) { |
+ uint32_t promise_id = SaveSessionPromise(promise.Pass()); |
PP_Var init_data_array = |
PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( |
init_data_length, init_data); |
- |
plugin_decryption_interface_->CreateSession( |
pp_instance_, |
- session_id, |
- StringVar::StringToPPVar(content_type), |
- init_data_array); |
- return true; |
+ promise_id, |
+ StringVar::StringToPPVar(init_data_type), |
+ init_data_array, |
+ MediaSessionTypeToPpSessionType(session_type)); |
} |
-void ContentDecryptorDelegate::LoadSession(uint32 session_id, |
- const std::string& web_session_id) { |
+void ContentDecryptorDelegate::LoadSession( |
+ const std::string& web_session_id, |
+ scoped_ptr<media::CdmNewSessionPromise> promise) { |
+ uint32_t promise_id = SaveSessionPromise(promise.Pass()); |
plugin_decryption_interface_->LoadSession( |
- pp_instance_, session_id, StringVar::StringToPPVar(web_session_id)); |
+ pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id)); |
} |
-bool ContentDecryptorDelegate::UpdateSession(uint32 session_id, |
- const uint8* response, |
- int response_length) { |
+void ContentDecryptorDelegate::UpdateSession( |
+ const std::string& web_session_id, |
+ const uint8* response, |
+ int response_length, |
+ scoped_ptr<media::CdmChangeSessionPromise> promise) { |
+ uint32_t promise_id = SaveVoidPromise(promise.Pass()); |
PP_Var response_array = |
PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( |
response_length, response); |
plugin_decryption_interface_->UpdateSession( |
- pp_instance_, session_id, response_array); |
- return true; |
+ pp_instance_, |
+ promise_id, |
+ StringVar::StringToPPVar(web_session_id), |
+ response_array); |
} |
-bool ContentDecryptorDelegate::ReleaseSession(uint32 session_id) { |
- plugin_decryption_interface_->ReleaseSession(pp_instance_, session_id); |
- return true; |
+void ContentDecryptorDelegate::ReleaseSession( |
+ const std::string& web_session_id, |
+ scoped_ptr<media::CdmChangeSessionPromise> promise) { |
+ uint32_t promise_id = SaveVoidPromise(promise.Pass()); |
+ plugin_decryption_interface_->ReleaseSession( |
+ pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id)); |
} |
// TODO(xhwang): Remove duplication of code in Decrypt(), |
@@ -573,68 +644,108 @@ bool ContentDecryptorDelegate::DecryptAndDecodeVideo( |
return true; |
} |
-void ContentDecryptorDelegate::OnSessionCreated(uint32 session_id, |
- PP_Var web_session_id_var) { |
- if (session_created_cb_.is_null()) |
- return; |
+void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id) { |
+ scoped_ptr<media::CdmChangeSessionPromise> promise = |
+ RetrieveVoidPromise(promise_id); |
+ promise->resolve(); |
+} |
- StringVar* session_id_string = StringVar::FromPPVar(web_session_id_var); |
+void ContentDecryptorDelegate::OnPromiseResolvedWithSession( |
+ uint32 promise_id, |
+ PP_Var web_session_id_var) { |
+ scoped_ptr<media::CdmNewSessionPromise> promise = |
+ RetrieveSessionPromise(promise_id); |
- if (!session_id_string) { |
- OnSessionError(session_id, media::MediaKeys::kUnknownError, 0); |
- return; |
- } |
+ StringVar* web_session_id = StringVar::FromPPVar(web_session_id_var); |
+ DCHECK(web_session_id); |
- session_created_cb_.Run(session_id, session_id_string->value()); |
+ promise->resolve(web_session_id->value()); |
} |
-void ContentDecryptorDelegate::OnSessionMessage(uint32 session_id, |
+void ContentDecryptorDelegate::OnPromiseRejected( |
+ uint32 promise_id, |
+ PP_ExceptionCodeType exception_code, |
+ uint32 system_code, |
+ PP_Var error_description_var) { |
+ StringVar* error_description = StringVar::FromPPVar(error_description_var); |
+ DCHECK(error_description); |
+ |
+ scoped_ptr<media::CdmNewSessionPromise> promise = |
+ RetrieveSessionPromise(promise_id); |
+ if (promise) { |
+ promise->reject(PpExceptionTypeToMediaException(exception_code), |
+ system_code, |
+ error_description->value()); |
+ } else { |
+ scoped_ptr<media::CdmChangeSessionPromise> promise = |
+ RetrieveVoidPromise(promise_id); |
+ promise->reject(PpExceptionTypeToMediaException(exception_code), |
+ system_code, |
+ error_description->value()); |
+ } |
+} |
+ |
+void ContentDecryptorDelegate::OnSessionMessage(PP_Var web_session_id_var, |
PP_Var message_var, |
- PP_Var default_url_var) { |
+ PP_Var destination_url_var) { |
if (session_message_cb_.is_null()) |
return; |
- ArrayBufferVar* message_array_buffer = ArrayBufferVar::FromPPVar(message_var); |
+ StringVar* web_session_id = StringVar::FromPPVar(web_session_id_var); |
+ DCHECK(web_session_id); |
+ ArrayBufferVar* message_array_buffer = ArrayBufferVar::FromPPVar(message_var); |
std::vector<uint8> message; |
if (message_array_buffer) { |
const uint8* data = static_cast<const uint8*>(message_array_buffer->Map()); |
message.assign(data, data + message_array_buffer->ByteLength()); |
} |
- StringVar* default_url_string = StringVar::FromPPVar(default_url_var); |
- |
- if (!default_url_string) { |
- OnSessionError(session_id, media::MediaKeys::kUnknownError, 0); |
- return; |
- } |
+ StringVar* destination_url_string = StringVar::FromPPVar(destination_url_var); |
+ DCHECK(destination_url_string); |
- session_message_cb_.Run(session_id, message, default_url_string->value()); |
+ session_message_cb_.Run( |
+ web_session_id->value(), message, destination_url_string->value()); |
} |
-void ContentDecryptorDelegate::OnSessionReady(uint32 session_id) { |
+void ContentDecryptorDelegate::OnSessionReady(PP_Var web_session_id_var) { |
if (session_ready_cb_.is_null()) |
return; |
- session_ready_cb_.Run(session_id); |
+ StringVar* web_session_id = StringVar::FromPPVar(web_session_id_var); |
+ DCHECK(web_session_id); |
+ |
+ session_ready_cb_.Run(web_session_id->value()); |
} |
-void ContentDecryptorDelegate::OnSessionClosed(uint32 session_id) { |
+void ContentDecryptorDelegate::OnSessionClosed(PP_Var web_session_id_var) { |
if (session_closed_cb_.is_null()) |
return; |
- session_closed_cb_.Run(session_id); |
+ StringVar* web_session_id = StringVar::FromPPVar(web_session_id_var); |
+ DCHECK(web_session_id); |
+ |
+ session_closed_cb_.Run(web_session_id->value()); |
} |
-void ContentDecryptorDelegate::OnSessionError(uint32 session_id, |
- int32_t media_error, |
- uint32_t system_code) { |
+void ContentDecryptorDelegate::OnSessionError( |
+ PP_Var web_session_id_var, |
+ PP_ExceptionCodeType exception_code, |
+ uint32 system_code, |
+ PP_Var error_description_var) { |
if (session_error_cb_.is_null()) |
return; |
- session_error_cb_.Run(session_id, |
- static_cast<media::MediaKeys::KeyError>(media_error), |
- system_code); |
+ StringVar* web_session_id = StringVar::FromPPVar(web_session_id_var); |
+ DCHECK(web_session_id); |
+ |
+ StringVar* error_description = StringVar::FromPPVar(error_description_var); |
+ DCHECK(error_description); |
+ |
+ session_error_cb_.Run(web_session_id->value(), |
+ PpExceptionTypeToMediaException(exception_code), |
+ system_code, |
+ error_description->value()); |
} |
void ContentDecryptorDelegate::DecoderInitializeDone( |
@@ -1060,6 +1171,47 @@ void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() { |
if (!video_decode_cb_.is_null()) |
video_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL); |
+ |
+ // TODO(jrummell): Reject all outstanding promises. Currently some tests |
+ // (ECKEncryptedMediaTest.CDMExpectedCrash and CDMCrashDuringDecode) |
+ // trigger a crash in the CDM, and don't handle the response to the pending |
+ // request. Once blink:: uses promises, this will be required. |
+} |
+ |
+uint32_t ContentDecryptorDelegate::SaveVoidPromise( |
+ scoped_ptr<media::CdmChangeSessionPromise> promise) { |
+ uint32_t promise_id = ++next_promise_id_; |
+ void_promises_.insert(std::make_pair(promise_id, promise.release())); |
+ return promise_id; |
+} |
+ |
+scoped_ptr<media::CdmChangeSessionPromise> |
+ContentDecryptorDelegate::RetrieveVoidPromise(uint32_t promise_id) { |
+ std::map<uint32_t, media::CdmChangeSessionPromise*>::iterator it = |
+ void_promises_.find(promise_id); |
+ if (it == void_promises_.end()) |
+ return scoped_ptr<media::CdmChangeSessionPromise>(); |
+ scoped_ptr<media::CdmChangeSessionPromise> result(it->second); |
+ void_promises_.erase(it); |
+ return result.Pass(); |
+} |
+ |
+uint32_t ContentDecryptorDelegate::SaveSessionPromise( |
+ scoped_ptr<media::CdmNewSessionPromise> promise) { |
+ uint32_t promise_id = ++next_promise_id_; |
+ session_promises_.insert(std::make_pair(promise_id, promise.release())); |
+ return promise_id; |
+} |
+ |
+scoped_ptr<media::CdmNewSessionPromise> |
+ContentDecryptorDelegate::RetrieveSessionPromise(uint32_t promise_id) { |
+ std::map<uint32_t, media::CdmNewSessionPromise*>::iterator it = |
+ session_promises_.find(promise_id); |
+ if (it == session_promises_.end()) |
+ return scoped_ptr<media::CdmNewSessionPromise>(); |
+ scoped_ptr<media::CdmNewSessionPromise> result(it->second); |
+ session_promises_.erase(it); |
+ return result.Pass(); |
} |
} // namespace content |