├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── app ├── CMakeLists.txt └── src │ ├── log.h │ └── main.cc ├── doc └── screenshot.png └── lib ├── CMakeLists.txt └── src ├── api ├── README.md ├── content_decryption_module.h ├── content_decryption_module_export.h └── content_decryption_module_ext.h ├── common └── log.h ├── lib.cc ├── lib.h └── proxy ├── cdm_host_proxy.cc ├── cdm_host_proxy.h ├── cdm_host_proxy_data.h ├── cdm_proxy.cc ├── cdm_proxy.h ├── lib_proxy.cc └── lib_proxy.h /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | cmake-build-* 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.17) 2 | 3 | project(cdm_proxy) 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | 7 | add_subdirectory(lib) 8 | add_subdirectory(app) 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Tomo Kunagisa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chromium CDM proxy 2 | 3 | ## Introduction 4 | 5 | A proxy shared library aims to monitor the data exchange between Chromium browser and WidevineCDM library. 6 | 7 | **ONLY works on Linux.** 8 | 9 | ## Usage 10 | 11 | * Build the libproxy for target platform. 12 | * Move original `libwidevinecdm.so` to other path. 13 | * Move/link `libproxy.so` to the path where `libwidevinecdm.so` was at. 14 | * Set environment variable `Z_CDM_LIB` with the full path of original `libwidevinecdm.so`. 15 | * Run Chromium/Chrome browser. 16 | 17 | All function call and data exchange will be logged to STDERR, prefixed with `[ZeasnLog]`. 18 | 19 | To recover the original Widevine CDM, simply move original `libwidevinecdm.so` back, replacing 20 | the proxy library. 21 | 22 | ## Example: 23 | 24 | > Assume OS architecture is x64, and Chrome browser is installed at "/opt/google/chrome", then 25 | > the WidevineCDM library can be found at "/opt/google/chrome/WidevineCdm/_platform_specific/linux_x64". 26 | 27 | ``` 28 | # 1. Move the original library to other path: 29 | cd /opt/google/chrome/WidevineCdm/_platform_specific/linux_x64/ 30 | sudo mv libwidevinecdm.so libwidevinecdm-original.so 31 | 32 | # 2. Link libproxy.so to here 33 | sudo ln -s /path/to/libproxy.so libwidevinecdm.so 34 | 35 | # 3. Manually quit chrome, or kill all running chrome process: 36 | killall -s 9 chrome 37 | 38 | # 4. Run browser with environment variable "Z_CDM_LIB". 39 | export Z_CDM_LIB=/opt/google/chrome/WidevineCdm/_platform_specific/linux_x64/libwidevinecdm-original.so 40 | /opt/google/chrome/google-chrome 41 | 42 | # 5. Open a URL which contains DRM protected video, then check the logging. 43 | ``` 44 | 45 | If everything is OK, you can see logging from the proxy library. 46 | 47 | ## Screenshot 48 | 49 | ![Screenshot](doc/screenshot.png) 50 | 51 | -------------------------------------------------------------------------------- /app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(loader) 2 | 3 | aux_source_directory(src SRC_FILES) 4 | 5 | add_executable(loader ${SRC_FILES}) 6 | 7 | target_link_libraries(loader PRIVATE dl) 8 | -------------------------------------------------------------------------------- /app/src/log.h: -------------------------------------------------------------------------------- 1 | #ifndef CDM_PROXY_LOG_H 2 | #define CDM_PROXY_LOG_H 3 | 4 | #include 5 | #include 6 | 7 | #define LOG_PREFIX "[ZeasnLog][%s(%d)] %s - " 8 | #define LOG_NEWLINE "\n" 9 | #define FILE_NAME strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__ 10 | 11 | #define ZLOG(message, args...) \ 12 | fprintf(stderr, LOG_PREFIX message LOG_NEWLINE, FILE_NAME, __LINE__, __FUNCTION__, ## args) 13 | 14 | #endif //CDM_PROXY_LOG_H 15 | -------------------------------------------------------------------------------- /app/src/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "log.h" 5 | 6 | typedef char *(* get_ver_func)(); 7 | 8 | int main(int argc, char * argv[]) { 9 | if(argc <= 1) { 10 | std::cout << "Usage: " 11 | << argv[0] << " " << std::endl; 12 | return 0; 13 | } 14 | 15 | ZLOG("Loading proxy lib: %s ...", argv[1]); 16 | auto hdr = dlopen(argv[1], RTLD_LAZY); 17 | if(hdr == nullptr) { 18 | ZLOG("Load error: %s", dlerror()); 19 | } else { 20 | // Call function on proxy 21 | auto func = (get_ver_func)dlsym(hdr, "GetCdmVersion"); 22 | auto version = func(); 23 | ZLOG("GetCdmVersion: %s", version); 24 | 25 | ZLOG("Unloading proxy ..."); 26 | dlclose(hdr); 27 | } 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /doc/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deadblue/chromium-cdm-proxy/312bdd34f095e13cacd111c954c187ab689e9d79/doc/screenshot.png -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(proxy) 2 | 3 | aux_source_directory(src/common SRC_FILES) 4 | aux_source_directory(src/api SRC_FILES) 5 | aux_source_directory(src/proxy SRC_FILES) 6 | aux_source_directory(src SRC_FILES) 7 | 8 | add_library(proxy SHARED ${SRC_FILES}) 9 | target_link_libraries(proxy PRIVATE dl) 10 | target_compile_options(proxy PRIVATE -fPIC -fvisibility=hidden) 11 | -------------------------------------------------------------------------------- /lib/src/api/README.md: -------------------------------------------------------------------------------- 1 | All header files under this directory are copied from Google Chromium project, so they are 2 | under the LICENSE which Chromium used. 3 | 4 | Source URL: https://source.chromium.org/chromium/chromium/src/+/master:media/cdm/api/ -------------------------------------------------------------------------------- /lib/src/api/content_decryption_module.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 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 CDM_PROXY_CONTENT_DECRYPTION_MODULE_H 6 | #define CDM_PROXY_CONTENT_DECRYPTION_MODULE_H 7 | 8 | #include 9 | 10 | #include "content_decryption_module_export.h" 11 | 12 | #if defined(_MSC_VER) 13 | typedef unsigned char uint8_t; 14 | typedef unsigned int uint32_t; 15 | typedef int int32_t; 16 | typedef __int64 int64_t; 17 | #else 18 | #include 19 | #endif 20 | 21 | // The version number must be rolled when the exported functions are updated! 22 | // If the CDM and the adapter use different versions of these functions, the 23 | // adapter will fail to load or crash! 24 | #define CDM_MODULE_VERSION 4 25 | 26 | // Build the versioned entrypoint name. 27 | // The extra macros are necessary to expand version to an actual value. 28 | #define INITIALIZE_CDM_MODULE \ 29 | BUILD_ENTRYPOINT(InitializeCdmModule, CDM_MODULE_VERSION) 30 | #define BUILD_ENTRYPOINT(name, version) \ 31 | BUILD_ENTRYPOINT_NO_EXPANSION(name, version) 32 | #define BUILD_ENTRYPOINT_NO_EXPANSION(name, version) name##_##version 33 | 34 | // Macro to check that |type| does the following: 35 | // 1. is a standard layout. 36 | // 2. is trivial. 37 | // 3. sizeof(type) matches the expected size in bytes. As some types contain 38 | // pointers, the size is specified for both 32 and 64 bit. 39 | #define CHECK_TYPE(type, size_32, size_64) \ 40 | static_assert(std::is_standard_layout(), \ 41 | #type " not standard_layout"); \ 42 | static_assert(std::is_trivial(), #type " not trivial"); \ 43 | static_assert((sizeof(void*) == 4 && sizeof(type) == size_32) || \ 44 | (sizeof(void*) == 8 && sizeof(type) == size_64), \ 45 | #type " size mismatch") 46 | 47 | extern "C" { 48 | 49 | CDM_API void INITIALIZE_CDM_MODULE(); 50 | 51 | CDM_API void DeinitializeCdmModule(); 52 | 53 | // Returns a pointer to the requested CDM Host interface upon success. 54 | // Returns NULL if the requested CDM Host interface is not supported. 55 | // The caller should cast the returned pointer to the type matching 56 | // |host_interface_version|. 57 | typedef void* (*GetCdmHostFunc)(int host_interface_version, void* user_data); 58 | 59 | // Returns a pointer to the requested CDM upon success. 60 | // Returns NULL if an error occurs or the requested |cdm_interface_version| or 61 | // |key_system| is not supported or another error occurs. 62 | // The caller should cast the returned pointer to the type matching 63 | // |cdm_interface_version|. 64 | // Caller retains ownership of arguments and must call Destroy() on the returned 65 | // object. 66 | CDM_API void* CreateCdmInstance(int cdm_interface_version, 67 | const char* key_system, 68 | uint32_t key_system_size, 69 | GetCdmHostFunc get_cdm_host_func, 70 | void* user_data); 71 | 72 | CDM_API const char* GetCdmVersion(); 73 | 74 | } // extern "C" 75 | 76 | namespace cdm { 77 | 78 | enum Status : uint32_t { 79 | kSuccess = 0, 80 | kNeedMoreData, // Decoder needs more data to produce a decoded frame/sample. 81 | kNoKey, // The required decryption key is not available. 82 | kInitializationError, // Initialization error. 83 | kDecryptError, // Decryption failed. 84 | kDecodeError, // Error decoding audio or video. 85 | kDeferredInitialization // Decoder is not ready for initialization. 86 | }; 87 | CHECK_TYPE(Status, 4, 4); 88 | 89 | // Exceptions used by the CDM to reject promises. 90 | // https://w3c.github.io/encrypted-media/#exceptions 91 | enum Exception : uint32_t { 92 | kExceptionTypeError, 93 | kExceptionNotSupportedError, 94 | kExceptionInvalidStateError, 95 | kExceptionQuotaExceededError 96 | }; 97 | CHECK_TYPE(Exception, 4, 4); 98 | 99 | // The encryption scheme. The definitions are from ISO/IEC 23001-7:2016. 100 | enum class EncryptionScheme : uint32_t { 101 | kUnencrypted = 0, 102 | kCenc, // 'cenc' subsample encryption using AES-CTR mode. 103 | kCbcs // 'cbcs' pattern encryption using AES-CBC mode. 104 | }; 105 | CHECK_TYPE(EncryptionScheme, 4, 4); 106 | 107 | // The pattern used for pattern encryption. Note that ISO/IEC 23001-7:2016 108 | // defines each block to be 16-bytes. 109 | struct Pattern { 110 | uint32_t crypt_byte_block; // Count of the encrypted blocks. 111 | uint32_t skip_byte_block; // Count of the unencrypted blocks. 112 | }; 113 | CHECK_TYPE(Pattern, 8, 8); 114 | 115 | enum class ColorRange : uint8_t { 116 | kInvalid, 117 | kLimited, // 709 color range with RGB values ranging from 16 to 235. 118 | kFull, // Full RGB color range with RGB values from 0 to 255. 119 | kDerived // Range is defined by |transfer_id| and |matrix_id|. 120 | }; 121 | CHECK_TYPE(ColorRange, 1, 1); 122 | 123 | // Described in ISO 23001-8:2016, section 7. All the IDs are in the range 124 | // [0, 255] so 8-bit integer is sufficient. An unspecified ColorSpace should be 125 | // {2, 2, 2, ColorRange::kInvalid}, where value 2 means "Unspecified" for all 126 | // the IDs, as defined by the spec. 127 | struct ColorSpace { 128 | uint8_t primary_id; // 7.1 colour primaries, table 2 129 | uint8_t transfer_id; // 7.2 transfer characteristics, table 3 130 | uint8_t matrix_id; // 7.3 matrix coefficients, table 4 131 | ColorRange range; 132 | }; 133 | CHECK_TYPE(ColorSpace, 4, 4); 134 | 135 | // Time is defined as the number of seconds since the Epoch 136 | // (00:00:00 UTC, January 1, 1970), not including any added leap second. 137 | // Also see Time definition in spec: https://w3c.github.io/encrypted-media/#time 138 | // Note that Time is defined in millisecond accuracy in the spec but in second 139 | // accuracy here. 140 | typedef double Time; 141 | 142 | // An input buffer can be split into several continuous subsamples. 143 | // A SubsampleEntry specifies the number of clear and cipher bytes in each 144 | // subsample. For example, the following buffer has three subsamples: 145 | // 146 | // |<----- subsample1 ----->|<----- subsample2 ----->|<----- subsample3 ----->| 147 | // | clear1 | cipher1 | clear2 | cipher2 | clear3 | cipher3 | 148 | // 149 | // For decryption, all of the cipher bytes in a buffer should be concatenated 150 | // (in the subsample order) into a single logical stream. The clear bytes should 151 | // not be considered as part of decryption. 152 | // 153 | // Stream to decrypt: | cipher1 | cipher2 | cipher3 | 154 | // Decrypted stream: | decrypted1| decrypted2 | decrypted3 | 155 | // 156 | // After decryption, the decrypted bytes should be copied over the position 157 | // of the corresponding cipher bytes in the original buffer to form the output 158 | // buffer. Following the above example, the decrypted buffer should be: 159 | // 160 | // |<----- subsample1 ----->|<----- subsample2 ----->|<----- subsample3 ----->| 161 | // | clear1 | decrypted1| clear2 | decrypted2 | clear3 | decrypted3 | 162 | // 163 | struct SubsampleEntry { 164 | uint32_t clear_bytes; 165 | uint32_t cipher_bytes; 166 | }; 167 | CHECK_TYPE(SubsampleEntry, 8, 8); 168 | 169 | // Represents an input buffer to be decrypted (and possibly decoded). It does 170 | // not own any pointers in this struct. If |encryption_scheme| = kUnencrypted, 171 | // the data is unencrypted. 172 | // Note that this struct is organized so that sizeof(InputBuffer_2) 173 | // equals the sum of sizeof() all members in both 32-bit and 64-bit compiles. 174 | // Padding has been added to keep the fields aligned. 175 | struct InputBuffer_2 { 176 | const uint8_t* data; // Pointer to the beginning of the input data. 177 | uint32_t data_size; // Size (in bytes) of |data|. 178 | 179 | EncryptionScheme encryption_scheme; 180 | 181 | const uint8_t* key_id; // Key ID to identify the decryption key. 182 | uint32_t key_id_size; // Size (in bytes) of |key_id|. 183 | uint32_t : 32; // Padding. 184 | 185 | const uint8_t* iv; // Initialization vector. 186 | uint32_t iv_size; // Size (in bytes) of |iv|. 187 | uint32_t : 32; // Padding. 188 | 189 | const struct SubsampleEntry* subsamples; 190 | uint32_t num_subsamples; // Number of subsamples in |subsamples|. 191 | uint32_t : 32; // Padding. 192 | 193 | // |pattern| is required if |encryption_scheme| specifies pattern encryption. 194 | Pattern pattern; 195 | 196 | int64_t timestamp; // Presentation timestamp in microseconds. 197 | }; 198 | CHECK_TYPE(InputBuffer_2, 64, 80); 199 | 200 | enum AudioCodec : uint32_t { kUnknownAudioCodec = 0, kCodecVorbis, kCodecAac }; 201 | CHECK_TYPE(AudioCodec, 4, 4); 202 | 203 | struct AudioDecoderConfig_2 { 204 | AudioCodec codec; 205 | int32_t channel_count; 206 | int32_t bits_per_channel; 207 | int32_t samples_per_second; 208 | 209 | // Optional byte data required to initialize audio decoders, such as the 210 | // vorbis setup header. 211 | uint8_t* extra_data; 212 | uint32_t extra_data_size; 213 | 214 | // Encryption scheme. 215 | EncryptionScheme encryption_scheme; 216 | }; 217 | CHECK_TYPE(AudioDecoderConfig_2, 28, 32); 218 | 219 | // Supported sample formats for AudioFrames. 220 | enum AudioFormat : uint32_t { 221 | kUnknownAudioFormat = 0, // Unknown format value. Used for error reporting. 222 | kAudioFormatU8, // Interleaved unsigned 8-bit w/ bias of 128. 223 | kAudioFormatS16, // Interleaved signed 16-bit. 224 | kAudioFormatS32, // Interleaved signed 32-bit. 225 | kAudioFormatF32, // Interleaved float 32-bit. 226 | kAudioFormatPlanarS16, // Signed 16-bit planar. 227 | kAudioFormatPlanarF32, // Float 32-bit planar. 228 | }; 229 | CHECK_TYPE(AudioFormat, 4, 4); 230 | 231 | // Surface formats based on FOURCC labels, see: http://www.fourcc.org/yuv.php 232 | // Values are chosen to be consistent with Chromium's VideoPixelFormat values. 233 | enum VideoFormat : uint32_t { 234 | kUnknownVideoFormat = 0, // Unknown format value. Used for error reporting. 235 | kYv12 = 1, // 12bpp YVU planar 1x1 Y, 2x2 VU samples. 236 | kI420 = 2, // 12bpp YUV planar 1x1 Y, 2x2 UV samples. 237 | 238 | // In the following formats, each sample uses 16-bit in storage, while the 239 | // sample value is stored in the least significant N bits where N is 240 | // specified by the number after "P". For example, for YUV420P9, each Y, U, 241 | // and V sample is stored in the least significant 9 bits in a 2-byte block. 242 | kYUV420P9 = 16, 243 | kYUV420P10 = 17, 244 | kYUV422P9 = 18, 245 | kYUV422P10 = 19, 246 | kYUV444P9 = 20, 247 | kYUV444P10 = 21, 248 | kYUV420P12 = 22, 249 | kYUV422P12 = 23, 250 | kYUV444P12 = 24, 251 | }; 252 | CHECK_TYPE(VideoFormat, 4, 4); 253 | 254 | struct Size { 255 | int32_t width; 256 | int32_t height; 257 | }; 258 | CHECK_TYPE(Size, 8, 8); 259 | 260 | enum VideoCodec : uint32_t { 261 | kUnknownVideoCodec = 0, 262 | kCodecVp8, 263 | kCodecH264, 264 | kCodecVp9, 265 | kCodecAv1 266 | }; 267 | CHECK_TYPE(VideoCodec, 4, 4); 268 | 269 | enum VideoCodecProfile : uint32_t { 270 | kUnknownVideoCodecProfile = 0, 271 | kProfileNotNeeded, 272 | kH264ProfileBaseline, 273 | kH264ProfileMain, 274 | kH264ProfileExtended, 275 | kH264ProfileHigh, 276 | kH264ProfileHigh10, 277 | kH264ProfileHigh422, 278 | kH264ProfileHigh444Predictive, 279 | kVP9Profile0, 280 | kVP9Profile1, 281 | kVP9Profile2, 282 | kVP9Profile3, 283 | kAv1ProfileMain, 284 | kAv1ProfileHigh, 285 | kAv1ProfilePro 286 | }; 287 | CHECK_TYPE(VideoCodecProfile, 4, 4); 288 | 289 | // Deprecated: New CDM implementations should use VideoDecoderConfig_3. 290 | // Note that this struct is organized so that sizeof(VideoDecoderConfig_2) 291 | // equals the sum of sizeof() all members in both 32-bit and 64-bit compiles. 292 | // Padding has been added to keep the fields aligned. 293 | struct VideoDecoderConfig_2 { 294 | VideoCodec codec; 295 | VideoCodecProfile profile; 296 | VideoFormat format; 297 | uint32_t : 32; // Padding. 298 | 299 | // Width and height of video frame immediately post-decode. Not all pixels 300 | // in this region are valid. 301 | Size coded_size; 302 | 303 | // Optional byte data required to initialize video decoders, such as H.264 304 | // AAVC data. 305 | uint8_t* extra_data; 306 | uint32_t extra_data_size; 307 | 308 | // Encryption scheme. 309 | EncryptionScheme encryption_scheme; 310 | }; 311 | CHECK_TYPE(VideoDecoderConfig_2, 36, 40); 312 | 313 | struct VideoDecoderConfig_3 { 314 | VideoCodec codec; 315 | VideoCodecProfile profile; 316 | VideoFormat format; 317 | ColorSpace color_space; 318 | 319 | // Width and height of video frame immediately post-decode. Not all pixels 320 | // in this region are valid. 321 | Size coded_size; 322 | 323 | // Optional byte data required to initialize video decoders, such as H.264 324 | // AAVC data. 325 | uint8_t* extra_data; 326 | uint32_t extra_data_size; 327 | 328 | EncryptionScheme encryption_scheme; 329 | }; 330 | CHECK_TYPE(VideoDecoderConfig_3, 36, 40); 331 | 332 | enum StreamType : uint32_t { kStreamTypeAudio = 0, kStreamTypeVideo = 1 }; 333 | CHECK_TYPE(StreamType, 4, 4); 334 | 335 | // Structure provided to ContentDecryptionModule::OnPlatformChallengeResponse() 336 | // after a platform challenge was initiated via Host::SendPlatformChallenge(). 337 | // All values will be NULL / zero in the event of a challenge failure. 338 | struct PlatformChallengeResponse { 339 | // |challenge| provided during Host::SendPlatformChallenge() combined with 340 | // nonce data and signed with the platform's private key. 341 | const uint8_t* signed_data; 342 | uint32_t signed_data_length; 343 | 344 | // RSASSA-PKCS1-v1_5-SHA256 signature of the |signed_data| block. 345 | const uint8_t* signed_data_signature; 346 | uint32_t signed_data_signature_length; 347 | 348 | // X.509 device specific certificate for the |service_id| requested. 349 | const uint8_t* platform_key_certificate; 350 | uint32_t platform_key_certificate_length; 351 | }; 352 | CHECK_TYPE(PlatformChallengeResponse, 24, 48); 353 | 354 | // The current status of the associated key. The valid types are defined in the 355 | // spec: https://w3c.github.io/encrypted-media/#dom-mediakeystatus 356 | enum KeyStatus : uint32_t { 357 | kUsable = 0, 358 | kInternalError = 1, 359 | kExpired = 2, 360 | kOutputRestricted = 3, 361 | kOutputDownscaled = 4, 362 | kStatusPending = 5, 363 | kReleased = 6 364 | }; 365 | CHECK_TYPE(KeyStatus, 4, 4); 366 | 367 | // Used when passing arrays of key information. Does not own the referenced 368 | // data. |system_code| is an additional error code for unusable keys and 369 | // should be 0 when |status| == kUsable. 370 | struct KeyInformation { 371 | const uint8_t* key_id; 372 | uint32_t key_id_size; 373 | KeyStatus status; 374 | uint32_t system_code; 375 | }; 376 | CHECK_TYPE(KeyInformation, 16, 24); 377 | 378 | // Supported output protection methods for use with EnableOutputProtection() and 379 | // returned by OnQueryOutputProtectionStatus(). 380 | enum OutputProtectionMethods : uint32_t { 381 | kProtectionNone = 0, 382 | kProtectionHDCP = 1 << 0 383 | }; 384 | CHECK_TYPE(OutputProtectionMethods, 4, 4); 385 | 386 | // Connected output link types returned by OnQueryOutputProtectionStatus(). 387 | enum OutputLinkTypes : uint32_t { 388 | kLinkTypeNone = 0, 389 | kLinkTypeUnknown = 1 << 0, 390 | kLinkTypeInternal = 1 << 1, 391 | kLinkTypeVGA = 1 << 2, 392 | kLinkTypeHDMI = 1 << 3, 393 | kLinkTypeDVI = 1 << 4, 394 | kLinkTypeDisplayPort = 1 << 5, 395 | kLinkTypeNetwork = 1 << 6 396 | }; 397 | CHECK_TYPE(OutputLinkTypes, 4, 4); 398 | 399 | // Result of the QueryOutputProtectionStatus() call. 400 | enum QueryResult : uint32_t { kQuerySucceeded = 0, kQueryFailed }; 401 | CHECK_TYPE(QueryResult, 4, 4); 402 | 403 | // The Initialization Data Type. The valid types are defined in the spec: 404 | // https://w3c.github.io/encrypted-media/format-registry/initdata/index.html#registry 405 | enum InitDataType : uint32_t { kCenc = 0, kKeyIds = 1, kWebM = 2 }; 406 | CHECK_TYPE(InitDataType, 4, 4); 407 | 408 | // The type of session to create. The valid types are defined in the spec: 409 | // https://w3c.github.io/encrypted-media/#dom-mediakeysessiontype 410 | enum SessionType : uint32_t { 411 | kTemporary = 0, 412 | kPersistentLicense = 1, 413 | kPersistentUsageRecord = 2 414 | }; 415 | CHECK_TYPE(SessionType, 4, 4); 416 | 417 | // The type of the message event. The valid types are defined in the spec: 418 | // https://w3c.github.io/encrypted-media/#dom-mediakeymessagetype 419 | enum MessageType : uint32_t { 420 | kLicenseRequest = 0, 421 | kLicenseRenewal = 1, 422 | kLicenseRelease = 2, 423 | kIndividualizationRequest = 3 424 | }; 425 | CHECK_TYPE(MessageType, 4, 4); 426 | 427 | enum HdcpVersion : uint32_t { 428 | kHdcpVersionNone, 429 | kHdcpVersion1_0, 430 | kHdcpVersion1_1, 431 | kHdcpVersion1_2, 432 | kHdcpVersion1_3, 433 | kHdcpVersion1_4, 434 | kHdcpVersion2_0, 435 | kHdcpVersion2_1, 436 | kHdcpVersion2_2, 437 | kHdcpVersion2_3 438 | }; 439 | CHECK_TYPE(HdcpVersion, 4, 4); 440 | 441 | struct Policy { 442 | HdcpVersion min_hdcp_version; 443 | }; 444 | CHECK_TYPE(Policy, 4, 4); 445 | 446 | // Represents a buffer created by Allocator implementations. 447 | class CDM_CLASS_API Buffer { 448 | public: 449 | // Destroys the buffer in the same context as it was created. 450 | virtual void Destroy() = 0; 451 | 452 | virtual uint32_t Capacity() const = 0; 453 | virtual uint8_t* Data() = 0; 454 | virtual void SetSize(uint32_t size) = 0; 455 | virtual uint32_t Size() const = 0; 456 | 457 | protected: 458 | Buffer() {} 459 | virtual ~Buffer() {} 460 | 461 | private: 462 | Buffer(const Buffer&); 463 | void operator=(const Buffer&); 464 | }; 465 | 466 | // Represents a decrypted block that has not been decoded. 467 | class CDM_CLASS_API DecryptedBlock { 468 | public: 469 | virtual void SetDecryptedBuffer(Buffer* buffer) = 0; 470 | virtual Buffer* DecryptedBuffer() = 0; 471 | 472 | // TODO(tomfinegan): Figure out if timestamp is really needed. If it is not, 473 | // we can just pass Buffer pointers around. 474 | virtual void SetTimestamp(int64_t timestamp) = 0; 475 | virtual int64_t Timestamp() const = 0; 476 | 477 | protected: 478 | DecryptedBlock() {} 479 | virtual ~DecryptedBlock() {} 480 | }; 481 | 482 | enum VideoPlane : uint32_t { 483 | kYPlane = 0, 484 | kUPlane = 1, 485 | kVPlane = 2, 486 | kMaxPlanes = 3, 487 | }; 488 | CHECK_TYPE(VideoPlane, 4, 4); 489 | 490 | class CDM_CLASS_API VideoFrame { 491 | public: 492 | virtual void SetFormat(VideoFormat format) = 0; 493 | virtual VideoFormat Format() const = 0; 494 | 495 | virtual void SetSize(cdm::Size size) = 0; 496 | virtual cdm::Size Size() const = 0; 497 | 498 | virtual void SetFrameBuffer(Buffer* frame_buffer) = 0; 499 | virtual Buffer* FrameBuffer() = 0; 500 | 501 | virtual void SetPlaneOffset(VideoPlane plane, uint32_t offset) = 0; 502 | virtual uint32_t PlaneOffset(VideoPlane plane) = 0; 503 | 504 | virtual void SetStride(VideoPlane plane, uint32_t stride) = 0; 505 | virtual uint32_t Stride(VideoPlane plane) = 0; 506 | 507 | // Sets and gets the presentation timestamp which is in microseconds. 508 | virtual void SetTimestamp(int64_t timestamp) = 0; 509 | virtual int64_t Timestamp() const = 0; 510 | 511 | protected: 512 | VideoFrame() {} 513 | virtual ~VideoFrame() {} 514 | }; 515 | 516 | // Represents a decoded video frame. The CDM should call the interface methods 517 | // to set the frame attributes. See DecryptAndDecodeFrame(). 518 | class CDM_CLASS_API VideoFrame_2 { 519 | public: 520 | virtual void SetFormat(VideoFormat format) = 0; 521 | virtual void SetSize(cdm::Size size) = 0; 522 | virtual void SetFrameBuffer(Buffer* frame_buffer) = 0; 523 | virtual void SetPlaneOffset(VideoPlane plane, uint32_t offset) = 0; 524 | virtual void SetStride(VideoPlane plane, uint32_t stride) = 0; 525 | // Sets the presentation timestamp which is in microseconds. 526 | virtual void SetTimestamp(int64_t timestamp) = 0; 527 | virtual void SetColorSpace(ColorSpace color_space) = 0; 528 | 529 | protected: 530 | VideoFrame_2() {} 531 | virtual ~VideoFrame_2() {} 532 | }; 533 | 534 | // Represents decrypted and decoded audio frames. AudioFrames can contain 535 | // multiple audio output buffers, which are serialized into this format: 536 | // 537 | // |<------------------- serialized audio buffer ------------------->| 538 | // | int64_t timestamp | int64_t length | length bytes of audio data | 539 | // 540 | // For example, with three audio output buffers, the AudioFrames will look 541 | // like this: 542 | // 543 | // |<----------------- AudioFrames ------------------>| 544 | // | audio buffer 0 | audio buffer 1 | audio buffer 2 | 545 | class CDM_CLASS_API AudioFrames { 546 | public: 547 | virtual void SetFrameBuffer(Buffer* buffer) = 0; 548 | virtual Buffer* FrameBuffer() = 0; 549 | 550 | // The CDM must call this method, providing a valid format, when providing 551 | // frame buffers. Planar data should be stored end to end; e.g., 552 | // |ch1 sample1||ch1 sample2|....|ch1 sample_last||ch2 sample1|... 553 | virtual void SetFormat(AudioFormat format) = 0; 554 | virtual AudioFormat Format() const = 0; 555 | 556 | protected: 557 | AudioFrames() {} 558 | virtual ~AudioFrames() {} 559 | }; 560 | 561 | // FileIO interface provides a way for the CDM to store data in a file in 562 | // persistent storage. This interface aims only at providing basic read/write 563 | // capabilities and should not be used as a full fledged file IO API. 564 | // Each CDM and origin (e.g. HTTPS, "foo.example.com", 443) combination has 565 | // its own persistent storage. All instances of a given CDM associated with a 566 | // given origin share the same persistent storage. 567 | // Note to implementors of this interface: 568 | // Per-origin storage and the ability for users to clear it are important. 569 | // See http://www.w3.org/TR/encrypted-media/#privacy-storedinfo. 570 | class CDM_CLASS_API FileIO { 571 | public: 572 | // Opens the file with |file_name| for read and write. 573 | // FileIOClient::OnOpenComplete() will be called after the opening 574 | // operation finishes. 575 | // - When the file is opened by a CDM instance, it will be classified as "in 576 | // use". In this case other CDM instances in the same domain may receive 577 | // kInUse status when trying to open it. 578 | // - |file_name| must only contain letters (A-Za-z), digits(0-9), or "._-". 579 | // It must not start with an underscore ('_'), and must be at least 1 580 | // character and no more than 256 characters long. 581 | virtual void Open(const char* file_name, uint32_t file_name_size) = 0; 582 | 583 | // Reads the contents of the file. FileIOClient::OnReadComplete() will be 584 | // called with the read status. Read() should not be called if a previous 585 | // Read() or Write() call is still pending; otherwise OnReadComplete() will 586 | // be called with kInUse. 587 | virtual void Read() = 0; 588 | 589 | // Writes |data_size| bytes of |data| into the file. 590 | // FileIOClient::OnWriteComplete() will be called with the write status. 591 | // All existing contents in the file will be overwritten. Calling Write() with 592 | // NULL |data| will clear all contents in the file. Write() should not be 593 | // called if a previous Write() or Read() call is still pending; otherwise 594 | // OnWriteComplete() will be called with kInUse. 595 | virtual void Write(const uint8_t* data, uint32_t data_size) = 0; 596 | 597 | // Closes the file if opened, destroys this FileIO object and releases any 598 | // resources allocated. The CDM must call this method when it finished using 599 | // this object. A FileIO object must not be used after Close() is called. 600 | virtual void Close() = 0; 601 | 602 | protected: 603 | FileIO() {} 604 | virtual ~FileIO() {} 605 | }; 606 | 607 | // Responses to FileIO calls. All responses will be called asynchronously. 608 | // When kError is returned, the FileIO object could be in an error state. All 609 | // following calls (other than Close()) could return kError. The CDM should 610 | // still call Close() to destroy the FileIO object. 611 | class CDM_CLASS_API FileIOClient { 612 | public: 613 | enum class Status : uint32_t { kSuccess = 0, kInUse, kError }; 614 | 615 | // Response to a FileIO::Open() call with the open |status|. 616 | virtual void OnOpenComplete(Status status) = 0; 617 | 618 | // Response to a FileIO::Read() call to provide |data_size| bytes of |data| 619 | // read from the file. 620 | // - kSuccess indicates that all contents of the file has been successfully 621 | // read. In this case, 0 |data_size| means that the file is empty. 622 | // - kInUse indicates that there are other read/write operations pending. 623 | // - kError indicates read failure, e.g. the storage is not open or cannot be 624 | // fully read. 625 | virtual void OnReadComplete(Status status, 626 | const uint8_t* data, 627 | uint32_t data_size) = 0; 628 | 629 | // Response to a FileIO::Write() call. 630 | // - kSuccess indicates that all the data has been written into the file 631 | // successfully. 632 | // - kInUse indicates that there are other read/write operations pending. 633 | // - kError indicates write failure, e.g. the storage is not open or cannot be 634 | // fully written. Upon write failure, the contents of the file should be 635 | // regarded as corrupt and should not used. 636 | virtual void OnWriteComplete(Status status) = 0; 637 | 638 | protected: 639 | FileIOClient() {} 640 | virtual ~FileIOClient() {} 641 | }; 642 | 643 | class CDM_CLASS_API Host_10; 644 | class CDM_CLASS_API Host_11; 645 | 646 | // ContentDecryptionModule interface that all CDMs need to implement. 647 | // The interface is versioned for backward compatibility. 648 | // Note: ContentDecryptionModule implementations must use the allocator 649 | // provided in CreateCdmInstance() to allocate any Buffer that needs to 650 | // be passed back to the caller. Implementations must call Buffer::Destroy() 651 | // when a Buffer is created that will never be returned to the caller. 652 | class CDM_CLASS_API ContentDecryptionModule_10 { 653 | public: 654 | static const int kVersion = 10; 655 | static const bool kIsStable = true; 656 | typedef Host_10 Host; 657 | 658 | // Initializes the CDM instance, providing information about permitted 659 | // functionalities. The CDM must respond by calling Host::OnInitialized() 660 | // with whether the initialization succeeded. No other calls will be made by 661 | // the host before Host::OnInitialized() returns. 662 | // If |allow_distinctive_identifier| is false, messages from the CDM, 663 | // such as message events, must not contain a Distinctive Identifier, 664 | // even in an encrypted form. 665 | // If |allow_persistent_state| is false, the CDM must not attempt to 666 | // persist state. Calls to CreateFileIO() will fail. 667 | // If |use_hw_secure_codecs| is true, the CDM must ensure the decryption key 668 | // and video buffers (compressed and uncompressed) are securely protected by 669 | // hardware. 670 | virtual void Initialize(bool allow_distinctive_identifier, 671 | bool allow_persistent_state, 672 | bool use_hw_secure_codecs) = 0; 673 | 674 | // Gets the key status if the CDM has a hypothetical key with the |policy|. 675 | // The CDM must respond by calling either Host::OnResolveKeyStatusPromise() 676 | // with the result key status or Host::OnRejectPromise() if an unexpected 677 | // error happened or this method is not supported. 678 | virtual void GetStatusForPolicy(uint32_t promise_id, 679 | const Policy& policy) = 0; 680 | 681 | // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(), 682 | // UpdateSession(), CloseSession(), and RemoveSession() all accept a 683 | // |promise_id|, which must be passed to the completion Host method 684 | // (e.g. Host::OnResolveNewSessionPromise()). 685 | 686 | // Provides a server certificate to be used to encrypt messages to the 687 | // license server. The CDM must respond by calling either 688 | // Host::OnResolvePromise() or Host::OnRejectPromise(). 689 | // If the CDM does not support server certificates, the promise should be 690 | // rejected with kExceptionNotSupportedError. If |server_certificate_data| 691 | // is empty, reject with kExceptionTypeError. Any other error should be 692 | // rejected with kExceptionInvalidStateError or kExceptionQuotaExceededError. 693 | // TODO(crbug.com/796417): Add support for the promise to return true or 694 | // false, rather than using kExceptionNotSupportedError to mean false. 695 | virtual void SetServerCertificate(uint32_t promise_id, 696 | const uint8_t* server_certificate_data, 697 | uint32_t server_certificate_data_size) = 0; 698 | 699 | // Creates a session given |session_type|, |init_data_type|, and |init_data|. 700 | // The CDM must respond by calling either Host::OnResolveNewSessionPromise() 701 | // or Host::OnRejectPromise(). 702 | virtual void CreateSessionAndGenerateRequest(uint32_t promise_id, 703 | SessionType session_type, 704 | InitDataType init_data_type, 705 | const uint8_t* init_data, 706 | uint32_t init_data_size) = 0; 707 | 708 | // Loads the session of type |session_type| specified by |session_id|. 709 | // The CDM must respond by calling either Host::OnResolveNewSessionPromise() 710 | // or Host::OnRejectPromise(). If the session is not found, call 711 | // Host::OnResolveNewSessionPromise() with session_id = NULL. 712 | virtual void LoadSession(uint32_t promise_id, 713 | SessionType session_type, 714 | const char* session_id, 715 | uint32_t session_id_size) = 0; 716 | 717 | // Updates the session with |response|. The CDM must respond by calling 718 | // either Host::OnResolvePromise() or Host::OnRejectPromise(). 719 | virtual void UpdateSession(uint32_t promise_id, 720 | const char* session_id, 721 | uint32_t session_id_size, 722 | const uint8_t* response, 723 | uint32_t response_size) = 0; 724 | 725 | // Requests that the CDM close the session. The CDM must respond by calling 726 | // either Host::OnResolvePromise() or Host::OnRejectPromise() when the request 727 | // has been processed. This may be before the session is closed. Once the 728 | // session is closed, Host::OnSessionClosed() must also be called. 729 | virtual void CloseSession(uint32_t promise_id, 730 | const char* session_id, 731 | uint32_t session_id_size) = 0; 732 | 733 | // Removes any stored session data associated with this session. Will only be 734 | // called for persistent sessions. The CDM must respond by calling either 735 | // Host::OnResolvePromise() or Host::OnRejectPromise() when the request has 736 | // been processed. 737 | virtual void RemoveSession(uint32_t promise_id, 738 | const char* session_id, 739 | uint32_t session_id_size) = 0; 740 | 741 | // Performs scheduled operation with |context| when the timer fires. 742 | virtual void TimerExpired(void* context) = 0; 743 | 744 | // Decrypts the |encrypted_buffer|. 745 | // 746 | // Returns kSuccess if decryption succeeded, in which case the callee 747 | // should have filled the |decrypted_buffer| and passed the ownership of 748 | // |data| in |decrypted_buffer| to the caller. 749 | // Returns kNoKey if the CDM did not have the necessary decryption key 750 | // to decrypt. 751 | // Returns kDecryptError if any other error happened. 752 | // If the return value is not kSuccess, |decrypted_buffer| should be ignored 753 | // by the caller. 754 | virtual Status Decrypt(const InputBuffer_2& encrypted_buffer, 755 | DecryptedBlock* decrypted_buffer) = 0; 756 | 757 | // Initializes the CDM audio decoder with |audio_decoder_config|. This 758 | // function must be called before DecryptAndDecodeSamples() is called. 759 | // 760 | // Returns kSuccess if the |audio_decoder_config| is supported and the CDM 761 | // audio decoder is successfully initialized. 762 | // Returns kInitializationError if |audio_decoder_config| is not supported. 763 | // The CDM may still be able to do Decrypt(). 764 | // Returns kDeferredInitialization if the CDM is not ready to initialize the 765 | // decoder at this time. Must call Host::OnDeferredInitializationDone() once 766 | // initialization is complete. 767 | virtual Status InitializeAudioDecoder( 768 | const AudioDecoderConfig_2& audio_decoder_config) = 0; 769 | 770 | // Initializes the CDM video decoder with |video_decoder_config|. This 771 | // function must be called before DecryptAndDecodeFrame() is called. 772 | // 773 | // Returns kSuccess if the |video_decoder_config| is supported and the CDM 774 | // video decoder is successfully initialized. 775 | // Returns kInitializationError if |video_decoder_config| is not supported. 776 | // The CDM may still be able to do Decrypt(). 777 | // Returns kDeferredInitialization if the CDM is not ready to initialize the 778 | // decoder at this time. Must call Host::OnDeferredInitializationDone() once 779 | // initialization is complete. 780 | virtual Status InitializeVideoDecoder( 781 | const VideoDecoderConfig_2& video_decoder_config) = 0; 782 | 783 | // De-initializes the CDM decoder and sets it to an uninitialized state. The 784 | // caller can initialize the decoder again after this call to re-initialize 785 | // it. This can be used to reconfigure the decoder if the configuration 786 | // changes. 787 | virtual void DeinitializeDecoder(StreamType decoder_type) = 0; 788 | 789 | // Resets the CDM decoder to an initialized clean state. All internal buffers 790 | // MUST be flushed. 791 | virtual void ResetDecoder(StreamType decoder_type) = 0; 792 | 793 | // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into a 794 | // |video_frame|. Upon end-of-stream, the caller should call this function 795 | // repeatedly with empty |encrypted_buffer| (|data| == NULL) until 796 | // kNeedMoreData is returned. 797 | // 798 | // Returns kSuccess if decryption and decoding both succeeded, in which case 799 | // the callee will have filled the |video_frame| and passed the ownership of 800 | // |frame_buffer| in |video_frame| to the caller. 801 | // Returns kNoKey if the CDM did not have the necessary decryption key 802 | // to decrypt. 803 | // Returns kNeedMoreData if more data was needed by the decoder to generate 804 | // a decoded frame (e.g. during initialization and end-of-stream). 805 | // Returns kDecryptError if any decryption error happened. 806 | // Returns kDecodeError if any decoding error happened. 807 | // If the return value is not kSuccess, |video_frame| should be ignored by 808 | // the caller. 809 | virtual Status DecryptAndDecodeFrame(const InputBuffer_2& encrypted_buffer, 810 | VideoFrame* video_frame) = 0; 811 | 812 | // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into 813 | // |audio_frames|. Upon end-of-stream, the caller should call this function 814 | // repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty 815 | // |audio_frames| is produced. 816 | // 817 | // Returns kSuccess if decryption and decoding both succeeded, in which case 818 | // the callee will have filled |audio_frames| and passed the ownership of 819 | // |data| in |audio_frames| to the caller. 820 | // Returns kNoKey if the CDM did not have the necessary decryption key 821 | // to decrypt. 822 | // Returns kNeedMoreData if more data was needed by the decoder to generate 823 | // audio samples (e.g. during initialization and end-of-stream). 824 | // Returns kDecryptError if any decryption error happened. 825 | // Returns kDecodeError if any decoding error happened. 826 | // If the return value is not kSuccess, |audio_frames| should be ignored by 827 | // the caller. 828 | virtual Status DecryptAndDecodeSamples(const InputBuffer_2& encrypted_buffer, 829 | AudioFrames* audio_frames) = 0; 830 | 831 | // Called by the host after a platform challenge was initiated via 832 | // Host::SendPlatformChallenge(). 833 | virtual void OnPlatformChallengeResponse( 834 | const PlatformChallengeResponse& response) = 0; 835 | 836 | // Called by the host after a call to Host::QueryOutputProtectionStatus(). The 837 | // |link_mask| is a bit mask of OutputLinkTypes and |output_protection_mask| 838 | // is a bit mask of OutputProtectionMethods. If |result| is kQueryFailed, 839 | // then |link_mask| and |output_protection_mask| are undefined and should 840 | // be ignored. 841 | virtual void OnQueryOutputProtectionStatus( 842 | QueryResult result, 843 | uint32_t link_mask, 844 | uint32_t output_protection_mask) = 0; 845 | 846 | // Called by the host after a call to Host::RequestStorageId(). If the 847 | // version of the storage ID requested is available, |storage_id| and 848 | // |storage_id_size| are set appropriately. |version| will be the same as 849 | // what was requested, unless 0 (latest) was requested, in which case 850 | // |version| will be the actual version number for the |storage_id| returned. 851 | // If the requested version is not available, null/zero will be provided as 852 | // |storage_id| and |storage_id_size|, respectively, and |version| should be 853 | // ignored. 854 | virtual void OnStorageId(uint32_t version, 855 | const uint8_t* storage_id, 856 | uint32_t storage_id_size) = 0; 857 | 858 | // Destroys the object in the same context as it was created. 859 | virtual void Destroy() = 0; 860 | 861 | protected: 862 | ContentDecryptionModule_10() {} 863 | virtual ~ContentDecryptionModule_10() {} 864 | }; 865 | 866 | // ----- Note: CDM interface(s) below still in development and not stable! ----- 867 | 868 | // ContentDecryptionModule interface that all CDMs need to implement. 869 | // The interface is versioned for backward compatibility. 870 | // Note: ContentDecryptionModule implementations must use the allocator 871 | // provided in CreateCdmInstance() to allocate any Buffer that needs to 872 | // be passed back to the caller. Implementations must call Buffer::Destroy() 873 | // when a Buffer is created that will never be returned to the caller. 874 | class CDM_CLASS_API ContentDecryptionModule_11 { 875 | public: 876 | static const int kVersion = 11; 877 | static const bool kIsStable = false; 878 | typedef Host_11 Host; 879 | 880 | // Initializes the CDM instance, providing information about permitted 881 | // functionalities. The CDM must respond by calling Host::OnInitialized() 882 | // with whether the initialization succeeded. No other calls will be made by 883 | // the host before Host::OnInitialized() returns. 884 | // If |allow_distinctive_identifier| is false, messages from the CDM, 885 | // such as message events, must not contain a Distinctive Identifier, 886 | // even in an encrypted form. 887 | // If |allow_persistent_state| is false, the CDM must not attempt to 888 | // persist state. Calls to CreateFileIO() will fail. 889 | // If |use_hw_secure_codecs| is true, the CDM must ensure the decryption key 890 | // and video buffers (compressed and uncompressed) are securely protected by 891 | // hardware. 892 | virtual void Initialize(bool allow_distinctive_identifier, 893 | bool allow_persistent_state, 894 | bool use_hw_secure_codecs) = 0; 895 | 896 | // Gets the key status if the CDM has a hypothetical key with the |policy|. 897 | // The CDM must respond by calling either Host::OnResolveKeyStatusPromise() 898 | // with the result key status or Host::OnRejectPromise() if an unexpected 899 | // error happened or this method is not supported. 900 | virtual void GetStatusForPolicy(uint32_t promise_id, 901 | const Policy& policy) = 0; 902 | 903 | // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(), 904 | // UpdateSession(), CloseSession(), and RemoveSession() all accept a 905 | // |promise_id|, which must be passed to the completion Host method 906 | // (e.g. Host::OnResolveNewSessionPromise()). 907 | 908 | // Provides a server certificate to be used to encrypt messages to the 909 | // license server. The CDM must respond by calling either 910 | // Host::OnResolvePromise() or Host::OnRejectPromise(). 911 | // If the CDM does not support server certificates, the promise should be 912 | // rejected with kExceptionNotSupportedError. If |server_certificate_data| 913 | // is empty, reject with kExceptionTypeError. Any other error should be 914 | // rejected with kExceptionInvalidStateError or kExceptionQuotaExceededError. 915 | // TODO(crbug.com/796417): Add support for the promise to return true or 916 | // false, rather than using kExceptionNotSupportedError to mean false. 917 | virtual void SetServerCertificate(uint32_t promise_id, 918 | const uint8_t* server_certificate_data, 919 | uint32_t server_certificate_data_size) = 0; 920 | 921 | // Creates a session given |session_type|, |init_data_type|, and |init_data|. 922 | // The CDM must respond by calling either Host::OnResolveNewSessionPromise() 923 | // or Host::OnRejectPromise(). 924 | virtual void CreateSessionAndGenerateRequest(uint32_t promise_id, 925 | SessionType session_type, 926 | InitDataType init_data_type, 927 | const uint8_t* init_data, 928 | uint32_t init_data_size) = 0; 929 | 930 | // Loads the session of type |session_type| specified by |session_id|. 931 | // The CDM must respond by calling either Host::OnResolveNewSessionPromise() 932 | // or Host::OnRejectPromise(). If the session is not found, call 933 | // Host::OnResolveNewSessionPromise() with session_id = NULL. 934 | virtual void LoadSession(uint32_t promise_id, 935 | SessionType session_type, 936 | const char* session_id, 937 | uint32_t session_id_size) = 0; 938 | 939 | // Updates the session with |response|. The CDM must respond by calling 940 | // either Host::OnResolvePromise() or Host::OnRejectPromise(). 941 | virtual void UpdateSession(uint32_t promise_id, 942 | const char* session_id, 943 | uint32_t session_id_size, 944 | const uint8_t* response, 945 | uint32_t response_size) = 0; 946 | 947 | // Requests that the CDM close the session. The CDM must respond by calling 948 | // either Host::OnResolvePromise() or Host::OnRejectPromise() when the request 949 | // has been processed. This may be before the session is closed. Once the 950 | // session is closed, Host::OnSessionClosed() must also be called. 951 | virtual void CloseSession(uint32_t promise_id, 952 | const char* session_id, 953 | uint32_t session_id_size) = 0; 954 | 955 | // Removes any stored session data associated with this session. Removes all 956 | // license(s) and key(s) associated with the session, whether they are in 957 | // memory, persistent store, or both. For persistent session types, other 958 | // session data (e.g. record of license destruction) will be cleared as 959 | // defined for each session type once a release message acknowledgment is 960 | // processed by UpdateSession(). The CDM must respond by calling either 961 | // Host::OnResolvePromise() or Host::OnRejectPromise() when the request has 962 | // been processed. 963 | virtual void RemoveSession(uint32_t promise_id, 964 | const char* session_id, 965 | uint32_t session_id_size) = 0; 966 | 967 | // Performs scheduled operation with |context| when the timer fires. 968 | virtual void TimerExpired(void* context) = 0; 969 | 970 | // Decrypts the |encrypted_buffer|. 971 | // 972 | // Returns kSuccess if decryption succeeded, in which case the callee 973 | // should have filled the |decrypted_buffer| and passed the ownership of 974 | // |data| in |decrypted_buffer| to the caller. 975 | // Returns kNoKey if the CDM did not have the necessary decryption key 976 | // to decrypt. 977 | // Returns kDecryptError if any other error happened. 978 | // If the return value is not kSuccess, |decrypted_buffer| should be ignored 979 | // by the caller. 980 | virtual Status Decrypt(const InputBuffer_2& encrypted_buffer, 981 | DecryptedBlock* decrypted_buffer) = 0; 982 | 983 | // Initializes the CDM audio decoder with |audio_decoder_config|. This 984 | // function must be called before DecryptAndDecodeSamples() is called. 985 | // 986 | // Returns kSuccess if the |audio_decoder_config| is supported and the CDM 987 | // audio decoder is successfully initialized. 988 | // Returns kInitializationError if |audio_decoder_config| is not supported. 989 | // The CDM may still be able to do Decrypt(). 990 | // Returns kDeferredInitialization if the CDM is not ready to initialize the 991 | // decoder at this time. Must call Host::OnDeferredInitializationDone() once 992 | // initialization is complete. 993 | virtual Status InitializeAudioDecoder( 994 | const AudioDecoderConfig_2& audio_decoder_config) = 0; 995 | 996 | // Initializes the CDM video decoder with |video_decoder_config|. This 997 | // function must be called before DecryptAndDecodeFrame() is called. 998 | // 999 | // Returns kSuccess if the |video_decoder_config| is supported and the CDM 1000 | // video decoder is successfully initialized. 1001 | // Returns kInitializationError if |video_decoder_config| is not supported. 1002 | // The CDM may still be able to do Decrypt(). 1003 | // Returns kDeferredInitialization if the CDM is not ready to initialize the 1004 | // decoder at this time. Must call Host::OnDeferredInitializationDone() once 1005 | // initialization is complete. 1006 | virtual Status InitializeVideoDecoder( 1007 | const VideoDecoderConfig_3& video_decoder_config) = 0; 1008 | 1009 | // De-initializes the CDM decoder and sets it to an uninitialized state. The 1010 | // caller can initialize the decoder again after this call to re-initialize 1011 | // it. This can be used to reconfigure the decoder if the configuration 1012 | // changes. 1013 | virtual void DeinitializeDecoder(StreamType decoder_type) = 0; 1014 | 1015 | // Resets the CDM decoder to an initialized clean state. All internal buffers 1016 | // MUST be flushed. 1017 | virtual void ResetDecoder(StreamType decoder_type) = 0; 1018 | 1019 | // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into a 1020 | // |video_frame|. Upon end-of-stream, the caller should call this function 1021 | // repeatedly with empty |encrypted_buffer| (|data| == NULL) until 1022 | // kNeedMoreData is returned. 1023 | // 1024 | // Returns kSuccess if decryption and decoding both succeeded, in which case 1025 | // the callee will have filled the |video_frame| and passed the ownership of 1026 | // |frame_buffer| in |video_frame| to the caller. 1027 | // Returns kNoKey if the CDM did not have the necessary decryption key 1028 | // to decrypt. 1029 | // Returns kNeedMoreData if more data was needed by the decoder to generate 1030 | // a decoded frame (e.g. during initialization and end-of-stream). 1031 | // Returns kDecryptError if any decryption error happened. 1032 | // Returns kDecodeError if any decoding error happened. 1033 | // If the return value is not kSuccess, |video_frame| should be ignored by 1034 | // the caller. 1035 | virtual Status DecryptAndDecodeFrame(const InputBuffer_2& encrypted_buffer, 1036 | VideoFrame_2* video_frame) = 0; 1037 | 1038 | // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into 1039 | // |audio_frames|. Upon end-of-stream, the caller should call this function 1040 | // repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty 1041 | // |audio_frames| is produced. 1042 | // 1043 | // Returns kSuccess if decryption and decoding both succeeded, in which case 1044 | // the callee will have filled |audio_frames| and passed the ownership of 1045 | // |data| in |audio_frames| to the caller. 1046 | // Returns kNoKey if the CDM did not have the necessary decryption key 1047 | // to decrypt. 1048 | // Returns kNeedMoreData if more data was needed by the decoder to generate 1049 | // audio samples (e.g. during initialization and end-of-stream). 1050 | // Returns kDecryptError if any decryption error happened. 1051 | // Returns kDecodeError if any decoding error happened. 1052 | // If the return value is not kSuccess, |audio_frames| should be ignored by 1053 | // the caller. 1054 | virtual Status DecryptAndDecodeSamples(const InputBuffer_2& encrypted_buffer, 1055 | AudioFrames* audio_frames) = 0; 1056 | 1057 | // Called by the host after a platform challenge was initiated via 1058 | // Host::SendPlatformChallenge(). 1059 | virtual void OnPlatformChallengeResponse( 1060 | const PlatformChallengeResponse& response) = 0; 1061 | 1062 | // Called by the host after a call to Host::QueryOutputProtectionStatus(). The 1063 | // |link_mask| is a bit mask of OutputLinkTypes and |output_protection_mask| 1064 | // is a bit mask of OutputProtectionMethods. If |result| is kQueryFailed, 1065 | // then |link_mask| and |output_protection_mask| are undefined and should 1066 | // be ignored. 1067 | virtual void OnQueryOutputProtectionStatus( 1068 | QueryResult result, 1069 | uint32_t link_mask, 1070 | uint32_t output_protection_mask) = 0; 1071 | 1072 | // Called by the host after a call to Host::RequestStorageId(). If the 1073 | // version of the storage ID requested is available, |storage_id| and 1074 | // |storage_id_size| are set appropriately. |version| will be the same as 1075 | // what was requested, unless 0 (latest) was requested, in which case 1076 | // |version| will be the actual version number for the |storage_id| returned. 1077 | // If the requested version is not available, null/zero will be provided as 1078 | // |storage_id| and |storage_id_size|, respectively, and |version| should be 1079 | // ignored. 1080 | virtual void OnStorageId(uint32_t version, 1081 | const uint8_t* storage_id, 1082 | uint32_t storage_id_size) = 0; 1083 | 1084 | // Destroys the object in the same context as it was created. 1085 | virtual void Destroy() = 0; 1086 | 1087 | protected: 1088 | ContentDecryptionModule_11() {} 1089 | virtual ~ContentDecryptionModule_11() {} 1090 | }; 1091 | 1092 | class CDM_CLASS_API Host_10 { 1093 | public: 1094 | static const int kVersion = 10; 1095 | 1096 | // Returns a Buffer* containing non-zero members upon success, or NULL on 1097 | // failure. The caller owns the Buffer* after this call. The buffer is not 1098 | // guaranteed to be zero initialized. The capacity of the allocated Buffer 1099 | // is guaranteed to be not less than |capacity|. 1100 | virtual Buffer* Allocate(uint32_t capacity) = 0; 1101 | 1102 | // Requests the host to call ContentDecryptionModule::TimerFired() |delay_ms| 1103 | // from now with |context|. 1104 | virtual void SetTimer(int64_t delay_ms, void* context) = 0; 1105 | 1106 | // Returns the current wall time. 1107 | virtual Time GetCurrentWallTime() = 0; 1108 | 1109 | // Called by the CDM with the result after the CDM instance was initialized. 1110 | virtual void OnInitialized(bool success) = 0; 1111 | 1112 | // Called by the CDM when a key status is available in response to 1113 | // GetStatusForPolicy(). 1114 | virtual void OnResolveKeyStatusPromise(uint32_t promise_id, 1115 | KeyStatus key_status) = 0; 1116 | 1117 | // Called by the CDM when a session is created or loaded and the value for the 1118 | // MediaKeySession's sessionId attribute is available (|session_id|). 1119 | // This must be called before OnSessionMessage() or 1120 | // OnSessionKeysChange() is called for the same session. |session_id_size| 1121 | // should not include null termination. 1122 | // When called in response to LoadSession(), the |session_id| must be the 1123 | // same as the |session_id| passed in LoadSession(), or NULL if the 1124 | // session could not be loaded. 1125 | virtual void OnResolveNewSessionPromise(uint32_t promise_id, 1126 | const char* session_id, 1127 | uint32_t session_id_size) = 0; 1128 | 1129 | // Called by the CDM when a session is updated or released. 1130 | virtual void OnResolvePromise(uint32_t promise_id) = 0; 1131 | 1132 | // Called by the CDM when an error occurs as a result of one of the 1133 | // ContentDecryptionModule calls that accept a |promise_id|. 1134 | // |exception| must be specified. |error_message| and |system_code| 1135 | // are optional. |error_message_size| should not include null termination. 1136 | virtual void OnRejectPromise(uint32_t promise_id, 1137 | Exception exception, 1138 | uint32_t system_code, 1139 | const char* error_message, 1140 | uint32_t error_message_size) = 0; 1141 | 1142 | // Called by the CDM when it has a message for session |session_id|. 1143 | // Size parameters should not include null termination. 1144 | virtual void OnSessionMessage(const char* session_id, 1145 | uint32_t session_id_size, 1146 | MessageType message_type, 1147 | const char* message, 1148 | uint32_t message_size) = 0; 1149 | 1150 | // Called by the CDM when there has been a change in keys or their status for 1151 | // session |session_id|. |has_additional_usable_key| should be set if a 1152 | // key is newly usable (e.g. new key available, previously expired key has 1153 | // been renewed, etc.) and the browser should attempt to resume playback. 1154 | // |keys_info| is the list of key IDs for this session along with their 1155 | // current status. |keys_info_count| is the number of entries in |keys_info|. 1156 | // Size parameter for |session_id| should not include null termination. 1157 | virtual void OnSessionKeysChange(const char* session_id, 1158 | uint32_t session_id_size, 1159 | bool has_additional_usable_key, 1160 | const KeyInformation* keys_info, 1161 | uint32_t keys_info_count) = 0; 1162 | 1163 | // Called by the CDM when there has been a change in the expiration time for 1164 | // session |session_id|. This can happen as the result of an Update() call 1165 | // or some other event. If this happens as a result of a call to Update(), 1166 | // it must be called before resolving the Update() promise. |new_expiry_time| 1167 | // represents the time after which the key(s) in the session will no longer 1168 | // be usable for decryption. It can be 0 if no such time exists or if the 1169 | // license explicitly never expires. Size parameter should not include null 1170 | // termination. 1171 | virtual void OnExpirationChange(const char* session_id, 1172 | uint32_t session_id_size, 1173 | Time new_expiry_time) = 0; 1174 | 1175 | // Called by the CDM when session |session_id| is closed. Size 1176 | // parameter should not include null termination. 1177 | virtual void OnSessionClosed(const char* session_id, 1178 | uint32_t session_id_size) = 0; 1179 | 1180 | // The following are optional methods that may not be implemented on all 1181 | // platforms. 1182 | 1183 | // Sends a platform challenge for the given |service_id|. |challenge| is at 1184 | // most 256 bits of data to be signed. Once the challenge has been completed, 1185 | // the host will call ContentDecryptionModule::OnPlatformChallengeResponse() 1186 | // with the signed challenge response and platform certificate. Size 1187 | // parameters should not include null termination. 1188 | virtual void SendPlatformChallenge(const char* service_id, 1189 | uint32_t service_id_size, 1190 | const char* challenge, 1191 | uint32_t challenge_size) = 0; 1192 | 1193 | // Attempts to enable output protection (e.g. HDCP) on the display link. The 1194 | // |desired_protection_mask| is a bit mask of OutputProtectionMethods. No 1195 | // status callback is issued, the CDM must call QueryOutputProtectionStatus() 1196 | // periodically to ensure the desired protections are applied. 1197 | virtual void EnableOutputProtection(uint32_t desired_protection_mask) = 0; 1198 | 1199 | // Requests the current output protection status. Once the host has the status 1200 | // it will call ContentDecryptionModule::OnQueryOutputProtectionStatus(). 1201 | virtual void QueryOutputProtectionStatus() = 0; 1202 | 1203 | // Must be called by the CDM if it returned kDeferredInitialization during 1204 | // InitializeAudioDecoder() or InitializeVideoDecoder(). 1205 | virtual void OnDeferredInitializationDone(StreamType stream_type, 1206 | Status decoder_status) = 0; 1207 | 1208 | // Creates a FileIO object from the host to do file IO operation. Returns NULL 1209 | // if a FileIO object cannot be obtained. Once a valid FileIO object is 1210 | // returned, |client| must be valid until FileIO::Close() is called. The 1211 | // CDM can call this method multiple times to operate on different files. 1212 | virtual FileIO* CreateFileIO(FileIOClient* client) = 0; 1213 | 1214 | // Requests a specific version of the storage ID. A storage ID is a stable, 1215 | // device specific ID used by the CDM to securely store persistent data. The 1216 | // ID will be returned by the host via ContentDecryptionModule::OnStorageId(). 1217 | // If |version| is 0, the latest version will be returned. All |version|s 1218 | // that are greater than or equal to 0x80000000 are reserved for the CDM and 1219 | // should not be supported or returned by the host. The CDM must not expose 1220 | // the ID outside the client device, even in encrypted form. 1221 | virtual void RequestStorageId(uint32_t version) = 0; 1222 | 1223 | protected: 1224 | Host_10() {} 1225 | virtual ~Host_10() {} 1226 | }; 1227 | 1228 | class CDM_CLASS_API Host_11 { 1229 | public: 1230 | static const int kVersion = 11; 1231 | 1232 | // Returns a Buffer* containing non-zero members upon success, or NULL on 1233 | // failure. The caller owns the Buffer* after this call. The buffer is not 1234 | // guaranteed to be zero initialized. The capacity of the allocated Buffer 1235 | // is guaranteed to be not less than |capacity|. 1236 | virtual Buffer* Allocate(uint32_t capacity) = 0; 1237 | 1238 | // Requests the host to call ContentDecryptionModule::TimerFired() |delay_ms| 1239 | // from now with |context|. 1240 | virtual void SetTimer(int64_t delay_ms, void* context) = 0; 1241 | 1242 | // Returns the current wall time. 1243 | virtual Time GetCurrentWallTime() = 0; 1244 | 1245 | // Called by the CDM with the result after the CDM instance was initialized. 1246 | virtual void OnInitialized(bool success) = 0; 1247 | 1248 | // Called by the CDM when a key status is available in response to 1249 | // GetStatusForPolicy(). 1250 | virtual void OnResolveKeyStatusPromise(uint32_t promise_id, 1251 | KeyStatus key_status) = 0; 1252 | 1253 | // Called by the CDM when a session is created or loaded and the value for the 1254 | // MediaKeySession's sessionId attribute is available (|session_id|). 1255 | // This must be called before OnSessionMessage() or 1256 | // OnSessionKeysChange() is called for the same session. |session_id_size| 1257 | // should not include null termination. 1258 | // When called in response to LoadSession(), the |session_id| must be the 1259 | // same as the |session_id| passed in LoadSession(), or NULL if the 1260 | // session could not be loaded. 1261 | virtual void OnResolveNewSessionPromise(uint32_t promise_id, 1262 | const char* session_id, 1263 | uint32_t session_id_size) = 0; 1264 | 1265 | // Called by the CDM when a session is updated or released. 1266 | virtual void OnResolvePromise(uint32_t promise_id) = 0; 1267 | 1268 | // Called by the CDM when an error occurs as a result of one of the 1269 | // ContentDecryptionModule calls that accept a |promise_id|. 1270 | // |exception| must be specified. |error_message| and |system_code| 1271 | // are optional. |error_message_size| should not include null termination. 1272 | virtual void OnRejectPromise(uint32_t promise_id, 1273 | Exception exception, 1274 | uint32_t system_code, 1275 | const char* error_message, 1276 | uint32_t error_message_size) = 0; 1277 | 1278 | // Called by the CDM when it has a message for session |session_id|. 1279 | // Size parameters should not include null termination. 1280 | virtual void OnSessionMessage(const char* session_id, 1281 | uint32_t session_id_size, 1282 | MessageType message_type, 1283 | const char* message, 1284 | uint32_t message_size) = 0; 1285 | 1286 | // Called by the CDM when there has been a change in keys or their status for 1287 | // session |session_id|. |has_additional_usable_key| should be set if a 1288 | // key is newly usable (e.g. new key available, previously expired key has 1289 | // been renewed, etc.) and the browser should attempt to resume playback. 1290 | // |keys_info| is the list of key IDs for this session along with their 1291 | // current status. |keys_info_count| is the number of entries in |keys_info|. 1292 | // Size parameter for |session_id| should not include null termination. 1293 | virtual void OnSessionKeysChange(const char* session_id, 1294 | uint32_t session_id_size, 1295 | bool has_additional_usable_key, 1296 | const KeyInformation* keys_info, 1297 | uint32_t keys_info_count) = 0; 1298 | 1299 | // Called by the CDM when there has been a change in the expiration time for 1300 | // session |session_id|. This can happen as the result of an Update() call 1301 | // or some other event. If this happens as a result of a call to Update(), 1302 | // it must be called before resolving the Update() promise. |new_expiry_time| 1303 | // represents the time after which the key(s) in the session will no longer 1304 | // be usable for decryption. It can be 0 if no such time exists or if the 1305 | // license explicitly never expires. Size parameter should not include null 1306 | // termination. 1307 | virtual void OnExpirationChange(const char* session_id, 1308 | uint32_t session_id_size, 1309 | Time new_expiry_time) = 0; 1310 | 1311 | // Called by the CDM when session |session_id| is closed. Size 1312 | // parameter should not include null termination. 1313 | virtual void OnSessionClosed(const char* session_id, 1314 | uint32_t session_id_size) = 0; 1315 | 1316 | // The following are optional methods that may not be implemented on all 1317 | // platforms. 1318 | 1319 | // Sends a platform challenge for the given |service_id|. |challenge| is at 1320 | // most 256 bits of data to be signed. Once the challenge has been completed, 1321 | // the host will call ContentDecryptionModule::OnPlatformChallengeResponse() 1322 | // with the signed challenge response and platform certificate. Size 1323 | // parameters should not include null termination. 1324 | virtual void SendPlatformChallenge(const char* service_id, 1325 | uint32_t service_id_size, 1326 | const char* challenge, 1327 | uint32_t challenge_size) = 0; 1328 | 1329 | // Attempts to enable output protection (e.g. HDCP) on the display link. The 1330 | // |desired_protection_mask| is a bit mask of OutputProtectionMethods. No 1331 | // status callback is issued, the CDM must call QueryOutputProtectionStatus() 1332 | // periodically to ensure the desired protections are applied. 1333 | virtual void EnableOutputProtection(uint32_t desired_protection_mask) = 0; 1334 | 1335 | // Requests the current output protection status. Once the host has the status 1336 | // it will call ContentDecryptionModule::OnQueryOutputProtectionStatus(). 1337 | virtual void QueryOutputProtectionStatus() = 0; 1338 | 1339 | // Must be called by the CDM if it returned kDeferredInitialization during 1340 | // InitializeAudioDecoder() or InitializeVideoDecoder(). 1341 | virtual void OnDeferredInitializationDone(StreamType stream_type, 1342 | Status decoder_status) = 0; 1343 | 1344 | // Creates a FileIO object from the host to do file IO operation. Returns NULL 1345 | // if a FileIO object cannot be obtained. Once a valid FileIO object is 1346 | // returned, |client| must be valid until FileIO::Close() is called. The 1347 | // CDM can call this method multiple times to operate on different files. 1348 | virtual FileIO* CreateFileIO(FileIOClient* client) = 0; 1349 | 1350 | // Requests a specific version of the storage ID. A storage ID is a stable, 1351 | // device specific ID used by the CDM to securely store persistent data. The 1352 | // ID will be returned by the host via ContentDecryptionModule::OnStorageId(). 1353 | // If |version| is 0, the latest version will be returned. All |version|s 1354 | // that are greater than or equal to 0x80000000 are reserved for the CDM and 1355 | // should not be supported or returned by the host. The CDM must not expose 1356 | // the ID outside the client device, even in encrypted form. 1357 | virtual void RequestStorageId(uint32_t version) = 0; 1358 | 1359 | protected: 1360 | Host_11() {} 1361 | virtual ~Host_11() {} 1362 | }; 1363 | 1364 | } // namespace cdm 1365 | 1366 | #endif //CDM_PROXY_CONTENT_DECRYPTION_MODULE_H 1367 | -------------------------------------------------------------------------------- /lib/src/api/content_decryption_module_export.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 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 CDM_PROXY_CONTENT_DECRYPTION_MODULE_EXPORT_H 6 | #define CDM_PROXY_CONTENT_DECRYPTION_MODULE_EXPORT_H 7 | 8 | // Define CDM_API so that functionality implemented by the CDM module 9 | // can be exported to consumers. 10 | #if defined(_WIN32) 11 | 12 | #if defined(CDM_IMPLEMENTATION) 13 | #define CDM_API __declspec(dllexport) 14 | #else 15 | #define CDM_API __declspec(dllimport) 16 | #endif // defined(CDM_IMPLEMENTATION) 17 | 18 | #else // defined(_WIN32) 19 | #define CDM_API __attribute__((visibility("default"))) 20 | #endif // defined(_WIN32) 21 | 22 | // Define CDM_CLASS_API to export class types. We have to add visibility 23 | // attributes to make sure virtual tables in CDM consumer and CDM implementation 24 | // are the same. Generally, it was always a good idea, as there're no guarantees 25 | // about that for the internal symbols, but it has only become a practical issue 26 | // after introduction of LTO devirtualization. See more details on 27 | // https://crbug.com/609564#c35 28 | #if defined(_WIN32) 29 | #if defined(__clang__) 30 | #define CDM_CLASS_API [[clang::lto_visibility_public]] 31 | #else 32 | #define CDM_CLASS_API 33 | #endif 34 | #else // defined(_WIN32) 35 | #define CDM_CLASS_API __attribute__((visibility("default"))) 36 | #endif // defined(_WIN32) 37 | 38 | #endif //CDM_PROXY_CONTENT_DECRYPTION_MODULE_EXPORT_H 39 | -------------------------------------------------------------------------------- /lib/src/api/content_decryption_module_ext.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 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 CDM_PROXY_CONTENT_DECRYPTION_MODULE_EXT_H 6 | #define CDM_PROXY_CONTENT_DECRYPTION_MODULE_EXT_H 7 | 8 | #if defined(_WIN32) 9 | #include 10 | #endif 11 | 12 | #include "content_decryption_module_export.h" 13 | 14 | #if defined(_MSC_VER) 15 | typedef unsigned int uint32_t; 16 | #else 17 | #include 18 | #endif 19 | 20 | namespace cdm { 21 | 22 | #if defined(_WIN32) 23 | typedef wchar_t FilePathCharType; 24 | typedef HANDLE PlatformFile; 25 | const PlatformFile kInvalidPlatformFile = INVALID_HANDLE_VALUE; 26 | #else 27 | typedef char FilePathCharType; 28 | typedef int PlatformFile; 29 | const PlatformFile kInvalidPlatformFile = -1; 30 | #endif // defined(_WIN32) 31 | 32 | struct HostFile { 33 | HostFile(const FilePathCharType* file_path, 34 | PlatformFile file, 35 | PlatformFile sig_file) 36 | : file_path(file_path), file(file), sig_file(sig_file) {} 37 | 38 | // File that is part of the host of the CDM. 39 | const FilePathCharType* file_path = nullptr; 40 | PlatformFile file = kInvalidPlatformFile; 41 | 42 | // Signature file for |file|. 43 | PlatformFile sig_file = kInvalidPlatformFile; 44 | }; 45 | 46 | } // namespace cdm 47 | 48 | extern "C" { 49 | 50 | // Functions in this file are dynamically retrieved by their versioned function 51 | // names. Increment the version number for any backward incompatible API 52 | // changes. 53 | 54 | // Verifies CDM host. All files in |host_files| are opened in read-only mode. 55 | // 56 | // Returns false and closes all files if there is an immediate failure. 57 | // Otherwise returns true as soon as possible and processes the files 58 | // asynchronously. All files MUST be closed by the CDM after this one-time 59 | // processing is finished. 60 | CDM_API bool VerifyCdmHost_0(const cdm::HostFile* host_files, 61 | uint32_t num_files); 62 | 63 | } 64 | 65 | #endif //CDM_PROXY_CONTENT_DECRYPTION_MODULE_EXT_H 66 | -------------------------------------------------------------------------------- /lib/src/common/log.h: -------------------------------------------------------------------------------- 1 | #ifndef CDM_PROXY_LOG_H 2 | #define CDM_PROXY_LOG_H 3 | 4 | #include 5 | #include 6 | 7 | #define LOG_PREFIX "[ZeasnLog][%s(%d)] %s - " 8 | #define LOG_NEWLINE "\n" 9 | #define FILE_NAME strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__ 10 | 11 | #define ZLOG(message, args...) \ 12 | fprintf(stderr, LOG_PREFIX message LOG_NEWLINE, FILE_NAME, __LINE__, __FUNCTION__, ## args) 13 | 14 | #endif //CDM_PROXY_LOG_H 15 | -------------------------------------------------------------------------------- /lib/src/lib.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | #include 4 | #include 5 | 6 | void on_init() { 7 | ZLOG("Proxy initializing ..."); 8 | char* lib_path = getenv(lib::ENV_CDM_LIB); 9 | if(lib_path == nullptr || strlen(lib_path) == 0) { 10 | ZLOG("Please set environment variable: %s", lib::ENV_CDM_LIB); 11 | } else { 12 | lib::proxy_ptr = proxy::LibProxy::Hijack(lib_path); 13 | } 14 | } 15 | 16 | void on_fini() { 17 | ZLOG("Proxy finalizing ..."); 18 | // Release proxy instance 19 | if(lib::proxy_ptr) { 20 | lib::proxy_ptr.reset(); 21 | } 22 | } 23 | 24 | void INITIALIZE_CDM_MODULE() { 25 | if(lib::proxy_ptr) { 26 | lib::proxy_ptr->InitializeCmdModule(); 27 | } 28 | } 29 | 30 | void DeinitializeCdmModule() { 31 | if(lib::proxy_ptr) { 32 | lib::proxy_ptr->DeinitializeCmdModule(); 33 | } 34 | } 35 | 36 | void* CreateCdmInstance(int cdm_interface_version, 37 | const char* key_system, 38 | uint32_t key_system_size, 39 | GetCdmHostFunc get_cdm_host_func, 40 | void* user_data) { 41 | if(lib::proxy_ptr) { 42 | return lib::proxy_ptr->CreateCdmInstance( 43 | cdm_interface_version, key_system, key_system_size, 44 | get_cdm_host_func, user_data ); 45 | } else { 46 | return nullptr; 47 | } 48 | } 49 | 50 | const char* GetCdmVersion() { 51 | if(lib::proxy_ptr) { 52 | return lib::proxy_ptr->GetCdmVersion();; 53 | } else { 54 | return ""; 55 | } 56 | } 57 | 58 | bool VerifyCdmHost_0(const cdm::HostFile* host_files, 59 | uint32_t num_files) { 60 | return true; 61 | } 62 | -------------------------------------------------------------------------------- /lib/src/lib.h: -------------------------------------------------------------------------------- 1 | #ifndef CDM_PROXY_LIB_H 2 | #define CDM_PROXY_LIB_H 3 | 4 | #include 5 | 6 | #include "api/content_decryption_module.h" 7 | #include "api/content_decryption_module_ext.h" 8 | #include "common/log.h" 9 | #include "proxy/lib_proxy.h" 10 | 11 | #define INIT __attribute__((constructor)) 12 | #define FINI __attribute__((destructor)) 13 | 14 | INIT void on_init(); 15 | 16 | FINI void on_fini(); 17 | 18 | namespace lib { 19 | 20 | const char* ENV_CDM_LIB = "Z_CDM_LIB"; 21 | 22 | std::shared_ptr proxy_ptr; 23 | 24 | } // namespace lib 25 | 26 | #endif //CDM_PROXY_LIB_H 27 | -------------------------------------------------------------------------------- /lib/src/proxy/cdm_host_proxy.cc: -------------------------------------------------------------------------------- 1 | #include "cdm_host_proxy.h" 2 | #include "../common/log.h" 3 | 4 | namespace proxy { 5 | 6 | void CdmHostProxy_10::SetUpstreamPtr(void *ptr) { 7 | ZLOG("Original CDM host => %p", ptr); 8 | up_ptr = static_cast(ptr); 9 | } 10 | 11 | cdm::Buffer * CdmHostProxy_10::Allocate(uint32_t capacity) { 12 | ZLOG("capacity=%d", capacity); 13 | return up_ptr->Allocate(capacity); 14 | } 15 | 16 | void CdmHostProxy_10::SetTimer(int64_t delay_ms, void *context) { 17 | ZLOG("delay_ms=%ld, context=%p", delay_ms, context); 18 | up_ptr->SetTimer(delay_ms, context); 19 | } 20 | 21 | cdm::Time CdmHostProxy_10::GetCurrentWallTime() { 22 | auto result = up_ptr->GetCurrentWallTime(); 23 | ZLOG("result => %f", result); 24 | return result; 25 | } 26 | 27 | void CdmHostProxy_10::OnInitialized(bool success) { 28 | ZLOG("success=%d", success); 29 | up_ptr->OnInitialized(success); 30 | } 31 | 32 | void CdmHostProxy_10::OnResolveKeyStatusPromise(uint32_t promise_id, cdm::KeyStatus key_status) { 33 | ZLOG("promise_id=%d, key_status=%d", promise_id, key_status); 34 | up_ptr->OnResolveKeyStatusPromise(promise_id, key_status); 35 | } 36 | 37 | void CdmHostProxy_10::OnResolveNewSessionPromise(uint32_t promise_id, const char *session_id, 38 | uint32_t session_id_size) { 39 | ZLOG("promise_id=%d, session_id=%s", promise_id, session_id); 40 | up_ptr->OnResolveNewSessionPromise(promise_id, session_id, session_id_size); 41 | } 42 | 43 | void CdmHostProxy_10::OnResolvePromise(uint32_t promise_id) { 44 | ZLOG("promise_id=%d", promise_id); 45 | up_ptr->OnResolvePromise(promise_id); 46 | } 47 | 48 | void CdmHostProxy_10::OnRejectPromise(uint32_t promise_id, cdm::Exception exception, uint32_t system_code, 49 | const char *error_message, uint32_t error_message_size) { 50 | ZLOG("promise_id=%d, exception=%d, system_code=%d, error_message=%s", 51 | promise_id, exception, system_code, error_message); 52 | up_ptr->OnRejectPromise(promise_id, exception, system_code, error_message, error_message_size); 53 | } 54 | 55 | void CdmHostProxy_10::OnSessionMessage(const char *session_id, uint32_t session_id_size, 56 | cdm::MessageType message_type, const char *message, uint32_t message_size) { 57 | ZLOG("session_id=%s, message_type=%d, message_size=%d", session_id, message_type, message_size); 58 | up_ptr->OnSessionMessage(session_id, session_id_size, message_type, message, message_size); 59 | } 60 | 61 | void CdmHostProxy_10::OnSessionKeysChange(const char *session_id, uint32_t session_id_size, 62 | bool has_additional_usable_key, const cdm::KeyInformation *keys_info, 63 | uint32_t keys_info_count) { 64 | ZLOG("session_id=%s, has_additional_usable_key=%d, keys_info_count=%d", 65 | session_id, has_additional_usable_key, keys_info_count); 66 | up_ptr->OnSessionKeysChange(session_id, session_id_size, has_additional_usable_key, keys_info, keys_info_count); 67 | } 68 | 69 | void CdmHostProxy_10::OnExpirationChange(const char *session_id, uint32_t session_id_size, 70 | cdm::Time new_expiry_time) { 71 | ZLOG("session_id=%s, new_expiry_time=%f", session_id, new_expiry_time); 72 | up_ptr->OnExpirationChange(session_id, session_id_size, new_expiry_time); 73 | } 74 | 75 | void CdmHostProxy_10::OnSessionClosed(const char *session_id, uint32_t session_id_size) { 76 | ZLOG("session_id=%s", session_id); 77 | up_ptr->OnSessionClosed(session_id, session_id_size); 78 | } 79 | 80 | void CdmHostProxy_10::SendPlatformChallenge(const char *service_id, uint32_t service_id_size, 81 | const char *challenge, uint32_t challenge_size) { 82 | ZLOG("service_id=%s, challenge_size=%d", service_id, challenge_size); 83 | up_ptr->SendPlatformChallenge(service_id, service_id_size, challenge, challenge_size); 84 | } 85 | 86 | void CdmHostProxy_10::EnableOutputProtection(uint32_t desired_protection_mask) { 87 | ZLOG("desired_protection_mask=%d", desired_protection_mask); 88 | up_ptr->EnableOutputProtection(desired_protection_mask); 89 | } 90 | 91 | void CdmHostProxy_10::QueryOutputProtectionStatus() { 92 | ZLOG(""); 93 | up_ptr->QueryOutputProtectionStatus(); 94 | } 95 | 96 | void CdmHostProxy_10::OnDeferredInitializationDone(cdm::StreamType stream_type, cdm::Status decoder_status) { 97 | ZLOG("stream_type=%d, decoder_status=%d", stream_type, decoder_status); 98 | up_ptr->OnDeferredInitializationDone(stream_type, decoder_status); 99 | } 100 | 101 | cdm::FileIO * CdmHostProxy_10::CreateFileIO(cdm::FileIOClient *client) { 102 | ZLOG(""); 103 | return up_ptr->CreateFileIO(client); 104 | } 105 | 106 | void CdmHostProxy_10::RequestStorageId(uint32_t version) { 107 | ZLOG("version=%d", version); 108 | up_ptr->RequestStorageId(version); 109 | } 110 | 111 | } -------------------------------------------------------------------------------- /lib/src/proxy/cdm_host_proxy.h: -------------------------------------------------------------------------------- 1 | #ifndef CDM_PROXY_CDM_HOST_PROXY_H 2 | #define CDM_PROXY_CDM_HOST_PROXY_H 3 | 4 | #include 5 | #include "../api/content_decryption_module.h" 6 | 7 | namespace proxy { 8 | 9 | class CdmHostProxy_10 : public cdm::Host_10 { 10 | using CdmHostInterface = cdm::Host_10; 11 | 12 | public: 13 | explicit CdmHostProxy_10() = default; 14 | ~CdmHostProxy_10() override = default; 15 | 16 | void SetUpstreamPtr(void* ptr); 17 | 18 | // CDM Host implementations 19 | cdm::Buffer* Allocate(uint32_t capacity) override; 20 | void SetTimer(int64_t delay_ms, void* context) override; 21 | cdm::Time GetCurrentWallTime() override; 22 | void OnInitialized(bool success) override; 23 | void OnResolveKeyStatusPromise(uint32_t promise_id, 24 | cdm::KeyStatus key_status) override; 25 | void OnResolveNewSessionPromise(uint32_t promise_id, 26 | const char* session_id, 27 | uint32_t session_id_size) override; 28 | void OnResolvePromise(uint32_t promise_id) override; 29 | void OnRejectPromise(uint32_t promise_id, 30 | cdm::Exception exception, 31 | uint32_t system_code, 32 | const char* error_message, 33 | uint32_t error_message_size) override; 34 | void OnSessionMessage(const char* session_id, 35 | uint32_t session_id_size, 36 | cdm::MessageType message_type, 37 | const char* message, 38 | uint32_t message_size) override; 39 | void OnSessionKeysChange(const char* session_id, 40 | uint32_t session_id_size, 41 | bool has_additional_usable_key, 42 | const cdm::KeyInformation* keys_info, 43 | uint32_t keys_info_count) override; 44 | void OnExpirationChange(const char* session_id, 45 | uint32_t session_id_size, 46 | cdm::Time new_expiry_time) override; 47 | void OnSessionClosed(const char* session_id, 48 | uint32_t session_id_size) override; 49 | void SendPlatformChallenge(const char* service_id, 50 | uint32_t service_id_size, 51 | const char* challenge, 52 | uint32_t challenge_size) override; 53 | void EnableOutputProtection(uint32_t desired_protection_mask) override; 54 | void QueryOutputProtectionStatus() override; 55 | void OnDeferredInitializationDone(cdm::StreamType stream_type, 56 | cdm::Status decoder_status) override; 57 | cdm::FileIO* CreateFileIO(cdm::FileIOClient* client) override; 58 | void RequestStorageId(uint32_t version) override; 59 | 60 | private: 61 | CdmHostInterface* up_ptr = nullptr; 62 | 63 | }; 64 | 65 | } 66 | 67 | 68 | #endif //CDM_PROXY_CDM_HOST_PROXY_H 69 | -------------------------------------------------------------------------------- /lib/src/proxy/cdm_host_proxy_data.h: -------------------------------------------------------------------------------- 1 | #ifndef CDM_PROXY_CDM_HOST_WRAPPER_H 2 | #define CDM_PROXY_CDM_HOST_WRAPPER_H 3 | 4 | #include "../api/content_decryption_module.h" 5 | #include "cdm_host_proxy.h" 6 | 7 | namespace proxy { 8 | 9 | struct CmdHostProxyData { 10 | GetCdmHostFunc up_get_host_func; 11 | void* up_user_data; 12 | CdmHostProxy_10* host_proxy; 13 | }; 14 | 15 | } 16 | 17 | #endif //CDM_PROXY_CDM_HOST_WRAPPER_H 18 | -------------------------------------------------------------------------------- /lib/src/proxy/cdm_proxy.cc: -------------------------------------------------------------------------------- 1 | #include "cdm_proxy.h" 2 | 3 | namespace proxy { 4 | 5 | CdmProxy_10::CdmProxy_10(void* ptr) { 6 | this->up_ptr =static_cast(ptr); 7 | } 8 | 9 | void CdmProxy_10::Initialize(bool allow_distinctive_identifier, 10 | bool allow_persistent_state, bool use_hw_secure_codecs) { 11 | ZLOG("allow_distinctive_identifier=%d, allow_persistent_state=%d, use_hw_secure_codecs=%d", 12 | allow_distinctive_identifier, allow_persistent_state, use_hw_secure_codecs); 13 | up_ptr->Initialize(allow_distinctive_identifier, allow_persistent_state, use_hw_secure_codecs); 14 | } 15 | 16 | void CdmProxy_10::GetStatusForPolicy(uint32_t promise_id, const cdm::Policy &policy) { 17 | ZLOG("promise_id=%d", promise_id); 18 | up_ptr->GetStatusForPolicy(promise_id, policy); 19 | } 20 | 21 | void CdmProxy_10::SetServerCertificate(uint32_t promise_id, const uint8_t *server_certificate_data, 22 | uint32_t server_certificate_data_size) { 23 | ZLOG("promise_id=%d, server_certificate_data_size=%d", promise_id, server_certificate_data_size); 24 | up_ptr->SetServerCertificate(promise_id, 25 | server_certificate_data, server_certificate_data_size); 26 | } 27 | 28 | void CdmProxy_10::CreateSessionAndGenerateRequest(uint32_t promise_id, cdm::SessionType session_type, 29 | cdm::InitDataType init_data_type, const uint8_t *init_data, 30 | uint32_t init_data_size) { 31 | ZLOG("promise_id=%d, session_tpye=%d, init_data_type=%d, init_data_size=%d", 32 | promise_id, session_type, init_data_type, init_data_size); 33 | up_ptr->CreateSessionAndGenerateRequest(promise_id, session_type, 34 | init_data_type, init_data, init_data_size); 35 | } 36 | 37 | void CdmProxy_10::LoadSession(uint32_t promise_id, cdm::SessionType session_type, const char *session_id, 38 | uint32_t session_id_size) { 39 | ZLOG("promise_id=%d, session_tpye=%d, session_id=%s", promise_id, session_type, session_id); 40 | up_ptr->LoadSession(promise_id, session_type, session_id, session_id_size); 41 | } 42 | 43 | void CdmProxy_10::UpdateSession(uint32_t promise_id, const char *session_id, uint32_t session_id_size, 44 | const uint8_t *response, uint32_t response_size) { 45 | ZLOG("promise_id=%d, session_id=%s, response_size=%d", promise_id, session_id, response_size); 46 | up_ptr->UpdateSession(promise_id, session_id, session_id_size, 47 | response, response_size); 48 | } 49 | 50 | void CdmProxy_10::CloseSession(uint32_t promise_id, const char *session_id, uint32_t session_id_size) { 51 | ZLOG("promise_id=%d, session_id=%s", promise_id, session_id); 52 | up_ptr->CloseSession(promise_id, session_id, session_id_size); 53 | } 54 | 55 | void CdmProxy_10::RemoveSession(uint32_t promise_id, const char *session_id, uint32_t session_id_size) { 56 | ZLOG("promise_id=%d, session_id=%s", promise_id, session_id); 57 | up_ptr->RemoveSession(promise_id, session_id, session_id_size); 58 | } 59 | 60 | void CdmProxy_10::TimerExpired(void *context) { 61 | ZLOG("context=%p", context); 62 | up_ptr->TimerExpired(context); 63 | } 64 | 65 | cdm::Status CdmProxy_10::Decrypt(const cdm::InputBuffer_2 &encrypted_buffer, 66 | cdm::DecryptedBlock *decrypted_buffer) { 67 | auto result = up_ptr->Decrypt(encrypted_buffer, decrypted_buffer); 68 | ZLOG("result => %d", result); 69 | return result; 70 | } 71 | 72 | cdm::Status CdmProxy_10::InitializeAudioDecoder(const cdm::AudioDecoderConfig_2 &audio_decoder_config) { 73 | auto result = up_ptr->InitializeAudioDecoder(audio_decoder_config); 74 | ZLOG("result => %d", result); 75 | return result; 76 | } 77 | 78 | cdm::Status CdmProxy_10::InitializeVideoDecoder(const cdm::VideoDecoderConfig_2 &video_decoder_config) { 79 | auto result = up_ptr->InitializeVideoDecoder(video_decoder_config); 80 | ZLOG("result => %d", result); 81 | return result; 82 | } 83 | 84 | void CdmProxy_10::DeinitializeDecoder(cdm::StreamType decoder_type) { 85 | ZLOG("decoder_type=%d", decoder_type); 86 | up_ptr->DeinitializeDecoder(decoder_type); 87 | } 88 | 89 | void CdmProxy_10::ResetDecoder(cdm::StreamType decoder_type) { 90 | ZLOG("decoder_type=%d", decoder_type); 91 | up_ptr->ResetDecoder(decoder_type); 92 | } 93 | 94 | cdm::Status CdmProxy_10::DecryptAndDecodeFrame(const cdm::InputBuffer_2 &encrypted_buffer, 95 | cdm::VideoFrame *video_frame) { 96 | auto result = up_ptr->DecryptAndDecodeFrame(encrypted_buffer, video_frame); 97 | ZLOG("result => %d", result); 98 | return result; 99 | } 100 | 101 | cdm::Status CdmProxy_10::DecryptAndDecodeSamples(const cdm::InputBuffer_2 &encrypted_buffer, 102 | cdm::AudioFrames *audio_frames) { 103 | auto result = up_ptr->DecryptAndDecodeSamples(encrypted_buffer, audio_frames); 104 | ZLOG("result => %d", result); 105 | return result; 106 | } 107 | 108 | void CdmProxy_10::OnPlatformChallengeResponse(const cdm::PlatformChallengeResponse &response) { 109 | ZLOG(""); 110 | up_ptr->OnPlatformChallengeResponse(response); 111 | } 112 | 113 | void CdmProxy_10::OnQueryOutputProtectionStatus(cdm::QueryResult result, uint32_t link_mask, 114 | uint32_t output_protection_mask) { 115 | ZLOG("result=%d", result); 116 | up_ptr->OnQueryOutputProtectionStatus(result, link_mask, output_protection_mask); 117 | } 118 | 119 | void CdmProxy_10::OnStorageId(uint32_t version, const uint8_t *storage_id, uint32_t storage_id_size) { 120 | ZLOG("version=%d, storage_id_size=%d", version, storage_id_size); 121 | up_ptr->OnStorageId(version, storage_id, storage_id_size); 122 | } 123 | 124 | void CdmProxy_10::Destroy() { 125 | ZLOG(""); 126 | up_ptr->Destroy(); 127 | } 128 | 129 | } // namespace proxy -------------------------------------------------------------------------------- /lib/src/proxy/cdm_proxy.h: -------------------------------------------------------------------------------- 1 | #ifndef CDM_PROXY_CMDPROXY_H 2 | #define CDM_PROXY_CMDPROXY_H 3 | 4 | #include 5 | #include "../api/content_decryption_module.h" 6 | #include "../common/log.h" 7 | 8 | namespace proxy { 9 | 10 | // Proxy for CDM module. 11 | class CdmProxy_10 : public cdm::ContentDecryptionModule_10 { 12 | 13 | using CdmInterface = cdm::ContentDecryptionModule_10; 14 | 15 | public: 16 | explicit CdmProxy_10(void* ptr); 17 | ~CdmProxy_10() override =default; 18 | 19 | // ContentDecryptModule implementations 20 | void Initialize( 21 | bool allow_distinctive_identifier, bool allow_persistent_state, 22 | bool use_hw_secure_codecs) override; 23 | void GetStatusForPolicy( 24 | uint32_t promise_id, const cdm::Policy& policy) override; 25 | void SetServerCertificate( 26 | uint32_t promise_id, const uint8_t* server_certificate_data, 27 | uint32_t server_certificate_data_size) override; 28 | void CreateSessionAndGenerateRequest( 29 | uint32_t promise_id, cdm::SessionType session_type, 30 | cdm::InitDataType init_data_type, 31 | const uint8_t* init_data, uint32_t init_data_size) override; 32 | void LoadSession( 33 | uint32_t promise_id, cdm::SessionType session_type, 34 | const char* session_id, uint32_t session_id_size) override; 35 | void UpdateSession( 36 | uint32_t promise_id, const char* session_id, uint32_t session_id_size, 37 | const uint8_t* response, uint32_t response_size) override; 38 | void CloseSession( 39 | uint32_t promise_id, const char* session_id, uint32_t session_id_size) override; 40 | void RemoveSession( 41 | uint32_t promise_id, const char* session_id, uint32_t session_id_size) override; 42 | void TimerExpired(void* context) override; 43 | cdm::Status Decrypt( 44 | const cdm::InputBuffer_2& encrypted_buffer, cdm::DecryptedBlock* decrypted_buffer) override; 45 | cdm::Status InitializeAudioDecoder( 46 | const cdm::AudioDecoderConfig_2& audio_decoder_config) override; 47 | cdm::Status InitializeVideoDecoder( 48 | const cdm::VideoDecoderConfig_2& video_decoder_config) override; 49 | void DeinitializeDecoder(cdm::StreamType decoder_type) override; 50 | void ResetDecoder(cdm::StreamType decoder_type) override; 51 | cdm::Status DecryptAndDecodeFrame( 52 | const cdm::InputBuffer_2& encrypted_buffer, cdm::VideoFrame* video_frame) override; 53 | cdm::Status DecryptAndDecodeSamples( 54 | const cdm::InputBuffer_2& encrypted_buffer, cdm::AudioFrames* audio_frames) override; 55 | void OnPlatformChallengeResponse( 56 | const cdm::PlatformChallengeResponse& response) override; 57 | void OnQueryOutputProtectionStatus( 58 | cdm::QueryResult result, uint32_t link_mask, uint32_t output_protection_mask) override; 59 | void OnStorageId( 60 | uint32_t version, const uint8_t* storage_id, uint32_t storage_id_size) override; 61 | void Destroy() override; 62 | 63 | private: 64 | CdmInterface* up_ptr; 65 | 66 | }; 67 | 68 | } // namespace proxy 69 | 70 | #endif //CDM_PROXY_CMDPROXY_H 71 | -------------------------------------------------------------------------------- /lib/src/proxy/lib_proxy.cc: -------------------------------------------------------------------------------- 1 | #include "lib_proxy.h" 2 | 3 | #include 4 | #include 5 | 6 | namespace proxy { 7 | 8 | void* GetCdmHostProxy(int version, void* user_data) { 9 | ZLOG("version=%d", version); 10 | 11 | // Call original GetCdmHostFunc 12 | auto data = static_cast(user_data); 13 | auto ptr = data->up_get_host_func(version, data->up_user_data); 14 | // Store original host 15 | data->host_proxy->SetUpstreamPtr(ptr); 16 | return data->host_proxy; 17 | } 18 | 19 | std::shared_ptr LibProxy::Hijack(const char *lib_path) { 20 | std::shared_ptr ptr; 21 | 22 | ZLOG("Loading CDM lib: %s", lib_path); 23 | auto hdl = dlopen(lib_path, RTLD_LAZY); 24 | if(hdl != nullptr) { 25 | auto f1 = (VoidFunc) dlsym(hdl, "InitializeCdmModule_4"); 26 | auto f2 = (VoidFunc) dlsym(hdl, "DeinitializeCdmModule"); 27 | auto f3 = (CreateInstanceFunc) dlsym(hdl, "CreateCdmInstance"); 28 | auto f4 = (GetVersionFunc) dlsym(hdl, "GetCdmVersion"); 29 | if(f1 == nullptr || f2 == nullptr || f3 == nullptr || f4 == nullptr) { 30 | ZLOG("Get upstream API function error: %s", dlerror()); 31 | } else { 32 | ZLOG("Upsteam InitializeCdmModule_4 => %p", f1); 33 | ZLOG("Upsteam DeinitializeCdmModule => %p", f2); 34 | ZLOG("Upsteam CreateCdmInstance => %p", f3); 35 | ZLOG("Upsteam GetCdmVersion => %p", f4); 36 | ptr.reset(new LibProxy(hdl, f1, f2, f3, f4)); 37 | } 38 | } else { 39 | ZLOG("Load upstream lib error: %s", dlerror()); 40 | } 41 | return ptr; 42 | } 43 | 44 | void LibProxy::InitializeCmdModule() { 45 | ZLOG(""); 46 | this->func_init(); 47 | } 48 | void LibProxy::DeinitializeCmdModule() { 49 | ZLOG(""); 50 | this->func_deinit(); 51 | } 52 | 53 | void* LibProxy::CreateCdmInstance(int interface_version, 54 | const char* key_system, uint32_t key_system_size, 55 | GetCdmHostFunc get_cdm_host_func, void* user_data) { 56 | ZLOG("interface_version=%d, key_system=%s", interface_version, key_system); 57 | CmdHostProxyData proxy_data = { 58 | .up_get_host_func = get_cdm_host_func, 59 | .up_user_data = user_data, 60 | .host_proxy = cmd_host_proxy.get() 61 | }; 62 | auto ptr = this->func_create_inst(interface_version, 63 | key_system, key_system_size, 64 | // Hijack CDM host 65 | GetCdmHostProxy, &proxy_data); 66 | // Hijack CDM instance 67 | cdm_proxy = std::make_shared(ptr); 68 | return cdm_proxy.get(); 69 | } 70 | 71 | const char* LibProxy::GetCdmVersion() { 72 | auto version = this->func_get_ver(); 73 | ZLOG("result => %s", version); 74 | return version; 75 | } 76 | 77 | LibProxy::~LibProxy() { 78 | if (hdl != nullptr) { 79 | dlclose(hdl); 80 | } 81 | } 82 | 83 | } // namespace proxy 84 | -------------------------------------------------------------------------------- /lib/src/proxy/lib_proxy.h: -------------------------------------------------------------------------------- 1 | #ifndef CDM_PROXY_LIB_PROXY_H 2 | #define CDM_PROXY_LIB_PROXY_H 3 | 4 | #include 5 | #include 6 | 7 | #include "../common/log.h" 8 | #include "../api/content_decryption_module.h" 9 | #include "cdm_proxy.h" 10 | #include "cdm_host_proxy_data.h" 11 | #include "cdm_host_proxy.h" 12 | 13 | namespace proxy { 14 | 15 | void* GetCdmHostProxy(int version, void* user_data); 16 | 17 | typedef void (* VoidFunc)(); 18 | typedef void* (* CreateInstanceFunc)(int, const char*, uint32_t, GetCdmHostFunc, void*); 19 | typedef char* (* GetVersionFunc)(); 20 | 21 | // Proxy for libwidevinecdm APIs 22 | class LibProxy { 23 | 24 | public: 25 | static std::shared_ptr Hijack(const char* lib_path); 26 | 27 | void InitializeCmdModule(); 28 | void DeinitializeCmdModule(); 29 | void* CreateCdmInstance(int interface_version, 30 | const char* key_system, uint32_t key_system_size, 31 | GetCdmHostFunc get_cdm_host_func, void* user_data); 32 | const char* GetCdmVersion(); 33 | 34 | ~LibProxy(); 35 | 36 | private: 37 | LibProxy(void* hdl, 38 | VoidFunc func_init, 39 | VoidFunc func_deinit, 40 | CreateInstanceFunc func_create_inst, 41 | GetVersionFunc func_get_ver) { 42 | this->hdl = hdl; 43 | this->func_init = func_init; 44 | this->func_deinit = func_deinit; 45 | this->func_create_inst = func_create_inst; 46 | this->func_get_ver = func_get_ver; 47 | 48 | this->cmd_host_proxy = std::make_shared(); 49 | } 50 | 51 | private: 52 | // Upstream lib 53 | void* hdl; 54 | VoidFunc func_init; 55 | VoidFunc func_deinit; 56 | CreateInstanceFunc func_create_inst; 57 | GetVersionFunc func_get_ver; 58 | 59 | // Proxies 60 | std::shared_ptr cdm_proxy; 61 | std::shared_ptr cmd_host_proxy; 62 | 63 | }; 64 | } 65 | 66 | #endif //CDM_PROXY_LIB_PROXY_H 67 | --------------------------------------------------------------------------------