1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/media/crypto/ppapi_decryptor.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "content/renderer/media/crypto/key_systems.h"
14 #include "content/renderer/pepper/content_decryptor_delegate.h"
15 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
16 #include "media/base/audio_decoder_config.h"
17 #include "media/base/data_buffer.h"
18 #include "media/base/decoder_buffer.h"
19 #include "media/base/video_decoder_config.h"
20 #include "media/base/video_frame.h"
24 scoped_ptr<PpapiDecryptor> PpapiDecryptor::Create(
25 const std::string& key_system,
26 const GURL& security_origin,
27 const CreatePepperCdmCB& create_pepper_cdm_cb,
28 const media::SessionMessageCB& session_message_cb,
29 const media::SessionReadyCB& session_ready_cb,
30 const media::SessionClosedCB& session_closed_cb,
31 const media::SessionErrorCB& session_error_cb,
32 const media::SessionKeysChangeCB& session_keys_change_cb,
33 const media::SessionExpirationUpdateCB& session_expiration_update_cb) {
34 std::string plugin_type = GetPepperType(key_system);
35 DCHECK(!plugin_type.empty());
36 scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper =
37 create_pepper_cdm_cb.Run(plugin_type, security_origin);
38 if (!pepper_cdm_wrapper) {
39 DLOG(ERROR) << "Plugin instance creation failed.";
40 return scoped_ptr<PpapiDecryptor>();
43 return scoped_ptr<PpapiDecryptor>(
44 new PpapiDecryptor(key_system,
45 pepper_cdm_wrapper.Pass(),
50 session_keys_change_cb,
51 session_expiration_update_cb));
54 PpapiDecryptor::PpapiDecryptor(
55 const std::string& key_system,
56 scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper,
57 const media::SessionMessageCB& session_message_cb,
58 const media::SessionReadyCB& session_ready_cb,
59 const media::SessionClosedCB& session_closed_cb,
60 const media::SessionErrorCB& session_error_cb,
61 const media::SessionKeysChangeCB& session_keys_change_cb,
62 const media::SessionExpirationUpdateCB& session_expiration_update_cb)
63 : pepper_cdm_wrapper_(pepper_cdm_wrapper.Pass()),
64 session_message_cb_(session_message_cb),
65 session_ready_cb_(session_ready_cb),
66 session_closed_cb_(session_closed_cb),
67 session_error_cb_(session_error_cb),
68 session_keys_change_cb_(session_keys_change_cb),
69 session_expiration_update_cb_(session_expiration_update_cb),
70 render_loop_proxy_(base::MessageLoopProxy::current()),
71 weak_ptr_factory_(this) {
72 DCHECK(pepper_cdm_wrapper_.get());
73 DCHECK(!session_message_cb_.is_null());
74 DCHECK(!session_ready_cb_.is_null());
75 DCHECK(!session_closed_cb_.is_null());
76 DCHECK(!session_error_cb_.is_null());
77 DCHECK(!session_keys_change_cb.is_null());
78 DCHECK(!session_expiration_update_cb.is_null());
80 base::WeakPtr<PpapiDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr();
81 CdmDelegate()->Initialize(
83 base::Bind(&PpapiDecryptor::OnSessionMessage, weak_this),
84 base::Bind(&PpapiDecryptor::OnSessionReady, weak_this),
85 base::Bind(&PpapiDecryptor::OnSessionClosed, weak_this),
86 base::Bind(&PpapiDecryptor::OnSessionError, weak_this),
87 base::Bind(&PpapiDecryptor::OnSessionKeysChange, weak_this),
88 base::Bind(&PpapiDecryptor::OnSessionExpirationUpdate, weak_this),
89 base::Bind(&PpapiDecryptor::OnFatalPluginError, weak_this));
92 PpapiDecryptor::~PpapiDecryptor() {
93 pepper_cdm_wrapper_.reset();
96 void PpapiDecryptor::SetServerCertificate(
97 const uint8* certificate_data,
98 int certificate_data_length,
99 scoped_ptr<media::SimpleCdmPromise> promise) {
100 DVLOG(2) << __FUNCTION__;
101 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
103 if (!CdmDelegate()) {
104 promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
108 CdmDelegate()->SetServerCertificate(
109 certificate_data, certificate_data_length, promise.Pass());
112 void PpapiDecryptor::CreateSession(
113 const std::string& init_data_type,
114 const uint8* init_data,
115 int init_data_length,
116 SessionType session_type,
117 scoped_ptr<media::NewSessionCdmPromise> promise) {
118 DVLOG(2) << __FUNCTION__;
119 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
121 if (!CdmDelegate()) {
122 promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
126 CdmDelegate()->CreateSession(init_data_type,
133 void PpapiDecryptor::LoadSession(
134 const std::string& web_session_id,
135 scoped_ptr<media::NewSessionCdmPromise> promise) {
136 DVLOG(2) << __FUNCTION__;
137 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
139 if (!CdmDelegate()) {
140 promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
143 CdmDelegate()->LoadSession(web_session_id, promise.Pass());
146 void PpapiDecryptor::UpdateSession(
147 const std::string& web_session_id,
148 const uint8* response,
150 scoped_ptr<media::SimpleCdmPromise> promise) {
151 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
153 if (!CdmDelegate()) {
154 promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
157 CdmDelegate()->UpdateSession(web_session_id, response, response_length,
161 void PpapiDecryptor::CloseSession(const std::string& web_session_id,
162 scoped_ptr<media::SimpleCdmPromise> promise) {
163 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
165 if (!CdmDelegate()) {
166 promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
170 CdmDelegate()->CloseSession(web_session_id, promise.Pass());
173 void PpapiDecryptor::RemoveSession(
174 const std::string& web_session_id,
175 scoped_ptr<media::SimpleCdmPromise> promise) {
176 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
178 if (!CdmDelegate()) {
179 promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
183 CdmDelegate()->RemoveSession(web_session_id, promise.Pass());
186 void PpapiDecryptor::GetUsableKeyIds(const std::string& web_session_id,
187 scoped_ptr<media::KeyIdsPromise> promise) {
188 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
190 if (!CdmDelegate()) {
191 promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
195 CdmDelegate()->GetUsableKeyIds(web_session_id, promise.Pass());
198 media::Decryptor* PpapiDecryptor::GetDecryptor() {
202 void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type,
203 const NewKeyCB& new_key_cb) {
204 if (!render_loop_proxy_->BelongsToCurrentThread()) {
205 render_loop_proxy_->PostTask(FROM_HERE,
206 base::Bind(&PpapiDecryptor::RegisterNewKeyCB,
207 weak_ptr_factory_.GetWeakPtr(),
213 DVLOG(3) << __FUNCTION__ << " - stream_type: " << stream_type;
214 switch (stream_type) {
216 new_audio_key_cb_ = new_key_cb;
219 new_video_key_cb_ = new_key_cb;
226 void PpapiDecryptor::Decrypt(
227 StreamType stream_type,
228 const scoped_refptr<media::DecoderBuffer>& encrypted,
229 const DecryptCB& decrypt_cb) {
230 if (!render_loop_proxy_->BelongsToCurrentThread()) {
231 render_loop_proxy_->PostTask(FROM_HERE,
232 base::Bind(&PpapiDecryptor::Decrypt,
233 weak_ptr_factory_.GetWeakPtr(),
240 DVLOG(3) << __FUNCTION__ << " - stream_type: " << stream_type;
241 if (!CdmDelegate() ||
242 !CdmDelegate()->Decrypt(stream_type, encrypted, decrypt_cb)) {
243 decrypt_cb.Run(kError, NULL);
247 void PpapiDecryptor::CancelDecrypt(StreamType stream_type) {
248 if (!render_loop_proxy_->BelongsToCurrentThread()) {
249 render_loop_proxy_->PostTask(FROM_HERE,
250 base::Bind(&PpapiDecryptor::CancelDecrypt,
251 weak_ptr_factory_.GetWeakPtr(),
256 DVLOG(1) << __FUNCTION__ << " - stream_type: " << stream_type;
258 CdmDelegate()->CancelDecrypt(stream_type);
261 void PpapiDecryptor::InitializeAudioDecoder(
262 const media::AudioDecoderConfig& config,
263 const DecoderInitCB& init_cb) {
264 if (!render_loop_proxy_->BelongsToCurrentThread()) {
265 render_loop_proxy_->PostTask(
267 base::Bind(&PpapiDecryptor::InitializeAudioDecoder,
268 weak_ptr_factory_.GetWeakPtr(),
274 DVLOG(2) << __FUNCTION__;
275 DCHECK(config.is_encrypted());
276 DCHECK(config.IsValidConfig());
278 audio_decoder_init_cb_ = init_cb;
279 if (!CdmDelegate() || !CdmDelegate()->InitializeAudioDecoder(
281 base::Bind(&PpapiDecryptor::OnDecoderInitialized,
282 weak_ptr_factory_.GetWeakPtr(),
284 base::ResetAndReturn(&audio_decoder_init_cb_).Run(false);
289 void PpapiDecryptor::InitializeVideoDecoder(
290 const media::VideoDecoderConfig& config,
291 const DecoderInitCB& init_cb) {
292 if (!render_loop_proxy_->BelongsToCurrentThread()) {
293 render_loop_proxy_->PostTask(
295 base::Bind(&PpapiDecryptor::InitializeVideoDecoder,
296 weak_ptr_factory_.GetWeakPtr(),
302 DVLOG(2) << __FUNCTION__;
303 DCHECK(config.is_encrypted());
304 DCHECK(config.IsValidConfig());
306 video_decoder_init_cb_ = init_cb;
307 if (!CdmDelegate() || !CdmDelegate()->InitializeVideoDecoder(
309 base::Bind(&PpapiDecryptor::OnDecoderInitialized,
310 weak_ptr_factory_.GetWeakPtr(),
312 base::ResetAndReturn(&video_decoder_init_cb_).Run(false);
317 void PpapiDecryptor::DecryptAndDecodeAudio(
318 const scoped_refptr<media::DecoderBuffer>& encrypted,
319 const AudioDecodeCB& audio_decode_cb) {
320 if (!render_loop_proxy_->BelongsToCurrentThread()) {
321 render_loop_proxy_->PostTask(
323 base::Bind(&PpapiDecryptor::DecryptAndDecodeAudio,
324 weak_ptr_factory_.GetWeakPtr(),
330 DVLOG(3) << __FUNCTION__;
331 if (!CdmDelegate() ||
332 !CdmDelegate()->DecryptAndDecodeAudio(encrypted, audio_decode_cb)) {
333 audio_decode_cb.Run(kError, AudioBuffers());
337 void PpapiDecryptor::DecryptAndDecodeVideo(
338 const scoped_refptr<media::DecoderBuffer>& encrypted,
339 const VideoDecodeCB& video_decode_cb) {
340 if (!render_loop_proxy_->BelongsToCurrentThread()) {
341 render_loop_proxy_->PostTask(
343 base::Bind(&PpapiDecryptor::DecryptAndDecodeVideo,
344 weak_ptr_factory_.GetWeakPtr(),
350 DVLOG(3) << __FUNCTION__;
351 if (!CdmDelegate() ||
352 !CdmDelegate()->DecryptAndDecodeVideo(encrypted, video_decode_cb)) {
353 video_decode_cb.Run(kError, NULL);
357 void PpapiDecryptor::ResetDecoder(StreamType stream_type) {
358 if (!render_loop_proxy_->BelongsToCurrentThread()) {
359 render_loop_proxy_->PostTask(FROM_HERE,
360 base::Bind(&PpapiDecryptor::ResetDecoder,
361 weak_ptr_factory_.GetWeakPtr(),
366 DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type;
368 CdmDelegate()->ResetDecoder(stream_type);
371 void PpapiDecryptor::DeinitializeDecoder(StreamType stream_type) {
372 if (!render_loop_proxy_->BelongsToCurrentThread()) {
373 render_loop_proxy_->PostTask(
375 base::Bind(&PpapiDecryptor::DeinitializeDecoder,
376 weak_ptr_factory_.GetWeakPtr(),
381 DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type;
383 CdmDelegate()->DeinitializeDecoder(stream_type);
386 void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type,
388 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
389 switch (stream_type) {
391 DCHECK(!audio_decoder_init_cb_.is_null());
392 base::ResetAndReturn(&audio_decoder_init_cb_).Run(success);
395 DCHECK(!video_decoder_init_cb_.is_null());
396 base::ResetAndReturn(&video_decoder_init_cb_).Run(success);
403 void PpapiDecryptor::OnSessionMessage(const std::string& web_session_id,
404 const std::vector<uint8>& message,
405 const GURL& destination_url) {
406 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
407 session_message_cb_.Run(web_session_id, message, destination_url);
410 void PpapiDecryptor::OnSessionKeysChange(const std::string& web_session_id,
411 bool has_additional_usable_key) {
412 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
414 // TODO(jrummell): Handling resume playback should be done in the media
415 // player, not in the Decryptors. http://crbug.com/413413.
416 if (has_additional_usable_key)
417 AttemptToResumePlayback();
419 session_keys_change_cb_.Run(web_session_id, has_additional_usable_key);
422 void PpapiDecryptor::OnSessionExpirationUpdate(
423 const std::string& web_session_id,
424 const base::Time& new_expiry_time) {
425 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
426 session_expiration_update_cb_.Run(web_session_id, new_expiry_time);
429 void PpapiDecryptor::OnSessionReady(const std::string& web_session_id) {
430 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
431 session_ready_cb_.Run(web_session_id);
434 void PpapiDecryptor::OnSessionClosed(const std::string& web_session_id) {
435 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
436 session_closed_cb_.Run(web_session_id);
439 void PpapiDecryptor::OnSessionError(const std::string& web_session_id,
440 MediaKeys::Exception exception_code,
442 const std::string& error_description) {
443 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
444 session_error_cb_.Run(
445 web_session_id, exception_code, system_code, error_description);
448 void PpapiDecryptor::AttemptToResumePlayback() {
449 if (!new_audio_key_cb_.is_null())
450 new_audio_key_cb_.Run();
452 if (!new_video_key_cb_.is_null())
453 new_video_key_cb_.Run();
456 void PpapiDecryptor::OnFatalPluginError() {
457 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
458 pepper_cdm_wrapper_.reset();
461 ContentDecryptorDelegate* PpapiDecryptor::CdmDelegate() {
462 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
463 return (pepper_cdm_wrapper_) ? pepper_cdm_wrapper_->GetCdmDelegate() : NULL;
466 } // namespace content