KeySystemConfig.h (10157B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef DOM_MEDIA_EME_KEYSYSTEMCONFIG_H_ 8 #define DOM_MEDIA_EME_KEYSYSTEMCONFIG_H_ 9 10 #include "MediaData.h" 11 #include "mozilla/MozPromise.h" 12 #include "mozilla/dom/MediaKeySystemAccessBinding.h" 13 #include "mozilla/dom/MediaKeysBinding.h" 14 #include "nsString.h" 15 #include "nsTArray.h" 16 17 namespace mozilla { 18 19 struct KeySystemConfigRequest; 20 21 struct KeySystemConfig { 22 public: 23 using SupportedConfigsPromise = 24 MozPromise<nsTArray<KeySystemConfig>, bool /* aIgnored */, 25 /* IsExclusive = */ true>; 26 using KeySystemConfigPromise = 27 MozPromise<dom::MediaKeySystemConfiguration, bool /* aIgnored */, 28 /* IsExclusive = */ true>; 29 30 // EME MediaKeysRequirement: 31 // https://www.w3.org/TR/encrypted-media/#dom-mediakeysrequirement 32 MOZ_DEFINE_ENUM_CLASS_WITH_TOSTRING_AT_CLASS_SCOPE(Requirement, 33 (Required, Optional, 34 NotAllowed)); 35 36 // EME MediaKeySessionType: 37 // https://www.w3.org/TR/encrypted-media/#dom-mediakeysessiontype 38 MOZ_DEFINE_ENUM_CLASS_WITH_TOSTRING_AT_CLASS_SCOPE(SessionType, 39 (Temporary, 40 PersistentLicense)); 41 42 using EMECodecString = nsCString; 43 static constexpr auto EME_CODEC_AAC = "aac"_ns; 44 static constexpr auto EME_CODEC_OPUS = "opus"_ns; 45 static constexpr auto EME_CODEC_VORBIS = "vorbis"_ns; 46 static constexpr auto EME_CODEC_FLAC = "flac"_ns; 47 static constexpr auto EME_CODEC_H264 = "h264"_ns; 48 static constexpr auto EME_CODEC_AV1 = "av1"_ns; 49 static constexpr auto EME_CODEC_VP8 = "vp8"_ns; 50 static constexpr auto EME_CODEC_VP9 = "vp9"_ns; 51 static constexpr auto EME_CODEC_HEVC = "hevc"_ns; 52 53 using EMEEncryptionSchemeString = nsCString; 54 static constexpr auto EME_ENCRYPTION_SCHEME_CENC = "cenc"_ns; 55 static constexpr auto EME_ENCRYPTION_SCHEME_CBCS = "cbcs"_ns; 56 57 // A codec can be decrypted-and-decoded by the CDM, or only decrypted 58 // by the CDM and decoded by Gecko. Not both. 59 struct ContainerSupport { 60 ContainerSupport() = default; 61 ~ContainerSupport() = default; 62 ContainerSupport(const ContainerSupport& aOther) { 63 mCodecsDecoded = aOther.mCodecsDecoded.Clone(); 64 mCodecsDecrypted = aOther.mCodecsDecrypted.Clone(); 65 } 66 ContainerSupport& operator=(const ContainerSupport& aOther) { 67 if (this == &aOther) { 68 return *this; 69 } 70 mCodecsDecoded = aOther.mCodecsDecoded.Clone(); 71 mCodecsDecrypted = aOther.mCodecsDecrypted.Clone(); 72 return *this; 73 } 74 ContainerSupport(ContainerSupport&& aOther) = default; 75 ContainerSupport& operator=(ContainerSupport&&) = default; 76 77 bool IsSupported() const { 78 return !mCodecsDecoded.IsEmpty() || !mCodecsDecrypted.IsEmpty(); 79 } 80 81 // True if a codec and scheme pair can be decrypted and decoded 82 bool DecryptsAndDecodes( 83 const EMECodecString& aCodec, 84 const Maybe<CryptoScheme>& aScheme = Nothing()) const { 85 return CheckCodecAndSchemePair(mCodecsDecoded, aCodec, aScheme); 86 } 87 88 // True if a codec and scheme pair can be decrypted 89 bool Decrypts(const EMECodecString& aCodec, 90 const Maybe<CryptoScheme>& aScheme = Nothing()) const { 91 return CheckCodecAndSchemePair(mCodecsDecrypted, aCodec, aScheme); 92 } 93 94 void SetCanDecryptAndDecode( 95 const EMECodecString& aCodec, 96 const Maybe<CryptoSchemeSet>& aSchemes = Nothing{}) { 97 // Can't both decrypt and decrypt-and-decode a codec. 98 MOZ_ASSERT(!ContainsDecryptedOnlyCodec(aCodec)); 99 // Prevent duplicates. 100 MOZ_ASSERT(!ContainsDecryptedAndDecodedCodec(aCodec)); 101 102 mCodecsDecoded.AppendElement(CodecSchemePair{aCodec, aSchemes}); 103 } 104 105 void SetCanDecrypt(const EMECodecString& aCodec, 106 const Maybe<CryptoSchemeSet>& aSchemes = Nothing{}) { 107 // Prevent duplicates. 108 MOZ_ASSERT(!ContainsDecryptedOnlyCodec(aCodec)); 109 // Can't both decrypt and decrypt-and-decode a codec. 110 MOZ_ASSERT(!ContainsDecryptedAndDecodedCodec(aCodec)); 111 mCodecsDecrypted.AppendElement(CodecSchemePair{aCodec, aSchemes}); 112 } 113 114 EMECodecString GetDebugInfo() const { 115 EMECodecString info; 116 info.AppendLiteral("decoding-and-decrypting:["); 117 for (size_t idx = 0; idx < mCodecsDecoded.Length(); idx++) { 118 const auto& cur = mCodecsDecoded[idx]; 119 info.Append(cur.first); 120 if (cur.second) { 121 info.AppendLiteral("("); 122 info.Append(CryptoSchemeSetToString(*cur.second)); 123 info.AppendLiteral(")"); 124 } else { 125 info.AppendLiteral("(all)"); 126 } 127 if (idx + 1 < mCodecsDecoded.Length()) { 128 info.AppendLiteral(","); 129 } 130 } 131 info.AppendLiteral("],"); 132 info.AppendLiteral("decrypting-only:["); 133 for (size_t idx = 0; idx < mCodecsDecrypted.Length(); idx++) { 134 const auto& cur = mCodecsDecrypted[idx]; 135 info.Append(cur.first); 136 if (cur.second) { 137 info.AppendLiteral("("); 138 info.Append(CryptoSchemeSetToString(*cur.second)); 139 info.AppendLiteral(")"); 140 } else { 141 info.AppendLiteral("(all)"); 142 } 143 if (idx + 1 < mCodecsDecrypted.Length()) { 144 info.AppendLiteral(","); 145 } 146 } 147 info.AppendLiteral("]"); 148 return info; 149 } 150 151 private: 152 using CodecSchemePair = std::pair<EMECodecString, Maybe<CryptoSchemeSet>>; 153 // These two arrays are exclusive, the codec in one array can't appear on 154 // another array. If CryptoSchemeSet is nothing, that means the codec has 155 // support for all schemes, which is our default. Setting CryptoSchemeSet 156 // explicitly can restrict avaiable schemes for a codec. 157 nsTArray<CodecSchemePair> mCodecsDecoded; 158 nsTArray<CodecSchemePair> mCodecsDecrypted; 159 160 bool ContainsDecryptedOnlyCodec(const EMECodecString& aCodec) const { 161 return std::any_of( 162 mCodecsDecrypted.begin(), mCodecsDecrypted.end(), 163 [&](const auto& aPair) { return aPair.first.Equals(aCodec); }); 164 } 165 bool ContainsDecryptedAndDecodedCodec(const EMECodecString& aCodec) const { 166 return std::any_of( 167 mCodecsDecoded.begin(), mCodecsDecoded.end(), 168 [&](const auto& aPair) { return aPair.first.Equals(aCodec); }); 169 } 170 bool CheckCodecAndSchemePair(const nsTArray<CodecSchemePair>& aArray, 171 const EMECodecString& aCodec, 172 const Maybe<CryptoScheme>& aScheme) const { 173 return std::any_of(aArray.begin(), aArray.end(), [&](const auto& aPair) { 174 if (!aPair.first.Equals(aCodec)) { 175 return false; 176 } 177 // No scheme is specified, which means accepting all schemes. 178 if (!aPair.second || !aScheme) { 179 return true; 180 } 181 return aPair.second->contains(*aScheme); 182 }); 183 } 184 }; 185 186 // Return true if given key system is supported on the current device. 187 static bool Supports(const nsAString& aKeySystem); 188 189 enum class DecryptionInfo : uint8_t { 190 Software, 191 Hardware, 192 }; 193 static RefPtr<SupportedConfigsPromise> CreateKeySystemConfigs( 194 const nsTArray<KeySystemConfigRequest>& aRequests); 195 static void GetGMPKeySystemConfigs(dom::Promise* aPromise); 196 197 KeySystemConfig() = default; 198 ~KeySystemConfig() = default; 199 explicit KeySystemConfig(const KeySystemConfig& aOther) { 200 mKeySystem = aOther.mKeySystem; 201 mInitDataTypes = aOther.mInitDataTypes.Clone(); 202 mPersistentState = aOther.mPersistentState; 203 mDistinctiveIdentifier = aOther.mDistinctiveIdentifier; 204 mSessionTypes = aOther.mSessionTypes.Clone(); 205 mVideoRobustness = aOther.mVideoRobustness.Clone(); 206 mAudioRobustness = aOther.mAudioRobustness.Clone(); 207 mMP4 = aOther.mMP4; 208 mWebM = aOther.mWebM; 209 } 210 KeySystemConfig& operator=(const KeySystemConfig& aOther) { 211 if (this == &aOther) { 212 return *this; 213 } 214 mKeySystem = aOther.mKeySystem; 215 mInitDataTypes = aOther.mInitDataTypes.Clone(); 216 mPersistentState = aOther.mPersistentState; 217 mDistinctiveIdentifier = aOther.mDistinctiveIdentifier; 218 mSessionTypes = aOther.mSessionTypes.Clone(); 219 mVideoRobustness = aOther.mVideoRobustness.Clone(); 220 mAudioRobustness = aOther.mAudioRobustness.Clone(); 221 mMP4 = aOther.mMP4; 222 mWebM = aOther.mWebM; 223 return *this; 224 } 225 KeySystemConfig(KeySystemConfig&&) = default; 226 KeySystemConfig& operator=(KeySystemConfig&&) = default; 227 228 nsString GetDebugInfo() const; 229 230 nsString mKeySystem; 231 nsTArray<nsString> mInitDataTypes; 232 Requirement mPersistentState = Requirement::NotAllowed; 233 Requirement mDistinctiveIdentifier = Requirement::NotAllowed; 234 nsTArray<SessionType> mSessionTypes; 235 nsTArray<nsString> mVideoRobustness; 236 nsTArray<nsString> mAudioRobustness; 237 ContainerSupport mMP4; 238 ContainerSupport mWebM; 239 240 private: 241 static void CreateClearKeyKeySystemConfigs( 242 const KeySystemConfigRequest& aRequest, 243 nsTArray<KeySystemConfig>& aOutConfigs); 244 static void CreateWivineL3KeySystemConfigs( 245 const KeySystemConfigRequest& aRequest, 246 nsTArray<KeySystemConfig>& aOutConfigs); 247 }; 248 249 struct KeySystemConfigRequest final { 250 KeySystemConfigRequest(const nsAString& aKeySystem, 251 KeySystemConfig::DecryptionInfo aDecryption, 252 bool aIsPrivateBrowsing) 253 : mKeySystem(aKeySystem), 254 mDecryption(aDecryption), 255 mIsPrivateBrowsing(aIsPrivateBrowsing) {} 256 const nsString mKeySystem; 257 const KeySystemConfig::DecryptionInfo mDecryption; 258 const bool mIsPrivateBrowsing; 259 }; 260 261 KeySystemConfig::SessionType ConvertToKeySystemConfigSessionType( 262 dom::MediaKeySessionType aType); 263 264 } // namespace mozilla 265 266 #endif // DOM_MEDIA_EME_KEYSYSTEMCONFIG_H_