Chromium Code Reviews| 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..732b0a4368977faa888ad4b9510a739eeb12d134 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,62 @@ 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::Exception PpExceptionTypeToMediaException( |
| + PP_ExceptionCode exception_code) { |
| + switch (exception_code) { |
| + case PP_EXCEPTIONCODE_NOMODIFICATIONALLOWEDERROR: |
| + return media::MediaKeys::EXCEPTION_NO_MODIFICATION_ALLOWED_ERROR; |
| + case PP_EXCEPTIONCODE_NOTFOUNDERROR: |
| + return media::MediaKeys::EXCEPTION_NOT_FOUND_ERROR; |
| + case PP_EXCEPTIONCODE_NOTSUPPORTEDERROR: |
| + return media::MediaKeys::EXCEPTION_NOT_SUPPORTED_ERROR; |
| + case PP_EXCEPTIONCODE_INVALIDSTATEERROR: |
| + return media::MediaKeys::EXCEPTION_INVALID_STATE_ERROR; |
| + case PP_EXCEPTIONCODE_INVALIDMODIFICATIONERROR: |
| + return media::MediaKeys::EXCEPTION_INVALID_MODIFICATION_ERROR; |
| + case PP_EXCEPTIONCODE_INVALIDACCESSERROR: |
| + return media::MediaKeys::EXCEPTION_INVALID_ACCESS_ERROR; |
| + case PP_EXCEPTIONCODE_SECURITYERROR: |
| + return media::MediaKeys::EXCEPTION_SECURITY_ERROR; |
| + case PP_EXCEPTIONCODE_ABORTERROR: |
| + return media::MediaKeys::EXCEPTION_ABORT_ERROR; |
| + case PP_EXCEPTIONCODE_QUOTAEXCEEDEDERROR: |
| + return media::MediaKeys::EXCEPTION_QUOTA_EXCEEDED_ERROR; |
| + case PP_EXCEPTIONCODE_TIMEOUTERROR: |
| + return media::MediaKeys::EXCEPTION_TIMEOUT_ERROR; |
| + case PP_EXCEPTIONCODE_UNKNOWNERROR: |
| + return media::MediaKeys::EXCEPTION_UNKNOWN_ERROR; |
| + case PP_EXCEPTIONCODE_DATAERROR: |
| + return media::MediaKeys::EXCEPTION_DATA_ERROR; |
| + case PP_EXCEPTIONCODE_VERSIONERROR: |
| + return media::MediaKeys::EXCEPTION_VERSION_ERROR; |
| + case PP_EXCEPTIONCODE_NOTREADABLEERROR: |
| + return media::MediaKeys::EXCEPTION_NOT_READABLE_ERROR; |
| + case PP_EXCEPTIONCODE_OPERATIONERROR: |
| + return media::MediaKeys::EXCEPTION_OPERATION_ERROR; |
| + case PP_EXCEPTIONCODE_CLIENTERROR: |
| + return media::MediaKeys::EXCEPTION_CLIENT_ERROR; |
| + case PP_EXCEPTIONCODE_OUTPUTERROR: |
| + return media::MediaKeys::EXCEPTION_OUTPUT_ERROR; |
| + default: |
| + NOTREACHED(); |
| + return media::MediaKeys::EXCEPTION_UNKNOWN_ERROR; |
| + } |
| +} |
| + |
| } // namespace |
| ContentDecryptorDelegate::ContentDecryptorDelegate( |
| @@ -256,6 +313,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 +324,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 +333,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 +348,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::NewSessionCdmPromise> promise) { |
| + uint32_t promise_id = SaveNewSessionPromise(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::NewSessionCdmPromise> promise) { |
| + uint32_t promise_id = SaveNewSessionPromise(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::SimpleCdmPromise> promise) { |
| + uint32_t promise_id = SaveSimplePromise(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::SimpleCdmPromise> promise) { |
| + uint32_t promise_id = SaveSimplePromise(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 +641,105 @@ 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::SimpleCdmPromise> promise = TakeSimplePromise(promise_id); |
| + promise->resolve(); |
|
xhwang
2014/05/23 06:01:23
Is the CdmWrapper making sure the |promise_id| ret
jrummell
2014/05/29 00:54:40
Done.
|
| +} |
| - 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::NewSessionCdmPromise> promise = |
| + TakeNewSessionPromise(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_ExceptionCode exception_code, |
| + uint32 system_code, |
| + PP_Var error_description_var) { |
| + StringVar* error_description = StringVar::FromPPVar(error_description_var); |
| + DCHECK(error_description); |
| + |
| + scoped_ptr<media::NewSessionCdmPromise> promise = |
| + TakeNewSessionPromise(promise_id); |
| + if (promise) { |
| + promise->reject(PpExceptionTypeToMediaException(exception_code), |
| + system_code, |
| + error_description->value()); |
|
xhwang
2014/05/23 06:01:23
nit: return early here so that you don't need the
jrummell
2014/05/29 00:54:40
Done.
|
| + } else { |
| + scoped_ptr<media::SimpleCdmPromise> promise = TakeSimplePromise(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_ExceptionCode 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 +1165,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::SaveSimplePromise( |
| + scoped_ptr<media::SimpleCdmPromise> promise) { |
| + uint32_t promise_id = ++next_promise_id_; |
| + simple_promises_.insert(std::make_pair(promise_id, promise.release())); |
| + return promise_id; |
| +} |
| + |
| +scoped_ptr<media::SimpleCdmPromise> ContentDecryptorDelegate::TakeSimplePromise( |
| + uint32_t promise_id) { |
| + std::map<uint32_t, media::SimpleCdmPromise*>::iterator it = |
| + simple_promises_.find(promise_id); |
| + if (it == simple_promises_.end()) |
| + return scoped_ptr<media::SimpleCdmPromise>(); |
| + scoped_ptr<media::SimpleCdmPromise> result(it->second); |
| + simple_promises_.erase(it); |
| + return result.Pass(); |
| +} |
| + |
| +uint32_t ContentDecryptorDelegate::SaveNewSessionPromise( |
| + scoped_ptr<media::NewSessionCdmPromise> promise) { |
| + uint32_t promise_id = ++next_promise_id_; |
| + new_session_promises_.insert(std::make_pair(promise_id, promise.release())); |
| + return promise_id; |
| +} |
| + |
| +scoped_ptr<media::NewSessionCdmPromise> |
| +ContentDecryptorDelegate::TakeNewSessionPromise(uint32_t promise_id) { |
| + std::map<uint32_t, media::NewSessionCdmPromise*>::iterator it = |
| + new_session_promises_.find(promise_id); |
| + if (it == new_session_promises_.end()) |
| + return scoped_ptr<media::NewSessionCdmPromise>(); |
| + scoped_ptr<media::NewSessionCdmPromise> result(it->second); |
| + new_session_promises_.erase(it); |
| + return result.Pass(); |
|
xhwang
2014/05/23 06:01:23
There are some duplication here:
1, 2 maps instead
jrummell
2014/05/29 00:54:40
Done.
|
| } |
| } // namespace content |