• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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