diff --git a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp index fa703ab0b8..57d4ecec27 100644 --- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp @@ -106,8 +106,8 @@ WidevineAdapter::GMPGetAPI(const char* aAPIName, WidevineDecryptor* decryptor = new WidevineDecryptor(); - auto cdm = reinterpret_cast( - create(cdm::ContentDecryptionModule::kVersion, + auto cdm = reinterpret_cast( + create(cdm::ContentDecryptionModule_9::kVersion, kEMEKeySystemWidevine.get(), kEMEKeySystemWidevine.Length(), &GetCdmHost, @@ -161,7 +161,7 @@ WidevineAdapter::Supports(int32_t aModuleVersion, int32_t aHostVersion) { return aModuleVersion == CDM_MODULE_VERSION && - aInterfaceVersion == cdm::ContentDecryptionModule::kVersion && + aInterfaceVersion == cdm::ContentDecryptionModule_9::kVersion && aHostVersion == cdm::Host_9::kVersion; } diff --git a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp b/dom/media/gmp/widevine-adapter/WidevineUtils.cpp index deb71e51a5..10c6c2e18c 100644 --- a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineUtils.cpp @@ -43,7 +43,7 @@ ToGMPErr(cdm::Status aStatus) case cdm::kSuccess: return GMPNoErr; case cdm::kNeedMoreData: return GMPGenericErr; case cdm::kNoKey: return GMPNoKeyErr; - case cdm::kSessionError: return GMPGenericErr; + case cdm::kInitializationError: return GMPGenericErr; case cdm::kDecryptError: return GMPCryptoErr; case cdm::kDecodeError: return GMPDecodeErr; case cdm::kDeferredInitialization: return GMPGenericErr; diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module.h b/dom/media/gmp/widevine-adapter/content_decryption_module.h index 512ca97689..3f065017bf 100644 --- a/dom/media/gmp/widevine-adapter/content_decryption_module.h +++ b/dom/media/gmp/widevine-adapter/content_decryption_module.h @@ -5,6 +5,8 @@ #ifndef CDM_CONTENT_DECRYPTION_MODULE_H_ #define CDM_CONTENT_DECRYPTION_MODULE_H_ +#include "content_decryption_module_export.h" + #if defined(_MSC_VER) typedef unsigned char uint8_t; typedef unsigned int uint32_t; @@ -14,25 +16,21 @@ typedef __int64 int64_t; #include #endif -// Define CDM_EXPORT so that functionality implemented by the CDM module -// can be exported to consumers. -#if defined(WIN32) - -#if defined(CDM_IMPLEMENTATION) -#define CDM_EXPORT __declspec(dllexport) +// Define CDM_CLASS_API to export class types. We have to add visibility +// attributes to make sure virtual tables in CDM consumer and CDM implementation +// are the same. Generally, it was always a good idea, as there're no guarantees +// about that for the internal symbols, but it has only become a practical issue +// after introduction of LTO devirtualization. See more details on +// https://crbug.com/609564#c35 +#if defined(_WIN32) +#if defined(__clang__) +#define CDM_CLASS_API [[clang::lto_visibility_public]] #else -#define CDM_EXPORT __declspec(dllimport) -#endif // defined(CDM_IMPLEMENTATION) - -#else // defined(WIN32) - -#if defined(CDM_IMPLEMENTATION) -#define CDM_EXPORT __attribute__((visibility("default"))) -#else -#define CDM_EXPORT +#define CDM_CLASS_API #endif - -#endif // defined(WIN32) +#else // defined(_WIN32) +#define CDM_CLASS_API __attribute__((visibility("default"))) +#endif // defined(_WIN32) // The version number must be rolled when the exported functions are updated! // If the CDM and the adapter use different versions of these functions, the @@ -48,9 +46,9 @@ typedef __int64 int64_t; #define BUILD_ENTRYPOINT_NO_EXPANSION(name, version) name##_##version extern "C" { -CDM_EXPORT void INITIALIZE_CDM_MODULE(); +CDM_API void INITIALIZE_CDM_MODULE(); -CDM_EXPORT 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. @@ -65,30 +63,30 @@ typedef void* (*GetCdmHostFunc)(int host_interface_version, void* user_data); // |cdm_interface_version|. // Caller retains ownership of arguments and must call Destroy() on the returned // object. -CDM_EXPORT void* CreateCdmInstance( +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_EXPORT const char* GetCdmVersion(); +CDM_API const char* GetCdmVersion(); } namespace cdm { -class AudioFrames; -class DecryptedBlock; -class VideoFrame; +class CDM_CLASS_API AudioFrames; +class CDM_CLASS_API DecryptedBlock; +class CDM_CLASS_API VideoFrame; -class Host_7; -class Host_8; +class CDM_CLASS_API Host_8; +class CDM_CLASS_API Host_9; enum Status { kSuccess = 0, kNeedMoreData, // Decoder needs more data to produce a decoded frame/sample. - kNoKey, // The required decryption key is not available. - kSessionError, // Session management error. - kDecryptError, // Decryption failed. - kDecodeError, // Error decoding audio or video. + 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. }; @@ -97,6 +95,7 @@ enum Status { // The following starts with the list of DOM4 exceptions from: // http://www.w3.org/TR/dom/#domexception // Some DOM4 exceptions are not included as they are not expected to be used. +// Should only be used on Host_8 and before. enum Error { kNotSupportedError = 9, kInvalidStateError = 11, @@ -113,8 +112,20 @@ enum Error { kOutputError = 101 }; -// Time is defined as the number of seconds since the -// Epoch (00:00:00 UTC, January 1, 1970). +// Exceptions used by the CDM to reject promises. +// https://w3c.github.io/encrypted-media/#exceptions +enum Exception { + kExceptionTypeError, + kExceptionNotSupportedError, + kExceptionInvalidStateError, + kExceptionQuotaExceededError +}; + +// 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. @@ -151,13 +162,13 @@ struct SubsampleEntry { // unencrypted. struct InputBuffer { InputBuffer() - : data(NULL), + : data(nullptr), data_size(0), - key_id(NULL), + key_id(nullptr), key_id_size(0), - iv(NULL), + iv(nullptr), iv_size(0), - subsamples(NULL), + subsamples(nullptr), num_subsamples(0), timestamp(0) {} @@ -188,7 +199,7 @@ struct AudioDecoderConfig { channel_count(0), bits_per_channel(0), samples_per_second(0), - extra_data(NULL), + extra_data(nullptr), extra_data_size(0) {} AudioCodec codec; @@ -214,10 +225,25 @@ enum AudioFormat { }; // 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 { kUnknownVideoFormat = 0, // Unknown format value. Used for error reporting. - kYv12, // 12bpp YVU planar 1x1 Y, 2x2 VU samples. - kI420 // 12bpp YVU planar 1x1 Y, 2x2 UV samples. + 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, }; struct Size { @@ -245,14 +271,19 @@ struct VideoDecoderConfig { kH264ProfileHigh, kH264ProfileHigh10, kH264ProfileHigh422, - kH264ProfileHigh444Predictive + kH264ProfileHigh444Predictive, + // VP9 Profiles are only passed in starting from CDM_9. + kVP9Profile0, + kVP9Profile1, + kVP9Profile2, + kVP9Profile3 }; VideoDecoderConfig() : codec(kUnknownVideoCodec), profile(kUnknownVideoCodecProfile), format(kUnknownVideoFormat), - extra_data(NULL), + extra_data(nullptr), extra_data_size(0) {} VideoCodec codec; @@ -294,7 +325,7 @@ struct PlatformChallengeResponse { // Used when passing arrays of binary data. Does not own the referenced data. struct BinaryData { - BinaryData() : data(NULL), length(0) {} + BinaryData() : data(nullptr), length(0) {} const uint8_t* data; uint32_t length; }; @@ -316,7 +347,10 @@ enum KeyStatus { // should be 0 when |status| == kUsable. struct KeyInformation { KeyInformation() - : key_id(NULL), key_id_size(0), status(kInternalError), system_code(0) {} + : key_id(nullptr), + key_id_size(0), + status(kInternalError), + system_code(0) {} const uint8_t* key_id; uint32_t key_id_size; KeyStatus status; @@ -372,6 +406,24 @@ enum MessageType { kLicenseRelease = 2 }; +enum HdcpVersion { + kHdcpVersionNone, + kHdcpVersion1_0, + kHdcpVersion1_1, + kHdcpVersion1_2, + kHdcpVersion1_3, + kHdcpVersion1_4, + kHdcpVersion2_0, + kHdcpVersion2_1, + kHdcpVersion2_2 +}; + +struct Policy { + Policy() : min_hdcp_version(kHdcpVersionNone) {} + + HdcpVersion min_hdcp_version; +}; + // 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. @@ -381,7 +433,7 @@ enum MessageType { // 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 FileIO { +class CDM_CLASS_API FileIO { public: // Opens the file with |file_name| for read and write. // FileIOClient::OnOpenComplete() will be called after the opening @@ -421,7 +473,7 @@ class FileIO { // 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 FileIOClient { +class CDM_CLASS_API FileIOClient { public: enum Status { kSuccess = 0, @@ -462,186 +514,7 @@ class FileIOClient { // 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 ContentDecryptionModule_7 { - public: - static const int kVersion = 7; - typedef Host_7 Host; - - // 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, - const char* init_data_type, - uint32_t init_data_type_size, - 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& 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 kSessionError 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& 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 kSessionError 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& 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 only empty - // |video_frame| (|format| == kEmptyVideoFrame) is produced. - // - // 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& 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& 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( - QueryResult result, - uint32_t link_mask, - uint32_t output_protection_mask) = 0; - - // Destroys the object in the same context as it was created. - virtual void Destroy() = 0; - - protected: - ContentDecryptionModule_7() {} - virtual ~ContentDecryptionModule_7() {} -}; - -// 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 ContentDecryptionModule_8 { +class CDM_CLASS_API ContentDecryptionModule_8 { public: static const int kVersion = 8; typedef Host_8 Host; @@ -823,10 +696,210 @@ class ContentDecryptionModule_8 { virtual ~ContentDecryptionModule_8() {} }; -typedef ContentDecryptionModule_8 ContentDecryptionModule; +// 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& 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 kSessionError 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& 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 kSessionError 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& 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 only empty + // |video_frame| (|format| == kEmptyVideoFrame) is produced. + // + // 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& 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& 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( + QueryResult result, + uint32_t link_mask, + uint32_t output_protection_mask) = 0; + + // Called by the host after a call to Host::RequestStorageId(). If the storage + // ID is not available, null/zero will be provided. + virtual void OnStorageId(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() {} +}; + +typedef ContentDecryptionModule_9 ContentDecryptionModule; // Represents a buffer created by Allocator implementations. -class Buffer { +class CDM_CLASS_API Buffer { public: // Destroys the buffer in the same context as it was created. virtual void Destroy() = 0; @@ -845,144 +918,7 @@ class Buffer { void operator=(const Buffer&); }; -class Host_7 { - public: - static const int kVersion = 7; - - // 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 in seconds. - virtual Time GetCurrentWallTime() = 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|. - // |error| 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, - Error error, - 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. - // |legacy_destination_url| is only for supporting the prefixed EME API and - // is ignored by unprefixed EME. It should only be non-null if |message_type| - // is kLicenseRenewal. - virtual void OnSessionMessage(const char* session_id, - uint32_t session_id_size, - MessageType message_type, - const char* message, - uint32_t message_size, - const char* legacy_destination_url, - uint32_t legacy_destination_url_length) = 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. - // |key_ids| is the list of key ids for this session along with their - // current status. |key_ids_count| is the number of entries in |key_ids|. - // 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| - // can be 0 to represent "undefined". 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; - - // Called by the CDM when an error occurs in session |session_id| - // unrelated to one of the ContentDecryptionModule calls that accept a - // |promise_id|. |error| must be specified, |error_message| and - // |system_code| are optional. Length parameters should not include null - // termination. - // Note: - // - This method is only for supporting prefixed EME API. - // - This method will be ignored by unprefixed EME. All errors reported - // in this method should probably also be reported by one of other methods. - virtual void OnLegacySessionError( - const char* session_id, uint32_t session_id_length, - Error error, - uint32_t system_code, - const char* error_message, uint32_t error_message_length) = 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; - - protected: - Host_7() {} - virtual ~Host_7() {} -}; - -class Host_8 { +class CDM_CLASS_API Host_8 { public: static const int kVersion = 8; @@ -996,7 +932,7 @@ class Host_8 { // from now with |context|. virtual void SetTimer(int64_t delay_ms, void* context) = 0; - // Returns the current wall time in seconds. + // Returns the current wall time. virtual Time GetCurrentWallTime() = 0; // Called by the CDM when a session is created or loaded and the value for the @@ -1054,8 +990,10 @@ class Host_8 { // 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| - // can be 0 to represent "undefined". Size parameter should not include - // null termination. + // 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; @@ -1119,8 +1057,138 @@ class Host_8 { virtual ~Host_8() {} }; +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. + // |key_ids| is the list of key ids for this session along with their + // current status. |key_ids_count| is the number of entries in |key_ids|. + // 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 the storage ID. The ID will be returned by the host via + // ContentDecryptionModule::OnStorageId(). A storage ID is a stable, device + // specific ID used by the CDM to securely store persistent data. The CDM must + // not expose the ID outside the client device, even in encrypted form. + virtual void RequestStorageId() = 0; + + protected: + Host_9() {} + virtual ~Host_9() {} +}; + // Represents a decrypted block that has not been decoded. -class DecryptedBlock { +class CDM_CLASS_API DecryptedBlock { public: virtual void SetDecryptedBuffer(Buffer* buffer) = 0; virtual Buffer* DecryptedBuffer() = 0; @@ -1135,7 +1203,7 @@ class DecryptedBlock { virtual ~DecryptedBlock() {} }; -class VideoFrame { +class CDM_CLASS_API VideoFrame { public: enum VideoPlane { kYPlane = 0, @@ -1178,7 +1246,7 @@ class VideoFrame { // // |<----------------- AudioFrames ------------------>| // | audio buffer 0 | audio buffer 1 | audio buffer 2 | -class AudioFrames { +class CDM_CLASS_API AudioFrames { public: virtual void SetFrameBuffer(Buffer* buffer) = 0; virtual Buffer* FrameBuffer() = 0; diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module_export.h b/dom/media/gmp/widevine-adapter/content_decryption_module_export.h new file mode 100644 index 0000000000..51d485892b --- /dev/null +++ b/dom/media/gmp/widevine-adapter/content_decryption_module_export.h @@ -0,0 +1,22 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_ +#define CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_ + +// Define CDM_API so that functionality implemented by the CDM module +// can be exported to consumers. +#if defined(_WIN32) + +#if defined(CDM_IMPLEMENTATION) +#define CDM_API __declspec(dllexport) +#else +#define CDM_API __declspec(dllimport) +#endif // defined(CDM_IMPLEMENTATION) + +#else // defined(_WIN32) +#define CDM_API __attribute__((visibility("default"))) +#endif // defined(_WIN32) + +#endif // CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_