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.
4
5 #include "content/renderer/media/crypto/ppapi_decryptor.h"
6
7 #include <string>
8
9 #include "base/bind.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 "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/data_buffer.h"
19 #include "media/base/decoder_buffer.h"
20 #include "media/base/video_decoder_config.h"
21 #include "media/base/video_frame.h"
22
23 namespace content {
24
Create(const std::string & key_system,const scoped_refptr<PepperPluginInstanceImpl> & plugin_instance,const media::SessionCreatedCB & session_created_cb,const media::SessionMessageCB & session_message_cb,const media::SessionReadyCB & session_ready_cb,const media::SessionClosedCB & session_closed_cb,const media::SessionErrorCB & session_error_cb,const base::Closure & destroy_plugin_cb)25 scoped_ptr<PpapiDecryptor> PpapiDecryptor::Create(
26 const std::string& key_system,
27 const scoped_refptr<PepperPluginInstanceImpl>& plugin_instance,
28 const media::SessionCreatedCB& session_created_cb,
29 const media::SessionMessageCB& session_message_cb,
30 const media::SessionReadyCB& session_ready_cb,
31 const media::SessionClosedCB& session_closed_cb,
32 const media::SessionErrorCB& session_error_cb,
33 const base::Closure& destroy_plugin_cb) {
34 ContentDecryptorDelegate* plugin_cdm_delegate =
35 plugin_instance->GetContentDecryptorDelegate();
36 if (!plugin_cdm_delegate) {
37 DVLOG(1) << "PpapiDecryptor: plugin cdm delegate creation failed.";
38 return scoped_ptr<PpapiDecryptor>();
39 }
40
41 plugin_cdm_delegate->Initialize(key_system);
42
43 return scoped_ptr<PpapiDecryptor>(new PpapiDecryptor(plugin_instance,
44 plugin_cdm_delegate,
45 session_created_cb,
46 session_message_cb,
47 session_ready_cb,
48 session_closed_cb,
49 session_error_cb,
50 destroy_plugin_cb));
51 }
52
PpapiDecryptor(const scoped_refptr<PepperPluginInstanceImpl> & plugin_instance,ContentDecryptorDelegate * plugin_cdm_delegate,const media::SessionCreatedCB & session_created_cb,const media::SessionMessageCB & session_message_cb,const media::SessionReadyCB & session_ready_cb,const media::SessionClosedCB & session_closed_cb,const media::SessionErrorCB & session_error_cb,const base::Closure & destroy_plugin_cb)53 PpapiDecryptor::PpapiDecryptor(
54 const scoped_refptr<PepperPluginInstanceImpl>& plugin_instance,
55 ContentDecryptorDelegate* plugin_cdm_delegate,
56 const media::SessionCreatedCB& session_created_cb,
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 base::Closure& destroy_plugin_cb)
62 : plugin_instance_(plugin_instance),
63 plugin_cdm_delegate_(plugin_cdm_delegate),
64 session_created_cb_(session_created_cb),
65 session_message_cb_(session_message_cb),
66 session_ready_cb_(session_ready_cb),
67 session_closed_cb_(session_closed_cb),
68 session_error_cb_(session_error_cb),
69 destroy_plugin_cb_(destroy_plugin_cb),
70 render_loop_proxy_(base::MessageLoopProxy::current()),
71 weak_ptr_factory_(this) {
72 DCHECK(plugin_instance_.get());
73 DCHECK(!session_created_cb_.is_null());
74 DCHECK(!session_message_cb_.is_null());
75 DCHECK(!session_ready_cb_.is_null());
76 DCHECK(!session_closed_cb_.is_null());
77 DCHECK(!session_error_cb_.is_null());
78 DCHECK(!destroy_plugin_cb_.is_null());
79
80 weak_this_ = weak_ptr_factory_.GetWeakPtr();
81
82 plugin_cdm_delegate_->SetSessionEventCallbacks(
83 base::Bind(&PpapiDecryptor::OnSessionCreated, weak_this_),
84 base::Bind(&PpapiDecryptor::OnSessionMessage, weak_this_),
85 base::Bind(&PpapiDecryptor::OnSessionReady, weak_this_),
86 base::Bind(&PpapiDecryptor::OnSessionClosed, weak_this_),
87 base::Bind(&PpapiDecryptor::OnSessionError, weak_this_));
88 }
89
~PpapiDecryptor()90 PpapiDecryptor::~PpapiDecryptor() {
91 plugin_cdm_delegate_ = NULL;
92 plugin_instance_ = NULL;
93 destroy_plugin_cb_.Run();
94 }
95
CreateSession(uint32 session_id,const std::string & type,const uint8 * init_data,int init_data_length)96 bool PpapiDecryptor::CreateSession(uint32 session_id,
97 const std::string& type,
98 const uint8* init_data,
99 int init_data_length) {
100 DVLOG(2) << __FUNCTION__;
101 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
102 DCHECK(plugin_cdm_delegate_);
103
104 if (!plugin_cdm_delegate_->CreateSession(
105 session_id, type, init_data, init_data_length)) {
106 ReportFailureToCallPlugin(session_id);
107 return false;
108 }
109
110 return true;
111 }
112
UpdateSession(uint32 session_id,const uint8 * response,int response_length)113 void PpapiDecryptor::UpdateSession(uint32 session_id,
114 const uint8* response,
115 int response_length) {
116 DVLOG(2) << __FUNCTION__;
117 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
118
119 if (!plugin_cdm_delegate_->UpdateSession(
120 session_id, response, response_length))
121 ReportFailureToCallPlugin(session_id);
122
123 if (!new_audio_key_cb_.is_null())
124 new_audio_key_cb_.Run();
125
126 if (!new_video_key_cb_.is_null())
127 new_video_key_cb_.Run();
128 }
129
ReleaseSession(uint32 session_id)130 void PpapiDecryptor::ReleaseSession(uint32 session_id) {
131 DVLOG(2) << __FUNCTION__;
132 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
133
134 if (!plugin_cdm_delegate_->ReleaseSession(session_id))
135 ReportFailureToCallPlugin(session_id);
136 }
137
GetDecryptor()138 media::Decryptor* PpapiDecryptor::GetDecryptor() {
139 #if defined(GOOGLE_TV)
140 // Google TV only uses PpapiDecrytor as a MediaKeys and does not need the
141 // Decryptor interface of the PpapiDecryptor.
142 // Details: If we don't do this GTV will be broken. The reason is that during
143 // initialization, MediaSourceDelegate tries to use DecryptingDemuxerStream
144 // to decrypt the stream in the renderer process (for ClearKey support).
145 // However, for GTV, PpapiDecryptor cannot do decryption at all. By returning
146 // NULL, DDS init will fail and we fallback to what GTV used to do.
147 return NULL;
148 #else
149 return this;
150 #endif // defined(GOOGLE_TV)
151 }
152
RegisterNewKeyCB(StreamType stream_type,const NewKeyCB & new_key_cb)153 void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type,
154 const NewKeyCB& new_key_cb) {
155 if (!render_loop_proxy_->BelongsToCurrentThread()) {
156 render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
157 &PpapiDecryptor::RegisterNewKeyCB, weak_this_, stream_type,
158 new_key_cb));
159 return;
160 }
161
162 DVLOG(3) << __FUNCTION__ << " - stream_type: " << stream_type;
163 switch (stream_type) {
164 case kAudio:
165 new_audio_key_cb_ = new_key_cb;
166 break;
167 case kVideo:
168 new_video_key_cb_ = new_key_cb;
169 break;
170 default:
171 NOTREACHED();
172 }
173 }
174
Decrypt(StreamType stream_type,const scoped_refptr<media::DecoderBuffer> & encrypted,const DecryptCB & decrypt_cb)175 void PpapiDecryptor::Decrypt(
176 StreamType stream_type,
177 const scoped_refptr<media::DecoderBuffer>& encrypted,
178 const DecryptCB& decrypt_cb) {
179 if (!render_loop_proxy_->BelongsToCurrentThread()) {
180 render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
181 &PpapiDecryptor::Decrypt, weak_this_,
182 stream_type, encrypted, decrypt_cb));
183 return;
184 }
185
186 DVLOG(3) << __FUNCTION__ << " - stream_type: " << stream_type;
187 if (!plugin_cdm_delegate_->Decrypt(stream_type, encrypted, decrypt_cb))
188 decrypt_cb.Run(kError, NULL);
189 }
190
CancelDecrypt(StreamType stream_type)191 void PpapiDecryptor::CancelDecrypt(StreamType stream_type) {
192 if (!render_loop_proxy_->BelongsToCurrentThread()) {
193 render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
194 &PpapiDecryptor::CancelDecrypt, weak_this_, stream_type));
195 return;
196 }
197
198 DVLOG(1) << __FUNCTION__ << " - stream_type: " << stream_type;
199 plugin_cdm_delegate_->CancelDecrypt(stream_type);
200 }
201
InitializeAudioDecoder(const media::AudioDecoderConfig & config,const DecoderInitCB & init_cb)202 void PpapiDecryptor::InitializeAudioDecoder(
203 const media::AudioDecoderConfig& config,
204 const DecoderInitCB& init_cb) {
205 if (!render_loop_proxy_->BelongsToCurrentThread()) {
206 render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
207 &PpapiDecryptor::InitializeAudioDecoder, weak_this_, config, init_cb));
208 return;
209 }
210
211 DVLOG(2) << __FUNCTION__;
212 DCHECK(config.is_encrypted());
213 DCHECK(config.IsValidConfig());
214
215 audio_decoder_init_cb_ = init_cb;
216 if (!plugin_cdm_delegate_->InitializeAudioDecoder(config, base::Bind(
217 &PpapiDecryptor::OnDecoderInitialized, weak_this_, kAudio))) {
218 base::ResetAndReturn(&audio_decoder_init_cb_).Run(false);
219 return;
220 }
221 }
222
InitializeVideoDecoder(const media::VideoDecoderConfig & config,const DecoderInitCB & init_cb)223 void PpapiDecryptor::InitializeVideoDecoder(
224 const media::VideoDecoderConfig& config,
225 const DecoderInitCB& init_cb) {
226 if (!render_loop_proxy_->BelongsToCurrentThread()) {
227 render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
228 &PpapiDecryptor::InitializeVideoDecoder, weak_this_, config, init_cb));
229 return;
230 }
231
232 DVLOG(2) << __FUNCTION__;
233 DCHECK(config.is_encrypted());
234 DCHECK(config.IsValidConfig());
235
236 video_decoder_init_cb_ = init_cb;
237 if (!plugin_cdm_delegate_->InitializeVideoDecoder(config, base::Bind(
238 &PpapiDecryptor::OnDecoderInitialized, weak_this_, kVideo))) {
239 base::ResetAndReturn(&video_decoder_init_cb_).Run(false);
240 return;
241 }
242 }
243
DecryptAndDecodeAudio(const scoped_refptr<media::DecoderBuffer> & encrypted,const AudioDecodeCB & audio_decode_cb)244 void PpapiDecryptor::DecryptAndDecodeAudio(
245 const scoped_refptr<media::DecoderBuffer>& encrypted,
246 const AudioDecodeCB& audio_decode_cb) {
247 if (!render_loop_proxy_->BelongsToCurrentThread()) {
248 render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
249 &PpapiDecryptor::DecryptAndDecodeAudio, weak_this_,
250 encrypted, audio_decode_cb));
251 return;
252 }
253
254 DVLOG(3) << __FUNCTION__;
255 if (!plugin_cdm_delegate_->DecryptAndDecodeAudio(encrypted, audio_decode_cb))
256 audio_decode_cb.Run(kError, AudioBuffers());
257 }
258
DecryptAndDecodeVideo(const scoped_refptr<media::DecoderBuffer> & encrypted,const VideoDecodeCB & video_decode_cb)259 void PpapiDecryptor::DecryptAndDecodeVideo(
260 const scoped_refptr<media::DecoderBuffer>& encrypted,
261 const VideoDecodeCB& video_decode_cb) {
262 if (!render_loop_proxy_->BelongsToCurrentThread()) {
263 render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
264 &PpapiDecryptor::DecryptAndDecodeVideo, weak_this_,
265 encrypted, video_decode_cb));
266 return;
267 }
268
269 DVLOG(3) << __FUNCTION__;
270 if (!plugin_cdm_delegate_->DecryptAndDecodeVideo(encrypted, video_decode_cb))
271 video_decode_cb.Run(kError, NULL);
272 }
273
ResetDecoder(StreamType stream_type)274 void PpapiDecryptor::ResetDecoder(StreamType stream_type) {
275 if (!render_loop_proxy_->BelongsToCurrentThread()) {
276 render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
277 &PpapiDecryptor::ResetDecoder, weak_this_, stream_type));
278 return;
279 }
280
281 DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type;
282 plugin_cdm_delegate_->ResetDecoder(stream_type);
283 }
284
DeinitializeDecoder(StreamType stream_type)285 void PpapiDecryptor::DeinitializeDecoder(StreamType stream_type) {
286 if (!render_loop_proxy_->BelongsToCurrentThread()) {
287 render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
288 &PpapiDecryptor::DeinitializeDecoder, weak_this_, stream_type));
289 return;
290 }
291
292 DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type;
293 plugin_cdm_delegate_->DeinitializeDecoder(stream_type);
294 }
295
ReportFailureToCallPlugin(uint32 session_id)296 void PpapiDecryptor::ReportFailureToCallPlugin(uint32 session_id) {
297 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
298 DVLOG(1) << "Failed to call plugin.";
299 session_error_cb_.Run(session_id, kUnknownError, 0);
300 }
301
OnDecoderInitialized(StreamType stream_type,bool success)302 void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type,
303 bool success) {
304 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
305 switch (stream_type) {
306 case kAudio:
307 DCHECK(!audio_decoder_init_cb_.is_null());
308 base::ResetAndReturn(&audio_decoder_init_cb_).Run(success);
309 break;
310 case kVideo:
311 DCHECK(!video_decoder_init_cb_.is_null());
312 base::ResetAndReturn(&video_decoder_init_cb_).Run(success);
313 break;
314 default:
315 NOTREACHED();
316 }
317 }
318
OnSessionCreated(uint32 session_id,const std::string & web_session_id)319 void PpapiDecryptor::OnSessionCreated(uint32 session_id,
320 const std::string& web_session_id) {
321 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
322 session_created_cb_.Run(session_id, web_session_id);
323 }
324
OnSessionMessage(uint32 session_id,const std::vector<uint8> & message,const std::string & destination_url)325 void PpapiDecryptor::OnSessionMessage(uint32 session_id,
326 const std::vector<uint8>& message,
327 const std::string& destination_url) {
328 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
329 session_message_cb_.Run(session_id, message, destination_url);
330 }
331
OnSessionReady(uint32 session_id)332 void PpapiDecryptor::OnSessionReady(uint32 session_id) {
333 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
334 session_ready_cb_.Run(session_id);
335 }
336
OnSessionClosed(uint32 session_id)337 void PpapiDecryptor::OnSessionClosed(uint32 session_id) {
338 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
339 session_closed_cb_.Run(session_id);
340 }
341
OnSessionError(uint32 session_id,media::MediaKeys::KeyError error_code,int system_code)342 void PpapiDecryptor::OnSessionError(uint32 session_id,
343 media::MediaKeys::KeyError error_code,
344 int system_code) {
345 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
346 session_error_cb_.Run(session_id, error_code, system_code);
347 }
348
349 } // namespace content
350