diff options
Diffstat (limited to 'chromium/content/renderer/pepper/content_decryptor_delegate.cc')
-rw-r--r-- | chromium/content/renderer/pepper/content_decryptor_delegate.cc | 578 |
1 files changed, 343 insertions, 235 deletions
diff --git a/chromium/content/renderer/pepper/content_decryptor_delegate.cc b/chromium/content/renderer/pepper/content_decryptor_delegate.cc index 49790db2b7b..8692c1ce643 100644 --- a/chromium/content/renderer/pepper/content_decryptor_delegate.cc +++ b/chromium/content/renderer/pepper/content_decryptor_delegate.cc @@ -7,11 +7,12 @@ #include "base/callback_helpers.h" #include "base/debug/trace_event.h" #include "base/message_loop/message_loop_proxy.h" -#include "base/safe_numerics.h" +#include "base/numerics/safe_conversions.h" #include "content/renderer/pepper/ppb_buffer_impl.h" #include "media/base/audio_buffer.h" #include "media/base/audio_decoder_config.h" -#include "media/base/bind_to_loop.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" @@ -26,6 +27,11 @@ #include "ppapi/thunk/ppb_buffer_api.h" #include "ui/gfx/rect.h" +using media::CdmPromise; +using media::Decryptor; +using media::MediaKeys; +using media::NewSessionCdmPromise; +using media::SimpleCdmPromise; using ppapi::ArrayBufferVar; using ppapi::PpapiGlobals; using ppapi::ScopedPPResource; @@ -42,7 +48,8 @@ namespace { // reference-count of 0. If |data| is NULL, sets |*resource| to NULL. Returns // true upon success and false if any error happened. bool MakeBufferResource(PP_Instance instance, - const uint8* data, uint32_t size, + const uint8* data, + uint32_t size, scoped_refptr<PPB_Buffer_Impl>* resource) { TRACE_EVENT0("media", "ContentDecryptorDelegate - MakeBufferResource"); DCHECK(resource); @@ -105,7 +112,6 @@ static bool MakeEncryptedBlockInfo( const media::DecryptConfig* decrypt_config = encrypted_buffer->decrypt_config(); - block_info->data_offset = decrypt_config->data_offset(); if (!CopyStringToArray(decrypt_config->key_id(), block_info->key_id) || !CopyStringToArray(decrypt_config->iv(), block_info->iv)) @@ -145,6 +151,8 @@ PP_VideoCodec MediaVideoCodecToPpVideoCodec(media::VideoCodec codec) { return PP_VIDEOCODEC_VP8; case media::kCodecH264: return PP_VIDEOCODEC_H264; + case media::kCodecVP9: + return PP_VIDEOCODEC_VP9; default: return PP_VIDEOCODEC_UNKNOWN; } @@ -153,8 +161,11 @@ PP_VideoCodec MediaVideoCodecToPpVideoCodec(media::VideoCodec codec) { PP_VideoCodecProfile MediaVideoCodecProfileToPpVideoCodecProfile( media::VideoCodecProfile profile) { switch (profile) { + // TODO(xhwang): VP8 and VP9 do not have profiles. Clean up + // media::VideoCodecProfile and remove these two cases. case media::VP8PROFILE_MAIN: - return PP_VIDEOCODECPROFILE_VP8_MAIN; + case media::VP9PROFILE_MAIN: + return PP_VIDEOCODECPROFILE_NOT_NEEDED; case media::H264PROFILE_BASELINE: return PP_VIDEOCODECPROFILE_H264_BASELINE; case media::H264PROFILE_MAIN: @@ -186,31 +197,31 @@ PP_DecryptedFrameFormat MediaVideoFormatToPpDecryptedFrameFormat( } } -media::Decryptor::Status PpDecryptResultToMediaDecryptorStatus( +Decryptor::Status PpDecryptResultToMediaDecryptorStatus( PP_DecryptResult result) { switch (result) { case PP_DECRYPTRESULT_SUCCESS: - return media::Decryptor::kSuccess; + return Decryptor::kSuccess; case PP_DECRYPTRESULT_DECRYPT_NOKEY: - return media::Decryptor::kNoKey; + return Decryptor::kNoKey; case PP_DECRYPTRESULT_NEEDMOREDATA: - return media::Decryptor::kNeedMoreData; + return Decryptor::kNeedMoreData; case PP_DECRYPTRESULT_DECRYPT_ERROR: - return media::Decryptor::kError; + return Decryptor::kError; case PP_DECRYPTRESULT_DECODE_ERROR: - return media::Decryptor::kError; + return Decryptor::kError; default: NOTREACHED(); - return media::Decryptor::kError; + return Decryptor::kError; } } PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType( - media::Decryptor::StreamType stream_type) { + Decryptor::StreamType stream_type) { switch (stream_type) { - case media::Decryptor::kAudio: + case Decryptor::kAudio: return PP_DECRYPTORSTREAMTYPE_AUDIO; - case media::Decryptor::kVideo: + case Decryptor::kVideo: return PP_DECRYPTORSTREAMTYPE_VIDEO; default: NOTREACHED(); @@ -239,6 +250,42 @@ media::SampleFormat PpDecryptedSampleFormatToMediaSampleFormat( } } +PP_SessionType MediaSessionTypeToPpSessionType( + MediaKeys::SessionType session_type) { + switch (session_type) { + case MediaKeys::TEMPORARY_SESSION: + return PP_SESSIONTYPE_TEMPORARY; + case MediaKeys::PERSISTENT_SESSION: + return PP_SESSIONTYPE_PERSISTENT; + default: + NOTREACHED(); + return PP_SESSIONTYPE_TEMPORARY; + } +} + +MediaKeys::Exception PpExceptionTypeToMediaException( + PP_CdmExceptionCode exception_code) { + switch (exception_code) { + case PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR: + return MediaKeys::NOT_SUPPORTED_ERROR; + case PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR: + return MediaKeys::INVALID_STATE_ERROR; + case PP_CDMEXCEPTIONCODE_INVALIDACCESSERROR: + return MediaKeys::INVALID_ACCESS_ERROR; + case PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR: + return MediaKeys::QUOTA_EXCEEDED_ERROR; + case PP_CDMEXCEPTIONCODE_UNKNOWNERROR: + return MediaKeys::UNKNOWN_ERROR; + case PP_CDMEXCEPTIONCODE_CLIENTERROR: + return MediaKeys::CLIENT_ERROR; + case PP_CDMEXCEPTIONCODE_OUTPUTERROR: + return MediaKeys::OUTPUT_ERROR; + default: + NOTREACHED(); + return MediaKeys::UNKNOWN_ERROR; + } +} + } // namespace ContentDecryptorDelegate::ContentDecryptorDelegate( @@ -247,82 +294,102 @@ ContentDecryptorDelegate::ContentDecryptorDelegate( : pp_instance_(pp_instance), plugin_decryption_interface_(plugin_decryption_interface), next_decryption_request_id_(1), - pending_audio_decrypt_request_id_(0), - pending_video_decrypt_request_id_(0), - pending_audio_decoder_init_request_id_(0), - pending_video_decoder_init_request_id_(0), - pending_audio_decode_request_id_(0), - pending_video_decode_request_id_(0), audio_samples_per_second_(0), audio_channel_count_(0), + audio_channel_layout_(media::CHANNEL_LAYOUT_NONE), + next_promise_id_(1), weak_ptr_factory_(this) { weak_this_ = weak_ptr_factory_.GetWeakPtr(); } ContentDecryptorDelegate::~ContentDecryptorDelegate() { + SatisfyAllPendingCallbacksOnError(); } -void ContentDecryptorDelegate::Initialize(const std::string& key_system) { +void ContentDecryptorDelegate::Initialize( + const std::string& key_system, + const media::SessionMessageCB& session_message_cb, + const media::SessionReadyCB& session_ready_cb, + const media::SessionClosedCB& session_closed_cb, + const media::SessionErrorCB& session_error_cb, + const base::Closure& fatal_plugin_error_cb) { DCHECK(!key_system.empty()); DCHECK(key_system_.empty()); key_system_ = key_system; - plugin_decryption_interface_->Initialize( - pp_instance_, - StringVar::StringToPPVar(key_system_)); -} - -void ContentDecryptorDelegate::SetSessionEventCallbacks( - const media::SessionCreatedCB& session_created_cb, - const media::SessionMessageCB& session_message_cb, - const media::SessionReadyCB& session_ready_cb, - const media::SessionClosedCB& session_closed_cb, - const media::SessionErrorCB& session_error_cb) { - session_created_cb_ = session_created_cb; session_message_cb_ = session_message_cb; session_ready_cb_ = session_ready_cb; session_closed_cb_ = session_closed_cb; session_error_cb_ = session_error_cb; + fatal_plugin_error_cb_ = fatal_plugin_error_cb; + + plugin_decryption_interface_->Initialize( + pp_instance_, StringVar::StringToPPVar(key_system_)); +} + +void ContentDecryptorDelegate::InstanceCrashed() { + fatal_plugin_error_cb_.Run(); + SatisfyAllPendingCallbacksOnError(); } -bool ContentDecryptorDelegate::CreateSession(uint32 session_id, - const std::string& 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, + MediaKeys::SessionType session_type, + scoped_ptr<NewSessionCdmPromise> promise) { + uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>()); PP_Var init_data_array = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( init_data_length, init_data); + plugin_decryption_interface_->CreateSession( + pp_instance_, + promise_id, + StringVar::StringToPPVar(init_data_type), + init_data_array, + MediaSessionTypeToPpSessionType(session_type)); +} - plugin_decryption_interface_->CreateSession(pp_instance_, - session_id, - StringVar::StringToPPVar(type), - init_data_array); - return true; +void ContentDecryptorDelegate::LoadSession( + const std::string& web_session_id, + scoped_ptr<NewSessionCdmPromise> promise) { + uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>()); + plugin_decryption_interface_->LoadSession( + 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<SimpleCdmPromise> promise) { + uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>()); 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<SimpleCdmPromise> promise) { + uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>()); + plugin_decryption_interface_->ReleaseSession( + pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id)); } // TODO(xhwang): Remove duplication of code in Decrypt(), // DecryptAndDecodeAudio() and DecryptAndDecodeVideo(). bool ContentDecryptorDelegate::Decrypt( - media::Decryptor::StreamType stream_type, + Decryptor::StreamType stream_type, const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, - const media::Decryptor::DecryptCB& decrypt_cb) { + const Decryptor::DecryptCB& decrypt_cb) { DVLOG(3) << "Decrypt() - stream_type: " << stream_type; + // |{audio|video}_input_resource_| is not being used by the plugin // now because there is only one pending audio/video decrypt request at any // time. This is enforced by the media pipeline. @@ -346,17 +413,11 @@ bool ContentDecryptorDelegate::Decrypt( // There is only one pending decrypt request at any time per stream. This is // enforced by the media pipeline. switch (stream_type) { - case media::Decryptor::kAudio: - DCHECK_EQ(pending_audio_decrypt_request_id_, 0u); - DCHECK(pending_audio_decrypt_cb_.is_null()); - pending_audio_decrypt_request_id_ = request_id; - pending_audio_decrypt_cb_ = decrypt_cb; + case Decryptor::kAudio: + audio_decrypt_cb_.Set(request_id, decrypt_cb); break; - case media::Decryptor::kVideo: - DCHECK_EQ(pending_video_decrypt_request_id_, 0u); - DCHECK(pending_video_decrypt_cb_.is_null()); - pending_video_decrypt_request_id_ = request_id; - pending_video_decrypt_cb_ = decrypt_cb; + case Decryptor::kVideo: + video_decrypt_cb_.Set(request_id, decrypt_cb); break; default: NOTREACHED(); @@ -365,33 +426,29 @@ bool ContentDecryptorDelegate::Decrypt( SetBufferToFreeInTrackingInfo(&block_info.tracking_info); - plugin_decryption_interface_->Decrypt(pp_instance_, - pp_resource, - &block_info); + plugin_decryption_interface_->Decrypt(pp_instance_, pp_resource, &block_info); return true; } bool ContentDecryptorDelegate::CancelDecrypt( - media::Decryptor::StreamType stream_type) { + Decryptor::StreamType stream_type) { DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type; - media::Decryptor::DecryptCB decrypt_cb; + Decryptor::DecryptCB decrypt_cb; switch (stream_type) { - case media::Decryptor::kAudio: + case Decryptor::kAudio: // Release the shared memory as it can still be in use by the plugin. // The next Decrypt() call will need to allocate a new shared memory // buffer. audio_input_resource_ = NULL; - pending_audio_decrypt_request_id_ = 0; - decrypt_cb = base::ResetAndReturn(&pending_audio_decrypt_cb_); + decrypt_cb = audio_decrypt_cb_.ResetAndReturn(); break; - case media::Decryptor::kVideo: + case Decryptor::kVideo: // Release the shared memory as it can still be in use by the plugin. // The next Decrypt() call will need to allocate a new shared memory // buffer. video_input_resource_ = NULL; - pending_video_decrypt_request_id_ = 0; - decrypt_cb = base::ResetAndReturn(&pending_video_decrypt_cb_); + decrypt_cb = video_decrypt_cb_.ResetAndReturn(); break; default: NOTREACHED(); @@ -399,14 +456,14 @@ bool ContentDecryptorDelegate::CancelDecrypt( } if (!decrypt_cb.is_null()) - decrypt_cb.Run(media::Decryptor::kSuccess, NULL); + decrypt_cb.Run(Decryptor::kSuccess, NULL); return true; } bool ContentDecryptorDelegate::InitializeAudioDecoder( const media::AudioDecoderConfig& decoder_config, - const media::Decryptor::DecoderInitCB& init_cb) { + const Decryptor::DecoderInitCB& init_cb) { PP_AudioDecoderConfig pp_decoder_config; pp_decoder_config.codec = MediaAudioCodecToPpAudioCodec(decoder_config.codec()); @@ -418,6 +475,7 @@ bool ContentDecryptorDelegate::InitializeAudioDecoder( audio_samples_per_second_ = pp_decoder_config.samples_per_second; audio_channel_count_ = pp_decoder_config.channel_count; + audio_channel_layout_ = decoder_config.channel_layout(); scoped_refptr<PPB_Buffer_Impl> extra_data_resource; if (!MakeBufferResource(pp_instance_, @@ -428,20 +486,15 @@ bool ContentDecryptorDelegate::InitializeAudioDecoder( } ScopedPPResource pp_resource(extra_data_resource.get()); - DCHECK_EQ(pending_audio_decoder_init_request_id_, 0u); - DCHECK(pending_audio_decoder_init_cb_.is_null()); - pending_audio_decoder_init_request_id_ = pp_decoder_config.request_id; - pending_audio_decoder_init_cb_ = init_cb; - - plugin_decryption_interface_->InitializeAudioDecoder(pp_instance_, - &pp_decoder_config, - pp_resource); + audio_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb); + plugin_decryption_interface_->InitializeAudioDecoder( + pp_instance_, &pp_decoder_config, pp_resource); return true; } bool ContentDecryptorDelegate::InitializeVideoDecoder( const media::VideoDecoderConfig& decoder_config, - const media::Decryptor::DecoderInitCB& init_cb) { + const Decryptor::DecoderInitCB& init_cb) { PP_VideoDecoderConfig pp_decoder_config; pp_decoder_config.codec = MediaVideoCodecToPpVideoCodec(decoder_config.codec()); @@ -462,24 +515,20 @@ bool ContentDecryptorDelegate::InitializeVideoDecoder( } ScopedPPResource pp_resource(extra_data_resource.get()); - DCHECK_EQ(pending_video_decoder_init_request_id_, 0u); - DCHECK(pending_video_decoder_init_cb_.is_null()); - pending_video_decoder_init_request_id_ = pp_decoder_config.request_id; - pending_video_decoder_init_cb_ = init_cb; - + video_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb); natural_size_ = decoder_config.natural_size(); - plugin_decryption_interface_->InitializeVideoDecoder(pp_instance_, - &pp_decoder_config, - pp_resource); + plugin_decryption_interface_->InitializeVideoDecoder( + pp_instance_, &pp_decoder_config, pp_resource); return true; } bool ContentDecryptorDelegate::DeinitializeDecoder( - media::Decryptor::StreamType stream_type) { + Decryptor::StreamType stream_type) { CancelDecode(stream_type); - natural_size_ = gfx::Size(); + if (stream_type == Decryptor::kVideo) + natural_size_ = gfx::Size(); // TODO(tomfinegan): Add decoder deinitialize request tracking, and get // stream type from media stack. @@ -488,8 +537,7 @@ bool ContentDecryptorDelegate::DeinitializeDecoder( return true; } -bool ContentDecryptorDelegate::ResetDecoder( - media::Decryptor::StreamType stream_type) { +bool ContentDecryptorDelegate::ResetDecoder(Decryptor::StreamType stream_type) { CancelDecode(stream_type); // TODO(tomfinegan): Add decoder reset request tracking. @@ -500,14 +548,13 @@ bool ContentDecryptorDelegate::ResetDecoder( bool ContentDecryptorDelegate::DecryptAndDecodeAudio( const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, - const media::Decryptor::AudioDecodeCB& audio_decode_cb) { + const Decryptor::AudioDecodeCB& audio_decode_cb) { // |audio_input_resource_| is not being used by the plugin now // because there is only one pending audio decode request at any time. // This is enforced by the media pipeline. scoped_refptr<PPB_Buffer_Impl> encrypted_resource; - if (!MakeMediaBufferResource(media::Decryptor::kAudio, - encrypted_buffer, - &encrypted_resource)) { + if (!MakeMediaBufferResource( + Decryptor::kAudio, encrypted_buffer, &encrypted_resource)) { return false; } @@ -529,29 +576,23 @@ bool ContentDecryptorDelegate::DecryptAndDecodeAudio( // enforced by the media pipeline. If this DCHECK is violated, our buffer // reuse policy is not valid, and we may have race problems for the shared // buffer. - DCHECK_EQ(pending_audio_decode_request_id_, 0u); - DCHECK(pending_audio_decode_cb_.is_null()); - pending_audio_decode_request_id_ = request_id; - pending_audio_decode_cb_ = audio_decode_cb; + audio_decode_cb_.Set(request_id, audio_decode_cb); ScopedPPResource pp_resource(encrypted_resource.get()); - plugin_decryption_interface_->DecryptAndDecode(pp_instance_, - PP_DECRYPTORSTREAMTYPE_AUDIO, - pp_resource, - &block_info); + plugin_decryption_interface_->DecryptAndDecode( + pp_instance_, PP_DECRYPTORSTREAMTYPE_AUDIO, pp_resource, &block_info); return true; } bool ContentDecryptorDelegate::DecryptAndDecodeVideo( const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, - const media::Decryptor::VideoDecodeCB& video_decode_cb) { + const Decryptor::VideoDecodeCB& video_decode_cb) { // |video_input_resource_| is not being used by the plugin now // because there is only one pending video decode request at any time. // This is enforced by the media pipeline. scoped_refptr<PPB_Buffer_Impl> encrypted_resource; - if (!MakeMediaBufferResource(media::Decryptor::kVideo, - encrypted_buffer, - &encrypted_resource)) { + if (!MakeMediaBufferResource( + Decryptor::kVideo, encrypted_buffer, &encrypted_resource)) { return false; } @@ -575,111 +616,144 @@ bool ContentDecryptorDelegate::DecryptAndDecodeVideo( // media pipeline. If this DCHECK is violated, our buffer // reuse policy is not valid, and we may have race problems for the shared // buffer. - DCHECK_EQ(pending_video_decode_request_id_, 0u); - DCHECK(pending_video_decode_cb_.is_null()); - pending_video_decode_request_id_ = request_id; - pending_video_decode_cb_ = video_decode_cb; + video_decode_cb_.Set(request_id, video_decode_cb); // TODO(tomfinegan): Need to get stream type from media stack. ScopedPPResource pp_resource(encrypted_resource.get()); - plugin_decryption_interface_->DecryptAndDecode(pp_instance_, - PP_DECRYPTORSTREAMTYPE_VIDEO, - pp_resource, - &block_info); + plugin_decryption_interface_->DecryptAndDecode( + pp_instance_, PP_DECRYPTORSTREAMTYPE_VIDEO, pp_resource, &block_info); 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<CdmPromise> promise = TakePromise(promise_id); + if (promise) { + SimpleCdmPromise* simple_promise( + static_cast<SimpleCdmPromise*>(promise.get())); + simple_promise->resolve(); + } +} - StringVar* session_id_string = StringVar::FromPPVar(web_session_id_var); +void ContentDecryptorDelegate::OnPromiseResolvedWithSession( + uint32 promise_id, + PP_Var web_session_id) { + scoped_ptr<CdmPromise> promise = TakePromise(promise_id); - if (!session_id_string) { - OnSessionError(session_id, media::MediaKeys::kUnknownError, 0); - return; + StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id); + DCHECK(web_session_id_string); + + if (promise) { + NewSessionCdmPromise* session_promise( + static_cast<NewSessionCdmPromise*>(promise.get())); + session_promise->resolve(web_session_id_string->value()); } +} - session_created_cb_.Run(session_id, session_id_string->value()); +void ContentDecryptorDelegate::OnPromiseRejected( + uint32 promise_id, + PP_CdmExceptionCode exception_code, + uint32 system_code, + PP_Var error_description) { + StringVar* error_description_string = StringVar::FromPPVar(error_description); + DCHECK(error_description_string); + + scoped_ptr<CdmPromise> promise = TakePromise(promise_id); + if (promise) { + promise->reject(PpExceptionTypeToMediaException(exception_code), + system_code, + error_description_string->value()); + } } -void ContentDecryptorDelegate::OnSessionMessage(uint32 session_id, - PP_Var message_var, - PP_Var default_url_var) { +void ContentDecryptorDelegate::OnSessionMessage(PP_Var web_session_id, + PP_Var message, + PP_Var destination_url) { if (session_message_cb_.is_null()) return; - ArrayBufferVar* message_array_buffer = ArrayBufferVar::FromPPVar(message_var); + StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id); + DCHECK(web_session_id_string); - std::vector<uint8> message; + ArrayBufferVar* message_array_buffer = ArrayBufferVar::FromPPVar(message); + std::vector<uint8> message_vector; if (message_array_buffer) { const uint8* data = static_cast<const uint8*>(message_array_buffer->Map()); - message.assign(data, data + message_array_buffer->ByteLength()); + message_vector.assign(data, data + message_array_buffer->ByteLength()); } - StringVar* default_url_string = StringVar::FromPPVar(default_url_var); + StringVar* destination_url_string = StringVar::FromPPVar(destination_url); + DCHECK(destination_url_string); - if (!default_url_string) { - OnSessionError(session_id, media::MediaKeys::kUnknownError, 0); - return; + GURL verified_gurl = GURL(destination_url_string->value()); + if (!verified_gurl.is_valid() && !verified_gurl.is_empty()) { + DLOG(WARNING) << "SessionMessage default_url is invalid : " + << verified_gurl.possibly_invalid_spec(); + verified_gurl = GURL::EmptyGURL(); // Replace invalid destination_url. } - session_message_cb_.Run(session_id, message, default_url_string->value()); + session_message_cb_.Run( + web_session_id_string->value(), message_vector, verified_gurl); } -void ContentDecryptorDelegate::OnSessionReady(uint32 session_id) { +void ContentDecryptorDelegate::OnSessionReady(PP_Var web_session_id) { if (session_ready_cb_.is_null()) return; - session_ready_cb_.Run(session_id); + StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id); + DCHECK(web_session_id_string); + + session_ready_cb_.Run(web_session_id_string->value()); } -void ContentDecryptorDelegate::OnSessionClosed(uint32 session_id) { +void ContentDecryptorDelegate::OnSessionClosed(PP_Var web_session_id) { if (session_closed_cb_.is_null()) return; - session_closed_cb_.Run(session_id); + StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id); + DCHECK(web_session_id_string); + + session_closed_cb_.Run(web_session_id_string->value()); } -void ContentDecryptorDelegate::OnSessionError(uint32 session_id, - int32_t media_error, - int32_t system_code) { +void ContentDecryptorDelegate::OnSessionError( + PP_Var web_session_id, + PP_CdmExceptionCode exception_code, + uint32 system_code, + PP_Var error_description) { 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_string = StringVar::FromPPVar(web_session_id); + DCHECK(web_session_id_string); + + StringVar* error_description_string = StringVar::FromPPVar(error_description); + DCHECK(error_description_string); + + session_error_cb_.Run(web_session_id_string->value(), + PpExceptionTypeToMediaException(exception_code), + system_code, + error_description_string->value()); } void ContentDecryptorDelegate::DecoderInitializeDone( - PP_DecryptorStreamType decoder_type, - uint32_t request_id, - PP_Bool success) { + PP_DecryptorStreamType decoder_type, + uint32_t request_id, + PP_Bool success) { if (decoder_type == PP_DECRYPTORSTREAMTYPE_AUDIO) { // If the request ID is not valid or does not match what's saved, do // nothing. - if (request_id == 0 || - request_id != pending_audio_decoder_init_request_id_) + if (request_id == 0 || !audio_decoder_init_cb_.Matches(request_id)) return; - DCHECK(!pending_audio_decoder_init_cb_.is_null()); - pending_audio_decoder_init_request_id_ = 0; - base::ResetAndReturn( - &pending_audio_decoder_init_cb_).Run(PP_ToBool(success)); + audio_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success)); } else { - if (request_id == 0 || - request_id != pending_video_decoder_init_request_id_) + if (request_id == 0 || !video_decoder_init_cb_.Matches(request_id)) return; - if (!success) - natural_size_ = gfx::Size(); + if (!success) + natural_size_ = gfx::Size(); - DCHECK(!pending_video_decoder_init_cb_.is_null()); - pending_video_decoder_init_request_id_ = 0; - base::ResetAndReturn( - &pending_video_decoder_init_cb_).Run(PP_ToBool(success)); + video_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success)); } } @@ -711,47 +785,43 @@ void ContentDecryptorDelegate::DeliverBlock( return; } - media::Decryptor::DecryptCB decrypt_cb; - if (request_id == pending_audio_decrypt_request_id_) { - DCHECK(!pending_audio_decrypt_cb_.is_null()); - pending_audio_decrypt_request_id_ = 0; - decrypt_cb = base::ResetAndReturn(&pending_audio_decrypt_cb_); - } else if (request_id == pending_video_decrypt_request_id_) { - DCHECK(!pending_video_decrypt_cb_.is_null()); - pending_video_decrypt_request_id_ = 0; - decrypt_cb = base::ResetAndReturn(&pending_video_decrypt_cb_); + Decryptor::DecryptCB decrypt_cb; + if (audio_decrypt_cb_.Matches(request_id)) { + decrypt_cb = audio_decrypt_cb_.ResetAndReturn(); + } else if (video_decrypt_cb_.Matches(request_id)) { + decrypt_cb = video_decrypt_cb_.ResetAndReturn(); } else { DVLOG(1) << "DeliverBlock() - request_id " << request_id << " not found"; return; } - media::Decryptor::Status status = + Decryptor::Status status = PpDecryptResultToMediaDecryptorStatus(block_info->result); - if (status != media::Decryptor::kSuccess) { + if (status != Decryptor::kSuccess) { decrypt_cb.Run(status, NULL); return; } EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_block, true); if (!enter.succeeded()) { - decrypt_cb.Run(media::Decryptor::kError, NULL); + decrypt_cb.Run(Decryptor::kError, NULL); return; } BufferAutoMapper mapper(enter.object()); if (!mapper.data() || !mapper.size() || mapper.size() < block_info->data_size) { - decrypt_cb.Run(media::Decryptor::kError, NULL); + decrypt_cb.Run(Decryptor::kError, NULL); return; } // TODO(tomfinegan): Find a way to take ownership of the shared memory // managed by the PPB_Buffer_Dev, and avoid the extra copy. scoped_refptr<media::DecoderBuffer> decrypted_buffer( - media::DecoderBuffer::CopyFrom( - static_cast<uint8*>(mapper.data()), block_info->data_size)); - decrypted_buffer->set_timestamp(base::TimeDelta::FromMicroseconds( - block_info->tracking_info.timestamp)); - decrypt_cb.Run(media::Decryptor::kSuccess, decrypted_buffer); + media::DecoderBuffer::CopyFrom(static_cast<uint8*>(mapper.data()), + block_info->data_size)); + decrypted_buffer->set_timestamp( + base::TimeDelta::FromMicroseconds(block_info->tracking_info.timestamp)); + decrypt_cb.Run(Decryptor::kSuccess, decrypted_buffer); } // Use a non-class-member function here so that if for some reason @@ -796,7 +866,7 @@ void ContentDecryptorDelegate::DeliverFrame( DVLOG(2) << "DeliverFrame() - request_id: " << request_id; // If the request ID is not valid or does not match what's saved, do nothing. - if (request_id == 0 || request_id != pending_video_decode_request_id_) { + if (request_id == 0 || !video_decode_cb_.Matches(request_id)) { DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found"; FreeBuffer(frame_info->tracking_info.buffer_id); return; @@ -805,14 +875,11 @@ void ContentDecryptorDelegate::DeliverFrame( TRACE_EVENT_ASYNC_END0( "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id); - DCHECK(!pending_video_decode_cb_.is_null()); - pending_video_decode_request_id_ = 0; - media::Decryptor::VideoDecodeCB video_decode_cb = - base::ResetAndReturn(&pending_video_decode_cb_); + Decryptor::VideoDecodeCB video_decode_cb = video_decode_cb_.ResetAndReturn(); - media::Decryptor::Status status = + Decryptor::Status status = PpDecryptResultToMediaDecryptorStatus(frame_info->result); - if (status != media::Decryptor::kSuccess) { + if (status != Decryptor::kSuccess) { DCHECK(!frame_info->tracking_info.buffer_id); video_decode_cb.Run(status, NULL); return; @@ -822,7 +889,7 @@ void ContentDecryptorDelegate::DeliverFrame( uint8* frame_data = GetMappedBuffer(decrypted_frame, &ppb_buffer); if (!frame_data) { FreeBuffer(frame_info->tracking_info.buffer_id); - video_decode_cb.Run(media::Decryptor::kError, NULL); + video_decode_cb.Run(Decryptor::kError, NULL); return; } @@ -843,15 +910,14 @@ void ContentDecryptorDelegate::DeliverFrame( frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_V], base::TimeDelta::FromMicroseconds( frame_info->tracking_info.timestamp), - media::BindToLoop( - base::MessageLoopProxy::current(), + media::BindToCurrentLoop( base::Bind(&BufferNoLongerNeeded, ppb_buffer, base::Bind(&ContentDecryptorDelegate::FreeBuffer, weak_this_, frame_info->tracking_info.buffer_id)))); - video_decode_cb.Run(media::Decryptor::kSuccess, decoded_frame); + video_decode_cb.Run(Decryptor::kSuccess, decoded_frame); } void ContentDecryptorDelegate::DeliverSamples( @@ -865,21 +931,18 @@ void ContentDecryptorDelegate::DeliverSamples( DVLOG(2) << "DeliverSamples() - request_id: " << request_id; // If the request ID is not valid or does not match what's saved, do nothing. - if (request_id == 0 || request_id != pending_audio_decode_request_id_) { + if (request_id == 0 || !audio_decode_cb_.Matches(request_id)) { DVLOG(1) << "DeliverSamples() - request_id " << request_id << " not found"; return; } - DCHECK(!pending_audio_decode_cb_.is_null()); - pending_audio_decode_request_id_ = 0; - media::Decryptor::AudioDecodeCB audio_decode_cb = - base::ResetAndReturn(&pending_audio_decode_cb_); + Decryptor::AudioDecodeCB audio_decode_cb = audio_decode_cb_.ResetAndReturn(); - const media::Decryptor::AudioBuffers empty_frames; + const Decryptor::AudioBuffers empty_frames; - media::Decryptor::Status status = + Decryptor::Status status = PpDecryptResultToMediaDecryptorStatus(sample_info->result); - if (status != media::Decryptor::kSuccess) { + if (status != Decryptor::kSuccess) { audio_decode_cb.Run(status, empty_frames); return; } @@ -887,42 +950,38 @@ void ContentDecryptorDelegate::DeliverSamples( media::SampleFormat sample_format = PpDecryptedSampleFormatToMediaSampleFormat(sample_info->format); - media::Decryptor::AudioBuffers audio_frame_list; + Decryptor::AudioBuffers audio_frame_list; if (!DeserializeAudioFrames(audio_frames, sample_info->data_size, sample_format, &audio_frame_list)) { NOTREACHED() << "CDM did not serialize the buffer correctly."; - audio_decode_cb.Run(media::Decryptor::kError, empty_frames); + audio_decode_cb.Run(Decryptor::kError, empty_frames); return; } - audio_decode_cb.Run(media::Decryptor::kSuccess, audio_frame_list); + audio_decode_cb.Run(Decryptor::kSuccess, audio_frame_list); } // TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt(). -void ContentDecryptorDelegate::CancelDecode( - media::Decryptor::StreamType stream_type) { +void ContentDecryptorDelegate::CancelDecode(Decryptor::StreamType stream_type) { switch (stream_type) { - case media::Decryptor::kAudio: + case Decryptor::kAudio: // Release the shared memory as it can still be in use by the plugin. // The next DecryptAndDecode() call will need to allocate a new shared // memory buffer. audio_input_resource_ = NULL; - pending_audio_decode_request_id_ = 0; - if (!pending_audio_decode_cb_.is_null()) - base::ResetAndReturn(&pending_audio_decode_cb_).Run( - media::Decryptor::kSuccess, media::Decryptor::AudioBuffers()); + if (!audio_decode_cb_.is_null()) + audio_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess, + Decryptor::AudioBuffers()); break; - case media::Decryptor::kVideo: + case Decryptor::kVideo: // Release the shared memory as it can still be in use by the plugin. // The next DecryptAndDecode() call will need to allocate a new shared // memory buffer. video_input_resource_ = NULL; - pending_video_decode_request_id_ = 0; - if (!pending_video_decode_cb_.is_null()) - base::ResetAndReturn(&pending_video_decode_cb_).Run( - media::Decryptor::kSuccess, NULL); + if (!video_decode_cb_.is_null()) + video_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess, NULL); break; default: NOTREACHED(); @@ -930,7 +989,7 @@ void ContentDecryptorDelegate::CancelDecode( } bool ContentDecryptorDelegate::MakeMediaBufferResource( - media::Decryptor::StreamType stream_type, + Decryptor::StreamType stream_type, const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, scoped_refptr<PPB_Buffer_Impl>* resource) { TRACE_EVENT0("media", "ContentDecryptorDelegate::MakeMediaBufferResource"); @@ -941,11 +1000,10 @@ bool ContentDecryptorDelegate::MakeMediaBufferResource( return true; } - DCHECK(stream_type == media::Decryptor::kAudio || - stream_type == media::Decryptor::kVideo); + DCHECK(stream_type == Decryptor::kAudio || stream_type == Decryptor::kVideo); scoped_refptr<PPB_Buffer_Impl>& media_resource = - (stream_type == media::Decryptor::kAudio) ? audio_input_resource_ : - video_input_resource_; + (stream_type == Decryptor::kAudio) ? audio_input_resource_ + : video_input_resource_; const size_t data_size = static_cast<size_t>(encrypted_buffer->data_size()); if (!media_resource.get() || media_resource->size() < data_size) { @@ -964,11 +1022,11 @@ bool ContentDecryptorDelegate::MakeMediaBufferResource( media_resource_size *= 2; DVLOG(2) << "Size of media buffer for " - << ((stream_type == media::Decryptor::kAudio) ? "audio" : "video") + << ((stream_type == Decryptor::kAudio) ? "audio" : "video") << " stream bumped to " << media_resource_size << " bytes to fit input."; - media_resource = PPB_Buffer_Impl::CreateResource(pp_instance_, - media_resource_size); + media_resource = + PPB_Buffer_Impl::CreateResource(pp_instance_, media_resource_size); if (!media_resource.get()) return false; } @@ -1004,7 +1062,7 @@ bool ContentDecryptorDelegate::DeserializeAudioFrames( PP_Resource audio_frames, size_t data_size, media::SampleFormat sample_format, - media::Decryptor::AudioBuffers* frames) { + Decryptor::AudioBuffers* frames) { DCHECK(frames); EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true); if (!enter.succeeded()) @@ -1024,10 +1082,12 @@ bool ContentDecryptorDelegate::DeserializeAudioFrames( const int audio_bytes_per_frame = media::SampleFormatToBytesPerChannel(sample_format) * audio_channel_count_; + if (audio_bytes_per_frame <= 0) + return false; // Allocate space for the channel pointers given to AudioBuffer. - std::vector<const uint8*> channel_ptrs( - audio_channel_count_, static_cast<const uint8*>(NULL)); + std::vector<const uint8*> channel_ptrs(audio_channel_count_, + static_cast<const uint8*>(NULL)); do { int64 timestamp = 0; int64 frame_size = -1; @@ -1046,7 +1106,7 @@ bool ContentDecryptorDelegate::DeserializeAudioFrames( // We should *not* have empty frames in the list. if (frame_size <= 0 || - bytes_left < base::checked_numeric_cast<size_t>(frame_size)) { + bytes_left < base::checked_cast<size_t>(frame_size)) { return false; } @@ -1059,12 +1119,12 @@ bool ContentDecryptorDelegate::DeserializeAudioFrames( const int frame_count = frame_size / audio_bytes_per_frame; scoped_refptr<media::AudioBuffer> frame = media::AudioBuffer::CopyFrom( sample_format, + audio_channel_layout_, audio_channel_count_, + audio_samples_per_second_, frame_count, &channel_ptrs[0], - base::TimeDelta::FromMicroseconds(timestamp), - base::TimeDelta::FromMicroseconds(audio_samples_per_second_ / - frame_count)); + base::TimeDelta::FromMicroseconds(timestamp)); frames->push_back(frame); cur += frame_size; @@ -1074,4 +1134,52 @@ bool ContentDecryptorDelegate::DeserializeAudioFrames( return true; } +void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() { + if (!audio_decoder_init_cb_.is_null()) + audio_decoder_init_cb_.ResetAndReturn().Run(false); + + if (!video_decoder_init_cb_.is_null()) + video_decoder_init_cb_.ResetAndReturn().Run(false); + + audio_input_resource_ = NULL; + video_input_resource_ = NULL; + + if (!audio_decrypt_cb_.is_null()) + audio_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL); + + if (!video_decrypt_cb_.is_null()) + video_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL); + + if (!audio_decode_cb_.is_null()) { + const media::Decryptor::AudioBuffers empty_frames; + audio_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError, + empty_frames); + } + + if (!video_decode_cb_.is_null()) + video_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL); + + // Reject all outstanding promises. + for (PromiseMap::iterator it = promises_.begin(); it != promises_.end(); + ++it) { + it->second->reject( + media::MediaKeys::UNKNOWN_ERROR, 0, "Failure calling plugin."); + } + promises_.clear(); +} + +uint32_t ContentDecryptorDelegate::SavePromise(scoped_ptr<CdmPromise> promise) { + uint32_t promise_id = next_promise_id_++; + promises_.add(promise_id, promise.Pass()); + return promise_id; +} + +scoped_ptr<CdmPromise> ContentDecryptorDelegate::TakePromise( + uint32_t promise_id) { + PromiseMap::iterator it = promises_.find(promise_id); + if (it == promises_.end()) + return scoped_ptr<CdmPromise>(); + return promises_.take_and_erase(it); +} + } // namespace content |