Roll src/third_party/WebKit d10c917:a1123a1 (svn 198729:198730)
[chromium-blink-merge.git] / content / renderer / media / crypto / ppapi_decryptor.cc
blob099c7ae103fde27ab9deecc3701581a8b94a2d9c
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"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/thread_task_runner_handle.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/cdm_initialized_promise.h"
18 #include "media/base/cdm_key_information.h"
19 #include "media/base/data_buffer.h"
20 #include "media/base/decoder_buffer.h"
21 #include "media/base/key_systems.h"
22 #include "media/base/video_decoder_config.h"
23 #include "media/base/video_frame.h"
25 namespace content {
27 void PpapiDecryptor::Create(
28 const std::string& key_system,
29 const GURL& security_origin,
30 bool allow_distinctive_identifier,
31 bool allow_persistent_state,
32 const CreatePepperCdmCB& create_pepper_cdm_cb,
33 const media::SessionMessageCB& session_message_cb,
34 const media::SessionClosedCB& session_closed_cb,
35 const media::LegacySessionErrorCB& legacy_session_error_cb,
36 const media::SessionKeysChangeCB& session_keys_change_cb,
37 const media::SessionExpirationUpdateCB& session_expiration_update_cb,
38 const media::CdmCreatedCB& cdm_created_cb) {
39 std::string plugin_type = media::GetPepperType(key_system);
40 DCHECK(!plugin_type.empty());
41 scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper =
42 create_pepper_cdm_cb.Run(plugin_type, security_origin);
43 if (!pepper_cdm_wrapper) {
44 std::string message =
45 "Unable to create the CDM for the key system " + key_system + ".";
46 DLOG(ERROR) << message;
47 base::ThreadTaskRunnerHandle::Get()->PostTask(
48 FROM_HERE, base::Bind(cdm_created_cb, nullptr, message));
49 return;
52 scoped_ptr<PpapiDecryptor> ppapi_decryptor(
53 new PpapiDecryptor(pepper_cdm_wrapper.Pass(), session_message_cb,
54 session_closed_cb, legacy_session_error_cb,
55 session_keys_change_cb, session_expiration_update_cb));
57 // PpapiDecryptor ownership passed to the promise, but keep a copy in order
58 // to call InitializeCdm().
59 PpapiDecryptor* ppapi_decryptor_copy = ppapi_decryptor.get();
60 scoped_ptr<media::CdmInitializedPromise> promise(
61 new media::CdmInitializedPromise(cdm_created_cb, ppapi_decryptor.Pass()));
62 ppapi_decryptor_copy->InitializeCdm(key_system, allow_distinctive_identifier,
63 allow_persistent_state, promise.Pass());
66 PpapiDecryptor::PpapiDecryptor(
67 scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper,
68 const media::SessionMessageCB& session_message_cb,
69 const media::SessionClosedCB& session_closed_cb,
70 const media::LegacySessionErrorCB& legacy_session_error_cb,
71 const media::SessionKeysChangeCB& session_keys_change_cb,
72 const media::SessionExpirationUpdateCB& session_expiration_update_cb)
73 : pepper_cdm_wrapper_(pepper_cdm_wrapper.Pass()),
74 session_message_cb_(session_message_cb),
75 session_closed_cb_(session_closed_cb),
76 legacy_session_error_cb_(legacy_session_error_cb),
77 session_keys_change_cb_(session_keys_change_cb),
78 session_expiration_update_cb_(session_expiration_update_cb),
79 render_task_runner_(base::ThreadTaskRunnerHandle::Get()),
80 weak_ptr_factory_(this) {
81 DCHECK(pepper_cdm_wrapper_.get());
82 DCHECK(!session_message_cb_.is_null());
83 DCHECK(!session_closed_cb_.is_null());
84 DCHECK(!legacy_session_error_cb_.is_null());
85 DCHECK(!session_keys_change_cb.is_null());
86 DCHECK(!session_expiration_update_cb.is_null());
89 PpapiDecryptor::~PpapiDecryptor() {
90 pepper_cdm_wrapper_.reset();
93 void PpapiDecryptor::InitializeCdm(
94 const std::string& key_system,
95 bool allow_distinctive_identifier,
96 bool allow_persistent_state,
97 scoped_ptr<media::SimpleCdmPromise> promise) {
98 base::WeakPtr<PpapiDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr();
99 CdmDelegate()->Initialize(
100 key_system, allow_distinctive_identifier, allow_persistent_state,
101 base::Bind(&PpapiDecryptor::OnSessionMessage, weak_this),
102 base::Bind(&PpapiDecryptor::OnSessionClosed, weak_this),
103 base::Bind(&PpapiDecryptor::OnLegacySessionError, weak_this),
104 base::Bind(&PpapiDecryptor::OnSessionKeysChange, weak_this),
105 base::Bind(&PpapiDecryptor::OnSessionExpirationUpdate, weak_this),
106 base::Bind(&PpapiDecryptor::OnFatalPluginError, weak_this),
107 promise.Pass());
110 void PpapiDecryptor::SetServerCertificate(
111 const std::vector<uint8_t>& certificate,
112 scoped_ptr<media::SimpleCdmPromise> promise) {
113 DVLOG(2) << __FUNCTION__;
114 DCHECK(render_task_runner_->BelongsToCurrentThread());
116 if (!CdmDelegate()) {
117 promise->reject(INVALID_STATE_ERROR, 0, "CDM has failed.");
118 return;
121 CdmDelegate()->SetServerCertificate(certificate, promise.Pass());
124 void PpapiDecryptor::CreateSessionAndGenerateRequest(
125 SessionType session_type,
126 media::EmeInitDataType init_data_type,
127 const std::vector<uint8_t>& init_data,
128 scoped_ptr<media::NewSessionCdmPromise> promise) {
129 DVLOG(2) << __FUNCTION__;
130 DCHECK(render_task_runner_->BelongsToCurrentThread());
132 if (!CdmDelegate()) {
133 promise->reject(INVALID_STATE_ERROR, 0, "CDM has failed.");
134 return;
137 CdmDelegate()->CreateSessionAndGenerateRequest(session_type, init_data_type,
138 init_data, promise.Pass());
141 void PpapiDecryptor::LoadSession(
142 SessionType session_type,
143 const std::string& session_id,
144 scoped_ptr<media::NewSessionCdmPromise> promise) {
145 DVLOG(2) << __FUNCTION__;
146 DCHECK(render_task_runner_->BelongsToCurrentThread());
148 if (!CdmDelegate()) {
149 promise->reject(INVALID_STATE_ERROR, 0, "CDM has failed.");
150 return;
152 CdmDelegate()->LoadSession(session_type, session_id, promise.Pass());
155 void PpapiDecryptor::UpdateSession(
156 const std::string& session_id,
157 const std::vector<uint8_t>& response,
158 scoped_ptr<media::SimpleCdmPromise> promise) {
159 DCHECK(render_task_runner_->BelongsToCurrentThread());
161 if (!CdmDelegate()) {
162 promise->reject(INVALID_STATE_ERROR, 0, "CDM has failed.");
163 return;
165 CdmDelegate()->UpdateSession(session_id, response, promise.Pass());
168 void PpapiDecryptor::CloseSession(const std::string& session_id,
169 scoped_ptr<media::SimpleCdmPromise> promise) {
170 DCHECK(render_task_runner_->BelongsToCurrentThread());
172 if (!CdmDelegate()) {
173 promise->reject(INVALID_STATE_ERROR, 0, "CDM has failed.");
174 return;
177 CdmDelegate()->CloseSession(session_id, promise.Pass());
180 void PpapiDecryptor::RemoveSession(
181 const std::string& session_id,
182 scoped_ptr<media::SimpleCdmPromise> promise) {
183 DCHECK(render_task_runner_->BelongsToCurrentThread());
185 if (!CdmDelegate()) {
186 promise->reject(INVALID_STATE_ERROR, 0, "CDM has failed.");
187 return;
190 CdmDelegate()->RemoveSession(session_id, promise.Pass());
193 media::CdmContext* PpapiDecryptor::GetCdmContext() {
194 return this;
197 media::Decryptor* PpapiDecryptor::GetDecryptor() {
198 return this;
201 int PpapiDecryptor::GetCdmId() const {
202 return kInvalidCdmId;
205 void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type,
206 const NewKeyCB& new_key_cb) {
207 if (!render_task_runner_->BelongsToCurrentThread()) {
208 render_task_runner_->PostTask(
209 FROM_HERE,
210 base::Bind(&PpapiDecryptor::RegisterNewKeyCB,
211 weak_ptr_factory_.GetWeakPtr(), stream_type, new_key_cb));
212 return;
215 DVLOG(3) << __FUNCTION__ << " - stream_type: " << stream_type;
216 switch (stream_type) {
217 case kAudio:
218 new_audio_key_cb_ = new_key_cb;
219 break;
220 case kVideo:
221 new_video_key_cb_ = new_key_cb;
222 break;
223 default:
224 NOTREACHED();
228 void PpapiDecryptor::Decrypt(
229 StreamType stream_type,
230 const scoped_refptr<media::DecoderBuffer>& encrypted,
231 const DecryptCB& decrypt_cb) {
232 if (!render_task_runner_->BelongsToCurrentThread()) {
233 render_task_runner_->PostTask(
234 FROM_HERE,
235 base::Bind(&PpapiDecryptor::Decrypt, weak_ptr_factory_.GetWeakPtr(),
236 stream_type, encrypted, decrypt_cb));
237 return;
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_task_runner_->BelongsToCurrentThread()) {
249 render_task_runner_->PostTask(
250 FROM_HERE, base::Bind(&PpapiDecryptor::CancelDecrypt,
251 weak_ptr_factory_.GetWeakPtr(), stream_type));
252 return;
255 DVLOG(1) << __FUNCTION__ << " - stream_type: " << stream_type;
256 if (CdmDelegate())
257 CdmDelegate()->CancelDecrypt(stream_type);
260 void PpapiDecryptor::InitializeAudioDecoder(
261 const media::AudioDecoderConfig& config,
262 const DecoderInitCB& init_cb) {
263 if (!render_task_runner_->BelongsToCurrentThread()) {
264 render_task_runner_->PostTask(
265 FROM_HERE, base::Bind(&PpapiDecryptor::InitializeAudioDecoder,
266 weak_ptr_factory_.GetWeakPtr(), config, init_cb));
267 return;
270 DVLOG(2) << __FUNCTION__;
271 DCHECK(config.is_encrypted());
272 DCHECK(config.IsValidConfig());
274 audio_decoder_init_cb_ = init_cb;
275 if (!CdmDelegate() || !CdmDelegate()->InitializeAudioDecoder(
276 config,
277 base::Bind(&PpapiDecryptor::OnDecoderInitialized,
278 weak_ptr_factory_.GetWeakPtr(),
279 kAudio))) {
280 base::ResetAndReturn(&audio_decoder_init_cb_).Run(false);
281 return;
285 void PpapiDecryptor::InitializeVideoDecoder(
286 const media::VideoDecoderConfig& config,
287 const DecoderInitCB& init_cb) {
288 if (!render_task_runner_->BelongsToCurrentThread()) {
289 render_task_runner_->PostTask(
290 FROM_HERE, base::Bind(&PpapiDecryptor::InitializeVideoDecoder,
291 weak_ptr_factory_.GetWeakPtr(), config, init_cb));
292 return;
295 DVLOG(2) << __FUNCTION__;
296 DCHECK(config.is_encrypted());
297 DCHECK(config.IsValidConfig());
299 video_decoder_init_cb_ = init_cb;
300 if (!CdmDelegate() || !CdmDelegate()->InitializeVideoDecoder(
301 config,
302 base::Bind(&PpapiDecryptor::OnDecoderInitialized,
303 weak_ptr_factory_.GetWeakPtr(),
304 kVideo))) {
305 base::ResetAndReturn(&video_decoder_init_cb_).Run(false);
306 return;
310 void PpapiDecryptor::DecryptAndDecodeAudio(
311 const scoped_refptr<media::DecoderBuffer>& encrypted,
312 const AudioDecodeCB& audio_decode_cb) {
313 if (!render_task_runner_->BelongsToCurrentThread()) {
314 render_task_runner_->PostTask(
315 FROM_HERE,
316 base::Bind(&PpapiDecryptor::DecryptAndDecodeAudio,
317 weak_ptr_factory_.GetWeakPtr(), encrypted, audio_decode_cb));
318 return;
321 DVLOG(3) << __FUNCTION__;
322 if (!CdmDelegate() ||
323 !CdmDelegate()->DecryptAndDecodeAudio(encrypted, audio_decode_cb)) {
324 audio_decode_cb.Run(kError, AudioFrames());
328 void PpapiDecryptor::DecryptAndDecodeVideo(
329 const scoped_refptr<media::DecoderBuffer>& encrypted,
330 const VideoDecodeCB& video_decode_cb) {
331 if (!render_task_runner_->BelongsToCurrentThread()) {
332 render_task_runner_->PostTask(
333 FROM_HERE,
334 base::Bind(&PpapiDecryptor::DecryptAndDecodeVideo,
335 weak_ptr_factory_.GetWeakPtr(), encrypted, video_decode_cb));
336 return;
339 DVLOG(3) << __FUNCTION__;
340 if (!CdmDelegate() ||
341 !CdmDelegate()->DecryptAndDecodeVideo(encrypted, video_decode_cb)) {
342 video_decode_cb.Run(kError, NULL);
346 void PpapiDecryptor::ResetDecoder(StreamType stream_type) {
347 if (!render_task_runner_->BelongsToCurrentThread()) {
348 render_task_runner_->PostTask(
349 FROM_HERE, base::Bind(&PpapiDecryptor::ResetDecoder,
350 weak_ptr_factory_.GetWeakPtr(), stream_type));
351 return;
354 DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type;
355 if (CdmDelegate())
356 CdmDelegate()->ResetDecoder(stream_type);
359 void PpapiDecryptor::DeinitializeDecoder(StreamType stream_type) {
360 if (!render_task_runner_->BelongsToCurrentThread()) {
361 render_task_runner_->PostTask(
362 FROM_HERE, base::Bind(&PpapiDecryptor::DeinitializeDecoder,
363 weak_ptr_factory_.GetWeakPtr(), stream_type));
364 return;
367 DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type;
368 if (CdmDelegate())
369 CdmDelegate()->DeinitializeDecoder(stream_type);
372 void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type,
373 bool success) {
374 DCHECK(render_task_runner_->BelongsToCurrentThread());
375 switch (stream_type) {
376 case kAudio:
377 DCHECK(!audio_decoder_init_cb_.is_null());
378 base::ResetAndReturn(&audio_decoder_init_cb_).Run(success);
379 break;
380 case kVideo:
381 DCHECK(!video_decoder_init_cb_.is_null());
382 base::ResetAndReturn(&video_decoder_init_cb_).Run(success);
383 break;
384 default:
385 NOTREACHED();
389 void PpapiDecryptor::OnSessionMessage(const std::string& session_id,
390 MessageType message_type,
391 const std::vector<uint8_t>& message,
392 const GURL& legacy_destination_url) {
393 DCHECK(render_task_runner_->BelongsToCurrentThread());
394 session_message_cb_.Run(session_id, message_type, message,
395 legacy_destination_url);
398 void PpapiDecryptor::OnSessionKeysChange(const std::string& session_id,
399 bool has_additional_usable_key,
400 media::CdmKeysInfo keys_info) {
401 DCHECK(render_task_runner_->BelongsToCurrentThread());
403 // TODO(jrummell): Handling resume playback should be done in the media
404 // player, not in the Decryptors. http://crbug.com/413413.
405 if (has_additional_usable_key)
406 AttemptToResumePlayback();
408 session_keys_change_cb_.Run(session_id, has_additional_usable_key,
409 keys_info.Pass());
412 void PpapiDecryptor::OnSessionExpirationUpdate(
413 const std::string& session_id,
414 const base::Time& new_expiry_time) {
415 DCHECK(render_task_runner_->BelongsToCurrentThread());
416 session_expiration_update_cb_.Run(session_id, new_expiry_time);
419 void PpapiDecryptor::OnSessionClosed(const std::string& session_id) {
420 DCHECK(render_task_runner_->BelongsToCurrentThread());
421 session_closed_cb_.Run(session_id);
424 void PpapiDecryptor::OnLegacySessionError(
425 const std::string& session_id,
426 MediaKeys::Exception exception_code,
427 uint32_t system_code,
428 const std::string& error_description) {
429 DCHECK(render_task_runner_->BelongsToCurrentThread());
430 legacy_session_error_cb_.Run(session_id, exception_code, system_code,
431 error_description);
434 void PpapiDecryptor::AttemptToResumePlayback() {
435 if (!new_audio_key_cb_.is_null())
436 new_audio_key_cb_.Run();
438 if (!new_video_key_cb_.is_null())
439 new_video_key_cb_.Run();
442 void PpapiDecryptor::OnFatalPluginError() {
443 DCHECK(render_task_runner_->BelongsToCurrentThread());
444 pepper_cdm_wrapper_.reset();
447 ContentDecryptorDelegate* PpapiDecryptor::CdmDelegate() {
448 DCHECK(render_task_runner_->BelongsToCurrentThread());
449 return (pepper_cdm_wrapper_) ? pepper_cdm_wrapper_->GetCdmDelegate() : NULL;
452 } // namespace content