- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / media / encrypted_media_browsertest.cc
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.
4
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
17
18 #include "widevine_cdm_version.h"  // In SHARED_INTERMEDIATE_DIR.
19
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
30
31 const char kClearKeyCdmPluginMimeType[] = "application/x-ppapi-clearkey-cdm";
32 #endif  // defined(ENABLE_PEPPER_CDMS)
33
34 // Available key systems.
35 const char kClearKeyKeySystem[] = "webkit-org.w3.clearkey";
36 const char kExternalClearKeyKeySystem[] =
37     "org.chromium.externalclearkey";
38
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)
47
48 // EME-specific test results and errors.
49 const char kEmeKeyError[] = "KEYERROR";
50 const char kEmeNotSupportedError[] = "NOTSUPPORTEDERROR";
51
52 // The type of video src used to load media.
53 enum SrcType {
54   SRC,
55   MSE
56 };
57
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.";
63     return false;
64   }
65 #endif  // defined(OS_ANDROID)
66   return true;
67 }
68
69 // Base class for encrypted media tests.
70 class EncryptedMediaTestBase : public MediaBrowserTest {
71  public:
72   EncryptedMediaTestBase() : is_pepper_cdm_registered_(false) {}
73
74   bool IsExternalClearKey(const char* key_system) {
75     return (strcmp(key_system, kExternalClearKeyKeySystem) == 0);
76   }
77
78 #if defined(WIDEVINE_CDM_AVAILABLE)
79   bool IsWidevine(const char* key_system) {
80     return (strcmp(key_system, kWidevineKeySystem) == 0);
81   }
82 #endif  // defined(WIDEVINE_CDM_AVAILABLE)
83
84   void RunEncryptedMediaTest(const char* html_page,
85                              const char* media_file,
86                              const char* media_type,
87                              const char* key_system,
88                              SrcType src_type,
89                              const char* expectation) {
90     if (src_type == MSE && !IsMSESupported()) {
91       LOG(INFO) << "Skipping test - MSE not supported.";
92       return;
93     }
94
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));
99     if (src_type == MSE)
100       query_params.push_back(std::make_pair("usemse", "1"));
101     RunMediaTestPage(html_page, &query_params, expectation, true);
102   }
103
104   void RunSimpleEncryptedMediaTest(const char* media_file,
105                                    const char* media_type,
106                                    const char* key_system,
107                                    SrcType src_type) {
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);
117
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);
124       return;
125     }
126 #endif  // defined(WIDEVINE_CDM_AVAILABLE)
127
128     RunEncryptedMediaTest("encrypted_media_player.html", media_file,
129                           media_type, key_system, src_type, kEnded);
130   }
131
132  protected:
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));
138   }
139
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)
145   }
146
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);
153     }
154 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
155     else if (IsWidevine(key_system)) {
156       RegisterPepperCdm(command_line, kWidevineCdmAdapterFileName,
157                         kWidevineKeySystem);
158     }
159 #endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
160 #endif  // defined(ENABLE_PEPPER_CDMS)
161   }
162
163  private:
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;
171
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;"));
179 #if defined(OS_WIN)
180     pepper_plugin.append(ASCIIToWide(GetPepperType(key_system)));
181 #else
182     pepper_plugin.append(GetPepperType(key_system));
183 #endif
184     command_line->AppendSwitchNative(switches::kRegisterPepperPlugins,
185                                      pepper_plugin);
186   }
187
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
196
197     NOTREACHED();
198     return "";
199   }
200 #endif  // defined(ENABLE_PEPPER_CDMS)
201
202   bool is_pepper_cdm_registered_;
203 };
204
205 #if defined(ENABLE_PEPPER_CDMS)
206 // Tests encrypted media playback using ExternalClearKey key system.
207 class ECKEncryptedMediaTest : public EncryptedMediaTestBase {
208  protected:
209   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
210     EncryptedMediaTestBase::SetUpCommandLine(command_line);
211     SetUpCommandLineForKeySystem(kExternalClearKeyKeySystem, command_line);
212   }
213 };
214
215 #if defined(WIDEVINE_CDM_AVAILABLE)
216 // Tests encrypted media playback using Widevine key system.
217 class WVEncryptedMediaTest : public EncryptedMediaTestBase {
218  protected:
219   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
220     EncryptedMediaTestBase::SetUpCommandLine(command_line);
221     SetUpCommandLineForKeySystem(kWidevineKeySystem, command_line);
222   }
223 };
224 #endif  // defined(WIDEVINE_CDM_AVAILABLE)
225 #endif  // defined(ENABLE_PEPPER_CDMS)
226
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.
230 //
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> > {
236  public:
237   const char* CurrentKeySystem() {
238     return std::tr1::get<0>(GetParam());
239   }
240
241   SrcType CurrentSourceType() {
242     return std::tr1::get<1>(GetParam());
243   }
244
245   void TestSimplePlayback(const char* encrypted_media, const char* media_type) {
246     RunSimpleEncryptedMediaTest(
247         encrypted_media, media_type, CurrentKeySystem(), CurrentSourceType());
248   }
249
250   void TestFrameSizeChange() {
251 #if defined(WIDEVINE_CDM_AVAILABLE)
252     if (IsWidevine(CurrentKeySystem())) {
253       LOG(INFO) << "FrameSizeChange test cannot run with Widevine.";
254       return;
255     }
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);
260   }
261
262   void TestConfigChange() {
263     if (CurrentSourceType() != MSE || !IsMSESupported()) {
264       LOG(INFO) << "Skipping test - config change test requires MSE.";
265       return;
266     }
267 #if defined(WIDEVINE_CDM_AVAILABLE)
268     if (IsWidevine(CurrentKeySystem())) {
269       LOG(INFO) << "ConfigChange test cannot run with Widevine.";
270       return;
271     }
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);
277   }
278
279  protected:
280   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
281     EncryptedMediaTestBase::SetUpCommandLine(command_line);
282     SetUpCommandLineForKeySystem(CurrentKeySystem(), command_line);
283   }
284 };
285
286 using ::testing::Combine;
287 using ::testing::Values;
288
289 #if !defined(OS_ANDROID)
290 INSTANTIATE_TEST_CASE_P(SRC_ClearKey, EncryptedMediaTest,
291     Combine(Values(kClearKeyKeySystem), Values(SRC)));
292 #endif  // !defined(OS_ANDROID)
293
294 INSTANTIATE_TEST_CASE_P(MSE_ClearKey, EncryptedMediaTest,
295     Combine(Values(kClearKeyKeySystem), Values(MSE)));
296
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)
304
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)
312
313 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_WebM) {
314   TestSimplePlayback("bear-a-enc_a.webm", kWebMAudioOnly);
315 }
316
317 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioClearVideo_WebM) {
318   TestSimplePlayback("bear-320x240-av-enc_a.webm", kWebMAudioVideo);
319 }
320
321 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM) {
322   TestSimplePlayback("bear-320x240-av-enc_av.webm", kWebMAudioVideo);
323 }
324
325 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM) {
326   TestSimplePlayback("bear-320x240-v-enc_v.webm", kWebMVideoOnly);
327 }
328
329 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM) {
330   TestSimplePlayback("bear-320x240-av-enc_v.webm", kWebMAudioVideo);
331 }
332
333 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, ConfigChangeVideo) {
334   TestConfigChange();
335 }
336
337 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, FrameSizeChangeVideo) {
338   // Times out on Windows XP. http://crbug.com/171937
339 #if defined(OS_WIN)
340   if (base::win::GetVersion() < base::win::VERSION_VISTA)
341     return;
342 #endif
343   TestFrameSizeChange();
344 }
345
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.";
351     return;
352   }
353   TestSimplePlayback("bear-640x360-v_frag-cenc.mp4", kMP4VideoOnly);
354 }
355
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.";
360     return;
361   }
362   TestSimplePlayback("bear-640x360-a_frag-cenc.mp4", kMP4AudioOnly);
363 }
364 #endif  // defined(USE_PROPRIETARY_CODECS)
365
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",
370                         "bear-a-enc_a.webm",
371                         kWebMAudioOnly,
372                         "com.widevine",
373                         MSE,
374                         kEmeNotSupportedError);
375 }
376 #endif  // defined(WIDEVINE_CDM_AVAILABLE)
377
378 #if defined(ENABLE_PEPPER_CDMS)
379 IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest,
380                        ExternalClearKeyInitializeCDMFail) {
381   RunEncryptedMediaTest("encrypted_media_player.html",
382                         "bear-a-enc_a.webm",
383                         kWebMAudioOnly,
384                         "org.chromium.externalclearkey.initializefail",
385                         SRC,
386                         kEmeKeyError);
387 }
388 #endif  // defined(ENABLE_PEPPER_CDMS)