Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / media / encrypted_media_browsertest.cc
blob5612e0ce8420fa88526e64ae1375c52a3a64bd22
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"
16 #endif
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";
25 #elif defined(OS_WIN)
26 "clearkeycdmadapter.dll";
27 #elif defined(OS_POSIX)
28 "libclearkeycdmadapter.so";
29 #endif
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[] = "org.chromium.externalclearkey";
37 const char kExternalClearKeyDecryptOnlyKeySystem[] =
38 "org.chromium.externalclearkey.decryptonly";
39 const char kExternalClearKeyFileIOTestKeySystem[] =
40 "org.chromium.externalclearkey.fileiotest";
41 const char kExternalClearKeyInitializeFailKeySystem[] =
42 "org.chromium.externalclearkey.initializefail";
43 const char kExternalClearKeyCrashKeySystem[] =
44 "org.chromium.externalclearkey.crash";
46 // Supported media types.
47 const char kWebMAudioOnly[] = "audio/webm; codecs=\"vorbis\"";
48 const char kWebMVideoOnly[] = "video/webm; codecs=\"vp8\"";
49 const char kWebMAudioVideo[] = "video/webm; codecs=\"vorbis, vp8\"";
50 #if defined(USE_PROPRIETARY_CODECS)
51 const char kMP4AudioOnly[] = "audio/mp4; codecs=\"mp4a.40.2\"";
52 const char kMP4VideoOnly[] = "video/mp4; codecs=\"avc1.4D4041\"";
53 #endif // defined(USE_PROPRIETARY_CODECS)
55 // EME-specific test results and errors.
56 const char kEmeKeyError[] = "KEYERROR";
57 const char kEmeNotSupportedError[] = "NOTSUPPORTEDERROR";
58 const char kFileIOTestSuccess[] = "FILEIOTESTSUCCESS";
60 // The type of video src used to load media.
61 enum SrcType {
62 SRC,
63 MSE
66 // MSE is available on all desktop platforms and on Android 4.1 and later.
67 static bool IsMSESupported() {
68 #if defined(OS_ANDROID)
69 if (base::android::BuildInfo::GetInstance()->sdk_int() < 16) {
70 VLOG(0) << "MSE is only supported in Android 4.1 and later.";
71 return false;
73 #endif // defined(OS_ANDROID)
74 return true;
77 static bool IsParentKeySystemOf(const std::string& parent_key_system,
78 const std::string& key_system) {
79 std::string prefix = parent_key_system + '.';
80 return key_system.substr(0, prefix.size()) == prefix;
83 // Base class for encrypted media tests.
84 class EncryptedMediaTestBase : public MediaBrowserTest {
85 public:
86 EncryptedMediaTestBase() : is_pepper_cdm_registered_(false) {}
88 bool IsExternalClearKey(const std::string& key_system) {
89 return key_system == kExternalClearKeyKeySystem ||
90 IsParentKeySystemOf(kExternalClearKeyKeySystem, key_system);
93 #if defined(WIDEVINE_CDM_AVAILABLE)
94 bool IsWidevine(const std::string& key_system) {
95 return key_system == kWidevineKeySystem;
97 #endif // defined(WIDEVINE_CDM_AVAILABLE)
99 void RunEncryptedMediaTest(const char* html_page,
100 const char* media_file,
101 const char* media_type,
102 const char* key_system,
103 SrcType src_type,
104 const char* expectation) {
105 if (src_type == MSE && !IsMSESupported()) {
106 VLOG(0) << "Skipping test - MSE not supported.";
107 return;
110 std::vector<StringPair> query_params;
111 query_params.push_back(std::make_pair("mediafile", media_file));
112 query_params.push_back(std::make_pair("mediatype", media_type));
113 query_params.push_back(std::make_pair("keysystem", key_system));
114 if (src_type == MSE)
115 query_params.push_back(std::make_pair("usemse", "1"));
116 RunMediaTestPage(html_page, &query_params, expectation, true);
119 void RunSimpleEncryptedMediaTest(const char* media_file,
120 const char* media_type,
121 const char* key_system,
122 SrcType src_type) {
123 #if defined(WIDEVINE_CDM_AVAILABLE)
124 if (IsWidevine(key_system)) {
125 // Tests that the following happen after trying to play encrypted media:
126 // - webkitneedkey event is fired.
127 // - webkitGenerateKeyRequest() does not fail.
128 // - webkitkeymessage is fired.
129 // - webkitAddKey() triggers a WebKitKeyError since no real key is added.
130 RunEncryptedMediaTest("encrypted_media_player.html", media_file,
131 media_type, key_system, src_type, kEmeKeyError);
133 bool receivedKeyMessage = false;
134 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
135 browser()->tab_strip_model()->GetActiveWebContents(),
136 "window.domAutomationController.send(video.receivedKeyMessage);",
137 &receivedKeyMessage));
138 EXPECT_TRUE(receivedKeyMessage);
139 return;
141 #endif // defined(WIDEVINE_CDM_AVAILABLE)
143 RunEncryptedMediaTest("encrypted_media_player.html", media_file,
144 media_type, key_system, src_type, kEnded);
147 protected:
148 // We want to fail quickly when a test fails because an error is encountered.
149 virtual void AddWaitForTitles(content::TitleWatcher* title_watcher) OVERRIDE {
150 MediaBrowserTest::AddWaitForTitles(title_watcher);
151 title_watcher->AlsoWaitForTitle(base::ASCIIToUTF16(kEmeNotSupportedError));
152 title_watcher->AlsoWaitForTitle(base::ASCIIToUTF16(kEmeKeyError));
155 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
156 #if defined(OS_ANDROID)
157 command_line->AppendSwitch(
158 switches::kDisableGestureRequirementForMediaPlayback);
159 #endif // defined(OS_ANDROID)
162 void SetUpCommandLineForKeySystem(const char* key_system,
163 CommandLine* command_line) {
164 #if defined(ENABLE_PEPPER_CDMS)
165 if (IsExternalClearKey(key_system)) {
166 RegisterPepperCdm(command_line, kClearKeyCdmAdapterFileName, key_system);
168 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
169 else if (IsWidevine(key_system)) {
170 RegisterPepperCdm(command_line, kWidevineCdmAdapterFileName, key_system);
172 #endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
173 #endif // defined(ENABLE_PEPPER_CDMS)
176 private:
177 #if defined(ENABLE_PEPPER_CDMS)
178 void RegisterPepperCdm(CommandLine* command_line,
179 const std::string& adapter_name,
180 const std::string& key_system) {
181 DCHECK(!is_pepper_cdm_registered_)
182 << "RegisterPepperCdm() can only be called once.";
183 is_pepper_cdm_registered_ = true;
185 // Append the switch to register the Clear Key CDM Adapter.
186 base::FilePath plugin_dir;
187 EXPECT_TRUE(PathService::Get(base::DIR_MODULE, &plugin_dir));
188 base::FilePath plugin_lib = plugin_dir.AppendASCII(adapter_name);
189 EXPECT_TRUE(base::PathExists(plugin_lib)) << plugin_lib.value();
190 base::FilePath::StringType pepper_plugin = plugin_lib.value();
191 pepper_plugin.append(FILE_PATH_LITERAL("#CDM#0.1.0.0;"));
192 #if defined(OS_WIN)
193 pepper_plugin.append(base::ASCIIToWide(GetPepperType(key_system)));
194 #else
195 pepper_plugin.append(GetPepperType(key_system));
196 #endif
197 command_line->AppendSwitchNative(switches::kRegisterPepperPlugins,
198 pepper_plugin);
201 // Adapted from key_systems.cc.
202 std::string GetPepperType(const std::string& key_system) {
203 if (IsExternalClearKey(key_system))
204 return kClearKeyCdmPluginMimeType;
205 #if defined(WIDEVINE_CDM_AVAILABLE)
206 if (IsWidevine(key_system))
207 return kWidevineCdmPluginMimeType;
208 #endif // WIDEVINE_CDM_AVAILABLE
210 NOTREACHED();
211 return "";
213 #endif // defined(ENABLE_PEPPER_CDMS)
215 bool is_pepper_cdm_registered_;
218 #if defined(ENABLE_PEPPER_CDMS)
219 // Tests encrypted media playback using ExternalClearKey key system in
220 // decrypt-and-decode mode.
221 class ECKEncryptedMediaTest : public EncryptedMediaTestBase {
222 protected:
223 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
224 EncryptedMediaTestBase::SetUpCommandLine(command_line);
225 SetUpCommandLineForKeySystem(kExternalClearKeyKeySystem, command_line);
229 #if defined(WIDEVINE_CDM_AVAILABLE)
230 // Tests encrypted media playback using Widevine key system.
231 class WVEncryptedMediaTest : public EncryptedMediaTestBase {
232 protected:
233 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
234 EncryptedMediaTestBase::SetUpCommandLine(command_line);
235 SetUpCommandLineForKeySystem(kWidevineKeySystem, command_line);
238 #endif // defined(WIDEVINE_CDM_AVAILABLE)
239 #endif // defined(ENABLE_PEPPER_CDMS)
241 // Tests encrypted media playback with a combination of parameters:
242 // - char*: Key system name.
243 // - bool: True to load media using MSE, otherwise use src.
245 // Note: Only parameterized (*_P) tests can be used. Non-parameterized (*_F)
246 // tests will crash at GetParam(). To add non-parameterized tests, use
247 // EncryptedMediaTestBase or one of its subclasses (e.g. WVEncryptedMediaTest).
248 class EncryptedMediaTest : public EncryptedMediaTestBase,
249 public testing::WithParamInterface<std::tr1::tuple<const char*, SrcType> > {
250 public:
251 const char* CurrentKeySystem() {
252 return std::tr1::get<0>(GetParam());
255 SrcType CurrentSourceType() {
256 return std::tr1::get<1>(GetParam());
259 void TestSimplePlayback(const char* encrypted_media, const char* media_type) {
260 RunSimpleEncryptedMediaTest(
261 encrypted_media, media_type, CurrentKeySystem(), CurrentSourceType());
264 void TestFrameSizeChange() {
265 #if defined(WIDEVINE_CDM_AVAILABLE)
266 if (IsWidevine(CurrentKeySystem())) {
267 VLOG(0) << "FrameSizeChange test cannot run with Widevine.";
268 return;
270 #endif // defined(WIDEVINE_CDM_AVAILABLE)
271 RunEncryptedMediaTest("encrypted_frame_size_change.html",
272 "frame_size_change-av-enc-v.webm", kWebMAudioVideo,
273 CurrentKeySystem(), CurrentSourceType(), kEnded);
276 void TestConfigChange() {
277 if (CurrentSourceType() != MSE || !IsMSESupported()) {
278 VLOG(0) << "Skipping test - config change test requires MSE.";
279 return;
281 #if defined(WIDEVINE_CDM_AVAILABLE)
282 if (IsWidevine(CurrentKeySystem())) {
283 VLOG(0) << "ConfigChange test cannot run with Widevine.";
284 return;
286 #endif // defined(WIDEVINE_CDM_AVAILABLE)
287 std::vector<StringPair> query_params;
288 query_params.push_back(std::make_pair("keysystem", CurrentKeySystem()));
289 query_params.push_back(std::make_pair("runencrypted", "1"));
290 RunMediaTestPage("mse_config_change.html", &query_params, kEnded, true);
293 protected:
294 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
295 EncryptedMediaTestBase::SetUpCommandLine(command_line);
296 SetUpCommandLineForKeySystem(CurrentKeySystem(), command_line);
300 using ::testing::Combine;
301 using ::testing::Values;
303 #if !defined(OS_ANDROID)
304 INSTANTIATE_TEST_CASE_P(SRC_ClearKey, EncryptedMediaTest,
305 Combine(Values(kClearKeyKeySystem), Values(SRC)));
306 #endif // !defined(OS_ANDROID)
308 INSTANTIATE_TEST_CASE_P(MSE_ClearKey, EncryptedMediaTest,
309 Combine(Values(kClearKeyKeySystem), Values(MSE)));
311 // External Clear Key is currently only used on platforms that use Pepper CDMs.
312 #if defined(ENABLE_PEPPER_CDMS)
313 INSTANTIATE_TEST_CASE_P(SRC_ExternalClearKey, EncryptedMediaTest,
314 Combine(Values(kExternalClearKeyKeySystem), Values(SRC)));
315 INSTANTIATE_TEST_CASE_P(MSE_ExternalClearKey, EncryptedMediaTest,
316 Combine(Values(kExternalClearKeyKeySystem), Values(MSE)));
317 // To reduce test time, only run ExternalClearKeyDecryptOnly with MSE.
318 INSTANTIATE_TEST_CASE_P(MSE_ExternalClearKeyDecryptOnly, EncryptedMediaTest,
319 Combine(Values(kExternalClearKeyDecryptOnlyKeySystem), Values(MSE)));
320 #endif // defined(ENABLE_PEPPER_CDMS)
322 #if defined(WIDEVINE_CDM_AVAILABLE)
323 // This test doesn't fully test playback with Widevine. So we only run Widevine
324 // test with MSE (no SRC) to reduce test time. Also, on Android EME only works
325 // with MSE and we cannot run this test with SRC.
326 INSTANTIATE_TEST_CASE_P(MSE_Widevine, EncryptedMediaTest,
327 Combine(Values(kWidevineKeySystem), Values(MSE)));
328 #endif // defined(WIDEVINE_CDM_AVAILABLE)
330 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_WebM) {
331 TestSimplePlayback("bear-a-enc_a.webm", kWebMAudioOnly);
334 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioClearVideo_WebM) {
335 TestSimplePlayback("bear-320x240-av-enc_a.webm", kWebMAudioVideo);
338 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM) {
339 TestSimplePlayback("bear-320x240-av-enc_av.webm", kWebMAudioVideo);
342 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM) {
343 TestSimplePlayback("bear-320x240-v-enc_v.webm", kWebMVideoOnly);
346 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM) {
347 TestSimplePlayback("bear-320x240-av-enc_v.webm", kWebMAudioVideo);
350 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, ConfigChangeVideo) {
351 TestConfigChange();
354 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, FrameSizeChangeVideo) {
355 // Times out on Windows XP. http://crbug.com/171937
356 #if defined(OS_WIN)
357 if (base::win::GetVersion() < base::win::VERSION_VISTA)
358 return;
359 #endif
360 TestFrameSizeChange();
363 #if defined(USE_PROPRIETARY_CODECS)
364 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4) {
365 // MP4 without MSE is not support yet, http://crbug.com/170793.
366 if (CurrentSourceType() != MSE) {
367 VLOG(0) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
368 return;
370 TestSimplePlayback("bear-640x360-v_frag-cenc.mp4", kMP4VideoOnly);
373 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_MP4) {
374 // MP4 without MSE is not support yet, http://crbug.com/170793.
375 if (CurrentSourceType() != MSE) {
376 VLOG(0) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
377 return;
379 TestSimplePlayback("bear-640x360-a_frag-cenc.mp4", kMP4AudioOnly);
381 #endif // defined(USE_PROPRIETARY_CODECS)
383 #if defined(WIDEVINE_CDM_AVAILABLE)
384 // The parent key system cannot be used in generateKeyRequest.
385 IN_PROC_BROWSER_TEST_F(WVEncryptedMediaTest, ParentThrowsException) {
386 RunEncryptedMediaTest("encrypted_media_player.html",
387 "bear-a-enc_a.webm",
388 kWebMAudioOnly,
389 "com.widevine",
390 MSE,
391 kEmeNotSupportedError);
393 #endif // defined(WIDEVINE_CDM_AVAILABLE)
395 #if defined(ENABLE_PEPPER_CDMS)
396 IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, InitializeCDMFail) {
397 RunEncryptedMediaTest("encrypted_media_player.html",
398 "bear-a-enc_a.webm",
399 kWebMAudioOnly,
400 kExternalClearKeyInitializeFailKeySystem,
401 SRC,
402 kEmeKeyError);
405 // When CDM crashes, we should still get a decode error.
406 IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, CDMCrashDuringDecode) {
407 RunEncryptedMediaTest("encrypted_media_player.html",
408 "bear-a-enc_a.webm",
409 kWebMAudioOnly,
410 kExternalClearKeyCrashKeySystem,
411 SRC,
412 kError);
415 IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, FileIOTest) {
416 RunEncryptedMediaTest("encrypted_media_player.html",
417 "bear-a-enc_a.webm",
418 kWebMAudioOnly,
419 kExternalClearKeyFileIOTestKeySystem,
420 SRC,
421 kFileIOTestSuccess);
423 #endif // defined(ENABLE_PEPPER_CDMS)