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
[] = "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.
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.";
73 #endif // defined(OS_ANDROID)
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
{
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
,
104 const char* expectation
) {
105 if (src_type
== MSE
&& !IsMSESupported()) {
106 VLOG(0) << "Skipping test - MSE not supported.";
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
));
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
,
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
);
141 #endif // defined(WIDEVINE_CDM_AVAILABLE)
143 RunEncryptedMediaTest("encrypted_media_player.html", media_file
,
144 media_type
, key_system
, src_type
, kEnded
);
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)
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;"));
193 pepper_plugin
.append(base::ASCIIToWide(GetPepperType(key_system
)));
195 pepper_plugin
.append(GetPepperType(key_system
));
197 command_line
->AppendSwitchNative(switches::kRegisterPepperPlugins
,
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
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
{
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
{
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
> > {
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.";
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.";
281 #if defined(WIDEVINE_CDM_AVAILABLE)
282 if (IsWidevine(CurrentKeySystem())) {
283 VLOG(0) << "ConfigChange test cannot run with Widevine.";
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);
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
) {
354 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest
, FrameSizeChangeVideo
) {
355 // Times out on Windows XP. http://crbug.com/171937
357 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
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.";
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.";
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",
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",
400 kExternalClearKeyInitializeFailKeySystem
,
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",
410 kExternalClearKeyCrashKeySystem
,
415 IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest
, FileIOTest
) {
416 RunEncryptedMediaTest("encrypted_media_player.html",
419 kExternalClearKeyFileIOTestKeySystem
,
423 #endif // defined(ENABLE_PEPPER_CDMS)