Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / crypto / ppapi_decryptor.cc
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
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   return scoped_ptr<PpapiDecryptor>(new PpapiDecryptor(key_system,
42                                                        plugin_instance,
43                                                        plugin_cdm_delegate,
44                                                        session_created_cb,
45                                                        session_message_cb,
46                                                        session_ready_cb,
47                                                        session_closed_cb,
48                                                        session_error_cb,
49                                                        destroy_plugin_cb));
50 }
51
52 PpapiDecryptor::PpapiDecryptor(
53     const std::string& key_system,
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_->Initialize(
83       key_system,
84       base::Bind(&PpapiDecryptor::OnSessionCreated, weak_this_),
85       base::Bind(&PpapiDecryptor::OnSessionMessage, weak_this_),
86       base::Bind(&PpapiDecryptor::OnSessionReady, weak_this_),
87       base::Bind(&PpapiDecryptor::OnSessionClosed, weak_this_),
88       base::Bind(&PpapiDecryptor::OnSessionError, weak_this_),
89       base::Bind(&PpapiDecryptor::OnFatalPluginError, weak_this_));
90 }
91
92 PpapiDecryptor::~PpapiDecryptor() {
93   plugin_cdm_delegate_ = NULL;
94   plugin_instance_ = NULL;
95   if (!destroy_plugin_cb_.is_null())
96     base::ResetAndReturn(&destroy_plugin_cb_).Run();
97 }
98
99 bool PpapiDecryptor::CreateSession(uint32 session_id,
100                                    const std::string& content_type,
101                                    const uint8* init_data,
102                                    int init_data_length) {
103   DVLOG(2) << __FUNCTION__;
104   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
105
106   if (!plugin_cdm_delegate_ ||
107       !plugin_cdm_delegate_->CreateSession(
108            session_id, content_type, init_data, init_data_length)) {
109     ReportFailureToCallPlugin(session_id);
110     return false;
111   }
112
113   return true;
114 }
115
116 void PpapiDecryptor::LoadSession(uint32 session_id,
117                                  const std::string& web_session_id) {
118   DVLOG(2) << __FUNCTION__;
119   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
120
121   if (!plugin_cdm_delegate_) {
122     ReportFailureToCallPlugin(session_id);
123     return;
124   }
125
126   plugin_cdm_delegate_->LoadSession(session_id, web_session_id);
127 }
128
129 void PpapiDecryptor::UpdateSession(uint32 session_id,
130                                    const uint8* response,
131                                    int response_length) {
132   DVLOG(2) << __FUNCTION__;
133   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
134
135   if (!plugin_cdm_delegate_ || !plugin_cdm_delegate_->UpdateSession(
136                                     session_id, response, response_length)) {
137     ReportFailureToCallPlugin(session_id);
138     return;
139   }
140 }
141
142 void PpapiDecryptor::ReleaseSession(uint32 session_id) {
143   DVLOG(2) << __FUNCTION__;
144   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
145
146   if (!plugin_cdm_delegate_ ||
147       !plugin_cdm_delegate_->ReleaseSession(session_id)) {
148     ReportFailureToCallPlugin(session_id);
149     return;
150   }
151 }
152
153 media::Decryptor* PpapiDecryptor::GetDecryptor() {
154   return this;
155 }
156
157 void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type,
158                                       const NewKeyCB& new_key_cb) {
159   if (!render_loop_proxy_->BelongsToCurrentThread()) {
160     render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
161         &PpapiDecryptor::RegisterNewKeyCB, weak_this_, stream_type,
162         new_key_cb));
163     return;
164   }
165
166   DVLOG(3) << __FUNCTION__ << " - stream_type: " << stream_type;
167   switch (stream_type) {
168     case kAudio:
169       new_audio_key_cb_ = new_key_cb;
170       break;
171     case kVideo:
172       new_video_key_cb_ = new_key_cb;
173       break;
174     default:
175       NOTREACHED();
176   }
177 }
178
179 void PpapiDecryptor::Decrypt(
180     StreamType stream_type,
181     const scoped_refptr<media::DecoderBuffer>& encrypted,
182     const DecryptCB& decrypt_cb) {
183   if (!render_loop_proxy_->BelongsToCurrentThread()) {
184     render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
185         &PpapiDecryptor::Decrypt, weak_this_,
186         stream_type, encrypted, decrypt_cb));
187     return;
188   }
189
190   DVLOG(3) << __FUNCTION__ << " - stream_type: " << stream_type;
191   if (!plugin_cdm_delegate_ ||
192       !plugin_cdm_delegate_->Decrypt(stream_type, encrypted, decrypt_cb)) {
193     decrypt_cb.Run(kError, NULL);
194   }
195 }
196
197 void PpapiDecryptor::CancelDecrypt(StreamType stream_type) {
198   if (!render_loop_proxy_->BelongsToCurrentThread()) {
199     render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
200         &PpapiDecryptor::CancelDecrypt, weak_this_, stream_type));
201     return;
202   }
203
204   DVLOG(1) << __FUNCTION__ << " - stream_type: " << stream_type;
205   if (plugin_cdm_delegate_)
206     plugin_cdm_delegate_->CancelDecrypt(stream_type);
207 }
208
209 void PpapiDecryptor::InitializeAudioDecoder(
210       const media::AudioDecoderConfig& config,
211       const DecoderInitCB& init_cb) {
212   if (!render_loop_proxy_->BelongsToCurrentThread()) {
213     render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
214         &PpapiDecryptor::InitializeAudioDecoder, weak_this_, config, init_cb));
215     return;
216   }
217
218   DVLOG(2) << __FUNCTION__;
219   DCHECK(config.is_encrypted());
220   DCHECK(config.IsValidConfig());
221
222   audio_decoder_init_cb_ = init_cb;
223   if (!plugin_cdm_delegate_ ||
224       !plugin_cdm_delegate_->InitializeAudioDecoder(config, base::Bind(
225            &PpapiDecryptor::OnDecoderInitialized, weak_this_, kAudio))) {
226     base::ResetAndReturn(&audio_decoder_init_cb_).Run(false);
227     return;
228   }
229 }
230
231 void PpapiDecryptor::InitializeVideoDecoder(
232     const media::VideoDecoderConfig& config,
233     const DecoderInitCB& init_cb) {
234   if (!render_loop_proxy_->BelongsToCurrentThread()) {
235     render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
236         &PpapiDecryptor::InitializeVideoDecoder, weak_this_, config, init_cb));
237     return;
238   }
239
240   DVLOG(2) << __FUNCTION__;
241   DCHECK(config.is_encrypted());
242   DCHECK(config.IsValidConfig());
243
244   video_decoder_init_cb_ = init_cb;
245   if (!plugin_cdm_delegate_ ||
246       !plugin_cdm_delegate_->InitializeVideoDecoder(config, base::Bind(
247            &PpapiDecryptor::OnDecoderInitialized, weak_this_, kVideo))) {
248     base::ResetAndReturn(&video_decoder_init_cb_).Run(false);
249     return;
250   }
251 }
252
253 void PpapiDecryptor::DecryptAndDecodeAudio(
254     const scoped_refptr<media::DecoderBuffer>& encrypted,
255     const AudioDecodeCB& audio_decode_cb) {
256   if (!render_loop_proxy_->BelongsToCurrentThread()) {
257     render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
258         &PpapiDecryptor::DecryptAndDecodeAudio, weak_this_,
259         encrypted, audio_decode_cb));
260     return;
261   }
262
263   DVLOG(3) << __FUNCTION__;
264   if (!plugin_cdm_delegate_ || !plugin_cdm_delegate_->DecryptAndDecodeAudio(
265                                     encrypted, audio_decode_cb)) {
266     audio_decode_cb.Run(kError, AudioBuffers());
267   }
268 }
269
270 void PpapiDecryptor::DecryptAndDecodeVideo(
271     const scoped_refptr<media::DecoderBuffer>& encrypted,
272     const VideoDecodeCB& video_decode_cb) {
273   if (!render_loop_proxy_->BelongsToCurrentThread()) {
274     render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
275         &PpapiDecryptor::DecryptAndDecodeVideo, weak_this_,
276         encrypted, video_decode_cb));
277     return;
278   }
279
280   DVLOG(3) << __FUNCTION__;
281   if (!plugin_cdm_delegate_ || !plugin_cdm_delegate_->DecryptAndDecodeVideo(
282                                     encrypted, video_decode_cb)) {
283     video_decode_cb.Run(kError, NULL);
284   }
285 }
286
287 void PpapiDecryptor::ResetDecoder(StreamType stream_type) {
288   if (!render_loop_proxy_->BelongsToCurrentThread()) {
289     render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
290         &PpapiDecryptor::ResetDecoder, weak_this_, stream_type));
291     return;
292   }
293
294   DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type;
295   if (plugin_cdm_delegate_)
296     plugin_cdm_delegate_->ResetDecoder(stream_type);
297 }
298
299 void PpapiDecryptor::DeinitializeDecoder(StreamType stream_type) {
300   if (!render_loop_proxy_->BelongsToCurrentThread()) {
301     render_loop_proxy_->PostTask(FROM_HERE, base::Bind(
302         &PpapiDecryptor::DeinitializeDecoder, weak_this_, stream_type));
303     return;
304   }
305
306   DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type;
307   if (plugin_cdm_delegate_)
308     plugin_cdm_delegate_->DeinitializeDecoder(stream_type);
309 }
310
311 void PpapiDecryptor::ReportFailureToCallPlugin(uint32 session_id) {
312   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
313   DVLOG(1) << "Failed to call plugin.";
314   session_error_cb_.Run(session_id, kUnknownError, 0);
315 }
316
317 void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type,
318                                           bool success) {
319   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
320   switch (stream_type) {
321     case kAudio:
322       DCHECK(!audio_decoder_init_cb_.is_null());
323       base::ResetAndReturn(&audio_decoder_init_cb_).Run(success);
324       break;
325     case kVideo:
326       DCHECK(!video_decoder_init_cb_.is_null());
327       base::ResetAndReturn(&video_decoder_init_cb_).Run(success);
328       break;
329     default:
330       NOTREACHED();
331   }
332 }
333
334 void PpapiDecryptor::OnSessionCreated(uint32 session_id,
335                                       const std::string& web_session_id) {
336   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
337   session_created_cb_.Run(session_id, web_session_id);
338 }
339
340 void PpapiDecryptor::OnSessionMessage(uint32 session_id,
341                                       const std::vector<uint8>& message,
342                                       const std::string& destination_url) {
343   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
344   session_message_cb_.Run(session_id, message, destination_url);
345 }
346
347 void PpapiDecryptor::OnSessionReady(uint32 session_id) {
348   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
349
350   // Based on the spec, we need to resume playback when update() completes
351   // successfully, or when a session is successfully loaded. In both cases,
352   // the CDM fires OnSessionReady() event. So we choose to call the NewKeyCBs
353   // here.
354   // TODO(xhwang): Rename OnSessionReady to indicate that the playback may
355   // resume successfully (e.g. a new key is available or available again).
356   if (!new_audio_key_cb_.is_null())
357     new_audio_key_cb_.Run();
358
359   if (!new_video_key_cb_.is_null())
360     new_video_key_cb_.Run();
361
362   session_ready_cb_.Run(session_id);
363 }
364
365 void PpapiDecryptor::OnSessionClosed(uint32 session_id) {
366   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
367   session_closed_cb_.Run(session_id);
368 }
369
370 void PpapiDecryptor::OnSessionError(uint32 session_id,
371                                     media::MediaKeys::KeyError error_code,
372                                     int system_code) {
373   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
374   session_error_cb_.Run(session_id, error_code, system_code);
375 }
376
377 void PpapiDecryptor::OnFatalPluginError() {
378   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
379   DCHECK(plugin_cdm_delegate_);
380   plugin_cdm_delegate_ = NULL;
381   plugin_instance_ = NULL;
382   base::ResetAndReturn(&destroy_plugin_cb_).Run();
383 }
384
385 }  // namespace content