static bool
IsSupported(mozIGeckoMediaPluginService* aGMPService,
            const nsAString& aKeySystem,
            const MediaKeySystemConfiguration& aConfig,
            DecoderDoctorDiagnostics* aDiagnostics)
{
  if (aConfig.mInitDataType.IsEmpty() &&
      aConfig.mAudioType.IsEmpty() &&
      aConfig.mVideoType.IsEmpty()) {
    // Not an old-style request.
    return false;
  }

  // Backwards compatibility with legacy MediaKeySystemConfiguration method.
  if (!aConfig.mInitDataType.IsEmpty() &&
      !aConfig.mInitDataType.EqualsLiteral("cenc")) {
    return false;
  }
  if (!aConfig.mAudioType.IsEmpty() &&
      !IsSupportedAudio(aGMPService, aKeySystem, aConfig.mAudioType, aDiagnostics)) {
    return false;
  }
  if (!aConfig.mVideoType.IsEmpty() &&
      !IsSupportedVideo(aGMPService, aKeySystem, aConfig.mVideoType, aDiagnostics)) {
    return false;
  }

  return true;
}
static bool
GetSupportedConfig(mozIGeckoMediaPluginService* aGMPService,
                   const nsAString& aKeySystem,
                   const MediaKeySystemConfiguration& aCandidate,
                   MediaKeySystemConfiguration& aOutConfig)
{
  MediaKeySystemConfiguration config;
  config.mLabel = aCandidate.mLabel;
  if (aCandidate.mInitDataTypes.WasPassed()) {
    nsTArray<nsString> initDataTypes;
    for (const nsString& candidate : aCandidate.mInitDataTypes.Value()) {
      // All supported keySystems can handle "cenc" initDataType.
      // ClearKey also supports "keyids" and "webm" initDataTypes.
      if (candidate.EqualsLiteral("cenc")) {
        initDataTypes.AppendElement(candidate);
      } else if ((candidate.EqualsLiteral("keyids") ||
                  candidate.EqualsLiteral("webm)")) &&
                 aKeySystem.EqualsLiteral("org.w3.clearkey")) {
        initDataTypes.AppendElement(candidate);
      }
    }
    if (initDataTypes.IsEmpty()) {
      return false;
    }
    config.mInitDataTypes.Construct();
    config.mInitDataTypes.Value().Assign(initDataTypes);
  }
  if (aCandidate.mAudioCapabilities.WasPassed()) {
    nsTArray<MediaKeySystemMediaCapability> caps;
    for (const MediaKeySystemMediaCapability& cap : aCandidate.mAudioCapabilities.Value()) {
      if (IsSupportedAudio(aGMPService, aKeySystem, cap.mContentType)) {
        caps.AppendElement(cap);
      }
    }
    if (caps.IsEmpty()) {
      return false;
    }
    config.mAudioCapabilities.Construct();
    config.mAudioCapabilities.Value().Assign(caps);
  }
  if (aCandidate.mVideoCapabilities.WasPassed()) {
    nsTArray<MediaKeySystemMediaCapability> caps;
    for (const MediaKeySystemMediaCapability& cap : aCandidate.mVideoCapabilities.Value()) {
      if (IsSupportedVideo(aGMPService, aKeySystem, cap.mContentType)) {
        caps.AppendElement(cap);
      }
    }
    if (caps.IsEmpty()) {
      return false;
    }
    config.mVideoCapabilities.Construct();
    config.mVideoCapabilities.Value().Assign(caps);
  }

  aOutConfig = config;

  return true;
}
static bool
GetSupportedConfig(mozIGeckoMediaPluginService* aGMPService,
                   const nsAString& aKeySystem,
                   const MediaKeySystemConfiguration& aCandidate,
                   MediaKeySystemConfiguration& aOutConfig,
                   DecoderDoctorDiagnostics* aDiagnostics)
{
  MediaKeySystemConfiguration config;
  config.mLabel = aCandidate.mLabel;
  if (aCandidate.mInitDataTypes.WasPassed()) {
    nsTArray<nsString> initDataTypes;
    for (const nsString& candidate : aCandidate.mInitDataTypes.Value()) {
      if (IsSupportedInitDataType(candidate, aKeySystem)) {
        initDataTypes.AppendElement(candidate);
      }
    }
    if (initDataTypes.IsEmpty()) {
      return false;
    }
    config.mInitDataTypes.Construct();
    config.mInitDataTypes.Value().Assign(initDataTypes);
  }
  if (aCandidate.mAudioCapabilities.WasPassed()) {
    nsTArray<MediaKeySystemMediaCapability> caps;
    for (const MediaKeySystemMediaCapability& cap : aCandidate.mAudioCapabilities.Value()) {
      if (IsSupportedAudio(aGMPService, aKeySystem, cap.mContentType, aDiagnostics)) {
        caps.AppendElement(cap);
      }
    }
    if (caps.IsEmpty()) {
      return false;
    }
    config.mAudioCapabilities.Construct();
    config.mAudioCapabilities.Value().Assign(caps);
  }
  if (aCandidate.mVideoCapabilities.WasPassed()) {
    nsTArray<MediaKeySystemMediaCapability> caps;
    for (const MediaKeySystemMediaCapability& cap : aCandidate.mVideoCapabilities.Value()) {
      if (IsSupportedVideo(aGMPService, aKeySystem, cap.mContentType, aDiagnostics)) {
        caps.AppendElement(cap);
      }
    }
    if (caps.IsEmpty()) {
      return false;
    }
    config.mVideoCapabilities.Construct();
    config.mVideoCapabilities.Value().Assign(caps);
  }

#if defined(MOZ_WIDEVINE_EME) && defined(XP_WIN)
  // Widevine CDM doesn't include an AAC decoder. So if WMF can't decode AAC,
  // and a codec wasn't specified, be conservative and reject the MediaKeys request.
  if (aKeySystem.EqualsLiteral("com.widevine.alpha") &&
      (!aCandidate.mAudioCapabilities.WasPassed() ||
       !aCandidate.mVideoCapabilities.WasPassed()) &&
     !WMFDecoderModule::HasAAC()) {
    if (aDiagnostics) {
      aDiagnostics->SetKeySystemIssue(
        DecoderDoctorDiagnostics::eWidevineWithNoWMF);
    }
    return false;
  }
#endif

  aOutConfig = config;

  return true;
}