Home | History | Annotate | Download | only in media
      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