chromium/chromecast/renderer/media/key_systems_cast.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromecast/renderer/media/key_systems_cast.h"

#include <optional>
#include <string>

#include "base/check.h"
#include "base/command_line.h"
#include "build/build_config.h"
#include "chromecast/chromecast_buildflags.h"
#include "chromecast/media/base/key_systems_common.h"
#include "media/base/content_decryption_module.h"
#include "media/base/eme_constants.h"
#include "media/base/key_system_info.h"
#include "media/media_buildflags.h"
#include "third_party/widevine/cdm/buildflags.h"

#if BUILDFLAG(ENABLE_WIDEVINE)
#include "components/cdm/renderer/widevine_key_system_info.h"
#endif

using ::media::CdmSessionType;
using ::media::EmeConfig;
using ::media::EmeConfigRuleState;
using ::media::EmeFeatureSupport;
using ::media::EmeInitDataType;
using ::media::EmeMediaType;
using ::media::EncryptionScheme;
using ::media::SupportedCodecs;

namespace chromecast {
namespace media {
namespace {

#if BUILDFLAG(ENABLE_PLAYREADY)
class PlayReadyKeySystemInfo : public ::media::KeySystemInfo {
 public:
  PlayReadyKeySystemInfo(SupportedCodecs supported_non_secure_codecs,
                         SupportedCodecs supported_secure_codecs,
                         bool persistent_license_support)
      : supported_non_secure_codecs_(supported_non_secure_codecs),
#if BUILDFLAG(IS_ANDROID)
        supported_secure_codecs_(supported_secure_codecs),
#endif  // BUILDFLAG(IS_ANDROID)
        persistent_license_support_(persistent_license_support) {
  }

  std::string GetBaseKeySystemName() const override {
    return media::kChromecastPlayreadyKeySystem;
  }

  bool IsSupportedInitDataType(EmeInitDataType init_data_type) const override {
    return init_data_type == EmeInitDataType::CENC;
  }

  SupportedCodecs GetSupportedCodecs() const override {
    return supported_non_secure_codecs_;
  }

#if BUILDFLAG(IS_ANDROID)
  SupportedCodecs GetSupportedHwSecureCodecs() const override {
    return supported_secure_codecs_;
  }
#endif  // BUILDFLAG(IS_ANDROID)

  EmeConfig::Rule GetRobustnessConfigRule(
      const std::string& key_system,
      EmeMediaType media_type,
      const std::string& requested_robustness,
      const bool* /*hw_secure_requirement*/) const override {
    // `hw_secure_requirement` is ignored here because it's a temporary solution
    // until a larger refactoring of the key system logic is done. It also does
    // not need to account for it here because if it does introduce an
    // incompatibility at this point, it will still be caught by the rule logic
    // in KeySystemConfigSelector: crbug.com/1204284
    if (requested_robustness.empty()) {
#if BUILDFLAG(IS_ANDROID)
      return EmeConfig{.hw_secure_codecs = EmeConfigRuleState::kRequired};
#else
      return EmeConfig::SupportedRule();
#endif  // BUILDFLAG(IS_ANDROID)
    }

    // Cast-specific PlayReady implementation does not currently recognize or
    // support non-empty robustness strings.
    return EmeConfig::UnsupportedRule();
  }

  EmeConfig::Rule GetPersistentLicenseSessionSupport() const override {
    if (persistent_license_support_) {
      return EmeConfig::SupportedRule();
    } else {
      return EmeConfig::UnsupportedRule();
    }
  }

  EmeFeatureSupport GetPersistentStateSupport() const override {
    return EmeFeatureSupport::ALWAYS_ENABLED;
  }
  EmeFeatureSupport GetDistinctiveIdentifierSupport() const override {
    return EmeFeatureSupport::ALWAYS_ENABLED;
  }

  EmeConfig::Rule GetEncryptionSchemeConfigRule(
      EncryptionScheme encryption_scheme) const override {
    if (encryption_scheme == EncryptionScheme::kCenc) {
      return EmeConfig::SupportedRule();
    } else {
      return EmeConfig::UnsupportedRule();
    }
  }

 private:
  const SupportedCodecs supported_non_secure_codecs_;
#if BUILDFLAG(IS_ANDROID)
  const SupportedCodecs supported_secure_codecs_;
#endif  // BUILDFLAG(IS_ANDROID)
  const bool persistent_license_support_;
};
#endif  // BUILDFLAG(ENABLE_PLAYREADY)

#if BUILDFLAG(USE_CHROMECAST_CDMS) || BUILDFLAG(ENABLE_LIBRARY_CDMS)
SupportedCodecs GetCastEmeSupportedCodecs() {
  SupportedCodecs codecs = ::media::EME_CODEC_AAC | ::media::EME_CODEC_AVC1 |
                           ::media::EME_CODEC_VP9_PROFILE0 |
                           ::media::EME_CODEC_VP9_PROFILE2 |
                           ::media::EME_CODEC_VP8;

#if !BUILDFLAG(DISABLE_SECURE_FLAC_OPUS_DECODING)
  codecs |= ::media::EME_CODEC_FLAC | ::media::EME_CODEC_OPUS;
#endif  // BUILDFLAG(DISABLE_SECURE_FLAC_OPUS_DECODING)

#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
  codecs |= ::media::EME_CODEC_HEVC_PROFILE_MAIN;
  codecs |= ::media::EME_CODEC_HEVC_PROFILE_MAIN10;
#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)

#if BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION)
  codecs |= ::media::EME_CODEC_DOLBY_VISION_AVC;
#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
  codecs |= ::media::EME_CODEC_DOLBY_VISION_HEVC;
#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)
#endif  // BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION)

#if BUILDFLAG(ENABLE_PLATFORM_AC3_EAC3_AUDIO)
  codecs |= ::media::EME_CODEC_AC3 | ::media::EME_CODEC_EAC3;
#endif  // BUILDFLAG(ENABLE_PLATFORM_AC3_EAC3_AUDIO)

#if BUILDFLAG(ENABLE_PLATFORM_DTS_AUDIO)
  codecs |= ::media::EME_CODEC_DTS | ::media::EME_CODEC_DTSE |
            ::media::EME_CODEC_DTSXP2;
#endif  // BUILDFLAG(ENABLE_PLATFORM_DTS_AUDIO)

#if BUILDFLAG(ENABLE_PLATFORM_MPEG_H_AUDIO)
  codecs |= ::media::EME_CODEC_MPEG_H_AUDIO;
#endif  // BUILDFLAG(ENABLE_PLATFORM_MPEG_H_AUDIO)

  return codecs;
}

void AddCmaKeySystems(::media::KeySystemInfos* key_system_infos,
                      bool enable_persistent_license_support,
                      bool enable_playready) {
  // |codecs| may not be used if Widevine and Playready aren't supported.
  [[maybe_unused]] SupportedCodecs codecs = GetCastEmeSupportedCodecs();

#if BUILDFLAG(ENABLE_PLAYREADY)
  if (enable_playready) {
    key_system_infos->emplace_back(new PlayReadyKeySystemInfo(
        codecs, codecs, enable_persistent_license_support));
  }
#endif  // BUILDFLAG(ENABLE_PLAYREADY)

#if BUILDFLAG(ENABLE_WIDEVINE)
  using Robustness = cdm::WidevineKeySystemInfo::Robustness;

  const base::flat_set<EncryptionScheme> kEncryptionSchemes = {
      EncryptionScheme::kCenc, EncryptionScheme::kCbcs};

  const base::flat_set<CdmSessionType> kSessionTypes = {
      CdmSessionType::kTemporary, CdmSessionType::kPersistentLicense};

  key_system_infos->emplace_back(new cdm::WidevineKeySystemInfo(
      codecs,                        // Regular codecs.
      kEncryptionSchemes,            // Encryption schemes.
      kSessionTypes,                 // Session types.
      codecs,                        // Hardware secure codecs.
      kEncryptionSchemes,            // Hardware secure encryption schemes.
      kSessionTypes,                 // Hardware secure session types.
      Robustness::HW_SECURE_CRYPTO,  // Max audio robustness.
      Robustness::HW_SECURE_ALL,     // Max video robustness.
      // Note: On Chromecast, all CDMs may have persistent state.
      EmeFeatureSupport::ALWAYS_ENABLED,    // Persistent state.
      EmeFeatureSupport::ALWAYS_ENABLED));  // Distinctive identifier.
#endif                                      // BUILDFLAG(ENABLE_WIDEVINE)
}
#endif  // BUILDFLAG(USE_CHROMECAST_CDMS) || BUILDFLAG(ENABLE_LIBRARY_CDMS)

}  // namespace

void AddChromecastKeySystems(
    ::media::KeySystemInfos* key_system_infos,
    bool enable_persistent_license_support,
    bool enable_playready) {
#if BUILDFLAG(USE_CHROMECAST_CDMS) || BUILDFLAG(ENABLE_LIBRARY_CDMS)
  AddCmaKeySystems(key_system_infos, enable_persistent_license_support,
                   enable_playready);
#endif  // BUILDFLAG(USE_CHROMECAST_CDMS) || BUILDFLAG(ENABLE_LIBRARY_CDMS)
}

}  // namespace media
}  // namespace chromecast