1 // Copyright (c) 2012 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 "webkit/media/crypto/ppapi_decryptor.h"
10 #include "base/callback_helpers.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/message_loop.h"
14 #include "base/message_loop_proxy.h"
15 #include "media/base/audio_decoder_config.h"
16 #include "media/base/data_buffer.h"
17 #include "media/base/decoder_buffer.h"
18 #include "media/base/video_decoder_config.h"
19 #include "media/base/video_frame.h"
20 #include "webkit/media/crypto/key_systems.h"
21 #include "webkit/plugins/ppapi/content_decryptor_delegate.h"
22 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
24 namespace webkit_media
{
26 PpapiDecryptor::PpapiDecryptor(
27 const scoped_refptr
<webkit::ppapi::PluginInstance
>& plugin_instance
,
28 const media::KeyAddedCB
& key_added_cb
,
29 const media::KeyErrorCB
& key_error_cb
,
30 const media::KeyMessageCB
& key_message_cb
,
31 const media::NeedKeyCB
& need_key_cb
)
32 : plugin_instance_(plugin_instance
),
33 key_added_cb_(key_added_cb
),
34 key_error_cb_(key_error_cb
),
35 key_message_cb_(key_message_cb
),
36 need_key_cb_(need_key_cb
),
37 plugin_cdm_delegate_(NULL
),
38 render_loop_proxy_(base::MessageLoopProxy::current()),
39 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
40 weak_this_(weak_ptr_factory_
.GetWeakPtr()) {
41 DCHECK(plugin_instance_
);
44 PpapiDecryptor::~PpapiDecryptor() {
45 plugin_cdm_delegate_
= NULL
;
46 plugin_instance_
= NULL
;
49 bool PpapiDecryptor::GenerateKeyRequest(const std::string
& key_system
,
50 const std::string
& type
,
51 const uint8
* init_data
,
52 int init_data_length
) {
53 DVLOG(2) << "GenerateKeyRequest()";
54 DCHECK(render_loop_proxy_
->BelongsToCurrentThread());
56 if (!plugin_cdm_delegate_
) {
57 plugin_cdm_delegate_
= plugin_instance_
->GetContentDecryptorDelegate();
58 if (!plugin_cdm_delegate_
) {
59 DVLOG(1) << "PpapiDecryptor: plugin cdm delegate creation failed.";
62 plugin_cdm_delegate_
->SetKeyEventCallbacks(
63 base::Bind(&PpapiDecryptor::KeyAdded
, weak_this_
),
64 base::Bind(&PpapiDecryptor::KeyError
, weak_this_
),
65 base::Bind(&PpapiDecryptor::KeyMessage
, weak_this_
),
66 base::Bind(&PpapiDecryptor::NeedKey
, weak_this_
));
69 if (!plugin_cdm_delegate_
->GenerateKeyRequest(
70 key_system
, type
, init_data
, init_data_length
)) {
71 ReportFailureToCallPlugin(key_system
, std::string());
78 void PpapiDecryptor::AddKey(const std::string
& key_system
,
81 const uint8
* init_data
,
83 const std::string
& session_id
) {
84 DVLOG(2) << "AddKey()";
85 DCHECK(render_loop_proxy_
->BelongsToCurrentThread());
87 if (!plugin_cdm_delegate_
->AddKey(
88 session_id
, key
, key_length
, init_data
, init_data_length
)) {
89 ReportFailureToCallPlugin(key_system
, session_id
);
92 if (!new_audio_key_cb_
.is_null())
93 new_audio_key_cb_
.Run();
95 if (!new_video_key_cb_
.is_null())
96 new_video_key_cb_
.Run();
99 void PpapiDecryptor::CancelKeyRequest(const std::string
& key_system
,
100 const std::string
& session_id
) {
101 DVLOG(2) << "CancelKeyRequest()";
102 DCHECK(render_loop_proxy_
->BelongsToCurrentThread());
104 if (!plugin_cdm_delegate_
->CancelKeyRequest(session_id
))
105 ReportFailureToCallPlugin(key_system
, session_id
);
108 void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type
,
109 const NewKeyCB
& new_key_cb
) {
110 switch (stream_type
) {
112 new_audio_key_cb_
= new_key_cb
;
115 new_video_key_cb_
= new_key_cb
;
122 void PpapiDecryptor::Decrypt(
123 StreamType stream_type
,
124 const scoped_refptr
<media::DecoderBuffer
>& encrypted
,
125 const DecryptCB
& decrypt_cb
) {
126 if (!render_loop_proxy_
->BelongsToCurrentThread()) {
127 render_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
128 &PpapiDecryptor::Decrypt
, weak_this_
,
129 stream_type
, encrypted
, decrypt_cb
));
133 DVLOG(3) << "Decrypt() - stream_type: " << stream_type
;
134 if (!plugin_cdm_delegate_
->Decrypt(stream_type
, encrypted
, decrypt_cb
))
135 decrypt_cb
.Run(kError
, NULL
);
138 void PpapiDecryptor::CancelDecrypt(StreamType stream_type
) {
139 DVLOG(1) << "CancelDecrypt() - stream_type: " << stream_type
;
140 plugin_cdm_delegate_
->CancelDecrypt(stream_type
);
143 void PpapiDecryptor::InitializeAudioDecoder(
144 const media::AudioDecoderConfig
& config
,
145 const DecoderInitCB
& init_cb
) {
146 if (!render_loop_proxy_
->BelongsToCurrentThread()) {
147 render_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
148 &PpapiDecryptor::InitializeAudioDecoder
, weak_this_
, config
, init_cb
));
152 DVLOG(2) << "InitializeAudioDecoder()";
153 DCHECK(config
.is_encrypted());
154 DCHECK(config
.IsValidConfig());
156 audio_decoder_init_cb_
= init_cb
;
157 if (!plugin_cdm_delegate_
->InitializeAudioDecoder(config
, base::Bind(
158 &PpapiDecryptor::OnDecoderInitialized
, weak_this_
, kAudio
))) {
159 base::ResetAndReturn(&audio_decoder_init_cb_
).Run(false);
164 void PpapiDecryptor::InitializeVideoDecoder(
165 const media::VideoDecoderConfig
& config
,
166 const DecoderInitCB
& init_cb
) {
167 if (!render_loop_proxy_
->BelongsToCurrentThread()) {
168 render_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
169 &PpapiDecryptor::InitializeVideoDecoder
, weak_this_
, config
, init_cb
));
173 DVLOG(2) << "InitializeVideoDecoder()";
174 DCHECK(config
.is_encrypted());
175 DCHECK(config
.IsValidConfig());
177 video_decoder_init_cb_
= init_cb
;
178 if (!plugin_cdm_delegate_
->InitializeVideoDecoder(config
, base::Bind(
179 &PpapiDecryptor::OnDecoderInitialized
, weak_this_
, kVideo
))) {
180 base::ResetAndReturn(&video_decoder_init_cb_
).Run(false);
185 void PpapiDecryptor::DecryptAndDecodeAudio(
186 const scoped_refptr
<media::DecoderBuffer
>& encrypted
,
187 const AudioDecodeCB
& audio_decode_cb
) {
188 if (!render_loop_proxy_
->BelongsToCurrentThread()) {
189 render_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
190 &PpapiDecryptor::DecryptAndDecodeAudio
, weak_this_
,
191 encrypted
, audio_decode_cb
));
195 DVLOG(3) << "DecryptAndDecodeAudio()";
196 if (!plugin_cdm_delegate_
->DecryptAndDecodeAudio(encrypted
, audio_decode_cb
))
197 audio_decode_cb
.Run(kError
, AudioBuffers());
200 void PpapiDecryptor::DecryptAndDecodeVideo(
201 const scoped_refptr
<media::DecoderBuffer
>& encrypted
,
202 const VideoDecodeCB
& video_decode_cb
) {
203 if (!render_loop_proxy_
->BelongsToCurrentThread()) {
204 render_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
205 &PpapiDecryptor::DecryptAndDecodeVideo
, weak_this_
,
206 encrypted
, video_decode_cb
));
210 DVLOG(3) << "DecryptAndDecodeVideo()";
211 if (!plugin_cdm_delegate_
->DecryptAndDecodeVideo(encrypted
, video_decode_cb
))
212 video_decode_cb
.Run(kError
, NULL
);
215 void PpapiDecryptor::ResetDecoder(StreamType stream_type
) {
216 if (!render_loop_proxy_
->BelongsToCurrentThread()) {
217 render_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
218 &PpapiDecryptor::ResetDecoder
, weak_this_
, stream_type
));
222 DVLOG(2) << "ResetDecoder() - stream_type: " << stream_type
;
223 plugin_cdm_delegate_
->ResetDecoder(stream_type
);
226 void PpapiDecryptor::DeinitializeDecoder(StreamType stream_type
) {
227 if (!render_loop_proxy_
->BelongsToCurrentThread()) {
228 render_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
229 &PpapiDecryptor::DeinitializeDecoder
, weak_this_
, stream_type
));
233 DVLOG(2) << "DeinitializeDecoder() - stream_type: " << stream_type
;
234 plugin_cdm_delegate_
->DeinitializeDecoder(stream_type
);
237 void PpapiDecryptor::ReportFailureToCallPlugin(const std::string
& key_system
,
238 const std::string
& session_id
) {
239 DVLOG(1) << "Failed to call plugin.";
240 key_error_cb_
.Run(key_system
, session_id
, kUnknownError
, 0);
243 void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type
,
245 switch (stream_type
) {
247 DCHECK(!audio_decoder_init_cb_
.is_null());
248 base::ResetAndReturn(&audio_decoder_init_cb_
).Run(success
);
251 DCHECK(!video_decoder_init_cb_
.is_null());
252 base::ResetAndReturn(&video_decoder_init_cb_
).Run(success
);
259 void PpapiDecryptor::KeyAdded(const std::string
& key_system
,
260 const std::string
& session_id
) {
261 DCHECK(render_loop_proxy_
->BelongsToCurrentThread());
262 key_added_cb_
.Run(key_system
, session_id
);
265 void PpapiDecryptor::KeyError(const std::string
& key_system
,
266 const std::string
& session_id
,
267 media::Decryptor::KeyError error_code
,
269 DCHECK(render_loop_proxy_
->BelongsToCurrentThread());
270 key_error_cb_
.Run(key_system
, session_id
, error_code
, system_code
);
273 void PpapiDecryptor::KeyMessage(const std::string
& key_system
,
274 const std::string
& session_id
,
275 const std::string
& message
,
276 const std::string
& default_url
) {
277 DCHECK(render_loop_proxy_
->BelongsToCurrentThread());
278 key_message_cb_
.Run(key_system
, session_id
, message
, default_url
);
281 void PpapiDecryptor::NeedKey(const std::string
& key_system
,
282 const std::string
& session_id
,
283 const std::string
& type
,
284 scoped_ptr
<uint8
[]> init_data
,
285 int init_data_size
) {
286 DCHECK(render_loop_proxy_
->BelongsToCurrentThread());
287 need_key_cb_
.Run(key_system
, session_id
, type
,
288 init_data
.Pass(), init_data_size
);
291 } // namespace webkit_media