diff options
9 files changed, 353 insertions, 173 deletions
diff --git a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp index 74b5c38e8..57d4ecec2 100644 --- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp @@ -46,7 +46,7 @@ void* GetCdmHost(int aHostInterfaceVersion, void* aUserData) Log("GetCdmHostFunc(%d, %p)", aHostInterfaceVersion, aUserData); WidevineDecryptor* decryptor = reinterpret_cast<WidevineDecryptor*>(aUserData); MOZ_ASSERT(decryptor); - return static_cast<cdm::Host_8*>(decryptor); + return static_cast<cdm::Host_9*>(decryptor); } #define STRINGIFY(s) _STRINGIFY(s) @@ -106,8 +106,8 @@ WidevineAdapter::GMPGetAPI(const char* aAPIName, WidevineDecryptor* decryptor = new WidevineDecryptor(); - auto cdm = reinterpret_cast<cdm::ContentDecryptionModule*>( - create(cdm::ContentDecryptionModule::kVersion, + auto cdm = reinterpret_cast<cdm::ContentDecryptionModule_9*>( + create(cdm::ContentDecryptionModule_9::kVersion, kEMEKeySystemWidevine.get(), kEMEKeySystemWidevine.Length(), &GetCdmHost, @@ -161,8 +161,8 @@ WidevineAdapter::Supports(int32_t aModuleVersion, int32_t aHostVersion) { return aModuleVersion == CDM_MODULE_VERSION && - aInterfaceVersion == cdm::ContentDecryptionModule::kVersion && - aHostVersion == cdm::Host_8::kVersion; + aInterfaceVersion == cdm::ContentDecryptionModule_9::kVersion && + aHostVersion == cdm::Host_9::kVersion; } } // namespace mozilla diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp index 149fa1701..4d3408804 100644 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp @@ -102,7 +102,7 @@ WidevineDecryptor::CreateSession(uint32_t aCreateSessionToken, } else { // Invalid init data type const char* errorMsg = "Invalid init data type when creating session."; - OnRejectPromise(aPromiseId, kNotSupportedError, 0, errorMsg, sizeof(errorMsg)); + OnRejectPromise(aPromiseId, kExceptionNotSupportedError, 0, errorMsg, sizeof(errorMsg)); return; } mPromiseIdToNewSessionTokens[aPromiseId] = aCreateSessionToken; @@ -302,6 +302,12 @@ WidevineDecryptor::GetCurrentWallTime() } void +WidevineDecryptor::OnResolveKeyStatusPromise(uint32_t aPromiseId, + cdm::KeyStatus aKeyStatus) { + //TODO: The callback of GetStatusForPolicy. See Mozilla bug 1404230. +} + +void WidevineDecryptor::OnResolveNewSessionPromise(uint32_t aPromiseId, const char* aSessionId, uint32_t aSessionIdSize) @@ -333,41 +339,59 @@ WidevineDecryptor::OnResolvePromise(uint32_t aPromiseId) } static GMPDOMException -ToGMPDOMException(cdm::Error aError) -{ - switch (aError) { - case kNotSupportedError: return kGMPNotSupportedError; - case kInvalidStateError: return kGMPInvalidStateError; - case kInvalidAccessError: - // Note: Chrome converts kInvalidAccessError to TypeError, since the - // Chromium CDM API doesn't have a type error enum value. The EME spec - // requires TypeError in some places, so we do the same conversion. - // See bug 1313202. - return kGMPTypeError; - case kQuotaExceededError: return kGMPQuotaExceededError; +ConvertCDMExceptionToGMPDOMException(cdm::Exception aException) +{ + switch (aException) { + case kExceptionNotSupportedError: return kGMPNotSupportedError; + case kExceptionInvalidStateError: return kGMPInvalidStateError; + case kExceptionTypeError: return kGMPTypeError; + case kExceptionQuotaExceededError: return kGMPQuotaExceededError; case kUnknownError: return kGMPInvalidModificationError; // Note: Unique placeholder. case kClientError: return kGMPAbortError; // Note: Unique placeholder. case kOutputError: return kGMPSecurityError; // Note: Unique placeholder. }; - return kGMPTimeoutError; // Note: Unique placeholder. + return kGMPInvalidStateError; // Note: Unique placeholder. +} + +// Align with spec, the Exceptions used by CDM to reject promises . +// https://w3c.github.io/encrypted-media/#exceptions +cdm::Exception +ConvertCDMErrorToCDMException(cdm::Error error) { + switch (error) { + case cdm::kNotSupportedError: + return cdm::Exception::kExceptionNotSupportedError; + case cdm::kInvalidStateError: + return cdm::Exception::kExceptionInvalidStateError; + case cdm::kInvalidAccessError: + return cdm::Exception::kExceptionTypeError; + case cdm::kQuotaExceededError: + return cdm::Exception::kExceptionQuotaExceededError; + + case cdm::kUnknownError: + case cdm::kClientError: + case cdm::kOutputError: + break; + } + + return cdm::Exception::kExceptionInvalidStateError; } void WidevineDecryptor::OnRejectPromise(uint32_t aPromiseId, - Error aError, + cdm::Exception aException, uint32_t aSystemCode, const char* aErrorMessage, uint32_t aErrorMessageSize) { if (!mCallback) { Log("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s) FAIL; !mCallback", - aPromiseId, (int)aError, aSystemCode, aErrorMessage); + aPromiseId, (int)aException, aSystemCode, aErrorMessage); return; } Log("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s)", - aPromiseId, (int)aError, aSystemCode, aErrorMessage); + aPromiseId, (int)aException, aSystemCode, aErrorMessage); mCallback->RejectPromise(aPromiseId, - ToGMPDOMException(aError), + ConvertCDMExceptionToGMPDOMException(aException), !aErrorMessageSize ? "" : aErrorMessage, aErrorMessageSize); } @@ -386,11 +410,9 @@ ToGMPMessageType(MessageType message_type) void WidevineDecryptor::OnSessionMessage(const char* aSessionId, uint32_t aSessionIdSize, - MessageType aMessageType, + cdm::MessageType aMessageType, const char* aMessage, - uint32_t aMessageSize, - const char* aLegacyDestinationUrl, - uint32_t aLegacyDestinationUrlLength) + uint32_t aMessageSize) { if (!mCallback) { Log("Decryptor::OnSessionMessage() FAIL; !mCallback"); @@ -479,28 +501,6 @@ WidevineDecryptor::OnSessionClosed(const char* aSessionId, } void -WidevineDecryptor::OnLegacySessionError(const char* aSessionId, - uint32_t aSessionIdLength, - Error aError, - uint32_t aSystemCode, - const char* aErrorMessage, - uint32_t aErrorMessageLength) -{ - if (!mCallback) { - Log("Decryptor::OnLegacySessionError(sid=%s, error=%d) FAIL; !mCallback", - aSessionId, (int)aError); - return; - } - Log("Decryptor::OnLegacySessionError(sid=%s, error=%d)", aSessionId, (int)aError); - mCallback->SessionError(aSessionId, - aSessionIdLength, - ToGMPDOMException(aError), - aSystemCode, - aErrorMessage, - aErrorMessageLength); -} - -void WidevineDecryptor::SendPlatformChallenge(const char* aServiceId, uint32_t aServiceIdSize, const char* aChallenge, @@ -538,4 +538,17 @@ WidevineDecryptor::CreateFileIO(FileIOClient* aClient) return new WidevineFileIO(aClient); } +void +WidevineDecryptor::RequestStorageId(uint32_t aVersion) +{ + Log("Decryptor::RequestStorageId() aVersion = %u", aVersion); + if (aVersion >= 0x80000000) { + mCDM->OnStorageId(aVersion, nullptr, 0); + return; + } + + //TODO: Need to provide a menaingful buffer instead of a dummy one. + mCDM->OnStorageId(aVersion, new uint8_t[1024*1024], 1024 * 1024); +} + } // namespace mozilla diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h index d5185192b..f291c321d 100644 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h +++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h @@ -16,7 +16,7 @@ namespace mozilla { class WidevineDecryptor : public GMPDecryptor - , public cdm::Host_8 + , public cdm::Host_9 { public: @@ -69,16 +69,19 @@ public: void DecryptingComplete() override; - // cdm::Host_8 + // cdm::Host_9 implementation cdm::Buffer* Allocate(uint32_t aCapacity) override; void SetTimer(int64_t aDelayMs, void* aContext) override; cdm::Time GetCurrentWallTime() override; + // cdm::Host_9 interface + void OnResolveKeyStatusPromise(uint32_t aPromiseId, + cdm::KeyStatus aKeyStatus) override; void OnResolveNewSessionPromise(uint32_t aPromiseId, const char* aSessionId, uint32_t aSessionIdSize) override; void OnResolvePromise(uint32_t aPromiseId) override; void OnRejectPromise(uint32_t aPromiseId, - cdm::Error aError, + cdm::Exception aException, uint32_t aSystemCode, const char* aErrorMessage, uint32_t aErrorMessageSize) override; @@ -86,9 +89,7 @@ public: uint32_t aSessionIdSize, cdm::MessageType aMessageType, const char* aMessage, - uint32_t aMessageSize, - const char* aLegacyDestinationUrl, - uint32_t aLegacyDestinationUrlLength) override; + uint32_t aMessageSize) override; void OnSessionKeysChange(const char* aSessionId, uint32_t aSessionIdSize, bool aHasAdditionalUsableKey, @@ -99,12 +100,6 @@ public: cdm::Time aNewExpiryTime) override; void OnSessionClosed(const char* aSessionId, uint32_t aSessionIdSize) override; - void OnLegacySessionError(const char* aSessionId, - uint32_t aSessionId_length, - cdm::Error aError, - uint32_t aSystemCode, - const char* aErrorMessage, - uint32_t aErrorMessageLength) override; void SendPlatformChallenge(const char* aServiceId, uint32_t aServiceIdSize, const char* aChallenge, @@ -113,6 +108,9 @@ public: void QueryOutputProtectionStatus() override; void OnDeferredInitializationDone(cdm::StreamType aStreamType, cdm::Status aDecoderStatus) override; + // cdm::Host_9 interface + // NOTE: the interface has changed upstream. + void RequestStorageId(uint32_t aVersion) override; cdm::FileIO* CreateFileIO(cdm::FileIOClient* aClient) override; GMPDecryptorCallback* Callback() const { return mCallback; } @@ -120,7 +118,7 @@ public: private: ~WidevineDecryptor(); RefPtr<CDMWrapper> mCDM; - cdm::ContentDecryptionModule_8* CDM() { return mCDM->GetCDM(); } + cdm::ContentDecryptionModule_9* CDM() { return mCDM->GetCDM(); } GMPDecryptorCallback* mCallback; std::map<uint32_t, uint32_t> mPromiseIdToNewSessionTokens; diff --git a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp b/dom/media/gmp/widevine-adapter/WidevineUtils.cpp index 925dfe1a1..10c6c2e18 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; @@ -77,7 +77,7 @@ void InitInputBuffer(const GMPEncryptedBufferMetadata* aCrypto, aInputBuffer.timestamp = aTimestamp; } -CDMWrapper::CDMWrapper(cdm::ContentDecryptionModule_8* aCDM, +CDMWrapper::CDMWrapper(cdm::ContentDecryptionModule_9* aCDM, WidevineDecryptor* aDecryptor) : mCDM(aCDM) , mDecryptor(aDecryptor) diff --git a/dom/media/gmp/widevine-adapter/WidevineUtils.h b/dom/media/gmp/widevine-adapter/WidevineUtils.h index 57c004a87..2f6137fe3 100644 --- a/dom/media/gmp/widevine-adapter/WidevineUtils.h +++ b/dom/media/gmp/widevine-adapter/WidevineUtils.h @@ -48,12 +48,16 @@ class CDMWrapper { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CDMWrapper) - explicit CDMWrapper(cdm::ContentDecryptionModule_8* aCDM, + explicit CDMWrapper(cdm::ContentDecryptionModule_9* aCDM, WidevineDecryptor* aDecryptor); - cdm::ContentDecryptionModule_8* GetCDM() const { return mCDM; } + cdm::ContentDecryptionModule_9* GetCDM() const { return mCDM; } + void OnStorageId(uint32_t aVersion, const uint8_t* aStorageId, + uint32_t aStorageIdSize) { + mCDM->OnStorageId(aVersion, aStorageId, aStorageIdSize); + } private: ~CDMWrapper(); - cdm::ContentDecryptionModule_8* mCDM; + cdm::ContentDecryptionModule_9* mCDM; RefPtr<WidevineDecryptor> mDecryptor; }; diff --git a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h index b143f75f7..f5e63519b 100644 --- a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h +++ b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h @@ -45,7 +45,7 @@ private: ~WidevineVideoDecoder(); - cdm::ContentDecryptionModule_8* CDM() const { + cdm::ContentDecryptionModule_9* CDM() const { // CDM should only be accessed before 'DecodingComplete'. MOZ_ASSERT(mCDMWrapper); // CDMWrapper ensure the CDM is non-null, no need to check again. diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module.h b/dom/media/gmp/widevine-adapter/content_decryption_module.h index 512ca9768..0539135fb 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 <stdint.h> #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) -#else -#define CDM_EXPORT __declspec(dllimport) -#endif // defined(CDM_IMPLEMENTATION) - -#else // defined(WIN32) - -#if defined(CDM_IMPLEMENTATION) -#define CDM_EXPORT __attribute__((visibility("default"))) +// 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 +#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 @@ -389,8 +441,9 @@ class FileIO { // - 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 not contain forward slash ('/') or backslash ('\'), and - // must not start with an underscore ('_'). + // - |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 @@ -421,7 +474,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,10 +515,20 @@ 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 { +class CDM_CLASS_API ContentDecryptionModule_8 { public: - static const int kVersion = 7; - typedef Host_7 Host; + static const int kVersion = 8; + typedef Host_8 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; // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(), // UpdateSession(), CloseSession(), and RemoveSession() all accept a @@ -484,8 +547,7 @@ class ContentDecryptionModule_7 { // or Host::OnRejectPromise(). virtual void CreateSessionAndGenerateRequest(uint32_t promise_id, SessionType session_type, - const char* init_data_type, - uint32_t init_data_type_size, + InitDataType init_data_type, const uint8_t* init_data, uint32_t init_data_size) = 0; @@ -631,8 +693,8 @@ class ContentDecryptionModule_7 { virtual void Destroy() = 0; protected: - ContentDecryptionModule_7() {} - virtual ~ContentDecryptionModule_7() {} + ContentDecryptionModule_8() {} + virtual ~ContentDecryptionModule_8() {} }; // ContentDecryptionModule interface that all CDMs need to implement. @@ -641,10 +703,10 @@ class ContentDecryptionModule_7 { // 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_9 { public: - static const int kVersion = 8; - typedef Host_8 Host; + static const int kVersion = 9; + typedef Host_9 Host; // Initializes the CDM instance, providing information about permitted // functionalities. @@ -656,6 +718,13 @@ class ContentDecryptionModule_8 { 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 @@ -731,8 +800,8 @@ class ContentDecryptionModule_8 { // // 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 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. @@ -744,8 +813,8 @@ class ContentDecryptionModule_8 { // // 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 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. @@ -815,18 +884,30 @@ class ContentDecryptionModule_8 { 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_8() {} - virtual ~ContentDecryptionModule_8() {} + ContentDecryptionModule_9() {} + virtual ~ContentDecryptionModule_9() {} }; -typedef ContentDecryptionModule_8 ContentDecryptionModule; +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,9 +926,9 @@ class Buffer { void operator=(const Buffer&); }; -class Host_7 { +class CDM_CLASS_API Host_8 { public: - static const int kVersion = 7; + static const int kVersion = 8; // 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 @@ -859,7 +940,7 @@ class Host_7 { // 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 @@ -917,8 +998,10 @@ class Host_7 { // 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; @@ -978,13 +1061,13 @@ class Host_7 { virtual FileIO* CreateFileIO(FileIOClient* client) = 0; protected: - Host_7() {} - virtual ~Host_7() {} + Host_8() {} + virtual ~Host_8() {} }; -class Host_8 { +class CDM_CLASS_API Host_9 { public: - static const int kVersion = 8; + 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 @@ -996,9 +1079,14 @@ 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 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 @@ -1016,26 +1104,21 @@ class Host_8 { // 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| + // |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, - Error error, + 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. - // |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; + 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 @@ -1054,8 +1137,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; @@ -1065,21 +1150,6 @@ class Host_8 { 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. @@ -1114,13 +1184,22 @@ class Host_8 { // 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_8() {} - virtual ~Host_8() {} + 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 +1214,7 @@ class DecryptedBlock { virtual ~DecryptedBlock() {} }; -class VideoFrame { +class CDM_CLASS_API VideoFrame { public: enum VideoPlane { kYPlane = 0, @@ -1178,7 +1257,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 000000000..51d485892 --- /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_ diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h b/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h new file mode 100644 index 000000000..5df8344e6 --- /dev/null +++ b/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h @@ -0,0 +1,64 @@ +// 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_EXT_H_ +#define CDM_CONTENT_DECRYPTION_MODULE_EXT_H_ + +#if defined(_WIN32) +#include <windows.h> +#endif + +#include "content_decryption_module_export.h" + +#if defined(_MSC_VER) +typedef unsigned int uint32_t; +#else +#include <stdint.h> +#endif + +namespace cdm { + +#if defined(_WIN32) +typedef wchar_t FilePathCharType; +typedef HANDLE PlatformFile; +const PlatformFile kInvalidPlatformFile = INVALID_HANDLE_VALUE; +#else +typedef char FilePathCharType; +typedef int PlatformFile; +const PlatformFile kInvalidPlatformFile = -1; +#endif // defined(_WIN32) + +struct HostFile { + HostFile(const FilePathCharType* file_path, + PlatformFile file, + PlatformFile sig_file) + : file_path(file_path), file(file), sig_file(sig_file) {} + + // File that is part of the host of the CDM. + const FilePathCharType* file_path = nullptr; + PlatformFile file = kInvalidPlatformFile; + + // Signature file for |file|. + PlatformFile sig_file = kInvalidPlatformFile; +}; + +} // namespace cdm + +extern "C" { + +// Functions in this file are dynamically retrieved by their versioned function +// names. Increment the version number for any backward incompatible API +// changes. + +// Verifies CDM host. All files in |host_files| are opened in read-only mode. +// +// Returns false and closes all files if there is an immediate failure. +// Otherwise returns true as soon as possible and processes the files +// asynchronously. All files MUST be closed by the CDM after this one-time +// processing is finished. +CDM_API bool VerifyCdmHost_0(const cdm::HostFile* host_files, + uint32_t num_files); +} + +#endif // CDM_CONTENT_DECRYPTION_MODULE_EXT_H_ |