Home | History | Annotate | Download | only in crypto
      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::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   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>();
     37   }
     38 
     39   plugin_cdm_delegate->Initialize(key_system);
     40 
     41   return scoped_ptr<PpapiDecryptor>(new PpapiDecryptor(plugin_instance,
     42                                                        plugin_cdm_delegate,
     43                                                        key_added_cb,
     44                                                        key_error_cb,
     45                                                        key_message_cb,
     46                                                        destroy_plugin_cb));
     47 }
     48 
     49 PpapiDecryptor::PpapiDecryptor(
     50     const scoped_refptr<PepperPluginInstanceImpl>& plugin_instance,
     51     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());
     66 
     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_));
     71 }
     72 
     73 PpapiDecryptor::~PpapiDecryptor() {
     74   plugin_cdm_delegate_ = NULL;
     75   plugin_instance_ = NULL;
     76   destroy_plugin_cb_.Run();
     77 }
     78 
     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_);
     85 
     86   if (!plugin_cdm_delegate_->GenerateKeyRequest(
     87       type, init_data, init_data_length)) {
     88     ReportFailureToCallPlugin(std::string());
     89     return false;
     90   }
     91 
     92   return true;
     93 }
     94 
     95 void PpapiDecryptor::AddKey(const uint8* key,
     96                             int key_length,
     97                             const uint8* init_data,
     98                             int init_data_length,
     99                             const std::string& session_id) {
    100   DVLOG(2) << "AddKey()";
    101   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
    102 
    103   if (!plugin_cdm_delegate_->AddKey(
    104       session_id, key, key_length, init_data, init_data_length)) {
    105     ReportFailureToCallPlugin(session_id);
    106   }
    107 
    108   if (!new_audio_key_cb_.is_null())
    109     new_audio_key_cb_.Run();
    110 
    111   if (!new_video_key_cb_.is_null())
    112     new_video_key_cb_.Run();
    113 }
    114 
    115 void PpapiDecryptor::CancelKeyRequest(const std::string& session_id) {
    116   DVLOG(2) << "CancelKeyRequest()";
    117   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
    118 
    119   if (!plugin_cdm_delegate_->CancelKeyRequest(session_id))
    120     ReportFailureToCallPlugin(session_id);
    121 }
    122 
    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.
    132   return NULL;
    133 #else
    134   return this;
    135 #endif  // defined(GOOGLE_TV)
    136 }
    137 
    138 void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type,
    139                                       const NewKeyCB& new_key_cb) {
    140   switch (stream_type) {
    141     case kAudio:
    142       new_audio_key_cb_ = new_key_cb;
    143       break;
    144     case kVideo:
    145       new_video_key_cb_ = new_key_cb;
    146       break;
    147     default:
    148       NOTREACHED();
    149   }
    150 }
    151 
    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));
    160     return;
    161   }
    162 
    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);
    166 }
    167 
    168 void PpapiDecryptor::CancelDecrypt(StreamType stream_type) {
    169   DVLOG(1) << "CancelDecrypt() - stream_type: " << stream_type;
    170   plugin_cdm_delegate_->CancelDecrypt(stream_type);
    171 }
    172 
    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));
    179     return;
    180   }
    181 
    182   DVLOG(2) << "InitializeAudioDecoder()";
    183   DCHECK(config.is_encrypted());
    184   DCHECK(config.IsValidConfig());
    185 
    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);
    190     return;
    191   }
    192 }
    193 
    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));
    200     return;
    201   }
    202 
    203   DVLOG(2) << "InitializeVideoDecoder()";
    204   DCHECK(config.is_encrypted());
    205   DCHECK(config.IsValidConfig());
    206 
    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);
    211     return;
    212   }
    213 }
    214 
    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));
    222     return;
    223   }
    224 
    225   DVLOG(3) << "DecryptAndDecodeAudio()";
    226   if (!plugin_cdm_delegate_->DecryptAndDecodeAudio(encrypted, audio_decode_cb))
    227     audio_decode_cb.Run(kError, AudioBuffers());
    228 }
    229 
    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));
    237     return;
    238   }
    239 
    240   DVLOG(3) << "DecryptAndDecodeVideo()";
    241   if (!plugin_cdm_delegate_->DecryptAndDecodeVideo(encrypted, video_decode_cb))
    242     video_decode_cb.Run(kError, NULL);
    243 }
    244 
    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));
    249     return;
    250   }
    251 
    252   DVLOG(2) << "ResetDecoder() - stream_type: " << stream_type;
    253   plugin_cdm_delegate_->ResetDecoder(stream_type);
    254 }
    255 
    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));
    260     return;
    261   }
    262 
    263   DVLOG(2) << "DeinitializeDecoder() - stream_type: " << stream_type;
    264   plugin_cdm_delegate_->DeinitializeDecoder(stream_type);
    265 }
    266 
    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);
    270 }
    271 
    272 void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type,
    273                                           bool success) {
    274   switch (stream_type) {
    275     case kAudio:
    276       DCHECK(!audio_decoder_init_cb_.is_null());
    277       base::ResetAndReturn(&audio_decoder_init_cb_).Run(success);
    278       break;
    279     case kVideo:
    280       DCHECK(!video_decoder_init_cb_.is_null());
    281       base::ResetAndReturn(&video_decoder_init_cb_).Run(success);
    282       break;
    283     default:
    284       NOTREACHED();
    285   }
    286 }
    287 
    288 void PpapiDecryptor::KeyAdded(const std::string& session_id) {
    289   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
    290   key_added_cb_.Run(session_id);
    291 }
    292 
    293 void PpapiDecryptor::KeyError(const std::string& session_id,
    294                               media::MediaKeys::KeyError error_code,
    295                               int system_code) {
    296   DCHECK(render_loop_proxy_->BelongsToCurrentThread());
    297   key_error_cb_.Run(session_id, error_code, system_code);
    298 }
    299 
    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);
    305 }
    306 
    307 }  // namespace content
    308