1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/command_line.h"
6 #include "base/path_service.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "base/win/windows_version.h"
9 #include "chrome/browser/media/media_browsertest.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "content/public/test/browser_test_utils.h"
14 #if defined(OS_ANDROID)
15 #include "base/android/build_info.h"
18 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
20 #if defined(ENABLE_PEPPER_CDMS)
21 // Platform-specific filename relative to the chrome executable.
22 const char kClearKeyCdmAdapterFileName[] =
23 #if defined(OS_MACOSX)
24 "clearkeycdmadapter.plugin";
26 "clearkeycdmadapter.dll";
27 #elif defined(OS_POSIX)
28 "libclearkeycdmadapter.so";
31 const char kClearKeyCdmPluginMimeType[] = "application/x-ppapi-clearkey-cdm";
32 #endif // defined(ENABLE_PEPPER_CDMS)
34 // Available key systems.
35 const char kClearKeyKeySystem[] = "webkit-org.w3.clearkey";
36 const char kExternalClearKeyKeySystem[] =
37 "org.chromium.externalclearkey";
39 // Supported media types.
40 const char kWebMAudioOnly[] = "audio/webm; codecs=\"vorbis\"";
41 const char kWebMVideoOnly[] = "video/webm; codecs=\"vp8\"";
42 const char kWebMAudioVideo[] = "video/webm; codecs=\"vorbis, vp8\"";
43 #if defined(USE_PROPRIETARY_CODECS)
44 const char kMP4AudioOnly[] = "audio/mp4; codecs=\"mp4a.40.2\"";
45 const char kMP4VideoOnly[] = "video/mp4; codecs=\"avc1.4D4041\"";
46 #endif // defined(USE_PROPRIETARY_CODECS)
48 // EME-specific test results and errors.
49 const char kEmeKeyError[] = "KEYERROR";
50 const char kEmeNotSupportedError[] = "NOTSUPPORTEDERROR";
52 // The type of video src used to load media.
58 // MSE is available on all desktop platforms and on Android 4.1 and later.
59 static bool IsMSESupported() {
60 #if defined(OS_ANDROID)
61 if (base::android::BuildInfo::GetInstance()->sdk_int() < 16) {
62 LOG(INFO) << "MSE is only supported in Android 4.1 and later.";
65 #endif // defined(OS_ANDROID)
69 // Base class for encrypted media tests.
70 class EncryptedMediaTestBase : public MediaBrowserTest {
72 EncryptedMediaTestBase() : is_pepper_cdm_registered_(false) {}
74 bool IsExternalClearKey(const char* key_system) {
75 return (strcmp(key_system, kExternalClearKeyKeySystem) == 0);
78 #if defined(WIDEVINE_CDM_AVAILABLE)
79 bool IsWidevine(const char* key_system) {
80 return (strcmp(key_system, kWidevineKeySystem) == 0);
82 #endif // defined(WIDEVINE_CDM_AVAILABLE)
84 void RunEncryptedMediaTest(const char* html_page,
85 const char* media_file,
86 const char* media_type,
87 const char* key_system,
89 const char* expectation) {
90 if (src_type == MSE && !IsMSESupported()) {
91 LOG(INFO) << "Skipping test - MSE not supported.";
95 std::vector<StringPair> query_params;
96 query_params.push_back(std::make_pair("mediafile", media_file));
97 query_params.push_back(std::make_pair("mediatype", media_type));
98 query_params.push_back(std::make_pair("keysystem", key_system));
100 query_params.push_back(std::make_pair("usemse", "1"));
101 RunMediaTestPage(html_page, &query_params, expectation, true);
104 void RunSimpleEncryptedMediaTest(const char* media_file,
105 const char* media_type,
106 const char* key_system,
108 #if defined(WIDEVINE_CDM_AVAILABLE)
109 if (IsWidevine(key_system)) {
110 // Tests that the following happen after trying to play encrypted media:
111 // - webkitneedkey event is fired.
112 // - webkitGenerateKeyRequest() does not fail.
113 // - webkitkeymessage is fired.
114 // - webkitAddKey() triggers a WebKitKeyError since no real key is added.
115 RunEncryptedMediaTest("encrypted_media_player.html", media_file,
116 media_type, key_system, src_type, kEmeKeyError);
118 bool receivedKeyMessage = false;
119 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
120 browser()->tab_strip_model()->GetActiveWebContents(),
121 "window.domAutomationController.send(video.receivedKeyMessage);",
122 &receivedKeyMessage));
123 EXPECT_TRUE(receivedKeyMessage);
126 #endif // defined(WIDEVINE_CDM_AVAILABLE)
128 RunEncryptedMediaTest("encrypted_media_player.html", media_file,
129 media_type, key_system, src_type, kEnded);
133 // We want to fail quickly when a test fails because an error is encountered.
134 virtual void AddWaitForTitles(content::TitleWatcher* title_watcher) OVERRIDE {
135 MediaBrowserTest::AddWaitForTitles(title_watcher);
136 title_watcher->AlsoWaitForTitle(ASCIIToUTF16(kEmeNotSupportedError));
137 title_watcher->AlsoWaitForTitle(ASCIIToUTF16(kEmeKeyError));
140 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
141 #if defined(OS_ANDROID)
142 command_line->AppendSwitch(
143 switches::kDisableGestureRequirementForMediaPlayback);
144 #endif // defined(OS_ANDROID)
147 void SetUpCommandLineForKeySystem(const char* key_system,
148 CommandLine* command_line) {
149 #if defined(ENABLE_PEPPER_CDMS)
150 if (IsExternalClearKey(key_system)) {
151 RegisterPepperCdm(command_line, kClearKeyCdmAdapterFileName,
152 kExternalClearKeyKeySystem);
154 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
155 else if (IsWidevine(key_system)) {
156 RegisterPepperCdm(command_line, kWidevineCdmAdapterFileName,
159 #endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
160 #endif // defined(ENABLE_PEPPER_CDMS)
164 #if defined(ENABLE_PEPPER_CDMS)
165 void RegisterPepperCdm(CommandLine* command_line,
166 const std::string& adapter_name,
167 const std::string& key_system) {
168 DCHECK(!is_pepper_cdm_registered_)
169 << "RegisterPepperCdm() can only be called once.";
170 is_pepper_cdm_registered_ = true;
172 // Append the switch to register the Clear Key CDM Adapter.
173 base::FilePath plugin_dir;
174 EXPECT_TRUE(PathService::Get(base::DIR_MODULE, &plugin_dir));
175 base::FilePath plugin_lib = plugin_dir.AppendASCII(adapter_name);
176 EXPECT_TRUE(base::PathExists(plugin_lib)) << plugin_lib.value();
177 base::FilePath::StringType pepper_plugin = plugin_lib.value();
178 pepper_plugin.append(FILE_PATH_LITERAL("#CDM#0.1.0.0;"));
180 pepper_plugin.append(ASCIIToWide(GetPepperType(key_system)));
182 pepper_plugin.append(GetPepperType(key_system));
184 command_line->AppendSwitchNative(switches::kRegisterPepperPlugins,
188 // Adapted from key_systems.cc.
189 std::string GetPepperType(const std::string& key_system) {
190 if (key_system == kExternalClearKeyKeySystem)
191 return kClearKeyCdmPluginMimeType;
192 #if defined(WIDEVINE_CDM_AVAILABLE)
193 if (key_system == kWidevineKeySystem)
194 return kWidevineCdmPluginMimeType;
195 #endif // WIDEVINE_CDM_AVAILABLE
200 #endif // defined(ENABLE_PEPPER_CDMS)
202 bool is_pepper_cdm_registered_;
205 #if defined(ENABLE_PEPPER_CDMS)
206 // Tests encrypted media playback using ExternalClearKey key system.
207 class ECKEncryptedMediaTest : public EncryptedMediaTestBase {
209 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
210 EncryptedMediaTestBase::SetUpCommandLine(command_line);
211 SetUpCommandLineForKeySystem(kExternalClearKeyKeySystem, command_line);
215 #if defined(WIDEVINE_CDM_AVAILABLE)
216 // Tests encrypted media playback using Widevine key system.
217 class WVEncryptedMediaTest : public EncryptedMediaTestBase {
219 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
220 EncryptedMediaTestBase::SetUpCommandLine(command_line);
221 SetUpCommandLineForKeySystem(kWidevineKeySystem, command_line);
224 #endif // defined(WIDEVINE_CDM_AVAILABLE)
225 #endif // defined(ENABLE_PEPPER_CDMS)
227 // Tests encrypted media playback with a combination of parameters:
228 // - char*: Key system name.
229 // - bool: True to load media using MSE, otherwise use src.
231 // Note: Only parameterized (*_P) tests can be used. Non-parameterized (*_F)
232 // tests will crash at GetParam(). To add non-parameterized tests, use
233 // EncryptedMediaTestBase or one of its subclasses (e.g. WVEncryptedMediaTest).
234 class EncryptedMediaTest : public EncryptedMediaTestBase,
235 public testing::WithParamInterface<std::tr1::tuple<const char*, SrcType> > {
237 const char* CurrentKeySystem() {
238 return std::tr1::get<0>(GetParam());
241 SrcType CurrentSourceType() {
242 return std::tr1::get<1>(GetParam());
245 void TestSimplePlayback(const char* encrypted_media, const char* media_type) {
246 RunSimpleEncryptedMediaTest(
247 encrypted_media, media_type, CurrentKeySystem(), CurrentSourceType());
250 void TestFrameSizeChange() {
251 #if defined(WIDEVINE_CDM_AVAILABLE)
252 if (IsWidevine(CurrentKeySystem())) {
253 LOG(INFO) << "FrameSizeChange test cannot run with Widevine.";
256 #endif // defined(WIDEVINE_CDM_AVAILABLE)
257 RunEncryptedMediaTest("encrypted_frame_size_change.html",
258 "frame_size_change-av-enc-v.webm", kWebMAudioVideo,
259 CurrentKeySystem(), CurrentSourceType(), kEnded);
262 void TestConfigChange() {
263 if (CurrentSourceType() != MSE || !IsMSESupported()) {
264 LOG(INFO) << "Skipping test - config change test requires MSE.";
267 #if defined(WIDEVINE_CDM_AVAILABLE)
268 if (IsWidevine(CurrentKeySystem())) {
269 LOG(INFO) << "ConfigChange test cannot run with Widevine.";
272 #endif // defined(WIDEVINE_CDM_AVAILABLE)
273 std::vector<StringPair> query_params;
274 query_params.push_back(std::make_pair("keysystem", CurrentKeySystem()));
275 query_params.push_back(std::make_pair("runencrypted", "1"));
276 RunMediaTestPage("mse_config_change.html", &query_params, kEnded, true);
280 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
281 EncryptedMediaTestBase::SetUpCommandLine(command_line);
282 SetUpCommandLineForKeySystem(CurrentKeySystem(), command_line);
286 using ::testing::Combine;
287 using ::testing::Values;
289 #if !defined(OS_ANDROID)
290 INSTANTIATE_TEST_CASE_P(SRC_ClearKey, EncryptedMediaTest,
291 Combine(Values(kClearKeyKeySystem), Values(SRC)));
292 #endif // !defined(OS_ANDROID)
294 INSTANTIATE_TEST_CASE_P(MSE_ClearKey, EncryptedMediaTest,
295 Combine(Values(kClearKeyKeySystem), Values(MSE)));
297 // External Clear Key is currently only used on platforms that use Pepper CDMs.
298 #if defined(ENABLE_PEPPER_CDMS)
299 INSTANTIATE_TEST_CASE_P(SRC_ExternalClearKey, EncryptedMediaTest,
300 Combine(Values(kExternalClearKeyKeySystem), Values(SRC)));
301 INSTANTIATE_TEST_CASE_P(MSE_ExternalClearKey, EncryptedMediaTest,
302 Combine(Values(kExternalClearKeyKeySystem), Values(MSE)));
303 #endif // defined(ENABLE_PEPPER_CDMS)
305 #if defined(WIDEVINE_CDM_AVAILABLE)
306 // This test doesn't fully test playback with Widevine. So we only run Widevine
307 // test with MSE (no SRC) to reduce test time. Also, on Android EME only works
308 // with MSE and we cannot run this test with SRC.
309 INSTANTIATE_TEST_CASE_P(MSE_Widevine, EncryptedMediaTest,
310 Combine(Values(kWidevineKeySystem), Values(MSE)));
311 #endif // defined(WIDEVINE_CDM_AVAILABLE)
313 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_WebM) {
314 TestSimplePlayback("bear-a-enc_a.webm", kWebMAudioOnly);
317 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioClearVideo_WebM) {
318 TestSimplePlayback("bear-320x240-av-enc_a.webm", kWebMAudioVideo);
321 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM) {
322 TestSimplePlayback("bear-320x240-av-enc_av.webm", kWebMAudioVideo);
325 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM) {
326 TestSimplePlayback("bear-320x240-v-enc_v.webm", kWebMVideoOnly);
329 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM) {
330 TestSimplePlayback("bear-320x240-av-enc_v.webm", kWebMAudioVideo);
333 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, ConfigChangeVideo) {
337 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, FrameSizeChangeVideo) {
338 // Times out on Windows XP. http://crbug.com/171937
340 if (base::win::GetVersion() < base::win::VERSION_VISTA)
343 TestFrameSizeChange();
346 #if defined(USE_PROPRIETARY_CODECS)
347 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4) {
348 // MP4 without MSE is not support yet, http://crbug.com/170793.
349 if (CurrentSourceType() != MSE) {
350 LOG(INFO) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
353 TestSimplePlayback("bear-640x360-v_frag-cenc.mp4", kMP4VideoOnly);
356 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_MP4) {
357 // MP4 without MSE is not support yet, http://crbug.com/170793.
358 if (CurrentSourceType() != MSE) {
359 LOG(INFO) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
362 TestSimplePlayback("bear-640x360-a_frag-cenc.mp4", kMP4AudioOnly);
364 #endif // defined(USE_PROPRIETARY_CODECS)
366 #if defined(WIDEVINE_CDM_AVAILABLE)
367 // The parent key system cannot be used in generateKeyRequest.
368 IN_PROC_BROWSER_TEST_F(WVEncryptedMediaTest, ParentThrowsException) {
369 RunEncryptedMediaTest("encrypted_media_player.html",
374 kEmeNotSupportedError);
376 #endif // defined(WIDEVINE_CDM_AVAILABLE)
378 #if defined(ENABLE_PEPPER_CDMS)
379 IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest,
380 ExternalClearKeyInitializeCDMFail) {
381 RunEncryptedMediaTest("encrypted_media_player.html",
384 "org.chromium.externalclearkey.initializefail",
388 #endif // defined(ENABLE_PEPPER_CDMS)