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/callback_helpers.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/message_loop/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/plugins/ppapi/content_decryptor_delegate.h"
21 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
25 scoped_ptr
<PpapiDecryptor
> PpapiDecryptor::Create(
26 const std::string
& key_system
,
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 base::Closure
& destroy_plugin_cb
) {
32 webkit::ppapi::ContentDecryptorDelegate
* plugin_cdm_delegate
=
33 plugin_instance
->GetContentDecryptorDelegate();
34 if (!plugin_cdm_delegate
) {
35 DVLOG(1) << "PpapiDecryptor: plugin cdm delegate creation failed.";
36 return scoped_ptr
<PpapiDecryptor
>();
39 plugin_cdm_delegate
->Initialize(key_system
);
41 return scoped_ptr
<PpapiDecryptor
>(new PpapiDecryptor(plugin_instance
,
49 PpapiDecryptor::PpapiDecryptor(
50 const scoped_refptr
<webkit::ppapi::PluginInstance
>& plugin_instance
,
51 webkit::ppapi::ContentDecryptorDelegate
* plugin_cdm_delegate
,
52 const media::KeyAddedCB
& key_added_cb
,
53 const media::KeyErrorCB
& key_error_cb
,
54 const media::KeyMessageCB
& key_message_cb
,
55 const base::Closure
& destroy_plugin_cb
)
56 : plugin_instance_(plugin_instance
),
57 plugin_cdm_delegate_(plugin_cdm_delegate
),
58 key_added_cb_(key_added_cb
),
59 key_error_cb_(key_error_cb
),
60 key_message_cb_(key_message_cb
),
61 destroy_plugin_cb_(destroy_plugin_cb
),
62 render_loop_proxy_(base::MessageLoopProxy::current()),
63 weak_ptr_factory_(this),
64 weak_this_(weak_ptr_factory_
.GetWeakPtr()) {
65 DCHECK(plugin_instance_
.get());
67 plugin_cdm_delegate_
->SetKeyEventCallbacks(
68 base::Bind(&PpapiDecryptor::KeyAdded
, weak_this_
),
69 base::Bind(&PpapiDecryptor::KeyError
, weak_this_
),
70 base::Bind(&PpapiDecryptor::KeyMessage
, weak_this_
));
73 PpapiDecryptor::~PpapiDecryptor() {
74 plugin_cdm_delegate_
= NULL
;
75 plugin_instance_
= NULL
;
76 destroy_plugin_cb_
.Run();
79 bool PpapiDecryptor::GenerateKeyRequest(const std::string
& type
,
80 const uint8
* init_data
,
81 int init_data_length
) {
82 DVLOG(2) << "GenerateKeyRequest()";
83 DCHECK(render_loop_proxy_
->BelongsToCurrentThread());
84 DCHECK(plugin_cdm_delegate_
);
86 if (!plugin_cdm_delegate_
->GenerateKeyRequest(
87 type
, init_data
, init_data_length
)) {
88 ReportFailureToCallPlugin(std::string());
95 void PpapiDecryptor::AddKey(const uint8
* key
,
97 const uint8
* init_data
,
99 const std::string
& session_id
) {
100 DVLOG(2) << "AddKey()";
101 DCHECK(render_loop_proxy_
->BelongsToCurrentThread());
103 if (!plugin_cdm_delegate_
->AddKey(
104 session_id
, key
, key_length
, init_data
, init_data_length
)) {
105 ReportFailureToCallPlugin(session_id
);
108 if (!new_audio_key_cb_
.is_null())
109 new_audio_key_cb_
.Run();
111 if (!new_video_key_cb_
.is_null())
112 new_video_key_cb_
.Run();
115 void PpapiDecryptor::CancelKeyRequest(const std::string
& session_id
) {
116 DVLOG(2) << "CancelKeyRequest()";
117 DCHECK(render_loop_proxy_
->BelongsToCurrentThread());
119 if (!plugin_cdm_delegate_
->CancelKeyRequest(session_id
))
120 ReportFailureToCallPlugin(session_id
);
123 media::Decryptor
* PpapiDecryptor::GetDecryptor() {
124 #if defined(GOOGLE_TV)
125 // Google TV only uses PpapiDecrytor as a MediaKeys and does not need the
126 // Decryptor interface of the PpapiDecryptor.
127 // Details: If we don't do this GTV will be broken. The reason is that during
128 // initialization, MediaSourceDelegate tries to use DecryptingDemuxerStream
129 // to decrypt the stream in the renderer process (for ClearKey support).
130 // However, for GTV, PpapiDecryptor cannot do decryption at all. By returning
131 // NULL, DDS init will fail and we fallback to what GTV used to do.
135 #endif // defined(GOOGLE_TV)
138 void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type
,
139 const NewKeyCB
& new_key_cb
) {
140 switch (stream_type
) {
142 new_audio_key_cb_
= new_key_cb
;
145 new_video_key_cb_
= new_key_cb
;
152 void PpapiDecryptor::Decrypt(
153 StreamType stream_type
,
154 const scoped_refptr
<media::DecoderBuffer
>& encrypted
,
155 const DecryptCB
& decrypt_cb
) {
156 if (!render_loop_proxy_
->BelongsToCurrentThread()) {
157 render_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
158 &PpapiDecryptor::Decrypt
, weak_this_
,
159 stream_type
, encrypted
, decrypt_cb
));
163 DVLOG(3) << "Decrypt() - stream_type: " << stream_type
;
164 if (!plugin_cdm_delegate_
->Decrypt(stream_type
, encrypted
, decrypt_cb
))
165 decrypt_cb
.Run(kError
, NULL
);
168 void PpapiDecryptor::CancelDecrypt(StreamType stream_type
) {
169 DVLOG(1) << "CancelDecrypt() - stream_type: " << stream_type
;
170 plugin_cdm_delegate_
->CancelDecrypt(stream_type
);
173 void PpapiDecryptor::InitializeAudioDecoder(
174 const media::AudioDecoderConfig
& config
,
175 const DecoderInitCB
& init_cb
) {
176 if (!render_loop_proxy_
->BelongsToCurrentThread()) {
177 render_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
178 &PpapiDecryptor::InitializeAudioDecoder
, weak_this_
, config
, init_cb
));
182 DVLOG(2) << "InitializeAudioDecoder()";
183 DCHECK(config
.is_encrypted());
184 DCHECK(config
.IsValidConfig());
186 audio_decoder_init_cb_
= init_cb
;
187 if (!plugin_cdm_delegate_
->InitializeAudioDecoder(config
, base::Bind(
188 &PpapiDecryptor::OnDecoderInitialized
, weak_this_
, kAudio
))) {
189 base::ResetAndReturn(&audio_decoder_init_cb_
).Run(false);
194 void PpapiDecryptor::InitializeVideoDecoder(
195 const media::VideoDecoderConfig
& config
,
196 const DecoderInitCB
& init_cb
) {
197 if (!render_loop_proxy_
->BelongsToCurrentThread()) {
198 render_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
199 &PpapiDecryptor::InitializeVideoDecoder
, weak_this_
, config
, init_cb
));
203 DVLOG(2) << "InitializeVideoDecoder()";
204 DCHECK(config
.is_encrypted());
205 DCHECK(config
.IsValidConfig());
207 video_decoder_init_cb_
= init_cb
;
208 if (!plugin_cdm_delegate_
->InitializeVideoDecoder(config
, base::Bind(
209 &PpapiDecryptor::OnDecoderInitialized
, weak_this_
, kVideo
))) {
210 base::ResetAndReturn(&video_decoder_init_cb_
).Run(false);
215 void PpapiDecryptor::DecryptAndDecodeAudio(
216 const scoped_refptr
<media::DecoderBuffer
>& encrypted
,
217 const AudioDecodeCB
& audio_decode_cb
) {
218 if (!render_loop_proxy_
->BelongsToCurrentThread()) {
219 render_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
220 &PpapiDecryptor::DecryptAndDecodeAudio
, weak_this_
,
221 encrypted
, audio_decode_cb
));
225 DVLOG(3) << "DecryptAndDecodeAudio()";
226 if (!plugin_cdm_delegate_
->DecryptAndDecodeAudio(encrypted
, audio_decode_cb
))
227 audio_decode_cb
.Run(kError
, AudioBuffers());
230 void PpapiDecryptor::DecryptAndDecodeVideo(
231 const scoped_refptr
<media::DecoderBuffer
>& encrypted
,
232 const VideoDecodeCB
& video_decode_cb
) {
233 if (!render_loop_proxy_
->BelongsToCurrentThread()) {
234 render_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
235 &PpapiDecryptor::DecryptAndDecodeVideo
, weak_this_
,
236 encrypted
, video_decode_cb
));
240 DVLOG(3) << "DecryptAndDecodeVideo()";
241 if (!plugin_cdm_delegate_
->DecryptAndDecodeVideo(encrypted
, video_decode_cb
))
242 video_decode_cb
.Run(kError
, NULL
);
245 void PpapiDecryptor::ResetDecoder(StreamType stream_type
) {
246 if (!render_loop_proxy_
->BelongsToCurrentThread()) {
247 render_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
248 &PpapiDecryptor::ResetDecoder
, weak_this_
, stream_type
));
252 DVLOG(2) << "ResetDecoder() - stream_type: " << stream_type
;
253 plugin_cdm_delegate_
->ResetDecoder(stream_type
);
256 void PpapiDecryptor::DeinitializeDecoder(StreamType stream_type
) {
257 if (!render_loop_proxy_
->BelongsToCurrentThread()) {
258 render_loop_proxy_
->PostTask(FROM_HERE
, base::Bind(
259 &PpapiDecryptor::DeinitializeDecoder
, weak_this_
, stream_type
));
263 DVLOG(2) << "DeinitializeDecoder() - stream_type: " << stream_type
;
264 plugin_cdm_delegate_
->DeinitializeDecoder(stream_type
);
267 void PpapiDecryptor::ReportFailureToCallPlugin(const std::string
& session_id
) {
268 DVLOG(1) << "Failed to call plugin.";
269 key_error_cb_
.Run(session_id
, kUnknownError
, 0);
272 void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type
,
274 switch (stream_type
) {
276 DCHECK(!audio_decoder_init_cb_
.is_null());
277 base::ResetAndReturn(&audio_decoder_init_cb_
).Run(success
);
280 DCHECK(!video_decoder_init_cb_
.is_null());
281 base::ResetAndReturn(&video_decoder_init_cb_
).Run(success
);
288 void PpapiDecryptor::KeyAdded(const std::string
& session_id
) {
289 DCHECK(render_loop_proxy_
->BelongsToCurrentThread());
290 key_added_cb_
.Run(session_id
);
293 void PpapiDecryptor::KeyError(const std::string
& session_id
,
294 media::MediaKeys::KeyError error_code
,
296 DCHECK(render_loop_proxy_
->BelongsToCurrentThread());
297 key_error_cb_
.Run(session_id
, error_code
, system_code
);
300 void PpapiDecryptor::KeyMessage(const std::string
& session_id
,
301 const std::vector
<uint8
>& message
,
302 const std::string
& default_url
) {
303 DCHECK(render_loop_proxy_
->BelongsToCurrentThread());
304 key_message_cb_
.Run(session_id
, message
, default_url
);
307 } // namespace content