chromium/chrome/browser/media/encrypted_media_browsertest.cc

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

#include <memory>
#include <tuple>
#include <utility>

#include "base/command_line.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "chrome/browser/media/clear_key_cdm_test_helper.h"
#include "chrome/browser/media/media_browsertest.h"
#include "chrome/browser/media/test_license_server.h"
#include "chrome/browser/media/wv_test_license_server_config.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/test_launcher_utils.h"
#include "components/prefs/pref_service.h"
#include "components/ukm/test_ukm_recorder.h"
#include "components/variations/variations_switches.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "media/base/key_system_names.h"
#include "media/base/key_systems.h"
#include "media/base/media_switches.h"
#include "media/base/test_data_util.h"
#include "media/cdm/clear_key_cdm_common.h"
#include "media/cdm/supported_cdm_versions.h"
#include "media/media_buildflags.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gtest/include/gtest/gtest-spi.h"
#include "third_party/widevine/cdm/buildflags.h"
#include "third_party/widevine/cdm/widevine_cdm_common.h"
#include "ui/gl/gl_switches.h"

#if BUILDFLAG(IS_WIN)
#include "base/win/windows_version.h"
#include "chrome/browser/media/media_foundation_service_monitor.h"
#include "content/public/browser/gpu_data_manager.h"
#include "gpu/config/gpu_info.h"
#include "media/audio/win/core_audio_util_win.h"
#include "media/base/win/mf_feature_checks.h"
#endif  // BUILDFLAG(IS_WIN)

#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
const char kExternalClearKeyInitializeFailKeySystem[] =;
#endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)

// Sessions to load.
const char kNoSessionToLoad[] =;
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
const char kPersistentLicense[] =;
const char kUnknownSession[] =;
#endif

// EME-specific test results and errors.
const char kUnitTestSuccess[] =;
const char16_t kEmeUnitTestFailure16[] =;
const char kEmeNotSupportedError[] =;
const char16_t kEmeNotSupportedError16[] =;
const char16_t kEmeGenerateRequestFailed[] =;
const char16_t kEmeSessionNotFound16[] =;
const char16_t kEmeLoadFailed[] =;
const char kEmeUpdateFailed[] =;
const char16_t kEmeUpdateFailed16[] =;
const char16_t kEmeErrorEvent[] =;
const char16_t kEmeMessageUnexpectedType[] =;
const char16_t kEmeRenewalMissingHeader[] =;
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
const char kEmeSessionClosedAndError[] =;
const char kEmeSessionNotFound[] =;
#if BUILDFLAG(IS_CHROMEOS)
const char kEmeUnitTestFailure[] = "UNIT_TEST_FAILURE";
#endif
#endif

const char kDefaultEmePlayer[] =;
const char kDefaultMseOnlyEmePlayer[] =;

// The type of video src used to load media.
enum class SrcType {};

// Must be in sync with CONFIG_CHANGE_TYPE in eme_player_js/global.js
enum class ConfigChangeType {};

// Whether the video should be not played or played once or twice.
enum class PlayCount {};

Bool;
Combine;
Eq;
Not;
Pair;
UnitTest;
UnorderedElementsAre;
Values;
WithParamInterface;
Media_EME_ApiPromiseRejection;
Media_EME_CreateMediaKeys;
Media_EME_RequestMediaKeySystemAccess;
Media_EME_Usage;

// Base class for encrypted media tests.
class EncryptedMediaTestBase : public MediaBrowserTest {};

#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
// Tests encrypted media playback using ExternalClearKey key system with a
// specific library CDM interface version as test parameter:
// - int: CDM interface version to test
class ECKEncryptedMediaTest : public EncryptedMediaTestBase,
                              public WithParamInterface<int> {};

// Tests FileIO capabilities in Encrypted Media with the following test
// parameters:
// - bool: Whether the kCdmStorageDatabase feature is enabled
// - bool: Whether the kCdmStorageDatabaseMigration feature is enabled
class ECKEncryptedMediaFileIOTest
    : public EncryptedMediaTestBase,
      public WithParamInterface<std::tuple<int, bool, bool>> {};

// Tests encrypted media playback with output protection using ExternalClearKey
// key system with a specific display surface to be captured specified as the
// test parameter.
class ECKEncryptedMediaOutputProtectionTest
    : public EncryptedMediaTestBase,
      public WithParamInterface<const char*> {};

class ECKIncognitoEncryptedMediaTest : public EncryptedMediaTestBase {};

// Tests FileIO capabilities in Encrypted Media in Incognito mode with the
// following test parameters:
// - bool: Whether the kCdmStorageDatabase feature is enabled
// - bool: Whether the kCdmStorageDatabaseMigration feature is enabled
class ECKIncognitoEncryptedMediaFileIOTest
    : public EncryptedMediaTestBase,
      public WithParamInterface<std::tuple<bool, bool>> {};
#endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)

#if BUILDFLAG(IS_WIN)
// Tests encrypted media playback using ClearKey key system while
// the MediaFoundationForClear feature is enabled. This ensures
// proper renderer selection occurs when Media Foundation Renderer
// is set as the default but the playback requires another (e.g.
// default) renderer.
// TODO(crbug.com/40267198): We should create a browser test suite
// intended explicitly for Media Foundation scenarios and move
// the MFClearEncryptedMediaTest tests there.
class MFClearEncryptedMediaTest : public EncryptedMediaTestBase {
 public:
  void TestSimplePlayback(const std::string& encrypted_media) {
    RunSimpleEncryptedMediaTest(encrypted_media, media::kClearKeyKeySystem,
                                SrcType::SRC, PlayCount::ONCE);
  }

 protected:
  void SetUpCommandLine(base::CommandLine* command_line) override {
    EncryptedMediaTestBase::SetUpCommandLine(command_line);
    // Add MediaFoundationClearPlayback feature to enablement list.
    std::vector<base::test::FeatureRefAndParams> mf_clear;
    mf_clear.push_back({media::kMediaFoundationClearPlayback, {}});
    SetUpCommandLineForKeySystem(media::kExternalClearKeyKeySystem,
                                 command_line, mf_clear);
  }
};
#endif  // BUILDFLAG(IS_WIN)

// A base class for parameterized encrypted media tests. Subclasses must
// override `CurrentKeySystem()` and `CurrentSourceType()`.
class ParameterizedEncryptedMediaTestBase : public EncryptedMediaTestBase {};

// Tests encrypted media playback with a combination of parameters:
// - char*: Key system name.
// - SrcType: Use MSE or SRC.
//
// Note:
// 1. Only parameterized (*_P) tests can be used. Non-parameterized (*_F)
// tests will crash at GetParam().
// 2. For key systems backed by library CDMs, the latest CDM interface version
// supported by both the CDM and Chromium will be used.
class EncryptedMediaTest
    : public ParameterizedEncryptedMediaTestBase,
      public WithParamInterface<std::tuple<const char*, SrcType>> {};

// Similar to EncryptedMediaTest, but the source type is always MSE. This is
// needed because many tests can only work with MSE (not with SRC), e.g.
// encrypted MP4, see http://crbug.com/170793. Use this class for those tests so
// we don't have to start the test and then skip it.
class MseEncryptedMediaTest : public ParameterizedEncryptedMediaTestBase,
                              public WithParamInterface<const char*> {};

INSTANTIATE_TEST_SUITE_P();

INSTANTIATE_TEST_SUITE_P();

// External Clear Key is currently only used on platforms that use library CDMs.
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
INSTANTIATE_TEST_SUITE_P();

INSTANTIATE_TEST_SUITE_P();

INSTANTIATE_TEST_SUITE_P();
#else   // BUILDFLAG(ENABLE_LIBRARY_CDMS)
// To reduce test time, only run ClearKey SRC tests when we are not running
// ExternalClearKey SRC tests.
INSTANTIATE_TEST_SUITE_P(SRC_ClearKey,
                         EncryptedMediaTest,
                         Combine(Values(media::kClearKeyKeySystem),
                                 Values(SrcType::SRC)));
#endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)

#if BUILDFLAG(BUNDLE_WIDEVINE_CDM)
INSTANTIATE_TEST_SUITE_P(MSE_Widevine,
                         EncryptedMediaTest,
                         Combine(Values(kWidevineKeySystem),
                                 Values(SrcType::MSE)));

INSTANTIATE_TEST_SUITE_P(MSE_Widevine,
                         MseEncryptedMediaTest,
                         Values(kWidevineKeySystem));
#endif  // BUILDFLAG(BUNDLE_WIDEVINE_CDM)

IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioClearVideo_WebM) {}

IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM) {}

IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM) {}

IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VP9Video_WebM_Fullsample) {}

IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VP9Video_WebM_Subsample) {}

IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM_Opus) {}

IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM_Opus) {}

IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_Multiple_VideoAudio_WebM) {}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, Playback_AudioOnly_MP4_FLAC) {}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, Playback_AudioOnly_MP4_OPUS) {}

// TODO(crbug.com/40116010): Flaky on multiple platforms.
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
                       DISABLED_Playback_VideoOnly_MP4_VP9) {}

#if BUILDFLAG(IS_MAC)
// TODO(crbug.com/40197943): Fails on dcheck-enabled builds on 11.0.
#define MAYBE_Playback_VideoOnly_WebM_VP9Profile2
#else
#define MAYBE_Playback_VideoOnly_WebM_VP9Profile2
#endif
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest,
                       MAYBE_Playback_VideoOnly_WebM_VP9Profile2) {}

#if BUILDFLAG(IS_MAC)
// TODO(crbug.com/40197943): Fails on dcheck-enabled builds on 11.0.
#define MAYBE_Playback_VideoOnly_MP4_VP9Profile2
#else
#define MAYBE_Playback_VideoOnly_MP4_VP9Profile2
#endif
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
                       MAYBE_Playback_VideoOnly_MP4_VP9Profile2) {}

#if BUILDFLAG(ENABLE_AV1_DECODER)

IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM_AV1) {}

IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM_AV1_10bit) {}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, Playback_VideoOnly_MP4_AV1) {}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
                       Playback_VideoOnly_MP4_AV1_10bit) {}

#endif  // BUILDFLAG(ENABLE_AV1_DECODER)

IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, InvalidResponseKeyError) {}

// This is not really an "encrypted" media test. Keep it here for completeness.
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, ConfigChangeVideo_ClearToClear) {}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
                       ConfigChangeVideo_ClearToEncrypted) {}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
                       ConfigChangeVideo_EncryptedToClear) {}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
                       ConfigChangeVideo_EncryptedToEncrypted) {}

IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, FrameSizeChangeVideo) {}

// Only use MSE since this is independent to the demuxer.
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, PolicyCheck) {}

// Only use MSE since this is independent to the demuxer.
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, RemoveTemporarySession) {}

// Only use MSE since this is independent to the demuxer.
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, EncryptedMediaDisabled) {}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, Playback_Check_Ukm) {}

#if BUILDFLAG(USE_PROPRIETARY_CODECS)

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, Playback_VideoOnly_MP4) {
  TestSimplePlayback("bear-640x360-v_frag-cenc.mp4");
}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, Playback_VideoOnly_MP4_MDAT) {
  TestSimplePlayback("bear-640x360-v_frag-cenc-mdat.mp4");
}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, Playback_Encryption_CBCS) {
  TestSimplePlayback("bear-640x360-v_frag-cbcs.mp4");
}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
                       Playback_EncryptedVideo_MP4_ClearAudio_WEBM) {
  TestDifferentContainers("bear-640x360-v_frag-cenc.mp4",
                          "bear-320x240-audio-only.webm");
}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
                       Playback_ClearVideo_WEBM_EncryptedAudio_MP4) {
  TestDifferentContainers("bear-320x240-video-only.webm",
                          "bear-640x360-a_frag-cenc.mp4");
}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
                       Playback_EncryptedVideo_WEBM_EncryptedAudio_MP4) {
  TestDifferentContainers("bear-320x240-v_enc-v.webm",
                          "bear-640x360-a_frag-cenc.mp4");
}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
                       Playback_EncryptedVideo_CBCS_EncryptedAudio_CENC) {
  TestDifferentContainers("bear-640x360-v_frag-cbcs.mp4",
                          "bear-640x360-a_frag-cenc.mp4");
}

IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
                       Playback_EncryptedVideo_CENC_EncryptedAudio_CBCS) {
  TestDifferentContainers("bear-640x360-v_frag-cenc.mp4",
                          "bear-640x360-a_frag-cbcs.mp4");
}

#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)

#if BUILDFLAG(ENABLE_LIBRARY_CDMS)

// Test CDM_10 through CDM_11.
static_assert;
INSTANTIATE_TEST_SUITE_P();
INSTANTIATE_TEST_SUITE_P();
INSTANTIATE_TEST_SUITE_P();
INSTANTIATE_TEST_SUITE_P();

IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, InitializeCDMFail) {}

// TODO(crbug.com/40105240): Failing on Windows.
#if BUILDFLAG(IS_WIN)
#define MAYBE_CDMCrashDuringDecode
#else
#define MAYBE_CDMCrashDuringDecode
#endif
// When CDM crashes, we should still get a decode error and all sessions should
// be closed.
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, MAYBE_CDMCrashDuringDecode) {}

IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, PlatformVerificationTest) {}

IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaFileIOTest, FileIOTest) {}

// Intermittent leaks on ASan/LSan runs: crbug.com/889923
#if defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER)
#define MAYBE_MessageTypeTest
#else
#define MAYBE_MessageTypeTest
#endif
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, MAYBE_MessageTypeTest) {}

// Exercises Storage Path, so use ECKEncryptedMediaFileIOTest
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaFileIOTest, LoadPersistentLicense) {}

// Exercises Storage Path, so use ECKEncryptedMediaFileIOTest
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaFileIOTest, LoadUnknownSession) {}

IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, LoadSessionAfterClose) {}

IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, DecryptOnly_VideoAudio_WebM) {}

IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, DecryptOnly_VideoOnly_MP4_VP9) {}

#if BUILDFLAG(USE_PROPRIETARY_CODECS)

IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, DecryptOnly_VideoOnly_MP4_CBCS) {
  // 'cbcs' decryption is only supported on CDM 10 or later as long as
  // the appropriate buildflag is enabled.
  std::string expected_result =
      GetCdmInterfaceVersion() >= 10 ? media::kEndedTitle : media::kErrorTitle;
  RunEncryptedMediaTest(kDefaultEmePlayer, "bear-640x360-v_frag-cbcs.mp4",
                        media::kExternalClearKeyDecryptOnlyKeySystem,
                        SrcType::MSE, kNoSessionToLoad, false, PlayCount::ONCE,
                        expected_result);
}

// Encryption Scheme tests. ClearKey key system is covered in
// content/browser/media/encrypted_media_browsertest.cc.
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, Playback_Encryption_CENC) {
  RunEncryptedMediaMultipleFileTest(
      media::kExternalClearKeyKeySystem, "bear-640x360-v_frag-cenc.mp4",
      "bear-640x360-a_frag-cenc.mp4", media::kEndedTitle);
}

IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, Playback_Encryption_CBC1) {
  RunEncryptedMediaMultipleFileTest(media::kExternalClearKeyKeySystem,
                                    "bear-640x360-v_frag-cbc1.mp4",
                                    std::string(), media::kErrorTitle);
}

IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, Playback_Encryption_CENS) {
  RunEncryptedMediaMultipleFileTest(media::kExternalClearKeyKeySystem,
                                    "bear-640x360-v_frag-cens.mp4",
                                    std::string(), media::kErrorTitle);
}

IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, Playback_Encryption_CBCS) {
  // 'cbcs' decryption is only supported on CDM 10 or later as long as
  // the appropriate buildflag is enabled.
  std::string expected_result =
      GetCdmInterfaceVersion() >= 10 ? media::kEndedTitle : media::kErrorTitle;
  RunEncryptedMediaMultipleFileTest(
      media::kExternalClearKeyKeySystem, "bear-640x360-v_frag-cbcs.mp4",
      "bear-640x360-a_frag-cbcs.mp4", expected_result);
}

#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)

#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, VerifyCdmHostTest) {
  TestNonPlaybackCases(media::kExternalClearKeyVerifyCdmHostTestKeySystem,
                       kUnitTestSuccess);
}
#endif  // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)

// TODO(b/326134178): Disable this test on branded builder
// ci/linux_lacros_chrome since it fails.
#if BUILDFLAG(IS_CHROMEOS_LACROS) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
#define MAYBE_StorageIdTest
#else
#define MAYBE_StorageIdTest
#endif
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, MAYBE_StorageIdTest) {}

// TODO(crbug.com/40601162): Times out in debug builds.
// TODO(crbug.com/40916095, crbug.com/348996697): Test flakiness.
#if !defined(NDEBUG) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
#define MAYBE_MultipleCdmTypes
#else
#define MAYBE_MultipleCdmTypes
#endif
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, MAYBE_MultipleCdmTypes) {}

// Output Protection Tests. Run with different capture inputs. "monitor"
// simulates the whole screen being captured. "window" simulates the Chrome
// window being captured. "browser" simulates the current Chrome tab being
// captured.

INSTANTIATE_TEST_SUITE_P();
INSTANTIATE_TEST_SUITE_P();
INSTANTIATE_TEST_SUITE_P();

// TODO(crbug.com/40671674): Failing on Win.
#if BUILDFLAG(IS_WIN)
#define MAYBE_BeforeMediaKeys
#else
#define MAYBE_BeforeMediaKeys
#endif
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaOutputProtectionTest,
                       MAYBE_BeforeMediaKeys) {}

// TODO(crbug.com/40671674): Failing on Win.
#if BUILDFLAG(IS_WIN)
#define MAYBE_AfterMediaKeys
#else
#define MAYBE_AfterMediaKeys
#endif
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaOutputProtectionTest,
                       MAYBE_AfterMediaKeys) {}

// Incognito tests. Ideally we would run all above tests in incognito mode to
// ensure that everything works. However, that would add a lot of extra tests
// that aren't really testing anything different, as normal playback does not
// save anything to disk. Instead we are only running the tests that actually
// have the CDM do file access.
INSTANTIATE_TEST_SUITE_P();

IN_PROC_BROWSER_TEST_P(ECKIncognitoEncryptedMediaFileIOTest, FileIO) {}

IN_PROC_BROWSER_TEST_F(ECKIncognitoEncryptedMediaTest, LoadSessionAfterClose) {}
#endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)

#if BUILDFLAG(IS_WIN)
IN_PROC_BROWSER_TEST_F(MFClearEncryptedMediaTest, Playback_AudioClearVideo) {
  TestSimplePlayback("bear-320x240-av_enc-a.webm");
}

IN_PROC_BROWSER_TEST_F(MFClearEncryptedMediaTest, Playback_VideoAudio) {
  TestSimplePlayback("bear-320x240-av_enc-av.webm");
}

IN_PROC_BROWSER_TEST_F(MFClearEncryptedMediaTest, Playback_VideoClearAudio) {
  TestSimplePlayback("bear-320x240-av_enc-v.webm");
}
#endif  // BUILDFLAG(IS_WIN)

#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_PROPRIETARY_CODECS)
// MediaFoundation Clear Key Key System uses Windows Media Foundation's decoders
// and H264 is always supported.
class MediaFoundationEncryptedMediaTest : public EncryptedMediaTestBase {
 public:
  void TestMediaFoundationPlayback(const std::string& encrypted_media) {
    RunSimpleEncryptedMediaTest(encrypted_media,
                                media::kMediaFoundationClearKeyKeySystem,
                                SrcType::MSE, PlayCount::ONCE);
  }

  void TestMediaFoundationMultipleFilePlayback(const std::string& video_file,
                                               const std::string& audio_file) {
    std::string expected_title = media::kEndedTitle;
    if (!IsPlayBackPossible(media::kMediaFoundationClearKeyKeySystem)) {
      expected_title = kEmeUpdateFailed;
    }

    base::StringPairs query_params;
    const auto video_format = media::GetMimeTypeForFile(video_file);
    const auto audio_format = media::GetMimeTypeForFile(audio_file);
    const auto media_type =
        media::GetMimeTypeForFile(audio_file + ";" + video_file);
    query_params.emplace_back("keySystem",
                              media::kMediaFoundationClearKeyKeySystem);
    query_params.emplace_back("runEncrypted", "1");
    query_params.emplace_back("useMSE", "1");
    query_params.emplace_back("playCount", "1");
    query_params.emplace_back("videoFile", video_file);
    query_params.emplace_back("videoFormat", video_format);
    query_params.emplace_back("audioFile", audio_file);
    query_params.emplace_back("audioFormat", audio_format);
    query_params.emplace_back("mediaType", media_type);
    RunEncryptedMediaTestPage(kDefaultEmePlayer,
                              media::kMediaFoundationClearKeyKeySystem,
                              query_params, media::kEndedTitle);

    // Check KeyMessage received for all key systems.
    EXPECT_EQ(true, content::EvalJs(
                        browser()->tab_strip_model()->GetActiveWebContents(),
                        "document.querySelector('video').receivedKeyMessage;"));
  }

 protected:
  void SetUpCommandLine(base::CommandLine* command_line) override {
    EncryptedMediaTestBase::SetUpCommandLine(command_line);
    SetUpCommandLineForKeySystem(media::kMediaFoundationClearKeyKeySystem,
                                 command_line);
  }

  bool IsMediaFoundationEncryptedPlaybackSupported() {
    bool is_mediafoundation_encrypted_playback_supported =
        media::SupportMediaFoundationEncryptedPlayback();
    bool use_gpu_in_tests = base::CommandLine::ForCurrentProcess()->HasSwitch(
        switches::kUseGpuInTests);
    bool disable_gpu = base::CommandLine::ForCurrentProcess()->HasSwitch(
        switches::kDisableGpu);

    const auto& gpu_info = content::GpuDataManager::GetInstance()->GetGPUInfo();
    const auto& active_gpu = gpu_info.active_gpu();
    LOG(INFO) << "active_gpu.vendor_id=" << active_gpu.vendor_id;
    LOG(INFO) << "active_gpu.device_id=" << active_gpu.device_id;
    LOG(INFO) << "active_gpu.driver_version=" << active_gpu.driver_version;
    LOG(INFO) << "gpu_info.gl_vendor=" << gpu_info.gl_vendor;
    LOG(INFO) << "gpu_info.gl_renderer=" << gpu_info.gl_renderer;
    LOG(INFO) << "switches::kDisableGpuDriverBugWorkarounds="
              << base::CommandLine::ForCurrentProcess()->HasSwitch(
                     switches::kDisableGpuDriverBugWorkarounds);

    bool is_playback_supported =
        is_mediafoundation_encrypted_playback_supported && use_gpu_in_tests &&
        !disable_gpu;
    LOG(INFO) << "is_mediafoundation_encrypted_playback_supported="
              << is_mediafoundation_encrypted_playback_supported
              << ", use_gpu_in_tests=" << use_gpu_in_tests
              << ", disable_gpu=" << disable_gpu;

    // Run test only if the test machine supports MediaFoundation playback.
    // Otherwise, NotSupportedError or the failure to create D3D11 device is
    // expected.
    if (!is_playback_supported) {
      LOG(INFO) << "Test method "
                << UnitTest::GetInstance()->current_test_info()->name()
                << " is inconclusive since MediaFoundation playback is not "
                   "supported.";

      if (!is_mediafoundation_encrypted_playback_supported) {
        auto os_version = static_cast<int>(base::win::GetVersion());
        LOG(INFO) << "os_version=" << os_version;
      }

      if (!use_gpu_in_tests) {
        LOG(INFO) << "MediaFoundation playback will not work without a "
                     "hardware GPU. Use `--use-gpu-in-tests` flag.";
      }
    }

    return is_playback_supported;
  }

  bool IsDefaultAudioOutputDeviceAvailable() {
    auto default_audio_output_device_id =
        media::CoreAudioUtil::GetDefaultOutputDeviceID();
    LOG(INFO) << "default_audio_output_device_id="
              << default_audio_output_device_id;

    if (default_audio_output_device_id.empty()) {
      LOG(INFO) << "No default audio output device available!";
      return false;
    }

    return true;
  }
};

IN_PROC_BROWSER_TEST_F(MediaFoundationEncryptedMediaTest,
                       Playback_ClearLeadEncryptedCencVideo_Success) {
  if (!IsMediaFoundationEncryptedPlaybackSupported()) {
    GTEST_SKIP() << "MediaFoundationEncryptedPlayback not supported on device.";
  }

  TestMediaFoundationPlayback("bear-640x360-v_frag-cenc.mp4");  // H.264
}

IN_PROC_BROWSER_TEST_F(MediaFoundationEncryptedMediaTest,
                       Playback_ClearLeadEncryptedCbcsVideo_Success) {
  if (!IsMediaFoundationEncryptedPlaybackSupported()) {
    GTEST_SKIP() << "MediaFoundationEncryptedPlayback not supported on device.";
  }

  TestMediaFoundationPlayback("bear-640x360-v_frag-cbcs.mp4");  // H.264
}

IN_PROC_BROWSER_TEST_F(MediaFoundationEncryptedMediaTest,
                       Playback_EncryptedCencVideoAudio_Success) {
  if (!IsMediaFoundationEncryptedPlaybackSupported()) {
    GTEST_SKIP() << "MediaFoundationEncryptedPlayback not supported on device.";
  }

  TestMediaFoundationMultipleFilePlayback(
      "bear-640x360-v_frag-cenc.mp4",   // H.264
      "bear-640x360-a_frag-cenc.mp4");  // MP4 AAC
}

IN_PROC_BROWSER_TEST_F(MediaFoundationEncryptedMediaTest,
                       Playback_EncryptedCencAudio_Success) {
  if (!IsMediaFoundationEncryptedPlaybackSupported()) {
    GTEST_SKIP() << "MediaFoundationEncryptedPlayback not supported on device.";
  }

  std::string expected_title = media::kEndedTitle;

  // TODO(crbug.com/40270855): "Activate failed to create mediasink
  // (0xC00D36FA)" kPlaybackError is expected when playing encrypted audio only
  // content if no audio device. Remove this temporary fix for test machines
  // once the permenent solution is implemented (i.e., a null sink for no audio
  // device).
  if (!IsDefaultAudioOutputDeviceAvailable()) {
    LOG(INFO)
        << "Test method "
        << UnitTest::GetInstance()->current_test_info()->name()
        << " is expected to receive an error since there is no default audio "
           "output device.";
    expected_title = media::kErrorTitle;
  }

  RunEncryptedMediaTest(
      kDefaultEmePlayer, "bear-640x360-a_frag-cenc.mp4",  // MP4 AAC audio only
      media::kMediaFoundationClearKeyKeySystem, SrcType::MSE, kNoSessionToLoad,
      false, PlayCount::ONCE, expected_title);
}

IN_PROC_BROWSER_TEST_F(MediaFoundationEncryptedMediaTest,
                       Playback_EncryptedAv1CencAudio_MediaTypeUnsupported) {
  if (!IsMediaFoundationEncryptedPlaybackSupported()) {
    GTEST_SKIP() << "MediaFoundationEncryptedPlayback not supported on device.";
  }

  // MediaFoundation Clear Key Key System doesn't support AV1 videos
  // (codecs-"av01.0.04M.08"). See AddMediaFoundationClearKey() in
  // components/cdm/renderer/key_system_support_update.cc
  RunEncryptedMediaTest(
      kDefaultEmePlayer, "bear-av1-cenc.mp4", /*codecs="av01.0.04M.08"*/
      media::kMediaFoundationClearKeyKeySystem, SrcType::MSE, kNoSessionToLoad,
      false, PlayCount::ONCE, kEmeNotSupportedError);
}

IN_PROC_BROWSER_TEST_F(MediaFoundationEncryptedMediaTest,
                       FallbackTest_KeySystemNotSupported) {
  if (!IsMediaFoundationEncryptedPlaybackSupported()) {
    GTEST_SKIP() << "MediaFoundationEncryptedPlayback not supported on device.";
  }

  // MediaFoundationServiceMonitor gets lazily initialized in
  // media_foundation_widevine_cdm_component_installer which is not call by the
  // browser tests. Lazily initialize it here.
  MediaFoundationServiceMonitor::GetInstance();

  const char* fallback_expected_title = media::kEndedTitle;

  RunMediaTestPage("media_foundation_fallback.html",
                   {{"keySystem", media::kMediaFoundationClearKeyKeySystem}},
                   fallback_expected_title, /*http=*/true);
}
#endif  // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_PROPRIETARY_CODECS)