blob: e2461266b3384baa9aed1acdb208658aa8738e02 [file] [log] [blame]
// 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 <mfapi.h>
#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[] =
"org.chromium.externalclearkey.initializefail";
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
// Sessions to load.
const char kNoSessionToLoad[] = "";
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
const char kPersistentLicense[] = "PersistentLicense";
const char kUnknownSession[] = "UnknownSession";
#endif
// EME-specific test results and errors.
const char kUnitTestSuccess[] = "UNIT_TEST_SUCCESS";
const char16_t kEmeUnitTestFailure16[] = u"UNIT_TEST_FAILURE";
const char kEmeNotSupportedError[] = "NOTSUPPORTEDERROR";
const char16_t kEmeNotSupportedError16[] = u"NOTSUPPORTEDERROR";
const char16_t kEmeGenerateRequestFailed[] = u"EME_GENERATEREQUEST_FAILED";
const char16_t kEmeSessionNotFound16[] = u"EME_SESSION_NOT_FOUND";
const char16_t kEmeLoadFailed[] = u"EME_LOAD_FAILED";
const char kEmeUpdateFailed[] = "EME_UPDATE_FAILED";
const char16_t kEmeUpdateFailed16[] = u"EME_UPDATE_FAILED";
const char16_t kEmeErrorEvent[] = u"EME_ERROR_EVENT";
const char16_t kEmeMessageUnexpectedType[] = u"EME_MESSAGE_UNEXPECTED_TYPE";
const char16_t kEmeRenewalMissingHeader[] = u"EME_RENEWAL_MISSING_HEADER";
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
const char kEmeSessionClosedAndError[] = "EME_SESSION_CLOSED_AND_ERROR";
const char kEmeSessionNotFound[] = "EME_SESSION_NOT_FOUND";
#if BUILDFLAG(IS_CHROMEOS)
const char kEmeUnitTestFailure[] = "UNIT_TEST_FAILURE";
#endif
#endif
const char kDefaultEmePlayer[] = "eme_player.html";
const char kDefaultMseOnlyEmePlayer[] = "mse_different_containers.html";
#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_PROPRIETARY_CODECS) && \
BUILDFLAG(ENABLE_PLATFORM_ENCRYPTED_DOLBY_VISION)
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif
static constexpr wchar_t kDolbyVisionProfile5[] = L"dvhe.05";
static constexpr wchar_t kDolbyVisionProfile8[] = L"dvhe.08";
#endif
#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_PROPRIETARY_CODECS)
const char kProtectedContentIdPrefPath[] =
"profile.default_content_setting_values.protected_media_identifier";
const char kProtectedContentIdExceptionPrefPath[] =
"profile.content_settings.exceptions.protected_media_identifier";
const int kAllowProtectedContentId = 1;
const int kDisallowProtectedContentId = 2;
#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_PROPRIETARY_CODECS)
// The type of video src used to load media.
enum class SrcType { SRC, MSE };
// Must be in sync with CONFIG_CHANGE_TYPE in eme_player_js/global.js
enum class ConfigChangeType {
CLEAR_TO_CLEAR = 0,
CLEAR_TO_ENCRYPTED = 1,
ENCRYPTED_TO_CLEAR = 2,
ENCRYPTED_TO_ENCRYPTED = 3,
};
// Whether the video should be not played or played once or twice.
enum class PlayCount { ZERO = 0, ONCE = 1, TWICE = 2 };
using testing::Bool;
using testing::Combine;
using testing::Eq;
using testing::Not;
using testing::Pair;
using testing::UnitTest;
using testing::UnorderedElementsAre;
using testing::Values;
using testing::WithParamInterface;
using ukm::builders::Media_EME_ApiPromiseRejection;
using ukm::builders::Media_EME_CdmMetrics;
using ukm::builders::Media_EME_CreateMediaKeys;
using ukm::builders::Media_EME_RequestMediaKeySystemAccess;
using ukm::builders::Media_EME_Usage;
// Base class for encrypted media tests.
class EncryptedMediaTestBase : public MediaBrowserTest {
public:
// Occasionally these tests are timing out (see crbug.com/1444672).
// Overriding the setup/run/teardown methods so that the failures will log
// when these happen to see if we can get a better understanding of what
// causes the timeout.
void SetUp() override {
LOG(INFO) << __func__;
MediaBrowserTest::SetUp();
}
void TearDown() override {
LOG(INFO) << __func__;
MediaBrowserTest::TearDown();
}
void SetUpOnMainThread() override {
LOG(INFO) << __func__;
MediaBrowserTest::SetUpOnMainThread();
}
void TearDownOnMainThread() override {
LOG(INFO) << __func__;
MediaBrowserTest::TearDownOnMainThread();
}
bool RequiresClearKeyCdm(const std::string& key_system) {
if (key_system == media::kExternalClearKeyKeySystem) {
return true;
}
// Treat `media::kMediaFoundationClearKeyKeySystem` as a separate key system
// only for Windows
#if BUILDFLAG(IS_WIN)
if (key_system == media::kMediaFoundationClearKeyKeySystem) {
return false;
}
#endif // BUILDFLAG(IS_WIN)
std::string prefix = std::string(media::kExternalClearKeyKeySystem) + '.';
return key_system.substr(0, prefix.size()) == prefix;
}
#if BUILDFLAG(IS_WIN)
bool IsMediaFoundationClearKey(const std::string& key_system) {
return (key_system == media::kMediaFoundationClearKeyKeySystem);
}
#endif // BUILDFLAG(IS_WIN)
#if BUILDFLAG(ENABLE_WIDEVINE)
bool IsWidevine(const std::string& key_system) {
return key_system == kWidevineKeySystem;
}
#endif // BUILDFLAG(ENABLE_WIDEVINE)
void RunEncryptedMediaTestPage(const std::string& html_page,
const std::string& key_system,
const base::StringPairs& query_params,
const std::string& expected_title) {
base::StringPairs new_query_params = query_params;
StartLicenseServerIfNeeded(key_system, &new_query_params);
RunMediaTestPage(html_page, new_query_params, expected_title, true);
}
// Tests |html_page| using |media_file| and |key_system|.
// When |session_to_load| is not empty, the test will try to load
// |session_to_load| with stored keys, instead of creating a new session
// and trying to update it with licenses.
// When |force_invalid_response| is true, the test will provide invalid
// responses, which should trigger errors.
// TODO(xhwang): Find an easier way to pass multiple configuration test
// options.
void RunEncryptedMediaTest(const std::string& html_page,
const std::string& media_file,
const std::string& key_system,
SrcType src_type,
const std::string& session_to_load,
bool force_invalid_response,
PlayCount play_count,
const std::string& expected_title) {
base::StringPairs query_params;
query_params.emplace_back("mediaFile", media_file);
query_params.emplace_back("mediaType",
media::GetMimeTypeForFile(media_file));
query_params.emplace_back("keySystem", key_system);
if (src_type == SrcType::MSE) {
query_params.emplace_back("useMSE", "1");
}
if (force_invalid_response) {
query_params.emplace_back("forceInvalidResponse", "1");
}
if (!session_to_load.empty()) {
query_params.emplace_back("sessionToLoad", session_to_load);
}
query_params.emplace_back(
"playCount", base::NumberToString(static_cast<int>(play_count)));
RunEncryptedMediaTestPage(html_page, key_system, query_params,
expected_title);
}
void RunSimpleEncryptedMediaTest(const std::string& media_file,
const std::string& key_system,
SrcType src_type,
PlayCount play_count) {
std::string expected_title = media::kEndedTitle;
if (!IsPlayBackPossible(key_system)) {
expected_title = kEmeUpdateFailed;
}
RunEncryptedMediaTest(kDefaultEmePlayer, media_file, key_system, src_type,
kNoSessionToLoad, false, play_count, expected_title);
// Check KeyMessage received for all key systems.
EXPECT_EQ(true, content::EvalJs(
browser()->tab_strip_model()->GetActiveWebContents(),
"document.querySelector('video').receivedKeyMessage;"));
}
void RunEncryptedMediaMultipleFileTest(const std::string& key_system,
const std::string& video_file,
const std::string& audio_file,
const std::string& expected_title) {
if (!IsPlayBackPossible(key_system)) {
LOG(INFO) << "Skipping test - Test requires video playback.";
return;
}
base::StringPairs query_params;
query_params.emplace_back("keySystem", key_system);
query_params.emplace_back("runEncrypted", "1");
if (!video_file.empty()) {
query_params.emplace_back("videoFile", video_file);
query_params.emplace_back("videoFormat",
media::GetMimeTypeForFile(video_file));
}
if (!audio_file.empty()) {
query_params.emplace_back("audioFile", audio_file);
query_params.emplace_back("audioFormat",
media::GetMimeTypeForFile(audio_file));
}
RunEncryptedMediaTestPage(kDefaultMseOnlyEmePlayer, key_system,
query_params, expected_title);
}
// Starts a license server if available for the |key_system| and adds a
// 'licenseServerURL' query parameter to |query_params|.
void StartLicenseServerIfNeeded(const std::string& key_system,
base::StringPairs* query_params) {
std::unique_ptr<TestLicenseServerConfig> config =
GetServerConfig(key_system);
if (!config) {
return;
}
license_server_ = std::make_unique<TestLicenseServer>(std::move(config));
{
base::ScopedAllowBlockingForTesting allow_blocking;
EXPECT_TRUE(license_server_->Start());
}
query_params->push_back(
std::make_pair("licenseServerURL", license_server_->GetServerURL()));
}
bool IsPlayBackPossible(const std::string& key_system) {
#if BUILDFLAG(ENABLE_WIDEVINE)
if (IsWidevine(key_system) && !GetServerConfig(key_system)) {
return false;
}
#endif // BUILDFLAG(ENABLE_WIDEVINE)
return true;
}
std::unique_ptr<TestLicenseServerConfig> GetServerConfig(
const std::string& key_system) {
#if BUILDFLAG(ENABLE_WIDEVINE)
if (IsWidevine(key_system)) {
std::unique_ptr<TestLicenseServerConfig> config(
new WVTestLicenseServerConfig);
if (config->IsPlatformSupported()) {
return config;
}
}
#endif // BUILDFLAG(ENABLE_WIDEVINE)
return nullptr;
}
protected:
std::unique_ptr<TestLicenseServer> license_server_;
// We want to fail quickly when a test fails because an error is encountered.
void AddWaitForTitles(content::TitleWatcher* title_watcher) override {
MediaBrowserTest::AddWaitForTitles(title_watcher);
title_watcher->AlsoWaitForTitle(kEmeUnitTestFailure16);
title_watcher->AlsoWaitForTitle(kEmeNotSupportedError16);
title_watcher->AlsoWaitForTitle(kEmeGenerateRequestFailed);
title_watcher->AlsoWaitForTitle(kEmeSessionNotFound16);
title_watcher->AlsoWaitForTitle(kEmeLoadFailed);
title_watcher->AlsoWaitForTitle(kEmeUpdateFailed16);
title_watcher->AlsoWaitForTitle(kEmeErrorEvent);
title_watcher->AlsoWaitForTitle(kEmeMessageUnexpectedType);
title_watcher->AlsoWaitForTitle(kEmeRenewalMissingHeader);
}
#if BUILDFLAG(IS_CHROMEOS)
void SetUpCommandLine(base::CommandLine* command_line) override {
MediaBrowserTest::SetUpCommandLine(command_line);
// Persistent license is supported on ChromeOS when protected media
// identifier is allowed which involves a user action. Use this switch to
// always allow the identifier for testing purpose. Note that the test page
// is hosted on "127.0.0.1". See net::EmbeddedTestServer for details.
command_line->AppendSwitchASCII(
switches::kUnsafelyAllowProtectedMediaIdentifierForDomain, "127.0.0.1");
}
#endif // BUILDFLAG(IS_CHROMEOS)
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
InProcessBrowserTest::SetUpDefaultCommandLine(command_line);
command_line->RemoveSwitch(switches::kDisableComponentUpdate);
}
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
void SetUpCommandLineForKeySystem(
const std::string& key_system,
base::CommandLine* command_line,
const std::vector<base::test::FeatureRefAndParams>&
enable_additional_features = {}) {
if (GetServerConfig(key_system)) {
// Since the web and license servers listen on different ports, we need to
// disable web-security to send license requests to the license server.
// TODO(shadi): Add port forwarding to the test web server configuration.
command_line->AppendSwitch(switches::kDisableWebSecurity);
}
// TODO(crbug.com/40787541): WhatsNewUI might be causing timeouts.
command_line->AppendSwitch(switches::kNoFirstRun);
std::vector<base::test::FeatureRefAndParams> enabled_features;
for (auto feature : enable_additional_features) {
enabled_features.emplace_back(feature);
}
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
if (RequiresClearKeyCdm(key_system)) {
RegisterClearKeyCdm(command_line);
enabled_features.push_back({media::kExternalClearKeyForTesting, {}});
}
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
#if BUILDFLAG(IS_WIN)
if (IsMediaFoundationClearKey(key_system)) {
RegisterMediaFoundationClearKeyCdm(enabled_features);
enabled_features.push_back(
{media::kHardwareSecureDecryptionExperiment, {}});
base::FieldTrialParams fallback_params;
fallback_params["per_site"] = "true";
enabled_features.emplace_back(media::kHardwareSecureDecryptionFallback,
fallback_params);
// To enable MediaFoundation playback, tests should run on a hardware GPU
// other than use a software OpenGL implementation. This can be configured
// via `switches::kUseGpuInTests` or `--use-gpu-in-tests`.
if (command_line->HasSwitch(switches::kUseGpuInTests)) {
// TODO(crbug.com/40896253): Investigate why the video playback doesn't
// work with `switches::kDisableGpu` and remove this line if possible.
// For now, `switches::kDisableGpu` should not be set. Otherwise,
// the video playback will not work with software rendering. Note that
// this switch is appended to browser_tests.exe by force as a workaround
// of http://crbug.com/687387.
command_line->RemoveSwitch(switches::kDisableGpu);
}
}
#endif // BUILDFLAG(IS_WIN)
#if BUILDFLAG(ENABLE_PLATFORM_ENCRYPTED_DOLBY_VISION)
enabled_features.push_back({media::kPlatformEncryptedDolbyVision, {}});
#endif // BUILDFLAG(ENABLE_PLATFORM_ENCRYPTED_DOLBY_VISION)
scoped_feature_list_.InitWithFeaturesAndParameters(enabled_features, {});
}
base::test::ScopedFeatureList scoped_feature_list_;
};
#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> {
public:
int GetCdmInterfaceVersion() { return GetParam(); }
// We use special |key_system| names to do non-playback related tests,
// e.g. media::kExternalClearKeyPlatformVerificationTestKeySystem is used to
// test the platform verification.
void TestNonPlaybackCases(const std::string& key_system,
const std::string& expected_title) {
// Since we do not test playback, arbitrarily choose a test file and source
// type.
RunEncryptedMediaTest(kDefaultEmePlayer, "bear-a_enc-a.webm", key_system,
SrcType::SRC, kNoSessionToLoad, false,
PlayCount::ONCE, expected_title);
}
void TestPlaybackCase(const std::string& key_system,
const std::string& session_to_load,
const std::string& expected_title) {
RunEncryptedMediaTest(kDefaultEmePlayer, "bear-320x240-v_enc-v.webm",
key_system, SrcType::MSE, session_to_load, false,
PlayCount::ONCE, expected_title);
}
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
EncryptedMediaTestBase::SetUpCommandLine(command_line);
SetUpCommandLineForKeySystem(media::kExternalClearKeyKeySystem,
command_line);
// Override enabled CDM interface version for testing.
command_line->AppendSwitchASCII(
switches::kOverrideEnabledCdmInterfaceVersion,
base::NumberToString(GetCdmInterfaceVersion()));
}
};
// Tests FileIO capabilities in Encrypted Media with the following test
// parameters:
// - int: CDM interface version to test
class ECKEncryptedMediaFileIOTest : public EncryptedMediaTestBase,
public WithParamInterface<int> {
public:
int GetCdmInterfaceVersion() { return GetParam(); }
void TestPlaybackCase(const std::string& key_system,
const std::string& session_to_load,
const std::string& expected_title) {
RunEncryptedMediaTest(kDefaultEmePlayer, "bear-320x240-v_enc-v.webm",
key_system, SrcType::MSE, session_to_load, false,
PlayCount::ONCE, expected_title);
}
// We use special |key_system| names to do non-playback related tests,
// e.g. media::kExternalClearKeyFileIOTestKeySystem is used to test file IO.
void TestNonPlaybackCases(const std::string& key_system,
const std::string& expected_title) {
// Since we do not test playback, arbitrarily choose a test file and source
// type.
RunEncryptedMediaTest(kDefaultEmePlayer, "bear-a_enc-a.webm", key_system,
SrcType::SRC, kNoSessionToLoad, false,
PlayCount::ONCE, expected_title);
}
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
EncryptedMediaTestBase::SetUpCommandLine(command_line);
SetUpCommandLineForKeySystem(media::kExternalClearKeyKeySystem,
command_line);
// Override enabled CDM interface version for testing.
command_line->AppendSwitchASCII(
switches::kOverrideEnabledCdmInterfaceVersion,
base::NumberToString(GetCdmInterfaceVersion()));
}
};
class ECKEncryptedMediaReportMetricsTest : public EncryptedMediaTestBase,
public WithParamInterface<int> {
public:
int GetCdmInterfaceVersion() { return GetParam(); }
void SetUpOnMainThread() override {
ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
}
void TearDown() override {
auto report_metric_entries = ukm_recorder_->GetEntries(
Media_EME_CdmMetrics::kEntryName,
{
Media_EME_CdmMetrics::kCertificateSerialNumberName,
Media_EME_CdmMetrics::kDecoderBypassBlockCountName,
Media_EME_CdmMetrics::kLicenseSdkVersionName,
Media_EME_CdmMetrics::kNumberOfOnMessageEventsName,
Media_EME_CdmMetrics::kNumberOfUpdateCallsName,
});
// The ReportMetrics functionality only works in v11 and onwards, but verify
// that in v10, RecordUkm is not called and the Ukm is not set.
if (GetCdmInterfaceVersion() > 10) {
EXPECT_EQ(report_metric_entries.size(), 1u);
EXPECT_EQ(ukm::GetSourceIdType(report_metric_entries[0].source_id),
ukm::SourceIdType::CDM_ID);
// The ClearKey cdm does not report kCertificateSerialNumber or
// kDecoderBypassBlockCount, so the entries should not even be set in the
// ukm data.
EXPECT_THAT(
report_metric_entries[0].metrics,
UnorderedElementsAre(
Pair(Media_EME_CdmMetrics::kLicenseSdkVersionName, 12345),
Pair(Media_EME_CdmMetrics::kNumberOfOnMessageEventsName, 1),
Pair(Media_EME_CdmMetrics::kNumberOfUpdateCallsName, 1)));
} else {
EXPECT_EQ(report_metric_entries.size(), 0u);
}
}
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
EncryptedMediaTestBase::SetUpCommandLine(command_line);
SetUpCommandLineForKeySystem(media::kExternalClearKeyKeySystem,
command_line);
// Override enabled CDM interface version for testing.
command_line->AppendSwitchASCII(
switches::kOverrideEnabledCdmInterfaceVersion,
base::NumberToString(GetCdmInterfaceVersion()));
}
std::unique_ptr<ukm::TestAutoSetUkmRecorder> ukm_recorder_;
};
// 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*> {
public:
void TestOutputProtection(bool create_recorder_before_media_keys) {
#if BUILDFLAG(IS_CHROMEOS)
// QueryOutputProtectionStatus() is known to fail on Linux Chrome OS builds.
std::string expected_title = kEmeUnitTestFailure;
#else
std::string expected_title = kUnitTestSuccess;
#endif
base::StringPairs query_params;
if (create_recorder_before_media_keys) {
query_params.emplace_back("createMediaRecorderBeforeMediaKeys", "1");
}
RunMediaTestPage("eme_and_get_display_media.html", query_params,
expected_title, /*http=*/true,
/*with_transient_activation=*/true);
}
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
EncryptedMediaTestBase::SetUpCommandLine(command_line);
SetUpCommandLineForKeySystem(media::kExternalClearKeyKeySystem,
command_line);
// The output protection tests create a MediaRecorder on a MediaStream,
// so this allows for a fake stream to be created.
command_line->AppendSwitch(switches::kUseFakeUIForMediaStream);
command_line->AppendSwitchASCII(
switches::kUseFakeDeviceForMediaStream,
base::StringPrintf("display-media-type=%s", GetParam()));
}
};
class ECKIncognitoEncryptedMediaTest : public EncryptedMediaTestBase {
public:
void TestNonPlaybackCases(const std::string& key_system,
const std::string& expected_title) {
// Since we do not test playback, arbitrarily choose a test file and source
// type.
RunEncryptedMediaTest(kDefaultEmePlayer, "bear-a_enc-a.webm", key_system,
SrcType::SRC, kNoSessionToLoad, false,
PlayCount::ONCE, expected_title);
}
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
EncryptedMediaTestBase::SetUpCommandLine(command_line);
SetUpCommandLineForKeySystem(media::kExternalClearKeyKeySystem,
command_line);
command_line->AppendSwitch(switches::kIncognito);
}
};
class ECKIncognitoEncryptedMediaFileIOTest : public EncryptedMediaTestBase {
public:
// We use special |key_system| names to do non-playback related tests,
// e.g. media::kExternalClearKeyFileIOTestKeySystem is used to test file IO.
void TestNonPlaybackCases(const std::string& key_system,
const std::string& expected_title) {
// Since we do not test playback, arbitrarily choose a test file and source
// type.
RunEncryptedMediaTest(kDefaultEmePlayer, "bear-a_enc-a.webm", key_system,
SrcType::SRC, kNoSessionToLoad, false,
PlayCount::ONCE, expected_title);
}
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
EncryptedMediaTestBase::SetUpCommandLine(command_line);
SetUpCommandLineForKeySystem(media::kExternalClearKeyKeySystem,
command_line);
command_line->AppendSwitch(switches::kIncognito);
}
};
#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 {
public:
virtual std::string CurrentKeySystem() = 0;
virtual SrcType CurrentSourceType() = 0;
void TestSimplePlayback(const std::string& encrypted_media) {
RunSimpleEncryptedMediaTest(encrypted_media, CurrentKeySystem(),
CurrentSourceType(), PlayCount::ONCE);
}
void TestMultiplePlayback(const std::string& encrypted_media) {
DCHECK(IsPlayBackPossible(CurrentKeySystem()));
RunEncryptedMediaTest(kDefaultEmePlayer, encrypted_media,
CurrentKeySystem(), CurrentSourceType(),
kNoSessionToLoad, false, PlayCount::TWICE,
media::kEndedTitle);
}
void RunInvalidResponseTest() {
RunEncryptedMediaTest(kDefaultEmePlayer, "bear-320x240-av_enc-av.webm",
CurrentKeySystem(), CurrentSourceType(),
kNoSessionToLoad, true, PlayCount::ONCE,
kEmeUpdateFailed);
}
void TestFrameSizeChange() {
RunEncryptedMediaTest("encrypted_frame_size_change.html",
"frame_size_change-av_enc-v.webm", CurrentKeySystem(),
CurrentSourceType(), kNoSessionToLoad, false,
PlayCount::ONCE, media::kEndedTitle);
}
void TestConfigChange(ConfigChangeType config_change_type) {
DCHECK_EQ(CurrentSourceType(), SrcType::MSE)
<< "Config change only happens when using MSE.";
DCHECK(IsPlayBackPossible(CurrentKeySystem()))
<< "ConfigChange test requires video playback.";
base::StringPairs query_params;
query_params.emplace_back("keySystem", CurrentKeySystem());
query_params.emplace_back(
"configChangeType",
base::NumberToString(static_cast<int>(config_change_type)));
RunEncryptedMediaTestPage("mse_config_change.html", CurrentKeySystem(),
query_params, media::kEndedTitle);
}
void TestPolicyCheck() {
base::StringPairs query_params;
// We do not care about playback so choose an arbitrary media file.
std::string media_file = "bear-a_enc-a.webm";
query_params.emplace_back("mediaFile", media_file);
query_params.emplace_back("mediaType",
media::GetMimeTypeForFile(media_file));
if (CurrentSourceType() == SrcType::MSE) {
query_params.emplace_back("useMSE", "1");
}
query_params.emplace_back("keySystem", CurrentKeySystem());
query_params.emplace_back("policyCheck", "1");
RunEncryptedMediaTestPage(kDefaultEmePlayer, CurrentKeySystem(),
query_params, kUnitTestSuccess);
}
void TestDifferentContainers(const std::string& video_media_file,
const std::string& audio_media_file) {
DCHECK_EQ(CurrentSourceType(), SrcType::MSE);
RunEncryptedMediaMultipleFileTest(CurrentKeySystem(), video_media_file,
audio_media_file, media::kEndedTitle);
}
void DisableEncryptedMedia() {
PrefService* pref_service = browser()->profile()->GetPrefs();
pref_service->SetBoolean(prefs::kEnableEncryptedMedia, false);
}
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
EncryptedMediaTestBase::SetUpCommandLine(command_line);
SetUpCommandLineForKeySystem(CurrentKeySystem(), command_line);
}
};
// 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>> {
public:
std::string CurrentKeySystem() override { return std::get<0>(GetParam()); }
SrcType CurrentSourceType() override { return std::get<1>(GetParam()); }
};
// 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*> {
public:
std::string CurrentKeySystem() override { return GetParam(); }
SrcType CurrentSourceType() override { return SrcType::MSE; }
};
INSTANTIATE_TEST_SUITE_P(MSE_ClearKey,
EncryptedMediaTest,
Combine(Values(media::kClearKeyKeySystem),
Values(SrcType::MSE)));
INSTANTIATE_TEST_SUITE_P(MSE_ClearKey,
MseEncryptedMediaTest,
Values(media::kClearKeyKeySystem));
// External Clear Key is currently only used on platforms that use library CDMs.
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
INSTANTIATE_TEST_SUITE_P(SRC_ExternalClearKey,
EncryptedMediaTest,
Combine(Values(media::kExternalClearKeyKeySystem),
Values(SrcType::SRC)));
INSTANTIATE_TEST_SUITE_P(MSE_ExternalClearKey,
EncryptedMediaTest,
Combine(Values(media::kExternalClearKeyKeySystem),
Values(SrcType::MSE)));
INSTANTIATE_TEST_SUITE_P(MSE_ExternalClearKey,
MseEncryptedMediaTest,
Values(media::kExternalClearKeyKeySystem));
#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) {
TestSimplePlayback("bear-320x240-av_enc-a.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM) {
TestSimplePlayback("bear-320x240-av_enc-av.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM) {
TestSimplePlayback("bear-320x240-av_enc-v.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VP9Video_WebM_Fullsample) {
TestSimplePlayback("bear-320x240-v-vp9_fullsample_enc-v.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VP9Video_WebM_Subsample) {
TestSimplePlayback("bear-320x240-v-vp9_subsample_enc-v.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM_Opus) {
TestSimplePlayback("bear-320x240-opus-av_enc-av.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM_Opus) {
TestSimplePlayback("bear-320x240-opus-av_enc-v.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_Multiple_VideoAudio_WebM) {
if (!IsPlayBackPossible(CurrentKeySystem())) {
GTEST_SKIP() << "Playback_Multiple test requires playback.";
}
TestMultiplePlayback("bear-320x240-av_enc-av.webm");
}
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, Playback_AudioOnly_MP4_FLAC) {
TestSimplePlayback("bear-flac-cenc.mp4");
}
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, Playback_AudioOnly_MP4_OPUS) {
TestSimplePlayback("bear-opus-cenc.mp4");
}
// TODO(crbug.com/40116010): Flaky on multiple platforms.
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
DISABLED_Playback_VideoOnly_MP4_VP9) {
TestSimplePlayback("bear-320x240-v_frag-vp9-cenc.mp4");
}
#if BUILDFLAG(IS_MAC)
// TODO(crbug.com/40197943): Fails on dcheck-enabled builds on 11.0.
#define MAYBE_Playback_VideoOnly_WebM_VP9Profile2 \
DISABLED_Playback_VideoOnly_WebM_VP9Profile2
#else
#define MAYBE_Playback_VideoOnly_WebM_VP9Profile2 \
Playback_VideoOnly_WebM_VP9Profile2
#endif
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest,
MAYBE_Playback_VideoOnly_WebM_VP9Profile2) {
TestSimplePlayback("bear-320x240-v-vp9_profile2_subsample_cenc-v.webm");
}
#if BUILDFLAG(IS_MAC)
// TODO(crbug.com/40197943): Fails on dcheck-enabled builds on 11.0.
#define MAYBE_Playback_VideoOnly_MP4_VP9Profile2 \
DISABLED_Playback_VideoOnly_MP4_VP9Profile2
#else
#define MAYBE_Playback_VideoOnly_MP4_VP9Profile2 \
Playback_VideoOnly_MP4_VP9Profile2
#endif
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
MAYBE_Playback_VideoOnly_MP4_VP9Profile2) {
TestSimplePlayback("bear-320x240-v-vp9_profile2_subsample_cenc-v.mp4");
}
#if BUILDFLAG(ENABLE_AV1_DECODER)
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM_AV1) {
TestSimplePlayback("bear-av1-cenc.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM_AV1_10bit) {
TestSimplePlayback("bear-av1-320x180-10bit-cenc.webm");
}
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, Playback_VideoOnly_MP4_AV1) {
TestSimplePlayback("bear-av1-cenc.mp4");
}
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
Playback_VideoOnly_MP4_AV1_10bit) {
TestSimplePlayback("bear-av1-320x180-10bit-cenc.mp4");
}
#endif // BUILDFLAG(ENABLE_AV1_DECODER)
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, InvalidResponseKeyError) {
RunInvalidResponseTest();
}
// This is not really an "encrypted" media test. Keep it here for completeness.
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, ConfigChangeVideo_ClearToClear) {
LOG(INFO) << UnitTest::GetInstance()->current_test_info()->name();
if (!IsPlayBackPossible(CurrentKeySystem())) {
GTEST_SKIP() << "ConfigChange test requires video playback.";
}
TestConfigChange(ConfigChangeType::CLEAR_TO_CLEAR);
}
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
ConfigChangeVideo_ClearToEncrypted) {
LOG(INFO) << UnitTest::GetInstance()->current_test_info()->name();
if (!IsPlayBackPossible(CurrentKeySystem())) {
GTEST_SKIP() << "ConfigChange test requires video playback.";
}
TestConfigChange(ConfigChangeType::CLEAR_TO_ENCRYPTED);
}
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
ConfigChangeVideo_EncryptedToClear) {
LOG(INFO) << UnitTest::GetInstance()->current_test_info()->name();
if (!IsPlayBackPossible(CurrentKeySystem())) {
GTEST_SKIP() << "ConfigChange test requires video playback.";
}
TestConfigChange(ConfigChangeType::ENCRYPTED_TO_CLEAR);
}
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest,
ConfigChangeVideo_EncryptedToEncrypted) {
LOG(INFO) << UnitTest::GetInstance()->current_test_info()->name();
if (!IsPlayBackPossible(CurrentKeySystem())) {
GTEST_SKIP() << "ConfigChange test requires video playback.";
}
TestConfigChange(ConfigChangeType::ENCRYPTED_TO_ENCRYPTED);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, FrameSizeChangeVideo) {
LOG(INFO) << UnitTest::GetInstance()->current_test_info()->name();
if (!IsPlayBackPossible(CurrentKeySystem())) {
GTEST_SKIP() << "FrameSizeChange test requires video playback.";
}
TestFrameSizeChange();
}
// Only use MSE since this is independent to the demuxer.
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, PolicyCheck) {
TestPolicyCheck();
}
// Only use MSE since this is independent to the demuxer.
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, RemoveTemporarySession) {
if (!IsPlayBackPossible(CurrentKeySystem())) {
GTEST_SKIP() << "RemoveTemporarySession test requires license server.";
}
base::StringPairs query_params{{"keySystem", CurrentKeySystem()}};
RunEncryptedMediaTestPage("eme_remove_session_test.html", CurrentKeySystem(),
query_params, media::kEndedTitle);
}
// Only use MSE since this is independent to the demuxer.
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, EncryptedMediaDisabled) {
DisableEncryptedMedia();
// Clear Key key system is always supported.
std::string expected_title = media::IsClearKey(CurrentKeySystem())
? media::kEndedTitle
: kEmeNotSupportedError;
RunEncryptedMediaTest(kDefaultEmePlayer, "bear-a_enc-a.webm",
CurrentKeySystem(), CurrentSourceType(),
kNoSessionToLoad, false, PlayCount::ONCE,
expected_title);
}
IN_PROC_BROWSER_TEST_P(MseEncryptedMediaTest, Playback_Check_Ukm) {
bool is_widevine =
#if BUILDFLAG(ENABLE_WIDEVINE)
IsWidevine(CurrentKeySystem());
#else
false;
#endif // BUILDFLAG(ENABLE_WIDEVINE)
ukm::TestAutoSetUkmRecorder ukm_recorder;
TestSimplePlayback("bear-320x240-av_enc-a.webm");
// Check Media_EME_RequestMediaKeySystemAccess UKM. It is only recorded for
// Widevine.
auto request_entries = ukm_recorder.GetEntries(
Media_EME_RequestMediaKeySystemAccess::kEntryName,
{Media_EME_RequestMediaKeySystemAccess::kIsAdFrameName,
Media_EME_RequestMediaKeySystemAccess::kIsCrossOriginName,
Media_EME_RequestMediaKeySystemAccess::kIsFromMediaCapabilitiesName,
Media_EME_RequestMediaKeySystemAccess::kIsTopFrameName,
Media_EME_RequestMediaKeySystemAccess::kKeySystemName,
Media_EME_RequestMediaKeySystemAccess::kVideoCapabilitiesName,
Media_EME_RequestMediaKeySystemAccess::
kVideoCapabilities_HasEmptyRobustnessName,
Media_EME_RequestMediaKeySystemAccess::
kVideoCapabilities_HasHwSecureAllRobustnessName});
if (is_widevine) {
EXPECT_EQ(request_entries.size(), 1u);
EXPECT_THAT(
request_entries[0].metrics,
UnorderedElementsAre(
Pair(Media_EME_RequestMediaKeySystemAccess::kIsAdFrameName,
/*false=*/0),
Pair(Media_EME_RequestMediaKeySystemAccess::kIsCrossOriginName,
/*false=*/0),
Pair(Media_EME_RequestMediaKeySystemAccess::
kIsFromMediaCapabilitiesName,
/*false=*/0),
Pair(Media_EME_RequestMediaKeySystemAccess::kIsTopFrameName,
/*true=*/1),
Pair(Media_EME_RequestMediaKeySystemAccess::kKeySystemName,
/*blink::KeySystemForUkmLegacy::kWidevine=*/1),
Pair(Media_EME_RequestMediaKeySystemAccess::kVideoCapabilitiesName,
/*true=*/1),
Pair(Media_EME_RequestMediaKeySystemAccess::
kVideoCapabilities_HasEmptyRobustnessName,
/*true=*/1),
Pair(Media_EME_RequestMediaKeySystemAccess::
kVideoCapabilities_HasHwSecureAllRobustnessName,
/*false=*/0)));
} else {
// Not Widevine, so nothing should be recorded.
EXPECT_EQ(request_entries.size(), 0u);
}
// Check Media_EME_CreateMediaKeys UKM. It is also only recorded for Widevine.
auto create_entries =
ukm_recorder.GetEntries(Media_EME_CreateMediaKeys::kEntryName,
{Media_EME_CreateMediaKeys::kIsAdFrameName,
Media_EME_CreateMediaKeys::kIsCrossOriginName,
Media_EME_CreateMediaKeys::kIsTopFrameName,
Media_EME_CreateMediaKeys::kKeySystemName});
if (is_widevine) {
EXPECT_EQ(create_entries.size(), 1u);
EXPECT_THAT(create_entries[0].metrics,
UnorderedElementsAre(
Pair(Media_EME_CreateMediaKeys::kIsAdFrameName,
/*false=*/0),
Pair(Media_EME_CreateMediaKeys::kIsCrossOriginName,
/*false=*/0),
Pair(Media_EME_CreateMediaKeys::kIsTopFrameName,
/*true=*/1),
Pair(Media_EME_CreateMediaKeys::kKeySystemName,
/*blink::KeySystemForUkmLegacy::kWidevine=*/1)));
} else {
// Not Widevine, so nothing should be recorded.
EXPECT_EQ(create_entries.size(), 0u);
}
// Check Media_EME_Usage UKM. It is recorded for all key systems. Currently
// only update() will be called during playback.
auto usage_entries = ukm_recorder.GetEntries(
Media_EME_Usage::kEntryName,
{Media_EME_Usage::kApiName, Media_EME_Usage::kIsPersistentSessionName,
Media_EME_Usage::kKeySystemName,
Media_EME_Usage::kUseHardwareSecureCodecsName});
EXPECT_EQ(usage_entries.size(), 2u);
EXPECT_THAT(
usage_entries[0].metrics,
UnorderedElementsAre(
Pair(Media_EME_Usage::kApiName,
/*blink::EmeApiType::kGenerateRequest=*/4),
Pair(Media_EME_Usage::kIsPersistentSessionName, /*false=*/0),
Pair(Media_EME_Usage::kKeySystemName,
media::GetKeySystemIntForUKM(CurrentKeySystem())),
Pair(Media_EME_Usage::kUseHardwareSecureCodecsName, /*false=*/0)));
EXPECT_THAT(
usage_entries[1].metrics,
UnorderedElementsAre(
Pair(Media_EME_Usage::kApiName, /*blink::EmeApiType::kUpdate=*/6),
Pair(Media_EME_Usage::kIsPersistentSessionName, /*false=*/0),
Pair(Media_EME_Usage::kKeySystemName,
media::GetKeySystemIntForUKM(CurrentKeySystem())),
Pair(Media_EME_Usage::kUseHardwareSecureCodecsName, /*false=*/0)));
// Check Media_EME_ApiPromiseRejection. With Widevine if there is no license
// server Update() will fail. With ClearKey a valid response is provided, so
// there is no failure.
auto promise_entries = ukm_recorder.GetEntries(
Media_EME_ApiPromiseRejection::kEntryName,
{Media_EME_ApiPromiseRejection::kApiName,
Media_EME_ApiPromiseRejection::kKeySystemName,
Media_EME_ApiPromiseRejection::kSystemCodeName,
Media_EME_ApiPromiseRejection::kUseHardwareSecureCodecsName});
if (is_widevine && !license_server_) {
// Update() should have failed due to invalid license response.
EXPECT_EQ(promise_entries.size(), 1u);
// Media_EME_ApiPromiseRejection::kSystemCodeName is key system
// implementation specific, so exact value may change.
EXPECT_THAT(
promise_entries[0].metrics,
UnorderedElementsAre(
Pair(Media_EME_ApiPromiseRejection::kApiName,
/*blink::EmeApiType::kUpdate=*/6),
Pair(Media_EME_ApiPromiseRejection::kKeySystemName,
media::GetKeySystemIntForUKM(CurrentKeySystem())),
Pair(Media_EME_ApiPromiseRejection::kSystemCodeName, Not(Eq(0))),
Pair(Media_EME_ApiPromiseRejection::kUseHardwareSecureCodecsName,
/*false=*/0)));
} else {
// No error with ClearKey or with Widevine if a license server is available.
EXPECT_EQ(promise_entries.size(), 0u);
}
}
#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_12.
static_assert(media::CheckSupportedCdmInterfaceVersions(10, 12),
"Mismatch between implementation and test coverage");
INSTANTIATE_TEST_SUITE_P(CDM_10, ECKEncryptedMediaTest, Values(10));
INSTANTIATE_TEST_SUITE_P(CDM_11, ECKEncryptedMediaTest, Values(11));
INSTANTIATE_TEST_SUITE_P(CDM_12, ECKEncryptedMediaTest, Values(12));
INSTANTIATE_TEST_SUITE_P(CDM_10, ECKEncryptedMediaFileIOTest, Values(10));
INSTANTIATE_TEST_SUITE_P(CDM_11, ECKEncryptedMediaFileIOTest, Values(11));
INSTANTIATE_TEST_SUITE_P(CDM_12, ECKEncryptedMediaFileIOTest, Values(12));
INSTANTIATE_TEST_SUITE_P(CDM_10,
ECKEncryptedMediaReportMetricsTest,
Values(10));
INSTANTIATE_TEST_SUITE_P(CDM_11,
ECKEncryptedMediaReportMetricsTest,
Values(11));
INSTANTIATE_TEST_SUITE_P(CDM_12,
ECKEncryptedMediaReportMetricsTest,
Values(12));
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaReportMetricsTest, RecordUkmTest) {
RunSimpleEncryptedMediaTest("bear-320x240-av_enc-a.webm",
media::kExternalClearKeyKeySystem, SrcType::SRC,
PlayCount::ONCE);
base::RunLoop().RunUntilIdle();
}
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, InitializeCDMFail) {
TestNonPlaybackCases(kExternalClearKeyInitializeFailKeySystem,
kEmeNotSupportedError);
}
// When CDM crashes, we should still get a decode error and all sessions should
// be closed.
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, CDMCrashDuringDecode) {
TestNonPlaybackCases(media::kExternalClearKeyCrashKeySystem,
kEmeSessionClosedAndError);
}
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, PlatformVerificationTest) {
TestNonPlaybackCases(
media::kExternalClearKeyPlatformVerificationTestKeySystem,
kUnitTestSuccess);
}
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaFileIOTest, FileIOTest) {
TestNonPlaybackCases(media::kExternalClearKeyFileIOTestKeySystem,
kUnitTestSuccess);
}
// Intermittent leaks on ASan/LSan runs: crbug.com/889923
#if defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER)
#define MAYBE_MessageTypeTest DISABLED_MessageTypeTest
#else
#define MAYBE_MessageTypeTest MessageTypeTest
#endif
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, MAYBE_MessageTypeTest) {
TestPlaybackCase(media::kExternalClearKeyMessageTypeTestKeySystem,
kNoSessionToLoad, media::kEndedTitle);
// Expects 3 message types: 'license-request', 'license-renewal' and
// 'individualization-request'.
EXPECT_EQ(3,
content::EvalJs(
browser()->tab_strip_model()->GetActiveWebContents(),
"document.querySelector('video').receivedMessageTypes.size;"));
}
// Exercises Storage Path, so use ECKEncryptedMediaFileIOTest
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaFileIOTest, LoadPersistentLicense) {
TestPlaybackCase(media::kExternalClearKeyKeySystem, kPersistentLicense,
media::kEndedTitle);
}
// Exercises Storage Path, so use ECKEncryptedMediaFileIOTest
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaFileIOTest, LoadUnknownSession) {
TestPlaybackCase(media::kExternalClearKeyKeySystem, kUnknownSession,
kEmeSessionNotFound);
}
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, LoadSessionAfterClose) {
base::StringPairs query_params{
{"keySystem", media::kExternalClearKeyKeySystem}};
RunEncryptedMediaTestPage("eme_load_session_after_close_test.html",
media::kExternalClearKeyKeySystem, query_params,
media::kEndedTitle);
}
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, DecryptOnly_VideoAudio_WebM) {
RunSimpleEncryptedMediaTest("bear-320x240-av_enc-av.webm",
media::kExternalClearKeyDecryptOnlyKeySystem,
SrcType::MSE, PlayCount::ONCE);
}
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, DecryptOnly_VideoOnly_MP4_VP9) {
RunSimpleEncryptedMediaTest("bear-320x240-v_frag-vp9-cenc.mp4",
media::kExternalClearKeyDecryptOnlyKeySystem,
SrcType::MSE, PlayCount::ONCE);
}
#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)
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, StorageIdTest) {
TestNonPlaybackCases(media::kExternalClearKeyStorageIdTestKeySystem,
kUnitTestSuccess);
}
// TODO(crbug.com/40601162): Times out in debug builds.
// TODO(crbug.com/40916095): Test flakiness.
#if !defined(NDEBUG) || BUILDFLAG(IS_CHROMEOS)
#define MAYBE_MultipleCdmTypes DISABLED_MultipeCdmTypes
#else
#define MAYBE_MultipleCdmTypes MultipeCdmTypes
#endif
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, MAYBE_MultipleCdmTypes) {
base::StringPairs empty_query_params;
RunMediaTestPage("multiple_cdm_types.html", empty_query_params,
media::kEndedTitle, true);
}
// 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(Capture_Monitor,
ECKEncryptedMediaOutputProtectionTest,
Values("monitor"));
INSTANTIATE_TEST_SUITE_P(Capture_Window,
ECKEncryptedMediaOutputProtectionTest,
Values("window"));
INSTANTIATE_TEST_SUITE_P(Capture_Browser,
ECKEncryptedMediaOutputProtectionTest,
Values("browser"));
// TODO(crbug.com/40671674): Failing on Win.
#if BUILDFLAG(IS_WIN)
#define MAYBE_BeforeMediaKeys DISABLED_BeforeMediaKeys
#else
#define MAYBE_BeforeMediaKeys BeforeMediaKeys
#endif
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaOutputProtectionTest,
MAYBE_BeforeMediaKeys) {
TestOutputProtection(/*create_recorder_before_media_keys=*/true);
}
// TODO(crbug.com/40671674): Failing on Win.
#if BUILDFLAG(IS_WIN)
#define MAYBE_AfterMediaKeys DISABLED_AfterMediaKeys
#else
#define MAYBE_AfterMediaKeys AfterMediaKeys
#endif
IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaOutputProtectionTest,
MAYBE_AfterMediaKeys) {
TestOutputProtection(/*create_recorder_before_media_keys=*/false);
}
// 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.
IN_PROC_BROWSER_TEST_F(ECKIncognitoEncryptedMediaFileIOTest, FileIO) {
// Try the FileIO test using the default CDM API while running in incognito.
TestNonPlaybackCases(media::kExternalClearKeyFileIOTestKeySystem,
kUnitTestSuccess);
}
IN_PROC_BROWSER_TEST_F(ECKIncognitoEncryptedMediaTest, LoadSessionAfterClose) {
// Loading a session should work in incognito mode.
base::StringPairs query_params{
{"keySystem", media::kExternalClearKeyKeySystem}};
RunEncryptedMediaTestPage("eme_load_session_after_close_test.html",
media::kExternalClearKeyKeySystem, query_params,
media::kEndedTitle);
}
#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;
}
#if BUILDFLAG(ENABLE_PLATFORM_ENCRYPTED_DOLBY_VISION)
bool IsVideoDecoderSupported(const GUID& video_decoder_guid) {
MFT_REGISTER_TYPE_INFO inputInfo{MFMediaType_Video, video_decoder_guid};
IMFActivate** activates;
unsigned int numActivates = 0;
auto result = MFTEnumEx(MFT_CATEGORY_VIDEO_DECODER, MFT_ENUM_FLAG_SYNCMFT,
&inputInfo, nullptr, &activates, &numActivates);
if (result != S_OK || numActivates == 0) {
LOG(INFO) << "No decoders found!";
return false;
}
return true;
}
bool IsVideoRendererEffectSupported(const wchar_t* profile) {
bool supported = false;
IMFActivate** activates = nullptr;
unsigned int numActivates = 0;
auto result = MFTEnumEx(MFT_CATEGORY_VIDEO_RENDERER_EFFECT,
MFT_ENUM_FLAG_SORTANDFILTER, nullptr, nullptr,
&activates, &numActivates);
if (result != S_OK || numActivates == 0) {
LOG(INFO) << "No video renderer effect found!";
return false;
}
for (unsigned int i = 0; i < numActivates && !supported; i++) {
PROPVARIANT var;
PropVariantInit(&var);
auto hr = activates[i]->GetItem(MFT_ENUM_VIDEO_RENDERER_EXTENSION_PROFILE,
&var);
if (hr == S_OK && var.vt == VARTYPE(VT_VECTOR | VT_LPWSTR)) {
for (unsigned long j = 0; j < var.calpwstr.cElems; j++) {
auto elem = *(var.calpwstr.pElems + j);
if (_wcsicmp(elem, profile) == 0) {
supported = true;
break;
}
}
}
PropVariantClear(&var);
}
if (*activates) {
(*activates)->Release();
}
return supported;
}
// |profile| is a Dolby Vision renderer profile string which has always 7
// characters in MediaFoundation. For HEVC based profiles, it's either
// "dvhe.xx" or "dvh1.xx" where "xx" is a two-digit profile number. Note the
// DolbyVision level is ignored. See "Table 1: Dolby Vision bitstream
// profiles" at
// `https://professionalsupport.dolby.com/s/article/What-is-Dolby-Vision-Profile`.
bool IsDolbyVisionEncryptedPlaybackSupported(const wchar_t* profile) {
// Dolby Vision video playback requires both HEVC and Dolby Vision extension
// codecs.
bool is_hevc_decoder_supported =
IsVideoDecoderSupported(MFVideoFormat_HEVC);
bool is_dolbyvision_supported = IsVideoRendererEffectSupported(profile);
LOG(INFO) << "is_hevc_decoder_supported=" << is_hevc_decoder_supported;
LOG(INFO) << "is_dolbyvision_supported=" << is_dolbyvision_supported;
if (!is_hevc_decoder_supported || !is_dolbyvision_supported) {
LOG(INFO)
<< "Test method "
<< UnitTest::GetInstance()->current_test_info()->name()
<< " is inconclusive since DolbyVisionEncrypted playback is not "
"supported.";
return false;
}
return true;
}
#endif // BUILDFLAG(ENABLE_PLATFORM_ENCRYPTED_DOLBY_VISION)
};
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);
}
IN_PROC_BROWSER_TEST_F(MediaFoundationEncryptedMediaTest,
ProtectedContentIdSettingAllowed) {
if (!IsMediaFoundationEncryptedPlaybackSupported()) {
GTEST_SKIP() << "MediaFoundationEncryptedPlayback not supported on device.";
}
PrefService* prefs = browser()->profile()->GetPrefs();
ASSERT_TRUE(prefs);
prefs->SetInteger(kProtectedContentIdPrefPath, kAllowProtectedContentId);
RunEncryptedMediaTest(kDefaultEmePlayer, "bear-640x360-v_frag-cbcs.mp4",
media::kMediaFoundationClearKeyKeySystem, SrcType::MSE,
kNoSessionToLoad, false, PlayCount::ONCE,
media::kEndedTitle);
}
IN_PROC_BROWSER_TEST_F(MediaFoundationEncryptedMediaTest,
ProtectedContentIdSettingDisallowed) {
if (!IsMediaFoundationEncryptedPlaybackSupported()) {
GTEST_SKIP() << "MediaFoundationEncryptedPlayback not supported on device.";
}
PrefService* prefs = browser()->profile()->GetPrefs();
ASSERT_TRUE(prefs);
prefs->SetInteger(kProtectedContentIdPrefPath, kDisallowProtectedContentId);
RunEncryptedMediaTest(kDefaultEmePlayer, "bear-640x360-v_frag-cbcs.mp4",
media::kMediaFoundationClearKeyKeySystem, SrcType::MSE,
kNoSessionToLoad, false, PlayCount::ONCE,
kEmeNotSupportedError);
}
IN_PROC_BROWSER_TEST_F(MediaFoundationEncryptedMediaTest,
ProtectedContentIdCustomSettingAllowed) {
if (!IsMediaFoundationEncryptedPlaybackSupported()) {
GTEST_SKIP() << "MediaFoundationEncryptedPlayback not supported on device.";
}
PrefService* prefs = browser()->profile()->GetPrefs();
ASSERT_TRUE(prefs);
// Disable protected media identifier by default.
prefs->SetInteger(kProtectedContentIdPrefPath, kDisallowProtectedContentId);
// Enable 127.0.0.1 as an exception.
prefs->SetDict(
kProtectedContentIdExceptionPrefPath,
base::Value::Dict().Set(
"http://127.0.0.1,*",
base::Value::Dict().Set("setting", kAllowProtectedContentId)));
RunEncryptedMediaTest(kDefaultEmePlayer, "bear-640x360-v_frag-cbcs.mp4",
media::kMediaFoundationClearKeyKeySystem, SrcType::MSE,
kNoSessionToLoad, false, PlayCount::ONCE,
media::kEndedTitle);
}
IN_PROC_BROWSER_TEST_F(MediaFoundationEncryptedMediaTest,
ProtectedContentIdCustomSettingDisallowed) {
if (!IsMediaFoundationEncryptedPlaybackSupported()) {
GTEST_SKIP() << "MediaFoundationEncryptedPlayback not supported on device.";
}
PrefService* prefs = browser()->profile()->GetPrefs();
ASSERT_TRUE(prefs);
// Enable protected media identifier by default.
prefs->SetInteger(kProtectedContentIdPrefPath, kAllowProtectedContentId);
// Disable 127.0.0.1 as an exception.
prefs->SetDict(
kProtectedContentIdExceptionPrefPath,
base::Value::Dict().Set(
"http://127.0.0.1,*",
base::Value::Dict().Set("setting", kDisallowProtectedContentId)));
RunEncryptedMediaTest(kDefaultEmePlayer, "bear-640x360-v_frag-cbcs.mp4",
media::kMediaFoundationClearKeyKeySystem, SrcType::MSE,
kNoSessionToLoad, false, PlayCount::ONCE,
kEmeNotSupportedError);
}
#if BUILDFLAG(ENABLE_PLATFORM_ENCRYPTED_DOLBY_VISION)
IN_PROC_BROWSER_TEST_F(MediaFoundationEncryptedMediaTest,
Playback_DolbyVisionProfile5CencVideo_Success) {
if (!IsMediaFoundationEncryptedPlaybackSupported()) {
GTEST_SKIP() << "MediaFoundationEncryptedPlayback not supported on device.";
}
if (!IsDolbyVisionEncryptedPlaybackSupported(kDolbyVisionProfile5)) {
GTEST_SKIP() << "DolbyVisionEncryptedPlayback not supported on device.";
}
// DolbyVision Profile 5
TestMediaFoundationPlayback(
"color_pattern_24_dvhe_05_1920x1080-3sec-frag-cenc.mp4");
}
IN_PROC_BROWSER_TEST_F(MediaFoundationEncryptedMediaTest,
Playback_DolbyVisionProfile81CencVideo_Success) {
if (!IsMediaFoundationEncryptedPlaybackSupported()) {
GTEST_SKIP() << "MediaFoundationEncryptedPlayback not supported on device.";
}
if (!IsDolbyVisionEncryptedPlaybackSupported(kDolbyVisionProfile8)) {
GTEST_SKIP() << "DolbyVisionEncryptedPlayback not supported on device.";
}
// DolbyVision Profile 8.1
TestMediaFoundationPlayback(
"color_pattern_24_dvhe_081_1920x1080-3sec-frag-cenc.mp4");
}
IN_PROC_BROWSER_TEST_F(MediaFoundationEncryptedMediaTest,
Playback_DolbyVisionProfile5CencClearLeadVideo_Success) {
if (!IsMediaFoundationEncryptedPlaybackSupported()) {
GTEST_SKIP() << "MediaFoundationEncryptedPlayback not supported on device.";
}
if (!IsDolbyVisionEncryptedPlaybackSupported(kDolbyVisionProfile5)) {
GTEST_SKIP() << "DolbyVisionEncryptedPlayback not supported on device.";
}
// DolbyVision Profile 5
TestMediaFoundationPlayback(
"color_pattern_24_dvhe_05_1920x1080-3sec-frag-cenc-clearlead-2sec.mp4");
}
IN_PROC_BROWSER_TEST_F(
MediaFoundationEncryptedMediaTest,
Playback_DolbyVisionProfile81CencClearLeadVideo_Success) {
if (!IsMediaFoundationEncryptedPlaybackSupported()) {
GTEST_SKIP() << "MediaFoundationEncryptedPlayback not supported on device.";
}
if (!IsDolbyVisionEncryptedPlaybackSupported(kDolbyVisionProfile8)) {
GTEST_SKIP() << "DolbyVisionEncryptedPlayback not supported on device.";
}
// DolbyVision Profile 8.1
TestMediaFoundationPlayback(
"color_pattern_24_dvhe_081_1920x1080-3sec-frag-cenc-clearlead-2sec.mp4");
}
#endif // BUILDFLAG(ENABLE_PLATFORM_ENCRYPTED_DOLBY_VISION)
#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_PROPRIETARY_CODECS)