Upstream version 5.34.104.0
[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/memory/scoped_ptr.h"
7 #include "base/path_service.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/win/windows_version.h"
10 #include "chrome/browser/media/media_browsertest.h"
11 #include "chrome/browser/media/test_license_server.h"
12 #include "chrome/browser/media/wv_test_license_server_config.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "content/public/test/browser_test_utils.h"
17 #if defined(OS_ANDROID)
18 #include "base/android/build_info.h"
19 #endif
20
21 #include "widevine_cdm_version.h"  //  In SHARED_INTERMEDIATE_DIR.
22
23 #if defined(ENABLE_PEPPER_CDMS)
24 // Platform-specific filename relative to the chrome executable.
25 const char kClearKeyCdmAdapterFileName[] =
26 #if defined(OS_MACOSX)
27     "clearkeycdmadapter.plugin";
28 #elif defined(OS_WIN)
29     "clearkeycdmadapter.dll";
30 #elif defined(OS_POSIX)
31     "libclearkeycdmadapter.so";
32 #endif
33
34 const char kClearKeyCdmPluginMimeType[] = "application/x-ppapi-clearkey-cdm";
35 #endif  // defined(ENABLE_PEPPER_CDMS)
36
37 // Available key systems.
38 const char kClearKeyKeySystem[] = "webkit-org.w3.clearkey";
39 const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey";
40 const char kExternalClearKeyDecryptOnlyKeySystem[] =
41     "org.chromium.externalclearkey.decryptonly";
42 const char kExternalClearKeyFileIOTestKeySystem[] =
43     "org.chromium.externalclearkey.fileiotest";
44 const char kExternalClearKeyInitializeFailKeySystem[] =
45     "org.chromium.externalclearkey.initializefail";
46 const char kExternalClearKeyCrashKeySystem[] =
47     "org.chromium.externalclearkey.crash";
48
49 // Supported media types.
50 const char kWebMAudioOnly[] = "audio/webm; codecs=\"vorbis\"";
51 const char kWebMVideoOnly[] = "video/webm; codecs=\"vp8\"";
52 const char kWebMAudioVideo[] = "video/webm; codecs=\"vorbis, vp8\"";
53 #if defined(USE_PROPRIETARY_CODECS)
54 const char kMP4AudioOnly[] = "audio/mp4; codecs=\"mp4a.40.2\"";
55 const char kMP4VideoOnly[] = "video/mp4; codecs=\"avc1.4D4041\"";
56 #endif  // defined(USE_PROPRIETARY_CODECS)
57
58 // Sessions to load.
59 const char kNoSessionToLoad[] = "";
60 const char kLoadableSession[] = "LoadableSession";
61 const char kUnknownSession[] = "UnknownSession";
62
63 // EME-specific test results and errors.
64 const char kEmeKeyError[] = "KEYERROR";
65 const char kEmeNotSupportedError[] = "NOTSUPPORTEDERROR";
66 const char kFileIOTestSuccess[] = "FILEIOTESTSUCCESS";
67
68 // The type of video src used to load media.
69 enum SrcType {
70   SRC,
71   MSE
72 };
73
74 // MSE is available on all desktop platforms and on Android 4.1 and later.
75 static bool IsMSESupported() {
76 #if defined(OS_ANDROID)
77   if (base::android::BuildInfo::GetInstance()->sdk_int() < 16) {
78     VLOG(0) << "MSE is only supported in Android 4.1 and later.";
79     return false;
80   }
81 #endif  // defined(OS_ANDROID)
82   return true;
83 }
84
85 static bool IsParentKeySystemOf(const std::string& parent_key_system,
86                                 const std::string& key_system) {
87   std::string prefix = parent_key_system + '.';
88   return key_system.substr(0, prefix.size()) == prefix;
89 }
90
91 // Base class for encrypted media tests.
92 class EncryptedMediaTestBase : public MediaBrowserTest {
93  public:
94   EncryptedMediaTestBase() : is_pepper_cdm_registered_(false) {}
95
96   bool IsExternalClearKey(const std::string& key_system) {
97     return key_system == kExternalClearKeyKeySystem ||
98            IsParentKeySystemOf(kExternalClearKeyKeySystem, key_system);
99   }
100
101 #if defined(WIDEVINE_CDM_AVAILABLE)
102   bool IsWidevine(const std::string& key_system) {
103     return key_system == kWidevineKeySystem;
104   }
105 #endif  // defined(WIDEVINE_CDM_AVAILABLE)
106
107   void RunEncryptedMediaTestPage(const std::string& html_page,
108                                  const std::string& key_system,
109                                  std::vector<StringPair>* query_params,
110                                  const std::string& expected_title) {
111     StartLicenseServerIfNeeded(key_system, query_params);
112     RunMediaTestPage(html_page, query_params, expected_title, true);
113   }
114
115   // Tests |html_page| using |media_file| (with |media_type|) and |key_system|.
116   // When |session_to_load| is not empty, the test will try to load
117   // |session_to_load| with stored keys, instead of creating a new session
118   // and trying to update it with licenses.
119   // When |force_invalid_response| is true, the test will provide invalid
120   // responses, which should trigger errors.
121   // TODO(xhwang): Find an easier way to pass multiple configuration test
122   // options.
123   void RunEncryptedMediaTest(const std::string& html_page,
124                              const std::string& media_file,
125                              const std::string& media_type,
126                              const std::string& key_system,
127                              SrcType src_type,
128                              const std::string& session_to_load,
129                              bool force_invalid_response,
130                              const std::string& expected_title) {
131     if (src_type == MSE && !IsMSESupported()) {
132       VLOG(0) << "Skipping test - MSE not supported.";
133       return;
134     }
135     std::vector<StringPair> query_params;
136     query_params.push_back(std::make_pair("mediaFile", media_file));
137     query_params.push_back(std::make_pair("mediaType", media_type));
138     query_params.push_back(std::make_pair("keySystem", key_system));
139     if (src_type == MSE)
140       query_params.push_back(std::make_pair("useMSE", "1"));
141     if (force_invalid_response)
142       query_params.push_back(std::make_pair("forceInvalidResponse", "1"));
143     if (!session_to_load.empty())
144       query_params.push_back(std::make_pair("sessionToLoad", session_to_load));
145     RunEncryptedMediaTestPage(html_page, key_system, &query_params,
146                               expected_title);
147   }
148
149   void RunSimpleEncryptedMediaTest(const std::string& media_file,
150                                    const std::string& media_type,
151                                    const std::string& key_system,
152                                    SrcType src_type) {
153     std::string expected_title = kEnded;
154     if (!IsPlayBackPossible(key_system))
155       expected_title = kEmeKeyError;
156
157     RunEncryptedMediaTest("encrypted_media_player.html", media_file, media_type,
158                           key_system, src_type, kNoSessionToLoad, false,
159                           expected_title);
160     // Check KeyMessage received for all key systems.
161     bool receivedKeyMessage = false;
162     EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
163         browser()->tab_strip_model()->GetActiveWebContents(),
164         "window.domAutomationController.send(video.receivedKeyMessage);",
165         &receivedKeyMessage));
166     EXPECT_TRUE(receivedKeyMessage);
167   }
168
169
170   void StartLicenseServerIfNeeded(const std::string& key_system,
171                                   std::vector<StringPair>* query_params) {
172     scoped_ptr<TestLicenseServerConfig> config = GetServerConfig(key_system);
173     if (!config)
174       return;
175     license_server_.reset(new TestLicenseServer(config.Pass()));
176     EXPECT_TRUE(license_server_->Start());
177     query_params->push_back(std::make_pair("licenseServerURL",
178         license_server_->GetServerURL()));
179   }
180
181   bool IsPlayBackPossible(const std::string& key_system) {
182 #if defined(WIDEVINE_CDM_AVAILABLE)
183     if (IsWidevine(key_system) && !GetServerConfig(key_system))
184       return false;
185 #endif  // defined(WIDEVINE_CDM_AVAILABLE)
186     return true;
187   }
188
189   scoped_ptr<TestLicenseServerConfig> GetServerConfig(
190       const std::string& key_system) {
191 #if defined(WIDEVINE_CDM_AVAILABLE)
192     if (IsWidevine(key_system)) {
193       scoped_ptr<TestLicenseServerConfig> config =
194          scoped_ptr<TestLicenseServerConfig>(new WVTestLicenseServerConfig());
195       if (config->IsPlatformSupported())
196         return config.Pass();
197     }
198 #endif  // defined(WIDEVINE_CDM_AVAILABLE)
199     return scoped_ptr<TestLicenseServerConfig>();
200   }
201
202  protected:
203   scoped_ptr<TestLicenseServer> license_server_;
204
205   // We want to fail quickly when a test fails because an error is encountered.
206   virtual void AddWaitForTitles(content::TitleWatcher* title_watcher) OVERRIDE {
207     MediaBrowserTest::AddWaitForTitles(title_watcher);
208     title_watcher->AlsoWaitForTitle(base::ASCIIToUTF16(kEmeNotSupportedError));
209     title_watcher->AlsoWaitForTitle(base::ASCIIToUTF16(kEmeKeyError));
210   }
211
212   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
213 #if defined(OS_ANDROID)
214     command_line->AppendSwitch(
215         switches::kDisableGestureRequirementForMediaPlayback);
216 #endif  // defined(OS_ANDROID)
217   }
218
219   void SetUpCommandLineForKeySystem(const std::string& key_system,
220                                     CommandLine* command_line) {
221     if (GetServerConfig(key_system))
222       // Since the web and license servers listen on different ports, we need to
223       // disable web-security to send license requests to the license server.
224       // TODO(shadi): Add port forwarding to the test web server configuration.
225       command_line->AppendSwitch(switches::kDisableWebSecurity);
226
227 #if defined(ENABLE_PEPPER_CDMS)
228     if (IsExternalClearKey(key_system)) {
229       RegisterPepperCdm(command_line, kClearKeyCdmAdapterFileName, key_system);
230     }
231 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
232     else if (IsWidevine(key_system)) {
233       RegisterPepperCdm(command_line, kWidevineCdmAdapterFileName, key_system);
234     }
235 #endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
236 #endif  // defined(ENABLE_PEPPER_CDMS)
237   }
238
239  private:
240 #if defined(ENABLE_PEPPER_CDMS)
241   void RegisterPepperCdm(CommandLine* command_line,
242                          const std::string& adapter_name,
243                          const std::string& key_system) {
244     DCHECK(!is_pepper_cdm_registered_)
245         << "RegisterPepperCdm() can only be called once.";
246     is_pepper_cdm_registered_ = true;
247
248     // Append the switch to register the Clear Key CDM Adapter.
249     base::FilePath plugin_dir;
250     EXPECT_TRUE(PathService::Get(base::DIR_MODULE, &plugin_dir));
251     base::FilePath plugin_lib = plugin_dir.AppendASCII(adapter_name);
252     EXPECT_TRUE(base::PathExists(plugin_lib)) << plugin_lib.value();
253     base::FilePath::StringType pepper_plugin = plugin_lib.value();
254     pepper_plugin.append(FILE_PATH_LITERAL("#CDM#0.1.0.0;"));
255 #if defined(OS_WIN)
256     pepper_plugin.append(base::ASCIIToWide(GetPepperType(key_system)));
257 #else
258     pepper_plugin.append(GetPepperType(key_system));
259 #endif
260     command_line->AppendSwitchNative(switches::kRegisterPepperPlugins,
261                                      pepper_plugin);
262   }
263
264   // Adapted from key_systems.cc.
265   std::string GetPepperType(const std::string& key_system) {
266     if (IsExternalClearKey(key_system))
267       return kClearKeyCdmPluginMimeType;
268 #if defined(WIDEVINE_CDM_AVAILABLE)
269     if (IsWidevine(key_system))
270       return kWidevineCdmPluginMimeType;
271 #endif  // WIDEVINE_CDM_AVAILABLE
272
273     NOTREACHED();
274     return "";
275   }
276 #endif  // defined(ENABLE_PEPPER_CDMS)
277
278   bool is_pepper_cdm_registered_;
279 };
280
281 #if defined(ENABLE_PEPPER_CDMS)
282 // Tests encrypted media playback using ExternalClearKey key system in
283 // decrypt-and-decode mode.
284 class ECKEncryptedMediaTest : public EncryptedMediaTestBase {
285  public:
286   // We use special |key_system| names to do non-playback related tests, e.g.
287   // kExternalClearKeyFileIOTestKeySystem is used to test file IO.
288   void TestNonPlaybackCases(const std::string& key_system,
289                             const std::string& expected_title) {
290     // Since we do not test playback, arbitrarily choose a test file and source
291     // type.
292     RunEncryptedMediaTest("encrypted_media_player.html",
293                           "bear-a-enc_a.webm",
294                           kWebMAudioOnly,
295                           key_system,
296                           SRC,
297                           kNoSessionToLoad,
298                           false,
299                           expected_title);
300   }
301
302  protected:
303   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
304     EncryptedMediaTestBase::SetUpCommandLine(command_line);
305     SetUpCommandLineForKeySystem(kExternalClearKeyKeySystem, command_line);
306   }
307 };
308
309 #if defined(WIDEVINE_CDM_AVAILABLE)
310 // Tests encrypted media playback using Widevine key system.
311 class WVEncryptedMediaTest : public EncryptedMediaTestBase {
312  protected:
313   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
314     EncryptedMediaTestBase::SetUpCommandLine(command_line);
315     SetUpCommandLineForKeySystem(kWidevineKeySystem, command_line);
316   }
317 };
318
319 #endif  // defined(WIDEVINE_CDM_AVAILABLE)
320 #endif  // defined(ENABLE_PEPPER_CDMS)
321
322 // Tests encrypted media playback with a combination of parameters:
323 // - char*: Key system name.
324 // - bool: True to load media using MSE, otherwise use src.
325 //
326 // Note: Only parameterized (*_P) tests can be used. Non-parameterized (*_F)
327 // tests will crash at GetParam(). To add non-parameterized tests, use
328 // EncryptedMediaTestBase or one of its subclasses (e.g. WVEncryptedMediaTest).
329 class EncryptedMediaTest : public EncryptedMediaTestBase,
330   public testing::WithParamInterface<std::tr1::tuple<const char*, SrcType> > {
331  public:
332   std::string CurrentKeySystem() {
333     return std::tr1::get<0>(GetParam());
334   }
335
336   SrcType CurrentSourceType() {
337     return std::tr1::get<1>(GetParam());
338   }
339
340   void TestSimplePlayback(const std::string& encrypted_media,
341                           const std::string& media_type) {
342     RunSimpleEncryptedMediaTest(
343         encrypted_media, media_type, CurrentKeySystem(), CurrentSourceType());
344   }
345
346   void RunInvalidResponseTest() {
347     RunEncryptedMediaTest("encrypted_media_player.html",
348                           "bear-320x240-av-enc_av.webm",
349                           kWebMAudioVideo,
350                           CurrentKeySystem(),
351                           CurrentSourceType(),
352                           kNoSessionToLoad,
353                           true,
354                           kEmeKeyError);
355   }
356
357   void TestFrameSizeChange() {
358     RunEncryptedMediaTest("encrypted_frame_size_change.html",
359                           "frame_size_change-av-enc-v.webm",
360                           kWebMAudioVideo,
361                           CurrentKeySystem(),
362                           CurrentSourceType(),
363                           kNoSessionToLoad,
364                           false,
365                           kEnded);
366   }
367
368   void TestConfigChange() {
369     DCHECK(IsMSESupported());
370     std::vector<StringPair> query_params;
371     query_params.push_back(std::make_pair("keySystem", CurrentKeySystem()));
372     query_params.push_back(std::make_pair("runEncrypted", "1"));
373     RunEncryptedMediaTestPage("mse_config_change.html",
374                               CurrentKeySystem(),
375                               &query_params,
376                               kEnded);
377   }
378
379  protected:
380   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
381     EncryptedMediaTestBase::SetUpCommandLine(command_line);
382     SetUpCommandLineForKeySystem(CurrentKeySystem(), command_line);
383   }
384 };
385
386 using ::testing::Combine;
387 using ::testing::Values;
388
389 #if !defined(OS_ANDROID)
390 INSTANTIATE_TEST_CASE_P(SRC_ClearKey, EncryptedMediaTest,
391     Combine(Values(kClearKeyKeySystem), Values(SRC)));
392 #endif  // !defined(OS_ANDROID)
393
394 INSTANTIATE_TEST_CASE_P(MSE_ClearKey, EncryptedMediaTest,
395     Combine(Values(kClearKeyKeySystem), Values(MSE)));
396
397 // External Clear Key is currently only used on platforms that use Pepper CDMs.
398 #if defined(ENABLE_PEPPER_CDMS)
399 INSTANTIATE_TEST_CASE_P(SRC_ExternalClearKey, EncryptedMediaTest,
400     Combine(Values(kExternalClearKeyKeySystem), Values(SRC)));
401 INSTANTIATE_TEST_CASE_P(MSE_ExternalClearKey, EncryptedMediaTest,
402     Combine(Values(kExternalClearKeyKeySystem), Values(MSE)));
403 // To reduce test time, only run ExternalClearKeyDecryptOnly with MSE.
404 INSTANTIATE_TEST_CASE_P(MSE_ExternalClearKeyDecryptOnly, EncryptedMediaTest,
405     Combine(Values(kExternalClearKeyDecryptOnlyKeySystem), Values(MSE)));
406 #endif // defined(ENABLE_PEPPER_CDMS)
407
408 #if defined(WIDEVINE_CDM_AVAILABLE)
409 // This test doesn't fully test playback with Widevine. So we only run Widevine
410 // test with MSE (no SRC) to reduce test time. Also, on Android EME only works
411 // with MSE and we cannot run this test with SRC.
412 INSTANTIATE_TEST_CASE_P(MSE_Widevine, EncryptedMediaTest,
413     Combine(Values(kWidevineKeySystem), Values(MSE)));
414 #endif  // defined(WIDEVINE_CDM_AVAILABLE)
415
416 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_WebM) {
417   TestSimplePlayback("bear-a-enc_a.webm", kWebMAudioOnly);
418 }
419
420 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioClearVideo_WebM) {
421   TestSimplePlayback("bear-320x240-av-enc_a.webm", kWebMAudioVideo);
422 }
423
424 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM) {
425   TestSimplePlayback("bear-320x240-av-enc_av.webm", kWebMAudioVideo);
426 }
427
428 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM) {
429   TestSimplePlayback("bear-320x240-v-enc_v.webm", kWebMVideoOnly);
430 }
431
432 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM) {
433   TestSimplePlayback("bear-320x240-av-enc_v.webm", kWebMAudioVideo);
434 }
435
436 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, InvalidResponseKeyError) {
437   RunInvalidResponseTest();
438 }
439
440 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, ConfigChangeVideo) {
441   if (CurrentSourceType() != MSE || !IsMSESupported()) {
442     VLOG(0) << "Skipping test - ConfigChange test requires MSE.";
443     return;
444   }
445   if (!IsPlayBackPossible(CurrentKeySystem())) {
446     VLOG(0) << "Skipping test - ConfigChange test requires video playback.";
447     return;
448   }
449   TestConfigChange();
450 }
451
452 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, FrameSizeChangeVideo) {
453   // Times out on Windows XP. http://crbug.com/171937
454 #if defined(OS_WIN)
455   if (base::win::GetVersion() < base::win::VERSION_VISTA)
456     return;
457 #endif
458   if (!IsPlayBackPossible(CurrentKeySystem())) {
459     VLOG(0) << "Skipping test - FrameSizeChange test requires video playback.";
460     return;
461   }
462   TestFrameSizeChange();
463 }
464
465 #if defined(USE_PROPRIETARY_CODECS)
466 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4) {
467   // MP4 without MSE is not support yet, http://crbug.com/170793.
468   if (CurrentSourceType() != MSE) {
469     VLOG(0) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
470     return;
471   }
472   TestSimplePlayback("bear-640x360-v_frag-cenc.mp4", kMP4VideoOnly);
473 }
474
475 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_MP4) {
476   // MP4 without MSE is not support yet, http://crbug.com/170793.
477   if (CurrentSourceType() != MSE) {
478     VLOG(0) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
479     return;
480   }
481   TestSimplePlayback("bear-640x360-a_frag-cenc.mp4", kMP4AudioOnly);
482 }
483 #endif  // defined(USE_PROPRIETARY_CODECS)
484
485 #if defined(WIDEVINE_CDM_AVAILABLE)
486 // The parent key system cannot be used in generateKeyRequest.
487 IN_PROC_BROWSER_TEST_F(WVEncryptedMediaTest, ParentThrowsException) {
488   RunEncryptedMediaTest("encrypted_media_player.html",
489                         "bear-a-enc_a.webm",
490                         kWebMAudioOnly,
491                         "com.widevine",
492                         MSE,
493                         kNoSessionToLoad,
494                         false,
495                         kEmeNotSupportedError);
496 }
497 #endif  // defined(WIDEVINE_CDM_AVAILABLE)
498
499 #if defined(ENABLE_PEPPER_CDMS)
500 IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, InitializeCDMFail) {
501   TestNonPlaybackCases(kExternalClearKeyInitializeFailKeySystem, kEmeKeyError);
502 }
503
504 // When CDM crashes, we should still get a decode error.
505 IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, CDMCrashDuringDecode) {
506   TestNonPlaybackCases(kExternalClearKeyCrashKeySystem, kError);
507 }
508
509 IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, FileIOTest) {
510   TestNonPlaybackCases(kExternalClearKeyFileIOTestKeySystem,
511                        kFileIOTestSuccess);
512 }
513
514 IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, LoadLoadableSession) {
515   RunEncryptedMediaTest("encrypted_media_player.html",
516                         "bear-320x240-v-enc_v.webm",
517                         kWebMVideoOnly,
518                         kExternalClearKeyKeySystem,
519                         SRC,
520                         kLoadableSession,
521                         false,
522                         kEnded);
523 }
524
525 IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, LoadUnknownSession) {
526   // TODO(xhwang): Add a specific error for this failure, e.g. kSessionNotFound.
527   RunEncryptedMediaTest("encrypted_media_player.html",
528                         "bear-320x240-v-enc_v.webm",
529                         kWebMVideoOnly,
530                         kExternalClearKeyKeySystem,
531                         SRC,
532                         kUnknownSession,
533                         false,
534                         kEmeKeyError);
535 }
536 #endif  // defined(ENABLE_PEPPER_CDMS)