blob: f11672cadc33bf51632900c57f2581bd163be7d1 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_CDM_PPAPI_CDM_WRAPPER_H_
#define MEDIA_CDM_PPAPI_CDM_WRAPPER_H_
#include <map>
#include <queue>
#include <string>
#include "base/basictypes.h"
#include "media/cdm/ppapi/api/content_decryption_module.h"
#include "media/cdm/ppapi/cdm_helpers.h"
#include "media/cdm/ppapi/supported_cdm_versions.h"
#include "ppapi/cpp/logging.h"
namespace media {
// CdmWrapper wraps different versions of ContentDecryptionModule interfaces and
// exposes a common interface to the caller.
//
// The caller should call CdmWrapper::Create() to create a CDM instance.
// CdmWrapper will first try to create a CDM instance that supports the latest
// CDM interface (ContentDecryptionModule). If such an instance cannot be
// created (e.g. an older CDM was loaded), CdmWrapper will try to create a CDM
// that supports an older version of CDM interface (e.g.
// ContentDecryptionModule_*). Internally CdmWrapper converts the CdmWrapper
// calls to corresponding ContentDecryptionModule calls.
//
// Note that CdmWrapper interface always reflects the latest state of content
// decryption related PPAPI APIs (e.g. pp::ContentDecryptor_Private).
//
// Since this file is highly templated and default implementations are short
// (just a shim layer in most cases), everything is done in this header file.
class CdmWrapper {
public:
static CdmWrapper* Create(const char* key_system,
uint32_t key_system_size,
GetCdmHostFunc get_cdm_host_func,
void* user_data);
virtual ~CdmWrapper() {};
virtual void CreateSession(uint32_t promise_id,
const char* init_data_type,
uint32_t init_data_type_size,
const uint8_t* init_data,
uint32_t init_data_size,
cdm::SessionType session_type) = 0;
virtual void LoadSession(uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) = 0;
virtual void UpdateSession(uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size,
const uint8_t* response,
uint32_t response_size) = 0;
// TODO(jrummell): Remove return value when CDM4/5 are removed.
virtual bool CloseSession(uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) = 0;
virtual void RemoveSession(uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) = 0;
// TODO(jrummell): Remove return value when CDM4/5 are removed.
virtual bool GetUsableKeyIds(uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) = 0;
virtual void TimerExpired(void* context) = 0;
virtual cdm::Status Decrypt(const cdm::InputBuffer& encrypted_buffer,
cdm::DecryptedBlock* decrypted_buffer) = 0;
virtual cdm::Status InitializeAudioDecoder(
const cdm::AudioDecoderConfig& audio_decoder_config) = 0;
virtual cdm::Status InitializeVideoDecoder(
const cdm::VideoDecoderConfig& video_decoder_config) = 0;
virtual void DeinitializeDecoder(cdm::StreamType decoder_type) = 0;
virtual void ResetDecoder(cdm::StreamType decoder_type) = 0;
virtual cdm::Status DecryptAndDecodeFrame(
const cdm::InputBuffer& encrypted_buffer,
cdm::VideoFrame* video_frame) = 0;
virtual cdm::Status DecryptAndDecodeSamples(
const cdm::InputBuffer& encrypted_buffer,
cdm::AudioFrames* audio_frames) = 0;
virtual void OnPlatformChallengeResponse(
const cdm::PlatformChallengeResponse& response) = 0;
virtual void OnQueryOutputProtectionStatus(
uint32_t link_mask,
uint32_t output_protection_mask) = 0;
// Helper function for the cdm::Host_4 methods. Calls to CreateSession(),
// LoadSession(), UpdateSession(), and ReleaseSession() pass in promise ids,
// but the CDM interface needs session ids. For create and load, we need to
// create a new session_id to pass to the CDM. For update and release, we need
// to look up |web_session_id| and convert it into the existing |session_id|.
// Since the callbacks don't come through this interface, cdm_adapter needs to
// create the mapping (and delete it on release).
// TODO(jrummell): Remove these once Host_4 interface is removed.
virtual uint32_t LookupPromiseId(uint32_t session_id) = 0;
virtual void AssignWebSessionId(uint32_t session_id,
const char* web_session_id,
uint32_t web_session_id_size) = 0;
virtual std::string LookupWebSessionId(uint32_t session_id) = 0;
virtual void DropWebSessionId(std::string web_session_id) = 0;
// Helper functions for the cdm::Host_4 and cdm::Host_5 methods.
// CDMs using cdm::Host_6 will call OnSessionUsableKeys() as necessary when
// resolving LoadSession() and UpdateSession(). This needs to be simulated
// for the older CDMs. These must not be called for cdm::Host_6 and later.
// TODO(jrummell): Remove these once Host_4 and Host_5 interfaces are removed.
// Query whether a SessionUsableKeys event is necessary for the specified
// |promise_id|. Returns true if needed and |web_session_id| is updated,
// otherwise returns false.
virtual bool SessionUsableKeysEventNeeded(uint32_t promise_id,
std::string* web_session_id) = 0;
// Used to indicate that a SessionUsableKeys event is required for the
// specified |promise_id| and associated |web_session_id|.
virtual void SetSessionUsableKeysEventNeeded(
uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) = 0;
// cdm::Host_6 introduces InputBuffer_2 (aka InputBuffer). cdm::Host_4 and
// cdm::Host_5 methods still use InputBuffer_1, so this helper function
// converts InputBuffer_2 to InputBuffer_1.
// TODO(jrummell): Remove these once Host_4 and Host_5 interfaces are removed.
virtual void ConvertInputBuffer(const cdm::InputBuffer& v2,
cdm::InputBuffer_1* v1) = 0;
// Prior to CDM_6, |init_data_type| was a content type. This helper convererts
// an |init_data_type| to a content type.
// TODO(sandersd): Remove once Host_4 and Host_5 interfaces are removed.
virtual std::string ConvertInitDataTypeToContentType(
const std::string& init_data_type) const = 0;
protected:
CdmWrapper() {}
private:
DISALLOW_COPY_AND_ASSIGN(CdmWrapper);
};
// Template class that does the CdmWrapper -> CdmInterface conversion. Default
// implementations are provided. Any methods that need special treatment should
// be specialized.
template <class CdmInterface>
class CdmWrapperImpl : public CdmWrapper {
public:
static CdmWrapper* Create(const char* key_system,
uint32_t key_system_size,
GetCdmHostFunc get_cdm_host_func,
void* user_data) {
void* cdm_instance = ::CreateCdmInstance(
CdmInterface::kVersion, key_system, key_system_size, get_cdm_host_func,
user_data);
if (!cdm_instance)
return NULL;
return new CdmWrapperImpl<CdmInterface>(
static_cast<CdmInterface*>(cdm_instance));
}
virtual ~CdmWrapperImpl() {
cdm_->Destroy();
}
// Returns true if |data| is prefixed with |header| and has data after the
// |header|.
bool HasHeader(const uint8* data,
int data_length,
const std::string& header) {
return static_cast<size_t>(data_length) > header.length() &&
std::equal(data, data + header.length(), header.begin());
}
virtual void CreateSession(uint32_t promise_id,
const char* init_data_type,
uint32_t init_data_type_size,
const uint8_t* init_data,
uint32_t init_data_size,
cdm::SessionType session_type) OVERRIDE {
// TODO(jrummell): Remove this code once |session_type| is passed through
// Pepper. When removing, add the header back in for CDM4.
PP_DCHECK(session_type == cdm::kTemporary);
const char kPersistentSessionHeader[] = "PERSISTENT|";
if (HasHeader(init_data, init_data_size, kPersistentSessionHeader)) {
cdm_->CreateSession(promise_id,
init_data_type,
init_data_type_size,
init_data + strlen(kPersistentSessionHeader),
init_data_size - strlen(kPersistentSessionHeader),
cdm::kPersistent);
return;
}
cdm_->CreateSession(promise_id,
init_data_type,
init_data_type_size,
init_data,
init_data_size,
session_type);
}
virtual void LoadSession(uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) OVERRIDE {
cdm_->LoadSession(promise_id, web_session_id, web_session_id_size);
}
virtual void UpdateSession(uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size,
const uint8_t* response,
uint32_t response_size) OVERRIDE {
cdm_->UpdateSession(promise_id,
web_session_id,
web_session_id_size,
response,
response_size);
}
virtual bool GetUsableKeyIds(uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) OVERRIDE {
cdm_->GetUsableKeyIds(promise_id, web_session_id, web_session_id_size);
return true;
}
virtual bool CloseSession(uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) OVERRIDE {
cdm_->CloseSession(promise_id, web_session_id, web_session_id_size);
return true;
}
virtual void RemoveSession(uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) OVERRIDE {
cdm_->RemoveSession(promise_id, web_session_id, web_session_id_size);
}
virtual void TimerExpired(void* context) OVERRIDE {
cdm_->TimerExpired(context);
}
virtual cdm::Status Decrypt(const cdm::InputBuffer& encrypted_buffer,
cdm::DecryptedBlock* decrypted_buffer) OVERRIDE {
return cdm_->Decrypt(encrypted_buffer, decrypted_buffer);
}
virtual cdm::Status InitializeAudioDecoder(
const cdm::AudioDecoderConfig& audio_decoder_config) OVERRIDE {
return cdm_->InitializeAudioDecoder(audio_decoder_config);
}
virtual cdm::Status InitializeVideoDecoder(
const cdm::VideoDecoderConfig& video_decoder_config) OVERRIDE {
return cdm_->InitializeVideoDecoder(video_decoder_config);
}
virtual void DeinitializeDecoder(cdm::StreamType decoder_type) OVERRIDE {
cdm_->DeinitializeDecoder(decoder_type);
}
virtual void ResetDecoder(cdm::StreamType decoder_type) OVERRIDE {
cdm_->ResetDecoder(decoder_type);
}
virtual cdm::Status DecryptAndDecodeFrame(
const cdm::InputBuffer& encrypted_buffer,
cdm::VideoFrame* video_frame) OVERRIDE {
return cdm_->DecryptAndDecodeFrame(encrypted_buffer, video_frame);
}
virtual cdm::Status DecryptAndDecodeSamples(
const cdm::InputBuffer& encrypted_buffer,
cdm::AudioFrames* audio_frames) OVERRIDE {
return cdm_->DecryptAndDecodeSamples(encrypted_buffer, audio_frames);
}
virtual void OnPlatformChallengeResponse(
const cdm::PlatformChallengeResponse& response) OVERRIDE {
cdm_->OnPlatformChallengeResponse(response);
}
virtual void OnQueryOutputProtectionStatus(
uint32_t link_mask,
uint32_t output_protection_mask) OVERRIDE {
cdm_->OnQueryOutputProtectionStatus(link_mask, output_protection_mask);
}
uint32_t CreateSessionId() {
return next_session_id_++;
}
void RegisterPromise(uint32_t session_id, uint32_t promise_id) {
PP_DCHECK(promise_to_session_id_map_.find(session_id) ==
promise_to_session_id_map_.end());
promise_to_session_id_map_.insert(std::make_pair(session_id, promise_id));
}
virtual uint32_t LookupPromiseId(uint32_t session_id) {
std::map<uint32_t, uint32_t>::iterator it =
promise_to_session_id_map_.find(session_id);
if (it == promise_to_session_id_map_.end())
return 0;
uint32_t promise_id = it->second;
promise_to_session_id_map_.erase(it);
return promise_id;
}
virtual void AssignWebSessionId(uint32_t session_id,
const char* web_session_id,
uint32_t web_session_id_size) {
web_session_to_session_id_map_.insert(std::make_pair(
std::string(web_session_id, web_session_id_size), session_id));
}
uint32_t LookupSessionId(std::string web_session_id) {
return web_session_to_session_id_map_.find(web_session_id)->second;
}
virtual std::string LookupWebSessionId(uint32_t session_id) {
std::map<std::string, uint32_t>::iterator it;
for (it = web_session_to_session_id_map_.begin();
it != web_session_to_session_id_map_.end();
++it) {
if (it->second == session_id)
return it->first;
}
PP_NOTREACHED();
return std::string();
}
virtual void DropWebSessionId(std::string web_session_id) {
web_session_to_session_id_map_.erase(web_session_id);
}
virtual bool SessionUsableKeysEventNeeded(uint32_t promise_id,
std::string* web_session_id) {
std::map<uint32_t, std::string>::iterator it =
promises_needing_usable_keys_event_.find(promise_id);
if (it == promises_needing_usable_keys_event_.end())
return false;
web_session_id->swap(it->second);
promises_needing_usable_keys_event_.erase(it);
return true;
}
virtual void SetSessionUsableKeysEventNeeded(uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) {
promises_needing_usable_keys_event_.insert(std::make_pair(
promise_id, std::string(web_session_id, web_session_id_size)));
}
virtual void ConvertInputBuffer(const cdm::InputBuffer& v2,
cdm::InputBuffer_1* v1) {
v1->data = v2.data;
v1->data_size = v2.data_size;
v1->data_offset = 0;
v1->key_id = v2.key_id;
v1->key_id_size = v2.key_id_size;
v1->iv = v2.iv;
v1->iv_size = v2.iv_size;
v1->subsamples = v2.subsamples;
v1->num_subsamples = v2.num_subsamples;
v1->timestamp = v2.timestamp;
}
virtual std::string ConvertInitDataTypeToContentType(
const std::string& init_data_type) const {
if (init_data_type == "cenc")
return "video/mp4";
if (init_data_type == "webm")
return "video/webm";
return init_data_type;
}
private:
CdmWrapperImpl(CdmInterface* cdm) : cdm_(cdm), next_session_id_(100) {
PP_DCHECK(cdm_);
}
CdmInterface* cdm_;
std::map<uint32_t, uint32_t> promise_to_session_id_map_;
uint32_t next_session_id_;
std::map<std::string, uint32_t> web_session_to_session_id_map_;
std::map<uint32_t, std::string> promises_needing_usable_keys_event_;
DISALLOW_COPY_AND_ASSIGN(CdmWrapperImpl);
};
// Overrides for the cdm::Host_4 methods. Calls to CreateSession(),
// LoadSession(), UpdateSession(), and ReleaseSession() pass in promise ids,
// but the CDM interface needs session ids. For create and load, we need to
// create a new session_id to pass to the CDM. For update and release, we need
// to look up |web_session_id| and convert it into the existing |session_id|.
// Since the callbacks don't come through this interface, cdm_adapter needs to
// create the mapping (and delete it on release). Finally, for create, we need
// to translate |init_data_type| to a MIME type.
// TODO(jrummell): Remove these once Host_4 interface is removed.
template <>
void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::CreateSession(
uint32_t promise_id,
const char* init_data_type,
uint32_t init_data_type_size,
const uint8_t* init_data,
uint32_t init_data_size,
cdm::SessionType session_type) {
uint32_t session_id = CreateSessionId();
RegisterPromise(session_id, promise_id);
std::string converted_init_data_type = ConvertInitDataTypeToContentType(
std::string(init_data_type, init_data_type_size));
cdm_->CreateSession(session_id,
converted_init_data_type.data(),
converted_init_data_type.length(),
init_data,
init_data_size);
}
template <>
void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::LoadSession(
uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) {
uint32_t session_id = CreateSessionId();
RegisterPromise(session_id, promise_id);
// As CDM_4 doesn't support OnSessionUsableKeysChange(), make sure to generate
// one when the promise is resolved. This may be overly aggressive.
SetSessionUsableKeysEventNeeded(
promise_id, web_session_id, web_session_id_size);
cdm_->LoadSession(session_id, web_session_id, web_session_id_size);
}
template <>
void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::UpdateSession(
uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size,
const uint8_t* response,
uint32_t response_size) {
std::string web_session_str(web_session_id, web_session_id_size);
uint32_t session_id = LookupSessionId(web_session_str);
RegisterPromise(session_id, promise_id);
// As CDM_4 doesn't support OnSessionUsableKeysChange(), make sure to generate
// one when the promise is resolved. This may be overly aggressive.
SetSessionUsableKeysEventNeeded(
promise_id, web_session_id, web_session_id_size);
cdm_->UpdateSession(session_id, response, response_size);
}
template <>
bool CdmWrapperImpl<cdm::ContentDecryptionModule_4>::CloseSession(
uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) {
return false;
}
template <>
void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::RemoveSession(
uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) {
std::string web_session_str(web_session_id, web_session_id_size);
uint32_t session_id = LookupSessionId(web_session_str);
RegisterPromise(session_id, promise_id);
cdm_->ReleaseSession(session_id);
}
template <>
bool CdmWrapperImpl<cdm::ContentDecryptionModule_4>::GetUsableKeyIds(
uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) {
return false;
}
template <>
cdm::Status CdmWrapperImpl<cdm::ContentDecryptionModule_4>::Decrypt(
const cdm::InputBuffer& encrypted_buffer,
cdm::DecryptedBlock* decrypted_buffer) {
cdm::InputBuffer_1 buffer;
ConvertInputBuffer(encrypted_buffer, &buffer);
return cdm_->Decrypt(buffer, decrypted_buffer);
}
template <>
cdm::Status
CdmWrapperImpl<cdm::ContentDecryptionModule_4>::DecryptAndDecodeFrame(
const cdm::InputBuffer& encrypted_buffer,
cdm::VideoFrame* video_frame) {
cdm::InputBuffer_1 buffer;
ConvertInputBuffer(encrypted_buffer, &buffer);
return cdm_->DecryptAndDecodeFrame(buffer, video_frame);
}
template <>
cdm::Status
CdmWrapperImpl<cdm::ContentDecryptionModule_4>::DecryptAndDecodeSamples(
const cdm::InputBuffer& encrypted_buffer,
cdm::AudioFrames* audio_frames) {
cdm::InputBuffer_1 buffer;
ConvertInputBuffer(encrypted_buffer, &buffer);
return cdm_->DecryptAndDecodeSamples(buffer, audio_frames);
}
// Overrides for the cdm::Host_5 methods.
// TODO(jrummell): Remove these once Host_5 interface is removed.
template <>
void CdmWrapperImpl<cdm::ContentDecryptionModule_5>::CreateSession(
uint32_t promise_id,
const char* init_data_type,
uint32_t init_data_type_size,
const uint8_t* init_data,
uint32_t init_data_size,
cdm::SessionType session_type) {
std::string converted_init_data_type = ConvertInitDataTypeToContentType(
std::string(init_data_type, init_data_type_size));
// TODO(jrummell): Remove this code once |session_type| is passed through
// Pepper. When removing, add the header back in for CDM4.
PP_DCHECK(session_type == cdm::kTemporary);
const char kPersistentSessionHeader[] = "PERSISTENT|";
if (HasHeader(init_data, init_data_size, kPersistentSessionHeader)) {
cdm_->CreateSession(promise_id,
converted_init_data_type.data(),
converted_init_data_type.length(),
init_data + strlen(kPersistentSessionHeader),
init_data_size - strlen(kPersistentSessionHeader),
cdm::kPersistent);
return;
}
cdm_->CreateSession(promise_id,
converted_init_data_type.data(),
converted_init_data_type.length(),
init_data,
init_data_size,
session_type);
}
template <>
void CdmWrapperImpl<cdm::ContentDecryptionModule_5>::LoadSession(
uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) {
// As CDM_5 doesn't support OnSessionUsableKeysChange(), make sure to generate
// one when the promise is resolved. This may be overly aggressive.
SetSessionUsableKeysEventNeeded(
promise_id, web_session_id, web_session_id_size);
cdm_->LoadSession(promise_id, web_session_id, web_session_id_size);
}
template <>
void CdmWrapperImpl<cdm::ContentDecryptionModule_5>::UpdateSession(
uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size,
const uint8_t* response,
uint32_t response_size) {
// As CDM_5 doesn't support OnSessionUsableKeysChange(), make sure to generate
// one when the promise is resolved. This may be overly aggressive.
SetSessionUsableKeysEventNeeded(
promise_id, web_session_id, web_session_id_size);
cdm_->UpdateSession(
promise_id, web_session_id, web_session_id_size, response, response_size);
}
template <>
bool CdmWrapperImpl<cdm::ContentDecryptionModule_5>::CloseSession(
uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) {
return false;
}
template <>
void CdmWrapperImpl<cdm::ContentDecryptionModule_5>::RemoveSession(
uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) {
cdm_->ReleaseSession(promise_id, web_session_id, web_session_id_size);
}
template <>
bool CdmWrapperImpl<cdm::ContentDecryptionModule_5>::GetUsableKeyIds(
uint32_t promise_id,
const char* web_session_id,
uint32_t web_session_id_size) {
return false;
}
template <>
cdm::Status CdmWrapperImpl<cdm::ContentDecryptionModule_5>::Decrypt(
const cdm::InputBuffer& encrypted_buffer,
cdm::DecryptedBlock* decrypted_buffer) {
cdm::InputBuffer_1 buffer;
ConvertInputBuffer(encrypted_buffer, &buffer);
return cdm_->Decrypt(buffer, decrypted_buffer);
}
template <>
cdm::Status
CdmWrapperImpl<cdm::ContentDecryptionModule_5>::DecryptAndDecodeFrame(
const cdm::InputBuffer& encrypted_buffer,
cdm::VideoFrame* video_frame) {
cdm::InputBuffer_1 buffer;
ConvertInputBuffer(encrypted_buffer, &buffer);
return cdm_->DecryptAndDecodeFrame(buffer, video_frame);
}
template <>
cdm::Status
CdmWrapperImpl<cdm::ContentDecryptionModule_5>::DecryptAndDecodeSamples(
const cdm::InputBuffer& encrypted_buffer,
cdm::AudioFrames* audio_frames) {
cdm::InputBuffer_1 buffer;
ConvertInputBuffer(encrypted_buffer, &buffer);
return cdm_->DecryptAndDecodeSamples(buffer, audio_frames);
}
CdmWrapper* CdmWrapper::Create(const char* key_system,
uint32_t key_system_size,
GetCdmHostFunc get_cdm_host_func,
void* user_data) {
COMPILE_ASSERT(cdm::ContentDecryptionModule::kVersion ==
cdm::ContentDecryptionModule_6::kVersion,
update_code_below);
// Ensure IsSupportedCdmInterfaceVersion() matches this implementation.
// Always update this DCHECK when updating this function.
// If this check fails, update this function and DCHECK or update
// IsSupportedCdmInterfaceVersion().
PP_DCHECK(
!IsSupportedCdmInterfaceVersion(cdm::ContentDecryptionModule::kVersion +
1) &&
IsSupportedCdmInterfaceVersion(cdm::ContentDecryptionModule::kVersion) &&
IsSupportedCdmInterfaceVersion(
cdm::ContentDecryptionModule_4::kVersion) &&
!IsSupportedCdmInterfaceVersion(cdm::ContentDecryptionModule_4::kVersion -
1));
// Try to create the CDM using the latest CDM interface version.
CdmWrapper* cdm_wrapper =
CdmWrapperImpl<cdm::ContentDecryptionModule>::Create(
key_system, key_system_size, get_cdm_host_func, user_data);
if (cdm_wrapper)
return cdm_wrapper;
// If |cdm_wrapper| is NULL, try to create the CDM using older supported
// versions of the CDM interface.
cdm_wrapper = CdmWrapperImpl<cdm::ContentDecryptionModule_5>::Create(
key_system, key_system_size, get_cdm_host_func, user_data);
if (cdm_wrapper)
return cdm_wrapper;
cdm_wrapper = CdmWrapperImpl<cdm::ContentDecryptionModule_4>::Create(
key_system, key_system_size, get_cdm_host_func, user_data);
return cdm_wrapper;
}
// When updating the CdmAdapter, ensure you've updated the CdmWrapper to contain
// stub implementations for new or modified methods that the older CDM interface
// does not have.
// Also update supported_cdm_versions.h.
COMPILE_ASSERT(cdm::ContentDecryptionModule::kVersion ==
cdm::ContentDecryptionModule_6::kVersion,
ensure_cdm_wrapper_templates_have_old_version_support);
} // namespace media
#endif // MEDIA_CDM_PPAPI_CDM_WRAPPER_H_