Home | History | Annotate | Download | only in ppapi
      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