Update To 11.40.268.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/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "content/renderer/media/crypto/key_systems.h"
14 #include "content/renderer/pepper/content_decryptor_delegate.h"
15 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
16 #include "media/base/audio_decoder_config.h"
17 #include "media/base/data_buffer.h"
18 #include "media/base/decoder_buffer.h"
19 #include "media/base/video_decoder_config.h"
20 #include "media/base/video_frame.h"
21
22 namespace content {
23
24 scoped_ptr<PpapiDecryptor> PpapiDecryptor::Create(
25     const std::string& key_system,
26     const GURL& security_origin,
27     const CreatePepperCdmCB& create_pepper_cdm_cb,
28     const media::SessionMessageCB& session_message_cb,
29     const media::SessionReadyCB& session_ready_cb,
30     const media::SessionClosedCB& session_closed_cb,
31     const media::SessionErrorCB& session_error_cb,
32     const media::SessionKeysChangeCB& session_keys_change_cb,
33     const media::SessionExpirationUpdateCB& session_expiration_update_cb) {
34   std::string plugin_type = GetPepperType(key_system);
35   DCHECK(!plugin_type.empty());
36   scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper =
37       create_pepper_cdm_cb.Run(plugin_type, security_origin);
38   if (!pepper_cdm_wrapper) {
39     DLOG(ERROR) << "Plugin instance creation failed.";
40     return scoped_ptr<PpapiDecryptor>();
41   }
42
43   return scoped_ptr<PpapiDecryptor>(
44       new PpapiDecryptor(key_system,
45                          pepper_cdm_wrapper.Pass(),
46                          session_message_cb,
47                          session_ready_cb,
48                          session_closed_cb,
49                          session_error_cb,
50                          session_keys_change_cb,
51                          session_expiration_update_cb));
52 }
53
54 PpapiDecryptor::PpapiDecryptor(
55     const std::string& key_system,
56     scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper,
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 media::SessionKeysChangeCB& session_keys_change_cb,
62     const media::SessionExpirationUpdateCB& session_expiration_update_cb)
63     : pepper_cdm_wrapper_(pepper_cdm_wrapper.Pass()),
64       session_message_cb_(session_message_cb),
65       session_ready_cb_(session_ready_cb),
66       session_closed_cb_(session_closed_cb),
67       session_error_cb_(session_error_cb),
68       session_keys_change_cb_(session_keys_change_cb),
69       session_expiration_update_cb_(session_expiration_update_cb),
70       render_loop_proxy_(base::MessageLoopProxy::current()),
71       weak_ptr_factory_(this) {
72   DCHECK(pepper_cdm_wrapper_.get());
73   DCHECK(!session_message_cb_.is_null());
74   DCHECK(!session_ready_cb_.is_null());
75   DCHECK(!session_closed_cb_.is_null());
76   DCHECK(!session_error_cb_.is_null());
77   DCHECK(!session_keys_change_cb.is_null());
78   DCHECK(!session_expiration_update_cb.is_null());
79
80   base::WeakPtr<PpapiDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr();
81   CdmDelegate()->Initialize(
82       key_system,
83       base::Bind(&PpapiDecryptor::OnSessionMessage, weak_this),
84       base::Bind(&PpapiDecryptor::OnSessionReady, weak_this),
85       base::Bind(&PpapiDecryptor::OnSessionClosed, weak_this),
86       base::Bind(&PpapiDecryptor::OnSessionError, weak_this),
87       base::Bind(&PpapiDecryptor::OnSessionKeysChange, weak_this),
88       base::Bind(&PpapiDecryptor::OnSessionExpirationUpdate, weak_this),
89       base::Bind(&PpapiDecryptor::OnFatalPluginError, weak_this));
90 }
91
92 PpapiDecryptor::~PpapiDecryptor() {
93   pepper_cdm_wrapper_.reset();
94 }
95
96 void PpapiDecryptor::SetServerCertificate(
97     const uint8* certificate_data,
98     int certificate_data_length,
99     scoped_ptr<media::SimpleCdmPromise> promise) {
100   DVLOG(2) << __FUNCTION__;
101   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
102
103   if (!CdmDelegate()) {
104     promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
105     return;
106   }
107
108   CdmDelegate()->SetServerCertificate(
109       certificate_data, certificate_data_length, promise.Pass());
110 }
111
112 void PpapiDecryptor::CreateSession(
113     const std::string& init_data_type,
114     const uint8* init_data,
115     int init_data_length,
116     SessionType session_type,
117     scoped_ptr<media::NewSessionCdmPromise> promise) {
118   DVLOG(2) << __FUNCTION__;
119   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
120
121   if (!CdmDelegate()) {
122     promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
123     return;
124   }
125
126   CdmDelegate()->CreateSession(init_data_type,
127                                init_data,
128                                init_data_length,
129                                session_type,
130                                promise.Pass());
131 }
132
133 void PpapiDecryptor::LoadSession(
134     const std::string& web_session_id,
135     scoped_ptr<media::NewSessionCdmPromise> promise) {
136   DVLOG(2) << __FUNCTION__;
137   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
138
139   if (!CdmDelegate()) {
140     promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
141     return;
142   }
143   CdmDelegate()->LoadSession(web_session_id, promise.Pass());
144 }
145
146 void PpapiDecryptor::UpdateSession(
147     const std::string& web_session_id,
148     const uint8* response,
149     int response_length,
150     scoped_ptr<media::SimpleCdmPromise> promise) {
151   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
152
153   if (!CdmDelegate()) {
154     promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
155     return;
156   }
157   CdmDelegate()->UpdateSession(web_session_id, response, response_length,
158                                promise.Pass());
159 }
160
161 void PpapiDecryptor::CloseSession(const std::string& web_session_id,
162                                   scoped_ptr<media::SimpleCdmPromise> promise) {
163   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
164
165   if (!CdmDelegate()) {
166     promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
167     return;
168   }
169
170   CdmDelegate()->CloseSession(web_session_id, promise.Pass());
171 }
172
173 void PpapiDecryptor::RemoveSession(
174     const std::string& web_session_id,
175     scoped_ptr<media::SimpleCdmPromise> promise) {
176   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
177
178   if (!CdmDelegate()) {
179     promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
180     return;
181   }
182
183   CdmDelegate()->RemoveSession(web_session_id, promise.Pass());
184 }
185
186 void PpapiDecryptor::GetUsableKeyIds(const std::string& web_session_id,
187                                      scoped_ptr<media::KeyIdsPromise> promise) {
188   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
189
190   if (!CdmDelegate()) {
191     promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
192     return;
193   }
194
195   CdmDelegate()->GetUsableKeyIds(web_session_id, promise.Pass());
196 }
197
198 media::Decryptor* PpapiDecryptor::GetDecryptor() {
199   return this;
200 }
201
202 void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type,
203                                       const NewKeyCB& new_key_cb) {
204   if (!render_loop_proxy_->BelongsToCurrentThread()) {
205     render_loop_proxy_->PostTask(FROM_HERE,
206                                  base::Bind(&PpapiDecryptor::RegisterNewKeyCB,
207                                             weak_ptr_factory_.GetWeakPtr(),
208                                             stream_type,
209                                             new_key_cb));
210     return;
211   }
212
213   DVLOG(3) << __FUNCTION__ << " - stream_type: " << stream_type;
214   switch (stream_type) {
215     case kAudio:
216       new_audio_key_cb_ = new_key_cb;
217       break;
218     case kVideo:
219       new_video_key_cb_ = new_key_cb;
220       break;
221     default:
222       NOTREACHED();
223   }
224 }
225
226 void PpapiDecryptor::Decrypt(
227     StreamType stream_type,
228     const scoped_refptr<media::DecoderBuffer>& encrypted,
229     const DecryptCB& decrypt_cb) {
230   if (!render_loop_proxy_->BelongsToCurrentThread()) {
231     render_loop_proxy_->PostTask(FROM_HERE,
232                                  base::Bind(&PpapiDecryptor::Decrypt,
233                                             weak_ptr_factory_.GetWeakPtr(),
234                                             stream_type,
235                                             encrypted,
236                                             decrypt_cb));
237     return;
238   }
239
240   DVLOG(3) << __FUNCTION__ << " - stream_type: " << stream_type;
241   if (!CdmDelegate() ||
242       !CdmDelegate()->Decrypt(stream_type, encrypted, decrypt_cb)) {
243     decrypt_cb.Run(kError, NULL);
244   }
245 }
246
247 void PpapiDecryptor::CancelDecrypt(StreamType stream_type) {
248   if (!render_loop_proxy_->BelongsToCurrentThread()) {
249     render_loop_proxy_->PostTask(FROM_HERE,
250                                  base::Bind(&PpapiDecryptor::CancelDecrypt,
251                                             weak_ptr_factory_.GetWeakPtr(),
252                                             stream_type));
253     return;
254   }
255
256   DVLOG(1) << __FUNCTION__ << " - stream_type: " << stream_type;
257   if (CdmDelegate())
258     CdmDelegate()->CancelDecrypt(stream_type);
259 }
260
261 void PpapiDecryptor::InitializeAudioDecoder(
262       const media::AudioDecoderConfig& config,
263       const DecoderInitCB& init_cb) {
264   if (!render_loop_proxy_->BelongsToCurrentThread()) {
265     render_loop_proxy_->PostTask(
266         FROM_HERE,
267         base::Bind(&PpapiDecryptor::InitializeAudioDecoder,
268                    weak_ptr_factory_.GetWeakPtr(),
269                    config,
270                    init_cb));
271     return;
272   }
273
274   DVLOG(2) << __FUNCTION__;
275   DCHECK(config.is_encrypted());
276   DCHECK(config.IsValidConfig());
277
278   audio_decoder_init_cb_ = init_cb;
279   if (!CdmDelegate() || !CdmDelegate()->InitializeAudioDecoder(
280                             config,
281                             base::Bind(&PpapiDecryptor::OnDecoderInitialized,
282                                        weak_ptr_factory_.GetWeakPtr(),
283                                        kAudio))) {
284     base::ResetAndReturn(&audio_decoder_init_cb_).Run(false);
285     return;
286   }
287 }
288
289 void PpapiDecryptor::InitializeVideoDecoder(
290     const media::VideoDecoderConfig& config,
291     const DecoderInitCB& init_cb) {
292   if (!render_loop_proxy_->BelongsToCurrentThread()) {
293     render_loop_proxy_->PostTask(
294         FROM_HERE,
295         base::Bind(&PpapiDecryptor::InitializeVideoDecoder,
296                    weak_ptr_factory_.GetWeakPtr(),
297                    config,
298                    init_cb));
299     return;
300   }
301
302   DVLOG(2) << __FUNCTION__;
303   DCHECK(config.is_encrypted());
304   DCHECK(config.IsValidConfig());
305
306   video_decoder_init_cb_ = init_cb;
307   if (!CdmDelegate() || !CdmDelegate()->InitializeVideoDecoder(
308                             config,
309                             base::Bind(&PpapiDecryptor::OnDecoderInitialized,
310                                        weak_ptr_factory_.GetWeakPtr(),
311                                        kVideo))) {
312     base::ResetAndReturn(&video_decoder_init_cb_).Run(false);
313     return;
314   }
315 }
316
317 void PpapiDecryptor::DecryptAndDecodeAudio(
318     const scoped_refptr<media::DecoderBuffer>& encrypted,
319     const AudioDecodeCB& audio_decode_cb) {
320   if (!render_loop_proxy_->BelongsToCurrentThread()) {
321     render_loop_proxy_->PostTask(
322         FROM_HERE,
323         base::Bind(&PpapiDecryptor::DecryptAndDecodeAudio,
324                    weak_ptr_factory_.GetWeakPtr(),
325                    encrypted,
326                    audio_decode_cb));
327     return;
328   }
329
330   DVLOG(3) << __FUNCTION__;
331   if (!CdmDelegate() ||
332       !CdmDelegate()->DecryptAndDecodeAudio(encrypted, audio_decode_cb)) {
333     audio_decode_cb.Run(kError, AudioBuffers());
334   }
335 }
336
337 void PpapiDecryptor::DecryptAndDecodeVideo(
338     const scoped_refptr<media::DecoderBuffer>& encrypted,
339     const VideoDecodeCB& video_decode_cb) {
340   if (!render_loop_proxy_->BelongsToCurrentThread()) {
341     render_loop_proxy_->PostTask(
342         FROM_HERE,
343         base::Bind(&PpapiDecryptor::DecryptAndDecodeVideo,
344                    weak_ptr_factory_.GetWeakPtr(),
345                    encrypted,
346                    video_decode_cb));
347     return;
348   }
349
350   DVLOG(3) << __FUNCTION__;
351   if (!CdmDelegate() ||
352       !CdmDelegate()->DecryptAndDecodeVideo(encrypted, video_decode_cb)) {
353     video_decode_cb.Run(kError, NULL);
354   }
355 }
356
357 void PpapiDecryptor::ResetDecoder(StreamType stream_type) {
358   if (!render_loop_proxy_->BelongsToCurrentThread()) {
359     render_loop_proxy_->PostTask(FROM_HERE,
360                                  base::Bind(&PpapiDecryptor::ResetDecoder,
361                                             weak_ptr_factory_.GetWeakPtr(),
362                                             stream_type));
363     return;
364   }
365
366   DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type;
367   if (CdmDelegate())
368     CdmDelegate()->ResetDecoder(stream_type);
369 }
370
371 void PpapiDecryptor::DeinitializeDecoder(StreamType stream_type) {
372   if (!render_loop_proxy_->BelongsToCurrentThread()) {
373     render_loop_proxy_->PostTask(
374         FROM_HERE,
375         base::Bind(&PpapiDecryptor::DeinitializeDecoder,
376                    weak_ptr_factory_.GetWeakPtr(),
377                    stream_type));
378     return;
379   }
380
381   DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type;
382   if (CdmDelegate())
383     CdmDelegate()->DeinitializeDecoder(stream_type);
384 }
385
386 void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type,
387                                           bool success) {
388   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
389   switch (stream_type) {
390     case kAudio:
391       DCHECK(!audio_decoder_init_cb_.is_null());
392       base::ResetAndReturn(&audio_decoder_init_cb_).Run(success);
393       break;
394     case kVideo:
395       DCHECK(!video_decoder_init_cb_.is_null());
396       base::ResetAndReturn(&video_decoder_init_cb_).Run(success);
397       break;
398     default:
399       NOTREACHED();
400   }
401 }
402
403 void PpapiDecryptor::OnSessionMessage(const std::string& web_session_id,
404                                       const std::vector<uint8>& message,
405                                       const GURL& destination_url) {
406   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
407   session_message_cb_.Run(web_session_id, message, destination_url);
408 }
409
410 void PpapiDecryptor::OnSessionKeysChange(const std::string& web_session_id,
411                                          bool has_additional_usable_key) {
412   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
413
414   // TODO(jrummell): Handling resume playback should be done in the media
415   // player, not in the Decryptors. http://crbug.com/413413.
416   if (has_additional_usable_key)
417     AttemptToResumePlayback();
418
419   session_keys_change_cb_.Run(web_session_id, has_additional_usable_key);
420 }
421
422 void PpapiDecryptor::OnSessionExpirationUpdate(
423     const std::string& web_session_id,
424     const base::Time& new_expiry_time) {
425   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
426   session_expiration_update_cb_.Run(web_session_id, new_expiry_time);
427 }
428
429 void PpapiDecryptor::OnSessionReady(const std::string& web_session_id) {
430   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
431   session_ready_cb_.Run(web_session_id);
432 }
433
434 void PpapiDecryptor::OnSessionClosed(const std::string& web_session_id) {
435   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
436   session_closed_cb_.Run(web_session_id);
437 }
438
439 void PpapiDecryptor::OnSessionError(const std::string& web_session_id,
440                                     MediaKeys::Exception exception_code,
441                                     uint32 system_code,
442                                     const std::string& error_description) {
443   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
444   session_error_cb_.Run(
445       web_session_id, exception_code, system_code, error_description);
446 }
447
448 void PpapiDecryptor::AttemptToResumePlayback() {
449   if (!new_audio_key_cb_.is_null())
450     new_audio_key_cb_.Run();
451
452   if (!new_video_key_cb_.is_null())
453     new_video_key_cb_.Run();
454 }
455
456 void PpapiDecryptor::OnFatalPluginError() {
457   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
458   pepper_cdm_wrapper_.reset();
459 }
460
461 ContentDecryptorDelegate* PpapiDecryptor::CdmDelegate() {
462   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
463   return (pepper_cdm_wrapper_) ? pepper_cdm_wrapper_->GetCdmDelegate() : NULL;
464 }
465
466 }  // namespace content