diff options
Diffstat (limited to 'chromium/content/renderer/media/crypto/ppapi_decryptor.cc')
-rw-r--r-- | chromium/content/renderer/media/crypto/ppapi_decryptor.cc | 352 |
1 files changed, 223 insertions, 129 deletions
diff --git a/chromium/content/renderer/media/crypto/ppapi_decryptor.cc b/chromium/content/renderer/media/crypto/ppapi_decryptor.cc index aff94a240e5..dd07aaacc69 100644 --- a/chromium/content/renderer/media/crypto/ppapi_decryptor.cc +++ b/chromium/content/renderer/media/crypto/ppapi_decryptor.cc @@ -7,14 +7,17 @@ #include <string> #include "base/bind.h" +#include "base/callback.h" #include "base/callback_helpers.h" #include "base/location.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_proxy.h" +#include "content/renderer/media/crypto/key_systems.h" #include "content/renderer/pepper/content_decryptor_delegate.h" #include "content/renderer/pepper/pepper_plugin_instance_impl.h" #include "media/base/audio_decoder_config.h" +#include "media/base/cdm_promise.h" #include "media/base/data_buffer.h" #include "media/base/decoder_buffer.h" #include "media/base/video_decoder_config.h" @@ -22,140 +25,179 @@ namespace content { +// This class is needed so that resolving an Update() promise triggers playback +// of the stream. It intercepts the resolve() call to invoke an additional +// callback. +class SessionUpdatedPromise : public media::SimpleCdmPromise { + public: + SessionUpdatedPromise(scoped_ptr<media::SimpleCdmPromise> caller_promise, + base::Closure additional_resolve_cb) + : caller_promise_(caller_promise.Pass()), + additional_resolve_cb_(additional_resolve_cb) {} + + virtual void resolve() OVERRIDE { + DCHECK(is_pending_); + is_pending_ = false; + additional_resolve_cb_.Run(); + caller_promise_->resolve(); + } + + virtual void reject(media::MediaKeys::Exception exception_code, + uint32 system_code, + const std::string& error_message) OVERRIDE { + DCHECK(is_pending_); + is_pending_ = false; + caller_promise_->reject(exception_code, system_code, error_message); + } + + protected: + scoped_ptr<media::SimpleCdmPromise> caller_promise_; + base::Closure additional_resolve_cb_; +}; + scoped_ptr<PpapiDecryptor> PpapiDecryptor::Create( const std::string& key_system, - const scoped_refptr<PepperPluginInstanceImpl>& plugin_instance, - const media::SessionCreatedCB& session_created_cb, + const GURL& security_origin, + const CreatePepperCdmCB& create_pepper_cdm_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, - const base::Closure& destroy_plugin_cb) { - ContentDecryptorDelegate* plugin_cdm_delegate = - plugin_instance->GetContentDecryptorDelegate(); - if (!plugin_cdm_delegate) { - DVLOG(1) << "PpapiDecryptor: plugin cdm delegate creation failed."; + const media::SessionErrorCB& session_error_cb) { + std::string plugin_type = GetPepperType(key_system); + DCHECK(!plugin_type.empty()); + scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper = + create_pepper_cdm_cb.Run(plugin_type, security_origin); + if (!pepper_cdm_wrapper) { + DLOG(ERROR) << "Plugin instance creation failed."; return scoped_ptr<PpapiDecryptor>(); } - plugin_cdm_delegate->Initialize(key_system); - - return scoped_ptr<PpapiDecryptor>(new PpapiDecryptor(plugin_instance, - plugin_cdm_delegate, - session_created_cb, - session_message_cb, - session_ready_cb, - session_closed_cb, - session_error_cb, - destroy_plugin_cb)); + return scoped_ptr<PpapiDecryptor>( + new PpapiDecryptor(key_system, + pepper_cdm_wrapper.Pass(), + session_message_cb, + session_ready_cb, + session_closed_cb, + session_error_cb)); } PpapiDecryptor::PpapiDecryptor( - const scoped_refptr<PepperPluginInstanceImpl>& plugin_instance, - ContentDecryptorDelegate* plugin_cdm_delegate, - const media::SessionCreatedCB& session_created_cb, + const std::string& key_system, + scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper, 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& destroy_plugin_cb) - : plugin_instance_(plugin_instance), - plugin_cdm_delegate_(plugin_cdm_delegate), - session_created_cb_(session_created_cb), + const media::SessionErrorCB& session_error_cb) + : pepper_cdm_wrapper_(pepper_cdm_wrapper.Pass()), session_message_cb_(session_message_cb), session_ready_cb_(session_ready_cb), session_closed_cb_(session_closed_cb), session_error_cb_(session_error_cb), - destroy_plugin_cb_(destroy_plugin_cb), render_loop_proxy_(base::MessageLoopProxy::current()), weak_ptr_factory_(this) { - DCHECK(plugin_instance_.get()); - DCHECK(!session_created_cb_.is_null()); + DCHECK(pepper_cdm_wrapper_.get()); DCHECK(!session_message_cb_.is_null()); DCHECK(!session_ready_cb_.is_null()); DCHECK(!session_closed_cb_.is_null()); DCHECK(!session_error_cb_.is_null()); - DCHECK(!destroy_plugin_cb_.is_null()); - - weak_this_ = weak_ptr_factory_.GetWeakPtr(); - plugin_cdm_delegate_->SetSessionEventCallbacks( - base::Bind(&PpapiDecryptor::OnSessionCreated, weak_this_), - base::Bind(&PpapiDecryptor::OnSessionMessage, weak_this_), - base::Bind(&PpapiDecryptor::OnSessionReady, weak_this_), - base::Bind(&PpapiDecryptor::OnSessionClosed, weak_this_), - base::Bind(&PpapiDecryptor::OnSessionError, weak_this_)); + base::WeakPtr<PpapiDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr(); + CdmDelegate()->Initialize( + key_system, + base::Bind(&PpapiDecryptor::OnSessionMessage, weak_this), + base::Bind(&PpapiDecryptor::OnSessionReady, weak_this), + base::Bind(&PpapiDecryptor::OnSessionClosed, weak_this), + base::Bind(&PpapiDecryptor::OnSessionError, weak_this), + base::Bind(&PpapiDecryptor::OnFatalPluginError, weak_this)); } PpapiDecryptor::~PpapiDecryptor() { - plugin_cdm_delegate_ = NULL; - plugin_instance_ = NULL; - destroy_plugin_cb_.Run(); + pepper_cdm_wrapper_.reset(); } -bool PpapiDecryptor::CreateSession(uint32 session_id, - const std::string& type, - const uint8* init_data, - int init_data_length) { +void PpapiDecryptor::CreateSession( + const std::string& init_data_type, + const uint8* init_data, + int init_data_length, + SessionType session_type, + scoped_ptr<media::NewSessionCdmPromise> promise) { DVLOG(2) << __FUNCTION__; DCHECK(render_loop_proxy_->BelongsToCurrentThread()); - DCHECK(plugin_cdm_delegate_); - if (!plugin_cdm_delegate_->CreateSession( - session_id, type, init_data, init_data_length)) { - ReportFailureToCallPlugin(session_id); - return false; + if (!CdmDelegate()) { + promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist."); + return; } - return true; + CdmDelegate()->CreateSession(init_data_type, + init_data, + init_data_length, + session_type, + promise.Pass()); } -void PpapiDecryptor::UpdateSession(uint32 session_id, - const uint8* response, - int response_length) { +void PpapiDecryptor::LoadSession( + const std::string& web_session_id, + scoped_ptr<media::NewSessionCdmPromise> promise) { DVLOG(2) << __FUNCTION__; DCHECK(render_loop_proxy_->BelongsToCurrentThread()); - if (!plugin_cdm_delegate_->UpdateSession( - session_id, response, response_length)) - ReportFailureToCallPlugin(session_id); + if (!CdmDelegate()) { + promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist."); + return; + } + + CdmDelegate()->LoadSession(web_session_id, promise.Pass()); +} - if (!new_audio_key_cb_.is_null()) - new_audio_key_cb_.Run(); +void PpapiDecryptor::UpdateSession( + const std::string& web_session_id, + const uint8* response, + int response_length, + scoped_ptr<media::SimpleCdmPromise> promise) { + DCHECK(render_loop_proxy_->BelongsToCurrentThread()); - if (!new_video_key_cb_.is_null()) - new_video_key_cb_.Run(); + if (!CdmDelegate()) { + promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist."); + return; + } + + scoped_ptr<SessionUpdatedPromise> session_updated_promise( + new SessionUpdatedPromise(promise.Pass(), + base::Bind(&PpapiDecryptor::ResumePlayback, + weak_ptr_factory_.GetWeakPtr()))); + CdmDelegate()->UpdateSession( + web_session_id, + response, + response_length, + session_updated_promise.PassAs<media::SimpleCdmPromise>()); } -void PpapiDecryptor::ReleaseSession(uint32 session_id) { - DVLOG(2) << __FUNCTION__; +void PpapiDecryptor::ReleaseSession( + const std::string& web_session_id, + scoped_ptr<media::SimpleCdmPromise> promise) { DCHECK(render_loop_proxy_->BelongsToCurrentThread()); - if (!plugin_cdm_delegate_->ReleaseSession(session_id)) - ReportFailureToCallPlugin(session_id); + if (!CdmDelegate()) { + promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist."); + return; + } + + CdmDelegate()->ReleaseSession(web_session_id, promise.Pass()); } media::Decryptor* PpapiDecryptor::GetDecryptor() { -#if defined(GOOGLE_TV) - // Google TV only uses PpapiDecrytor as a MediaKeys and does not need the - // Decryptor interface of the PpapiDecryptor. - // Details: If we don't do this GTV will be broken. The reason is that during - // initialization, MediaSourceDelegate tries to use DecryptingDemuxerStream - // to decrypt the stream in the renderer process (for ClearKey support). - // However, for GTV, PpapiDecryptor cannot do decryption at all. By returning - // NULL, DDS init will fail and we fallback to what GTV used to do. - return NULL; -#else return this; -#endif // defined(GOOGLE_TV) } void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type, const NewKeyCB& new_key_cb) { if (!render_loop_proxy_->BelongsToCurrentThread()) { - render_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &PpapiDecryptor::RegisterNewKeyCB, weak_this_, stream_type, - new_key_cb)); + render_loop_proxy_->PostTask(FROM_HERE, + base::Bind(&PpapiDecryptor::RegisterNewKeyCB, + weak_ptr_factory_.GetWeakPtr(), + stream_type, + new_key_cb)); return; } @@ -177,34 +219,46 @@ void PpapiDecryptor::Decrypt( const scoped_refptr<media::DecoderBuffer>& encrypted, const DecryptCB& decrypt_cb) { if (!render_loop_proxy_->BelongsToCurrentThread()) { - render_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &PpapiDecryptor::Decrypt, weak_this_, - stream_type, encrypted, decrypt_cb)); + render_loop_proxy_->PostTask(FROM_HERE, + base::Bind(&PpapiDecryptor::Decrypt, + weak_ptr_factory_.GetWeakPtr(), + stream_type, + encrypted, + decrypt_cb)); return; } DVLOG(3) << __FUNCTION__ << " - stream_type: " << stream_type; - if (!plugin_cdm_delegate_->Decrypt(stream_type, encrypted, decrypt_cb)) + if (!CdmDelegate() || + !CdmDelegate()->Decrypt(stream_type, encrypted, decrypt_cb)) { decrypt_cb.Run(kError, NULL); + } } void PpapiDecryptor::CancelDecrypt(StreamType stream_type) { if (!render_loop_proxy_->BelongsToCurrentThread()) { - render_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &PpapiDecryptor::CancelDecrypt, weak_this_, stream_type)); + render_loop_proxy_->PostTask(FROM_HERE, + base::Bind(&PpapiDecryptor::CancelDecrypt, + weak_ptr_factory_.GetWeakPtr(), + stream_type)); return; } DVLOG(1) << __FUNCTION__ << " - stream_type: " << stream_type; - plugin_cdm_delegate_->CancelDecrypt(stream_type); + if (CdmDelegate()) + CdmDelegate()->CancelDecrypt(stream_type); } void PpapiDecryptor::InitializeAudioDecoder( const media::AudioDecoderConfig& config, const DecoderInitCB& init_cb) { if (!render_loop_proxy_->BelongsToCurrentThread()) { - render_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &PpapiDecryptor::InitializeAudioDecoder, weak_this_, config, init_cb)); + render_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PpapiDecryptor::InitializeAudioDecoder, + weak_ptr_factory_.GetWeakPtr(), + config, + init_cb)); return; } @@ -213,8 +267,11 @@ void PpapiDecryptor::InitializeAudioDecoder( DCHECK(config.IsValidConfig()); audio_decoder_init_cb_ = init_cb; - if (!plugin_cdm_delegate_->InitializeAudioDecoder(config, base::Bind( - &PpapiDecryptor::OnDecoderInitialized, weak_this_, kAudio))) { + if (!CdmDelegate() || !CdmDelegate()->InitializeAudioDecoder( + config, + base::Bind(&PpapiDecryptor::OnDecoderInitialized, + weak_ptr_factory_.GetWeakPtr(), + kAudio))) { base::ResetAndReturn(&audio_decoder_init_cb_).Run(false); return; } @@ -224,8 +281,12 @@ void PpapiDecryptor::InitializeVideoDecoder( const media::VideoDecoderConfig& config, const DecoderInitCB& init_cb) { if (!render_loop_proxy_->BelongsToCurrentThread()) { - render_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &PpapiDecryptor::InitializeVideoDecoder, weak_this_, config, init_cb)); + render_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PpapiDecryptor::InitializeVideoDecoder, + weak_ptr_factory_.GetWeakPtr(), + config, + init_cb)); return; } @@ -234,8 +295,11 @@ void PpapiDecryptor::InitializeVideoDecoder( DCHECK(config.IsValidConfig()); video_decoder_init_cb_ = init_cb; - if (!plugin_cdm_delegate_->InitializeVideoDecoder(config, base::Bind( - &PpapiDecryptor::OnDecoderInitialized, weak_this_, kVideo))) { + if (!CdmDelegate() || !CdmDelegate()->InitializeVideoDecoder( + config, + base::Bind(&PpapiDecryptor::OnDecoderInitialized, + weak_ptr_factory_.GetWeakPtr(), + kVideo))) { base::ResetAndReturn(&video_decoder_init_cb_).Run(false); return; } @@ -245,58 +309,69 @@ void PpapiDecryptor::DecryptAndDecodeAudio( const scoped_refptr<media::DecoderBuffer>& encrypted, const AudioDecodeCB& audio_decode_cb) { if (!render_loop_proxy_->BelongsToCurrentThread()) { - render_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &PpapiDecryptor::DecryptAndDecodeAudio, weak_this_, - encrypted, audio_decode_cb)); + render_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PpapiDecryptor::DecryptAndDecodeAudio, + weak_ptr_factory_.GetWeakPtr(), + encrypted, + audio_decode_cb)); return; } DVLOG(3) << __FUNCTION__; - if (!plugin_cdm_delegate_->DecryptAndDecodeAudio(encrypted, audio_decode_cb)) + if (!CdmDelegate() || + !CdmDelegate()->DecryptAndDecodeAudio(encrypted, audio_decode_cb)) { audio_decode_cb.Run(kError, AudioBuffers()); + } } void PpapiDecryptor::DecryptAndDecodeVideo( const scoped_refptr<media::DecoderBuffer>& encrypted, const VideoDecodeCB& video_decode_cb) { if (!render_loop_proxy_->BelongsToCurrentThread()) { - render_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &PpapiDecryptor::DecryptAndDecodeVideo, weak_this_, - encrypted, video_decode_cb)); + render_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PpapiDecryptor::DecryptAndDecodeVideo, + weak_ptr_factory_.GetWeakPtr(), + encrypted, + video_decode_cb)); return; } DVLOG(3) << __FUNCTION__; - if (!plugin_cdm_delegate_->DecryptAndDecodeVideo(encrypted, video_decode_cb)) + if (!CdmDelegate() || + !CdmDelegate()->DecryptAndDecodeVideo(encrypted, video_decode_cb)) { video_decode_cb.Run(kError, NULL); + } } void PpapiDecryptor::ResetDecoder(StreamType stream_type) { if (!render_loop_proxy_->BelongsToCurrentThread()) { - render_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &PpapiDecryptor::ResetDecoder, weak_this_, stream_type)); + render_loop_proxy_->PostTask(FROM_HERE, + base::Bind(&PpapiDecryptor::ResetDecoder, + weak_ptr_factory_.GetWeakPtr(), + stream_type)); return; } DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type; - plugin_cdm_delegate_->ResetDecoder(stream_type); + if (CdmDelegate()) + CdmDelegate()->ResetDecoder(stream_type); } void PpapiDecryptor::DeinitializeDecoder(StreamType stream_type) { if (!render_loop_proxy_->BelongsToCurrentThread()) { - render_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &PpapiDecryptor::DeinitializeDecoder, weak_this_, stream_type)); + render_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PpapiDecryptor::DeinitializeDecoder, + weak_ptr_factory_.GetWeakPtr(), + stream_type)); return; } DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type; - plugin_cdm_delegate_->DeinitializeDecoder(stream_type); -} - -void PpapiDecryptor::ReportFailureToCallPlugin(uint32 session_id) { - DCHECK(render_loop_proxy_->BelongsToCurrentThread()); - DVLOG(1) << "Failed to call plugin."; - session_error_cb_.Run(session_id, kUnknownError, 0); + if (CdmDelegate()) + CdmDelegate()->DeinitializeDecoder(stream_type); } void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type, @@ -316,34 +391,53 @@ void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type, } } -void PpapiDecryptor::OnSessionCreated(uint32 session_id, - const std::string& web_session_id) { +void PpapiDecryptor::OnSessionMessage(const std::string& web_session_id, + const std::vector<uint8>& message, + const GURL& destination_url) { DCHECK(render_loop_proxy_->BelongsToCurrentThread()); - session_created_cb_.Run(session_id, web_session_id); + session_message_cb_.Run(web_session_id, message, destination_url); } -void PpapiDecryptor::OnSessionMessage(uint32 session_id, - const std::vector<uint8>& message, - const std::string& destination_url) { +void PpapiDecryptor::OnSessionReady(const std::string& web_session_id) { DCHECK(render_loop_proxy_->BelongsToCurrentThread()); - session_message_cb_.Run(session_id, message, destination_url); + + ResumePlayback(); + session_ready_cb_.Run(web_session_id); +} + +void PpapiDecryptor::OnSessionClosed(const std::string& web_session_id) { + DCHECK(render_loop_proxy_->BelongsToCurrentThread()); + session_closed_cb_.Run(web_session_id); } -void PpapiDecryptor::OnSessionReady(uint32 session_id) { +void PpapiDecryptor::OnSessionError(const std::string& web_session_id, + MediaKeys::Exception exception_code, + uint32 system_code, + const std::string& error_description) { DCHECK(render_loop_proxy_->BelongsToCurrentThread()); - session_ready_cb_.Run(session_id); + session_error_cb_.Run( + web_session_id, exception_code, system_code, error_description); +} + +void PpapiDecryptor::ResumePlayback() { + // Based on the spec, we need to resume playback when update() completes + // successfully, or when a session is successfully loaded (triggered by + // OnSessionReady()). So we choose to call the NewKeyCBs here. + if (!new_audio_key_cb_.is_null()) + new_audio_key_cb_.Run(); + + if (!new_video_key_cb_.is_null()) + new_video_key_cb_.Run(); } -void PpapiDecryptor::OnSessionClosed(uint32 session_id) { +void PpapiDecryptor::OnFatalPluginError() { DCHECK(render_loop_proxy_->BelongsToCurrentThread()); - session_closed_cb_.Run(session_id); + pepper_cdm_wrapper_.reset(); } -void PpapiDecryptor::OnSessionError(uint32 session_id, - media::MediaKeys::KeyError error_code, - int system_code) { +ContentDecryptorDelegate* PpapiDecryptor::CdmDelegate() { DCHECK(render_loop_proxy_->BelongsToCurrentThread()); - session_error_cb_.Run(session_id, error_code, system_code); + return (pepper_cdm_wrapper_) ? pepper_cdm_wrapper_->GetCdmDelegate() : NULL; } } // namespace content |