media: Add trace event for pepper plugin (CDM) loading time.
[chromium-blink-merge.git] / content / renderer / media / crypto / ppapi_decryptor.cc
blob4b35c9975e834fa33cc0ab79952838d76e3ea9a5
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 "base/trace_event/trace_event.h"
15 #include "content/renderer/pepper/content_decryptor_delegate.h"
16 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
17 #include "media/base/audio_decoder_config.h"
18 #include "media/base/cdm_initialized_promise.h"
19 #include "media/base/cdm_key_information.h"
20 #include "media/base/data_buffer.h"
21 #include "media/base/decoder_buffer.h"
22 #include "media/base/key_systems.h"
23 #include "media/base/video_decoder_config.h"
24 #include "media/base/video_frame.h"
26 namespace content {
28 void PpapiDecryptor::Create(
29 const std::string& key_system,
30 const GURL& security_origin,
31 bool allow_distinctive_identifier,
32 bool allow_persistent_state,
33 const CreatePepperCdmCB& create_pepper_cdm_cb,
34 const media::SessionMessageCB& session_message_cb,
35 const media::SessionClosedCB& session_closed_cb,
36 const media::LegacySessionErrorCB& legacy_session_error_cb,
37 const media::SessionKeysChangeCB& session_keys_change_cb,
38 const media::SessionExpirationUpdateCB& session_expiration_update_cb,
39 const media::CdmCreatedCB& cdm_created_cb) {
40 std::string plugin_type = media::GetPepperType(key_system);
41 DCHECK(!plugin_type.empty());
43 scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper;
45 TRACE_EVENT0("media", "PpapiDecryptor::CreatePepperCDM");
46 pepper_cdm_wrapper = create_pepper_cdm_cb.Run(plugin_type, security_origin);
49 if (!pepper_cdm_wrapper) {
50 std::string message =
51 "Unable to create the CDM for the key system " + key_system + ".";
52 DLOG(ERROR) << message;
53 base::ThreadTaskRunnerHandle::Get()->PostTask(
54 FROM_HERE, base::Bind(cdm_created_cb, nullptr, message));
55 return;
58 scoped_ptr<PpapiDecryptor> ppapi_decryptor(
59 new PpapiDecryptor(pepper_cdm_wrapper.Pass(), session_message_cb,
60 session_closed_cb, legacy_session_error_cb,
61 session_keys_change_cb, session_expiration_update_cb));
63 // PpapiDecryptor ownership passed to the promise, but keep a copy in order
64 // to call InitializeCdm().
65 PpapiDecryptor* ppapi_decryptor_copy = ppapi_decryptor.get();
66 scoped_ptr<media::CdmInitializedPromise> promise(
67 new media::CdmInitializedPromise(cdm_created_cb, ppapi_decryptor.Pass()));
68 ppapi_decryptor_copy->InitializeCdm(key_system, allow_distinctive_identifier,
69 allow_persistent_state, promise.Pass());
72 PpapiDecryptor::PpapiDecryptor(
73 scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper,
74 const media::SessionMessageCB& session_message_cb,
75 const media::SessionClosedCB& session_closed_cb,
76 const media::LegacySessionErrorCB& legacy_session_error_cb,
77 const media::SessionKeysChangeCB& session_keys_change_cb,
78 const media::SessionExpirationUpdateCB& session_expiration_update_cb)
79 : pepper_cdm_wrapper_(pepper_cdm_wrapper.Pass()),
80 session_message_cb_(session_message_cb),
81 session_closed_cb_(session_closed_cb),
82 legacy_session_error_cb_(legacy_session_error_cb),
83 session_keys_change_cb_(session_keys_change_cb),
84 session_expiration_update_cb_(session_expiration_update_cb),
85 render_task_runner_(base::ThreadTaskRunnerHandle::Get()),
86 weak_ptr_factory_(this) {
87 DCHECK(pepper_cdm_wrapper_.get());
88 DCHECK(!session_message_cb_.is_null());
89 DCHECK(!session_closed_cb_.is_null());
90 DCHECK(!legacy_session_error_cb_.is_null());
91 DCHECK(!session_keys_change_cb.is_null());
92 DCHECK(!session_expiration_update_cb.is_null());
95 PpapiDecryptor::~PpapiDecryptor() {
96 pepper_cdm_wrapper_.reset();
99 void PpapiDecryptor::InitializeCdm(
100 const std::string& key_system,
101 bool allow_distinctive_identifier,
102 bool allow_persistent_state,
103 scoped_ptr<media::SimpleCdmPromise> promise) {
104 base::WeakPtr<PpapiDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr();
105 CdmDelegate()->Initialize(
106 key_system, allow_distinctive_identifier, allow_persistent_state,
107 base::Bind(&PpapiDecryptor::OnSessionMessage, weak_this),
108 base::Bind(&PpapiDecryptor::OnSessionClosed, weak_this),
109 base::Bind(&PpapiDecryptor::OnLegacySessionError, weak_this),
110 base::Bind(&PpapiDecryptor::OnSessionKeysChange, weak_this),
111 base::Bind(&PpapiDecryptor::OnSessionExpirationUpdate, weak_this),
112 base::Bind(&PpapiDecryptor::OnFatalPluginError, weak_this),
113 promise.Pass());
116 void PpapiDecryptor::SetServerCertificate(
117 const std::vector<uint8_t>& certificate,
118 scoped_ptr<media::SimpleCdmPromise> promise) {
119 DVLOG(2) << __FUNCTION__;
120 DCHECK(render_task_runner_->BelongsToCurrentThread());
122 if (!CdmDelegate()) {
123 promise->reject(INVALID_STATE_ERROR, 0, "CDM has failed.");
124 return;
127 CdmDelegate()->SetServerCertificate(certificate, promise.Pass());
130 void PpapiDecryptor::CreateSessionAndGenerateRequest(
131 SessionType session_type,
132 media::EmeInitDataType init_data_type,
133 const std::vector<uint8_t>& init_data,
134 scoped_ptr<media::NewSessionCdmPromise> promise) {
135 DVLOG(2) << __FUNCTION__;
136 DCHECK(render_task_runner_->BelongsToCurrentThread());
138 if (!CdmDelegate()) {
139 promise->reject(INVALID_STATE_ERROR, 0, "CDM has failed.");
140 return;
143 CdmDelegate()->CreateSessionAndGenerateRequest(session_type, init_data_type,
144 init_data, promise.Pass());
147 void PpapiDecryptor::LoadSession(
148 SessionType session_type,
149 const std::string& session_id,
150 scoped_ptr<media::NewSessionCdmPromise> promise) {
151 DVLOG(2) << __FUNCTION__;
152 DCHECK(render_task_runner_->BelongsToCurrentThread());
154 if (!CdmDelegate()) {
155 promise->reject(INVALID_STATE_ERROR, 0, "CDM has failed.");
156 return;
158 CdmDelegate()->LoadSession(session_type, session_id, promise.Pass());
161 void PpapiDecryptor::UpdateSession(
162 const std::string& session_id,
163 const std::vector<uint8_t>& response,
164 scoped_ptr<media::SimpleCdmPromise> promise) {
165 DCHECK(render_task_runner_->BelongsToCurrentThread());
167 if (!CdmDelegate()) {
168 promise->reject(INVALID_STATE_ERROR, 0, "CDM has failed.");
169 return;
171 CdmDelegate()->UpdateSession(session_id, response, promise.Pass());
174 void PpapiDecryptor::CloseSession(const std::string& session_id,
175 scoped_ptr<media::SimpleCdmPromise> promise) {
176 DCHECK(render_task_runner_->BelongsToCurrentThread());
178 if (!CdmDelegate()) {
179 promise->reject(INVALID_STATE_ERROR, 0, "CDM has failed.");
180 return;
183 CdmDelegate()->CloseSession(session_id, promise.Pass());
186 void PpapiDecryptor::RemoveSession(
187 const std::string& session_id,
188 scoped_ptr<media::SimpleCdmPromise> promise) {
189 DCHECK(render_task_runner_->BelongsToCurrentThread());
191 if (!CdmDelegate()) {
192 promise->reject(INVALID_STATE_ERROR, 0, "CDM has failed.");
193 return;
196 CdmDelegate()->RemoveSession(session_id, promise.Pass());
199 media::CdmContext* PpapiDecryptor::GetCdmContext() {
200 return this;
203 media::Decryptor* PpapiDecryptor::GetDecryptor() {
204 return this;
207 int PpapiDecryptor::GetCdmId() const {
208 return kInvalidCdmId;
211 void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type,
212 const NewKeyCB& new_key_cb) {
213 if (!render_task_runner_->BelongsToCurrentThread()) {
214 render_task_runner_->PostTask(
215 FROM_HERE,
216 base::Bind(&PpapiDecryptor::RegisterNewKeyCB,
217 weak_ptr_factory_.GetWeakPtr(), stream_type, new_key_cb));
218 return;
221 DVLOG(3) << __FUNCTION__ << " - stream_type: " << stream_type;
222 switch (stream_type) {
223 case kAudio:
224 new_audio_key_cb_ = new_key_cb;
225 break;
226 case kVideo:
227 new_video_key_cb_ = new_key_cb;
228 break;
229 default:
230 NOTREACHED();
234 void PpapiDecryptor::Decrypt(
235 StreamType stream_type,
236 const scoped_refptr<media::DecoderBuffer>& encrypted,
237 const DecryptCB& decrypt_cb) {
238 if (!render_task_runner_->BelongsToCurrentThread()) {
239 render_task_runner_->PostTask(
240 FROM_HERE,
241 base::Bind(&PpapiDecryptor::Decrypt, weak_ptr_factory_.GetWeakPtr(),
242 stream_type, encrypted, decrypt_cb));
243 return;
246 DVLOG(3) << __FUNCTION__ << " - stream_type: " << stream_type;
247 if (!CdmDelegate() ||
248 !CdmDelegate()->Decrypt(stream_type, encrypted, decrypt_cb)) {
249 decrypt_cb.Run(kError, NULL);
253 void PpapiDecryptor::CancelDecrypt(StreamType stream_type) {
254 if (!render_task_runner_->BelongsToCurrentThread()) {
255 render_task_runner_->PostTask(
256 FROM_HERE, base::Bind(&PpapiDecryptor::CancelDecrypt,
257 weak_ptr_factory_.GetWeakPtr(), stream_type));
258 return;
261 DVLOG(1) << __FUNCTION__ << " - stream_type: " << stream_type;
262 if (CdmDelegate())
263 CdmDelegate()->CancelDecrypt(stream_type);
266 void PpapiDecryptor::InitializeAudioDecoder(
267 const media::AudioDecoderConfig& config,
268 const DecoderInitCB& init_cb) {
269 if (!render_task_runner_->BelongsToCurrentThread()) {
270 render_task_runner_->PostTask(
271 FROM_HERE, base::Bind(&PpapiDecryptor::InitializeAudioDecoder,
272 weak_ptr_factory_.GetWeakPtr(), config, init_cb));
273 return;
276 DVLOG(2) << __FUNCTION__;
277 DCHECK(config.is_encrypted());
278 DCHECK(config.IsValidConfig());
280 audio_decoder_init_cb_ = init_cb;
281 if (!CdmDelegate() || !CdmDelegate()->InitializeAudioDecoder(
282 config,
283 base::Bind(&PpapiDecryptor::OnDecoderInitialized,
284 weak_ptr_factory_.GetWeakPtr(),
285 kAudio))) {
286 base::ResetAndReturn(&audio_decoder_init_cb_).Run(false);
287 return;
291 void PpapiDecryptor::InitializeVideoDecoder(
292 const media::VideoDecoderConfig& config,
293 const DecoderInitCB& init_cb) {
294 if (!render_task_runner_->BelongsToCurrentThread()) {
295 render_task_runner_->PostTask(
296 FROM_HERE, base::Bind(&PpapiDecryptor::InitializeVideoDecoder,
297 weak_ptr_factory_.GetWeakPtr(), config, init_cb));
298 return;
301 DVLOG(2) << __FUNCTION__;
302 DCHECK(config.is_encrypted());
303 DCHECK(config.IsValidConfig());
305 video_decoder_init_cb_ = init_cb;
306 if (!CdmDelegate() || !CdmDelegate()->InitializeVideoDecoder(
307 config,
308 base::Bind(&PpapiDecryptor::OnDecoderInitialized,
309 weak_ptr_factory_.GetWeakPtr(),
310 kVideo))) {
311 base::ResetAndReturn(&video_decoder_init_cb_).Run(false);
312 return;
316 void PpapiDecryptor::DecryptAndDecodeAudio(
317 const scoped_refptr<media::DecoderBuffer>& encrypted,
318 const AudioDecodeCB& audio_decode_cb) {
319 if (!render_task_runner_->BelongsToCurrentThread()) {
320 render_task_runner_->PostTask(
321 FROM_HERE,
322 base::Bind(&PpapiDecryptor::DecryptAndDecodeAudio,
323 weak_ptr_factory_.GetWeakPtr(), encrypted, audio_decode_cb));
324 return;
327 DVLOG(3) << __FUNCTION__;
328 if (!CdmDelegate() ||
329 !CdmDelegate()->DecryptAndDecodeAudio(encrypted, audio_decode_cb)) {
330 audio_decode_cb.Run(kError, AudioFrames());
334 void PpapiDecryptor::DecryptAndDecodeVideo(
335 const scoped_refptr<media::DecoderBuffer>& encrypted,
336 const VideoDecodeCB& video_decode_cb) {
337 if (!render_task_runner_->BelongsToCurrentThread()) {
338 render_task_runner_->PostTask(
339 FROM_HERE,
340 base::Bind(&PpapiDecryptor::DecryptAndDecodeVideo,
341 weak_ptr_factory_.GetWeakPtr(), encrypted, video_decode_cb));
342 return;
345 DVLOG(3) << __FUNCTION__;
346 if (!CdmDelegate() ||
347 !CdmDelegate()->DecryptAndDecodeVideo(encrypted, video_decode_cb)) {
348 video_decode_cb.Run(kError, NULL);
352 void PpapiDecryptor::ResetDecoder(StreamType stream_type) {
353 if (!render_task_runner_->BelongsToCurrentThread()) {
354 render_task_runner_->PostTask(
355 FROM_HERE, base::Bind(&PpapiDecryptor::ResetDecoder,
356 weak_ptr_factory_.GetWeakPtr(), stream_type));
357 return;
360 DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type;
361 if (CdmDelegate())
362 CdmDelegate()->ResetDecoder(stream_type);
365 void PpapiDecryptor::DeinitializeDecoder(StreamType stream_type) {
366 if (!render_task_runner_->BelongsToCurrentThread()) {
367 render_task_runner_->PostTask(
368 FROM_HERE, base::Bind(&PpapiDecryptor::DeinitializeDecoder,
369 weak_ptr_factory_.GetWeakPtr(), stream_type));
370 return;
373 DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type;
374 if (CdmDelegate())
375 CdmDelegate()->DeinitializeDecoder(stream_type);
378 void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type,
379 bool success) {
380 DCHECK(render_task_runner_->BelongsToCurrentThread());
381 switch (stream_type) {
382 case kAudio:
383 DCHECK(!audio_decoder_init_cb_.is_null());
384 base::ResetAndReturn(&audio_decoder_init_cb_).Run(success);
385 break;
386 case kVideo:
387 DCHECK(!video_decoder_init_cb_.is_null());
388 base::ResetAndReturn(&video_decoder_init_cb_).Run(success);
389 break;
390 default:
391 NOTREACHED();
395 void PpapiDecryptor::OnSessionMessage(const std::string& session_id,
396 MessageType message_type,
397 const std::vector<uint8_t>& message,
398 const GURL& legacy_destination_url) {
399 DCHECK(render_task_runner_->BelongsToCurrentThread());
400 session_message_cb_.Run(session_id, message_type, message,
401 legacy_destination_url);
404 void PpapiDecryptor::OnSessionKeysChange(const std::string& session_id,
405 bool has_additional_usable_key,
406 media::CdmKeysInfo keys_info) {
407 DCHECK(render_task_runner_->BelongsToCurrentThread());
409 // TODO(jrummell): Handling resume playback should be done in the media
410 // player, not in the Decryptors. http://crbug.com/413413.
411 if (has_additional_usable_key)
412 AttemptToResumePlayback();
414 session_keys_change_cb_.Run(session_id, has_additional_usable_key,
415 keys_info.Pass());
418 void PpapiDecryptor::OnSessionExpirationUpdate(
419 const std::string& session_id,
420 const base::Time& new_expiry_time) {
421 DCHECK(render_task_runner_->BelongsToCurrentThread());
422 session_expiration_update_cb_.Run(session_id, new_expiry_time);
425 void PpapiDecryptor::OnSessionClosed(const std::string& session_id) {
426 DCHECK(render_task_runner_->BelongsToCurrentThread());
427 session_closed_cb_.Run(session_id);
430 void PpapiDecryptor::OnLegacySessionError(
431 const std::string& session_id,
432 MediaKeys::Exception exception_code,
433 uint32_t system_code,
434 const std::string& error_description) {
435 DCHECK(render_task_runner_->BelongsToCurrentThread());
436 legacy_session_error_cb_.Run(session_id, exception_code, system_code,
437 error_description);
440 void PpapiDecryptor::AttemptToResumePlayback() {
441 if (!new_audio_key_cb_.is_null())
442 new_audio_key_cb_.Run();
444 if (!new_video_key_cb_.is_null())
445 new_video_key_cb_.Run();
448 void PpapiDecryptor::OnFatalPluginError() {
449 DCHECK(render_task_runner_->BelongsToCurrentThread());
450 pepper_cdm_wrapper_.reset();
453 ContentDecryptorDelegate* PpapiDecryptor::CdmDelegate() {
454 DCHECK(render_task_runner_->BelongsToCurrentThread());
455 return (pepper_cdm_wrapper_) ? pepper_cdm_wrapper_->GetCdmDelegate() : NULL;
458 } // namespace content