cdm_wrapper.h revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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
18namespace 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.
36class 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.
108template <class CdmInterface>
109class 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
287template <>
288void 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
304template <>
305void 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
314template <>
315void 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
327template <>
328void 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
338CdmWrapper* 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.
377COMPILE_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