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