LCOV - code coverage report
Current view: top level - dom/media/eme - MediaKeySystemAccess.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 6 435 1.4 %
Date: 2017-07-14 16:53:18 Functions: 0 56 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #include "mozilla/dom/MediaKeySystemAccess.h"
       8             : #include "mozilla/dom/MediaKeySystemAccessBinding.h"
       9             : #include "mozilla/dom/MediaKeySession.h"
      10             : #include "mozilla/Preferences.h"
      11             : #include "MediaContainerType.h"
      12             : #include "MediaPrefs.h"
      13             : #ifdef MOZ_FMP4
      14             : #include "MP4Decoder.h"
      15             : #endif
      16             : #ifdef XP_WIN
      17             : #include "WMFDecoderModule.h"
      18             : #endif
      19             : #include "nsContentCID.h"
      20             : #include "nsServiceManagerUtils.h"
      21             : #include "mozIGeckoMediaPluginService.h"
      22             : #include "VideoUtils.h"
      23             : #include "mozilla/Services.h"
      24             : #include "nsIObserverService.h"
      25             : #include "mozilla/EMEUtils.h"
      26             : #include "GMPUtils.h"
      27             : #include "nsAppDirectoryServiceDefs.h"
      28             : #include "nsDirectoryServiceUtils.h"
      29             : #include "nsDirectoryServiceDefs.h"
      30             : #include "nsXULAppAPI.h"
      31             : #include "DecoderDoctorDiagnostics.h"
      32             : #include "WebMDecoder.h"
      33             : #include "mozilla/StaticPtr.h"
      34             : #include "mozilla/ClearOnShutdown.h"
      35             : #include "nsUnicharUtils.h"
      36             : #include "mozilla/dom/MediaSource.h"
      37             : #ifdef MOZ_WIDGET_ANDROID
      38             : #include "FennecJNIWrappers.h"
      39             : #endif
      40             : #include <functional>
      41             : 
      42             : namespace mozilla {
      43             : namespace dom {
      44             : 
      45           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeySystemAccess,
      46             :                                       mParent)
      47           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeySystemAccess)
      48           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeySystemAccess)
      49           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeySystemAccess)
      50           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      51           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      52           0 : NS_INTERFACE_MAP_END
      53             : 
      54             : static nsCString
      55             : ToCString(const MediaKeySystemConfiguration& aConfig);
      56             : 
      57           0 : MediaKeySystemAccess::MediaKeySystemAccess(nsPIDOMWindowInner* aParent,
      58             :                                            const nsAString& aKeySystem,
      59           0 :                                            const MediaKeySystemConfiguration& aConfig)
      60             :   : mParent(aParent)
      61             :   , mKeySystem(aKeySystem)
      62           0 :   , mConfig(aConfig)
      63             : {
      64           0 :   EME_LOG("Created MediaKeySystemAccess for keysystem=%s config=%s",
      65             :           NS_ConvertUTF16toUTF8(mKeySystem).get(), mozilla::dom::ToCString(mConfig).get());
      66           0 : }
      67             : 
      68           0 : MediaKeySystemAccess::~MediaKeySystemAccess()
      69             : {
      70           0 : }
      71             : 
      72             : JSObject*
      73           0 : MediaKeySystemAccess::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
      74             : {
      75           0 :   return MediaKeySystemAccessBinding::Wrap(aCx, this, aGivenProto);
      76             : }
      77             : 
      78             : nsPIDOMWindowInner*
      79           0 : MediaKeySystemAccess::GetParentObject() const
      80             : {
      81           0 :   return mParent;
      82             : }
      83             : 
      84             : void
      85           0 : MediaKeySystemAccess::GetKeySystem(nsString& aOutKeySystem) const
      86             : {
      87           0 :   aOutKeySystem.Assign(mKeySystem);
      88           0 : }
      89             : 
      90             : void
      91           0 : MediaKeySystemAccess::GetConfiguration(MediaKeySystemConfiguration& aConfig)
      92             : {
      93           0 :   aConfig = mConfig;
      94           0 : }
      95             : 
      96             : already_AddRefed<Promise>
      97           0 : MediaKeySystemAccess::CreateMediaKeys(ErrorResult& aRv)
      98             : {
      99             :   RefPtr<MediaKeys> keys(new MediaKeys(mParent,
     100             :                                        mKeySystem,
     101           0 :                                        mConfig));
     102           0 :   return keys->Init(aRv);
     103             : }
     104             : 
     105             : static bool
     106           0 : HavePluginForKeySystem(const nsCString& aKeySystem)
     107             : {
     108           0 :   nsCString api = MediaPrefs::EMEChromiumAPIEnabled()
     109           0 :                     ? NS_LITERAL_CSTRING(CHROMIUM_CDM_API)
     110           0 :                     : NS_LITERAL_CSTRING(GMP_API_DECRYPTOR);
     111             : 
     112           0 :   bool havePlugin = HaveGMPFor(api, { aKeySystem });
     113             : #ifdef MOZ_WIDGET_ANDROID
     114             :   // Check if we can use MediaDrm for this keysystem.
     115             :   if (!havePlugin) {
     116             :     havePlugin = mozilla::java::MediaDrmProxy::IsSchemeSupported(aKeySystem);
     117             :   }
     118             : #endif
     119           0 :   return havePlugin;
     120             : }
     121             : 
     122             : static MediaKeySystemStatus
     123           0 : EnsureCDMInstalled(const nsAString& aKeySystem,
     124             :                     nsACString& aOutMessage)
     125             : {
     126           0 :   if (!HavePluginForKeySystem(NS_ConvertUTF16toUTF8(aKeySystem))) {
     127           0 :     aOutMessage = NS_LITERAL_CSTRING("CDM is not installed");
     128           0 :     return MediaKeySystemStatus::Cdm_not_installed;
     129             :   }
     130             : 
     131           0 :   return MediaKeySystemStatus::Available;
     132             : }
     133             : 
     134             : /* static */
     135             : MediaKeySystemStatus
     136           0 : MediaKeySystemAccess::GetKeySystemStatus(const nsAString& aKeySystem,
     137             :                                          nsACString& aOutMessage)
     138             : {
     139           0 :   MOZ_ASSERT(MediaPrefs::EMEEnabled() || IsClearkeyKeySystem(aKeySystem));
     140             : 
     141           0 :   if (IsClearkeyKeySystem(aKeySystem)) {
     142           0 :     return EnsureCDMInstalled(aKeySystem, aOutMessage);
     143             :   }
     144             : 
     145           0 :   if (IsWidevineKeySystem(aKeySystem)) {
     146           0 :     if (Preferences::GetBool("media.gmp-widevinecdm.visible", false)) {
     147           0 :       if (!Preferences::GetBool("media.gmp-widevinecdm.enabled", false)) {
     148           0 :         aOutMessage = NS_LITERAL_CSTRING("Widevine EME disabled");
     149           0 :         return MediaKeySystemStatus::Cdm_disabled;
     150             :       }
     151           0 :       return EnsureCDMInstalled(aKeySystem, aOutMessage);
     152             : #ifdef MOZ_WIDGET_ANDROID
     153             :     } else if (Preferences::GetBool("media.mediadrm-widevinecdm.visible", false)) {
     154             :         nsCString keySystem = NS_ConvertUTF16toUTF8(aKeySystem);
     155             :         bool supported = mozilla::java::MediaDrmProxy::IsSchemeSupported(keySystem);
     156             :         if (!supported) {
     157             :           aOutMessage = NS_LITERAL_CSTRING("KeySystem or Minimum API level not met for Widevine EME");
     158             :           return MediaKeySystemStatus::Cdm_not_supported;
     159             :         }
     160             :         return MediaKeySystemStatus::Available;
     161             : #endif
     162             :     }
     163             :   }
     164             : 
     165           0 :   return MediaKeySystemStatus::Cdm_not_supported;
     166             : }
     167             : 
     168             : typedef nsCString EMECodecString;
     169             : 
     170           3 : static NS_NAMED_LITERAL_CSTRING(EME_CODEC_AAC, "aac");
     171           3 : static NS_NAMED_LITERAL_CSTRING(EME_CODEC_OPUS, "opus");
     172           3 : static NS_NAMED_LITERAL_CSTRING(EME_CODEC_VORBIS, "vorbis");
     173           3 : static NS_NAMED_LITERAL_CSTRING(EME_CODEC_H264, "h264");
     174           3 : static NS_NAMED_LITERAL_CSTRING(EME_CODEC_VP8, "vp8");
     175           3 : static NS_NAMED_LITERAL_CSTRING(EME_CODEC_VP9, "vp9");
     176             : 
     177             : EMECodecString
     178           0 : ToEMEAPICodecString(const nsString& aCodec)
     179             : {
     180           0 :   if (IsAACCodecString(aCodec)) {
     181           0 :     return EME_CODEC_AAC;
     182             :   }
     183           0 :   if (aCodec.EqualsLiteral("opus")) {
     184           0 :     return EME_CODEC_OPUS;
     185             :   }
     186           0 :   if (aCodec.EqualsLiteral("vorbis")) {
     187           0 :     return EME_CODEC_VORBIS;
     188             :   }
     189           0 :   if (IsH264CodecString(aCodec)) {
     190           0 :     return EME_CODEC_H264;
     191             :   }
     192           0 :   if (IsVP8CodecString(aCodec)) {
     193           0 :     return EME_CODEC_VP8;
     194             :   }
     195           0 :   if (IsVP9CodecString(aCodec)) {
     196           0 :     return EME_CODEC_VP9;
     197             :   }
     198           0 :   return EmptyCString();
     199             : }
     200             : 
     201             : // A codec can be decrypted-and-decoded by the CDM, or only decrypted
     202             : // by the CDM and decoded by Gecko. Not both.
     203           0 : struct KeySystemContainerSupport
     204             : {
     205           0 :   bool IsSupported() const
     206             :   {
     207           0 :     return !mCodecsDecoded.IsEmpty() || !mCodecsDecrypted.IsEmpty();
     208             :   }
     209             : 
     210             :   // CDM decrypts and decodes using a DRM robust decoder, and passes decoded
     211             :   // samples back to Gecko for rendering.
     212           0 :   bool DecryptsAndDecodes(EMECodecString aCodec) const
     213             :   {
     214           0 :     return mCodecsDecoded.Contains(aCodec);
     215             :   }
     216             : 
     217             :   // CDM decrypts and passes the decrypted samples back to Gecko for decoding.
     218           0 :   bool Decrypts(EMECodecString aCodec) const
     219             :   {
     220           0 :     return mCodecsDecrypted.Contains(aCodec);
     221             :   }
     222             : 
     223           0 :   void SetCanDecryptAndDecode(EMECodecString aCodec)
     224             :   {
     225             :     // Can't both decrypt and decrypt-and-decode a codec.
     226           0 :     MOZ_ASSERT(!Decrypts(aCodec));
     227             :     // Prevent duplicates.
     228           0 :     MOZ_ASSERT(!DecryptsAndDecodes(aCodec));
     229           0 :     mCodecsDecoded.AppendElement(aCodec);
     230           0 :   }
     231             : 
     232           0 :   void SetCanDecrypt(EMECodecString aCodec)
     233             :   {
     234             :     // Prevent duplicates.
     235           0 :     MOZ_ASSERT(!Decrypts(aCodec));
     236             :     // Can't both decrypt and decrypt-and-decode a codec.
     237           0 :     MOZ_ASSERT(!DecryptsAndDecodes(aCodec));
     238           0 :     mCodecsDecrypted.AppendElement(aCodec);
     239           0 :   }
     240             : 
     241             : private:
     242             :   nsTArray<EMECodecString> mCodecsDecoded;
     243             :   nsTArray<EMECodecString> mCodecsDecrypted;
     244             : };
     245             : 
     246             : enum class KeySystemFeatureSupport
     247             : {
     248             :   Prohibited = 1,
     249             :   Requestable = 2,
     250             :   Required = 3,
     251             : };
     252             : 
     253           0 : struct KeySystemConfig
     254             : {
     255             :   nsString mKeySystem;
     256             :   nsTArray<nsString> mInitDataTypes;
     257             :   KeySystemFeatureSupport mPersistentState = KeySystemFeatureSupport::Prohibited;
     258             :   KeySystemFeatureSupport mDistinctiveIdentifier = KeySystemFeatureSupport::Prohibited;
     259             :   nsTArray<MediaKeySessionType> mSessionTypes;
     260             :   nsTArray<nsString> mVideoRobustness;
     261             :   nsTArray<nsString> mAudioRobustness;
     262             :   KeySystemContainerSupport mMP4;
     263             :   KeySystemContainerSupport mWebM;
     264             : };
     265             : 
     266             : static nsTArray<KeySystemConfig>
     267           0 : GetSupportedKeySystems()
     268             : {
     269           0 :   nsTArray<KeySystemConfig> keySystemConfigs;
     270             : 
     271             :   {
     272           0 :     if (HavePluginForKeySystem(kEMEKeySystemClearkey)) {
     273           0 :       KeySystemConfig clearkey;
     274           0 :       clearkey.mKeySystem = NS_ConvertUTF8toUTF16(kEMEKeySystemClearkey);
     275           0 :       clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc"));
     276           0 :       clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("keyids"));
     277           0 :       clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("webm"));
     278           0 :       clearkey.mPersistentState = KeySystemFeatureSupport::Requestable;
     279           0 :       clearkey.mDistinctiveIdentifier = KeySystemFeatureSupport::Prohibited;
     280           0 :       clearkey.mSessionTypes.AppendElement(MediaKeySessionType::Temporary);
     281           0 :       if (MediaPrefs::ClearKeyPersistentLicenseEnabled()) {
     282           0 :         clearkey.mSessionTypes.AppendElement(MediaKeySessionType::Persistent_license);
     283             :       }
     284             : #if defined(XP_WIN)
     285             :       // Clearkey CDM uses WMF's H.264 decoder on Windows.
     286             :       if (WMFDecoderModule::HasH264()) {
     287             :         clearkey.mMP4.SetCanDecryptAndDecode(EME_CODEC_H264);
     288             :       } else {
     289             :         clearkey.mMP4.SetCanDecrypt(EME_CODEC_H264);
     290             :       }
     291             : #else
     292           0 :       clearkey.mMP4.SetCanDecrypt(EME_CODEC_H264);
     293             : #endif
     294           0 :       clearkey.mMP4.SetCanDecrypt(EME_CODEC_AAC);
     295           0 :       if (Preferences::GetBool("media.eme.vp9-in-mp4.enabled", false)) {
     296           0 :         clearkey.mMP4.SetCanDecrypt(EME_CODEC_VP9);
     297             :       }
     298           0 :       clearkey.mWebM.SetCanDecrypt(EME_CODEC_VORBIS);
     299           0 :       clearkey.mWebM.SetCanDecrypt(EME_CODEC_OPUS);
     300           0 :       clearkey.mWebM.SetCanDecrypt(EME_CODEC_VP8);
     301           0 :       clearkey.mWebM.SetCanDecrypt(EME_CODEC_VP9);
     302           0 :       keySystemConfigs.AppendElement(Move(clearkey));
     303             :     }
     304             :   }
     305             :   {
     306           0 :     if (HavePluginForKeySystem(kEMEKeySystemWidevine)) {
     307           0 :       KeySystemConfig widevine;
     308           0 :       widevine.mKeySystem = NS_ConvertUTF8toUTF16(kEMEKeySystemWidevine);
     309           0 :       widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc"));
     310           0 :       widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("keyids"));
     311           0 :       widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("webm"));
     312           0 :       widevine.mPersistentState = KeySystemFeatureSupport::Requestable;
     313           0 :       widevine.mDistinctiveIdentifier = KeySystemFeatureSupport::Prohibited;
     314           0 :       widevine.mSessionTypes.AppendElement(MediaKeySessionType::Temporary);
     315             : #ifdef MOZ_WIDGET_ANDROID
     316             :       widevine.mSessionTypes.AppendElement(MediaKeySessionType::Persistent_license);
     317             : #endif
     318           0 :       widevine.mAudioRobustness.AppendElement(NS_LITERAL_STRING("SW_SECURE_CRYPTO"));
     319           0 :       widevine.mVideoRobustness.AppendElement(NS_LITERAL_STRING("SW_SECURE_CRYPTO"));
     320           0 :       widevine.mVideoRobustness.AppendElement(NS_LITERAL_STRING("SW_SECURE_DECODE"));
     321             : #if defined(XP_WIN)
     322             :       // Widevine CDM doesn't include an AAC decoder. So if WMF can't
     323             :       // decode AAC, and a codec wasn't specified, be conservative
     324             :       // and reject the MediaKeys request, since we assume Widevine
     325             :       // will be used with AAC.
     326             :       if (WMFDecoderModule::HasAAC()) {
     327             :         widevine.mMP4.SetCanDecrypt(EME_CODEC_AAC);
     328             :       }
     329             : #elif !defined(MOZ_WIDGET_ANDROID)
     330           0 :       widevine.mMP4.SetCanDecrypt(EME_CODEC_AAC);
     331             : #endif
     332             : 
     333             : #if defined(MOZ_WIDGET_ANDROID)
     334             :       using namespace mozilla::java;
     335             :       // MediaDrm.isCryptoSchemeSupported only allows passing
     336             :       // "video/mp4" or "video/webm" for mimetype string.
     337             :       // See https://developer.android.com/reference/android/media/MediaDrm.html#isCryptoSchemeSupported(java.util.UUID, java.lang.String)
     338             :       // for more detail.
     339             :       typedef struct {
     340             :         const nsCString& mMimeType;
     341             :         const nsCString& mEMECodecType;
     342             :         const char16_t* mCodecType;
     343             :         KeySystemContainerSupport* mSupportType;
     344             :       } DataForValidation;
     345             : 
     346             :       DataForValidation validationList[] = {
     347             :         { nsCString("video/mp4"), EME_CODEC_H264, MediaDrmProxy::AVC, &widevine.mMP4 },
     348             :         { nsCString("video/mp4"), EME_CODEC_VP9, MediaDrmProxy::AVC, &widevine.mMP4 },
     349             :         { nsCString("audio/mp4"), EME_CODEC_AAC, MediaDrmProxy::AAC, &widevine.mMP4 },
     350             :         { nsCString("video/webm"), EME_CODEC_VP8, MediaDrmProxy::VP8, &widevine.mWebM },
     351             :         { nsCString("video/webm"), EME_CODEC_VP9, MediaDrmProxy::VP9, &widevine.mWebM},
     352             :         { nsCString("audio/webm"), EME_CODEC_VORBIS, MediaDrmProxy::VORBIS, &widevine.mWebM},
     353             :         { nsCString("audio/webm"), EME_CODEC_OPUS, MediaDrmProxy::OPUS, &widevine.mWebM},
     354             :       };
     355             : 
     356             :       for (const auto& data: validationList) {
     357             :         if (MediaDrmProxy::IsCryptoSchemeSupported(kEMEKeySystemWidevine,
     358             :                                                    data.mMimeType)) {
     359             :           if (MediaDrmProxy::CanDecode(data.mCodecType)) {
     360             :             data.mSupportType->SetCanDecryptAndDecode(data.mEMECodecType);
     361             :           } else {
     362             :             data.mSupportType->SetCanDecrypt(data.mEMECodecType);
     363             :           }
     364             :         }
     365             :       }
     366             : #else
     367           0 :       widevine.mMP4.SetCanDecryptAndDecode(EME_CODEC_H264);
     368           0 :       if (Preferences::GetBool("media.eme.vp9-in-mp4.enabled", false)) {
     369           0 :         widevine.mMP4.SetCanDecryptAndDecode(EME_CODEC_VP9);
     370             :       }
     371           0 :       widevine.mWebM.SetCanDecrypt(EME_CODEC_VORBIS);
     372           0 :       widevine.mWebM.SetCanDecrypt(EME_CODEC_OPUS);
     373           0 :       widevine.mWebM.SetCanDecryptAndDecode(EME_CODEC_VP8);
     374           0 :       widevine.mWebM.SetCanDecryptAndDecode(EME_CODEC_VP9);
     375             : #endif
     376           0 :       keySystemConfigs.AppendElement(Move(widevine));
     377             :     }
     378             :   }
     379             : 
     380           0 :   return keySystemConfigs;
     381             : }
     382             : 
     383             : static bool
     384           0 : GetKeySystemConfig(const nsAString& aKeySystem, KeySystemConfig& aOutKeySystemConfig)
     385             : {
     386           0 :   for (auto&& config : GetSupportedKeySystems()) {
     387           0 :     if (config.mKeySystem.Equals(aKeySystem)) {
     388           0 :       aOutKeySystemConfig = mozilla::Move(config);
     389           0 :       return true;
     390             :     }
     391             :   }
     392             :   // No matching key system found.
     393           0 :   return false;
     394             : }
     395             : 
     396             : /* static */
     397             : bool
     398           0 : MediaKeySystemAccess::KeySystemSupportsInitDataType(const nsAString& aKeySystem,
     399             :                                                     const nsAString& aInitDataType)
     400             : {
     401           0 :   KeySystemConfig implementation;
     402           0 :   return GetKeySystemConfig(aKeySystem, implementation) &&
     403           0 :          implementation.mInitDataTypes.Contains(aInitDataType);
     404             : }
     405             : 
     406             : enum CodecType
     407             : {
     408             :   Audio,
     409             :   Video,
     410             :   Invalid
     411             : };
     412             : 
     413             : static bool
     414           0 : CanDecryptAndDecode(const nsString& aKeySystem,
     415             :                     const nsString& aContentType,
     416             :                     CodecType aCodecType,
     417             :                     const KeySystemContainerSupport& aContainerSupport,
     418             :                     const nsTArray<EMECodecString>& aCodecs,
     419             :                     DecoderDoctorDiagnostics* aDiagnostics)
     420             : {
     421           0 :   MOZ_ASSERT(aCodecType != Invalid);
     422           0 :   for (const EMECodecString& codec : aCodecs) {
     423           0 :     MOZ_ASSERT(!codec.IsEmpty());
     424             : 
     425           0 :     if (aContainerSupport.DecryptsAndDecodes(codec)) {
     426             :       // GMP can decrypt-and-decode this codec.
     427           0 :       continue;
     428             :     }
     429             : 
     430           0 :     if (aContainerSupport.Decrypts(codec) &&
     431           0 :         NS_SUCCEEDED(MediaSource::IsTypeSupported(aContentType, aDiagnostics))) {
     432             :       // GMP can decrypt and is allowed to return compressed samples to
     433             :       // Gecko to decode, and Gecko has a decoder.
     434           0 :       continue;
     435             :     }
     436             : 
     437             :     // Neither the GMP nor Gecko can both decrypt and decode. We don't
     438             :     // support this codec.
     439             : 
     440             : #if defined(XP_WIN)
     441             :     // Widevine CDM doesn't include an AAC decoder. So if WMF can't
     442             :     // decode AAC, and a codec wasn't specified, be conservative
     443             :     // and reject the MediaKeys request, since we assume Widevine
     444             :     // will be used with AAC.
     445             :     if (codec == EME_CODEC_AAC &&
     446             :         IsWidevineKeySystem(aKeySystem) &&
     447             :         !WMFDecoderModule::HasAAC()) {
     448             :       if (aDiagnostics) {
     449             :         aDiagnostics->SetKeySystemIssue(
     450             :           DecoderDoctorDiagnostics::eWidevineWithNoWMF);
     451             :       }
     452             :     }
     453             : #endif
     454           0 :     return false;
     455             :   }
     456           0 :   return true;
     457             : }
     458             : 
     459             : static bool
     460           0 : ToSessionType(const nsAString& aSessionType, MediaKeySessionType& aOutType)
     461             : {
     462           0 :   if (aSessionType.Equals(ToString(MediaKeySessionType::Temporary))) {
     463           0 :     aOutType = MediaKeySessionType::Temporary;
     464           0 :     return true;
     465             :   }
     466           0 :   if (aSessionType.Equals(ToString(MediaKeySessionType::Persistent_license))) {
     467           0 :     aOutType = MediaKeySessionType::Persistent_license;
     468           0 :     return true;
     469             :   }
     470           0 :   return false;
     471             : }
     472             : 
     473             : // 5.2.1 Is persistent session type?
     474             : static bool
     475           0 : IsPersistentSessionType(MediaKeySessionType aSessionType)
     476             : {
     477           0 :   return aSessionType == MediaKeySessionType::Persistent_license;
     478             : }
     479             : 
     480             : CodecType
     481           0 : GetMajorType(const MediaMIMEType& aMIMEType)
     482             : {
     483           0 :   if (aMIMEType.HasAudioMajorType()) {
     484           0 :     return Audio;
     485             :   }
     486           0 :   if (aMIMEType.HasVideoMajorType()) {
     487           0 :     return Video;
     488             :   }
     489           0 :   return Invalid;
     490             : }
     491             : 
     492             : static CodecType
     493           0 : GetCodecType(const EMECodecString& aCodec)
     494             : {
     495           0 :   if (aCodec.Equals(EME_CODEC_AAC) ||
     496           0 :       aCodec.Equals(EME_CODEC_OPUS) ||
     497           0 :       aCodec.Equals(EME_CODEC_VORBIS)) {
     498           0 :     return Audio;
     499             :   }
     500           0 :   if (aCodec.Equals(EME_CODEC_H264) ||
     501           0 :       aCodec.Equals(EME_CODEC_VP8) ||
     502           0 :       aCodec.Equals(EME_CODEC_VP9)) {
     503           0 :     return Video;
     504             :   }
     505           0 :   return Invalid;
     506             : }
     507             : 
     508             : static bool
     509           0 : AllCodecsOfType(const nsTArray<EMECodecString>& aCodecs, const CodecType aCodecType)
     510             : {
     511           0 :   for (const EMECodecString& codec : aCodecs) {
     512           0 :     if (GetCodecType(codec) != aCodecType) {
     513           0 :       return false;
     514             :     }
     515             :   }
     516           0 :   return true;
     517             : }
     518             : 
     519             : static bool
     520           0 : IsParameterUnrecognized(const nsAString& aContentType)
     521             : {
     522           0 :   nsAutoString contentType(aContentType);
     523           0 :   contentType.StripWhitespace();
     524             : 
     525           0 :   nsTArray<nsString> params;
     526           0 :   nsAString::const_iterator start, end, semicolon, equalSign;
     527           0 :   contentType.BeginReading(start);
     528           0 :   contentType.EndReading(end);
     529           0 :   semicolon = start;
     530             :   // Find any substring between ';' & '='.
     531           0 :   while (semicolon != end) {
     532           0 :     if (FindCharInReadable(';', semicolon, end)) {
     533           0 :       equalSign = ++semicolon;
     534           0 :       if (FindCharInReadable('=', equalSign, end)) {
     535           0 :         params.AppendElement(Substring(semicolon, equalSign));
     536           0 :         semicolon = equalSign;
     537             :       }
     538             :     }
     539             :   }
     540             : 
     541           0 :   for (auto param : params) {
     542           0 :     if (!param.LowerCaseEqualsLiteral("codecs") &&
     543           0 :         !param.LowerCaseEqualsLiteral("profiles")) {
     544           0 :       return true;
     545             :     }
     546             :   }
     547           0 :   return false;
     548             : }
     549             : 
     550             : // 3.1.2.3 Get Supported Capabilities for Audio/Video Type
     551             : static Sequence<MediaKeySystemMediaCapability>
     552           0 : GetSupportedCapabilities(
     553             :   const CodecType aCodecType,
     554             :   const nsTArray<MediaKeySystemMediaCapability>& aRequestedCapabilities,
     555             :   const MediaKeySystemConfiguration& aPartialConfig,
     556             :   const KeySystemConfig& aKeySystem,
     557             :   DecoderDoctorDiagnostics* aDiagnostics,
     558             :   const std::function<void(const char*)>& aDeprecationLogFn)
     559             : {
     560             :   // Let local accumulated configuration be a local copy of partial configuration.
     561             :   // (Note: It's not necessary for us to maintain a local copy, as we don't need
     562             :   // to test whether capabilites from previous calls to this algorithm work with
     563             :   // the capabilities currently being considered in this call. )
     564             : 
     565             :   // Let supported media capabilities be an empty sequence of
     566             :   // MediaKeySystemMediaCapability dictionaries.
     567           0 :   Sequence<MediaKeySystemMediaCapability> supportedCapabilities;
     568             : 
     569             :   // For each requested media capability in requested media capabilities:
     570           0 :   for (const MediaKeySystemMediaCapability& capabilities : aRequestedCapabilities) {
     571             :     // Let content type be requested media capability's contentType member.
     572           0 :     const nsString& contentTypeString = capabilities.mContentType;
     573             :     // Let robustness be requested media capability's robustness member.
     574           0 :     const nsString& robustness = capabilities.mRobustness;
     575             :     // If content type is the empty string, return null.
     576           0 :     if (contentTypeString.IsEmpty()) {
     577           0 :       EME_LOG("MediaKeySystemConfiguration (label='%s') "
     578             :               "MediaKeySystemMediaCapability('%s','%s') rejected; "
     579             :               "audio or video capability has empty contentType.",
     580             :               NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(),
     581             :               NS_ConvertUTF16toUTF8(contentTypeString).get(),
     582             :               NS_ConvertUTF16toUTF8(robustness).get());
     583           0 :       return Sequence<MediaKeySystemMediaCapability>();
     584             :     }
     585             :     // If content type is an invalid or unrecognized MIME type, continue
     586             :     // to the next iteration.
     587             :     Maybe<MediaContainerType> maybeContainerType =
     588           0 :       MakeMediaContainerType(contentTypeString);
     589           0 :     if (!maybeContainerType) {
     590           0 :       EME_LOG("MediaKeySystemConfiguration (label='%s') "
     591             :               "MediaKeySystemMediaCapability('%s','%s') unsupported; "
     592             :               "failed to parse contentTypeString as MIME type.",
     593             :               NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(),
     594             :               NS_ConvertUTF16toUTF8(contentTypeString).get(),
     595             :               NS_ConvertUTF16toUTF8(robustness).get());
     596           0 :       continue;
     597             :     }
     598           0 :     const MediaContainerType& containerType = *maybeContainerType;
     599           0 :     bool invalid = false;
     600           0 :     nsTArray<EMECodecString> codecs;
     601           0 :     for (const auto& codecString : containerType.ExtendedType().Codecs().Range()) {
     602           0 :       EMECodecString emeCodec = ToEMEAPICodecString(nsString(codecString));
     603           0 :       if (emeCodec.IsEmpty()) {
     604           0 :         invalid = true;
     605           0 :         EME_LOG("MediaKeySystemConfiguration (label='%s') "
     606             :                 "MediaKeySystemMediaCapability('%s','%s') unsupported; "
     607             :                 "'%s' is an invalid codec string.",
     608             :                 NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(),
     609             :                 NS_ConvertUTF16toUTF8(contentTypeString).get(),
     610             :                 NS_ConvertUTF16toUTF8(robustness).get(),
     611             :                 NS_ConvertUTF16toUTF8(codecString).get());
     612           0 :         break;
     613             :       }
     614           0 :       codecs.AppendElement(emeCodec);
     615             :     }
     616           0 :     if (invalid) {
     617           0 :       continue;
     618             :     }
     619             : 
     620             :     // If the user agent does not support container, continue to the next iteration.
     621             :     // The case-sensitivity of string comparisons is determined by the appropriate RFC.
     622             :     // (Note: Per RFC 6838 [RFC6838], "Both top-level type and subtype names are
     623             :     // case-insensitive."'. We're using nsContentTypeParser and that is
     624             :     // case-insensitive and converts all its parameter outputs to lower case.)
     625             :     const bool isMP4 =
     626           0 :       DecoderTraits::IsMP4SupportedType(containerType, aDiagnostics);
     627           0 :     if (isMP4 && !aKeySystem.mMP4.IsSupported()) {
     628           0 :       EME_LOG("MediaKeySystemConfiguration (label='%s') "
     629             :               "MediaKeySystemMediaCapability('%s','%s') unsupported; "
     630             :               "MP4 requested but unsupported.",
     631             :               NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(),
     632             :               NS_ConvertUTF16toUTF8(contentTypeString).get(),
     633             :               NS_ConvertUTF16toUTF8(robustness).get());
     634           0 :       continue;
     635             :     }
     636           0 :     const bool isWebM = WebMDecoder::IsSupportedType(containerType);
     637           0 :     if (isWebM && !aKeySystem.mWebM.IsSupported()) {
     638           0 :       EME_LOG("MediaKeySystemConfiguration (label='%s') "
     639             :               "MediaKeySystemMediaCapability('%s','%s') unsupported; "
     640             :               "WebM requested but unsupported.",
     641             :               NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(),
     642             :               NS_ConvertUTF16toUTF8(contentTypeString).get(),
     643             :               NS_ConvertUTF16toUTF8(robustness).get());
     644           0 :       continue;
     645             :     }
     646           0 :     if (!isMP4 && !isWebM) {
     647           0 :       EME_LOG("MediaKeySystemConfiguration (label='%s') "
     648             :               "MediaKeySystemMediaCapability('%s','%s') unsupported; "
     649             :               "Unsupported or unrecognized container requested.",
     650             :               NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(),
     651             :               NS_ConvertUTF16toUTF8(contentTypeString).get(),
     652             :               NS_ConvertUTF16toUTF8(robustness).get());
     653           0 :       continue;
     654             :     }
     655             : 
     656             :     // Let parameters be the RFC 6381[RFC6381] parameters, if any, specified by
     657             :     // content type.
     658             :     // If the user agent does not recognize one or more parameters, continue to
     659             :     // the next iteration.
     660           0 :     if (IsParameterUnrecognized(contentTypeString)) {
     661           0 :       continue;
     662             :     }
     663             : 
     664             :     // Let media types be the set of codecs and codec constraints specified by
     665             :     // parameters. The case-sensitivity of string comparisons is determined by
     666             :     // the appropriate RFC or other specification.
     667             :     // (Note: codecs array is 'parameter').
     668             : 
     669             :     // If media types is empty:
     670           0 :     if (codecs.IsEmpty()) {
     671             :       // Log deprecation warning to encourage authors to not do this!
     672           0 :       aDeprecationLogFn("MediaEMENoCodecsDeprecatedWarning");
     673             :       // TODO: Remove this once we're sure it doesn't break the web.
     674             :       // If container normatively implies a specific set of codecs and codec constraints:
     675             :       // Let parameters be that set.
     676           0 :       if (isMP4) {
     677           0 :         if (aCodecType == Audio) {
     678           0 :           codecs.AppendElement(EME_CODEC_AAC);
     679           0 :         } else if (aCodecType == Video) {
     680           0 :           codecs.AppendElement(EME_CODEC_H264);
     681             :         }
     682           0 :       } else if (isWebM) {
     683           0 :         if (aCodecType == Audio) {
     684           0 :           codecs.AppendElement(EME_CODEC_VORBIS);
     685           0 :         } else if (aCodecType == Video) {
     686           0 :           codecs.AppendElement(EME_CODEC_VP8);
     687             :         }
     688             :       }
     689             :       // Otherwise: Continue to the next iteration.
     690             :       // (Note: all containers we support have implied codecs, so don't continue here.)
     691             :     }
     692             : 
     693             :     // If container type is not strictly a audio/video type, continue to the next iteration.
     694           0 :     const auto majorType = GetMajorType(containerType.Type());
     695           0 :     if (majorType == Invalid) {
     696           0 :       EME_LOG("MediaKeySystemConfiguration (label='%s') "
     697             :               "MediaKeySystemMediaCapability('%s','%s') unsupported; "
     698             :               "MIME type is not an audio or video MIME type.",
     699             :               NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(),
     700             :               NS_ConvertUTF16toUTF8(contentTypeString).get(),
     701             :               NS_ConvertUTF16toUTF8(robustness).get());
     702           0 :       continue;
     703             :     }
     704           0 :     if (majorType != aCodecType || !AllCodecsOfType(codecs, aCodecType)) {
     705           0 :       EME_LOG("MediaKeySystemConfiguration (label='%s') "
     706             :               "MediaKeySystemMediaCapability('%s','%s') unsupported; "
     707             :               "MIME type mixes audio codecs in video capabilities "
     708             :               "or video codecs in audio capabilities.",
     709             :               NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(),
     710             :               NS_ConvertUTF16toUTF8(contentTypeString).get(),
     711             :               NS_ConvertUTF16toUTF8(robustness).get());
     712           0 :       continue;
     713             :     }
     714             :     // If robustness is not the empty string and contains an unrecognized
     715             :     // value or a value not supported by implementation, continue to the
     716             :     // next iteration. String comparison is case-sensitive.
     717           0 :     if (!robustness.IsEmpty()) {
     718           0 :       if (majorType == Audio && !aKeySystem.mAudioRobustness.Contains(robustness)) {
     719           0 :         EME_LOG("MediaKeySystemConfiguration (label='%s') "
     720             :                 "MediaKeySystemMediaCapability('%s','%s') unsupported; "
     721             :                 "unsupported robustness string.",
     722             :                 NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(),
     723             :                 NS_ConvertUTF16toUTF8(contentTypeString).get(),
     724             :                 NS_ConvertUTF16toUTF8(robustness).get());
     725           0 :         continue;
     726             :       }
     727           0 :       if (majorType == Video && !aKeySystem.mVideoRobustness.Contains(robustness)) {
     728           0 :         EME_LOG("MediaKeySystemConfiguration (label='%s') "
     729             :                 "MediaKeySystemMediaCapability('%s','%s') unsupported; "
     730             :                 "unsupported robustness string.",
     731             :                 NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(),
     732             :                 NS_ConvertUTF16toUTF8(contentTypeString).get(),
     733             :                 NS_ConvertUTF16toUTF8(robustness).get());
     734           0 :         continue;
     735             :       }
     736             :       // Note: specified robustness requirements are satisfied.
     737             :     }
     738             : 
     739             :     // If the user agent and implementation definitely support playback of
     740             :     // encrypted media data for the combination of container, media types,
     741             :     // robustness and local accumulated configuration in combination with
     742             :     // restrictions...
     743           0 :     const auto& containerSupport = isMP4 ? aKeySystem.mMP4 : aKeySystem.mWebM;
     744           0 :     if (!CanDecryptAndDecode(aKeySystem.mKeySystem,
     745             :                              contentTypeString,
     746             :                              majorType,
     747             :                              containerSupport,
     748             :                              codecs,
     749             :                              aDiagnostics)) {
     750           0 :         EME_LOG("MediaKeySystemConfiguration (label='%s') "
     751             :                 "MediaKeySystemMediaCapability('%s','%s') unsupported; "
     752             :                 "codec unsupported by CDM requested.",
     753             :                 NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(),
     754             :                 NS_ConvertUTF16toUTF8(contentTypeString).get(),
     755             :                 NS_ConvertUTF16toUTF8(robustness).get());
     756           0 :         continue;
     757             :     }
     758             : 
     759             :     // ... add requested media capability to supported media capabilities.
     760           0 :     if (!supportedCapabilities.AppendElement(capabilities, mozilla::fallible)) {
     761           0 :       NS_WARNING("GetSupportedCapabilities: Malloc failure");
     762           0 :       return Sequence<MediaKeySystemMediaCapability>();
     763             :     }
     764             : 
     765             :     // Note: omitting steps 3.13.2, our robustness is not sophisticated enough
     766             :     // to require considering all requirements together.
     767             :   }
     768           0 :   return Move(supportedCapabilities);
     769             : }
     770             : 
     771             : // "Get Supported Configuration and Consent" algorithm, steps 4-7 for
     772             : // distinctive identifier, and steps 8-11 for persistent state. The steps
     773             : // are the same for both requirements/features, so we factor them out into
     774             : // a single function.
     775             : static bool
     776           0 : CheckRequirement(const MediaKeysRequirement aRequirement,
     777             :                  const KeySystemFeatureSupport aFeatureSupport,
     778             :                  MediaKeysRequirement& aOutRequirement)
     779             : {
     780             :   // Let requirement be the value of candidate configuration's member.
     781           0 :   MediaKeysRequirement requirement = aRequirement;
     782             :   // If requirement is "optional" and feature is not allowed according to
     783             :   // restrictions, set requirement to "not-allowed".
     784           0 :   if (aRequirement == MediaKeysRequirement::Optional &&
     785             :       aFeatureSupport == KeySystemFeatureSupport::Prohibited) {
     786           0 :     requirement = MediaKeysRequirement::Not_allowed;
     787             :   }
     788             : 
     789             :   // Follow the steps for requirement from the following list:
     790           0 :   switch (requirement) {
     791             :     case MediaKeysRequirement::Required: {
     792             :       // If the implementation does not support use of requirement in combination
     793             :       // with accumulated configuration and restrictions, return NotSupported.
     794           0 :       if (aFeatureSupport == KeySystemFeatureSupport::Prohibited) {
     795           0 :         return false;
     796             :       }
     797           0 :       break;
     798             :     }
     799             :     case MediaKeysRequirement::Optional: {
     800             :       // Continue with the following steps.
     801           0 :       break;
     802             :     }
     803             :     case MediaKeysRequirement::Not_allowed: {
     804             :       // If the implementation requires use of feature in combination with
     805             :       // accumulated configuration and restrictions, return NotSupported.
     806           0 :       if (aFeatureSupport == KeySystemFeatureSupport::Required) {
     807           0 :         return false;
     808             :       }
     809           0 :       break;
     810             :     }
     811             :     default: {
     812           0 :       return false;
     813             :     }
     814             :   }
     815             : 
     816             :   // Set the requirement member of accumulated configuration to equal
     817             :   // calculated requirement.
     818           0 :   aOutRequirement = requirement;
     819             : 
     820           0 :   return true;
     821             : }
     822             : 
     823             : // 3.1.2.2, step 12
     824             : // Follow the steps for the first matching condition from the following list:
     825             : // If the sessionTypes member is present in candidate configuration.
     826             : // Let session types be candidate configuration's sessionTypes member.
     827             : // Otherwise let session types be ["temporary"].
     828             : // Note: This returns an empty array on malloc failure.
     829             : static Sequence<nsString>
     830           0 : UnboxSessionTypes(const Optional<Sequence<nsString>>& aSessionTypes)
     831             : {
     832           0 :   Sequence<nsString> sessionTypes;
     833           0 :   if (aSessionTypes.WasPassed()) {
     834           0 :     sessionTypes = aSessionTypes.Value();
     835             :   } else {
     836             :     // Note: fallible. Results in an empty array.
     837           0 :     sessionTypes.AppendElement(ToString(MediaKeySessionType::Temporary),
     838           0 :                                mozilla::fallible);
     839             :   }
     840           0 :   return sessionTypes;
     841             : }
     842             : 
     843             : // 3.1.2.2 Get Supported Configuration and Consent
     844             : static bool
     845           0 : GetSupportedConfig(const KeySystemConfig& aKeySystem,
     846             :                    const MediaKeySystemConfiguration& aCandidate,
     847             :                    MediaKeySystemConfiguration& aOutConfig,
     848             :                    DecoderDoctorDiagnostics* aDiagnostics,
     849             :                    bool aInPrivateBrowsing,
     850             :                    const std::function<void(const char*)>& aDeprecationLogFn)
     851             : {
     852             :   // Let accumulated configuration be a new MediaKeySystemConfiguration dictionary.
     853           0 :   MediaKeySystemConfiguration config;
     854             :   // Set the label member of accumulated configuration to equal the label member of
     855             :   // candidate configuration.
     856           0 :   config.mLabel = aCandidate.mLabel;
     857             :   // If the initDataTypes member of candidate configuration is non-empty, run the
     858             :   // following steps:
     859           0 :   if (!aCandidate.mInitDataTypes.IsEmpty()) {
     860             :     // Let supported types be an empty sequence of DOMStrings.
     861           0 :     nsTArray<nsString> supportedTypes;
     862             :     // For each value in candidate configuration's initDataTypes member:
     863           0 :     for (const nsString& initDataType : aCandidate.mInitDataTypes) {
     864             :       // Let initDataType be the value.
     865             :       // If the implementation supports generating requests based on initDataType,
     866             :       // add initDataType to supported types. String comparison is case-sensitive.
     867             :       // The empty string is never supported.
     868           0 :       if (aKeySystem.mInitDataTypes.Contains(initDataType)) {
     869           0 :         supportedTypes.AppendElement(initDataType);
     870             :       }
     871             :     }
     872             :     // If supported types is empty, return NotSupported.
     873           0 :     if (supportedTypes.IsEmpty()) {
     874           0 :       EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
     875             :               "no supported initDataTypes provided.",
     876             :               NS_ConvertUTF16toUTF8(aCandidate.mLabel).get());
     877           0 :       return false;
     878             :     }
     879             :     // Set the initDataTypes member of accumulated configuration to supported types.
     880           0 :     if (!config.mInitDataTypes.Assign(supportedTypes)) {
     881           0 :       return false;
     882             :     }
     883             :   }
     884             : 
     885           0 :   if (!CheckRequirement(aCandidate.mDistinctiveIdentifier,
     886           0 :                         aKeySystem.mDistinctiveIdentifier,
     887             :                         config.mDistinctiveIdentifier)) {
     888           0 :     EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
     889             :             "distinctiveIdentifier requirement not satisfied.",
     890             :             NS_ConvertUTF16toUTF8(aCandidate.mLabel).get());
     891           0 :     return false;
     892             :   }
     893             : 
     894           0 :   if (!CheckRequirement(aCandidate.mPersistentState,
     895           0 :                         aKeySystem.mPersistentState,
     896             :                         config.mPersistentState)) {
     897           0 :     EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
     898             :             "persistentState requirement not satisfied.",
     899             :             NS_ConvertUTF16toUTF8(aCandidate.mLabel).get());
     900           0 :     return false;
     901             :   }
     902             : 
     903           0 :   if (config.mPersistentState == MediaKeysRequirement::Required &&
     904             :       aInPrivateBrowsing) {
     905           0 :     EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
     906             :             "persistentState requested in Private Browsing window.",
     907             :             NS_ConvertUTF16toUTF8(aCandidate.mLabel).get());
     908           0 :     return false;
     909             :   }
     910             : 
     911           0 :   Sequence<nsString> sessionTypes(UnboxSessionTypes(aCandidate.mSessionTypes));
     912           0 :   if (sessionTypes.IsEmpty()) {
     913             :     // Malloc failure.
     914           0 :     return false;
     915             :   }
     916             : 
     917             :   // For each value in session types:
     918           0 :   for (const auto& sessionTypeString : sessionTypes) {
     919             :     // Let session type be the value.
     920             :     MediaKeySessionType sessionType;
     921           0 :     if (!ToSessionType(sessionTypeString, sessionType)) {
     922             :       // (Assume invalid sessionType is unsupported as per steps below).
     923           0 :       EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
     924             :               "invalid session type specified.",
     925             :               NS_ConvertUTF16toUTF8(aCandidate.mLabel).get());
     926           0 :       return false;
     927             :     }
     928             :     // If accumulated configuration's persistentState value is "not-allowed"
     929             :     // and the Is persistent session type? algorithm returns true for session
     930             :     // type return NotSupported.
     931           0 :     if (config.mPersistentState == MediaKeysRequirement::Not_allowed &&
     932           0 :         IsPersistentSessionType(sessionType)) {
     933           0 :       EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
     934             :               "persistent session requested but keysystem doesn't"
     935             :               "support persistent state.",
     936             :               NS_ConvertUTF16toUTF8(aCandidate.mLabel).get());
     937           0 :       return false;
     938             :     }
     939             :     // If the implementation does not support session type in combination
     940             :     // with accumulated configuration and restrictions for other reasons,
     941             :     // return NotSupported.
     942           0 :     if (!aKeySystem.mSessionTypes.Contains(sessionType)) {
     943           0 :       EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
     944             :               "session type '%s' unsupported by keySystem.",
     945             :               NS_ConvertUTF16toUTF8(aCandidate.mLabel).get(),
     946             :               NS_ConvertUTF16toUTF8(sessionTypeString).get());
     947           0 :       return false;
     948             :     }
     949             :     // If accumulated configuration's persistentState value is "optional"
     950             :     // and the result of running the Is persistent session type? algorithm
     951             :     // on session type is true, change accumulated configuration's
     952             :     // persistentState value to "required".
     953           0 :     if (config.mPersistentState == MediaKeysRequirement::Optional &&
     954           0 :         IsPersistentSessionType(sessionType)) {
     955           0 :       config.mPersistentState = MediaKeysRequirement::Required;
     956             :     }
     957             :   }
     958             :   // Set the sessionTypes member of accumulated configuration to session types.
     959           0 :   config.mSessionTypes.Construct(Move(sessionTypes));
     960             : 
     961             :   // If the videoCapabilities and audioCapabilities members in candidate
     962             :   // configuration are both empty, return NotSupported.
     963           0 :   if (aCandidate.mAudioCapabilities.IsEmpty() &&
     964           0 :       aCandidate.mVideoCapabilities.IsEmpty()) {
     965             :     // TODO: Most sites using EME still don't pass capabilities, so we
     966             :     // can't reject on it yet without breaking them. So add this later.
     967             :     // Log deprecation warning to encourage authors to not do this!
     968           0 :     aDeprecationLogFn("MediaEMENoCapabilitiesDeprecatedWarning");
     969             :   }
     970             : 
     971             :   // If the videoCapabilities member in candidate configuration is non-empty:
     972           0 :   if (!aCandidate.mVideoCapabilities.IsEmpty()) {
     973             :     // Let video capabilities be the result of executing the Get Supported
     974             :     // Capabilities for Audio/Video Type algorithm on Video, candidate
     975             :     // configuration's videoCapabilities member, accumulated configuration,
     976             :     // and restrictions.
     977             :     Sequence<MediaKeySystemMediaCapability> caps =
     978             :       GetSupportedCapabilities(Video,
     979             :                                aCandidate.mVideoCapabilities,
     980             :                                config,
     981             :                                aKeySystem,
     982             :                                aDiagnostics,
     983           0 :                                aDeprecationLogFn);
     984             :     // If video capabilities is null, return NotSupported.
     985           0 :     if (caps.IsEmpty()) {
     986           0 :       EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
     987             :               "no supported video capabilities.",
     988             :               NS_ConvertUTF16toUTF8(aCandidate.mLabel).get());
     989           0 :       return false;
     990             :     }
     991             :     // Set the videoCapabilities member of accumulated configuration to video capabilities.
     992           0 :     config.mVideoCapabilities = Move(caps);
     993             :   } else {
     994             :     // Otherwise:
     995             :     // Set the videoCapabilities member of accumulated configuration to an empty sequence.
     996             :   }
     997             : 
     998             :   // If the audioCapabilities member in candidate configuration is non-empty:
     999           0 :   if (!aCandidate.mAudioCapabilities.IsEmpty()) {
    1000             :     // Let audio capabilities be the result of executing the Get Supported Capabilities
    1001             :     // for Audio/Video Type algorithm on Audio, candidate configuration's audioCapabilities
    1002             :     // member, accumulated configuration, and restrictions.
    1003             :     Sequence<MediaKeySystemMediaCapability> caps =
    1004             :       GetSupportedCapabilities(Audio,
    1005             :                                aCandidate.mAudioCapabilities,
    1006             :                                config,
    1007             :                                aKeySystem,
    1008             :                                aDiagnostics,
    1009           0 :                                aDeprecationLogFn);
    1010             :     // If audio capabilities is null, return NotSupported.
    1011           0 :     if (caps.IsEmpty()) {
    1012           0 :       EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
    1013             :               "no supported audio capabilities.",
    1014             :               NS_ConvertUTF16toUTF8(aCandidate.mLabel).get());
    1015           0 :       return false;
    1016             :     }
    1017             :     // Set the audioCapabilities member of accumulated configuration to audio capabilities.
    1018           0 :     config.mAudioCapabilities = Move(caps);
    1019             :   } else {
    1020             :     // Otherwise:
    1021             :     // Set the audioCapabilities member of accumulated configuration to an empty sequence.
    1022             :   }
    1023             : 
    1024             :   // If accumulated configuration's distinctiveIdentifier value is "optional", follow the
    1025             :   // steps for the first matching condition from the following list:
    1026           0 :   if (config.mDistinctiveIdentifier == MediaKeysRequirement::Optional) {
    1027             :     // If the implementation requires use Distinctive Identifier(s) or
    1028             :     // Distinctive Permanent Identifier(s) for any of the combinations
    1029             :     // in accumulated configuration
    1030           0 :     if (aKeySystem.mDistinctiveIdentifier == KeySystemFeatureSupport::Required) {
    1031             :       // Change accumulated configuration's distinctiveIdentifier value to "required".
    1032           0 :       config.mDistinctiveIdentifier = MediaKeysRequirement::Required;
    1033             :     } else {
    1034             :       // Otherwise, change accumulated configuration's distinctiveIdentifier
    1035             :       // value to "not-allowed".
    1036           0 :       config.mDistinctiveIdentifier = MediaKeysRequirement::Not_allowed;
    1037             :     }
    1038             :   }
    1039             : 
    1040             :   // If accumulated configuration's persistentState value is "optional", follow the
    1041             :   // steps for the first matching condition from the following list:
    1042           0 :   if (config.mPersistentState == MediaKeysRequirement::Optional) {
    1043             :     // If the implementation requires persisting state for any of the combinations
    1044             :     // in accumulated configuration
    1045           0 :     if (aKeySystem.mPersistentState == KeySystemFeatureSupport::Required) {
    1046             :       // Change accumulated configuration's persistentState value to "required".
    1047           0 :       config.mPersistentState = MediaKeysRequirement::Required;
    1048             :     } else {
    1049             :       // Otherwise, change accumulated configuration's persistentState
    1050             :       // value to "not-allowed".
    1051           0 :       config.mPersistentState = MediaKeysRequirement::Not_allowed;
    1052             :     }
    1053             :   }
    1054             : 
    1055             :   // Note: Omitting steps 20-22. We don't ask for consent.
    1056             : 
    1057             : #if defined(XP_WIN)
    1058             :   // Widevine CDM doesn't include an AAC decoder. So if WMF can't decode AAC,
    1059             :   // and a codec wasn't specified, be conservative and reject the MediaKeys request.
    1060             :   if (IsWidevineKeySystem(aKeySystem.mKeySystem) &&
    1061             :       (aCandidate.mAudioCapabilities.IsEmpty() ||
    1062             :        aCandidate.mVideoCapabilities.IsEmpty()) &&
    1063             :      !WMFDecoderModule::HasAAC()) {
    1064             :     if (aDiagnostics) {
    1065             :       aDiagnostics->SetKeySystemIssue(
    1066             :         DecoderDoctorDiagnostics::eWidevineWithNoWMF);
    1067             :     }
    1068             :     EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
    1069             :             "WMF required for Widevine decoding, but it's not available.",
    1070             :             NS_ConvertUTF16toUTF8(aCandidate.mLabel).get());
    1071             :     return false;
    1072             :   }
    1073             : #endif
    1074             : 
    1075             :   // Return accumulated configuration.
    1076           0 :   aOutConfig = config;
    1077             : 
    1078           0 :   return true;
    1079             : }
    1080             : 
    1081             : /* static */
    1082             : bool
    1083           0 : MediaKeySystemAccess::GetSupportedConfig(
    1084             :   const nsAString& aKeySystem,
    1085             :   const Sequence<MediaKeySystemConfiguration>& aConfigs,
    1086             :   MediaKeySystemConfiguration& aOutConfig,
    1087             :   DecoderDoctorDiagnostics* aDiagnostics,
    1088             :   bool aIsPrivateBrowsing,
    1089             :   const std::function<void(const char*)>& aDeprecationLogFn)
    1090             : {
    1091           0 :   KeySystemConfig implementation;
    1092           0 :   if (!GetKeySystemConfig(aKeySystem, implementation)) {
    1093           0 :     return false;
    1094             :   }
    1095           0 :   for (const MediaKeySystemConfiguration& candidate : aConfigs) {
    1096           0 :     if (mozilla::dom::GetSupportedConfig(implementation,
    1097             :                                          candidate,
    1098             :                                          aOutConfig,
    1099             :                                          aDiagnostics,
    1100             :                                          aIsPrivateBrowsing,
    1101             :                                          aDeprecationLogFn)) {
    1102           0 :       return true;
    1103             :     }
    1104             :   }
    1105             : 
    1106           0 :   return false;
    1107             : }
    1108             : 
    1109             : 
    1110             : /* static */
    1111             : void
    1112           0 : MediaKeySystemAccess::NotifyObservers(nsPIDOMWindowInner* aWindow,
    1113             :                                       const nsAString& aKeySystem,
    1114             :                                       MediaKeySystemStatus aStatus)
    1115             : {
    1116           0 :   RequestMediaKeySystemAccessNotification data;
    1117           0 :   data.mKeySystem = aKeySystem;
    1118           0 :   data.mStatus = aStatus;
    1119           0 :   nsAutoString json;
    1120           0 :   data.ToJSON(json);
    1121           0 :   EME_LOG("MediaKeySystemAccess::NotifyObservers() %s", NS_ConvertUTF16toUTF8(json).get());
    1122           0 :   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
    1123           0 :   if (obs) {
    1124           0 :     obs->NotifyObservers(aWindow, "mediakeys-request", json.get());
    1125             :   }
    1126           0 : }
    1127             : 
    1128             : static nsCString
    1129           0 : ToCString(const nsString& aString)
    1130             : {
    1131           0 :   nsCString str("'");
    1132           0 :   str.Append(NS_ConvertUTF16toUTF8(aString));
    1133           0 :   str.AppendLiteral("'");
    1134           0 :   return str;
    1135             : }
    1136             : 
    1137             : static nsCString
    1138           0 : ToCString(const MediaKeysRequirement aValue)
    1139             : {
    1140           0 :   nsCString str("'");
    1141           0 :   str.Append(nsDependentCString(
    1142           0 :     MediaKeysRequirementValues::strings[static_cast<uint32_t>(aValue)].value));
    1143           0 :   str.AppendLiteral("'");
    1144           0 :   return str;
    1145             : }
    1146             : 
    1147             : static nsCString
    1148           0 : ToCString(const MediaKeySystemMediaCapability& aValue)
    1149             : {
    1150           0 :   nsCString str;
    1151           0 :   str.AppendLiteral("{contentType=");
    1152           0 :   str.Append(ToCString(aValue.mContentType));
    1153           0 :   str.AppendLiteral(", robustness=");
    1154           0 :   str.Append(ToCString(aValue.mRobustness));
    1155           0 :   str.AppendLiteral("}");
    1156           0 :   return str;
    1157             : }
    1158             : 
    1159             : template<class Type>
    1160             : static nsCString
    1161           0 : ToCString(const Sequence<Type>& aSequence)
    1162             : {
    1163           0 :   nsCString str;
    1164           0 :   str.AppendLiteral("[");
    1165           0 :   for (size_t i = 0; i < aSequence.Length(); i++) {
    1166           0 :     if (i != 0) {
    1167           0 :       str.AppendLiteral(",");
    1168             :     }
    1169           0 :     str.Append(ToCString(aSequence[i]));
    1170             :   }
    1171           0 :   str.AppendLiteral("]");
    1172           0 :   return str;
    1173             : }
    1174             : 
    1175             : template<class Type>
    1176             : static nsCString
    1177           0 : ToCString(const Optional<Sequence<Type>>& aOptional)
    1178             : {
    1179           0 :   nsCString str;
    1180           0 :   if (aOptional.WasPassed()) {
    1181           0 :     str.Append(ToCString(aOptional.Value()));
    1182             :   } else {
    1183           0 :     str.AppendLiteral("[]");
    1184             :   }
    1185           0 :   return str;
    1186             : }
    1187             : 
    1188             : static nsCString
    1189           0 : ToCString(const MediaKeySystemConfiguration& aConfig)
    1190             : {
    1191           0 :   nsCString str;
    1192           0 :   str.AppendLiteral("{label=");
    1193           0 :   str.Append(ToCString(aConfig.mLabel));
    1194             : 
    1195           0 :   str.AppendLiteral(", initDataTypes=");
    1196           0 :   str.Append(ToCString(aConfig.mInitDataTypes));
    1197             : 
    1198           0 :   str.AppendLiteral(", audioCapabilities=");
    1199           0 :   str.Append(ToCString(aConfig.mAudioCapabilities));
    1200             : 
    1201           0 :   str.AppendLiteral(", videoCapabilities=");
    1202           0 :   str.Append(ToCString(aConfig.mVideoCapabilities));
    1203             : 
    1204           0 :   str.AppendLiteral(", distinctiveIdentifier=");
    1205           0 :   str.Append(ToCString(aConfig.mDistinctiveIdentifier));
    1206             : 
    1207           0 :   str.AppendLiteral(", persistentState=");
    1208           0 :   str.Append(ToCString(aConfig.mPersistentState));
    1209             : 
    1210           0 :   str.AppendLiteral(", sessionTypes=");
    1211           0 :   str.Append(ToCString(aConfig.mSessionTypes));
    1212             : 
    1213           0 :   str.AppendLiteral("}");
    1214             : 
    1215           0 :   return str;
    1216             : }
    1217             : 
    1218             : /* static */
    1219             : nsCString
    1220           0 : MediaKeySystemAccess::ToCString(
    1221             :   const Sequence<MediaKeySystemConfiguration>& aConfig)
    1222             : {
    1223           0 :   return mozilla::dom::ToCString(aConfig);
    1224             : }
    1225             : 
    1226             : } // namespace dom
    1227             : } // namespace mozilla

Generated by: LCOV version 1.13