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 #ifndef MEDIA_CDM_PPAPI_CDM_WRAPPER_H_ 6 #define MEDIA_CDM_PPAPI_CDM_WRAPPER_H_ 7 8 #include <map> 9 #include <queue> 10 #include <string> 11 12 #include "base/basictypes.h" 13 #include "media/cdm/ppapi/api/content_decryption_module.h" 14 #include "media/cdm/ppapi/cdm_helpers.h" 15 #include "media/cdm/ppapi/supported_cdm_versions.h" 16 #include "ppapi/cpp/logging.h" 17 18 namespace media { 19 20 // CdmWrapper wraps different versions of ContentDecryptionModule interfaces and 21 // exposes a common interface to the caller. 22 // 23 // The caller should call CdmWrapper::Create() to create a CDM instance. 24 // CdmWrapper will first try to create a CDM instance that supports the latest 25 // CDM interface (ContentDecryptionModule). If such an instance cannot be 26 // created (e.g. an older CDM was loaded), CdmWrapper will try to create a CDM 27 // that supports an older version of CDM interface (e.g. 28 // ContentDecryptionModule_*). Internally CdmWrapper converts the CdmWrapper 29 // calls to corresponding ContentDecryptionModule calls. 30 // 31 // Note that CdmWrapper interface always reflects the latest state of content 32 // decryption related PPAPI APIs (e.g. pp::ContentDecryptor_Private). 33 // 34 // Since this file is highly templated and default implementations are short 35 // (just a shim layer in most cases), everything is done in this header file. 36 class CdmWrapper { 37 public: 38 static CdmWrapper* Create(const char* key_system, 39 uint32_t key_system_size, 40 GetCdmHostFunc get_cdm_host_func, 41 void* user_data); 42 43 virtual ~CdmWrapper() {}; 44 45 virtual void CreateSession(uint32_t promise_id, 46 const char* init_data_type, 47 uint32_t init_data_type_size, 48 const uint8_t* init_data, 49 uint32_t init_data_size, 50 cdm::SessionType session_type) = 0; 51 virtual void LoadSession(uint32_t promise_id, 52 const char* web_session_id, 53 uint32_t web_session_id_size) = 0; 54 virtual void UpdateSession(uint32_t promise_id, 55 const char* web_session_id, 56 uint32_t web_session_id_size, 57 const uint8_t* response, 58 uint32_t response_size) = 0; 59 virtual void ReleaseSession(uint32_t promise_id, 60 const char* web_session_id, 61 uint32_t web_session_id_size) = 0; 62 virtual void TimerExpired(void* context) = 0; 63 virtual cdm::Status Decrypt(const cdm::InputBuffer& encrypted_buffer, 64 cdm::DecryptedBlock* decrypted_buffer) = 0; 65 virtual cdm::Status InitializeAudioDecoder( 66 const cdm::AudioDecoderConfig& audio_decoder_config) = 0; 67 virtual cdm::Status InitializeVideoDecoder( 68 const cdm::VideoDecoderConfig& video_decoder_config) = 0; 69 virtual void DeinitializeDecoder(cdm::StreamType decoder_type) = 0; 70 virtual void ResetDecoder(cdm::StreamType decoder_type) = 0; 71 virtual cdm::Status DecryptAndDecodeFrame( 72 const cdm::InputBuffer& encrypted_buffer, 73 cdm::VideoFrame* video_frame) = 0; 74 virtual cdm::Status DecryptAndDecodeSamples( 75 const cdm::InputBuffer& encrypted_buffer, 76 cdm::AudioFrames* audio_frames) = 0; 77 virtual void OnPlatformChallengeResponse( 78 const cdm::PlatformChallengeResponse& response) = 0; 79 virtual void OnQueryOutputProtectionStatus( 80 uint32_t link_mask, 81 uint32_t output_protection_mask) = 0; 82 83 // Helper function for the cdm::Host_4 methods. Calls to CreateSession(), 84 // LoadSession(), UpdateSession(), and ReleaseSession() pass in promise ids, 85 // but the CDM interface needs session ids. For create and load, we need to 86 // create a new session_id to pass to the CDM. For update and release, we need 87 // to look up |web_session_id| and convert it into the existing |session_id|. 88 // Since the callbacks don't come through this interface, cdm_adapter needs to 89 // create the mapping (and delete it on release). 90 // TODO(jrummell): Remove these once Host_4 interface is removed. 91 virtual uint32_t LookupPromiseId(uint32_t session_id) = 0; 92 virtual void AssignWebSessionId(uint32_t session_id, 93 const char* web_session_id, 94 uint32_t web_session_id_size) = 0; 95 virtual std::string LookupWebSessionId(uint32_t session_id) = 0; 96 virtual void DropWebSessionId(std::string web_session_id) = 0; 97 98 protected: 99 CdmWrapper() {} 100 101 private: 102 DISALLOW_COPY_AND_ASSIGN(CdmWrapper); 103 }; 104 105 // Template class that does the CdmWrapper -> CdmInterface conversion. Default 106 // implementations are provided. Any methods that need special treatment should 107 // be specialized. 108 template <class CdmInterface> 109 class CdmWrapperImpl : public CdmWrapper { 110 public: 111 static CdmWrapper* Create(const char* key_system, 112 uint32_t key_system_size, 113 GetCdmHostFunc get_cdm_host_func, 114 void* user_data) { 115 void* cdm_instance = ::CreateCdmInstance( 116 CdmInterface::kVersion, key_system, key_system_size, get_cdm_host_func, 117 user_data); 118 if (!cdm_instance) 119 return NULL; 120 121 return new CdmWrapperImpl<CdmInterface>( 122 static_cast<CdmInterface*>(cdm_instance)); 123 } 124 125 virtual ~CdmWrapperImpl() { 126 cdm_->Destroy(); 127 } 128 129 virtual void CreateSession(uint32_t promise_id, 130 const char* init_data_type, 131 uint32_t init_data_type_size, 132 const uint8_t* init_data, 133 uint32_t init_data_size, 134 cdm::SessionType session_type) OVERRIDE { 135 cdm_->CreateSession(promise_id, 136 init_data_type, 137 init_data_type_size, 138 init_data, 139 init_data_size, 140 session_type); 141 } 142 143 virtual void LoadSession(uint32_t promise_id, 144 const char* web_session_id, 145 uint32_t web_session_id_size) OVERRIDE { 146 cdm_->LoadSession(promise_id, web_session_id, web_session_id_size); 147 } 148 149 virtual void UpdateSession(uint32_t promise_id, 150 const char* web_session_id, 151 uint32_t web_session_id_size, 152 const uint8_t* response, 153 uint32_t response_size) OVERRIDE { 154 cdm_->UpdateSession(promise_id, 155 web_session_id, 156 web_session_id_size, 157 response, 158 response_size); 159 } 160 161 virtual void ReleaseSession(uint32_t promise_id, 162 const char* web_session_id, 163 uint32_t web_session_id_size) OVERRIDE { 164 cdm_->ReleaseSession(promise_id, web_session_id, web_session_id_size); 165 } 166 167 virtual void TimerExpired(void* context) OVERRIDE { 168 cdm_->TimerExpired(context); 169 } 170 171 virtual cdm::Status Decrypt(const cdm::InputBuffer& encrypted_buffer, 172 cdm::DecryptedBlock* decrypted_buffer) OVERRIDE { 173 return cdm_->Decrypt(encrypted_buffer, decrypted_buffer); 174 } 175 176 virtual cdm::Status InitializeAudioDecoder( 177 const cdm::AudioDecoderConfig& audio_decoder_config) OVERRIDE { 178 return cdm_->InitializeAudioDecoder(audio_decoder_config); 179 } 180 181 virtual cdm::Status InitializeVideoDecoder( 182 const cdm::VideoDecoderConfig& video_decoder_config) OVERRIDE { 183 return cdm_->InitializeVideoDecoder(video_decoder_config); 184 } 185 186 virtual void DeinitializeDecoder(cdm::StreamType decoder_type) OVERRIDE { 187 cdm_->DeinitializeDecoder(decoder_type); 188 } 189 190 virtual void ResetDecoder(cdm::StreamType decoder_type) OVERRIDE { 191 cdm_->ResetDecoder(decoder_type); 192 } 193 194 virtual cdm::Status DecryptAndDecodeFrame( 195 const cdm::InputBuffer& encrypted_buffer, 196 cdm::VideoFrame* video_frame) OVERRIDE { 197 return cdm_->DecryptAndDecodeFrame(encrypted_buffer, video_frame); 198 } 199 200 virtual cdm::Status DecryptAndDecodeSamples( 201 const cdm::InputBuffer& encrypted_buffer, 202 cdm::AudioFrames* audio_frames) OVERRIDE { 203 return cdm_->DecryptAndDecodeSamples(encrypted_buffer, audio_frames); 204 } 205 206 virtual void OnPlatformChallengeResponse( 207 const cdm::PlatformChallengeResponse& response) OVERRIDE { 208 cdm_->OnPlatformChallengeResponse(response); 209 } 210 211 virtual void OnQueryOutputProtectionStatus( 212 uint32_t link_mask, 213 uint32_t output_protection_mask) OVERRIDE { 214 cdm_->OnQueryOutputProtectionStatus(link_mask, output_protection_mask); 215 } 216 217 uint32_t CreateSessionId() { 218 return next_session_id_++; 219 } 220 221 void RegisterPromise(uint32_t session_id, uint32_t promise_id) { 222 PP_DCHECK(promise_to_session_id_map_.find(session_id) == 223 promise_to_session_id_map_.end()); 224 promise_to_session_id_map_.insert(std::make_pair(session_id, promise_id)); 225 } 226 227 virtual uint32_t LookupPromiseId(uint32_t session_id) { 228 std::map<uint32_t, uint32_t>::iterator it = 229 promise_to_session_id_map_.find(session_id); 230 if (it == promise_to_session_id_map_.end()) 231 return 0; 232 uint32_t promise_id = it->second; 233 promise_to_session_id_map_.erase(it); 234 return promise_id; 235 } 236 237 virtual void AssignWebSessionId(uint32_t session_id, 238 const char* web_session_id, 239 uint32_t web_session_id_size) { 240 web_session_to_session_id_map_.insert(std::make_pair( 241 std::string(web_session_id, web_session_id_size), session_id)); 242 } 243 244 uint32_t LookupSessionId(std::string web_session_id) { 245 return web_session_to_session_id_map_.find(web_session_id)->second; 246 } 247 248 virtual std::string LookupWebSessionId(uint32_t session_id) { 249 std::map<std::string, uint32_t>::iterator it; 250 for (it = web_session_to_session_id_map_.begin(); 251 it != web_session_to_session_id_map_.end(); 252 ++it) { 253 if (it->second == session_id) 254 return it->first; 255 } 256 PP_NOTREACHED(); 257 return std::string(); 258 } 259 260 virtual void DropWebSessionId(std::string web_session_id) { 261 web_session_to_session_id_map_.erase(web_session_id); 262 } 263 264 private: 265 CdmWrapperImpl(CdmInterface* cdm) : cdm_(cdm), next_session_id_(100) { 266 PP_DCHECK(cdm_); 267 } 268 269 CdmInterface* cdm_; 270 271 std::map<uint32_t, uint32_t> promise_to_session_id_map_; 272 uint32_t next_session_id_; 273 std::map<std::string, uint32_t> web_session_to_session_id_map_; 274 275 DISALLOW_COPY_AND_ASSIGN(CdmWrapperImpl); 276 }; 277 278 // Overrides for the cdm::Host_4 methods. Calls to CreateSession(), 279 // LoadSession(), UpdateSession(), and ReleaseSession() pass in promise ids, 280 // but the CDM interface needs session ids. For create and load, we need to 281 // create a new session_id to pass to the CDM. For update and release, we need 282 // to look up |web_session_id| and convert it into the existing |session_id|. 283 // Since the callbacks don't come through this interface, cdm_adapter needs to 284 // create the mapping (and delete it on release). 285 // TODO(jrummell): Remove these once Host_4 interface is removed. 286 287 template <> 288 void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::CreateSession( 289 uint32_t promise_id, 290 const char* init_data_type, 291 uint32_t init_data_type_size, 292 const uint8_t* init_data, 293 uint32_t init_data_size, 294 cdm::SessionType session_type) { 295 uint32_t session_id = CreateSessionId(); 296 RegisterPromise(session_id, promise_id); 297 cdm_->CreateSession(session_id, 298 init_data_type, 299 init_data_type_size, 300 init_data, 301 init_data_size); 302 } 303 304 template <> 305 void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::LoadSession( 306 uint32_t promise_id, 307 const char* web_session_id, 308 uint32_t web_session_id_size) { 309 uint32_t session_id = CreateSessionId(); 310 RegisterPromise(session_id, promise_id); 311 cdm_->LoadSession(session_id, web_session_id, web_session_id_size); 312 } 313 314 template <> 315 void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::UpdateSession( 316 uint32_t promise_id, 317 const char* web_session_id, 318 uint32_t web_session_id_size, 319 const uint8_t* response, 320 uint32_t response_size) { 321 std::string web_session_str(web_session_id, web_session_id_size); 322 uint32_t session_id = LookupSessionId(web_session_str); 323 RegisterPromise(session_id, promise_id); 324 cdm_->UpdateSession(session_id, response, response_size); 325 } 326 327 template <> 328 void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::ReleaseSession( 329 uint32_t promise_id, 330 const char* web_session_id, 331 uint32_t web_session_id_size) { 332 std::string web_session_str(web_session_id, web_session_id_size); 333 uint32_t session_id = LookupSessionId(web_session_str); 334 RegisterPromise(session_id, promise_id); 335 cdm_->ReleaseSession(session_id); 336 } 337 338 CdmWrapper* CdmWrapper::Create(const char* key_system, 339 uint32_t key_system_size, 340 GetCdmHostFunc get_cdm_host_func, 341 void* user_data) { 342 COMPILE_ASSERT(cdm::ContentDecryptionModule::kVersion == 343 cdm::ContentDecryptionModule_5::kVersion, 344 update_code_below); 345 346 // Ensure IsSupportedCdmInterfaceVersion() matches this implementation. 347 // Always update this DCHECK when updating this function. 348 // If this check fails, update this function and DCHECK or update 349 // IsSupportedCdmInterfaceVersion(). 350 PP_DCHECK( 351 !IsSupportedCdmInterfaceVersion(cdm::ContentDecryptionModule::kVersion + 352 1) && 353 IsSupportedCdmInterfaceVersion(cdm::ContentDecryptionModule::kVersion) && 354 IsSupportedCdmInterfaceVersion( 355 cdm::ContentDecryptionModule_4::kVersion) && 356 !IsSupportedCdmInterfaceVersion(cdm::ContentDecryptionModule_4::kVersion - 357 1)); 358 359 // Try to create the CDM using the latest CDM interface version. 360 CdmWrapper* cdm_wrapper = 361 CdmWrapperImpl<cdm::ContentDecryptionModule>::Create( 362 key_system, key_system_size, get_cdm_host_func, user_data); 363 if (cdm_wrapper) 364 return cdm_wrapper; 365 366 // If |cdm_wrapper| is NULL, try to create the CDM using older supported 367 // versions of the CDM interface. 368 cdm_wrapper = CdmWrapperImpl<cdm::ContentDecryptionModule_4>::Create( 369 key_system, key_system_size, get_cdm_host_func, user_data); 370 return cdm_wrapper; 371 } 372 373 // When updating the CdmAdapter, ensure you've updated the CdmWrapper to contain 374 // stub implementations for new or modified methods that the older CDM interface 375 // does not have. 376 // Also update supported_cdm_versions.h. 377 COMPILE_ASSERT(cdm::ContentDecryptionModule::kVersion == 378 cdm::ContentDecryptionModule_5::kVersion, 379 ensure_cdm_wrapper_templates_have_old_version_support); 380 381 } // namespace media 382 383 #endif // MEDIA_CDM_PPAPI_CDM_WRAPPER_H_ 384