1 // Copyright (c) 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 "content/browser/media/media_browsertest.h" 10 #include "content/public/common/content_switches.h" 11 #include "content/public/test/browser_test_utils.h" 12 #include "content/shell/shell.h" 13 14 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. 15 16 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(OS_LINUX) 17 #include <gnu/libc-version.h> 18 #endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(OS_LINUX) 19 20 #if defined(ENABLE_PEPPER_CDMS) 21 // Platform-specific filename relative to the chrome executable. 22 static 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 #endif // defined(ENABLE_PEPPER_CDMS) 31 32 // Available key systems. 33 static const char kClearKeyKeySystem[] = "webkit-org.w3.clearkey"; 34 static const char kExternalClearKeyKeySystem[] = 35 "org.chromium.externalclearkey"; 36 37 // Supported media types. 38 static const char kWebMAudioOnly[] = "audio/webm; codecs=\"vorbis\""; 39 static const char kWebMVideoOnly[] = "video/webm; codecs=\"vp8\""; 40 static const char kWebMAudioVideo[] = "video/webm; codecs=\"vorbis, vp8\""; 41 static const char kMP4AudioOnly[] = "audio/mp4; codecs=\"mp4a.40.2\""; 42 static const char kMP4VideoOnly[] = "video/mp4; codecs=\"avc1.4D4041\""; 43 44 // Common test expectations. 45 static const char kKeyError[] = "KEYERROR"; 46 47 // The type of video src used to load media. 48 enum SrcType { 49 SRC, 50 MSE 51 }; 52 53 namespace content { 54 55 // Tests encrypted media playback with a combination of parameters: 56 // - char*: Key system name. 57 // - bool: True to load media using MSE, otherwise use src. 58 class EncryptedMediaTest : public content::MediaBrowserTest, 59 public testing::WithParamInterface<std::tr1::tuple<const char*, SrcType> > { 60 public: 61 void TestSimplePlayback(const char* encrypted_media, const char* media_type, 62 const std::tr1::tuple<const char*, SrcType> test_params, 63 const char* expectation) { 64 const char* key_system = std::tr1::get<0>(test_params); 65 SrcType src_type = std::tr1::get<1>(test_params); 66 RunEncryptedMediaTest("encrypted_media_player.html", encrypted_media, 67 media_type, key_system, src_type, expectation); 68 } 69 70 void TestMSESimplePlayback(const char* encrypted_media, 71 const char* media_type, const char* key_system, 72 const char* expectation) { 73 RunEncryptedMediaTest("encrypted_media_player.html", encrypted_media, 74 media_type, key_system, MSE, expectation); 75 } 76 77 void TestFrameSizeChange( 78 const std::tr1::tuple<const char*, SrcType> test_params, 79 const char* expectation) { 80 const char* key_system = std::tr1::get<0>(test_params); 81 SrcType src_type = std::tr1::get<1>(test_params); 82 RunEncryptedMediaTest("encrypted_frame_size_change.html", 83 "frame_size_change-av-enc-v.webm", kWebMAudioVideo, 84 key_system, src_type, expectation); 85 } 86 87 void TestConfigChange(const char* key_system, const char* expectation) { 88 std::vector<StringPair> query_params; 89 query_params.push_back(std::make_pair("keysystem", key_system)); 90 query_params.push_back(std::make_pair("runencrypted", "1")); 91 RunMediaTestPage("mse_config_change.html", &query_params, expectation, 92 true); 93 } 94 95 void RunEncryptedMediaTest(const char* html_page, const char* media_file, 96 const char* media_type, const char* key_system, 97 SrcType src_type, const char* expectation) { 98 std::vector<StringPair> query_params; 99 query_params.push_back(std::make_pair("mediafile", media_file)); 100 query_params.push_back(std::make_pair("mediatype", media_type)); 101 query_params.push_back(std::make_pair("keysystem", key_system)); 102 if (src_type == MSE) 103 query_params.push_back(std::make_pair("usemse", "1")); 104 RunMediaTestPage(html_page, &query_params, expectation, true); 105 } 106 107 protected: 108 #if defined(ENABLE_PEPPER_CDMS) 109 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 110 RegisterPepperCdm(command_line, kClearKeyCdmAdapterFileName, 111 kExternalClearKeyKeySystem); 112 } 113 114 virtual void RegisterPepperCdm(CommandLine* command_line, 115 const std::string& adapter_name, 116 const std::string& key_system) { 117 // Append the switch to register the Clear Key CDM Adapter. 118 base::FilePath plugin_dir; 119 EXPECT_TRUE(PathService::Get(base::DIR_MODULE, &plugin_dir)); 120 base::FilePath plugin_lib = plugin_dir.AppendASCII(adapter_name); 121 EXPECT_TRUE(base::PathExists(plugin_lib)); 122 base::FilePath::StringType pepper_plugin = plugin_lib.value(); 123 pepper_plugin.append(FILE_PATH_LITERAL("#CDM#0.1.0.0;")); 124 #if defined(OS_WIN) 125 pepper_plugin.append(ASCIIToWide(GetPepperType(key_system))); 126 #else 127 pepper_plugin.append(GetPepperType(key_system)); 128 #endif 129 command_line->AppendSwitchNative(switches::kRegisterPepperPlugins, 130 pepper_plugin); 131 } 132 133 // Adapted from key_systems.cc. 134 std::string GetPepperType(const std::string& key_system) { 135 if (key_system == kExternalClearKeyKeySystem) 136 return "application/x-ppapi-clearkey-cdm"; 137 #if defined(WIDEVINE_CDM_AVAILABLE) 138 if (key_system == kWidevineKeySystem) 139 return "application/x-ppapi-widevine-cdm"; 140 #endif // WIDEVINE_CDM_AVAILABLE 141 142 NOTREACHED(); 143 return ""; 144 } 145 #endif // defined(ENABLE_PEPPER_CDMS) 146 }; 147 148 #if defined(WIDEVINE_CDM_AVAILABLE) 149 class WVEncryptedMediaTest : public EncryptedMediaTest { 150 public: 151 // Tests that the following happen after trying to play encrypted media: 152 // - webkitneedkey event is fired. 153 // - webkitGenerateKeyRequest() does not fail. 154 // - webkitkeymessage is fired 155 // - webkitAddKey() generates a WebKitKeyError since no real WV key is added. 156 void TestMSESimplePlayback(const char* encrypted_media, 157 const char* media_type, const char* key_system) { 158 // TODO(shadi): Remove after bots upgrade to precise. 159 // Don't run on lucid bots since the CDM is not compatible (glibc < 2.14) 160 #if defined(OS_LINUX) 161 if (strcmp(gnu_get_libc_version(), "2.11.1") == 0) { 162 LOG(INFO) << "Skipping test; not supported on glibc version: " 163 << gnu_get_libc_version(); 164 return; 165 } 166 #endif // defined(OS_LINUX) 167 EncryptedMediaTest::TestMSESimplePlayback(encrypted_media, media_type, 168 key_system, kKeyError); 169 bool receivedKeyMessage = false; 170 EXPECT_TRUE(ExecuteScriptAndExtractBool( 171 shell()->web_contents(), 172 "window.domAutomationController.send(video.receivedKeyMessage);", 173 &receivedKeyMessage)); 174 ASSERT_TRUE(receivedKeyMessage); 175 } 176 177 protected: 178 #if defined(ENABLE_PEPPER_CDMS) 179 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 180 RegisterPepperCdm(command_line, kWidevineCdmAdapterFileName, 181 kWidevineKeySystem); 182 } 183 #endif // defined(ENABLE_PEPPER_CDMS) 184 }; 185 #endif // defined(WIDEVINE_CDM_AVAILABLE) 186 187 INSTANTIATE_TEST_CASE_P(ClearKey, EncryptedMediaTest, 188 ::testing::Combine( 189 ::testing::Values(kClearKeyKeySystem), ::testing::Values(SRC, MSE))); 190 191 // External Clear Key is currently only used on platforms that use Pepper CDMs. 192 #if defined(ENABLE_PEPPER_CDMS) 193 INSTANTIATE_TEST_CASE_P(ExternalClearKey, EncryptedMediaTest, 194 ::testing::Combine( 195 ::testing::Values(kExternalClearKeyKeySystem), 196 ::testing::Values(SRC, MSE))); 197 198 IN_PROC_BROWSER_TEST_F(EncryptedMediaTest, ConfigChangeVideo_ExternalClearKey) { 199 TestConfigChange(kExternalClearKeyKeySystem, kEnded); 200 } 201 #endif // defined(ENABLE_PEPPER_CDMS) 202 203 IN_PROC_BROWSER_TEST_F(EncryptedMediaTest, ConfigChangeVideo_ClearKey) { 204 TestConfigChange(kClearKeyKeySystem, kEnded); 205 } 206 207 IN_PROC_BROWSER_TEST_F(EncryptedMediaTest, InvalidKeySystem) { 208 TestMSESimplePlayback("bear-320x240-av-enc_av.webm", kWebMAudioVideo, 209 "com.example.invalid", 210 "GENERATE_KEY_REQUEST_EXCEPTION"); 211 } 212 213 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_WebM) { 214 TestSimplePlayback("bear-a-enc_a.webm", kWebMAudioOnly, GetParam(), kEnded); 215 } 216 217 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioClearVideo_WebM) { 218 TestSimplePlayback("bear-320x240-av-enc_a.webm", kWebMAudioVideo, GetParam(), 219 kEnded); 220 } 221 222 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM) { 223 TestSimplePlayback("bear-320x240-av-enc_av.webm", kWebMAudioVideo, GetParam(), 224 kEnded); 225 } 226 227 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM) { 228 TestSimplePlayback("bear-320x240-v-enc_v.webm", kWebMVideoOnly, GetParam(), 229 kEnded); 230 } 231 232 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM) { 233 TestSimplePlayback("bear-320x240-av-enc_v.webm", kWebMAudioVideo, GetParam(), 234 kEnded); 235 } 236 237 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, FrameChangeVideo) { 238 // Times out on Windows XP. http://crbug.com/171937 239 #if defined(OS_WIN) 240 if (base::win::GetVersion() < base::win::VERSION_VISTA) 241 return; 242 #endif 243 TestFrameSizeChange(GetParam(), kEnded); 244 } 245 246 #if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS) 247 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4) { 248 std::tr1::tuple<const char*, SrcType> test_params = GetParam(); 249 // MP4 without MSE is not support yet, http://crbug.com/170793. 250 if (std::tr1::get<1>(test_params) != MSE) { 251 LOG(INFO) << "Skipping test; Can only play MP4 encrypted streams by MSE."; 252 return; 253 } 254 TestMSESimplePlayback("bear-640x360-v_frag-cenc.mp4", kMP4VideoOnly, 255 std::tr1::get<0>(test_params), kEnded); 256 } 257 258 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_MP4) { 259 std::tr1::tuple<const char*, SrcType> test_params = GetParam(); 260 // MP4 without MSE is not support yet, http://crbug.com/170793. 261 if (std::tr1::get<1>(test_params) != MSE) { 262 LOG(INFO) << "Skipping test; Can only play MP4 encrypted streams by MSE."; 263 return; 264 } 265 TestMSESimplePlayback("bear-640x360-a_frag-cenc.mp4", kMP4AudioOnly, 266 std::tr1::get<0>(test_params), kEnded); 267 } 268 #endif 269 270 // Run only when WV CDM is available. 271 #if defined(WIDEVINE_CDM_AVAILABLE) 272 IN_PROC_BROWSER_TEST_F(WVEncryptedMediaTest, Playback_AudioOnly_WebM) { 273 TestMSESimplePlayback("bear-a-enc_a.webm", kWebMAudioOnly, 274 kWidevineKeySystem); 275 } 276 277 IN_PROC_BROWSER_TEST_F(WVEncryptedMediaTest, Playback_AudioClearVideo_WebM) { 278 TestMSESimplePlayback("bear-320x240-av-enc_a.webm", kWebMAudioVideo, 279 kWidevineKeySystem); 280 } 281 282 IN_PROC_BROWSER_TEST_F(WVEncryptedMediaTest, Playback_VideoAudio_WebM) { 283 TestMSESimplePlayback("bear-320x240-av-enc_av.webm", kWebMAudioVideo, 284 kWidevineKeySystem); 285 } 286 287 IN_PROC_BROWSER_TEST_F(WVEncryptedMediaTest, Playback_VideoOnly_WebM) { 288 TestMSESimplePlayback("bear-320x240-v-enc_v.webm", kWebMVideoOnly, 289 kWidevineKeySystem); 290 } 291 292 IN_PROC_BROWSER_TEST_F(WVEncryptedMediaTest, Playback_VideoClearAudio_WebM) { 293 TestMSESimplePlayback("bear-320x240-av-enc_v.webm", kWebMAudioVideo, 294 kWidevineKeySystem); 295 } 296 297 #if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS) 298 IN_PROC_BROWSER_TEST_F(WVEncryptedMediaTest, Playback_VideoOnly_MP4) { 299 TestMSESimplePlayback("bear-640x360-v_frag-cenc.mp4", kMP4VideoOnly, 300 kWidevineKeySystem); 301 } 302 303 IN_PROC_BROWSER_TEST_F(WVEncryptedMediaTest, Playback_AudioOnly_MP4) { 304 TestMSESimplePlayback("bear-640x360-a_frag-cenc.mp4", kMP4AudioOnly, 305 kWidevineKeySystem); 306 } 307 #endif // defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS) 308 #endif // defined(WIDEVINE_CDM_AVAILABLE) 309 310 } // namespace content 311