Re: Bug#1108891: kodi-inputstream-adaptive: Trixie version of inputstream-adaptive crashes with Widevine CDM
On 2025-07-15 21:07:56 +0300, Vasyl Gello wrote:
> Package: kodi-inputstream-adaptive
> Version: 21.5.9+ds-1
> Followup-For: Bug #1108891
> X-Debbugs-Cc: debian-release@lists.debian.org
>
> Hi Mark,
>
> Thanks for pointing this out! My analysis shows that the CDM fix
> was more or less sorted out in 21.5.15+ds-1 that I have prepared
> for upload.
>
> The test DEB for you is:
> http://temp.sh/XXsbF/kodi-inputstream-adaptive_21.5.15ds-1_amd64.deb
>
> Please confirm that everything works (or does not work) for you now.
>
> CC'ing #debian-release team with a broader question: since all Kodi
> and addon point releases for 21.x are bugfix-only, is it possible to
> get chromium-style approval for src:kodi and src:kodi-* in Debian 13?
>
> That would solve ton of user woes and, basically, that was my ideal
> when I started the maintainership back in 2020.
>
> For the record, I attach the debdiff between current version in trixie
> (21.5.9+ds-1) and the fixed (21.5.15+ds-1). It is quite big (250 KB)
> because of clang-format run during the backport. However it is all
> backport of a bugfix, therefore I barely see the reason to add the
> actual patch sequence to debian/patches compared to new version upload.
>
> Dear colleagues from release team, what do you think?
It's too late now, but for the future: best way to get input from us is
via unblock (pre-approval) requests. Mails to the mailing list have a
high chance to be missed.
Cheers
>
> Sincerely,
> Vasyl
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/azure-pipelines.yml kodi-inputstream-adaptive-21.5.15+ds/azure-pipelines.yml
> --- kodi-inputstream-adaptive-21.5.9+ds/azure-pipelines.yml 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/azure-pipelines.yml 2025-07-06 07:54:23.000000000 +0000
> @@ -39,11 +39,11 @@
> ARCHITECTURE: x64
> CONFIGURATION: Release
> WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.17763.0"
> - ARM32-UWP:
> - GENERATOR: "Visual Studio 17 2022"
> - ARCHITECTURE: ARM
> - CONFIGURATION: Release
> - WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.17763.0"
> + #ARM32-UWP:
> + # GENERATOR: "Visual Studio 17 2022"
> + # ARCHITECTURE: ARM
> + # CONFIGURATION: Release
> + # WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.17763.0"
> #ARM64-UWP:
> # GENERATOR: "Visual Studio 17 2022"
> # ARCHITECTURE: ARM64
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/debian/changelog kodi-inputstream-adaptive-21.5.15+ds/debian/changelog
> --- kodi-inputstream-adaptive-21.5.9+ds/debian/changelog 2025-01-27 08:45:13.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/debian/changelog 2025-07-15 16:51:54.000000000 +0000
> @@ -1,3 +1,9 @@
> +kodi-inputstream-adaptive (21.5.15+ds-1) unstable; urgency=high
> +
> + * New upstream version 21.5.15+ds (Closes: #1108891)
> +
> + -- Vasyl Gello <vasek.gello@gmail.com> Tue, 15 Jul 2025 16:51:54 +0000
> +
> kodi-inputstream-adaptive (21.5.9+ds-1) unstable; urgency=high
>
> * New upstream version 21.5.9+ds
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/depends/common/pugixml/flags.txt kodi-inputstream-adaptive-21.5.15+ds/depends/common/pugixml/flags.txt
> --- kodi-inputstream-adaptive-21.5.9+ds/depends/common/pugixml/flags.txt 1970-01-01 00:00:00.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/depends/common/pugixml/flags.txt 2025-07-06 07:54:23.000000000 +0000
> @@ -0,0 +1 @@
> +-DCMAKE_POLICY_VERSION_MINIMUM=3.5
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/depends/common/rapidjson/flags.txt kodi-inputstream-adaptive-21.5.15+ds/depends/common/rapidjson/flags.txt
> --- kodi-inputstream-adaptive-21.5.9+ds/depends/common/rapidjson/flags.txt 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/depends/common/rapidjson/flags.txt 2025-07-06 07:54:23.000000000 +0000
> @@ -1 +1 @@
> --DRAPIDJSON_BUILD_DOC=OFF -DRAPIDJSON_BUILD_EXAMPLES=OFF -DRAPIDJSON_BUILD_TESTS=OFF -DRAPIDJSON_BUILD_CXX17=ON -DRAPIDJSON_HAS_STDSTRING=ON
> +-DRAPIDJSON_BUILD_DOC=OFF -DRAPIDJSON_BUILD_EXAMPLES=OFF -DRAPIDJSON_BUILD_TESTS=OFF -DRAPIDJSON_BUILD_CXX17=ON -DRAPIDJSON_HAS_STDSTRING=ON -DCMAKE_POLICY_VERSION_MINIMUM=3.5
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/inputstream.adaptive/addon.xml.in kodi-inputstream-adaptive-21.5.15+ds/inputstream.adaptive/addon.xml.in
> --- kodi-inputstream-adaptive-21.5.9+ds/inputstream.adaptive/addon.xml.in 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/inputstream.adaptive/addon.xml.in 2025-07-06 07:54:23.000000000 +0000
> @@ -1,7 +1,7 @@
> <?xml version="1.0" encoding="UTF-8"?>
> <addon
> id="inputstream.adaptive"
> - version="21.5.9"
> + version="21.5.15"
> name="InputStream Adaptive"
> provider-name="peak3d, Team Kodi">
> <requires>@ADDON_DEPENDS@</requires>
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/inputstream.adaptive/changelog.txt kodi-inputstream-adaptive-21.5.15+ds/inputstream.adaptive/changelog.txt
> --- kodi-inputstream-adaptive-21.5.9+ds/inputstream.adaptive/changelog.txt 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/inputstream.adaptive/changelog.txt 2025-07-06 07:54:23.000000000 +0000
> @@ -1,3 +1,26 @@
> +v21.5.15 (2025-07-06)
> +- Fix playback with IP with port number
> +
> +v21.5.14 (2025-05-15)
> +- Fix playback problem due to URLs containing dots on paths
> +
> +v21.5.13 (2025-05-04)
> +- Fix crash with Widevine CDM 4.10.2891.0
> +- [Widevine] Updated CDM interface
> +
> +v21.5.12 (2025-04-27)
> +- [Dash] Fix SegmentTemplate TSB to prevent use extra live delay workarounds
> +
> +v21.5.11 (2025-04-15)
> +- Fix live delay that was causing broken playback in some cases
> +
> +v21.5.10 (2025-04-06)
> +- INFO: Widevine CDM 4.10.2891.0 cannot be used to play videos, if you installed it reinstall an old version
> +- [ClearKey] Fix playback with streams that have mixed unencrypted/encrypted segments
> +- [HLS] Fix timeshift on single period video stream
> +- [HLS] Fix possible repeated frames on live stream with discontinuities
> +- Fix playback with SMIL URL manifests
> +
> v21.5.9 (2025-01-19)
> - Fix packaging errors
>
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/lib/cdm/cdm/debug.cpp kodi-inputstream-adaptive-21.5.15+ds/lib/cdm/cdm/debug.cpp
> --- kodi-inputstream-adaptive-21.5.9+ds/lib/cdm/cdm/debug.cpp 1970-01-01 00:00:00.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/lib/cdm/cdm/debug.cpp 2025-07-06 07:54:23.000000000 +0000
> @@ -0,0 +1,57 @@
> +/*
> + * Copyright (C) 2025 Team Kodi
> + * This file is part of Kodi - https://kodi.tv
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + * See LICENSES/README.md for more information.
> + */
> +
> +#include "debug.h"
> +
> +#include <cstdarg>
> +#include <cstdio>
> +
> +#ifdef _MSC_VER
> +#define snprintf _snprintf
> +#endif
> +
> +struct dbgContext
> +{
> + const char* name;
> + void (*msgCallback)(const CDM_DBG::LogLevel level, const char* msg);
> +};
> +
> +dbgContext debugContext = {"WV-CDM-Library", nullptr};
> +
> +void CDM_DBG::Log(const CDM_DBG::LogLevel level, const char* format, ...)
> +{
> + if (!debugContext.msgCallback)
> + return;
> +
> + char msg[2048];
> + const int len = snprintf(msg, sizeof(msg), "[%s] ", debugContext.name);
> + if (len < 0 || len >= sizeof(msg))
> + {
> + debugContext.msgCallback(CDM_DBG::LogLevel::ERROR,
> + "Cannot print log string: Context name too long");
> + return;
> + }
> +
> + va_list ap;
> + va_start(ap, format);
> + const int formattedLen = vsnprintf(msg + len, sizeof(msg) - len, format, ap);
> + va_end(ap);
> + if (formattedLen < 0 || formattedLen >= (sizeof(msg) - len))
> + {
> + debugContext.msgCallback(CDM_DBG::LogLevel::ERROR,
> + "Cannot print log string: Text content too long");
> + return;
> + }
> +
> + debugContext.msgCallback(level, msg);
> +}
> +
> +void CDM_DBG::SetDBGMsgCallback(void (*msgcb)(const CDM_DBG::LogLevel level, const char* msg))
> +{
> + debugContext.msgCallback = msgcb;
> +}
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/lib/cdm/cdm/debug.h kodi-inputstream-adaptive-21.5.15+ds/lib/cdm/cdm/debug.h
> --- kodi-inputstream-adaptive-21.5.9+ds/lib/cdm/cdm/debug.h 1970-01-01 00:00:00.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/lib/cdm/cdm/debug.h 2025-07-06 07:54:23.000000000 +0000
> @@ -0,0 +1,27 @@
> +/*
> + * Copyright (C) 2025 Team Kodi
> + * This file is part of Kodi - https://kodi.tv
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + * See LICENSES/README.md for more information.
> + */
> +
> +#pragma once
> +
> +namespace CDM_DBG
> +{
> +enum class LogLevel
> +{
> + DEBUG,
> + INFO,
> + WARNING,
> + ERROR,
> + FATAL
> +};
> +
> +void Log(const LogLevel level, const char* format, ...);
> +#define LogF(level, format, ...) Log((level), ("%s: " format), __FUNCTION__, ##__VA_ARGS__)
> +
> +void SetDBGMsgCallback(void (*msgcb)(const LogLevel level, const char* msg));
> +
> +} // namespace cdm
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/lib/cdm/cdm/media/cdm/api/content_decryption_module.h kodi-inputstream-adaptive-21.5.15+ds/lib/cdm/cdm/media/cdm/api/content_decryption_module.h
> --- kodi-inputstream-adaptive-21.5.9+ds/lib/cdm/cdm/media/cdm/api/content_decryption_module.h 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/lib/cdm/cdm/media/cdm/api/content_decryption_module.h 2025-07-06 07:54:23.000000000 +0000
> @@ -12,7 +12,6 @@
> #include <type_traits>
>
> #include "content_decryption_module_export.h"
> -#include "content_decryption_module_proxy.h"
>
> #if defined(_MSC_VER)
> typedef unsigned char uint8_t;
> @@ -51,1731 +50,1728 @@
>
> extern "C" {
>
> - CDM_API void INITIALIZE_CDM_MODULE();
> +CDM_API void INITIALIZE_CDM_MODULE();
>
> - CDM_API void DeinitializeCdmModule();
> +CDM_API void DeinitializeCdmModule();
>
> - // Returns a pointer to the requested CDM Host interface upon success.
> - // Returns NULL if the requested CDM Host interface is not supported.
> - // The caller should cast the returned pointer to the type matching
> - // |host_interface_version|.
> - typedef void* (*GetCdmHostFunc)(int host_interface_version, void* user_data);
> -
> - // Returns a pointer to the requested CDM upon success.
> - // Returns NULL if an error occurs or the requested |cdm_interface_version| or
> - // |key_system| is not supported or another error occurs.
> - // The caller should cast the returned pointer to the type matching
> - // |cdm_interface_version|.
> - // Caller retains ownership of arguments and must call Destroy() on the returned
> - // object.
> - CDM_API void* CreateCdmInstance(int cdm_interface_version,
> - const char* key_system,
> - uint32_t key_system_size,
> - GetCdmHostFunc get_cdm_host_func,
> - void* user_data);
> +// Returns a pointer to the requested CDM Host interface upon success.
> +// Returns NULL if the requested CDM Host interface is not supported.
> +// The caller should cast the returned pointer to the type matching
> +// |host_interface_version|.
> +typedef void* (*GetCdmHostFunc)(int host_interface_version, void* user_data);
> +
> +// Returns a pointer to the requested CDM upon success.
> +// Returns NULL if an error occurs or the requested |cdm_interface_version| or
> +// |key_system| is not supported or another error occurs.
> +// The caller should cast the returned pointer to the type matching
> +// |cdm_interface_version|.
> +// Caller retains ownership of arguments and must call Destroy() on the returned
> +// object.
> +CDM_API void* CreateCdmInstance(int cdm_interface_version,
> + const char* key_system,
> + uint32_t key_system_size,
> + GetCdmHostFunc get_cdm_host_func,
> + void* user_data);
>
> - CDM_API const char* GetCdmVersion();
> +CDM_API const char* GetCdmVersion();
>
> } // extern "C"
>
> namespace cdm {
>
> - enum Status : uint32_t {
> - kSuccess = 0,
> - kNeedMoreData, // Decoder needs more data to produce a decoded frame/sample.
> - kNoKey, // The required decryption key is not available.
> - kInitializationError, // Initialization error.
> - kDecryptError, // Decryption failed.
> - kDecodeError, // Error decoding audio or video.
> - kDeferredInitialization // Decoder is not ready for initialization.
> - };
> - CHECK_TYPE(Status, 4, 4);
> -
> - // Exceptions used by the CDM to reject promises.
> - // https://w3c.github.io/encrypted-media/#exceptions
> - enum Exception : uint32_t {
> - kExceptionTypeError,
> - kExceptionNotSupportedError,
> - kExceptionInvalidStateError,
> - kExceptionQuotaExceededError
> - };
> - CHECK_TYPE(Exception, 4, 4);
> -
> - // The encryption scheme. The definitions are from ISO/IEC 23001-7:2016.
> - enum class EncryptionScheme : uint32_t {
> - kUnencrypted = 0,
> - kCenc, // 'cenc' subsample encryption using AES-CTR mode.
> - kCbcs // 'cbcs' pattern encryption using AES-CBC mode.
> - };
> - CHECK_TYPE(EncryptionScheme, 4, 4);
> -
> - // The pattern used for pattern encryption. Note that ISO/IEC 23001-7:2016
> - // defines each block to be 16-bytes.
> - struct Pattern {
> - uint32_t crypt_byte_block; // Count of the encrypted blocks.
> - uint32_t skip_byte_block; // Count of the unencrypted blocks.
> - };
> - CHECK_TYPE(Pattern, 8, 8);
> -
> - enum class ColorRange : uint8_t {
> - kInvalid,
> - kLimited, // 709 color range with RGB values ranging from 16 to 235.
> - kFull, // Full RGB color range with RGB values from 0 to 255.
> - kDerived // Range is defined by |transfer_id| and |matrix_id|.
> - };
> - CHECK_TYPE(ColorRange, 1, 1);
> -
> - // Described in ISO 23001-8:2016, section 7. All the IDs are in the range
> - // [0, 255] so 8-bit integer is sufficient. An unspecified ColorSpace should be
> - // {2, 2, 2, ColorRange::kInvalid}, where value 2 means "Unspecified" for all
> - // the IDs, as defined by the spec.
> - struct ColorSpace {
> - uint8_t primary_id; // 7.1 colour primaries, table 2
> - uint8_t transfer_id; // 7.2 transfer characteristics, table 3
> - uint8_t matrix_id; // 7.3 matrix coefficients, table 4
> - ColorRange range;
> - };
> - CHECK_TYPE(ColorSpace, 4, 4);
> -
> - // Time is defined as the number of seconds since the Epoch
> - // (00:00:00 UTC, January 1, 1970), not including any added leap second.
> - // Also see Time definition in spec: https://w3c.github.io/encrypted-media/#time
> - // Note that Time is defined in millisecond accuracy in the spec but in second
> - // accuracy here.
> - typedef double Time;
> -
> - // An input buffer can be split into several continuous subsamples.
> - // A SubsampleEntry specifies the number of clear and cipher bytes in each
> - // subsample. For example, the following buffer has three subsamples:
> - //
> - // |<----- subsample1 ----->|<----- subsample2 ----->|<----- subsample3 ----->|
> - // | clear1 | cipher1 | clear2 | cipher2 | clear3 | cipher3 |
> - //
> - // For decryption, all of the cipher bytes in a buffer should be concatenated
> - // (in the subsample order) into a single logical stream. The clear bytes should
> - // not be considered as part of decryption.
> - //
> - // Stream to decrypt: | cipher1 | cipher2 | cipher3 |
> - // Decrypted stream: | decrypted1| decrypted2 | decrypted3 |
> - //
> - // After decryption, the decrypted bytes should be copied over the position
> - // of the corresponding cipher bytes in the original buffer to form the output
> - // buffer. Following the above example, the decrypted buffer should be:
> +enum Status : uint32_t {
> + kSuccess = 0,
> + kNeedMoreData, // Decoder needs more data to produce a decoded frame/sample.
> + kNoKey, // The required decryption key is not available.
> + kInitializationError, // Initialization error.
> + kDecryptError, // Decryption failed.
> + kDecodeError, // Error decoding audio or video.
> + kDeferredInitialization // Decoder is not ready for initialization.
> +};
> +CHECK_TYPE(Status, 4, 4);
> +
> +// Exceptions used by the CDM to reject promises.
> +// https://w3c.github.io/encrypted-media/#exceptions
> +enum Exception : uint32_t {
> + kExceptionTypeError,
> + kExceptionNotSupportedError,
> + kExceptionInvalidStateError,
> + kExceptionQuotaExceededError
> +};
> +CHECK_TYPE(Exception, 4, 4);
> +
> +// The encryption scheme. The definitions are from ISO/IEC 23001-7:2016.
> +enum class EncryptionScheme : uint32_t {
> + kUnencrypted = 0,
> + kCenc, // 'cenc' subsample encryption using AES-CTR mode.
> + kCbcs // 'cbcs' pattern encryption using AES-CBC mode.
> +};
> +CHECK_TYPE(EncryptionScheme, 4, 4);
> +
> +// The pattern used for pattern encryption. Note that ISO/IEC 23001-7:2016
> +// defines each block to be 16-bytes.
> +struct Pattern {
> + uint32_t crypt_byte_block; // Count of the encrypted blocks.
> + uint32_t skip_byte_block; // Count of the unencrypted blocks.
> +};
> +CHECK_TYPE(Pattern, 8, 8);
> +
> +enum class ColorRange : uint8_t {
> + kInvalid,
> + kLimited, // 709 color range with RGB values ranging from 16 to 235.
> + kFull, // Full RGB color range with RGB values from 0 to 255.
> + kDerived // Range is defined by |transfer_id| and |matrix_id|.
> +};
> +CHECK_TYPE(ColorRange, 1, 1);
> +
> +// Described in ISO 23001-8:2016, section 7. All the IDs are in the range
> +// [0, 255] so 8-bit integer is sufficient. An unspecified ColorSpace should be
> +// {2, 2, 2, ColorRange::kInvalid}, where value 2 means "Unspecified" for all
> +// the IDs, as defined by the spec.
> +struct ColorSpace {
> + uint8_t primary_id; // 7.1 colour primaries, table 2
> + uint8_t transfer_id; // 7.2 transfer characteristics, table 3
> + uint8_t matrix_id; // 7.3 matrix coefficients, table 4
> + ColorRange range;
> +};
> +CHECK_TYPE(ColorSpace, 4, 4);
> +
> +// Time is defined as the number of seconds since the Epoch
> +// (00:00:00 UTC, January 1, 1970), not including any added leap second.
> +// Also see Time definition in spec: https://w3c.github.io/encrypted-media/#time
> +// Note that Time is defined in millisecond accuracy in the spec but in second
> +// accuracy here.
> +typedef double Time;
> +
> +// An input buffer can be split into several continuous subsamples.
> +// A SubsampleEntry specifies the number of clear and cipher bytes in each
> +// subsample. For example, the following buffer has three subsamples:
> +//
> +// |<----- subsample1 ----->|<----- subsample2 ----->|<----- subsample3 ----->|
> +// | clear1 | cipher1 | clear2 | cipher2 | clear3 | cipher3 |
> +//
> +// For decryption, all of the cipher bytes in a buffer should be concatenated
> +// (in the subsample order) into a single logical stream. The clear bytes should
> +// not be considered as part of decryption.
> +//
> +// Stream to decrypt: | cipher1 | cipher2 | cipher3 |
> +// Decrypted stream: | decrypted1| decrypted2 | decrypted3 |
> +//
> +// After decryption, the decrypted bytes should be copied over the position
> +// of the corresponding cipher bytes in the original buffer to form the output
> +// buffer. Following the above example, the decrypted buffer should be:
> +//
> +// |<----- subsample1 ----->|<----- subsample2 ----->|<----- subsample3 ----->|
> +// | clear1 | decrypted1| clear2 | decrypted2 | clear3 | decrypted3 |
> +//
> +struct SubsampleEntry {
> + uint32_t clear_bytes;
> + uint32_t cipher_bytes;
> +};
> +CHECK_TYPE(SubsampleEntry, 8, 8);
> +
> +// Represents an input buffer to be decrypted (and possibly decoded). It does
> +// not own any pointers in this struct. If |encryption_scheme| = kUnencrypted,
> +// the data is unencrypted.
> +// Note that this struct is organized so that sizeof(InputBuffer_2)
> +// equals the sum of sizeof() all members in both 32-bit and 64-bit compiles.
> +// Padding has been added to keep the fields aligned.
> +struct InputBuffer_2 {
> + const uint8_t* data; // Pointer to the beginning of the input data.
> + uint32_t data_size; // Size (in bytes) of |data|.
> +
> + EncryptionScheme encryption_scheme;
> +
> + const uint8_t* key_id; // Key ID to identify the decryption key.
> + uint32_t key_id_size; // Size (in bytes) of |key_id|.
> + uint32_t : 32; // Padding.
> +
> + const uint8_t* iv; // Initialization vector.
> + uint32_t iv_size; // Size (in bytes) of |iv|.
> + uint32_t : 32; // Padding.
> +
> + const struct SubsampleEntry* subsamples;
> + uint32_t num_subsamples; // Number of subsamples in |subsamples|.
> + uint32_t : 32; // Padding.
> +
> + // |pattern| is required if |encryption_scheme| specifies pattern encryption.
> + Pattern pattern;
> +
> + int64_t timestamp; // Presentation timestamp in microseconds.
> +};
> +CHECK_TYPE(InputBuffer_2, 64, 80);
> +
> +enum AudioCodec : uint32_t { kUnknownAudioCodec = 0, kCodecVorbis, kCodecAac };
> +CHECK_TYPE(AudioCodec, 4, 4);
> +
> +struct AudioDecoderConfig_2 {
> + AudioCodec codec;
> + int32_t channel_count;
> + int32_t bits_per_channel;
> + int32_t samples_per_second;
> +
> + // Optional byte data required to initialize audio decoders, such as the
> + // vorbis setup header.
> + uint8_t* extra_data;
> + uint32_t extra_data_size;
> +
> + // Encryption scheme.
> + EncryptionScheme encryption_scheme;
> +};
> +CHECK_TYPE(AudioDecoderConfig_2, 28, 32);
> +
> +// Supported sample formats for AudioFrames.
> +enum AudioFormat : uint32_t {
> + kUnknownAudioFormat = 0, // Unknown format value. Used for error reporting.
> + kAudioFormatU8, // Interleaved unsigned 8-bit w/ bias of 128.
> + kAudioFormatS16, // Interleaved signed 16-bit.
> + kAudioFormatS32, // Interleaved signed 32-bit.
> + kAudioFormatF32, // Interleaved float 32-bit.
> + kAudioFormatPlanarS16, // Signed 16-bit planar.
> + kAudioFormatPlanarF32, // Float 32-bit planar.
> +};
> +CHECK_TYPE(AudioFormat, 4, 4);
> +
> +// Surface formats based on FOURCC labels, see: http://www.fourcc.org/yuv.php
> +// Values are chosen to be consistent with Chromium's VideoPixelFormat values.
> +enum VideoFormat : uint32_t {
> + kUnknownVideoFormat = 0, // Unknown format value. Used for error reporting.
> + kYv12 = 1, // 12bpp YVU planar 1x1 Y, 2x2 VU samples.
> + kI420 = 2, // 12bpp YUV planar 1x1 Y, 2x2 UV samples.
> +
> + // In the following formats, each sample uses 16-bit in storage, while the
> + // sample value is stored in the least significant N bits where N is
> + // specified by the number after "P". For example, for YUV420P9, each Y, U,
> + // and V sample is stored in the least significant 9 bits in a 2-byte block.
> + kYUV420P9 = 16,
> + kYUV420P10 = 17,
> + kYUV422P9 = 18,
> + kYUV422P10 = 19,
> + kYUV444P9 = 20,
> + kYUV444P10 = 21,
> + kYUV420P12 = 22,
> + kYUV422P12 = 23,
> + kYUV444P12 = 24,
> +};
> +CHECK_TYPE(VideoFormat, 4, 4);
> +
> +struct Size {
> + int32_t width;
> + int32_t height;
> +};
> +CHECK_TYPE(Size, 8, 8);
> +
> +enum VideoCodec : uint32_t {
> + kUnknownVideoCodec = 0,
> + kCodecVp8,
> + kCodecH264,
> + kCodecVp9,
> + kCodecAv1
> +};
> +CHECK_TYPE(VideoCodec, 4, 4);
> +
> +enum VideoCodecProfile : uint32_t {
> + kUnknownVideoCodecProfile = 0,
> + kProfileNotNeeded,
> + kH264ProfileBaseline,
> + kH264ProfileMain,
> + kH264ProfileExtended,
> + kH264ProfileHigh,
> + kH264ProfileHigh10,
> + kH264ProfileHigh422,
> + kH264ProfileHigh444Predictive,
> + kVP9Profile0,
> + kVP9Profile1,
> + kVP9Profile2,
> + kVP9Profile3,
> + kAv1ProfileMain,
> + kAv1ProfileHigh,
> + kAv1ProfilePro
> +};
> +CHECK_TYPE(VideoCodecProfile, 4, 4);
> +
> +// Deprecated: New CDM implementations should use VideoDecoderConfig_3.
> +// Note that this struct is organized so that sizeof(VideoDecoderConfig_2)
> +// equals the sum of sizeof() all members in both 32-bit and 64-bit compiles.
> +// Padding has been added to keep the fields aligned.
> +struct VideoDecoderConfig_2 {
> + VideoCodec codec;
> + VideoCodecProfile profile;
> + VideoFormat format;
> + uint32_t : 32; // Padding.
> +
> + // Width and height of video frame immediately post-decode. Not all pixels
> + // in this region are valid.
> + Size coded_size;
> +
> + // Optional byte data required to initialize video decoders, such as H.264
> + // AAVC data.
> + uint8_t* extra_data;
> + uint32_t extra_data_size;
> +
> + // Encryption scheme.
> + EncryptionScheme encryption_scheme;
> +};
> +CHECK_TYPE(VideoDecoderConfig_2, 36, 40);
> +
> +struct VideoDecoderConfig_3 {
> + VideoCodec codec;
> + VideoCodecProfile profile;
> + VideoFormat format;
> + ColorSpace color_space;
> +
> + // Width and height of video frame immediately post-decode. Not all pixels
> + // in this region are valid.
> + Size coded_size;
> +
> + // Optional byte data required to initialize video decoders, such as H.264
> + // AAVC data.
> + uint8_t* extra_data;
> + uint32_t extra_data_size;
> +
> + EncryptionScheme encryption_scheme;
> +};
> +CHECK_TYPE(VideoDecoderConfig_3, 36, 40);
> +
> +enum StreamType : uint32_t { kStreamTypeAudio = 0, kStreamTypeVideo = 1 };
> +CHECK_TYPE(StreamType, 4, 4);
> +
> +// Structure provided to ContentDecryptionModule::OnPlatformChallengeResponse()
> +// after a platform challenge was initiated via Host::SendPlatformChallenge().
> +// All values will be NULL / zero in the event of a challenge failure.
> +struct PlatformChallengeResponse {
> + // |challenge| provided during Host::SendPlatformChallenge() combined with
> + // nonce data and signed with the platform's private key.
> + const uint8_t* signed_data;
> + uint32_t signed_data_length;
> +
> + // RSASSA-PKCS1-v1_5-SHA256 signature of the |signed_data| block.
> + const uint8_t* signed_data_signature;
> + uint32_t signed_data_signature_length;
> +
> + // X.509 device specific certificate for the |service_id| requested.
> + const uint8_t* platform_key_certificate;
> + uint32_t platform_key_certificate_length;
> +};
> +CHECK_TYPE(PlatformChallengeResponse, 24, 48);
> +
> +// The current status of the associated key. The valid types are defined in the
> +// spec: https://w3c.github.io/encrypted-media/#dom-mediakeystatus
> +enum KeyStatus : uint32_t {
> + kUsable = 0,
> + kInternalError = 1,
> + kExpired = 2,
> + kOutputRestricted = 3,
> + kOutputDownscaled = 4,
> + kStatusPending = 5,
> + kReleased = 6
> +};
> +CHECK_TYPE(KeyStatus, 4, 4);
> +
> +// The current status of the associated key. The valid types are defined in the
> +// spec: https://w3c.github.io/encrypted-media/#dom-mediakeystatus
> +// Note: For forward compatibility, Host implementations must gracefully handle
> +// unexpected (new) enum values, e.g. no-op. This is used by the CDM Interfaces
> +// starting from CDM_12.
> +enum class KeyStatus_2 : uint32_t {
> + kUsable = 0,
> + kInternalError = 1,
> + kExpired = 2,
> + kOutputRestricted = 3,
> + kOutputDownscaled = 4,
> + kStatusPending = 5,
> + kReleased = 6,
> + kUsableInFuture = 7
> +};
> +CHECK_TYPE(KeyStatus_2, 4, 4);
> +
> +// Used when passing arrays of key information. Does not own the referenced
> +// data. |system_code| is an additional error code for unusable keys and
> +// should be 0 when |status| == kUsable.
> +struct KeyInformation {
> + const uint8_t* key_id;
> + uint32_t key_id_size;
> + KeyStatus status;
> + uint32_t system_code;
> +};
> +CHECK_TYPE(KeyInformation, 16, 24);
> +
> +// Used when passing arrays of key information. Does not own the referenced
> +// data. |system_code| is an additional error code for unusable keys and
> +// should be 0 when |status| == kUsable. Used by CDM12 and beyond.
> +struct KeyInformation_2 {
> + const uint8_t* key_id;
> + uint32_t key_id_size;
> + KeyStatus_2 status;
> + uint32_t system_code;
> +};
> +CHECK_TYPE(KeyInformation_2, 16, 24);
> +
> +// Supported output protection methods for use with EnableOutputProtection() and
> +// returned by OnQueryOutputProtectionStatus().
> +enum OutputProtectionMethods : uint32_t {
> + kProtectionNone = 0,
> + kProtectionHDCP = 1 << 0
> +};
> +CHECK_TYPE(OutputProtectionMethods, 4, 4);
> +
> +// Connected output link types returned by OnQueryOutputProtectionStatus().
> +enum OutputLinkTypes : uint32_t {
> + kLinkTypeNone = 0,
> + kLinkTypeUnknown = 1 << 0,
> + kLinkTypeInternal = 1 << 1,
> + kLinkTypeVGA = 1 << 2,
> + kLinkTypeHDMI = 1 << 3,
> + kLinkTypeDVI = 1 << 4,
> + kLinkTypeDisplayPort = 1 << 5,
> + kLinkTypeNetwork = 1 << 6
> +};
> +CHECK_TYPE(OutputLinkTypes, 4, 4);
> +
> +// Result of the QueryOutputProtectionStatus() call.
> +enum QueryResult : uint32_t { kQuerySucceeded = 0, kQueryFailed };
> +CHECK_TYPE(QueryResult, 4, 4);
> +
> +// The Initialization Data Type. The valid types are defined in the spec:
> +// https://w3c.github.io/encrypted-media/format-registry/initdata/index.html#registry
> +enum InitDataType : uint32_t { kCenc = 0, kKeyIds = 1, kWebM = 2 };
> +CHECK_TYPE(InitDataType, 4, 4);
> +
> +// The type of session to create. The valid types are defined in the spec:
> +// https://w3c.github.io/encrypted-media/#dom-mediakeysessiontype
> +enum SessionType : uint32_t {
> + kTemporary = 0,
> + kPersistentLicense = 1
> +};
> +CHECK_TYPE(SessionType, 4, 4);
> +
> +// The type of the message event. The valid types are defined in the spec:
> +// https://w3c.github.io/encrypted-media/#dom-mediakeymessagetype
> +enum MessageType : uint32_t {
> + kLicenseRequest = 0,
> + kLicenseRenewal = 1,
> + kLicenseRelease = 2,
> + kIndividualizationRequest = 3
> +};
> +CHECK_TYPE(MessageType, 4, 4);
> +
> +enum HdcpVersion : uint32_t {
> + kHdcpVersionNone,
> + kHdcpVersion1_0,
> + kHdcpVersion1_1,
> + kHdcpVersion1_2,
> + kHdcpVersion1_3,
> + kHdcpVersion1_4,
> + kHdcpVersion2_0,
> + kHdcpVersion2_1,
> + kHdcpVersion2_2,
> + kHdcpVersion2_3
> +};
> +CHECK_TYPE(HdcpVersion, 4, 4);
> +
> +struct Policy {
> + HdcpVersion min_hdcp_version;
> +};
> +CHECK_TYPE(Policy, 4, 4);
> +
> +// Represents a buffer created by Allocator implementations.
> +class CDM_CLASS_API Buffer {
> + public:
> + // Destroys the buffer in the same context as it was created.
> + virtual void Destroy() = 0;
> +
> + virtual uint32_t Capacity() const = 0;
> + virtual uint8_t* Data() = 0;
> + virtual void SetSize(uint32_t size) = 0;
> + virtual uint32_t Size() const = 0;
> +
> + protected:
> + Buffer() {}
> + virtual ~Buffer() {}
> +
> + private:
> + Buffer(const Buffer&);
> + void operator=(const Buffer&);
> +};
> +
> +// Represents a decrypted block that has not been decoded.
> +class CDM_CLASS_API DecryptedBlock {
> + public:
> + virtual void SetDecryptedBuffer(Buffer* buffer) = 0;
> + virtual Buffer* DecryptedBuffer() = 0;
> +
> + // TODO(tomfinegan): Figure out if timestamp is really needed. If it is not,
> + // we can just pass Buffer pointers around.
> + virtual void SetTimestamp(int64_t timestamp) = 0;
> + virtual int64_t Timestamp() const = 0;
> +
> + protected:
> + DecryptedBlock() {}
> + virtual ~DecryptedBlock() {}
> +};
> +
> +// This intentionally avoids using an enum, since it will be used to do math
> +// with other enums, which is deprecated in C++20.
> +using VideoPlane = uint32_t;
> +constexpr VideoPlane kYPlane = 0;
> +constexpr VideoPlane kUPlane = 1;
> +constexpr VideoPlane kVPlane = 2;
> +constexpr VideoPlane kMaxPlanes = 3;
> +CHECK_TYPE(VideoPlane, 4, 4);
> +
> +class CDM_CLASS_API VideoFrame {
> + public:
> + virtual void SetFormat(VideoFormat format) = 0;
> + virtual VideoFormat Format() const = 0;
> +
> + virtual void SetSize(cdm::Size size) = 0;
> + virtual cdm::Size Size() const = 0;
> +
> + virtual void SetFrameBuffer(Buffer* frame_buffer) = 0;
> + virtual Buffer* FrameBuffer() = 0;
> +
> + virtual void SetPlaneOffset(VideoPlane plane, uint32_t offset) = 0;
> + virtual uint32_t PlaneOffset(VideoPlane plane) = 0;
> +
> + virtual void SetStride(VideoPlane plane, uint32_t stride) = 0;
> + virtual uint32_t Stride(VideoPlane plane) = 0;
> +
> + // Sets and gets the presentation timestamp which is in microseconds.
> + virtual void SetTimestamp(int64_t timestamp) = 0;
> + virtual int64_t Timestamp() const = 0;
> +
> + protected:
> + VideoFrame() {}
> + virtual ~VideoFrame() {}
> +};
> +
> +// Represents a decoded video frame. The CDM should call the interface methods
> +// to set the frame attributes. See DecryptAndDecodeFrame().
> +class CDM_CLASS_API VideoFrame_2 {
> + public:
> + virtual void SetFormat(VideoFormat format) = 0;
> + virtual void SetSize(cdm::Size size) = 0;
> + virtual void SetFrameBuffer(Buffer* frame_buffer) = 0;
> + virtual void SetPlaneOffset(VideoPlane plane, uint32_t offset) = 0;
> + virtual void SetStride(VideoPlane plane, uint32_t stride) = 0;
> + // Sets the presentation timestamp which is in microseconds.
> + virtual void SetTimestamp(int64_t timestamp) = 0;
> + virtual void SetColorSpace(ColorSpace color_space) = 0;
> +
> + protected:
> + VideoFrame_2() {}
> + virtual ~VideoFrame_2() {}
> +};
> +
> +// Represents decrypted and decoded audio frames. AudioFrames can contain
> +// multiple audio output buffers, which are serialized into this format:
> +//
> +// |<------------------- serialized audio buffer ------------------->|
> +// | int64_t timestamp | int64_t length | length bytes of audio data |
> +//
> +// For example, with three audio output buffers, the AudioFrames will look
> +// like this:
> +//
> +// |<----------------- AudioFrames ------------------>|
> +// | audio buffer 0 | audio buffer 1 | audio buffer 2 |
> +class CDM_CLASS_API AudioFrames {
> + public:
> + virtual void SetFrameBuffer(Buffer* buffer) = 0;
> + virtual Buffer* FrameBuffer() = 0;
> +
> + // The CDM must call this method, providing a valid format, when providing
> + // frame buffers. Planar data should be stored end to end; e.g.,
> + // |ch1 sample1||ch1 sample2|....|ch1 sample_last||ch2 sample1|...
> + virtual void SetFormat(AudioFormat format) = 0;
> + virtual AudioFormat Format() const = 0;
> +
> + protected:
> + AudioFrames() {}
> + virtual ~AudioFrames() {}
> +};
> +
> +// FileIO interface provides a way for the CDM to store data in a file in
> +// persistent storage. This interface aims only at providing basic read/write
> +// capabilities and should not be used as a full fledged file IO API.
> +// Each CDM and origin (e.g. HTTPS, "foo.example.com", 443) combination has
> +// its own persistent storage. All instances of a given CDM associated with a
> +// given origin share the same persistent storage.
> +// Note to implementors of this interface:
> +// Per-origin storage and the ability for users to clear it are important.
> +// See http://www.w3.org/TR/encrypted-media/#privacy-storedinfo.
> +class CDM_CLASS_API FileIO {
> + public:
> + // Opens the file with |file_name| for read and write.
> + // FileIOClient::OnOpenComplete() will be called after the opening
> + // operation finishes.
> + // - When the file is opened by a CDM instance, it will be classified as "in
> + // use". In this case other CDM instances in the same domain may receive
> + // kInUse status when trying to open it.
> + // - |file_name| must only contain letters (A-Za-z), digits(0-9), or "._-".
> + // It must not start with an underscore ('_'), and must be at least 1
> + // character and no more than 256 characters long.
> + virtual void Open(const char* file_name, uint32_t file_name_size) = 0;
> +
> + // Reads the contents of the file. FileIOClient::OnReadComplete() will be
> + // called with the read status. Read() should not be called if a previous
> + // Read() or Write() call is still pending; otherwise OnReadComplete() will
> + // be called with kInUse.
> + virtual void Read() = 0;
> +
> + // Writes |data_size| bytes of |data| into the file.
> + // FileIOClient::OnWriteComplete() will be called with the write status.
> + // All existing contents in the file will be overwritten. Calling Write() with
> + // NULL |data| will clear all contents in the file. Write() should not be
> + // called if a previous Write() or Read() call is still pending; otherwise
> + // OnWriteComplete() will be called with kInUse.
> + virtual void Write(const uint8_t* data, uint32_t data_size) = 0;
> +
> + // Closes the file if opened, destroys this FileIO object and releases any
> + // resources allocated. The CDM must call this method when it finished using
> + // this object. A FileIO object must not be used after Close() is called.
> + virtual void Close() = 0;
> +
> + protected:
> + FileIO() {}
> + virtual ~FileIO() {}
> +};
> +
> +// Responses to FileIO calls. All responses will be called asynchronously.
> +// When kError is returned, the FileIO object could be in an error state. All
> +// following calls (other than Close()) could return kError. The CDM should
> +// still call Close() to destroy the FileIO object.
> +class CDM_CLASS_API FileIOClient {
> + public:
> + enum class Status : uint32_t { kSuccess = 0, kInUse, kError };
> +
> + // Response to a FileIO::Open() call with the open |status|.
> + virtual void OnOpenComplete(Status status) = 0;
> +
> + // Response to a FileIO::Read() call to provide |data_size| bytes of |data|
> + // read from the file.
> + // - kSuccess indicates that all contents of the file has been successfully
> + // read. In this case, 0 |data_size| means that the file is empty.
> + // - kInUse indicates that there are other read/write operations pending.
> + // - kError indicates read failure, e.g. the storage is not open or cannot be
> + // fully read.
> + virtual void OnReadComplete(Status status,
> + const uint8_t* data,
> + uint32_t data_size) = 0;
> +
> + // Response to a FileIO::Write() call.
> + // - kSuccess indicates that all the data has been written into the file
> + // successfully.
> + // - kInUse indicates that there are other read/write operations pending.
> + // - kError indicates write failure, e.g. the storage is not open or cannot be
> + // fully written. Upon write failure, the contents of the file should be
> + // regarded as corrupt and should not used.
> + virtual void OnWriteComplete(Status status) = 0;
> +
> + protected:
> + FileIOClient() {}
> + virtual ~FileIOClient() {}
> +};
> +
> +// Metrics that will be reported from the CDM through the ReportMetrics()
> +// function. To add a new metric, please add it to the end of this enum list
> +// without changing any existing enum values.
> +// Note: For forward compatibility, Host implementations must gracefully handle
> +// unexpected (new) enum values, e.g. no-op.
> +enum MetricName : uint32_t {
> + kSdkVersion,
> + kCertificateSerialNumber,
> + kDecoderBypassBlockCount,
> +};
> +CHECK_TYPE(MetricName, 4, 4);
> +
> +class CDM_CLASS_API Host_10;
> +class CDM_CLASS_API Host_11;
> +class CDM_CLASS_API Host_12;
> +
> +// ContentDecryptionModule interface that all CDMs need to implement.
> +// The interface is versioned for backward compatibility.
> +// Note: ContentDecryptionModule implementations must use the allocator
> +// provided in CreateCdmInstance() to allocate any Buffer that needs to
> +// be passed back to the caller. Implementations must call Buffer::Destroy()
> +// when a Buffer is created that will never be returned to the caller.
> +class CDM_CLASS_API ContentDecryptionModule_10 {
> + public:
> + static const int kVersion = 10;
> + static const bool kIsStable = true;
> + typedef Host_10 Host;
> +
> + // Initializes the CDM instance, providing information about permitted
> + // functionalities. The CDM must respond by calling Host::OnInitialized()
> + // with whether the initialization succeeded. No other calls will be made by
> + // the host before Host::OnInitialized() returns.
> + // If |allow_distinctive_identifier| is false, messages from the CDM,
> + // such as message events, must not contain a Distinctive Identifier,
> + // even in an encrypted form.
> + // If |allow_persistent_state| is false, the CDM must not attempt to
> + // persist state. Calls to CreateFileIO() will fail.
> + // If |use_hw_secure_codecs| is true, the CDM must ensure the decryption key
> + // and video buffers (compressed and uncompressed) are securely protected by
> + // hardware.
> + virtual void Initialize(bool allow_distinctive_identifier,
> + bool allow_persistent_state,
> + bool use_hw_secure_codecs) = 0;
> +
> + // Gets the key status if the CDM has a hypothetical key with the |policy|.
> + // The CDM must respond by calling either Host::OnResolveKeyStatusPromise()
> + // with the result key status or Host::OnRejectPromise() if an unexpected
> + // error happened or this method is not supported.
> + virtual void GetStatusForPolicy(uint32_t promise_id,
> + const Policy& policy) = 0;
> +
> + // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(),
> + // UpdateSession(), CloseSession(), and RemoveSession() all accept a
> + // |promise_id|, which must be passed to the completion Host method
> + // (e.g. Host::OnResolveNewSessionPromise()).
> +
> + // Provides a server certificate to be used to encrypt messages to the
> + // license server. The CDM must respond by calling either
> + // Host::OnResolvePromise() or Host::OnRejectPromise().
> + // If the CDM does not support server certificates, the promise should be
> + // rejected with kExceptionNotSupportedError. If |server_certificate_data|
> + // is empty, reject with kExceptionTypeError. Any other error should be
> + // rejected with kExceptionInvalidStateError or kExceptionQuotaExceededError.
> + // TODO(crbug.com/796417): Add support for the promise to return true or
> + // false, rather than using kExceptionNotSupportedError to mean false.
> + virtual void SetServerCertificate(uint32_t promise_id,
> + const uint8_t* server_certificate_data,
> + uint32_t server_certificate_data_size) = 0;
> +
> + // Creates a session given |session_type|, |init_data_type|, and |init_data|.
> + // The CDM must respond by calling either Host::OnResolveNewSessionPromise()
> + // or Host::OnRejectPromise().
> + virtual void CreateSessionAndGenerateRequest(uint32_t promise_id,
> + SessionType session_type,
> + InitDataType init_data_type,
> + const uint8_t* init_data,
> + uint32_t init_data_size) = 0;
> +
> + // Loads the session of type |session_type| specified by |session_id|.
> + // The CDM must respond by calling either Host::OnResolveNewSessionPromise()
> + // or Host::OnRejectPromise(). If the session is not found, call
> + // Host::OnResolveNewSessionPromise() with session_id = NULL.
> + virtual void LoadSession(uint32_t promise_id,
> + SessionType session_type,
> + const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // Updates the session with |response|. The CDM must respond by calling
> + // either Host::OnResolvePromise() or Host::OnRejectPromise().
> + virtual void UpdateSession(uint32_t promise_id,
> + const char* session_id,
> + uint32_t session_id_size,
> + const uint8_t* response,
> + uint32_t response_size) = 0;
> +
> + // Requests that the CDM close the session. The CDM must respond by calling
> + // either Host::OnResolvePromise() or Host::OnRejectPromise() when the request
> + // has been processed. This may be before the session is closed. Once the
> + // session is closed, Host::OnSessionClosed() must also be called.
> + virtual void CloseSession(uint32_t promise_id,
> + const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // Removes any stored session data associated with this session. Will only be
> + // called for persistent sessions. The CDM must respond by calling either
> + // Host::OnResolvePromise() or Host::OnRejectPromise() when the request has
> + // been processed.
> + virtual void RemoveSession(uint32_t promise_id,
> + const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // Performs scheduled operation with |context| when the timer fires.
> + virtual void TimerExpired(void* context) = 0;
> +
> + // Decrypts the |encrypted_buffer|.
> //
> - // |<----- subsample1 ----->|<----- subsample2 ----->|<----- subsample3 ----->|
> - // | clear1 | decrypted1| clear2 | decrypted2 | clear3 | decrypted3 |
> + // Returns kSuccess if decryption succeeded, in which case the callee
> + // should have filled the |decrypted_buffer| and passed the ownership of
> + // |data| in |decrypted_buffer| to the caller.
> + // Returns kNoKey if the CDM did not have the necessary decryption key
> + // to decrypt.
> + // Returns kDecryptError if any other error happened.
> + // If the return value is not kSuccess, |decrypted_buffer| should be ignored
> + // by the caller.
> + virtual Status Decrypt(const InputBuffer_2& encrypted_buffer,
> + DecryptedBlock* decrypted_buffer) = 0;
> +
> + // Initializes the CDM audio decoder with |audio_decoder_config|. This
> + // function must be called before DecryptAndDecodeSamples() is called.
> //
> - struct SubsampleEntry {
> - uint32_t clear_bytes;
> - uint32_t cipher_bytes;
> - };
> - CHECK_TYPE(SubsampleEntry, 8, 8);
> -
> - // Represents an input buffer to be decrypted (and possibly decoded). It does
> - // not own any pointers in this struct. If |iv_size| = 0, the data is
> - // unencrypted.
> - // Deprecated: New CDM implementations should use InputBuffer_2.
> - struct InputBuffer_1 {
> - const uint8_t* data; // Pointer to the beginning of the input data.
> - uint32_t data_size; // Size (in bytes) of |data|.
> -
> - const uint8_t* key_id; // Key ID to identify the decryption key.
> - uint32_t key_id_size; // Size (in bytes) of |key_id|.
> -
> - const uint8_t* iv; // Initialization vector.
> - uint32_t iv_size; // Size (in bytes) of |iv|.
> -
> - const struct SubsampleEntry* subsamples;
> - uint32_t num_subsamples; // Number of subsamples in |subsamples|.
> -
> - int64_t timestamp; // Presentation timestamp in microseconds.
> - };
> - CHECK_TYPE(InputBuffer_1, 40, 72);
> -
> - // Represents an input buffer to be decrypted (and possibly decoded). It does
> - // not own any pointers in this struct. If |encryption_scheme| = kUnencrypted,
> - // the data is unencrypted.
> - // Note that this struct is organized so that sizeof(InputBuffer_2)
> - // equals the sum of sizeof() all members in both 32-bit and 64-bit compiles.
> - // Padding has been added to keep the fields aligned.
> - struct InputBuffer_2 {
> - const uint8_t* data; // Pointer to the beginning of the input data.
> - uint32_t data_size; // Size (in bytes) of |data|.
> -
> - EncryptionScheme encryption_scheme;
> -
> - const uint8_t* key_id; // Key ID to identify the decryption key.
> - uint32_t key_id_size; // Size (in bytes) of |key_id|.
> - uint32_t : 32; // Padding.
> -
> - const uint8_t* iv; // Initialization vector.
> - uint32_t iv_size; // Size (in bytes) of |iv|.
> - uint32_t : 32; // Padding.
> -
> - const struct SubsampleEntry* subsamples;
> - uint32_t num_subsamples; // Number of subsamples in |subsamples|.
> - uint32_t : 32; // Padding.
> -
> - // |pattern| is required if |encryption_scheme| specifies pattern encryption.
> - Pattern pattern;
> -
> - int64_t timestamp; // Presentation timestamp in microseconds.
> - };
> - CHECK_TYPE(InputBuffer_2, 64, 80);
> -
> - enum AudioCodec : uint32_t { kUnknownAudioCodec = 0, kCodecVorbis, kCodecAac };
> - CHECK_TYPE(AudioCodec, 4, 4);
> -
> - // Deprecated: New CDM implementations should use AudioDecoderConfig_2.
> - struct AudioDecoderConfig_1 {
> - AudioCodec codec;
> - int32_t channel_count;
> - int32_t bits_per_channel;
> - int32_t samples_per_second;
> -
> - // Optional byte data required to initialize audio decoders, such as the
> - // vorbis setup header.
> - uint8_t* extra_data;
> - uint32_t extra_data_size;
> - };
> - CHECK_TYPE(AudioDecoderConfig_1, 24, 32);
> -
> - struct AudioDecoderConfig_2 {
> - AudioCodec codec;
> - int32_t channel_count;
> - int32_t bits_per_channel;
> - int32_t samples_per_second;
> -
> - // Optional byte data required to initialize audio decoders, such as the
> - // vorbis setup header.
> - uint8_t* extra_data;
> - uint32_t extra_data_size;
> -
> - // Encryption scheme.
> - EncryptionScheme encryption_scheme;
> - };
> - CHECK_TYPE(AudioDecoderConfig_2, 28, 32);
> -
> - // Supported sample formats for AudioFrames.
> - enum AudioFormat : uint32_t {
> - kUnknownAudioFormat = 0, // Unknown format value. Used for error reporting.
> - kAudioFormatU8, // Interleaved unsigned 8-bit w/ bias of 128.
> - kAudioFormatS16, // Interleaved signed 16-bit.
> - kAudioFormatS32, // Interleaved signed 32-bit.
> - kAudioFormatF32, // Interleaved float 32-bit.
> - kAudioFormatPlanarS16, // Signed 16-bit planar.
> - kAudioFormatPlanarF32, // Float 32-bit planar.
> - };
> - CHECK_TYPE(AudioFormat, 4, 4);
> -
> - // Surface formats based on FOURCC labels, see: http://www.fourcc.org/yuv.php
> - // Values are chosen to be consistent with Chromium's VideoPixelFormat values.
> - enum VideoFormat : uint32_t {
> - kUnknownVideoFormat = 0, // Unknown format value. Used for error reporting.
> - kYv12 = 1, // 12bpp YVU planar 1x1 Y, 2x2 VU samples.
> - kI420 = 2, // 12bpp YUV planar 1x1 Y, 2x2 UV samples.
> -
> - // In the following formats, each sample uses 16-bit in storage, while the
> - // sample value is stored in the least significant N bits where N is
> - // specified by the number after "P". For example, for YUV420P9, each Y, U,
> - // and V sample is stored in the least significant 9 bits in a 2-byte block.
> - kYUV420P9 = 16,
> - kYUV420P10 = 17,
> - kYUV422P9 = 18,
> - kYUV422P10 = 19,
> - kYUV444P9 = 20,
> - kYUV444P10 = 21,
> - kYUV420P12 = 22,
> - kYUV422P12 = 23,
> - kYUV444P12 = 24,
> - };
> - CHECK_TYPE(VideoFormat, 4, 4);
> -
> - struct Size {
> - int32_t width;
> - int32_t height;
> - };
> - CHECK_TYPE(Size, 8, 8);
> -
> - enum VideoCodec : uint32_t {
> - kUnknownVideoCodec = 0,
> - kCodecVp8,
> - kCodecH264,
> - kCodecVp9,
> - kCodecAv1
> - };
> - CHECK_TYPE(VideoCodec, 4, 4);
> -
> - enum VideoCodecProfile : uint32_t {
> - kUnknownVideoCodecProfile = 0,
> - kProfileNotNeeded,
> - kH264ProfileBaseline,
> - kH264ProfileMain,
> - kH264ProfileExtended,
> - kH264ProfileHigh,
> - kH264ProfileHigh10,
> - kH264ProfileHigh422,
> - kH264ProfileHigh444Predictive,
> - // VP9 Profiles are only passed in starting from CDM_9.
> - kVP9Profile0,
> - kVP9Profile1,
> - kVP9Profile2,
> - kVP9Profile3,
> - kAv1ProfileMain,
> - kAv1ProfileHigh,
> - kAv1ProfilePro
> - };
> - CHECK_TYPE(VideoCodecProfile, 4, 4);
> -
> - // Deprecated: New CDM implementations should use VideoDecoderConfig_3.
> - struct VideoDecoderConfig_1 {
> - VideoCodec codec;
> - VideoCodecProfile profile;
> - VideoFormat format;
> -
> - // Width and height of video frame immediately post-decode. Not all pixels
> - // in this region are valid.
> - Size coded_size;
> -
> - // Optional byte data required to initialize video decoders, such as H.264
> - // AAVC data.
> - uint8_t* extra_data;
> - uint32_t extra_data_size;
> - };
> - CHECK_TYPE(VideoDecoderConfig_1, 28, 40);
> -
> - // Deprecated: New CDM implementations should use VideoDecoderConfig_3.
> - // Note that this struct is organized so that sizeof(VideoDecoderConfig_2)
> - // equals the sum of sizeof() all members in both 32-bit and 64-bit compiles.
> - // Padding has been added to keep the fields aligned.
> - struct VideoDecoderConfig_2 {
> - VideoCodec codec;
> - VideoCodecProfile profile;
> - VideoFormat format;
> - uint32_t : 32; // Padding.
> -
> - // Width and height of video frame immediately post-decode. Not all pixels
> - // in this region are valid.
> - Size coded_size;
> -
> - // Optional byte data required to initialize video decoders, such as H.264
> - // AAVC data.
> - uint8_t* extra_data;
> - uint32_t extra_data_size;
> -
> - // Encryption scheme.
> - EncryptionScheme encryption_scheme;
> - };
> - CHECK_TYPE(VideoDecoderConfig_2, 36, 40);
> -
> - struct VideoDecoderConfig_3 {
> - VideoCodec codec;
> - VideoCodecProfile profile;
> - VideoFormat format;
> - ColorSpace color_space;
> -
> - // Width and height of video frame immediately post-decode. Not all pixels
> - // in this region are valid.
> - Size coded_size;
> -
> - // Optional byte data required to initialize video decoders, such as H.264
> - // AAVC data.
> - uint8_t* extra_data;
> - uint32_t extra_data_size;
> -
> - EncryptionScheme encryption_scheme;
> - };
> - CHECK_TYPE(VideoDecoderConfig_3, 36, 40);
> -
> - enum StreamType : uint32_t { kStreamTypeAudio = 0, kStreamTypeVideo = 1 };
> - CHECK_TYPE(StreamType, 4, 4);
> -
> - // Structure provided to ContentDecryptionModule::OnPlatformChallengeResponse()
> - // after a platform challenge was initiated via Host::SendPlatformChallenge().
> - // All values will be NULL / zero in the event of a challenge failure.
> - struct PlatformChallengeResponse {
> - // |challenge| provided during Host::SendPlatformChallenge() combined with
> - // nonce data and signed with the platform's private key.
> - const uint8_t* signed_data;
> - uint32_t signed_data_length;
> -
> - // RSASSA-PKCS1-v1_5-SHA256 signature of the |signed_data| block.
> - const uint8_t* signed_data_signature;
> - uint32_t signed_data_signature_length;
> -
> - // X.509 device specific certificate for the |service_id| requested.
> - const uint8_t* platform_key_certificate;
> - uint32_t platform_key_certificate_length;
> - };
> - CHECK_TYPE(PlatformChallengeResponse, 24, 48);
> -
> - // The current status of the associated key. The valid types are defined in the
> - // spec: https://w3c.github.io/encrypted-media/#idl-def-MediaKeyStatus
> - enum KeyStatus : uint32_t {
> - kUsable = 0,
> - kInternalError = 1,
> - kExpired = 2,
> - kOutputRestricted = 3,
> - kOutputDownscaled = 4,
> - kStatusPending = 5,
> - kReleased = 6
> - };
> - CHECK_TYPE(KeyStatus, 4, 4);
> -
> - // Used when passing arrays of key information. Does not own the referenced
> - // data. |system_code| is an additional error code for unusable keys and
> - // should be 0 when |status| == kUsable.
> - struct KeyInformation {
> - const uint8_t* key_id;
> - uint32_t key_id_size;
> - KeyStatus status;
> - uint32_t system_code;
> - };
> - CHECK_TYPE(KeyInformation, 16, 24);
> -
> - // Supported output protection methods for use with EnableOutputProtection() and
> - // returned by OnQueryOutputProtectionStatus().
> - enum OutputProtectionMethods : uint32_t {
> - kProtectionNone = 0,
> - kProtectionHDCP = 1 << 0
> - };
> - CHECK_TYPE(OutputProtectionMethods, 4, 4);
> -
> - // Connected output link types returned by OnQueryOutputProtectionStatus().
> - enum OutputLinkTypes : uint32_t {
> - kLinkTypeNone = 0,
> - kLinkTypeUnknown = 1 << 0,
> - kLinkTypeInternal = 1 << 1,
> - kLinkTypeVGA = 1 << 2,
> - kLinkTypeHDMI = 1 << 3,
> - kLinkTypeDVI = 1 << 4,
> - kLinkTypeDisplayPort = 1 << 5,
> - kLinkTypeNetwork = 1 << 6
> - };
> - CHECK_TYPE(OutputLinkTypes, 4, 4);
> -
> - // Result of the QueryOutputProtectionStatus() call.
> - enum QueryResult : uint32_t { kQuerySucceeded = 0, kQueryFailed };
> - CHECK_TYPE(QueryResult, 4, 4);
> -
> - // The Initialization Data Type. The valid types are defined in the spec:
> - // https://w3c.github.io/encrypted-media/format-registry/initdata/index.html#registry
> - enum InitDataType : uint32_t { kCenc = 0, kKeyIds = 1, kWebM = 2 };
> - CHECK_TYPE(InitDataType, 4, 4);
> -
> - // The type of session to create. The valid types are defined in the spec:
> - // https://w3c.github.io/encrypted-media/#idl-def-SessionType
> - enum SessionType : uint32_t {
> - kTemporary = 0,
> - kPersistentLicense = 1,
> - kPersistentUsageRecord = 2
> - };
> - CHECK_TYPE(SessionType, 4, 4);
> -
> - // The type of the message event. The valid types are defined in the spec:
> - // https://w3c.github.io/encrypted-media/#idl-def-MediaKeyMessageType
> - enum MessageType : uint32_t {
> - kLicenseRequest = 0,
> - kLicenseRenewal = 1,
> - kLicenseRelease = 2,
> - // Only supported by Host_10 and later. On Host_9 and earlier, it's undefined
> - // behavior. For example, the host can drop the message or send it using
> - // other message type.
> - kIndividualizationRequest = 3
> - };
> - CHECK_TYPE(MessageType, 4, 4);
> -
> - enum HdcpVersion : uint32_t {
> - kHdcpVersionNone,
> - kHdcpVersion1_0,
> - kHdcpVersion1_1,
> - kHdcpVersion1_2,
> - kHdcpVersion1_3,
> - kHdcpVersion1_4,
> - kHdcpVersion2_0,
> - kHdcpVersion2_1,
> - kHdcpVersion2_2,
> - kHdcpVersion2_3
> - };
> - CHECK_TYPE(HdcpVersion, 4, 4);
> -
> - struct Policy {
> - HdcpVersion min_hdcp_version;
> - };
> - CHECK_TYPE(Policy, 4, 4);
> -
> - // Represents a buffer created by Allocator implementations.
> - class CDM_CLASS_API Buffer {
> - public:
> - // Destroys the buffer in the same context as it was created.
> - virtual void Destroy() = 0;
> -
> - virtual uint32_t Capacity() const = 0;
> - virtual uint8_t* Data() = 0;
> - virtual void SetSize(uint32_t size) = 0;
> - virtual uint32_t Size() const = 0;
> -
> - protected:
> - Buffer() {}
> - virtual ~Buffer() {}
> -
> - private:
> - Buffer(const Buffer&);
> - void operator=(const Buffer&);
> - };
> -
> - // Represents a decrypted block that has not been decoded.
> - class CDM_CLASS_API DecryptedBlock {
> - public:
> - virtual void SetDecryptedBuffer(Buffer* buffer) = 0;
> - virtual Buffer* DecryptedBuffer() = 0;
> -
> - // TODO(tomfinegan): Figure out if timestamp is really needed. If it is not,
> - // we can just pass Buffer pointers around.
> - virtual void SetTimestamp(int64_t timestamp) = 0;
> - virtual int64_t Timestamp() const = 0;
> -
> - protected:
> - DecryptedBlock() {}
> - virtual ~DecryptedBlock() {}
> - };
> -
> - enum VideoPlane : uint32_t {
> - kYPlane = 0,
> - kUPlane = 1,
> - kVPlane = 2,
> - kMaxPlanes = 3,
> - };
> - CHECK_TYPE(VideoPlane, 4, 4);
> -
> - class CDM_CLASS_API VideoFrame {
> - public:
> - virtual void SetFormat(VideoFormat format) = 0;
> - virtual VideoFormat Format() const = 0;
> -
> - virtual void SetSize(cdm::Size size) = 0;
> - virtual cdm::Size Size() const = 0;
> -
> - virtual void SetFrameBuffer(Buffer* frame_buffer) = 0;
> - virtual Buffer* FrameBuffer() = 0;
> -
> - virtual void SetPlaneOffset(VideoPlane plane, uint32_t offset) = 0;
> - virtual uint32_t PlaneOffset(VideoPlane plane) = 0;
> -
> - virtual void SetStride(VideoPlane plane, uint32_t stride) = 0;
> - virtual uint32_t Stride(VideoPlane plane) = 0;
> -
> - // Sets and gets the presentation timestamp which is in microseconds.
> - virtual void SetTimestamp(int64_t timestamp) = 0;
> - virtual int64_t Timestamp() const = 0;
> -
> - protected:
> - VideoFrame() {}
> - virtual ~VideoFrame() {}
> - };
> -
> - // Represents a decoded video frame. The CDM should call the interface methods
> - // to set the frame attributes. See DecryptAndDecodeFrame().
> - class CDM_CLASS_API VideoFrame_2 {
> - public:
> - virtual void SetFormat(VideoFormat format) = 0;
> - virtual void SetSize(cdm::Size size) = 0;
> - virtual void SetFrameBuffer(Buffer* frame_buffer) = 0;
> - virtual void SetPlaneOffset(VideoPlane plane, uint32_t offset) = 0;
> - virtual void SetStride(VideoPlane plane, uint32_t stride) = 0;
> - // Sets the presentation timestamp which is in microseconds.
> - virtual void SetTimestamp(int64_t timestamp) = 0;
> - virtual void SetColorSpace(ColorSpace color_space) = 0;
> -
> - protected:
> - VideoFrame_2() {}
> - virtual ~VideoFrame_2() {}
> - };
> + // Returns kSuccess if the |audio_decoder_config| is supported and the CDM
> + // audio decoder is successfully initialized.
> + // Returns kInitializationError if |audio_decoder_config| is not supported.
> + // The CDM may still be able to do Decrypt().
> + // Returns kDeferredInitialization if the CDM is not ready to initialize the
> + // decoder at this time. Must call Host::OnDeferredInitializationDone() once
> + // initialization is complete.
> + virtual Status InitializeAudioDecoder(
> + const AudioDecoderConfig_2& audio_decoder_config) = 0;
>
> - // Represents decrypted and decoded audio frames. AudioFrames can contain
> - // multiple audio output buffers, which are serialized into this format:
> + // Initializes the CDM video decoder with |video_decoder_config|. This
> + // function must be called before DecryptAndDecodeFrame() is called.
> //
> - // |<------------------- serialized audio buffer ------------------->|
> - // | int64_t timestamp | int64_t length | length bytes of audio data |
> + // Returns kSuccess if the |video_decoder_config| is supported and the CDM
> + // video decoder is successfully initialized.
> + // Returns kInitializationError if |video_decoder_config| is not supported.
> + // The CDM may still be able to do Decrypt().
> + // Returns kDeferredInitialization if the CDM is not ready to initialize the
> + // decoder at this time. Must call Host::OnDeferredInitializationDone() once
> + // initialization is complete.
> + virtual Status InitializeVideoDecoder(
> + const VideoDecoderConfig_2& video_decoder_config) = 0;
> +
> + // De-initializes the CDM decoder and sets it to an uninitialized state. The
> + // caller can initialize the decoder again after this call to re-initialize
> + // it. This can be used to reconfigure the decoder if the configuration
> + // changes.
> + virtual void DeinitializeDecoder(StreamType decoder_type) = 0;
> +
> + // Resets the CDM decoder to an initialized clean state. All internal buffers
> + // MUST be flushed.
> + virtual void ResetDecoder(StreamType decoder_type) = 0;
> +
> + // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into a
> + // |video_frame|. Upon end-of-stream, the caller should call this function
> + // repeatedly with empty |encrypted_buffer| (|data| == NULL) until
> + // kNeedMoreData is returned.
> //
> - // For example, with three audio output buffers, the AudioFrames will look
> - // like this:
> + // Returns kSuccess if decryption and decoding both succeeded, in which case
> + // the callee will have filled the |video_frame| and passed the ownership of
> + // |frame_buffer| in |video_frame| to the caller.
> + // Returns kNoKey if the CDM did not have the necessary decryption key
> + // to decrypt.
> + // Returns kNeedMoreData if more data was needed by the decoder to generate
> + // a decoded frame (e.g. during initialization and end-of-stream).
> + // Returns kDecryptError if any decryption error happened.
> + // Returns kDecodeError if any decoding error happened.
> + // If the return value is not kSuccess, |video_frame| should be ignored by
> + // the caller.
> + virtual Status DecryptAndDecodeFrame(const InputBuffer_2& encrypted_buffer,
> + VideoFrame* video_frame) = 0;
> +
> + // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into
> + // |audio_frames|. Upon end-of-stream, the caller should call this function
> + // repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty
> + // |audio_frames| is produced.
> //
> - // |<----------------- AudioFrames ------------------>|
> - // | audio buffer 0 | audio buffer 1 | audio buffer 2 |
> - class CDM_CLASS_API AudioFrames {
> - public:
> - virtual void SetFrameBuffer(Buffer* buffer) = 0;
> - virtual Buffer* FrameBuffer() = 0;
> -
> - // The CDM must call this method, providing a valid format, when providing
> - // frame buffers. Planar data should be stored end to end; e.g.,
> - // |ch1 sample1||ch1 sample2|....|ch1 sample_last||ch2 sample1|...
> - virtual void SetFormat(AudioFormat format) = 0;
> - virtual AudioFormat Format() const = 0;
> -
> - protected:
> - AudioFrames() {}
> - virtual ~AudioFrames() {}
> - };
> -
> - // FileIO interface provides a way for the CDM to store data in a file in
> - // persistent storage. This interface aims only at providing basic read/write
> - // capabilities and should not be used as a full fledged file IO API.
> - // Each CDM and origin (e.g. HTTPS, "foo.example.com", 443) combination has
> - // its own persistent storage. All instances of a given CDM associated with a
> - // given origin share the same persistent storage.
> - // Note to implementors of this interface:
> - // Per-origin storage and the ability for users to clear it are important.
> - // See http://www.w3.org/TR/encrypted-media/#privacy-storedinfo.
> - class CDM_CLASS_API FileIO {
> - public:
> - // Opens the file with |file_name| for read and write.
> - // FileIOClient::OnOpenComplete() will be called after the opening
> - // operation finishes.
> - // - When the file is opened by a CDM instance, it will be classified as "in
> - // use". In this case other CDM instances in the same domain may receive
> - // kInUse status when trying to open it.
> - // - |file_name| must only contain letters (A-Za-z), digits(0-9), or "._-".
> - // It must not start with an underscore ('_'), and must be at least 1
> - // character and no more than 256 characters long.
> - virtual void Open(const char* file_name, uint32_t file_name_size) = 0;
> -
> - // Reads the contents of the file. FileIOClient::OnReadComplete() will be
> - // called with the read status. Read() should not be called if a previous
> - // Read() or Write() call is still pending; otherwise OnReadComplete() will
> - // be called with kInUse.
> - virtual void Read() = 0;
> -
> - // Writes |data_size| bytes of |data| into the file.
> - // FileIOClient::OnWriteComplete() will be called with the write status.
> - // All existing contents in the file will be overwritten. Calling Write() with
> - // NULL |data| will clear all contents in the file. Write() should not be
> - // called if a previous Write() or Read() call is still pending; otherwise
> - // OnWriteComplete() will be called with kInUse.
> - virtual void Write(const uint8_t* data, uint32_t data_size) = 0;
> -
> - // Closes the file if opened, destroys this FileIO object and releases any
> - // resources allocated. The CDM must call this method when it finished using
> - // this object. A FileIO object must not be used after Close() is called.
> - virtual void Close() = 0;
> -
> - protected:
> - FileIO() {}
> - virtual ~FileIO() {}
> - };
> -
> - // Responses to FileIO calls. All responses will be called asynchronously.
> - // When kError is returned, the FileIO object could be in an error state. All
> - // following calls (other than Close()) could return kError. The CDM should
> - // still call Close() to destroy the FileIO object.
> - class CDM_CLASS_API FileIOClient {
> - public:
> - enum class Status : uint32_t { kSuccess = 0, kInUse, kError };
> -
> - // Response to a FileIO::Open() call with the open |status|.
> - virtual void OnOpenComplete(Status status) = 0;
> -
> - // Response to a FileIO::Read() call to provide |data_size| bytes of |data|
> - // read from the file.
> - // - kSuccess indicates that all contents of the file has been successfully
> - // read. In this case, 0 |data_size| means that the file is empty.
> - // - kInUse indicates that there are other read/write operations pending.
> - // - kError indicates read failure, e.g. the storage is not open or cannot be
> - // fully read.
> - virtual void OnReadComplete(Status status,
> - const uint8_t* data,
> - uint32_t data_size) = 0;
> -
> - // Response to a FileIO::Write() call.
> - // - kSuccess indicates that all the data has been written into the file
> - // successfully.
> - // - kInUse indicates that there are other read/write operations pending.
> - // - kError indicates write failure, e.g. the storage is not open or cannot be
> - // fully written. Upon write failure, the contents of the file should be
> - // regarded as corrupt and should not used.
> - virtual void OnWriteComplete(Status status) = 0;
> -
> - protected:
> - FileIOClient() {}
> - virtual ~FileIOClient() {}
> - };
> -
> - class CDM_CLASS_API Host_9;
> - class CDM_CLASS_API Host_10;
> - class CDM_CLASS_API Host_11;
> -
> - // ContentDecryptionModule interface that all CDMs need to implement.
> - // The interface is versioned for backward compatibility.
> - // Note: ContentDecryptionModule implementations must use the allocator
> - // provided in CreateCdmInstance() to allocate any Buffer that needs to
> - // be passed back to the caller. Implementations must call Buffer::Destroy()
> - // when a Buffer is created that will never be returned to the caller.
> - class CDM_CLASS_API ContentDecryptionModule_9 {
> - public:
> - static const int kVersion = 9;
> - typedef Host_9 Host;
> -
> - // Initializes the CDM instance, providing information about permitted
> - // functionalities.
> - // If |allow_distinctive_identifier| is false, messages from the CDM,
> - // such as message events, must not contain a Distinctive Identifier,
> - // even in an encrypted form.
> - // If |allow_persistent_state| is false, the CDM must not attempt to
> - // persist state. Calls to CreateFileIO() will fail.
> - virtual void Initialize(bool allow_distinctive_identifier,
> - bool allow_persistent_state) = 0;
> -
> - // Gets the key status if the CDM has a hypothetical key with the |policy|.
> - // The CDM must respond by calling either Host::OnResolveKeyStatusPromise()
> - // with the result key status or Host::OnRejectPromise() if an unexpected
> - // error happened or this method is not supported.
> - virtual void GetStatusForPolicy(uint32_t promise_id,
> - const Policy& policy) = 0;
> -
> - // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(),
> - // UpdateSession(), CloseSession(), and RemoveSession() all accept a
> - // |promise_id|, which must be passed to the completion Host method
> - // (e.g. Host::OnResolveNewSessionPromise()).
> -
> - // Provides a server certificate to be used to encrypt messages to the
> - // license server. The CDM must respond by calling either
> - // Host::OnResolvePromise() or Host::OnRejectPromise().
> - virtual void SetServerCertificate(uint32_t promise_id,
> - const uint8_t* server_certificate_data,
> - uint32_t server_certificate_data_size) = 0;
> -
> - // Creates a session given |session_type|, |init_data_type|, and |init_data|.
> - // The CDM must respond by calling either Host::OnResolveNewSessionPromise()
> - // or Host::OnRejectPromise().
> - virtual void CreateSessionAndGenerateRequest(uint32_t promise_id,
> - SessionType session_type,
> - InitDataType init_data_type,
> - const uint8_t* init_data,
> - uint32_t init_data_size) = 0;
> -
> - // Loads the session of type |session_type| specified by |session_id|.
> - // The CDM must respond by calling either Host::OnResolveNewSessionPromise()
> - // or Host::OnRejectPromise(). If the session is not found, call
> - // Host::OnResolveNewSessionPromise() with session_id = NULL.
> - virtual void LoadSession(uint32_t promise_id,
> - SessionType session_type,
> - const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // Updates the session with |response|. The CDM must respond by calling
> - // either Host::OnResolvePromise() or Host::OnRejectPromise().
> - virtual void UpdateSession(uint32_t promise_id,
> - const char* session_id,
> - uint32_t session_id_size,
> - const uint8_t* response,
> - uint32_t response_size) = 0;
> -
> - // Requests that the CDM close the session. The CDM must respond by calling
> - // either Host::OnResolvePromise() or Host::OnRejectPromise() when the request
> - // has been processed. This may be before the session is closed. Once the
> - // session is closed, Host::OnSessionClosed() must also be called.
> - virtual void CloseSession(uint32_t promise_id,
> - const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // Removes any stored session data associated with this session. Will only be
> - // called for persistent sessions. The CDM must respond by calling either
> - // Host::OnResolvePromise() or Host::OnRejectPromise() when the request has
> - // been processed.
> - virtual void RemoveSession(uint32_t promise_id,
> - const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // Performs scheduled operation with |context| when the timer fires.
> - virtual void TimerExpired(void* context) = 0;
> -
> - // Decrypts the |encrypted_buffer|.
> - //
> - // Returns kSuccess if decryption succeeded, in which case the callee
> - // should have filled the |decrypted_buffer| and passed the ownership of
> - // |data| in |decrypted_buffer| to the caller.
> - // Returns kNoKey if the CDM did not have the necessary decryption key
> - // to decrypt.
> - // Returns kDecryptError if any other error happened.
> - // If the return value is not kSuccess, |decrypted_buffer| should be ignored
> - // by the caller.
> - virtual Status Decrypt(const InputBuffer_1& encrypted_buffer,
> - DecryptedBlock* decrypted_buffer) = 0;
> -
> - // Initializes the CDM audio decoder with |audio_decoder_config|. This
> - // function must be called before DecryptAndDecodeSamples() is called.
> - //
> - // Returns kSuccess if the |audio_decoder_config| is supported and the CDM
> - // audio decoder is successfully initialized.
> - // Returns kInitializationError if |audio_decoder_config| is not supported.
> - // The CDM may still be able to do Decrypt().
> - // Returns kDeferredInitialization if the CDM is not ready to initialize the
> - // decoder at this time. Must call Host::OnDeferredInitializationDone() once
> - // initialization is complete.
> - virtual Status InitializeAudioDecoder(
> - const AudioDecoderConfig_1& audio_decoder_config) = 0;
> -
> - // Initializes the CDM video decoder with |video_decoder_config|. This
> - // function must be called before DecryptAndDecodeFrame() is called.
> - //
> - // Returns kSuccess if the |video_decoder_config| is supported and the CDM
> - // video decoder is successfully initialized.
> - // Returns kInitializationError if |video_decoder_config| is not supported.
> - // The CDM may still be able to do Decrypt().
> - // Returns kDeferredInitialization if the CDM is not ready to initialize the
> - // decoder at this time. Must call Host::OnDeferredInitializationDone() once
> - // initialization is complete.
> - virtual Status InitializeVideoDecoder(
> - const VideoDecoderConfig_1& video_decoder_config) = 0;
> -
> - // De-initializes the CDM decoder and sets it to an uninitialized state. The
> - // caller can initialize the decoder again after this call to re-initialize
> - // it. This can be used to reconfigure the decoder if the configuration
> - // changes.
> - virtual void DeinitializeDecoder(StreamType decoder_type) = 0;
> -
> - // Resets the CDM decoder to an initialized clean state. All internal buffers
> - // MUST be flushed.
> - virtual void ResetDecoder(StreamType decoder_type) = 0;
> -
> - // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into a
> - // |video_frame|. Upon end-of-stream, the caller should call this function
> - // repeatedly with empty |encrypted_buffer| (|data| == NULL) until
> - // kNeedMoreData is returned.
> - //
> - // Returns kSuccess if decryption and decoding both succeeded, in which case
> - // the callee will have filled the |video_frame| and passed the ownership of
> - // |frame_buffer| in |video_frame| to the caller.
> - // Returns kNoKey if the CDM did not have the necessary decryption key
> - // to decrypt.
> - // Returns kNeedMoreData if more data was needed by the decoder to generate
> - // a decoded frame (e.g. during initialization and end-of-stream).
> - // Returns kDecryptError if any decryption error happened.
> - // Returns kDecodeError if any decoding error happened.
> - // If the return value is not kSuccess, |video_frame| should be ignored by
> - // the caller.
> - virtual Status DecryptAndDecodeFrame(const InputBuffer_1& encrypted_buffer,
> - VideoFrame* video_frame) = 0;
> -
> - // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into
> - // |audio_frames|. Upon end-of-stream, the caller should call this function
> - // repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty
> - // |audio_frames| is produced.
> - //
> - // Returns kSuccess if decryption and decoding both succeeded, in which case
> - // the callee will have filled |audio_frames| and passed the ownership of
> - // |data| in |audio_frames| to the caller.
> - // Returns kNoKey if the CDM did not have the necessary decryption key
> - // to decrypt.
> - // Returns kNeedMoreData if more data was needed by the decoder to generate
> - // audio samples (e.g. during initialization and end-of-stream).
> - // Returns kDecryptError if any decryption error happened.
> - // Returns kDecodeError if any decoding error happened.
> - // If the return value is not kSuccess, |audio_frames| should be ignored by
> - // the caller.
> - virtual Status DecryptAndDecodeSamples(const InputBuffer_1& encrypted_buffer,
> - AudioFrames* audio_frames) = 0;
> -
> - // Called by the host after a platform challenge was initiated via
> - // Host::SendPlatformChallenge().
> - virtual void OnPlatformChallengeResponse(
> + // Returns kSuccess if decryption and decoding both succeeded, in which case
> + // the callee will have filled |audio_frames| and passed the ownership of
> + // |data| in |audio_frames| to the caller.
> + // Returns kNoKey if the CDM did not have the necessary decryption key
> + // to decrypt.
> + // Returns kNeedMoreData if more data was needed by the decoder to generate
> + // audio samples (e.g. during initialization and end-of-stream).
> + // Returns kDecryptError if any decryption error happened.
> + // Returns kDecodeError if any decoding error happened.
> + // If the return value is not kSuccess, |audio_frames| should be ignored by
> + // the caller.
> + virtual Status DecryptAndDecodeSamples(const InputBuffer_2& encrypted_buffer,
> + AudioFrames* audio_frames) = 0;
> +
> + // Called by the host after a platform challenge was initiated via
> + // Host::SendPlatformChallenge().
> + virtual void OnPlatformChallengeResponse(
> const PlatformChallengeResponse& response) = 0;
>
> - // Called by the host after a call to Host::QueryOutputProtectionStatus(). The
> - // |link_mask| is a bit mask of OutputLinkTypes and |output_protection_mask|
> - // is a bit mask of OutputProtectionMethods. If |result| is kQueryFailed,
> - // then |link_mask| and |output_protection_mask| are undefined and should
> - // be ignored.
> - virtual void OnQueryOutputProtectionStatus(
> + // Called by the host after a call to Host::QueryOutputProtectionStatus(). The
> + // |link_mask| is a bit mask of OutputLinkTypes and |output_protection_mask|
> + // is a bit mask of OutputProtectionMethods. If |result| is kQueryFailed,
> + // then |link_mask| and |output_protection_mask| are undefined and should
> + // be ignored.
> + virtual void OnQueryOutputProtectionStatus(
> QueryResult result,
> uint32_t link_mask,
> uint32_t output_protection_mask) = 0;
>
> - // Called by the host after a call to Host::RequestStorageId(). If the
> - // version of the storage ID requested is available, |storage_id| and
> - // |storage_id_size| are set appropriately. |version| will be the same as
> - // what was requested, unless 0 (latest) was requested, in which case
> - // |version| will be the actual version number for the |storage_id| returned.
> - // If the requested version is not available, null/zero will be provided as
> - // |storage_id| and |storage_id_size|, respectively, and |version| should be
> - // ignored.
> - virtual void OnStorageId(uint32_t version,
> - const uint8_t* storage_id,
> - uint32_t storage_id_size) = 0;
> -
> - // Destroys the object in the same context as it was created.
> - virtual void Destroy() = 0;
> -
> - protected:
> - ContentDecryptionModule_9() {}
> - virtual ~ContentDecryptionModule_9() {}
> - };
> -
> - // ContentDecryptionModule interface that all CDMs need to implement.
> - // The interface is versioned for backward compatibility.
> - // Note: ContentDecryptionModule implementations must use the allocator
> - // provided in CreateCdmInstance() to allocate any Buffer that needs to
> - // be passed back to the caller. Implementations must call Buffer::Destroy()
> - // when a Buffer is created that will never be returned to the caller.
> - class CDM_CLASS_API ContentDecryptionModule_10 {
> - public:
> - static const int kVersion = 10;
> - static const bool kIsStable = true;
> - typedef Host_10 Host;
> -
> - // Initializes the CDM instance, providing information about permitted
> - // functionalities. The CDM must respond by calling Host::OnInitialized()
> - // with whether the initialization succeeded. No other calls will be made by
> - // the host before Host::OnInitialized() returns.
> - // If |allow_distinctive_identifier| is false, messages from the CDM,
> - // such as message events, must not contain a Distinctive Identifier,
> - // even in an encrypted form.
> - // If |allow_persistent_state| is false, the CDM must not attempt to
> - // persist state. Calls to CreateFileIO() will fail.
> - // If |use_hw_secure_codecs| is true, the CDM must ensure the decryption key
> - // and video buffers (compressed and uncompressed) are securely protected by
> - // hardware.
> - virtual void Initialize(bool allow_distinctive_identifier,
> - bool allow_persistent_state,
> - bool use_hw_secure_codecs) = 0;
> -
> - // Gets the key status if the CDM has a hypothetical key with the |policy|.
> - // The CDM must respond by calling either Host::OnResolveKeyStatusPromise()
> - // with the result key status or Host::OnRejectPromise() if an unexpected
> - // error happened or this method is not supported.
> - virtual void GetStatusForPolicy(uint32_t promise_id,
> - const Policy& policy) = 0;
> -
> - // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(),
> - // UpdateSession(), CloseSession(), and RemoveSession() all accept a
> - // |promise_id|, which must be passed to the completion Host method
> - // (e.g. Host::OnResolveNewSessionPromise()).
> -
> - // Provides a server certificate to be used to encrypt messages to the
> - // license server. The CDM must respond by calling either
> - // Host::OnResolvePromise() or Host::OnRejectPromise().
> - // If the CDM does not support server certificates, the promise should be
> - // rejected with kExceptionNotSupportedError. If |server_certificate_data|
> - // is empty, reject with kExceptionTypeError. Any other error should be
> - // rejected with kExceptionInvalidStateError or kExceptionQuotaExceededError.
> - // TODO(crbug.com/796417): Add support for the promise to return true or
> - // false, rather than using kExceptionNotSupportedError to mean false.
> - virtual void SetServerCertificate(uint32_t promise_id,
> - const uint8_t* server_certificate_data,
> - uint32_t server_certificate_data_size) = 0;
> -
> - // Creates a session given |session_type|, |init_data_type|, and |init_data|.
> - // The CDM must respond by calling either Host::OnResolveNewSessionPromise()
> - // or Host::OnRejectPromise().
> - virtual void CreateSessionAndGenerateRequest(uint32_t promise_id,
> - SessionType session_type,
> - InitDataType init_data_type,
> - const uint8_t* init_data,
> - uint32_t init_data_size) = 0;
> -
> - // Loads the session of type |session_type| specified by |session_id|.
> - // The CDM must respond by calling either Host::OnResolveNewSessionPromise()
> - // or Host::OnRejectPromise(). If the session is not found, call
> - // Host::OnResolveNewSessionPromise() with session_id = NULL.
> - virtual void LoadSession(uint32_t promise_id,
> - SessionType session_type,
> - const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // Updates the session with |response|. The CDM must respond by calling
> - // either Host::OnResolvePromise() or Host::OnRejectPromise().
> - virtual void UpdateSession(uint32_t promise_id,
> - const char* session_id,
> - uint32_t session_id_size,
> - const uint8_t* response,
> - uint32_t response_size) = 0;
> -
> - // Requests that the CDM close the session. The CDM must respond by calling
> - // either Host::OnResolvePromise() or Host::OnRejectPromise() when the request
> - // has been processed. This may be before the session is closed. Once the
> - // session is closed, Host::OnSessionClosed() must also be called.
> - virtual void CloseSession(uint32_t promise_id,
> - const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // Removes any stored session data associated with this session. Will only be
> - // called for persistent sessions. The CDM must respond by calling either
> - // Host::OnResolvePromise() or Host::OnRejectPromise() when the request has
> - // been processed.
> - virtual void RemoveSession(uint32_t promise_id,
> - const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // Performs scheduled operation with |context| when the timer fires.
> - virtual void TimerExpired(void* context) = 0;
> -
> - // Decrypts the |encrypted_buffer|.
> - //
> - // Returns kSuccess if decryption succeeded, in which case the callee
> - // should have filled the |decrypted_buffer| and passed the ownership of
> - // |data| in |decrypted_buffer| to the caller.
> - // Returns kNoKey if the CDM did not have the necessary decryption key
> - // to decrypt.
> - // Returns kDecryptError if any other error happened.
> - // If the return value is not kSuccess, |decrypted_buffer| should be ignored
> - // by the caller.
> - virtual Status Decrypt(const InputBuffer_2& encrypted_buffer,
> - DecryptedBlock* decrypted_buffer) = 0;
> -
> - // Initializes the CDM audio decoder with |audio_decoder_config|. This
> - // function must be called before DecryptAndDecodeSamples() is called.
> - //
> - // Returns kSuccess if the |audio_decoder_config| is supported and the CDM
> - // audio decoder is successfully initialized.
> - // Returns kInitializationError if |audio_decoder_config| is not supported.
> - // The CDM may still be able to do Decrypt().
> - // Returns kDeferredInitialization if the CDM is not ready to initialize the
> - // decoder at this time. Must call Host::OnDeferredInitializationDone() once
> - // initialization is complete.
> - virtual Status InitializeAudioDecoder(
> + // Called by the host after a call to Host::RequestStorageId(). If the
> + // version of the storage ID requested is available, |storage_id| and
> + // |storage_id_size| are set appropriately. |version| will be the same as
> + // what was requested, unless 0 (latest) was requested, in which case
> + // |version| will be the actual version number for the |storage_id| returned.
> + // If the requested version is not available, null/zero will be provided as
> + // |storage_id| and |storage_id_size|, respectively, and |version| should be
> + // ignored.
> + virtual void OnStorageId(uint32_t version,
> + const uint8_t* storage_id,
> + uint32_t storage_id_size) = 0;
> +
> + // Destroys the object in the same context as it was created.
> + virtual void Destroy() = 0;
> +
> + protected:
> + ContentDecryptionModule_10() {}
> + virtual ~ContentDecryptionModule_10() {}
> +};
> +
> +// ContentDecryptionModule interface that all CDMs need to implement.
> +// The interface is versioned for backward compatibility.
> +// Note: ContentDecryptionModule implementations must use the allocator
> +// provided in CreateCdmInstance() to allocate any Buffer that needs to
> +// be passed back to the caller. Implementations must call Buffer::Destroy()
> +// when a Buffer is created that will never be returned to the caller.
> +class CDM_CLASS_API ContentDecryptionModule_11 {
> + public:
> + static const int kVersion = 11;
> + static const bool kIsStable = true;
> + typedef Host_11 Host;
> +
> + // Initializes the CDM instance, providing information about permitted
> + // functionalities. The CDM must respond by calling Host::OnInitialized()
> + // with whether the initialization succeeded. No other calls will be made by
> + // the host before Host::OnInitialized() returns.
> + // If |allow_distinctive_identifier| is false, messages from the CDM,
> + // such as message events, must not contain a Distinctive Identifier,
> + // even in an encrypted form.
> + // If |allow_persistent_state| is false, the CDM must not attempt to
> + // persist state. Calls to CreateFileIO() will fail.
> + // If |use_hw_secure_codecs| is true, the CDM must ensure the decryption key
> + // and video buffers (compressed and uncompressed) are securely protected by
> + // hardware.
> + virtual void Initialize(bool allow_distinctive_identifier,
> + bool allow_persistent_state,
> + bool use_hw_secure_codecs) = 0;
> +
> + // Gets the key status if the CDM has a hypothetical key with the |policy|.
> + // The CDM must respond by calling either Host::OnResolveKeyStatusPromise()
> + // with the result key status or Host::OnRejectPromise() if an unexpected
> + // error happened or this method is not supported.
> + virtual void GetStatusForPolicy(uint32_t promise_id,
> + const Policy& policy) = 0;
> +
> + // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(),
> + // UpdateSession(), CloseSession(), and RemoveSession() all accept a
> + // |promise_id|, which must be passed to the completion Host method
> + // (e.g. Host::OnResolveNewSessionPromise()).
> +
> + // Provides a server certificate to be used to encrypt messages to the
> + // license server. The CDM must respond by calling either
> + // Host::OnResolvePromise() or Host::OnRejectPromise().
> + // If the CDM does not support server certificates, the promise should be
> + // rejected with kExceptionNotSupportedError. If |server_certificate_data|
> + // is empty, reject with kExceptionTypeError. Any other error should be
> + // rejected with kExceptionInvalidStateError or kExceptionQuotaExceededError.
> + // TODO(crbug.com/796417): Add support for the promise to return true or
> + // false, rather than using kExceptionNotSupportedError to mean false.
> + virtual void SetServerCertificate(uint32_t promise_id,
> + const uint8_t* server_certificate_data,
> + uint32_t server_certificate_data_size) = 0;
> +
> + // Creates a session given |session_type|, |init_data_type|, and |init_data|.
> + // The CDM must respond by calling either Host::OnResolveNewSessionPromise()
> + // or Host::OnRejectPromise().
> + virtual void CreateSessionAndGenerateRequest(uint32_t promise_id,
> + SessionType session_type,
> + InitDataType init_data_type,
> + const uint8_t* init_data,
> + uint32_t init_data_size) = 0;
> +
> + // Loads the session of type |session_type| specified by |session_id|.
> + // The CDM must respond by calling either Host::OnResolveNewSessionPromise()
> + // or Host::OnRejectPromise(). If the session is not found, call
> + // Host::OnResolveNewSessionPromise() with session_id = NULL.
> + virtual void LoadSession(uint32_t promise_id,
> + SessionType session_type,
> + const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // Updates the session with |response|. The CDM must respond by calling
> + // either Host::OnResolvePromise() or Host::OnRejectPromise().
> + virtual void UpdateSession(uint32_t promise_id,
> + const char* session_id,
> + uint32_t session_id_size,
> + const uint8_t* response,
> + uint32_t response_size) = 0;
> +
> + // Requests that the CDM close the session. The CDM must respond by calling
> + // either Host::OnResolvePromise() or Host::OnRejectPromise() when the request
> + // has been processed. This may be before the session is closed. Once the
> + // session is closed, Host::OnSessionClosed() must also be called.
> + virtual void CloseSession(uint32_t promise_id,
> + const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // Removes any stored session data associated with this session. Will only be
> + // called for persistent sessions. The CDM must respond by calling either
> + // Host::OnResolvePromise() or Host::OnRejectPromise() when the request has
> + // been processed.
> + virtual void RemoveSession(uint32_t promise_id,
> + const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // Performs scheduled operation with |context| when the timer fires.
> + virtual void TimerExpired(void* context) = 0;
> +
> + // Decrypts the |encrypted_buffer|.
> + //
> + // Returns kSuccess if decryption succeeded, in which case the callee
> + // should have filled the |decrypted_buffer| and passed the ownership of
> + // |data| in |decrypted_buffer| to the caller.
> + // Returns kNoKey if the CDM did not have the necessary decryption key
> + // to decrypt.
> + // Returns kDecryptError if any other error happened.
> + // If the return value is not kSuccess, |decrypted_buffer| should be ignored
> + // by the caller.
> + virtual Status Decrypt(const InputBuffer_2& encrypted_buffer,
> + DecryptedBlock* decrypted_buffer) = 0;
> +
> + // Initializes the CDM audio decoder with |audio_decoder_config|. This
> + // function must be called before DecryptAndDecodeSamples() is called.
> + //
> + // Returns kSuccess if the |audio_decoder_config| is supported and the CDM
> + // audio decoder is successfully initialized.
> + // Returns kInitializationError if |audio_decoder_config| is not supported.
> + // The CDM may still be able to do Decrypt().
> + // Returns kDeferredInitialization if the CDM is not ready to initialize the
> + // decoder at this time. Must call Host::OnDeferredInitializationDone() once
> + // initialization is complete.
> + virtual Status InitializeAudioDecoder(
> const AudioDecoderConfig_2& audio_decoder_config) = 0;
>
> - // Initializes the CDM video decoder with |video_decoder_config|. This
> - // function must be called before DecryptAndDecodeFrame() is called.
> - //
> - // Returns kSuccess if the |video_decoder_config| is supported and the CDM
> - // video decoder is successfully initialized.
> - // Returns kInitializationError if |video_decoder_config| is not supported.
> - // The CDM may still be able to do Decrypt().
> - // Returns kDeferredInitialization if the CDM is not ready to initialize the
> - // decoder at this time. Must call Host::OnDeferredInitializationDone() once
> - // initialization is complete.
> - virtual Status InitializeVideoDecoder(
> + // Initializes the CDM video decoder with |video_decoder_config|. This
> + // function must be called before DecryptAndDecodeFrame() is called.
> + //
> + // Returns kSuccess if the |video_decoder_config| is supported and the CDM
> + // video decoder is successfully initialized.
> + // Returns kInitializationError if |video_decoder_config| is not supported.
> + // The CDM may still be able to do Decrypt().
> + // Returns kDeferredInitialization if the CDM is not ready to initialize the
> + // decoder at this time. Must call Host::OnDeferredInitializationDone() once
> + // initialization is complete.
> + virtual Status InitializeVideoDecoder(
> const VideoDecoderConfig_2& video_decoder_config) = 0;
>
> - // De-initializes the CDM decoder and sets it to an uninitialized state. The
> - // caller can initialize the decoder again after this call to re-initialize
> - // it. This can be used to reconfigure the decoder if the configuration
> - // changes.
> - virtual void DeinitializeDecoder(StreamType decoder_type) = 0;
> -
> - // Resets the CDM decoder to an initialized clean state. All internal buffers
> - // MUST be flushed.
> - virtual void ResetDecoder(StreamType decoder_type) = 0;
> -
> - // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into a
> - // |video_frame|. Upon end-of-stream, the caller should call this function
> - // repeatedly with empty |encrypted_buffer| (|data| == NULL) until
> - // kNeedMoreData is returned.
> - //
> - // Returns kSuccess if decryption and decoding both succeeded, in which case
> - // the callee will have filled the |video_frame| and passed the ownership of
> - // |frame_buffer| in |video_frame| to the caller.
> - // Returns kNoKey if the CDM did not have the necessary decryption key
> - // to decrypt.
> - // Returns kNeedMoreData if more data was needed by the decoder to generate
> - // a decoded frame (e.g. during initialization and end-of-stream).
> - // Returns kDecryptError if any decryption error happened.
> - // Returns kDecodeError if any decoding error happened.
> - // If the return value is not kSuccess, |video_frame| should be ignored by
> - // the caller.
> - virtual Status DecryptAndDecodeFrame(const InputBuffer_2& encrypted_buffer,
> - VideoFrame* video_frame) = 0;
> -
> - // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into
> - // |audio_frames|. Upon end-of-stream, the caller should call this function
> - // repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty
> - // |audio_frames| is produced.
> - //
> - // Returns kSuccess if decryption and decoding both succeeded, in which case
> - // the callee will have filled |audio_frames| and passed the ownership of
> - // |data| in |audio_frames| to the caller.
> - // Returns kNoKey if the CDM did not have the necessary decryption key
> - // to decrypt.
> - // Returns kNeedMoreData if more data was needed by the decoder to generate
> - // audio samples (e.g. during initialization and end-of-stream).
> - // Returns kDecryptError if any decryption error happened.
> - // Returns kDecodeError if any decoding error happened.
> - // If the return value is not kSuccess, |audio_frames| should be ignored by
> - // the caller.
> - virtual Status DecryptAndDecodeSamples(const InputBuffer_2& encrypted_buffer,
> - AudioFrames* audio_frames) = 0;
> -
> - // Called by the host after a platform challenge was initiated via
> - // Host::SendPlatformChallenge().
> - virtual void OnPlatformChallengeResponse(
> + // De-initializes the CDM decoder and sets it to an uninitialized state. The
> + // caller can initialize the decoder again after this call to re-initialize
> + // it. This can be used to reconfigure the decoder if the configuration
> + // changes.
> + virtual void DeinitializeDecoder(StreamType decoder_type) = 0;
> +
> + // Resets the CDM decoder to an initialized clean state. All internal buffers
> + // MUST be flushed.
> + virtual void ResetDecoder(StreamType decoder_type) = 0;
> +
> + // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into a
> + // |video_frame|. Upon end-of-stream, the caller should call this function
> + // repeatedly with empty |encrypted_buffer| (|data| == NULL) until
> + // kNeedMoreData is returned.
> + //
> + // Returns kSuccess if decryption and decoding both succeeded, in which case
> + // the callee will have filled the |video_frame| and passed the ownership of
> + // |frame_buffer| in |video_frame| to the caller.
> + // Returns kNoKey if the CDM did not have the necessary decryption key
> + // to decrypt.
> + // Returns kNeedMoreData if more data was needed by the decoder to generate
> + // a decoded frame (e.g. during initialization and end-of-stream).
> + // Returns kDecryptError if any decryption error happened.
> + // Returns kDecodeError if any decoding error happened.
> + // If the return value is not kSuccess, |video_frame| should be ignored by
> + // the caller.
> + virtual Status DecryptAndDecodeFrame(const InputBuffer_2& encrypted_buffer,
> + VideoFrame* video_frame) = 0;
> +
> + // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into
> + // |audio_frames|. Upon end-of-stream, the caller should call this function
> + // repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty
> + // |audio_frames| is produced.
> + //
> + // Returns kSuccess if decryption and decoding both succeeded, in which case
> + // the callee will have filled |audio_frames| and passed the ownership of
> + // |data| in |audio_frames| to the caller.
> + // Returns kNoKey if the CDM did not have the necessary decryption key
> + // to decrypt.
> + // Returns kNeedMoreData if more data was needed by the decoder to generate
> + // audio samples (e.g. during initialization and end-of-stream).
> + // Returns kDecryptError if any decryption error happened.
> + // Returns kDecodeError if any decoding error happened.
> + // If the return value is not kSuccess, |audio_frames| should be ignored by
> + // the caller.
> + virtual Status DecryptAndDecodeSamples(const InputBuffer_2& encrypted_buffer,
> + AudioFrames* audio_frames) = 0;
> +
> + // Called by the host after a platform challenge was initiated via
> + // Host::SendPlatformChallenge().
> + virtual void OnPlatformChallengeResponse(
> const PlatformChallengeResponse& response) = 0;
>
> - // Called by the host after a call to Host::QueryOutputProtectionStatus(). The
> - // |link_mask| is a bit mask of OutputLinkTypes and |output_protection_mask|
> - // is a bit mask of OutputProtectionMethods. If |result| is kQueryFailed,
> - // then |link_mask| and |output_protection_mask| are undefined and should
> - // be ignored.
> - virtual void OnQueryOutputProtectionStatus(
> + // Called by the host after a call to Host::QueryOutputProtectionStatus(). The
> + // |link_mask| is a bit mask of OutputLinkTypes and |output_protection_mask|
> + // is a bit mask of OutputProtectionMethods. If |result| is kQueryFailed,
> + // then |link_mask| and |output_protection_mask| are undefined and should
> + // be ignored.
> + virtual void OnQueryOutputProtectionStatus(
> QueryResult result,
> uint32_t link_mask,
> uint32_t output_protection_mask) = 0;
>
> - // Called by the host after a call to Host::RequestStorageId(). If the
> - // version of the storage ID requested is available, |storage_id| and
> - // |storage_id_size| are set appropriately. |version| will be the same as
> - // what was requested, unless 0 (latest) was requested, in which case
> - // |version| will be the actual version number for the |storage_id| returned.
> - // If the requested version is not available, null/zero will be provided as
> - // |storage_id| and |storage_id_size|, respectively, and |version| should be
> - // ignored.
> - virtual void OnStorageId(uint32_t version,
> - const uint8_t* storage_id,
> - uint32_t storage_id_size) = 0;
> -
> - // Destroys the object in the same context as it was created.
> - virtual void Destroy() = 0;
> -
> - protected:
> - ContentDecryptionModule_10() {}
> - virtual ~ContentDecryptionModule_10() {}
> - };
> -
> - // ----- Note: CDM interface(s) below still in development and not stable! -----
> -
> - // ContentDecryptionModule interface that all CDMs need to implement.
> - // The interface is versioned for backward compatibility.
> - // Note: ContentDecryptionModule implementations must use the allocator
> - // provided in CreateCdmInstance() to allocate any Buffer that needs to
> - // be passed back to the caller. Implementations must call Buffer::Destroy()
> - // when a Buffer is created that will never be returned to the caller.
> - class CDM_CLASS_API ContentDecryptionModule_11 {
> - public:
> - static const int kVersion = 11;
> - static const bool kIsStable = false;
> - typedef Host_11 Host;
> -
> - // Initializes the CDM instance, providing information about permitted
> - // functionalities. The CDM must respond by calling Host::OnInitialized()
> - // with whether the initialization succeeded. No other calls will be made by
> - // the host before Host::OnInitialized() returns.
> - // If |allow_distinctive_identifier| is false, messages from the CDM,
> - // such as message events, must not contain a Distinctive Identifier,
> - // even in an encrypted form.
> - // If |allow_persistent_state| is false, the CDM must not attempt to
> - // persist state. Calls to CreateFileIO() will fail.
> - // If |use_hw_secure_codecs| is true, the CDM must ensure the decryption key
> - // and video buffers (compressed and uncompressed) are securely protected by
> - // hardware.
> - virtual void Initialize(bool allow_distinctive_identifier,
> - bool allow_persistent_state,
> - bool use_hw_secure_codecs) = 0;
> -
> - // Gets the key status if the CDM has a hypothetical key with the |policy|.
> - // The CDM must respond by calling either Host::OnResolveKeyStatusPromise()
> - // with the result key status or Host::OnRejectPromise() if an unexpected
> - // error happened or this method is not supported.
> - virtual void GetStatusForPolicy(uint32_t promise_id,
> - const Policy& policy) = 0;
> -
> - // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(),
> - // UpdateSession(), CloseSession(), and RemoveSession() all accept a
> - // |promise_id|, which must be passed to the completion Host method
> - // (e.g. Host::OnResolveNewSessionPromise()).
> -
> - // Provides a server certificate to be used to encrypt messages to the
> - // license server. The CDM must respond by calling either
> - // Host::OnResolvePromise() or Host::OnRejectPromise().
> - // If the CDM does not support server certificates, the promise should be
> - // rejected with kExceptionNotSupportedError. If |server_certificate_data|
> - // is empty, reject with kExceptionTypeError. Any other error should be
> - // rejected with kExceptionInvalidStateError or kExceptionQuotaExceededError.
> - // TODO(crbug.com/796417): Add support for the promise to return true or
> - // false, rather than using kExceptionNotSupportedError to mean false.
> - virtual void SetServerCertificate(uint32_t promise_id,
> - const uint8_t* server_certificate_data,
> - uint32_t server_certificate_data_size) = 0;
> -
> - // Creates a session given |session_type|, |init_data_type|, and |init_data|.
> - // The CDM must respond by calling either Host::OnResolveNewSessionPromise()
> - // or Host::OnRejectPromise().
> - virtual void CreateSessionAndGenerateRequest(uint32_t promise_id,
> - SessionType session_type,
> - InitDataType init_data_type,
> - const uint8_t* init_data,
> - uint32_t init_data_size) = 0;
> -
> - // Loads the session of type |session_type| specified by |session_id|.
> - // The CDM must respond by calling either Host::OnResolveNewSessionPromise()
> - // or Host::OnRejectPromise(). If the session is not found, call
> - // Host::OnResolveNewSessionPromise() with session_id = NULL.
> - virtual void LoadSession(uint32_t promise_id,
> - SessionType session_type,
> - const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // Updates the session with |response|. The CDM must respond by calling
> - // either Host::OnResolvePromise() or Host::OnRejectPromise().
> - virtual void UpdateSession(uint32_t promise_id,
> - const char* session_id,
> - uint32_t session_id_size,
> - const uint8_t* response,
> - uint32_t response_size) = 0;
> -
> - // Requests that the CDM close the session. The CDM must respond by calling
> - // either Host::OnResolvePromise() or Host::OnRejectPromise() when the request
> - // has been processed. This may be before the session is closed. Once the
> - // session is closed, Host::OnSessionClosed() must also be called.
> - virtual void CloseSession(uint32_t promise_id,
> - const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // Removes any stored session data associated with this session. Removes all
> - // license(s) and key(s) associated with the session, whether they are in
> - // memory, persistent store, or both. For persistent session types, other
> - // session data (e.g. record of license destruction) will be cleared as
> - // defined for each session type once a release message acknowledgment is
> - // processed by UpdateSession(). The CDM must respond by calling either
> - // Host::OnResolvePromise() or Host::OnRejectPromise() when the request has
> - // been processed.
> - virtual void RemoveSession(uint32_t promise_id,
> - const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // Performs scheduled operation with |context| when the timer fires.
> - virtual void TimerExpired(void* context) = 0;
> -
> - // Decrypts the |encrypted_buffer|.
> - //
> - // Returns kSuccess if decryption succeeded, in which case the callee
> - // should have filled the |decrypted_buffer| and passed the ownership of
> - // |data| in |decrypted_buffer| to the caller.
> - // Returns kNoKey if the CDM did not have the necessary decryption key
> - // to decrypt.
> - // Returns kDecryptError if any other error happened.
> - // If the return value is not kSuccess, |decrypted_buffer| should be ignored
> - // by the caller.
> - virtual Status Decrypt(const InputBuffer_2& encrypted_buffer,
> - DecryptedBlock* decrypted_buffer) = 0;
> -
> - // Initializes the CDM audio decoder with |audio_decoder_config|. This
> - // function must be called before DecryptAndDecodeSamples() is called.
> - //
> - // Returns kSuccess if the |audio_decoder_config| is supported and the CDM
> - // audio decoder is successfully initialized.
> - // Returns kInitializationError if |audio_decoder_config| is not supported.
> - // The CDM may still be able to do Decrypt().
> - // Returns kDeferredInitialization if the CDM is not ready to initialize the
> - // decoder at this time. Must call Host::OnDeferredInitializationDone() once
> - // initialization is complete.
> - virtual Status InitializeAudioDecoder(
> + // Called by the host after a call to Host::RequestStorageId(). If the
> + // version of the storage ID requested is available, |storage_id| and
> + // |storage_id_size| are set appropriately. |version| will be the same as
> + // what was requested, unless 0 (latest) was requested, in which case
> + // |version| will be the actual version number for the |storage_id| returned.
> + // If the requested version is not available, null/zero will be provided as
> + // |storage_id| and |storage_id_size|, respectively, and |version| should be
> + // ignored.
> + virtual void OnStorageId(uint32_t version,
> + const uint8_t* storage_id,
> + uint32_t storage_id_size) = 0;
> +
> + // Destroys the object in the same context as it was created.
> + virtual void Destroy() = 0;
> +
> + protected:
> + ContentDecryptionModule_11() {}
> + virtual ~ContentDecryptionModule_11() {}
> +};
> +
> +// ----- Note: CDM interface(s) below still in development and not stable! -----
> +
> +// ContentDecryptionModule interface that all CDMs need to implement.
> +// The interface is versioned for backward compatibility.
> +// Note: ContentDecryptionModule implementations must use the allocator
> +// provided in CreateCdmInstance() to allocate any Buffer that needs to
> +// be passed back to the caller. Implementations must call Buffer::Destroy()
> +// when a Buffer is created that will never be returned to the caller.
> +class CDM_CLASS_API ContentDecryptionModule_12 {
> + public:
> + static const int kVersion = 12;
> + static const bool kIsStable = false;
> + typedef Host_12 Host;
> +
> + // Initializes the CDM instance, providing information about permitted
> + // functionalities. The CDM must respond by calling Host::OnInitialized()
> + // with whether the initialization succeeded. No other calls will be made by
> + // the host before Host::OnInitialized() returns.
> + // If |allow_distinctive_identifier| is false, messages from the CDM,
> + // such as message events, must not contain a Distinctive Identifier,
> + // even in an encrypted form.
> + // If |allow_persistent_state| is false, the CDM must not attempt to
> + // persist state. Calls to CreateFileIO() will fail.
> + // If |use_hw_secure_codecs| is true, the CDM must ensure the decryption key
> + // and video buffers (compressed and uncompressed) are securely protected by
> + // hardware.
> + virtual void Initialize(bool allow_distinctive_identifier,
> + bool allow_persistent_state,
> + bool use_hw_secure_codecs) = 0;
> +
> + // Gets the key status if the CDM has a hypothetical key with the |policy|.
> + // The CDM must respond by calling either Host::OnResolveKeyStatusPromise()
> + // with the result key status or Host::OnRejectPromise() if an unexpected
> + // error happened or this method is not supported.
> + virtual void GetStatusForPolicy(uint32_t promise_id,
> + const Policy& policy) = 0;
> +
> + // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(),
> + // UpdateSession(), CloseSession(), and RemoveSession() all accept a
> + // |promise_id|, which must be passed to the completion Host method
> + // (e.g. Host::OnResolveNewSessionPromise()).
> +
> + // Provides a server certificate to be used to encrypt messages to the
> + // license server. The CDM must respond by calling either
> + // Host::OnResolvePromise() or Host::OnRejectPromise().
> + // If the CDM does not support server certificates, the promise should be
> + // rejected with kExceptionNotSupportedError. If |server_certificate_data|
> + // is empty, reject with kExceptionTypeError. Any other error should be
> + // rejected with kExceptionInvalidStateError or kExceptionQuotaExceededError.
> + // TODO(crbug.com/796417): Add support for the promise to return true or
> + // false, rather than using kExceptionNotSupportedError to mean false.
> + virtual void SetServerCertificate(uint32_t promise_id,
> + const uint8_t* server_certificate_data,
> + uint32_t server_certificate_data_size) = 0;
> +
> + // Creates a session given |session_type|, |init_data_type|, and |init_data|.
> + // The CDM must respond by calling either Host::OnResolveNewSessionPromise()
> + // or Host::OnRejectPromise().
> + virtual void CreateSessionAndGenerateRequest(uint32_t promise_id,
> + SessionType session_type,
> + InitDataType init_data_type,
> + const uint8_t* init_data,
> + uint32_t init_data_size) = 0;
> +
> + // Loads the session of type |session_type| specified by |session_id|.
> + // The CDM must respond by calling either Host::OnResolveNewSessionPromise()
> + // or Host::OnRejectPromise(). If the session is not found, call
> + // Host::OnResolveNewSessionPromise() with session_id = NULL.
> + virtual void LoadSession(uint32_t promise_id,
> + SessionType session_type,
> + const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // Updates the session with |response|. The CDM must respond by calling
> + // either Host::OnResolvePromise() or Host::OnRejectPromise().
> + virtual void UpdateSession(uint32_t promise_id,
> + const char* session_id,
> + uint32_t session_id_size,
> + const uint8_t* response,
> + uint32_t response_size) = 0;
> +
> + // Requests that the CDM close the session. The CDM must respond by calling
> + // either Host::OnResolvePromise() or Host::OnRejectPromise() when the request
> + // has been processed. This may be before the session is closed. Once the
> + // session is closed, Host::OnSessionClosed() must also be called.
> + virtual void CloseSession(uint32_t promise_id,
> + const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // Removes any stored session data associated with this session. Removes all
> + // license(s) and key(s) associated with the session, whether they are in
> + // memory, persistent store, or both. For persistent session types, other
> + // session data (e.g. record of license destruction) will be cleared as
> + // defined for each session type once a release message acknowledgment is
> + // processed by UpdateSession(). The CDM must respond by calling either
> + // Host::OnResolvePromise() or Host::OnRejectPromise() when the request has
> + // been processed.
> + virtual void RemoveSession(uint32_t promise_id,
> + const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // Performs scheduled operation with |context| when the timer fires.
> + virtual void TimerExpired(void* context) = 0;
> +
> + // Decrypts the |encrypted_buffer|.
> + //
> + // Returns kSuccess if decryption succeeded, in which case the callee
> + // should have filled the |decrypted_buffer| and passed the ownership of
> + // |data| in |decrypted_buffer| to the caller.
> + // Returns kNoKey if the CDM did not have the necessary decryption key
> + // to decrypt.
> + // Returns kDecryptError if any other error happened.
> + // If the return value is not kSuccess, |decrypted_buffer| should be ignored
> + // by the caller.
> + virtual Status Decrypt(const InputBuffer_2& encrypted_buffer,
> + DecryptedBlock* decrypted_buffer) = 0;
> +
> + // Initializes the CDM audio decoder with |audio_decoder_config|. This
> + // function must be called before DecryptAndDecodeSamples() is called.
> + //
> + // Returns kSuccess if the |audio_decoder_config| is supported and the CDM
> + // audio decoder is successfully initialized.
> + // Returns kInitializationError if |audio_decoder_config| is not supported.
> + // The CDM may still be able to do Decrypt().
> + // Returns kDeferredInitialization if the CDM is not ready to initialize the
> + // decoder at this time. Must call Host::OnDeferredInitializationDone() once
> + // initialization is complete.
> + virtual Status InitializeAudioDecoder(
> const AudioDecoderConfig_2& audio_decoder_config) = 0;
>
> - // Initializes the CDM video decoder with |video_decoder_config|. This
> - // function must be called before DecryptAndDecodeFrame() is called.
> - //
> - // Returns kSuccess if the |video_decoder_config| is supported and the CDM
> - // video decoder is successfully initialized.
> - // Returns kInitializationError if |video_decoder_config| is not supported.
> - // The CDM may still be able to do Decrypt().
> - // Returns kDeferredInitialization if the CDM is not ready to initialize the
> - // decoder at this time. Must call Host::OnDeferredInitializationDone() once
> - // initialization is complete.
> - virtual Status InitializeVideoDecoder(
> + // Initializes the CDM video decoder with |video_decoder_config|. This
> + // function must be called before DecryptAndDecodeFrame() is called.
> + //
> + // Returns kSuccess if the |video_decoder_config| is supported and the CDM
> + // video decoder is successfully initialized.
> + // Returns kInitializationError if |video_decoder_config| is not supported.
> + // The CDM may still be able to do Decrypt().
> + // Returns kDeferredInitialization if the CDM is not ready to initialize the
> + // decoder at this time. Must call Host::OnDeferredInitializationDone() once
> + // initialization is complete.
> + virtual Status InitializeVideoDecoder(
> const VideoDecoderConfig_3& video_decoder_config) = 0;
>
> - // De-initializes the CDM decoder and sets it to an uninitialized state. The
> - // caller can initialize the decoder again after this call to re-initialize
> - // it. This can be used to reconfigure the decoder if the configuration
> - // changes.
> - virtual void DeinitializeDecoder(StreamType decoder_type) = 0;
> -
> - // Resets the CDM decoder to an initialized clean state. All internal buffers
> - // MUST be flushed.
> - virtual void ResetDecoder(StreamType decoder_type) = 0;
> -
> - // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into a
> - // |video_frame|. Upon end-of-stream, the caller should call this function
> - // repeatedly with empty |encrypted_buffer| (|data| == NULL) until
> - // kNeedMoreData is returned.
> - //
> - // Returns kSuccess if decryption and decoding both succeeded, in which case
> - // the callee will have filled the |video_frame| and passed the ownership of
> - // |frame_buffer| in |video_frame| to the caller.
> - // Returns kNoKey if the CDM did not have the necessary decryption key
> - // to decrypt.
> - // Returns kNeedMoreData if more data was needed by the decoder to generate
> - // a decoded frame (e.g. during initialization and end-of-stream).
> - // Returns kDecryptError if any decryption error happened.
> - // Returns kDecodeError if any decoding error happened.
> - // If the return value is not kSuccess, |video_frame| should be ignored by
> - // the caller.
> - virtual Status DecryptAndDecodeFrame(const InputBuffer_2& encrypted_buffer,
> - VideoFrame_2* video_frame) = 0;
> -
> - // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into
> - // |audio_frames|. Upon end-of-stream, the caller should call this function
> - // repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty
> - // |audio_frames| is produced.
> - //
> - // Returns kSuccess if decryption and decoding both succeeded, in which case
> - // the callee will have filled |audio_frames| and passed the ownership of
> - // |data| in |audio_frames| to the caller.
> - // Returns kNoKey if the CDM did not have the necessary decryption key
> - // to decrypt.
> - // Returns kNeedMoreData if more data was needed by the decoder to generate
> - // audio samples (e.g. during initialization and end-of-stream).
> - // Returns kDecryptError if any decryption error happened.
> - // Returns kDecodeError if any decoding error happened.
> - // If the return value is not kSuccess, |audio_frames| should be ignored by
> - // the caller.
> - virtual Status DecryptAndDecodeSamples(const InputBuffer_2& encrypted_buffer,
> - AudioFrames* audio_frames) = 0;
> -
> - // Called by the host after a platform challenge was initiated via
> - // Host::SendPlatformChallenge().
> - virtual void OnPlatformChallengeResponse(
> + // De-initializes the CDM decoder and sets it to an uninitialized state. The
> + // caller can initialize the decoder again after this call to re-initialize
> + // it. This can be used to reconfigure the decoder if the configuration
> + // changes.
> + virtual void DeinitializeDecoder(StreamType decoder_type) = 0;
> +
> + // Resets the CDM decoder to an initialized clean state. All internal buffers
> + // MUST be flushed.
> + virtual void ResetDecoder(StreamType decoder_type) = 0;
> +
> + // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into a
> + // |video_frame|. Upon end-of-stream, the caller should call this function
> + // repeatedly with empty |encrypted_buffer| (|data| == NULL) until
> + // kNeedMoreData is returned.
> + //
> + // Returns kSuccess if decryption and decoding both succeeded, in which case
> + // the callee will have filled the |video_frame| and passed the ownership of
> + // |frame_buffer| in |video_frame| to the caller.
> + // Returns kNoKey if the CDM did not have the necessary decryption key
> + // to decrypt.
> + // Returns kNeedMoreData if more data was needed by the decoder to generate
> + // a decoded frame (e.g. during initialization and end-of-stream).
> + // Returns kDecryptError if any decryption error happened.
> + // Returns kDecodeError if any decoding error happened.
> + // If the return value is not kSuccess, |video_frame| should be ignored by
> + // the caller.
> + virtual Status DecryptAndDecodeFrame(const InputBuffer_2& encrypted_buffer,
> + VideoFrame_2* video_frame) = 0;
> +
> + // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into
> + // |audio_frames|. Upon end-of-stream, the caller should call this function
> + // repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty
> + // |audio_frames| is produced.
> + //
> + // Returns kSuccess if decryption and decoding both succeeded, in which case
> + // the callee will have filled |audio_frames| and passed the ownership of
> + // |data| in |audio_frames| to the caller.
> + // Returns kNoKey if the CDM did not have the necessary decryption key
> + // to decrypt.
> + // Returns kNeedMoreData if more data was needed by the decoder to generate
> + // audio samples (e.g. during initialization and end-of-stream).
> + // Returns kDecryptError if any decryption error happened.
> + // Returns kDecodeError if any decoding error happened.
> + // If the return value is not kSuccess, |audio_frames| should be ignored by
> + // the caller.
> + virtual Status DecryptAndDecodeSamples(const InputBuffer_2& encrypted_buffer,
> + AudioFrames* audio_frames) = 0;
> +
> + // Called by the host after a platform challenge was initiated via
> + // Host::SendPlatformChallenge().
> + virtual void OnPlatformChallengeResponse(
> const PlatformChallengeResponse& response) = 0;
>
> - // Called by the host after a call to Host::QueryOutputProtectionStatus(). The
> - // |link_mask| is a bit mask of OutputLinkTypes and |output_protection_mask|
> - // is a bit mask of OutputProtectionMethods. If |result| is kQueryFailed,
> - // then |link_mask| and |output_protection_mask| are undefined and should
> - // be ignored.
> - virtual void OnQueryOutputProtectionStatus(
> + // Called by the host after a call to Host::QueryOutputProtectionStatus(). The
> + // |link_mask| is a bit mask of OutputLinkTypes and |output_protection_mask|
> + // is a bit mask of OutputProtectionMethods. If |result| is kQueryFailed,
> + // then |link_mask| and |output_protection_mask| are undefined and should
> + // be ignored.
> + virtual void OnQueryOutputProtectionStatus(
> QueryResult result,
> uint32_t link_mask,
> uint32_t output_protection_mask) = 0;
>
> - // Called by the host after a call to Host::RequestStorageId(). If the
> - // version of the storage ID requested is available, |storage_id| and
> - // |storage_id_size| are set appropriately. |version| will be the same as
> - // what was requested, unless 0 (latest) was requested, in which case
> - // |version| will be the actual version number for the |storage_id| returned.
> - // If the requested version is not available, null/zero will be provided as
> - // |storage_id| and |storage_id_size|, respectively, and |version| should be
> - // ignored.
> - virtual void OnStorageId(uint32_t version,
> - const uint8_t* storage_id,
> - uint32_t storage_id_size) = 0;
> -
> - // Destroys the object in the same context as it was created.
> - virtual void Destroy() = 0;
> -
> - protected:
> - ContentDecryptionModule_11() {}
> - virtual ~ContentDecryptionModule_11() {}
> - };
> -
> - class CDM_CLASS_API Host_9 {
> - public:
> - static const int kVersion = 9;
> -
> - // Returns a Buffer* containing non-zero members upon success, or NULL on
> - // failure. The caller owns the Buffer* after this call. The buffer is not
> - // guaranteed to be zero initialized. The capacity of the allocated Buffer
> - // is guaranteed to be not less than |capacity|.
> - virtual Buffer* Allocate(uint32_t capacity) = 0;
> -
> - // Requests the host to call ContentDecryptionModule::TimerFired() |delay_ms|
> - // from now with |context|.
> - virtual void SetTimer(int64_t delay_ms, void* context) = 0;
> -
> - // Returns the current wall time.
> - virtual Time GetCurrentWallTime() = 0;
> -
> - // Called by the CDM when a key status is available in response to
> - // GetStatusForPolicy().
> - virtual void OnResolveKeyStatusPromise(uint32_t promise_id,
> - KeyStatus key_status) = 0;
> -
> - // Called by the CDM when a session is created or loaded and the value for the
> - // MediaKeySession's sessionId attribute is available (|session_id|).
> - // This must be called before OnSessionMessage() or
> - // OnSessionKeysChange() is called for the same session. |session_id_size|
> - // should not include null termination.
> - // When called in response to LoadSession(), the |session_id| must be the
> - // same as the |session_id| passed in LoadSession(), or NULL if the
> - // session could not be loaded.
> - virtual void OnResolveNewSessionPromise(uint32_t promise_id,
> - const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // Called by the CDM when a session is updated or released.
> - virtual void OnResolvePromise(uint32_t promise_id) = 0;
> -
> - // Called by the CDM when an error occurs as a result of one of the
> - // ContentDecryptionModule calls that accept a |promise_id|.
> - // |exception| must be specified. |error_message| and |system_code|
> - // are optional. |error_message_size| should not include null termination.
> - virtual void OnRejectPromise(uint32_t promise_id,
> - Exception exception,
> - uint32_t system_code,
> - const char* error_message,
> - uint32_t error_message_size) = 0;
> -
> - // Called by the CDM when it has a message for session |session_id|.
> - // Size parameters should not include null termination.
> - virtual void OnSessionMessage(const char* session_id,
> - uint32_t session_id_size,
> - MessageType message_type,
> - const char* message,
> - uint32_t message_size) = 0;
> -
> - // Called by the CDM when there has been a change in keys or their status for
> - // session |session_id|. |has_additional_usable_key| should be set if a
> - // key is newly usable (e.g. new key available, previously expired key has
> - // been renewed, etc.) and the browser should attempt to resume playback.
> - // |keys_info| is the list of key IDs for this session along with their
> - // current status. |keys_info_count| is the number of entries in |keys_info|.
> - // Size parameter for |session_id| should not include null termination.
> - virtual void OnSessionKeysChange(const char* session_id,
> - uint32_t session_id_size,
> - bool has_additional_usable_key,
> - const KeyInformation* keys_info,
> - uint32_t keys_info_count) = 0;
> -
> - // Called by the CDM when there has been a change in the expiration time for
> - // session |session_id|. This can happen as the result of an Update() call
> - // or some other event. If this happens as a result of a call to Update(),
> - // it must be called before resolving the Update() promise. |new_expiry_time|
> - // represents the time after which the key(s) in the session will no longer
> - // be usable for decryption. It can be 0 if no such time exists or if the
> - // license explicitly never expires. Size parameter should not include null
> - // termination.
> - virtual void OnExpirationChange(const char* session_id,
> - uint32_t session_id_size,
> - Time new_expiry_time) = 0;
> -
> - // Called by the CDM when session |session_id| is closed. Size
> - // parameter should not include null termination.
> - virtual void OnSessionClosed(const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // The following are optional methods that may not be implemented on all
> - // platforms.
> -
> - // Sends a platform challenge for the given |service_id|. |challenge| is at
> - // most 256 bits of data to be signed. Once the challenge has been completed,
> - // the host will call ContentDecryptionModule::OnPlatformChallengeResponse()
> - // with the signed challenge response and platform certificate. Size
> - // parameters should not include null termination.
> - virtual void SendPlatformChallenge(const char* service_id,
> - uint32_t service_id_size,
> - const char* challenge,
> - uint32_t challenge_size) = 0;
> -
> - // Attempts to enable output protection (e.g. HDCP) on the display link. The
> - // |desired_protection_mask| is a bit mask of OutputProtectionMethods. No
> - // status callback is issued, the CDM must call QueryOutputProtectionStatus()
> - // periodically to ensure the desired protections are applied.
> - virtual void EnableOutputProtection(uint32_t desired_protection_mask) = 0;
> -
> - // Requests the current output protection status. Once the host has the status
> - // it will call ContentDecryptionModule::OnQueryOutputProtectionStatus().
> - virtual void QueryOutputProtectionStatus() = 0;
> -
> - // Must be called by the CDM if it returned kDeferredInitialization during
> - // InitializeAudioDecoder() or InitializeVideoDecoder().
> - virtual void OnDeferredInitializationDone(StreamType stream_type,
> - Status decoder_status) = 0;
> -
> - // Creates a FileIO object from the host to do file IO operation. Returns NULL
> - // if a FileIO object cannot be obtained. Once a valid FileIO object is
> - // returned, |client| must be valid until FileIO::Close() is called. The
> - // CDM can call this method multiple times to operate on different files.
> - virtual FileIO* CreateFileIO(FileIOClient* client) = 0;
> -
> - // Requests a specific version of the storage ID. A storage ID is a stable,
> - // device specific ID used by the CDM to securely store persistent data. The
> - // ID will be returned by the host via ContentDecryptionModule::OnStorageId().
> - // If |version| is 0, the latest version will be returned. All |version|s
> - // that are greater than or equal to 0x80000000 are reserved for the CDM and
> - // should not be supported or returned by the host. The CDM must not expose
> - // the ID outside the client device, even in encrypted form.
> - virtual void RequestStorageId(uint32_t version) = 0;
> -
> - protected:
> - Host_9() {}
> - virtual ~Host_9() {}
> - };
> -
> - class CDM_CLASS_API Host_10 {
> - public:
> - static const int kVersion = 10;
> -
> - // Returns a Buffer* containing non-zero members upon success, or NULL on
> - // failure. The caller owns the Buffer* after this call. The buffer is not
> - // guaranteed to be zero initialized. The capacity of the allocated Buffer
> - // is guaranteed to be not less than |capacity|.
> - virtual Buffer* Allocate(uint32_t capacity) = 0;
> -
> - // Requests the host to call ContentDecryptionModule::TimerFired() |delay_ms|
> - // from now with |context|.
> - virtual void SetTimer(int64_t delay_ms, void* context) = 0;
> -
> - // Returns the current wall time.
> - virtual Time GetCurrentWallTime() = 0;
> -
> - // Called by the CDM with the result after the CDM instance was initialized.
> - virtual void OnInitialized(bool success) = 0;
> -
> - // Called by the CDM when a key status is available in response to
> - // GetStatusForPolicy().
> - virtual void OnResolveKeyStatusPromise(uint32_t promise_id,
> - KeyStatus key_status) = 0;
> -
> - // Called by the CDM when a session is created or loaded and the value for the
> - // MediaKeySession's sessionId attribute is available (|session_id|).
> - // This must be called before OnSessionMessage() or
> - // OnSessionKeysChange() is called for the same session. |session_id_size|
> - // should not include null termination.
> - // When called in response to LoadSession(), the |session_id| must be the
> - // same as the |session_id| passed in LoadSession(), or NULL if the
> - // session could not be loaded.
> - virtual void OnResolveNewSessionPromise(uint32_t promise_id,
> - const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // Called by the CDM when a session is updated or released.
> - virtual void OnResolvePromise(uint32_t promise_id) = 0;
> -
> - // Called by the CDM when an error occurs as a result of one of the
> - // ContentDecryptionModule calls that accept a |promise_id|.
> - // |exception| must be specified. |error_message| and |system_code|
> - // are optional. |error_message_size| should not include null termination.
> - virtual void OnRejectPromise(uint32_t promise_id,
> - Exception exception,
> - uint32_t system_code,
> - const char* error_message,
> - uint32_t error_message_size) = 0;
> -
> - // Called by the CDM when it has a message for session |session_id|.
> - // Size parameters should not include null termination.
> - virtual void OnSessionMessage(const char* session_id,
> - uint32_t session_id_size,
> - MessageType message_type,
> - const char* message,
> - uint32_t message_size) = 0;
> -
> - // Called by the CDM when there has been a change in keys or their status for
> - // session |session_id|. |has_additional_usable_key| should be set if a
> - // key is newly usable (e.g. new key available, previously expired key has
> - // been renewed, etc.) and the browser should attempt to resume playback.
> - // |keys_info| is the list of key IDs for this session along with their
> - // current status. |keys_info_count| is the number of entries in |keys_info|.
> - // Size parameter for |session_id| should not include null termination.
> - virtual void OnSessionKeysChange(const char* session_id,
> - uint32_t session_id_size,
> - bool has_additional_usable_key,
> - const KeyInformation* keys_info,
> - uint32_t keys_info_count) = 0;
> -
> - // Called by the CDM when there has been a change in the expiration time for
> - // session |session_id|. This can happen as the result of an Update() call
> - // or some other event. If this happens as a result of a call to Update(),
> - // it must be called before resolving the Update() promise. |new_expiry_time|
> - // represents the time after which the key(s) in the session will no longer
> - // be usable for decryption. It can be 0 if no such time exists or if the
> - // license explicitly never expires. Size parameter should not include null
> - // termination.
> - virtual void OnExpirationChange(const char* session_id,
> - uint32_t session_id_size,
> - Time new_expiry_time) = 0;
> -
> - // Called by the CDM when session |session_id| is closed. Size
> - // parameter should not include null termination.
> - virtual void OnSessionClosed(const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // The following are optional methods that may not be implemented on all
> - // platforms.
> -
> - // Sends a platform challenge for the given |service_id|. |challenge| is at
> - // most 256 bits of data to be signed. Once the challenge has been completed,
> - // the host will call ContentDecryptionModule::OnPlatformChallengeResponse()
> - // with the signed challenge response and platform certificate. Size
> - // parameters should not include null termination.
> - virtual void SendPlatformChallenge(const char* service_id,
> - uint32_t service_id_size,
> - const char* challenge,
> - uint32_t challenge_size) = 0;
> -
> - // Attempts to enable output protection (e.g. HDCP) on the display link. The
> - // |desired_protection_mask| is a bit mask of OutputProtectionMethods. No
> - // status callback is issued, the CDM must call QueryOutputProtectionStatus()
> - // periodically to ensure the desired protections are applied.
> - virtual void EnableOutputProtection(uint32_t desired_protection_mask) = 0;
> -
> - // Requests the current output protection status. Once the host has the status
> - // it will call ContentDecryptionModule::OnQueryOutputProtectionStatus().
> - virtual void QueryOutputProtectionStatus() = 0;
> -
> - // Must be called by the CDM if it returned kDeferredInitialization during
> - // InitializeAudioDecoder() or InitializeVideoDecoder().
> - virtual void OnDeferredInitializationDone(StreamType stream_type,
> - Status decoder_status) = 0;
> -
> - // Creates a FileIO object from the host to do file IO operation. Returns NULL
> - // if a FileIO object cannot be obtained. Once a valid FileIO object is
> - // returned, |client| must be valid until FileIO::Close() is called. The
> - // CDM can call this method multiple times to operate on different files.
> - virtual FileIO* CreateFileIO(FileIOClient* client) = 0;
> -
> - // Requests a specific version of the storage ID. A storage ID is a stable,
> - // device specific ID used by the CDM to securely store persistent data. The
> - // ID will be returned by the host via ContentDecryptionModule::OnStorageId().
> - // If |version| is 0, the latest version will be returned. All |version|s
> - // that are greater than or equal to 0x80000000 are reserved for the CDM and
> - // should not be supported or returned by the host. The CDM must not expose
> - // the ID outside the client device, even in encrypted form.
> - virtual void RequestStorageId(uint32_t version) = 0;
> -
> - protected:
> - Host_10() {}
> - virtual ~Host_10() {}
> - };
> -
> - class CDM_CLASS_API Host_11 {
> - public:
> - static const int kVersion = 11;
> -
> - // Returns a Buffer* containing non-zero members upon success, or NULL on
> - // failure. The caller owns the Buffer* after this call. The buffer is not
> - // guaranteed to be zero initialized. The capacity of the allocated Buffer
> - // is guaranteed to be not less than |capacity|.
> - virtual Buffer* Allocate(uint32_t capacity) = 0;
> -
> - // Requests the host to call ContentDecryptionModule::TimerFired() |delay_ms|
> - // from now with |context|.
> - virtual void SetTimer(int64_t delay_ms, void* context) = 0;
> -
> - // Returns the current wall time.
> - virtual Time GetCurrentWallTime() = 0;
> -
> - // Called by the CDM with the result after the CDM instance was initialized.
> - virtual void OnInitialized(bool success) = 0;
> -
> - // Called by the CDM when a key status is available in response to
> - // GetStatusForPolicy().
> - virtual void OnResolveKeyStatusPromise(uint32_t promise_id,
> - KeyStatus key_status) = 0;
> -
> - // Called by the CDM when a session is created or loaded and the value for the
> - // MediaKeySession's sessionId attribute is available (|session_id|).
> - // This must be called before OnSessionMessage() or
> - // OnSessionKeysChange() is called for the same session. |session_id_size|
> - // should not include null termination.
> - // When called in response to LoadSession(), the |session_id| must be the
> - // same as the |session_id| passed in LoadSession(), or NULL if the
> - // session could not be loaded.
> - virtual void OnResolveNewSessionPromise(uint32_t promise_id,
> - const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // Called by the CDM when a session is updated or released.
> - virtual void OnResolvePromise(uint32_t promise_id) = 0;
> -
> - // Called by the CDM when an error occurs as a result of one of the
> - // ContentDecryptionModule calls that accept a |promise_id|.
> - // |exception| must be specified. |error_message| and |system_code|
> - // are optional. |error_message_size| should not include null termination.
> - virtual void OnRejectPromise(uint32_t promise_id,
> - Exception exception,
> - uint32_t system_code,
> - const char* error_message,
> - uint32_t error_message_size) = 0;
> -
> - // Called by the CDM when it has a message for session |session_id|.
> - // Size parameters should not include null termination.
> - virtual void OnSessionMessage(const char* session_id,
> - uint32_t session_id_size,
> - MessageType message_type,
> - const char* message,
> - uint32_t message_size) = 0;
> -
> - // Called by the CDM when there has been a change in keys or their status for
> - // session |session_id|. |has_additional_usable_key| should be set if a
> - // key is newly usable (e.g. new key available, previously expired key has
> - // been renewed, etc.) and the browser should attempt to resume playback.
> - // |keys_info| is the list of key IDs for this session along with their
> - // current status. |keys_info_count| is the number of entries in |keys_info|.
> - // Size parameter for |session_id| should not include null termination.
> - virtual void OnSessionKeysChange(const char* session_id,
> - uint32_t session_id_size,
> - bool has_additional_usable_key,
> - const KeyInformation* keys_info,
> - uint32_t keys_info_count) = 0;
> -
> - // Called by the CDM when there has been a change in the expiration time for
> - // session |session_id|. This can happen as the result of an Update() call
> - // or some other event. If this happens as a result of a call to Update(),
> - // it must be called before resolving the Update() promise. |new_expiry_time|
> - // represents the time after which the key(s) in the session will no longer
> - // be usable for decryption. It can be 0 if no such time exists or if the
> - // license explicitly never expires. Size parameter should not include null
> - // termination.
> - virtual void OnExpirationChange(const char* session_id,
> - uint32_t session_id_size,
> - Time new_expiry_time) = 0;
> -
> - // Called by the CDM when session |session_id| is closed. Size
> - // parameter should not include null termination.
> - virtual void OnSessionClosed(const char* session_id,
> - uint32_t session_id_size) = 0;
> -
> - // The following are optional methods that may not be implemented on all
> - // platforms.
> -
> - // Sends a platform challenge for the given |service_id|. |challenge| is at
> - // most 256 bits of data to be signed. Once the challenge has been completed,
> - // the host will call ContentDecryptionModule::OnPlatformChallengeResponse()
> - // with the signed challenge response and platform certificate. Size
> - // parameters should not include null termination.
> - virtual void SendPlatformChallenge(const char* service_id,
> - uint32_t service_id_size,
> - const char* challenge,
> - uint32_t challenge_size) = 0;
> -
> - // Attempts to enable output protection (e.g. HDCP) on the display link. The
> - // |desired_protection_mask| is a bit mask of OutputProtectionMethods. No
> - // status callback is issued, the CDM must call QueryOutputProtectionStatus()
> - // periodically to ensure the desired protections are applied.
> - virtual void EnableOutputProtection(uint32_t desired_protection_mask) = 0;
> -
> - // Requests the current output protection status. Once the host has the status
> - // it will call ContentDecryptionModule::OnQueryOutputProtectionStatus().
> - virtual void QueryOutputProtectionStatus() = 0;
> -
> - // Must be called by the CDM if it returned kDeferredInitialization during
> - // InitializeAudioDecoder() or InitializeVideoDecoder().
> - virtual void OnDeferredInitializationDone(StreamType stream_type,
> - Status decoder_status) = 0;
> -
> - // Creates a FileIO object from the host to do file IO operation. Returns NULL
> - // if a FileIO object cannot be obtained. Once a valid FileIO object is
> - // returned, |client| must be valid until FileIO::Close() is called. The
> - // CDM can call this method multiple times to operate on different files.
> - virtual FileIO* CreateFileIO(FileIOClient* client) = 0;
> -
> - // Requests a CdmProxy that proxies part of CDM functionalities to a different
> - // entity, e.g. a hardware CDM module. A CDM instance can have at most one
> - // CdmProxy throughout its lifetime, which must be requested and initialized
> - // during CDM instance initialization time, i.e. in or after CDM::Initialize()
> - // and before OnInitialized() is called, to ensure proper connection of the
> - // CdmProxy and the media player (e.g. hardware decoder). The CdmProxy is
> - // owned by the host and is guaranteed to be valid throughout the CDM
> - // instance's lifetime. The CDM must ensure that the |client| remain valid
> - // before the CDM instance is destroyed. Returns null if CdmProxy is not
> - // supported, called before CDM::Initialize(), RequestCdmProxy() is called
> - // more than once, or called after the CDM instance has been initialized.
> - virtual CdmProxy* RequestCdmProxy(CdmProxyClient* client) = 0;
> -
> - // Requests a specific version of the storage ID. A storage ID is a stable,
> - // device specific ID used by the CDM to securely store persistent data. The
> - // ID will be returned by the host via ContentDecryptionModule::OnStorageId().
> - // If |version| is 0, the latest version will be returned. All |version|s
> - // that are greater than or equal to 0x80000000 are reserved for the CDM and
> - // should not be supported or returned by the host. The CDM must not expose
> - // the ID outside the client device, even in encrypted form.
> - virtual void RequestStorageId(uint32_t version) = 0;
> -
> - protected:
> - Host_11() {}
> - virtual ~Host_11() {}
> - };
> + // Called by the host after a call to Host::RequestStorageId(). If the
> + // version of the storage ID requested is available, |storage_id| and
> + // |storage_id_size| are set appropriately. |version| will be the same as
> + // what was requested, unless 0 (latest) was requested, in which case
> + // |version| will be the actual version number for the |storage_id| returned.
> + // If the requested version is not available, null/zero will be provided as
> + // |storage_id| and |storage_id_size|, respectively, and |version| should be
> + // ignored.
> + virtual void OnStorageId(uint32_t version,
> + const uint8_t* storage_id,
> + uint32_t storage_id_size) = 0;
> +
> + // Destroys the object in the same context as it was created.
> + virtual void Destroy() = 0;
> +
> + protected:
> + ContentDecryptionModule_12() {}
> + virtual ~ContentDecryptionModule_12() {}
> +};
> +
> +class CDM_CLASS_API Host_10 {
> + public:
> + static const int kVersion = 10;
> +
> + // Returns a Buffer* containing non-zero members upon success, or NULL on
> + // failure. The caller owns the Buffer* after this call. The buffer is not
> + // guaranteed to be zero initialized. The capacity of the allocated Buffer
> + // is guaranteed to be not less than |capacity|.
> + virtual Buffer* Allocate(uint32_t capacity) = 0;
> +
> + // Requests the host to call ContentDecryptionModule::TimerFired() |delay_ms|
> + // from now with |context|.
> + virtual void SetTimer(int64_t delay_ms, void* context) = 0;
> +
> + // Returns the current wall time.
> + virtual Time GetCurrentWallTime() = 0;
> +
> + // Called by the CDM with the result after the CDM instance was initialized.
> + virtual void OnInitialized(bool success) = 0;
> +
> + // Called by the CDM when a key status is available in response to
> + // GetStatusForPolicy().
> + virtual void OnResolveKeyStatusPromise(uint32_t promise_id,
> + KeyStatus key_status) = 0;
> +
> + // Called by the CDM when a session is created or loaded and the value for the
> + // MediaKeySession's sessionId attribute is available (|session_id|).
> + // This must be called before OnSessionMessage() or
> + // OnSessionKeysChange() is called for the same session. |session_id_size|
> + // should not include null termination.
> + // When called in response to LoadSession(), the |session_id| must be the
> + // same as the |session_id| passed in LoadSession(), or NULL if the
> + // session could not be loaded.
> + virtual void OnResolveNewSessionPromise(uint32_t promise_id,
> + const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // Called by the CDM when a session is updated or released.
> + virtual void OnResolvePromise(uint32_t promise_id) = 0;
> +
> + // Called by the CDM when an error occurs as a result of one of the
> + // ContentDecryptionModule calls that accept a |promise_id|.
> + // |exception| must be specified. |error_message| and |system_code|
> + // are optional. |error_message_size| should not include null termination.
> + virtual void OnRejectPromise(uint32_t promise_id,
> + Exception exception,
> + uint32_t system_code,
> + const char* error_message,
> + uint32_t error_message_size) = 0;
> +
> + // Called by the CDM when it has a message for session |session_id|.
> + // Size parameters should not include null termination.
> + virtual void OnSessionMessage(const char* session_id,
> + uint32_t session_id_size,
> + MessageType message_type,
> + const char* message,
> + uint32_t message_size) = 0;
> +
> + // Called by the CDM when there has been a change in keys or their status for
> + // session |session_id|. |has_additional_usable_key| should be set if a
> + // key is newly usable (e.g. new key available, previously expired key has
> + // been renewed, etc.) and the browser should attempt to resume playback.
> + // |keys_info| is the list of key IDs for this session along with their
> + // current status. |keys_info_count| is the number of entries in |keys_info|.
> + // Size parameter for |session_id| should not include null termination.
> + virtual void OnSessionKeysChange(const char* session_id,
> + uint32_t session_id_size,
> + bool has_additional_usable_key,
> + const KeyInformation* keys_info,
> + uint32_t keys_info_count) = 0;
> +
> + // Called by the CDM when there has been a change in the expiration time for
> + // session |session_id|. This can happen as the result of an Update() call
> + // or some other event. If this happens as a result of a call to Update(),
> + // it must be called before resolving the Update() promise. |new_expiry_time|
> + // represents the time after which the key(s) in the session will no longer
> + // be usable for decryption. It can be 0 if no such time exists or if the
> + // license explicitly never expires. Size parameter should not include null
> + // termination.
> + virtual void OnExpirationChange(const char* session_id,
> + uint32_t session_id_size,
> + Time new_expiry_time) = 0;
> +
> + // Called by the CDM when session |session_id| is closed. Size
> + // parameter should not include null termination.
> + virtual void OnSessionClosed(const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // The following are optional methods that may not be implemented on all
> + // platforms.
> +
> + // Sends a platform challenge for the given |service_id|. |challenge| is at
> + // most 256 bits of data to be signed. Once the challenge has been completed,
> + // the host will call ContentDecryptionModule::OnPlatformChallengeResponse()
> + // with the signed challenge response and platform certificate. Size
> + // parameters should not include null termination.
> + virtual void SendPlatformChallenge(const char* service_id,
> + uint32_t service_id_size,
> + const char* challenge,
> + uint32_t challenge_size) = 0;
> +
> + // Attempts to enable output protection (e.g. HDCP) on the display link. The
> + // |desired_protection_mask| is a bit mask of OutputProtectionMethods. No
> + // status callback is issued, the CDM must call QueryOutputProtectionStatus()
> + // periodically to ensure the desired protections are applied.
> + virtual void EnableOutputProtection(uint32_t desired_protection_mask) = 0;
> +
> + // Requests the current output protection status. Once the host has the status
> + // it will call ContentDecryptionModule::OnQueryOutputProtectionStatus().
> + virtual void QueryOutputProtectionStatus() = 0;
> +
> + // Must be called by the CDM if it returned kDeferredInitialization during
> + // InitializeAudioDecoder() or InitializeVideoDecoder().
> + virtual void OnDeferredInitializationDone(StreamType stream_type,
> + Status decoder_status) = 0;
> +
> + // Creates a FileIO object from the host to do file IO operation. Returns NULL
> + // if a FileIO object cannot be obtained. Once a valid FileIO object is
> + // returned, |client| must be valid until FileIO::Close() is called. The
> + // CDM can call this method multiple times to operate on different files.
> + virtual FileIO* CreateFileIO(FileIOClient* client) = 0;
> +
> + // Requests a specific version of the storage ID. A storage ID is a stable,
> + // device specific ID used by the CDM to securely store persistent data. The
> + // ID will be returned by the host via ContentDecryptionModule::OnStorageId().
> + // If |version| is 0, the latest version will be returned. All |version|s
> + // that are greater than or equal to 0x80000000 are reserved for the CDM and
> + // should not be supported or returned by the host. The CDM must not expose
> + // the ID outside the client device, even in encrypted form.
> + virtual void RequestStorageId(uint32_t version) = 0;
> +
> + protected:
> + Host_10() {}
> + virtual ~Host_10() {}
> +};
> +
> +class CDM_CLASS_API Host_11 {
> + public:
> + static const int kVersion = 11;
> +
> + // Returns a Buffer* containing non-zero members upon success, or NULL on
> + // failure. The caller owns the Buffer* after this call. The buffer is not
> + // guaranteed to be zero initialized. The capacity of the allocated Buffer
> + // is guaranteed to be not less than |capacity|.
> + virtual Buffer* Allocate(uint32_t capacity) = 0;
> +
> + // Requests the host to call ContentDecryptionModule::TimerFired() |delay_ms|
> + // from now with |context|.
> + virtual void SetTimer(int64_t delay_ms, void* context) = 0;
> +
> + // Returns the current wall time.
> + virtual Time GetCurrentWallTime() = 0;
> +
> + // Called by the CDM with the result after the CDM instance was initialized.
> + virtual void OnInitialized(bool success) = 0;
> +
> + // Called by the CDM when a key status is available in response to
> + // GetStatusForPolicy().
> + virtual void OnResolveKeyStatusPromise(uint32_t promise_id,
> + KeyStatus key_status) = 0;
> +
> + // Called by the CDM when a session is created or loaded and the value for the
> + // MediaKeySession's sessionId attribute is available (|session_id|).
> + // This must be called before OnSessionMessage() or
> + // OnSessionKeysChange() is called for the same session. |session_id_size|
> + // should not include null termination.
> + // When called in response to LoadSession(), the |session_id| must be the
> + // same as the |session_id| passed in LoadSession(), or NULL if the
> + // session could not be loaded.
> + virtual void OnResolveNewSessionPromise(uint32_t promise_id,
> + const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // Called by the CDM when a session is updated or released.
> + virtual void OnResolvePromise(uint32_t promise_id) = 0;
> +
> + // Called by the CDM when an error occurs as a result of one of the
> + // ContentDecryptionModule calls that accept a |promise_id|.
> + // |exception| must be specified. |error_message| and |system_code|
> + // are optional. |error_message_size| should not include null termination.
> + virtual void OnRejectPromise(uint32_t promise_id,
> + Exception exception,
> + uint32_t system_code,
> + const char* error_message,
> + uint32_t error_message_size) = 0;
> +
> + // Called by the CDM when it has a message for session |session_id|.
> + // Size parameters should not include null termination.
> + virtual void OnSessionMessage(const char* session_id,
> + uint32_t session_id_size,
> + MessageType message_type,
> + const char* message,
> + uint32_t message_size) = 0;
> +
> + // Called by the CDM when there has been a change in keys or their status for
> + // session |session_id|. |has_additional_usable_key| should be set if a
> + // key is newly usable (e.g. new key available, previously expired key has
> + // been renewed, etc.) and the browser should attempt to resume playback.
> + // |keys_info| is the list of key IDs for this session along with their
> + // current status. |keys_info_count| is the number of entries in |keys_info|.
> + // Size parameter for |session_id| should not include null termination.
> + virtual void OnSessionKeysChange(const char* session_id,
> + uint32_t session_id_size,
> + bool has_additional_usable_key,
> + const KeyInformation* keys_info,
> + uint32_t keys_info_count) = 0;
> +
> + // Called by the CDM when there has been a change in the expiration time for
> + // session |session_id|. This can happen as the result of an Update() call
> + // or some other event. If this happens as a result of a call to Update(),
> + // it must be called before resolving the Update() promise. |new_expiry_time|
> + // represents the time after which the key(s) in the session will no longer
> + // be usable for decryption. It can be 0 if no such time exists or if the
> + // license explicitly never expires. Size parameter should not include null
> + // termination.
> + virtual void OnExpirationChange(const char* session_id,
> + uint32_t session_id_size,
> + Time new_expiry_time) = 0;
> +
> + // Called by the CDM when session |session_id| is closed. Size
> + // parameter should not include null termination.
> + virtual void OnSessionClosed(const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // The following are optional methods that may not be implemented on all
> + // platforms.
> +
> + // Sends a platform challenge for the given |service_id|. |challenge| is at
> + // most 256 bits of data to be signed. Once the challenge has been completed,
> + // the host will call ContentDecryptionModule::OnPlatformChallengeResponse()
> + // with the signed challenge response and platform certificate. Size
> + // parameters should not include null termination.
> + virtual void SendPlatformChallenge(const char* service_id,
> + uint32_t service_id_size,
> + const char* challenge,
> + uint32_t challenge_size) = 0;
> +
> + // Attempts to enable output protection (e.g. HDCP) on the display link. The
> + // |desired_protection_mask| is a bit mask of OutputProtectionMethods. No
> + // status callback is issued, the CDM must call QueryOutputProtectionStatus()
> + // periodically to ensure the desired protections are applied.
> + virtual void EnableOutputProtection(uint32_t desired_protection_mask) = 0;
> +
> + // Requests the current output protection status. Once the host has the status
> + // it will call ContentDecryptionModule::OnQueryOutputProtectionStatus().
> + virtual void QueryOutputProtectionStatus() = 0;
> +
> + // Must be called by the CDM if it returned kDeferredInitialization during
> + // InitializeAudioDecoder() or InitializeVideoDecoder().
> + virtual void OnDeferredInitializationDone(StreamType stream_type,
> + Status decoder_status) = 0;
> +
> + // Creates a FileIO object from the host to do file IO operation. Returns NULL
> + // if a FileIO object cannot be obtained. Once a valid FileIO object is
> + // returned, |client| must be valid until FileIO::Close() is called. The
> + // CDM can call this method multiple times to operate on different files.
> + virtual FileIO* CreateFileIO(FileIOClient* client) = 0;
> +
> + // Requests a specific version of the storage ID. A storage ID is a stable,
> + // device specific ID used by the CDM to securely store persistent data. The
> + // ID will be returned by the host via ContentDecryptionModule::OnStorageId().
> + // If |version| is 0, the latest version will be returned. All |version|s
> + // that are greater than or equal to 0x80000000 are reserved for the CDM and
> + // should not be supported or returned by the host. The CDM must not expose
> + // the ID outside the client device, even in encrypted form.
> + virtual void RequestStorageId(uint32_t version) = 0;
> +
> + // Reports the metric |metric_name| with value |value| to the host. Can be
> + // called by the CDM at any time. May report the same metric multiple times
> + // during the lifetime of the CDM.
> + virtual void ReportMetrics(MetricName metric_name, uint64_t value) = 0;
> +
> + protected:
> + Host_11() {}
> + virtual ~Host_11() {}
> +};
> +
> +class CDM_CLASS_API Host_12 {
> + public:
> + static const int kVersion = 12;
> +
> + // Returns a Buffer* containing non-zero members upon success, or NULL on
> + // failure. The caller owns the Buffer* after this call. The buffer is not
> + // guaranteed to be zero initialized. The capacity of the allocated Buffer
> + // is guaranteed to be not less than |capacity|.
> + virtual Buffer* Allocate(uint32_t capacity) = 0;
> +
> + // Requests the host to call ContentDecryptionModule::TimerFired() |delay_ms|
> + // from now with |context|.
> + virtual void SetTimer(int64_t delay_ms, void* context) = 0;
> +
> + // Returns the current wall time.
> + virtual Time GetCurrentWallTime() = 0;
> +
> + // Called by the CDM with the result after the CDM instance was initialized.
> + virtual void OnInitialized(bool success) = 0;
> +
> + // Called by the CDM when a key status is available in response to
> + // GetStatusForPolicy().
> + virtual void OnResolveKeyStatusPromise(uint32_t promise_id,
> + KeyStatus_2 key_status) = 0;
> +
> + // Called by the CDM when a session is created or loaded and the value for the
> + // MediaKeySession's sessionId attribute is available (|session_id|).
> + // This must be called before OnSessionMessage() or
> + // OnSessionKeysChange() is called for the same session. |session_id_size|
> + // should not include null termination.
> + // When called in response to LoadSession(), the |session_id| must be the
> + // same as the |session_id| passed in LoadSession(), or NULL if the
> + // session could not be loaded.
> + virtual void OnResolveNewSessionPromise(uint32_t promise_id,
> + const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // Called by the CDM when a session is updated or released.
> + virtual void OnResolvePromise(uint32_t promise_id) = 0;
> +
> + // Called by the CDM when an error occurs as a result of one of the
> + // ContentDecryptionModule calls that accept a |promise_id|.
> + // |exception| must be specified. |error_message| and |system_code|
> + // are optional. |error_message_size| should not include null termination.
> + virtual void OnRejectPromise(uint32_t promise_id,
> + Exception exception,
> + uint32_t system_code,
> + const char* error_message,
> + uint32_t error_message_size) = 0;
> +
> + // Called by the CDM when it has a message for session |session_id|.
> + // Size parameters should not include null termination.
> + virtual void OnSessionMessage(const char* session_id,
> + uint32_t session_id_size,
> + MessageType message_type,
> + const char* message,
> + uint32_t message_size) = 0;
> +
> + // Called by the CDM when there has been a change in keys or their status for
> + // session |session_id|. |has_additional_usable_key| should be set if a
> + // key is newly usable (e.g. new key available, previously expired key has
> + // been renewed, etc.) and the browser should attempt to resume playback.
> + // |keys_info| is the list of key IDs for this session along with their
> + // current status. |keys_info_count| is the number of entries in |keys_info|.
> + // Size parameter for |session_id| should not include null termination.
> + virtual void OnSessionKeysChange(const char* session_id,
> + uint32_t session_id_size,
> + bool has_additional_usable_key,
> + const KeyInformation_2* keys_info,
> + uint32_t keys_info_count) = 0;
> +
> + // Called by the CDM when there has been a change in the expiration time for
> + // session |session_id|. This can happen as the result of an Update() call
> + // or some other event. If this happens as a result of a call to Update(),
> + // it must be called before resolving the Update() promise. |new_expiry_time|
> + // represents the time after which the key(s) in the session will no longer
> + // be usable for decryption. It can be 0 if no such time exists or if the
> + // license explicitly never expires. Size parameter should not include null
> + // termination.
> + virtual void OnExpirationChange(const char* session_id,
> + uint32_t session_id_size,
> + Time new_expiry_time) = 0;
> +
> + // Called by the CDM when session |session_id| is closed. Size
> + // parameter should not include null termination.
> + virtual void OnSessionClosed(const char* session_id,
> + uint32_t session_id_size) = 0;
> +
> + // The following are optional methods that may not be implemented on all
> + // platforms.
> +
> + // Sends a platform challenge for the given |service_id|. |challenge| is at
> + // most 256 bits of data to be signed. Once the challenge has been completed,
> + // the host will call ContentDecryptionModule::OnPlatformChallengeResponse()
> + // with the signed challenge response and platform certificate. Size
> + // parameters should not include null termination.
> + virtual void SendPlatformChallenge(const char* service_id,
> + uint32_t service_id_size,
> + const char* challenge,
> + uint32_t challenge_size) = 0;
> +
> + // Attempts to enable output protection (e.g. HDCP) on the display link. The
> + // |desired_protection_mask| is a bit mask of OutputProtectionMethods. No
> + // status callback is issued, the CDM must call QueryOutputProtectionStatus()
> + // periodically to ensure the desired protections are applied.
> + virtual void EnableOutputProtection(uint32_t desired_protection_mask) = 0;
> +
> + // Requests the current output protection status. Once the host has the status
> + // it will call ContentDecryptionModule::OnQueryOutputProtectionStatus().
> + virtual void QueryOutputProtectionStatus() = 0;
> +
> + // Must be called by the CDM if it returned kDeferredInitialization during
> + // InitializeAudioDecoder() or InitializeVideoDecoder().
> + virtual void OnDeferredInitializationDone(StreamType stream_type,
> + Status decoder_status) = 0;
> +
> + // Creates a FileIO object from the host to do file IO operation. Returns NULL
> + // if a FileIO object cannot be obtained. Once a valid FileIO object is
> + // returned, |client| must be valid until FileIO::Close() is called. The
> + // CDM can call this method multiple times to operate on different files.
> + virtual FileIO* CreateFileIO(FileIOClient* client) = 0;
> +
> + // Requests a specific version of the storage ID. A storage ID is a stable,
> + // device specific ID used by the CDM to securely store persistent data. The
> + // ID will be returned by the host via ContentDecryptionModule::OnStorageId().
> + // If |version| is 0, the latest version will be returned. All |version|s
> + // that are greater than or equal to 0x80000000 are reserved for the CDM and
> + // should not be supported or returned by the host. The CDM must not expose
> + // the ID outside the client device, even in encrypted form.
> + virtual void RequestStorageId(uint32_t version) = 0;
> +
> + // Reports the metric |metric_name| with value |value| to the host. Can be
> + // called by the CDM at any time. May report the same metric multiple times
> + // during the lifetime of the CDM.
> + virtual void ReportMetrics(MetricName metric_name, uint64_t value) = 0;
> +
> + protected:
> + Host_12() {}
> + virtual ~Host_12() {}
> +};
>
> } // namespace cdm
>
> -#endif // CDM_CONTENT_DECRYPTION_MODULE_H_
> \ No newline at end of file
> +#endif // CDM_CONTENT_DECRYPTION_MODULE_H_
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/lib/cdm/cdm/media/cdm/api/content_decryption_module_proxy.h kodi-inputstream-adaptive-21.5.15+ds/lib/cdm/cdm/media/cdm/api/content_decryption_module_proxy.h
> --- kodi-inputstream-adaptive-21.5.9+ds/lib/cdm/cdm/media/cdm/api/content_decryption_module_proxy.h 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/lib/cdm/cdm/media/cdm/api/content_decryption_module_proxy.h 1970-01-01 00:00:00.000000000 +0000
> @@ -1,101 +0,0 @@
> -/*
> - * Copyright (C) 2017 The Chromium Authors. All rights reserved.
> - * This file is part of Kodi - https://kodi.tv
> - *
> - * SPDX-License-Identifier: BSD-3-Clause
> - * See LICENSES/README.md for more information.
> - */
> -
> -#ifndef CDM_CONTENT_DECRYPTION_MODULE_PROXY_H_
> -#define CDM_CONTENT_DECRYPTION_MODULE_PROXY_H_
> -#include "content_decryption_module_export.h"
> -#if defined(_MSC_VER)
> -typedef unsigned char uint8_t;
> -typedef unsigned int uint32_t;
> -typedef unsigned __int64 uint64_t;
> -#else
> -#include <stdint.h>
> -#endif
> -namespace cdm {
> -class CDM_CLASS_API CdmProxyClient;
> -// A proxy class for the CDM.
> -// In general, the interpretation of the CdmProxy and CdmProxyClient method
> -// parameters are protocol dependent. For enum parameters, values outside the
> -// enum range may not work.
> -class CDM_CLASS_API CdmProxy {
> - public:
> - enum Function : uint32_t {
> - // For Intel Negotiate Crypto SessionKey Exchange (CSME) path to call
> - // ID3D11VideoContext::NegotiateCryptoSessionKeyExchange.
> - kIntelNegotiateCryptoSessionKeyExchange = 1,
> - // There will be more values in the future e.g. for D3D11 RSA method.
> - };
> - // Initializes the proxy. The results will be returned in
> - // CdmProxyClient::OnInitialized().
> - virtual void Initialize() = 0;
> - // Processes and updates the state of the proxy.
> - // |output_data_size| is required by some protocol to set up the output data.
> - // The operation may fail if the |output_data_size| is wrong. The results will
> - // be returned in CdmProxyClient::OnProcessed().
> - virtual void Process(Function function,
> - uint32_t crypto_session_id,
> - const uint8_t* input_data,
> - uint32_t input_data_size,
> - uint32_t output_data_size) = 0;
> - // Creates a crypto session for handling media.
> - // If extra data has to be passed to further setup the media crypto session,
> - // pass the data as |input_data|. The results will be returned in
> - // CdmProxyClient::OnMediaCryptoSessionCreated().
> - virtual void CreateMediaCryptoSession(const uint8_t* input_data,
> - uint32_t input_data_size) = 0;
> - // Sets a key for the session identified by |crypto_session_id|.
> - virtual void SetKey(uint32_t crypto_session_id,
> - const uint8_t* key_id,
> - uint32_t key_id_size,
> - const uint8_t* key_blob,
> - uint32_t key_blob_size) = 0;
> - // Removes a key for the session identified by |crypto_session_id|.
> - virtual void RemoveKey(uint32_t crypto_session_id,
> - const uint8_t* key_id,
> - uint32_t key_id_size) = 0;
> - protected:
> - CdmProxy() {}
> - virtual ~CdmProxy() {}
> -};
> -// Responses to CdmProxy calls. All responses will be called asynchronously.
> -class CDM_CLASS_API CdmProxyClient {
> - public:
> - enum Status : uint32_t {
> - kOk,
> - kFail,
> - };
> - enum Protocol : uint32_t {
> - kNone = 0, // No protocol supported. Can be used in failure cases.
> - kIntelConvergedSecurityAndManageabilityEngine, // Method using Intel CSME.
> - // There will be more values in the future e.g. kD3D11RsaHardware,
> - // kD3D11RsaSoftware to use the D3D11 RSA method.
> - };
> - // Callback for Initialize(). If the proxy created a crypto session, then the
> - // ID for the crypto session is |crypto_session_id|.
> - virtual void OnInitialized(Status status,
> - Protocol protocol,
> - uint32_t crypto_session_id) = 0;
> - // Callback for Process(). |output_data| is the output of processing.
> - virtual void OnProcessed(Status status,
> - const uint8_t* output_data,
> - uint32_t output_data_size) = 0;
> - // Callback for CreateMediaCryptoSession(). On success:
> - // - |crypto_session_id| is the ID for the created crypto session.
> - // - |output_data| is extra value, if any.
> - // Otherwise, |crypto_session_id| and |output_data| should be ignored.
> - virtual void OnMediaCryptoSessionCreated(Status status,
> - uint32_t crypto_session_id,
> - uint64_t output_data) = 0;
> - // Called when there is a hardware reset and all the hardware context is lost.
> - virtual void NotifyHardwareReset() = 0;
> - protected:
> - CdmProxyClient() {}
> - virtual ~CdmProxyClient() {}
> -};
> -} // namespace cdm
> -#endif // CDM_CONTENT_DECRYPTION_MODULE_PROXY_H_
> \ No newline at end of file
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/lib/cdm/cdm/media/cdm/cdm_adapter.cc kodi-inputstream-adaptive-21.5.15+ds/lib/cdm/cdm/media/cdm/cdm_adapter.cc
> --- kodi-inputstream-adaptive-21.5.9+ds/lib/cdm/cdm/media/cdm/cdm_adapter.cc 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/lib/cdm/cdm/media/cdm/cdm_adapter.cc 2025-07-06 07:54:23.000000000 +0000
> @@ -8,11 +8,13 @@
>
> #include "cdm_adapter.h"
>
> -//! @todo: provide an appropriate interface for log output
> -#include "../../src/utils/log.h"
> +#include "../../debug.h"
> +#include "../base/limits.h"
>
> #include <chrono>
> +#include <cstring>
> #include <thread>
> +
> #include <sys/stat.h>
>
> #ifdef _WIN32
> @@ -21,8 +23,6 @@
>
> #define DCHECK(condition) assert(condition)
>
> -#include "../base/limits.h"
> -
> #ifdef __APPLE__
> #include <sys/time.h>
> //clock_gettime is not implemented on OSX
> @@ -39,6 +39,8 @@
> #endif
> #endif
>
> +using namespace CDM_DBG;
> +
> namespace media {
>
> uint64_t gtc()
> @@ -68,12 +70,12 @@
>
> switch (host_interface_version)
> {
> - case cdm::Host_9::kVersion:
> - return static_cast<cdm::Host_9*>(adapter);
> case cdm::Host_10::kVersion:
> return static_cast<cdm::Host_10*>(adapter);
> case cdm::Host_11::kVersion:
> return static_cast<cdm::Host_11*>(adapter);
> + case cdm::Host_12::kVersion:
> + return static_cast<cdm::Host_12*>(adapter);
> default:
> return nullptr;
> }
> @@ -147,22 +149,6 @@
>
> } // namespace
>
> -cdm::AudioDecoderConfig_1 ToAudioDecoderConfig_1(
> - const cdm::AudioDecoderConfig_2& config) {
> - return{ config.codec,
> - config.channel_count,
> - config.bits_per_channel,
> - config.samples_per_second,
> - config.extra_data,
> - config.extra_data_size };
> -}
> -
> -cdm::VideoDecoderConfig_1 ToVideoDecoderConfig_1(
> - const cdm::VideoDecoderConfig_3& config) {
> - return{ config.codec, config.profile, config.format,
> - config.coded_size, config.extra_data, config.extra_data_size };
> -}
> -
> cdm::VideoDecoderConfig_2 ToVideoDecoderConfig_2(
> const cdm::VideoDecoderConfig_3& config) {
> return{ config.codec,
> @@ -174,13 +160,6 @@
> config.encryption_scheme };
> }
>
> -cdm::InputBuffer_1 ToInputBuffer_1(const cdm::InputBuffer_2& buffer) {
> - return{ buffer.data, buffer.data_size,
> - buffer.key_id, buffer.key_id_size,
> - buffer.iv, buffer.iv_size,
> - buffer.subsamples, buffer.num_subsamples,
> - buffer.timestamp };
> -}
>
> /******************************* CdmAdapter ****************************************/
>
> @@ -198,7 +177,6 @@
> , key_system_(key_system)
> , cdm_config_(cdm_config)
> , active_buffer_(0)
> -, cdm9_(0), cdm10_(0), cdm11_(0)
> {
> //DCHECK(!key_system_.empty());
> Initialize();
> @@ -206,12 +184,12 @@
>
> CdmAdapter::~CdmAdapter()
> {
> - if (cdm9_)
> - cdm9_->Destroy(), cdm9_ = nullptr;
> - else if (cdm10_)
> - cdm10_->Destroy(), cdm10_ = nullptr;
> + if (cdm12_)
> + cdm12_->Destroy(), cdm12_ = nullptr;
> else if (cdm11_)
> cdm11_->Destroy(), cdm11_ = nullptr;
> + else if (cdm10_)
> + cdm10_->Destroy(), cdm10_ = nullptr;
> else
> return;
>
> @@ -223,14 +201,14 @@
> void CdmAdapter::Initialize()
> {
> m_isClosingSession = false;
> - if (cdm9_ || cdm10_ || cdm11_)
> + if (cdm12_ || cdm11_ || cdm10_)
> {
> - if (cdm9_)
> - cdm9_->Destroy(), cdm9_ = nullptr;
> - else if (cdm10_)
> - cdm10_->Destroy(), cdm10_ = nullptr;
> + if (cdm12_)
> + cdm12_->Destroy(), cdm12_ = nullptr;
> else if (cdm11_)
> cdm11_->Destroy(), cdm11_ = nullptr;
> + else if (cdm10_)
> + cdm10_->Destroy(), cdm10_ = nullptr;
> base::UnloadNativeLibrary(library_);
> library_ = 0;
> }
> @@ -240,8 +218,7 @@
>
> if (!library_)
> {
> - LOG::LogF(LOGERROR, "%s: Failed to load library: %s", __FUNCTION__,
> - error.ToString().c_str());
> + LogF(LogLevel::ERROR, "Failed to load library: %s", error.ToString().c_str());
> return;
> }
>
> @@ -258,7 +235,7 @@
> }
>
> std::string version{get_cdm_verion_func()};
> - LOG::LogF(LOGDEBUG, "CDM version: %s", version.c_str());
> + Log(LogLevel::DEBUG, "CDM version: %s", version.c_str());
>
> #if defined(OS_WIN)
> // Load DXVA before sandbox lockdown to give CDM access to Output Protection
> @@ -268,27 +245,32 @@
>
> init_cdm_func();
>
> - cdm11_ = static_cast<cdm::ContentDecryptionModule_11*>(create_cdm_func(11, key_system_.data(), key_system_.size(), GetCdmHost, this));
> + cdm12_ = static_cast<cdm::ContentDecryptionModule_12*>(create_cdm_func(
> + 12, key_system_.data(), static_cast<uint32_t>(key_system_.size()), GetCdmHost, this));
>
> - if (!cdm11_)
> + if (!cdm12_)
> {
> - cdm10_ = static_cast<cdm::ContentDecryptionModule_10*>(create_cdm_func(10, key_system_.data(), key_system_.size(), GetCdmHost, this));
> + cdm11_ = static_cast<cdm::ContentDecryptionModule_11*>(create_cdm_func(
> + 11, key_system_.data(), static_cast<uint32_t>(key_system_.size()), GetCdmHost, this));
>
> - if (!cdm10_)
> - cdm9_ = reinterpret_cast<cdm::ContentDecryptionModule_9*>(create_cdm_func(9, key_system_.data(), key_system_.size(), GetCdmHost, this));
> + if (!cdm11_)
> + {
> + cdm10_ = static_cast<cdm::ContentDecryptionModule_10*>(create_cdm_func(
> + 10, key_system_.data(), static_cast<uint32_t>(key_system_.size()), GetCdmHost, this));
> + }
> }
>
> - if (cdm9_ || cdm10_ || cdm11_)
> + if (cdm12_ || cdm11_ || cdm10_)
> {
> - if (cdm9_)
> - cdm9_->Initialize(cdm_config_.allow_distinctive_identifier,
> - cdm_config_.allow_persistent_state);
> - else if(cdm10_)
> - cdm10_->Initialize(cdm_config_.allow_distinctive_identifier,
> + if(cdm12_)
> + cdm12_->Initialize(cdm_config_.allow_distinctive_identifier,
> cdm_config_.allow_persistent_state, false);
> else if (cdm11_)
> cdm11_->Initialize(cdm_config_.allow_distinctive_identifier,
> cdm_config_.allow_persistent_state, false);
> + else if (cdm10_)
> + cdm10_->Initialize(cdm_config_.allow_distinctive_identifier,
> + cdm_config_.allow_persistent_state, false);
> }
> else
> {
> @@ -318,15 +300,15 @@
> server_certificate_data_size > limits::kMaxCertificateLength) {
> return;
> }
> - if (cdm9_)
> - cdm9_->SetServerCertificate(promise_id, server_certificate_data,
> - server_certificate_data_size);
> - else if (cdm10_)
> - cdm10_->SetServerCertificate(promise_id, server_certificate_data,
> +
> + if (cdm12_)
> + cdm12_->SetServerCertificate(promise_id, server_certificate_data,
> server_certificate_data_size);
> else if (cdm11_)
> cdm11_->SetServerCertificate(promise_id, server_certificate_data,
> server_certificate_data_size);
> + else if (cdm10_)
> + cdm10_->SetServerCertificate(promise_id, server_certificate_data, server_certificate_data_size);
> }
>
> void CdmAdapter::CreateSessionAndGenerateRequest(uint32_t promise_id,
> @@ -335,21 +317,15 @@
> const uint8_t* init_data,
> uint32_t init_data_size)
> {
> - if (cdm9_)
> - cdm9_->CreateSessionAndGenerateRequest(
> - promise_id, session_type,
> - init_data_type, init_data,
> - init_data_size);
> - else if (cdm10_)
> - cdm10_->CreateSessionAndGenerateRequest(
> - promise_id, session_type,
> - init_data_type, init_data,
> - init_data_size);
> - else if (cdm11_)
> - cdm11_->CreateSessionAndGenerateRequest(
> - promise_id, session_type,
> - init_data_type, init_data,
> - init_data_size);
> + if (cdm12_)
> + cdm12_->CreateSessionAndGenerateRequest(promise_id, session_type, init_data_type, init_data,
> + init_data_size);
> + else if (cdm11_)
> + cdm11_->CreateSessionAndGenerateRequest(promise_id, session_type, init_data_type, init_data,
> + init_data_size);
> + else if (cdm10_)
> + cdm10_->CreateSessionAndGenerateRequest(promise_id, session_type, init_data_type, init_data,
> + init_data_size);
> }
>
> void CdmAdapter::LoadSession(uint32_t promise_id,
> @@ -357,15 +333,12 @@
> const char* session_id,
> uint32_t session_id_size)
> {
> - if (cdm9_)
> - cdm9_->LoadSession(promise_id, session_type,
> - session_id, session_id_size);
> - else if (cdm10_)
> - cdm10_->LoadSession(promise_id, session_type,
> - session_id, session_id_size);
> + if (cdm12_)
> + cdm12_->LoadSession(promise_id, session_type, session_id, session_id_size);
> else if (cdm11_)
> - cdm11_->LoadSession(promise_id, session_type,
> - session_id, session_id_size);
> + cdm11_->LoadSession(promise_id, session_type, session_id, session_id_size);
> + else if (cdm10_)
> + cdm10_->LoadSession(promise_id, session_type, session_id, session_id_size);
> }
>
> void CdmAdapter::UpdateSession(uint32_t promise_id,
> @@ -374,15 +347,12 @@
> const uint8_t* response,
> uint32_t response_size)
> {
> - if (cdm9_)
> - cdm9_->UpdateSession(promise_id, session_id, session_id_size,
> - response, response_size);
> - else if(cdm10_)
> - cdm10_->UpdateSession(promise_id, session_id, session_id_size,
> - response, response_size);
> + if (cdm12_)
> + cdm12_->UpdateSession(promise_id, session_id, session_id_size, response, response_size);
> else if (cdm11_)
> - cdm11_->UpdateSession(promise_id, session_id, session_id_size,
> - response, response_size);
> + cdm11_->UpdateSession(promise_id, session_id, session_id_size, response, response_size);
> + else if (cdm10_)
> + cdm10_->UpdateSession(promise_id, session_id, session_id_size, response, response_size);
> }
>
> void CdmAdapter::CloseSession(uint32_t promise_id,
> @@ -394,12 +364,12 @@
> m_isClosingSession = true;
> }
> m_sessionClosingCond.notify_all();
> - if (cdm9_)
> - cdm9_->CloseSession(promise_id, session_id, session_id_size);
> - else if (cdm10_)
> - cdm10_->CloseSession(promise_id, session_id, session_id_size);
> + if (cdm12_)
> + cdm12_->CloseSession(promise_id, session_id, session_id_size);
> else if (cdm11_)
> cdm11_->CloseSession(promise_id, session_id, session_id_size);
> + else if (cdm10_)
> + cdm10_->CloseSession(promise_id, session_id, session_id_size);
> // remove any shared_ptr references left
> m_asyncTimerTasks.clear();
> }
> @@ -408,22 +378,22 @@
> const char* session_id,
> uint32_t session_id_size)
> {
> - if (cdm9_)
> - cdm9_->RemoveSession(promise_id, session_id, session_id_size);
> - else if (cdm10_)
> - cdm10_->RemoveSession(promise_id, session_id, session_id_size);
> + if (cdm12_)
> + cdm12_->RemoveSession(promise_id, session_id, session_id_size);
> else if (cdm11_)
> cdm11_->RemoveSession(promise_id, session_id, session_id_size);
> + else if (cdm10_)
> + cdm10_->RemoveSession(promise_id, session_id, session_id_size);
> }
>
> void CdmAdapter::TimerExpired(void* context)
> {
> - if (cdm9_)
> - cdm9_->TimerExpired(context);
> - else if (cdm10_)
> - cdm10_->TimerExpired(context);
> + if (cdm12_)
> + cdm12_->TimerExpired(context);
> else if (cdm11_)
> cdm11_->TimerExpired(context);
> + else if (cdm10_)
> + cdm10_->TimerExpired(context);
> }
>
> cdm::Status CdmAdapter::Decrypt(const cdm::InputBuffer_2& encrypted_buffer,
> @@ -438,15 +408,12 @@
> active_buffer_ = decrypted_buffer->DecryptedBuffer();
> cdm::Status ret;
>
> - if (cdm9_)
> - ret = cdm9_->Decrypt(ToInputBuffer_1(encrypted_buffer), decrypted_buffer);
> + if (cdm12_)
> + ret = cdm12_->Decrypt(encrypted_buffer, decrypted_buffer);
> + else if (cdm11_)
> + ret = cdm11_->Decrypt(encrypted_buffer, decrypted_buffer);
> else if (cdm10_)
> ret = cdm10_->Decrypt(encrypted_buffer, decrypted_buffer);
> - else if (cdm11_)
> - {
> - cdm::InputBuffer_2 tmp(encrypted_buffer);
> - ret = cdm11_->Decrypt(tmp, decrypted_buffer);
> - }
>
> active_buffer_ = 0;
> return ret;
> @@ -455,45 +422,47 @@
> cdm::Status CdmAdapter::InitializeAudioDecoder(
> const cdm::AudioDecoderConfig_2& audio_decoder_config)
> {
> - if (cdm9_)
> - return cdm9_->InitializeAudioDecoder(ToAudioDecoderConfig_1(audio_decoder_config));
> - else if (cdm10_)
> - return cdm10_->InitializeAudioDecoder(audio_decoder_config);
> + if (cdm12_)
> + return cdm12_->InitializeAudioDecoder(audio_decoder_config);
> else if (cdm11_)
> return cdm11_->InitializeAudioDecoder(audio_decoder_config);
> + else if (cdm10_)
> + return cdm10_->InitializeAudioDecoder(audio_decoder_config);
> +
> return cdm::kDeferredInitialization;
> }
>
> cdm::Status CdmAdapter::InitializeVideoDecoder(
> const cdm::VideoDecoderConfig_3& video_decoder_config)
> {
> - if (cdm9_)
> - return cdm9_->InitializeVideoDecoder(ToVideoDecoderConfig_1(video_decoder_config));
> + if (cdm12_)
> + return cdm12_->InitializeVideoDecoder(video_decoder_config);
> + else if (cdm11_)
> + return cdm11_->InitializeVideoDecoder(ToVideoDecoderConfig_2(video_decoder_config));
> else if (cdm10_)
> return cdm10_->InitializeVideoDecoder(ToVideoDecoderConfig_2(video_decoder_config));
> - else if (cdm11_)
> - return cdm11_->InitializeVideoDecoder(video_decoder_config);
> +
> return cdm::kDeferredInitialization;
> }
>
> void CdmAdapter::DeinitializeDecoder(cdm::StreamType decoder_type)
> {
> - if (cdm9_)
> - cdm9_->DeinitializeDecoder(decoder_type);
> - else if (cdm10_)
> - cdm10_->DeinitializeDecoder(decoder_type);
> + if (cdm12_)
> + cdm12_->DeinitializeDecoder(decoder_type);
> else if (cdm11_)
> cdm11_->DeinitializeDecoder(decoder_type);
> + else if (cdm10_)
> + cdm10_->DeinitializeDecoder(decoder_type);
> }
>
> void CdmAdapter::ResetDecoder(cdm::StreamType decoder_type)
> {
> - if (cdm9_)
> - cdm9_->ResetDecoder(decoder_type);
> - else if (cdm10_)
> - cdm10_->ResetDecoder(decoder_type);
> + if (cdm12_)
> + cdm12_->ResetDecoder(decoder_type);
> else if (cdm11_)
> cdm11_->ResetDecoder(decoder_type);
> + else if (cdm10_)
> + cdm10_->ResetDecoder(decoder_type);
> }
>
> cdm::Status CdmAdapter::DecryptAndDecodeFrame(const cdm::InputBuffer_2& encrypted_buffer,
> @@ -502,12 +471,12 @@
> std::lock_guard<std::mutex> lock(decrypt_mutex_);
> cdm::Status ret(cdm::kDeferredInitialization);
>
> - if (cdm9_)
> - ret = cdm9_->DecryptAndDecodeFrame(ToInputBuffer_1(encrypted_buffer), video_frame);
> - else if (cdm10_)
> - ret = cdm10_->DecryptAndDecodeFrame(encrypted_buffer, video_frame);
> + if (cdm12_)
> + ret = cdm12_->DecryptAndDecodeFrame(encrypted_buffer, video_frame);
> else if (cdm11_)
> ret = cdm11_->DecryptAndDecodeFrame(encrypted_buffer, video_frame);
> + else if (cdm10_)
> + ret = cdm10_->DecryptAndDecodeFrame(encrypted_buffer, video_frame);
>
> active_buffer_ = 0;
> return ret;
> @@ -517,39 +486,36 @@
> cdm::AudioFrames* audio_frames)
> {
> std::lock_guard<std::mutex> lock(decrypt_mutex_);
> - if (cdm9_)
> - return cdm9_->DecryptAndDecodeSamples(ToInputBuffer_1(encrypted_buffer), audio_frames);
> - else if (cdm10_)
> - return cdm10_->DecryptAndDecodeSamples(encrypted_buffer, audio_frames);
> + if (cdm12_)
> + return cdm12_->DecryptAndDecodeSamples(encrypted_buffer, audio_frames);
> else if (cdm11_)
> return cdm11_->DecryptAndDecodeSamples(encrypted_buffer, audio_frames);
> + else if (cdm10_)
> + return cdm10_->DecryptAndDecodeSamples(encrypted_buffer, audio_frames);
> return cdm::kDeferredInitialization;
> }
>
> void CdmAdapter::OnPlatformChallengeResponse(
> const cdm::PlatformChallengeResponse& response)
> {
> - if (cdm9_)
> - cdm9_->OnPlatformChallengeResponse(response);
> - else if (cdm10_)
> - cdm10_->OnPlatformChallengeResponse(response);
> + if (cdm12_)
> + cdm12_->OnPlatformChallengeResponse(response);
> else if (cdm11_)
> cdm11_->OnPlatformChallengeResponse(response);
> + else if (cdm10_)
> + cdm10_->OnPlatformChallengeResponse(response);
> }
>
> void CdmAdapter::OnQueryOutputProtectionStatus(cdm::QueryResult result,
> uint32_t link_mask,
> uint32_t output_protection_mask)
> {
> - if (cdm9_)
> - cdm9_->OnQueryOutputProtectionStatus(result, link_mask,
> - output_protection_mask);
> - else if (cdm10_)
> - cdm10_->OnQueryOutputProtectionStatus(result, link_mask,
> - output_protection_mask);
> + if (cdm12_)
> + cdm12_->OnQueryOutputProtectionStatus(result, link_mask, output_protection_mask);
> else if (cdm11_)
> - cdm11_->OnQueryOutputProtectionStatus(result, link_mask,
> - output_protection_mask);
> + cdm11_->OnQueryOutputProtectionStatus(result, link_mask, output_protection_mask);
> + else if (cdm10_)
> + cdm10_->OnQueryOutputProtectionStatus(result, link_mask, output_protection_mask);
> }
>
> /******************************** HOST *****************************************/
> @@ -624,14 +590,35 @@
> char* bufferPtr{buffer};
> for (uint32_t j{0}; j < keys_info[i].key_id_size; ++j)
> bufferPtr += std::snprintf(bufferPtr, 3, "%02X", (int)keys_info[i].key_id[j]);
> - LOG::Log(LOGDEBUG, "%s: Sessionkey %s status: %d syscode: %u", __func__, buffer,
> - keys_info[i].status, keys_info[i].system_code);
> + Log(LogLevel::DEBUG, "OnSessionKeysChange: KID %s, Status: %d, System code: %u", buffer,
> + keys_info[i].status, keys_info[i].system_code);
>
> SendClientMessage(session_id, session_id_size, CdmAdapterClient::kSessionKeysChange,
> keys_info[i].key_id, keys_info[i].key_id_size, keys_info[i].status);
> }
> }
>
> +void CdmAdapter::OnSessionKeysChange(const char* session_id,
> + uint32_t session_id_size,
> + bool has_additional_usable_key,
> + const cdm::KeyInformation_2* keys_info,
> + uint32_t keys_info_count)
> +{
> + for (uint32_t i(0); i < keys_info_count; ++i)
> + {
> + char buffer[128];
> + char* bufferPtr{buffer};
> + for (uint32_t j{0}; j < keys_info[i].key_id_size; ++j)
> + bufferPtr += std::snprintf(bufferPtr, 3, "%02X", (int)keys_info[i].key_id[j]);
> + Log(LogLevel::DEBUG, "OnSessionKeysChange: KID %s, Status: %d, System code: %u", buffer,
> + keys_info[i].status, keys_info[i].system_code);
> +
> + SendClientMessage(session_id, session_id_size, CdmAdapterClient::kSessionKeysChange,
> + keys_info[i].key_id, keys_info[i].key_id_size,
> + static_cast<uint32_t>(keys_info[i].status));
> + }
> +}
> +
> void CdmAdapter::OnExpirationChange(const char* session_id,
> uint32_t session_id_size,
> cdm::Time new_expiry_time)
> @@ -673,12 +660,14 @@
> return new CdmFileIoImpl(cdm_base_path_, client);
> }
>
> -
> -// Host_9 specific implementations
> void CdmAdapter::OnResolveKeyStatusPromise(uint32_t promise_id, cdm::KeyStatus key_status)
> {
> }
>
> +void CdmAdapter::OnResolveKeyStatusPromise(uint32_t promise_id, cdm::KeyStatus_2 key_status)
> +{
> +}
> +
> void CdmAdapter::OnRejectPromise(uint32_t promise_id, cdm::Exception exception,
> uint32_t system_code, const char* error_message, uint32_t error_message_size)
> {
> @@ -692,15 +681,21 @@
>
> void CdmAdapter::RequestStorageId(uint32_t version)
> {
> - if (cdm10_)
> - cdm10_->OnStorageId(1, nullptr, 0);
> + if (cdm12_)
> + cdm12_->OnStorageId(version, nullptr, 0);
> else if (cdm11_)
> - cdm11_->OnStorageId(1, nullptr, 0);
> + cdm11_->OnStorageId(version, nullptr, 0);
> + else if (cdm10_)
> + cdm10_->OnStorageId(version, nullptr, 0);
> +}
> +
> +void CdmAdapter::ReportMetrics(cdm::MetricName metric_name, uint64_t value)
> +{
> }
>
> void CdmAdapter::OnInitialized(bool success)
> {
> - LOG::LogF(LOGDEBUG, "CDM is initialized: %s", success ? "true" : "false");
> + Log(LogLevel::DEBUG, "CDM is initialized: %s", success ? "true" : "false");
> }
>
>
> @@ -751,14 +746,14 @@
> }
> } else
> status = cdm::FileIOClient::Status::kSuccess;
> - client_->OnReadComplete(status, data_buffer_, sz);
> + client_->OnReadComplete(status, data_buffer_, static_cast<uint32_t>(sz));
> }
>
> void CdmFileIoImpl::Write(const uint8_t* data, uint32_t data_size)
> {
> if (!ExistsDir(base_path_.c_str()) && !CreateDirs(base_path_.c_str()))
> {
> - LOG::LogF(LOGERROR, "Cannot create directory: %s", base_path_.c_str());
> + LogF(LogLevel::ERROR, "Cannot create directory: %s", base_path_.c_str());
> client_->OnWriteComplete(cdm::FileIOClient::Status::kError);
> return;
> }
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/lib/cdm/cdm/media/cdm/cdm_adapter.h kodi-inputstream-adaptive-21.5.15+ds/lib/cdm/cdm/media/cdm/cdm_adapter.h
> --- kodi-inputstream-adaptive-21.5.9+ds/lib/cdm/cdm/media/cdm/cdm_adapter.h 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/lib/cdm/cdm/media/cdm/cdm_adapter.h 2025-07-06 07:54:23.000000000 +0000
> @@ -69,16 +69,16 @@
> cdm::Size m_size;
> cdm::ColorSpace m_colorSpace;
>
> - uint32_t m_planeOffsets[cdm::VideoPlane::kMaxPlanes];
> - uint32_t m_stride[cdm::VideoPlane::kMaxPlanes];
> + uint32_t m_planeOffsets[cdm::kMaxPlanes];
> + uint32_t m_stride[cdm::kMaxPlanes];
>
> uint64_t m_pts;
> };
>
> -class CdmAdapter : public std::enable_shared_from_this<CdmAdapter>
> - , public cdm::Host_9
> - , public cdm::Host_10
> - , public cdm::Host_11
> +class CdmAdapter : public std::enable_shared_from_this<CdmAdapter>,
> + public cdm::Host_10,
> + public cdm::Host_11,
> + public cdm::Host_12
> {
> public:
> void timerfunc(CdmAdapter* adp, int64_t delay, void* context);
> @@ -158,6 +158,9 @@
> void OnResolveKeyStatusPromise(uint32_t promise_id,
> cdm::KeyStatus key_status) override;
>
> + // Used by CDM12 and beyond
> + void OnResolveKeyStatusPromise(uint32_t promise_id, cdm::KeyStatus_2 key_status) override;
> +
> void OnResolveNewSessionPromise(uint32_t promise_id,
> const char* session_id,
> uint32_t session_id_size) override;
> @@ -182,6 +185,13 @@
> const cdm::KeyInformation* keys_info,
> uint32_t keys_info_count) override;
>
> + // Used by CDM12 and beyond
> + void OnSessionKeysChange(const char* session_id,
> + uint32_t session_id_size,
> + bool has_additional_usable_key,
> + const cdm::KeyInformation_2* keys_info,
> + uint32_t keys_info_count) override;
> +
> void OnExpirationChange(const char* session_id,
> uint32_t session_id_size,
> cdm::Time new_expiry_time) override;
> @@ -205,7 +215,7 @@
>
> void RequestStorageId(uint32_t version) override;
>
> - cdm::CdmProxy* RequestCdmProxy(cdm::CdmProxyClient* client) override { return nullptr; };
> + void ReportMetrics(cdm::MetricName metric_name, uint64_t value) override;
>
> void OnInitialized(bool success) override;
>
> @@ -250,9 +260,9 @@
> cdm::MessageType message_type_;
> cdm::Buffer *active_buffer_;
>
> - cdm::ContentDecryptionModule_9 *cdm9_;
> - cdm::ContentDecryptionModule_10 *cdm10_;
> - cdm::ContentDecryptionModule_11 *cdm11_;
> + cdm::ContentDecryptionModule_10* cdm10_{nullptr};
> + cdm::ContentDecryptionModule_11* cdm11_{nullptr};
> + cdm::ContentDecryptionModule_12* cdm12_{nullptr};
>
> DISALLOW_COPY_AND_ASSIGN(CdmAdapter);
> };
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/lib/cdm/CMakeLists.txt kodi-inputstream-adaptive-21.5.15+ds/lib/cdm/CMakeLists.txt
> --- kodi-inputstream-adaptive-21.5.9+ds/lib/cdm/CMakeLists.txt 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/lib/cdm/CMakeLists.txt 2025-07-06 07:54:23.000000000 +0000
> @@ -10,6 +10,7 @@
> endif()
>
> add_library(cdm_library STATIC
> + cdm/debug.cpp
> cdm/base/native_library.cc
> cdm/base/native_library_${CDMTYPE}
> cdm/media/cdm/cdm_adapter.cc
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/src/common/AdaptiveStream.cpp kodi-inputstream-adaptive-21.5.15+ds/src/common/AdaptiveStream.cpp
> --- kodi-inputstream-adaptive-21.5.9+ds/src/common/AdaptiveStream.cpp 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/src/common/AdaptiveStream.cpp 2025-07-06 07:54:23.000000000 +0000
> @@ -676,6 +676,12 @@
> size_t segPosDelay =
> static_cast<size_t>((m_tree->m_liveDelay * current_rep_->GetTimescale()) / segDur);
>
> + //! @todo: hackish workaround, when segment duration is same of live delay, force at least 1 position delay
> + //! otherwise the current segment will be last available on the timeline,
> + //! therefore when GetNextSegment is executed will return nullptr and the below (todo) BUG condition stop the playback
> + if (segPosDelay == 0)
> + segPosDelay = 1;
> +
> if (segPos > segPosDelay)
> segPos -= segPosDelay;
> else
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/src/common/AdaptiveStream.h kodi-inputstream-adaptive-21.5.15+ds/src/common/AdaptiveStream.h
> --- kodi-inputstream-adaptive-21.5.9+ds/src/common/AdaptiveStream.h 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/src/common/AdaptiveStream.h 2025-07-06 07:54:23.000000000 +0000
> @@ -14,6 +14,7 @@
>
> #include <atomic>
> #include <condition_variable>
> +#include <chrono>
> #include <map>
> #include <mutex>
> #include <string>
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/src/decrypters/Helpers.cpp kodi-inputstream-adaptive-21.5.15+ds/src/decrypters/Helpers.cpp
> --- kodi-inputstream-adaptive-21.5.9+ds/src/decrypters/Helpers.cpp 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/src/decrypters/Helpers.cpp 2025-07-06 07:54:23.000000000 +0000
> @@ -81,8 +81,19 @@
> // to avoid possible collisions, so we include the first directory path after the domain name
> // e.g. http://localhost:1234/addonservicename/other_dir/get_license?id=xyz
> // domain will result: http://localhost/addonservicename/
> + // The port number will be removed, since add-ons should use each time a different random
> + // port number to avoid conflicts with other add-ons and/or system services
> if (STRING::Contains(baseDomain, "127.0.0.1") || STRING::Contains(baseDomain, "localhost"))
> {
> + const size_t bdStartPos = baseDomain.find("://") + 3;
> + const size_t bdPortPos = baseDomain.find_first_of(':', bdStartPos);
> + if (bdPortPos != std::string::npos)
> + {
> + // Remove the port number
> + // e.g. "http://localhost:1234" will remove ":1234"
> + baseDomain.erase(bdPortPos);
> + }
> +
> const size_t domainStartPos = url.find("://") + 3;
> const size_t pathStartPos = url.find_first_of('/', domainStartPos);
> if (pathStartPos != std::string::npos)
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/src/decrypters/widevine/WVCdmAdapter.cpp kodi-inputstream-adaptive-21.5.15+ds/src/decrypters/widevine/WVCdmAdapter.cpp
> --- kodi-inputstream-adaptive-21.5.9+ds/src/decrypters/widevine/WVCdmAdapter.cpp 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/src/decrypters/widevine/WVCdmAdapter.cpp 2025-07-06 07:54:23.000000000 +0000
> @@ -11,6 +11,7 @@
> #include "CdmFixedBuffer.h"
> #include "WVCencSingleSampleDecrypter.h"
> #include "WVDecrypter.h"
> +#include "cdm/debug.h"
> #include "decrypters/Helpers.h"
> #include "utils/FileUtils.h"
> #include "utils/log.h"
> @@ -28,6 +29,30 @@
> #else
> constexpr const char* LIBRARY_FILENAME = "libwidevinecdm.so";
> #endif
> +
> +void DebugLog(const CDM_DBG::LogLevel level, const char* msg)
> +{
> + switch (level)
> + {
> + case CDM_DBG::LogLevel::ERROR:
> + LOG::Log(LOGERROR, msg);
> + break;
> + case CDM_DBG::LogLevel::WARNING:
> + LOG::Log(LOGWARNING, msg);
> + break;
> + case CDM_DBG::LogLevel::INFO:
> + LOG::Log(LOGINFO, msg);
> + break;
> + case CDM_DBG::LogLevel::DEBUG:
> + LOG::Log(LOGDEBUG, msg);
> + break;
> + case CDM_DBG::LogLevel::FATAL:
> + LOG::Log(LOGFATAL, msg);
> + break;
> + default:
> + break;
> + }
> +}
> } // unnamed namespace
>
> CWVCdmAdapter::CWVCdmAdapter(std::string_view licenseURL,
> @@ -36,6 +61,8 @@
> CWVDecrypter* host)
> : m_licenseUrl(licenseURL), m_host(host), m_codecInstance(nullptr)
> {
> + CDM_DBG::SetDBGMsgCallback(DebugLog);
> +
> if (m_host->GetLibraryPath().empty())
> {
> LOG::LogF(LOGERROR, "Widevine CDM library path not specified");
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/src/decrypters/widevine/WVCencSingleSampleDecrypter.cpp kodi-inputstream-adaptive-21.5.15+ds/src/decrypters/widevine/WVCencSingleSampleDecrypter.cpp
> --- kodi-inputstream-adaptive-21.5.9+ds/src/decrypters/widevine/WVCencSingleSampleDecrypter.cpp 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/src/decrypters/widevine/WVCencSingleSampleDecrypter.cpp 2025-07-06 07:54:23.000000000 +0000
> @@ -1125,7 +1125,7 @@
> picture->decodedDataSize = videoFrame.FrameBuffer()->Size();
> picture->videoBufferHandle = static_cast<CdmFixedBuffer*>(videoFrame.FrameBuffer())->Buffer();
>
> - for (size_t i = 0; i < cdm::VideoPlane::kMaxPlanes; ++i)
> + for (size_t i = 0; i < cdm::kMaxPlanes; ++i)
> {
> picture->planeOffsets[i] = videoFrame.PlaneOffset(static_cast<cdm::VideoPlane>(i));
> picture->stride[i] = videoFrame.Stride(static_cast<cdm::VideoPlane>(i));
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/src/parser/DASHTree.cpp kodi-inputstream-adaptive-21.5.15+ds/src/parser/DASHTree.cpp
> --- kodi-inputstream-adaptive-21.5.9+ds/src/parser/DASHTree.cpp 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/src/parser/DASHTree.cpp 2025-07-06 07:54:23.000000000 +0000
> @@ -1102,16 +1102,8 @@
>
> segmentsCount = std::max<size_t>(durationMs / segDurMs, 1);
>
> - if (available_time_ == 0)
> - {
> - time = tsbStart * segTemplate->GetTimescale() / 1000;
> - segNumber = tsbStart / segDurMs;
> - }
> - else
> - {
> - time += tsbStart * segTemplate->GetTimescale() / 1000;
> - segNumber += tsbStart / segDurMs;
> - }
> + segNumber += (tsbStart - periodStartMs) / segDurMs;
> + time += (segNumber - segTemplate->GetStartNumber()) * segTemplate->GetDuration();
> }
> else if (periodDurMs > 0)
> {
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/src/parser/HLSTree.cpp kodi-inputstream-adaptive-21.5.15+ds/src/parser/HLSTree.cpp
> --- kodi-inputstream-adaptive-21.5.9+ds/src/parser/HLSTree.cpp 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/src/parser/HLSTree.cpp 2025-07-06 07:54:23.000000000 +0000
> @@ -802,15 +802,18 @@
> }
>
> FreeSegments(period, rep);
> - rep->Timeline().Swap(newSegments);
>
> rep->SetStartNumber(mediaSequenceNbr);
> +
> + // Update MEDIA-SEQUENCE for next period
> + mediaSequenceNbr += newSegments.GetSize();
> +
> + rep->Timeline().Swap(newSegments);
> }
>
> isSkipUntilDiscont = false;
> ++discontCount;
>
> - mediaSequenceNbr += rep->Timeline().GetSize();
> currentSegNumber = mediaSequenceNbr;
>
> CPeriod* newPeriod = FindDiscontinuityPeriod(m_discontSeq + discontCount);
> @@ -910,8 +913,7 @@
> uint64_t totalTimeMs = 0;
> if (discontCount > 0 || m_hasDiscontSeq)
> {
> - // On live stream you dont know the period end, so dont set the period duration in advance
> - if (!m_isLive && adp->GetStreamType() != StreamType::SUBTITLE)
> + if (adp->GetStreamType() != StreamType::SUBTITLE)
> {
> uint64_t periodDuration =
> (rep->GetDuration() * m_periods[discontCount]->GetTimescale()) / rep->GetTimescale();
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/src/samplereader/FragmentedSampleReader.cpp kodi-inputstream-adaptive-21.5.15+ds/src/samplereader/FragmentedSampleReader.cpp
> --- kodi-inputstream-adaptive-21.5.9+ds/src/samplereader/FragmentedSampleReader.cpp 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/src/samplereader/FragmentedSampleReader.cpp 2025-07-06 07:54:23.000000000 +0000
> @@ -466,6 +466,9 @@
> return;
> }
> }
> + else {
> + m_protectedDesc = nullptr;
> + }
>
> LOG::LogF(LOGDEBUG, "Codec fourcc: %s (%u)", CODEC::FourCCToString(desc->GetFormat()).c_str(),
> desc->GetFormat());
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/src/test/TestDASHTree.cpp kodi-inputstream-adaptive-21.5.15+ds/src/test/TestDASHTree.cpp
> --- kodi-inputstream-adaptive-21.5.9+ds/src/test/TestDASHTree.cpp 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/src/test/TestDASHTree.cpp 2025-07-06 07:54:23.000000000 +0000
> @@ -286,7 +286,7 @@
> auto& segments = tree->m_periods[0]->GetAdaptationSets()[0]->GetRepresentations()[0]->Timeline();
>
> EXPECT_EQ(segments.GetSize(), 450);
> - EXPECT_EQ(segments.Get(0)->m_number, 404314437);
> + EXPECT_EQ(segments.Get(0)->m_number, 404305524);
> }
>
> TEST_F(DASHTreeTest, CalculateCorrectSegmentNumbersFromSegmentTemplateWithOldPublishTime)
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/src/test/TestUtils.cpp kodi-inputstream-adaptive-21.5.15+ds/src/test/TestUtils.cpp
> --- kodi-inputstream-adaptive-21.5.9+ds/src/test/TestUtils.cpp 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/src/test/TestUtils.cpp 2025-07-06 07:54:23.000000000 +0000
> @@ -44,9 +44,12 @@
> EXPECT_EQ(URL::GetBaseDomain(url), "https://www.foo.bar");
>
> url = "https://www.foo.bar:1234";
> - EXPECT_EQ(URL::GetBaseDomain(url), "https://www.foo.bar");
> + EXPECT_EQ(URL::GetBaseDomain(url), "https://www.foo.bar:1234");
>
> url = "https://www.foo.bar:1234/mpd/test.mpd?ping=pong";
> + EXPECT_EQ(URL::GetBaseDomain(url), "https://www.foo.bar:1234");
> +
> + url = "https://www.foo.bar/example/smil:rtmp.smil/playlist.m3u8?ping=pong";
> EXPECT_EQ(URL::GetBaseDomain(url), "https://www.foo.bar");
> }
>
> @@ -131,6 +134,17 @@
> otherUrl = "./";
> EXPECT_EQ(URL::Join(baseUrl, otherUrl), "https://foo.bar/sub1/sub2/");
>
> +
> + baseUrl = "https://foo.bar/sub1../sub2./";
> + otherUrl = ".ending";
> + EXPECT_EQ(URL::Join(baseUrl, otherUrl), "https://foo.bar/sub1../sub2./.ending");
> +
> + otherUrl = "./.ending/.";
> + EXPECT_EQ(URL::Join(baseUrl, otherUrl), "https://foo.bar/sub1../sub2./.ending/");
> +
> + otherUrl = "./.ending/./";
> + EXPECT_EQ(URL::Join(baseUrl, otherUrl), "https://foo.bar/sub1../sub2./.ending/");
> +
> // Less common and malformed test cases
>
> baseUrl = "https://foo.bar/sub1/sub2/";
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/src/utils/log.h kodi-inputstream-adaptive-21.5.15+ds/src/utils/log.h
> --- kodi-inputstream-adaptive-21.5.9+ds/src/utils/log.h 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/src/utils/log.h 2025-07-06 07:54:23.000000000 +0000
> @@ -17,7 +17,6 @@
>
> #include <utility>
>
> -// To keep in sync with SSDLogLevel on SSD_dll.h
> enum LogLevel
> {
> LOGDEBUG,
> diff -Nru kodi-inputstream-adaptive-21.5.9+ds/src/utils/UrlUtils.cpp kodi-inputstream-adaptive-21.5.15+ds/src/utils/UrlUtils.cpp
> --- kodi-inputstream-adaptive-21.5.9+ds/src/utils/UrlUtils.cpp 2025-01-19 09:11:59.000000000 +0000
> +++ kodi-inputstream-adaptive-21.5.15+ds/src/utils/UrlUtils.cpp 2025-07-06 07:54:23.000000000 +0000
> @@ -78,6 +78,29 @@
> return true;
> }
>
> +void RemovePrefixSingleDot(std::string& url)
> +{
> + size_t pos{0};
> + // Remove occurrences of "/./" preserving the separator
> + while ((pos = url.find("/./")) != std::string::npos)
> + {
> + url.erase(pos, 2);
> + }
> +
> + if (StringUtils::EndsWith(url, "/."))
> + url.pop_back(); // Delete the dot and preserve the separator
> +}
> +
> +void RemovePrefixDoubleDot(std::string& url)
> +{
> + size_t pos{0};
> + // Remove occurrences of "/../" preserving the separator
> + while ((pos = url.find("/../")) != std::string::npos)
> + {
> + url.erase(pos, 3);
> + }
> +}
> +
> /*
> * \brief Remove and resolve special dot's from the end of the url.
> * e.g. "http://foo.bar/sub1/sub2/.././" will result "http://foo.bar/sub1/"
> @@ -88,18 +111,18 @@
> size_t numSegsRemove{0};
> size_t currPos{0};
> size_t startPos{url.size() - 2};
> - while ((currPos = url.rfind("/", startPos)) != std::string::npos)
> + while ((currPos = url.rfind('/', startPos)) != std::string::npos)
> {
> // Stop to ignore "/../" from the start of string, e.g. ignored --> "../../something/../" <-- handled
> - if (url.substr(currPos + 1, startPos - currPos + 1) != PREFIX_DOUBLE_DOT)
> + if (currPos == 0 || url.substr(currPos + 1, startPos - currPos + 1) != PREFIX_DOUBLE_DOT)
> break;
> startPos = currPos - 1;
> numSegsRemove++;
> }
>
> // Remove special prefixes
> - UTILS::STRING::ReplaceAll(url, PREFIX_DOUBLE_DOT, "");
> - UTILS::STRING::ReplaceAll(url, PREFIX_SINGLE_DOT, "");
> + RemovePrefixSingleDot(url);
> + RemovePrefixDoubleDot(url);
>
> size_t addrsStartPos{0};
> if (IsUrlAbsolute(url))
> @@ -257,18 +280,16 @@
> if (paramsPos != std::string::npos)
> url.erase(paramsPos);
>
> - const size_t domainStartPos = url.find("://") + 3;
> - // Try remove url port number and path
> - const size_t port = url.find_first_of(':', domainStartPos);
> - if (port != std::string::npos)
> - url.erase(port);
> - else
> - {
> - // Try remove the path
> - const size_t slashPos = url.find_first_of('/', domainStartPos);
> - if (slashPos != std::string::npos)
> - url.erase(slashPos);
> - }
> + const size_t schemeEndPos = url.find("://");
> + if (schemeEndPos == std::string::npos)
> + return ""; // Not valid
> +
> + const size_t domainStartPos = schemeEndPos + 3;
> + const size_t pathPos = url.find_first_of('/', domainStartPos);
> +
> + if (pathPos != std::string::npos)
> + url.erase(pathPos); // remove from slash
> +
> return url;
> }
> return "";
> @@ -284,8 +305,6 @@
>
> if (relativeUrl == ".") // Ignore single dot
> relativeUrl.clear();
> - else if (relativeUrl.compare(0, 2, PREFIX_SINGLE_DOT) == 0) // Ignore prefix ./
> - relativeUrl.erase(0, 2);
>
> // Sanitize for missing backslash
> if (relativeUrl == ".." || StringUtils::EndsWith(relativeUrl, "/.."))
--
Sebastian Ramacher
Reply to: