/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef DOM_MEDIA_EME_KEYSYSTEMCONFIG_H_ #define DOM_MEDIA_EME_KEYSYSTEMCONFIG_H_ #include "MediaData.h" #include "nsString.h" #include "nsTArray.h" #include "mozilla/MozPromise.h" #include "mozilla/dom/MediaKeysBinding.h" #include "mozilla/dom/MediaKeySystemAccessBinding.h" namespace mozilla { struct KeySystemConfigRequest; struct KeySystemConfig { public: using SupportedConfigsPromise = MozPromise, bool /* aIgnored */, /* IsExclusive = */ true>; using KeySystemConfigPromise = MozPromise; // EME MediaKeysRequirement: // https://www.w3.org/TR/encrypted-media/#dom-mediakeysrequirement MOZ_DEFINE_ENUM_CLASS_WITH_TOSTRING_AT_CLASS_SCOPE(Requirement, (Required, Optional, NotAllowed)); // EME MediaKeySessionType: // https://www.w3.org/TR/encrypted-media/#dom-mediakeysessiontype MOZ_DEFINE_ENUM_CLASS_WITH_TOSTRING_AT_CLASS_SCOPE(SessionType, (Temporary, PersistentLicense)); using EMECodecString = nsCString; static constexpr auto EME_CODEC_AAC = "aac"_ns; static constexpr auto EME_CODEC_OPUS = "opus"_ns; static constexpr auto EME_CODEC_VORBIS = "vorbis"_ns; static constexpr auto EME_CODEC_FLAC = "flac"_ns; static constexpr auto EME_CODEC_H264 = "h264"_ns; static constexpr auto EME_CODEC_AV1 = "av1"_ns; static constexpr auto EME_CODEC_VP8 = "vp8"_ns; static constexpr auto EME_CODEC_VP9 = "vp9"_ns; static constexpr auto EME_CODEC_HEVC = "hevc"_ns; using EMEEncryptionSchemeString = nsCString; static constexpr auto EME_ENCRYPTION_SCHEME_CENC = "cenc"_ns; static constexpr auto EME_ENCRYPTION_SCHEME_CBCS = "cbcs"_ns; // A codec can be decrypted-and-decoded by the CDM, or only decrypted // by the CDM and decoded by Gecko. Not both. struct ContainerSupport { ContainerSupport() = default; ~ContainerSupport() = default; ContainerSupport(const ContainerSupport& aOther) { mCodecsDecoded = aOther.mCodecsDecoded.Clone(); mCodecsDecrypted = aOther.mCodecsDecrypted.Clone(); } ContainerSupport& operator=(const ContainerSupport& aOther) { if (this == &aOther) { return *this; } mCodecsDecoded = aOther.mCodecsDecoded.Clone(); mCodecsDecrypted = aOther.mCodecsDecrypted.Clone(); return *this; } ContainerSupport(ContainerSupport&& aOther) = default; ContainerSupport& operator=(ContainerSupport&&) = default; bool IsSupported() const { return !mCodecsDecoded.IsEmpty() || !mCodecsDecrypted.IsEmpty(); } // True if a codec and scheme pair can be decrypted and decoded bool DecryptsAndDecodes( const EMECodecString& aCodec, const Maybe& aScheme = Nothing()) const { return CheckCodecAndSchemePair(mCodecsDecoded, aCodec, aScheme); } // True if a codec and scheme pair can be decrypted bool Decrypts(const EMECodecString& aCodec, const Maybe& aScheme = Nothing()) const { return CheckCodecAndSchemePair(mCodecsDecrypted, aCodec, aScheme); } void SetCanDecryptAndDecode( const EMECodecString& aCodec, const Maybe& aSchemes = Nothing{}) { // Can't both decrypt and decrypt-and-decode a codec. MOZ_ASSERT(!ContainsDecryptedOnlyCodec(aCodec)); // Prevent duplicates. MOZ_ASSERT(!ContainsDecryptedAndDecodedCodec(aCodec)); mCodecsDecoded.AppendElement(CodecSchemePair{aCodec, aSchemes}); } void SetCanDecrypt(const EMECodecString& aCodec, const Maybe& aSchemes = Nothing{}) { // Prevent duplicates. MOZ_ASSERT(!ContainsDecryptedOnlyCodec(aCodec)); // Can't both decrypt and decrypt-and-decode a codec. MOZ_ASSERT(!ContainsDecryptedAndDecodedCodec(aCodec)); mCodecsDecrypted.AppendElement(CodecSchemePair{aCodec, aSchemes}); } EMECodecString GetDebugInfo() const { EMECodecString info; info.AppendLiteral("decoding-and-decrypting:["); for (size_t idx = 0; idx < mCodecsDecoded.Length(); idx++) { const auto& cur = mCodecsDecoded[idx]; info.Append(cur.first); if (cur.second) { info.AppendLiteral("("); info.Append(CryptoSchemeSetToString(*cur.second)); info.AppendLiteral(")"); } else { info.AppendLiteral("(all)"); } if (idx + 1 < mCodecsDecoded.Length()) { info.AppendLiteral(","); } } info.AppendLiteral("],"); info.AppendLiteral("decrypting-only:["); for (size_t idx = 0; idx < mCodecsDecrypted.Length(); idx++) { const auto& cur = mCodecsDecrypted[idx]; info.Append(cur.first); if (cur.second) { info.AppendLiteral("("); info.Append(CryptoSchemeSetToString(*cur.second)); info.AppendLiteral(")"); } else { info.AppendLiteral("(all)"); } if (idx + 1 < mCodecsDecrypted.Length()) { info.AppendLiteral(","); } } info.AppendLiteral("]"); return info; } private: using CodecSchemePair = std::pair>; // These two arrays are exclusive, the codec in one array can't appear on // another array. If CryptoSchemeSet is nothing, that means the codec has // support for all schemes, which is our default. Setting CryptoSchemeSet // explicitly can restrict avaiable schemes for a codec. nsTArray mCodecsDecoded; nsTArray mCodecsDecrypted; bool ContainsDecryptedOnlyCodec(const EMECodecString& aCodec) const { return std::any_of( mCodecsDecrypted.begin(), mCodecsDecrypted.end(), [&](const auto& aPair) { return aPair.first.Equals(aCodec); }); } bool ContainsDecryptedAndDecodedCodec(const EMECodecString& aCodec) const { return std::any_of( mCodecsDecoded.begin(), mCodecsDecoded.end(), [&](const auto& aPair) { return aPair.first.Equals(aCodec); }); } bool CheckCodecAndSchemePair(const nsTArray& aArray, const EMECodecString& aCodec, const Maybe& aScheme) const { return std::any_of(aArray.begin(), aArray.end(), [&](const auto& aPair) { if (!aPair.first.Equals(aCodec)) { return false; } // No scheme is specified, which means accepting all schemes. if (!aPair.second || !aScheme) { return true; } return aPair.second->contains(*aScheme); }); } }; // Return true if given key system is supported on the current device. static bool Supports(const nsAString& aKeySystem); enum class DecryptionInfo : uint8_t { Software, Hardware, }; static RefPtr CreateKeySystemConfigs( const nsTArray& aRequests); static void GetGMPKeySystemConfigs(dom::Promise* aPromise); KeySystemConfig() = default; ~KeySystemConfig() = default; explicit KeySystemConfig(const KeySystemConfig& aOther) { mKeySystem = aOther.mKeySystem; mInitDataTypes = aOther.mInitDataTypes.Clone(); mPersistentState = aOther.mPersistentState; mDistinctiveIdentifier = aOther.mDistinctiveIdentifier; mSessionTypes = aOther.mSessionTypes.Clone(); mVideoRobustness = aOther.mVideoRobustness.Clone(); mAudioRobustness = aOther.mAudioRobustness.Clone(); mMP4 = aOther.mMP4; mWebM = aOther.mWebM; } KeySystemConfig& operator=(const KeySystemConfig& aOther) { if (this == &aOther) { return *this; } mKeySystem = aOther.mKeySystem; mInitDataTypes = aOther.mInitDataTypes.Clone(); mPersistentState = aOther.mPersistentState; mDistinctiveIdentifier = aOther.mDistinctiveIdentifier; mSessionTypes = aOther.mSessionTypes.Clone(); mVideoRobustness = aOther.mVideoRobustness.Clone(); mAudioRobustness = aOther.mAudioRobustness.Clone(); mMP4 = aOther.mMP4; mWebM = aOther.mWebM; return *this; } KeySystemConfig(KeySystemConfig&&) = default; KeySystemConfig& operator=(KeySystemConfig&&) = default; nsString GetDebugInfo() const; nsString mKeySystem; nsTArray mInitDataTypes; Requirement mPersistentState = Requirement::NotAllowed; Requirement mDistinctiveIdentifier = Requirement::NotAllowed; nsTArray mSessionTypes; nsTArray mVideoRobustness; nsTArray mAudioRobustness; ContainerSupport mMP4; ContainerSupport mWebM; bool mIsHDCP22Compatible = false; private: static void CreateClearKeyKeySystemConfigs( const KeySystemConfigRequest& aRequest, nsTArray& aOutConfigs); static void CreateWivineL3KeySystemConfigs( const KeySystemConfigRequest& aRequest, nsTArray& aOutConfigs); }; struct KeySystemConfigRequest final { KeySystemConfigRequest(const nsAString& aKeySystem, KeySystemConfig::DecryptionInfo aDecryption, bool aIsPrivateBrowsing) : mKeySystem(aKeySystem), mDecryption(aDecryption), mIsPrivateBrowsing(aIsPrivateBrowsing) {} const nsString mKeySystem; const KeySystemConfig::DecryptionInfo mDecryption; const bool mIsPrivateBrowsing; }; KeySystemConfig::SessionType ConvertToKeySystemConfigSessionType( dom::MediaKeySessionType aType); } // namespace mozilla #endif // DOM_MEDIA_EME_KEYSYSTEMCONFIG_H_