shaka-player 4.6.4 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (598) hide show
  1. package/README.md +1 -0
  2. package/dist/controls.css +1 -1
  3. package/dist/controls.css.map +1 -1
  4. package/dist/deps.js +9 -5
  5. package/dist/locales.js +29 -29
  6. package/dist/shaka-player.compiled.d.ts +46 -3
  7. package/dist/shaka-player.compiled.debug.d.ts +46 -3
  8. package/dist/shaka-player.compiled.debug.externs.js +45 -0
  9. package/dist/shaka-player.compiled.debug.js +382 -351
  10. package/dist/shaka-player.compiled.debug.map +4 -4
  11. package/dist/shaka-player.compiled.externs.js +45 -0
  12. package/dist/shaka-player.compiled.js +1135 -1121
  13. package/dist/shaka-player.compiled.map +4 -4
  14. package/dist/shaka-player.ui.d.ts +68 -4
  15. package/dist/shaka-player.ui.debug.d.ts +68 -4
  16. package/dist/shaka-player.ui.debug.externs.js +77 -0
  17. package/dist/shaka-player.ui.debug.js +428 -392
  18. package/dist/shaka-player.ui.debug.map +4 -4
  19. package/dist/shaka-player.ui.externs.js +77 -0
  20. package/dist/shaka-player.ui.js +1304 -1290
  21. package/dist/shaka-player.ui.map +4 -4
  22. package/externs/mediasession.js +7 -0
  23. package/externs/shaka/abr_manager.js +8 -0
  24. package/externs/shaka/manifest.js +3 -3
  25. package/externs/shaka/player.js +59 -4
  26. package/lib/abr/simple_abr_manager.js +41 -15
  27. package/lib/cea/cea708_service.js +1 -1
  28. package/lib/cea/cea708_window.js +95 -7
  29. package/lib/dash/dash_parser.js +55 -11
  30. package/lib/media/adaptation_set_criteria.js +76 -10
  31. package/lib/media/media_source_engine.js +42 -18
  32. package/lib/media/segment_reference.js +12 -0
  33. package/lib/media/streaming_engine.js +55 -3
  34. package/lib/player.js +92 -6
  35. package/lib/util/cmsd_manager.js +269 -0
  36. package/lib/util/content_steering_manager.js +5 -1
  37. package/lib/util/mime_utils.js +6 -2
  38. package/lib/util/periods.js +108 -39
  39. package/lib/util/player_configuration.js +19 -5
  40. package/lib/util/stream_utils.js +82 -13
  41. package/package.json +1 -1
  42. package/ui/audio_language_selection.js +3 -0
  43. package/ui/controls.js +60 -0
  44. package/ui/externs/ui.js +12 -1
  45. package/ui/hidden_fast_forward_button.js +32 -0
  46. package/ui/hidden_rewind_button.js +32 -0
  47. package/ui/hidden_seek_button.js +121 -0
  48. package/ui/less/buttons.less +50 -0
  49. package/ui/less/containers.less +18 -0
  50. package/ui/resolution_selection.js +2 -0
  51. package/ui/ui.js +2 -0
  52. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -75
  53. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -26
  54. package/.github/ISSUE_TEMPLATE/question.md +0 -26
  55. package/.github/config.yml +0 -1
  56. package/.github/workflows/appspot.yaml +0 -39
  57. package/.github/workflows/build-and-test.yaml +0 -222
  58. package/.github/workflows/compute-incremental-coverage.py +0 -265
  59. package/.github/workflows/custom-actions/prep-for-appspot/action.yaml +0 -56
  60. package/.github/workflows/custom-actions/set-commit-status/action.yaml +0 -37
  61. package/.github/workflows/deflake.yaml +0 -31
  62. package/.github/workflows/demo-version-index.yaml +0 -43
  63. package/.github/workflows/nightly-demo.yaml +0 -42
  64. package/.github/workflows/release-please.yaml +0 -193
  65. package/.github/workflows/report-incremental-coverage.yaml +0 -39
  66. package/.github/workflows/safari-homedir-launcher.sh +0 -18
  67. package/.github/workflows/selenium-lab-tests.yaml +0 -370
  68. package/.github/workflows/shaka-bot-commands/command-help.sh +0 -27
  69. package/.github/workflows/shaka-bot-commands/command-test.sh +0 -56
  70. package/.github/workflows/shaka-bot-commands/lib.sh +0 -83
  71. package/.github/workflows/shaka-bot-commands/main.sh +0 -51
  72. package/.github/workflows/sync-labels.yaml +0 -33
  73. package/.github/workflows/talk-to-shaka-bot.yaml +0 -29
  74. package/.github/workflows/update-issues.yaml +0 -31
  75. package/.github/workflows/update-screenshots.yaml +0 -142
  76. package/.github/workflows/validate-pr-title.yaml +0 -27
  77. package/CHANGELOG.md +0 -5774
  78. package/CODE_OF_CONDUCT.md +0 -93
  79. package/CONTRIBUTING.md +0 -76
  80. package/demo/TengwarTelcontar.woff2 +0 -0
  81. package/demo/app_logo_144.png +0 -0
  82. package/demo/app_logo_192.png +0 -0
  83. package/demo/app_logo_256.png +0 -0
  84. package/demo/app_logo_384.png +0 -0
  85. package/demo/app_logo_512.png +0 -0
  86. package/demo/app_manifest.json +0 -29
  87. package/demo/asset_card.js +0 -410
  88. package/demo/autoTemplate.txt +0 -61
  89. package/demo/cast_receiver/idle1.jpg +0 -0
  90. package/demo/cast_receiver/idle2.jpg +0 -0
  91. package/demo/cast_receiver/idle3.jpg +0 -0
  92. package/demo/cast_receiver/index.html +0 -75
  93. package/demo/cast_receiver/receiver_app.css +0 -111
  94. package/demo/cast_receiver/receiver_app.js +0 -158
  95. package/demo/close_button.js +0 -60
  96. package/demo/common/asset.js +0 -510
  97. package/demo/common/assets.js +0 -1634
  98. package/demo/config.js +0 -859
  99. package/demo/custom.js +0 -907
  100. package/demo/customWarning.txt +0 -8
  101. package/demo/demo.less +0 -591
  102. package/demo/demo_uncompiled.js +0 -11
  103. package/demo/demo_utils.js +0 -113
  104. package/demo/favicon.ico +0 -0
  105. package/demo/front.js +0 -156
  106. package/demo/icons/README.md +0 -4
  107. package/demo/icons/baseline-audiotrack-24px.svg +0 -1
  108. package/demo/icons/baseline-closed_caption-24px.svg +0 -1
  109. package/demo/icons/baseline-fast_forward-24px.svg +0 -1
  110. package/demo/icons/baseline-language-24px.svg +0 -1
  111. package/demo/icons/baseline-live_tv-24px.svg +0 -1
  112. package/demo/icons/baseline-subtitles-24px.svg +0 -1
  113. package/demo/icons/baseline-surround_sound-24px.svg +0 -1
  114. package/demo/icons/custom_ad.svg +0 -1
  115. package/demo/icons/custom_box_with_text.svg +0 -1
  116. package/demo/icons/custom_clear_key.svg +0 -1
  117. package/demo/icons/custom_high_definition.svg +0 -1
  118. package/demo/icons/custom_playready.svg +0 -1
  119. package/demo/icons/custom_ultra_high_definition.svg +0 -1
  120. package/demo/icons/custom_widevine.svg +0 -1
  121. package/demo/index.html +0 -173
  122. package/demo/input.js +0 -270
  123. package/demo/input_container.js +0 -218
  124. package/demo/load.js +0 -156
  125. package/demo/main.js +0 -1854
  126. package/demo/search.js +0 -452
  127. package/demo/service_worker.js +0 -355
  128. package/demo/shaka_logo_trans.png +0 -0
  129. package/demo/tooltip.js +0 -29
  130. package/demo/visualizer.js +0 -335
  131. package/demo/visualizer_button.js +0 -84
  132. package/dist/demo.compiled.debug.js +0 -340
  133. package/dist/demo.compiled.debug.map +0 -8
  134. package/dist/demo.compiled.js +0 -340
  135. package/dist/demo.compiled.map +0 -8
  136. package/dist/demo.css +0 -6
  137. package/dist/demo.css.map +0 -1
  138. package/dist/receiver.compiled.debug.js +0 -187
  139. package/dist/receiver.compiled.debug.map +0 -8
  140. package/dist/receiver.compiled.js +0 -187
  141. package/dist/receiver.compiled.map +0 -8
  142. package/docs/announcement-list-join-group.png +0 -0
  143. package/docs/api-mainpage.md +0 -28
  144. package/docs/design/REDESIGN.md +0 -283
  145. package/docs/design/architecture.md +0 -13
  146. package/docs/design/bg-fetch-after.gv +0 -29
  147. package/docs/design/bg-fetch-after.gv.png +0 -0
  148. package/docs/design/bg-fetch-before.gv +0 -18
  149. package/docs/design/bg-fetch-before.gv.png +0 -0
  150. package/docs/design/bg-fetch.md +0 -134
  151. package/docs/design/cast.gv +0 -35
  152. package/docs/design/cast.gv.png +0 -0
  153. package/docs/design/chromecast.md +0 -151
  154. package/docs/design/codec_preferences.md +0 -158
  155. package/docs/design/dash-audio-channels.md +0 -123
  156. package/docs/design/dash-manifests.md +0 -248
  157. package/docs/design/dash-timeline.svg +0 -4
  158. package/docs/design/dataflow.gv +0 -66
  159. package/docs/design/dataflow.gv.png +0 -0
  160. package/docs/design/export.md +0 -70
  161. package/docs/design/fuzzy-locale-matching.md +0 -40
  162. package/docs/design/gap-jumping.md +0 -151
  163. package/docs/design/lcevc-architecture.png +0 -0
  164. package/docs/design/lcevc-demo.png +0 -0
  165. package/docs/design/lcevc-integration.md +0 -72
  166. package/docs/design/locale_compatibility.svg +0 -1
  167. package/docs/design/locales_tree.svg +0 -1
  168. package/docs/design/localization-design-principles.md +0 -158
  169. package/docs/design/newdemo.gv +0 -83
  170. package/docs/design/newdemo.gv.png +0 -0
  171. package/docs/design/offline.gv +0 -43
  172. package/docs/design/offline.gv.png +0 -0
  173. package/docs/design/offline.md +0 -153
  174. package/docs/design/ownership.gv +0 -76
  175. package/docs/design/ownership.gv.png +0 -0
  176. package/docs/design/preload.md +0 -299
  177. package/docs/design/preload.png +0 -0
  178. package/docs/design/talking-about-languages.md +0 -46
  179. package/docs/design/timeline.svg +0 -152
  180. package/docs/design/ui.md +0 -31
  181. package/docs/design/ui_player_relationships.svg +0 -1
  182. package/docs/jsdoc-plugin.js +0 -74
  183. package/docs/jsdoc-template/README.md +0 -1
  184. package/docs/jsdoc-template/publish.js +0 -879
  185. package/docs/jsdoc-template/static/fonts/OpenSans-Bold-webfont.eot +0 -0
  186. package/docs/jsdoc-template/static/fonts/OpenSans-Bold-webfont.svg +0 -1830
  187. package/docs/jsdoc-template/static/fonts/OpenSans-Bold-webfont.woff +0 -0
  188. package/docs/jsdoc-template/static/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
  189. package/docs/jsdoc-template/static/fonts/OpenSans-BoldItalic-webfont.svg +0 -1830
  190. package/docs/jsdoc-template/static/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
  191. package/docs/jsdoc-template/static/fonts/OpenSans-Italic-webfont.eot +0 -0
  192. package/docs/jsdoc-template/static/fonts/OpenSans-Italic-webfont.svg +0 -1830
  193. package/docs/jsdoc-template/static/fonts/OpenSans-Italic-webfont.woff +0 -0
  194. package/docs/jsdoc-template/static/fonts/OpenSans-Light-webfont.eot +0 -0
  195. package/docs/jsdoc-template/static/fonts/OpenSans-Light-webfont.svg +0 -1831
  196. package/docs/jsdoc-template/static/fonts/OpenSans-Light-webfont.woff +0 -0
  197. package/docs/jsdoc-template/static/fonts/OpenSans-LightItalic-webfont.eot +0 -0
  198. package/docs/jsdoc-template/static/fonts/OpenSans-LightItalic-webfont.svg +0 -1835
  199. package/docs/jsdoc-template/static/fonts/OpenSans-LightItalic-webfont.woff +0 -0
  200. package/docs/jsdoc-template/static/fonts/OpenSans-Regular-webfont.eot +0 -0
  201. package/docs/jsdoc-template/static/fonts/OpenSans-Regular-webfont.svg +0 -1831
  202. package/docs/jsdoc-template/static/fonts/OpenSans-Regular-webfont.woff +0 -0
  203. package/docs/jsdoc-template/static/scripts/linenumber.js +0 -44
  204. package/docs/jsdoc-template/static/scripts/show-widget.js +0 -55
  205. package/docs/jsdoc-template/static/styles/jsdoc-default.css +0 -438
  206. package/docs/jsdoc-template/tmpl/augments.tmpl +0 -10
  207. package/docs/jsdoc-template/tmpl/container.tmpl +0 -205
  208. package/docs/jsdoc-template/tmpl/details.tmpl +0 -152
  209. package/docs/jsdoc-template/tmpl/example.tmpl +0 -2
  210. package/docs/jsdoc-template/tmpl/examples.tmpl +0 -13
  211. package/docs/jsdoc-template/tmpl/exceptions.tmpl +0 -32
  212. package/docs/jsdoc-template/tmpl/layout.tmpl +0 -50
  213. package/docs/jsdoc-template/tmpl/mainpage.tmpl +0 -14
  214. package/docs/jsdoc-template/tmpl/members.tmpl +0 -47
  215. package/docs/jsdoc-template/tmpl/method.tmpl +0 -140
  216. package/docs/jsdoc-template/tmpl/modifies.tmpl +0 -14
  217. package/docs/jsdoc-template/tmpl/params.tmpl +0 -131
  218. package/docs/jsdoc-template/tmpl/properties.tmpl +0 -125
  219. package/docs/jsdoc-template/tmpl/returns.tmpl +0 -19
  220. package/docs/jsdoc-template/tmpl/source.tmpl +0 -8
  221. package/docs/jsdoc-template/tmpl/tutorial.tmpl +0 -21
  222. package/docs/jsdoc-template/tmpl/type.tmpl +0 -7
  223. package/docs/jsdoc.conf.json +0 -38
  224. package/docs/shaka-player-logo.png +0 -0
  225. package/docs/style.md +0 -174
  226. package/docs/tutorials/a11y.md +0 -64
  227. package/docs/tutorials/ad_monetization.md +0 -292
  228. package/docs/tutorials/application-level-redirects.md +0 -94
  229. package/docs/tutorials/architecture.md +0 -32
  230. package/docs/tutorials/basic-usage.md +0 -89
  231. package/docs/tutorials/blob-url.md +0 -15
  232. package/docs/tutorials/config.md +0 -148
  233. package/docs/tutorials/debugging.md +0 -189
  234. package/docs/tutorials/drm-config.md +0 -274
  235. package/docs/tutorials/errors.md +0 -95
  236. package/docs/tutorials/fairplay.md +0 -242
  237. package/docs/tutorials/faq.md +0 -252
  238. package/docs/tutorials/index.json +0 -29
  239. package/docs/tutorials/lcevc.md +0 -118
  240. package/docs/tutorials/license-server-auth.md +0 -248
  241. package/docs/tutorials/license-wrapping.md +0 -168
  242. package/docs/tutorials/manifest-parser.md +0 -365
  243. package/docs/tutorials/network-and-buffering-config.md +0 -119
  244. package/docs/tutorials/offline.md +0 -683
  245. package/docs/tutorials/plugins.md +0 -184
  246. package/docs/tutorials/selenium-grid-config.md +0 -174
  247. package/docs/tutorials/service-worker.md +0 -106
  248. package/docs/tutorials/ui-customization.md +0 -288
  249. package/docs/tutorials/ui.md +0 -232
  250. package/docs/tutorials/upgrade-manifest.md +0 -281
  251. package/docs/tutorials/upgrade.md +0 -104
  252. package/docs/tutorials/welcome.md +0 -108
  253. package/docs/tutorials/widevine-service-certs.md +0 -45
  254. package/karma.conf.js +0 -879
  255. package/maintained-branches.md +0 -15
  256. package/roadmap.md +0 -186
  257. package/test/abr/simple_abr_manager_unit.js +0 -398
  258. package/test/ads/ad_manager_unit.js +0 -260
  259. package/test/assumptions/uint8_array_unit.js +0 -22
  260. package/test/cast/cast_proxy_unit.js +0 -736
  261. package/test/cast/cast_receiver_integration.js +0 -488
  262. package/test/cast/cast_receiver_unit.js +0 -1183
  263. package/test/cast/cast_sender_unit.js +0 -973
  264. package/test/cast/cast_utils_unit.js +0 -311
  265. package/test/cea/cea608_memory_unit.js +0 -411
  266. package/test/cea/cea708_service_unit.js +0 -674
  267. package/test/cea/cea708_window_unit.js +0 -373
  268. package/test/cea/cea_decoder_unit.js +0 -615
  269. package/test/cea/dtvcc_packet_builder_unit.js +0 -158
  270. package/test/cea/dtvcc_packet_unit.js +0 -60
  271. package/test/cea/mp4_cea_parser_unit.js +0 -127
  272. package/test/codec_switching/codec_switching_integration.js +0 -182
  273. package/test/dash/dash_parser_content_protection_unit.js +0 -998
  274. package/test/dash/dash_parser_integration.js +0 -74
  275. package/test/dash/dash_parser_live_unit.js +0 -1542
  276. package/test/dash/dash_parser_manifest_unit.js +0 -3121
  277. package/test/dash/dash_parser_segment_base_unit.js +0 -421
  278. package/test/dash/dash_parser_segment_list_unit.js +0 -380
  279. package/test/dash/dash_parser_segment_template_unit.js +0 -910
  280. package/test/dash/mpd_utils_unit.js +0 -794
  281. package/test/demo/demo_unit.js +0 -108
  282. package/test/deprecate/enforcer_unit.js +0 -74
  283. package/test/deprecate/version_unit.js +0 -57
  284. package/test/hls/hls_live_unit.js +0 -1330
  285. package/test/hls/hls_parser_unit.js +0 -5276
  286. package/test/hls/manifest_text_parser_unit.js +0 -545
  287. package/test/media/adaptation_set_criteria_unit.js +0 -806
  288. package/test/media/adaptation_set_unit.js +0 -229
  289. package/test/media/buffering_observer_unit.js +0 -143
  290. package/test/media/closed_caption_parser_unit.js +0 -18
  291. package/test/media/content_workarounds_unit.js +0 -43
  292. package/test/media/drm_engine_integration.js +0 -356
  293. package/test/media/drm_engine_unit.js +0 -2805
  294. package/test/media/media_source_engine_integration.js +0 -691
  295. package/test/media/media_source_engine_unit.js +0 -1512
  296. package/test/media/mp4_segment_index_parser_unit.js +0 -80
  297. package/test/media/play_rate_controller_unit.js +0 -69
  298. package/test/media/playhead_unit.js +0 -1394
  299. package/test/media/presentation_timeline_unit.js +0 -477
  300. package/test/media/quality_observer_unit.js +0 -138
  301. package/test/media/region_observer_unit.js +0 -374
  302. package/test/media/region_timeline_unit.js +0 -139
  303. package/test/media/segment_index_unit.js +0 -1080
  304. package/test/media/segment_prefetch_unit.js +0 -243
  305. package/test/media/segment_reference_unit.js +0 -63
  306. package/test/media/stall_detector_unit.js +0 -184
  307. package/test/media/streaming_engine_integration.js +0 -632
  308. package/test/media/streaming_engine_unit.js +0 -4211
  309. package/test/media/time_ranges_utils_unit.js +0 -123
  310. package/test/media/webm_segment_index_parser_unit.js +0 -90
  311. package/test/mss/mss_parser_content_protection_unit.js +0 -49
  312. package/test/mss/mss_parser_unit.js +0 -474
  313. package/test/mss/mss_player_integration.js +0 -124
  314. package/test/net/data_uri_plugin_unit.js +0 -105
  315. package/test/net/http_plugin_unit.js +0 -439
  316. package/test/net/networking_engine_unit.js +0 -1236
  317. package/test/net/networking_utils_unit.js +0 -37
  318. package/test/offline/download_progress_estimator_unit.js +0 -90
  319. package/test/offline/indexeddb_storage_unit.js +0 -192
  320. package/test/offline/manifest_convert_unit.js +0 -622
  321. package/test/offline/offline_integration.js +0 -168
  322. package/test/offline/offline_manifest_parser_unit.js +0 -231
  323. package/test/offline/offline_scheme_unit.js +0 -154
  324. package/test/offline/offline_uri_unit.js +0 -59
  325. package/test/offline/storage_compatibility_unit.js +0 -344
  326. package/test/offline/storage_integration.js +0 -1858
  327. package/test/player_external.js +0 -237
  328. package/test/player_integration.js +0 -1371
  329. package/test/player_load_graph_integration.js +0 -865
  330. package/test/player_src_equals_external.js +0 -154
  331. package/test/player_src_equals_integration.js +0 -527
  332. package/test/player_unit.js +0 -4434
  333. package/test/polyfill/media_capabilities_unit.js +0 -277
  334. package/test/polyfill/patchedmediakeys_apple_unit.js +0 -130
  335. package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
  336. package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
  337. package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
  338. package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
  339. package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
  340. package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
  341. package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
  342. package/test/test/assets/3675/dash_0.mpd +0 -30
  343. package/test/test/assets/3675/dash_1.mpd +0 -30
  344. package/test/test/assets/3675/dash_2.mpd +0 -30
  345. package/test/test/assets/3675/dash_3.mpd +0 -30
  346. package/test/test/assets/3675/dash_4.mpd +0 -30
  347. package/test/test/assets/3675/dash_5.mpd +0 -26
  348. package/test/test/assets/3675/init-stream0.m4s +0 -0
  349. package/test/test/assets/audio-xhe-aac.mp4 +0 -0
  350. package/test/test/assets/audio.ts +0 -0
  351. package/test/test/assets/captions-test.ts +0 -0
  352. package/test/test/assets/cea-init.mp4 +0 -0
  353. package/test/test/assets/cea-segment.mp4 +0 -0
  354. package/test/test/assets/chapters.srt +0 -11
  355. package/test/test/assets/chapters.vtt +0 -10
  356. package/test/test/assets/chapters2.vtt +0 -10
  357. package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
  358. package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
  359. package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
  360. package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
  361. package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
  362. package/test/test/assets/dash-aes-128/dash.mpd +0 -18
  363. package/test/test/assets/dash-aes-128/license +0 -1
  364. package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
  365. package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
  366. package/test/test/assets/dash-multi-codec/dash.mpd +0 -32
  367. package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
  368. package/test/test/assets/db-dump-v1.json +0 -1
  369. package/test/test/assets/db-dump-v2-broken.json +0 -1
  370. package/test/test/assets/db-dump-v2-clean.json +0 -1
  371. package/test/test/assets/db-dump-v3.json +0 -1
  372. package/test/test/assets/db-dump-v4-broken.json +0 -1
  373. package/test/test/assets/db-dump-v5.json +0 -1
  374. package/test/test/assets/empty_caption_video_init.mp4 +0 -0
  375. package/test/test/assets/empty_caption_video_segment.mp4 +0 -0
  376. package/test/test/assets/encrypted-sintel-audio-init.mp4 +0 -0
  377. package/test/test/assets/encrypted-sintel-audio-segment.mp4 +0 -0
  378. package/test/test/assets/encrypted-sintel-video-init.mp4 +0 -0
  379. package/test/test/assets/encrypted-sintel-video-segment.mp4 +0 -0
  380. package/test/test/assets/green-pixel.mp4 +0 -0
  381. package/test/test/assets/green-pixel.txt +0 -15
  382. package/test/test/assets/h265-cea-init.mp4 +0 -0
  383. package/test/test/assets/h265-cea-segment.mp4 +0 -0
  384. package/test/test/assets/hls-raw-aac/fileSequence0.aac +0 -0
  385. package/test/test/assets/hls-raw-aac/fileSequence1.aac +0 -0
  386. package/test/test/assets/hls-raw-aac/fileSequence2.aac +0 -0
  387. package/test/test/assets/hls-raw-aac/fileSequence3.aac +0 -0
  388. package/test/test/assets/hls-raw-aac/manifest.m3u8 +0 -4
  389. package/test/test/assets/hls-raw-aac/stream.m4a.m3u8 +0 -14
  390. package/test/test/assets/hls-raw-ac3/fileSequence0.ac3 +0 -0
  391. package/test/test/assets/hls-raw-ac3/fileSequence1.ac3 +0 -0
  392. package/test/test/assets/hls-raw-ac3/fileSequence2.ac3 +0 -0
  393. package/test/test/assets/hls-raw-ac3/fileSequence3.ac3 +0 -0
  394. package/test/test/assets/hls-raw-ac3/fileSequence4.ac3 +0 -0
  395. package/test/test/assets/hls-raw-ac3/fileSequence5.ac3 +0 -0
  396. package/test/test/assets/hls-raw-ac3/fileSequence6.ac3 +0 -0
  397. package/test/test/assets/hls-raw-ac3/fileSequence7.ac3 +0 -0
  398. package/test/test/assets/hls-raw-ac3/prog_index.m3u8 +0 -31
  399. package/test/test/assets/hls-raw-ec3/fileSequence0.ec3 +0 -0
  400. package/test/test/assets/hls-raw-ec3/fileSequence1.ec3 +0 -0
  401. package/test/test/assets/hls-raw-ec3/fileSequence2.ec3 +0 -0
  402. package/test/test/assets/hls-raw-ec3/fileSequence3.ec3 +0 -0
  403. package/test/test/assets/hls-raw-ec3/fileSequence4.ec3 +0 -0
  404. package/test/test/assets/hls-raw-ec3/fileSequence5.ec3 +0 -0
  405. package/test/test/assets/hls-raw-ec3/fileSequence6.ec3 +0 -0
  406. package/test/test/assets/hls-raw-ec3/fileSequence7.ec3 +0 -0
  407. package/test/test/assets/hls-raw-ec3/prog_index.m3u8 +0 -31
  408. package/test/test/assets/hls-raw-mp3/chunklist_w905519204.m3u8 +0 -13
  409. package/test/test/assets/hls-raw-mp3/media_w905519204_0.mp3 +0 -0
  410. package/test/test/assets/hls-raw-mp3/media_w905519204_1.mp3 +0 -0
  411. package/test/test/assets/hls-raw-mp3/media_w905519204_2.mp3 +0 -0
  412. package/test/test/assets/hls-raw-mp3/media_w905519204_3.mp3 +0 -0
  413. package/test/test/assets/hls-raw-mp3/playlist.m3u8 +0 -4
  414. package/test/test/assets/hls-ts-aac/playlist.m3u8 +0 -23
  415. package/test/test/assets/hls-ts-aac/segment_0.ts +0 -0
  416. package/test/test/assets/hls-ts-aac/segment_1.ts +0 -0
  417. package/test/test/assets/hls-ts-aac/segment_2.ts +0 -0
  418. package/test/test/assets/hls-ts-aac/segment_3.ts +0 -0
  419. package/test/test/assets/hls-ts-aac/segment_4.ts +0 -0
  420. package/test/test/assets/hls-ts-aac/segment_5.ts +0 -0
  421. package/test/test/assets/hls-ts-aac/segment_6.ts +0 -0
  422. package/test/test/assets/hls-ts-aac/segment_7.ts +0 -0
  423. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0000.ts +0 -0
  424. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0001.ts +0 -0
  425. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0002.ts +0 -0
  426. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0003.ts +0 -0
  427. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0004.ts +0 -0
  428. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0005.ts +0 -0
  429. package/test/test/assets/hls-ts-ac3/prog_index.m3u8 +0 -19
  430. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0000.ts +0 -0
  431. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0001.ts +0 -0
  432. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0002.ts +0 -0
  433. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0003.ts +0 -0
  434. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0004.ts +0 -0
  435. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0005.ts +0 -0
  436. package/test/test/assets/hls-ts-ec3/prog_index.m3u8 +0 -19
  437. package/test/test/assets/hls-ts-h264/fileSequence0.ts +0 -0
  438. package/test/test/assets/hls-ts-h264/fileSequence1.ts +0 -0
  439. package/test/test/assets/hls-ts-h264/fileSequence2.ts +0 -0
  440. package/test/test/assets/hls-ts-h264/fileSequence3.ts +0 -0
  441. package/test/test/assets/hls-ts-h264/fileSequence4.ts +0 -0
  442. package/test/test/assets/hls-ts-h264/fileSequence5.ts +0 -0
  443. package/test/test/assets/hls-ts-h264/prog_index.m3u8 +0 -25
  444. package/test/test/assets/hls-ts-h265/0.ts +0 -0
  445. package/test/test/assets/hls-ts-h265/hevc.m3u8 +0 -6
  446. package/test/test/assets/hls-ts-h265/index.m3u8 +0 -7
  447. package/test/test/assets/hls-ts-mp3/manifest.m3u8 +0 -13
  448. package/test/test/assets/hls-ts-mp3/media_w239891843_0.ts +0 -0
  449. package/test/test/assets/hls-ts-mp3/media_w239891843_1.ts +0 -0
  450. package/test/test/assets/hls-ts-mp3/media_w239891843_2.ts +0 -0
  451. package/test/test/assets/hls-ts-mp3/media_w239891843_3.ts +0 -0
  452. package/test/test/assets/hls-ts-muxed-aac-h264/chunk.m3u8 +0 -17
  453. package/test/test/assets/hls-ts-muxed-aac-h264/n_0_0_0.ts +0 -0
  454. package/test/test/assets/hls-ts-muxed-aac-h264/n_1_0_0.ts +0 -0
  455. package/test/test/assets/hls-ts-muxed-aac-h264/n_2_0_0.ts +0 -0
  456. package/test/test/assets/hls-ts-muxed-aac-h264/n_3_0_0.ts +0 -0
  457. package/test/test/assets/hls-ts-muxed-aac-h264/n_4_0_0.ts +0 -0
  458. package/test/test/assets/hls-ts-muxed-aac-h264/n_5_0_0.ts +0 -0
  459. package/test/test/assets/hls-ts-muxed-aac-h264/playlist.m3u8 +0 -4
  460. package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
  461. package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
  462. package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +0 -9
  463. package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +0 -24
  464. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
  465. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
  466. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
  467. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
  468. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
  469. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
  470. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
  471. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
  472. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
  473. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
  474. package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +0 -14
  475. package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +0 -23
  476. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
  477. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
  478. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
  479. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
  480. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
  481. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
  482. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
  483. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
  484. package/test/test/assets/id3-metadata.aac +0 -0
  485. package/test/test/assets/id3-metadata.ts +0 -0
  486. package/test/test/assets/index-segment.mp4 +0 -0
  487. package/test/test/assets/index-segment.webm +0 -0
  488. package/test/test/assets/init-segment.webm +0 -0
  489. package/test/test/assets/large_file.mpd +0 -4930
  490. package/test/test/assets/multidrm-audio-init.mp4 +0 -0
  491. package/test/test/assets/multidrm-audio-segment.mp4 +0 -0
  492. package/test/test/assets/multidrm-video-init.mp4 +0 -0
  493. package/test/test/assets/multidrm-video-segment.mp4 +0 -0
  494. package/test/test/assets/multiple-trun-init.mp4 +0 -0
  495. package/test/test/assets/multiple-trun-segment.mp4 +0 -0
  496. package/test/test/assets/sintel-audio-init.mp4 +0 -0
  497. package/test/test/assets/sintel-audio-segment.mp4 +0 -0
  498. package/test/test/assets/sintel-video-init.mp4 +0 -0
  499. package/test/test/assets/sintel-video-segment.mp4 +0 -0
  500. package/test/test/assets/small.mp4 +0 -0
  501. package/test/test/assets/text-clip-alt.vtt +0 -63
  502. package/test/test/assets/text-clip.vtt +0 -63
  503. package/test/test/assets/thumbnails-sprites.vtt +0 -10
  504. package/test/test/assets/thumbnails.vtt +0 -10
  505. package/test/test/assets/ttml-init.mp4 +0 -0
  506. package/test/test/assets/ttml-segment-multiplemdat.mp4 +0 -0
  507. package/test/test/assets/ttml-segment.mp4 +0 -0
  508. package/test/test/assets/video.ts +0 -0
  509. package/test/test/assets/vtt-init.mp4 +0 -0
  510. package/test/test/assets/vtt-segment-multi-payload.mp4 +0 -0
  511. package/test/test/assets/vtt-segment-no-duration.mp4 +0 -0
  512. package/test/test/assets/vtt-segment-settings.mp4 +0 -0
  513. package/test/test/assets/vtt-segment.mp4 +0 -0
  514. package/test/test/boot.js +0 -495
  515. package/test/test/externs/filters.js +0 -44
  516. package/test/test/externs/fontfaceonload.js +0 -29
  517. package/test/test/externs/jasmine.js +0 -670
  518. package/test/test/externs/karma.js +0 -26
  519. package/test/test/externs/require.js +0 -21
  520. package/test/test/externs/sprintf.js +0 -18
  521. package/test/test/namespace.js +0 -10
  522. package/test/test/util/canned_idb.js +0 -379
  523. package/test/test/util/cea_utils.js +0 -60
  524. package/test/test/util/dash_parser_util.js +0 -329
  525. package/test/test/util/fake_ad.js +0 -321
  526. package/test/test/util/fake_ad_manager.js +0 -122
  527. package/test/test/util/fake_demo_main.js +0 -144
  528. package/test/test/util/fake_drm_engine.js +0 -103
  529. package/test/test/util/fake_media_source_engine.js +0 -464
  530. package/test/test/util/fake_networking_engine.js +0 -381
  531. package/test/test/util/fake_segment_prefetch.js +0 -84
  532. package/test/test/util/fake_text_displayer.js +0 -60
  533. package/test/test/util/id3_generator.js +0 -100
  534. package/test/test/util/indexeddb_utils.js +0 -124
  535. package/test/test/util/jasmine_fetch.js +0 -382
  536. package/test/test/util/layout_tests.js +0 -435
  537. package/test/test/util/loader.js +0 -88
  538. package/test/test/util/manifest_generator.js +0 -705
  539. package/test/test/util/manifest_parser_util.js +0 -101
  540. package/test/test/util/mss_parser_util.js +0 -119
  541. package/test/test/util/offline_utils.js +0 -105
  542. package/test/test/util/simple_fakes.js +0 -535
  543. package/test/test/util/stream_generator.js +0 -676
  544. package/test/test/util/streaming_engine_util.js +0 -506
  545. package/test/test/util/test_scheme.js +0 -778
  546. package/test/test/util/ttml_utils.js +0 -77
  547. package/test/test/util/ui_utils.js +0 -183
  548. package/test/test/util/util.js +0 -374
  549. package/test/test/util/waiter.js +0 -406
  550. package/test/text/cue_integration.js +0 -51
  551. package/test/text/lrc_text_parser_unit.js +0 -98
  552. package/test/text/mp4_ttml_parser_unit.js +0 -171
  553. package/test/text/mp4_vtt_parser_unit.js +0 -195
  554. package/test/text/sbv_text_parser_unit.js +0 -81
  555. package/test/text/simple_text_displayer_unit.js +0 -468
  556. package/test/text/srt_text_parser_unit.js +0 -163
  557. package/test/text/ssa_text_parser_unit.js +0 -382
  558. package/test/text/text_displayer_layout_unit.js +0 -323
  559. package/test/text/text_engine_unit.js +0 -500
  560. package/test/text/text_track_integration.js +0 -186
  561. package/test/text/ttml_text_parser_unit.js +0 -2176
  562. package/test/text/ui_text_displayer_unit.js +0 -608
  563. package/test/text/vtt_text_parser_unit.js +0 -1363
  564. package/test/text/web_vtt_generator_unit.js +0 -144
  565. package/test/text/web_vtt_layout_integration.js +0 -524
  566. package/test/transmuxer/transmuxer_engine_integration.js +0 -69
  567. package/test/transmuxer/transmuxer_integration.js +0 -443
  568. package/test/ui/ad_ui_unit.js +0 -369
  569. package/test/ui/localization_unit.js +0 -508
  570. package/test/ui/ui_customization_unit.js +0 -208
  571. package/test/ui/ui_integration.js +0 -669
  572. package/test/ui/ui_unit.js +0 -902
  573. package/test/util/abortable_operation_unit.js +0 -624
  574. package/test/util/array_utils_unit.js +0 -58
  575. package/test/util/buffer_utils_unit.js +0 -185
  576. package/test/util/cmcd_manager_unit.js +0 -440
  577. package/test/util/content_steering_manager_unit.js +0 -427
  578. package/test/util/data_view_reader_unit.js +0 -254
  579. package/test/util/ebml_parser_unit.js +0 -297
  580. package/test/util/event_manager_unit.js +0 -185
  581. package/test/util/fake_event_target_unit.js +0 -123
  582. package/test/util/id3_utils_unit.js +0 -168
  583. package/test/util/iterables_unit.js +0 -68
  584. package/test/util/language_utils_unit.js +0 -240
  585. package/test/util/manifest_parser_utils_unit.js +0 -55
  586. package/test/util/mime_utils_unit.js +0 -64
  587. package/test/util/mp4_box_parsers_unit.js +0 -246
  588. package/test/util/mp4_parser_unit.js +0 -373
  589. package/test/util/multi_map_unit.js +0 -94
  590. package/test/util/object_utils_unit.js +0 -79
  591. package/test/util/periods_unit.js +0 -1623
  592. package/test/util/pssh_unit.js +0 -226
  593. package/test/util/state_history_unit.js +0 -101
  594. package/test/util/stream_utils_unit.js +0 -1068
  595. package/test/util/string_utils_unit.js +0 -166
  596. package/test/util/text_parser_unit.js +0 -165
  597. package/test/util/ts_parser_unit.js +0 -77
  598. package/test/util/xml_utils_unit.js +0 -444
@@ -1,2805 +0,0 @@
1
- /*! @license
2
- * Shaka Player
3
- * Copyright 2016 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- describe('DrmEngine', () => {
8
- const Util = shaka.test.Util;
9
-
10
- const originalRequestMediaKeySystemAccess =
11
- navigator.requestMediaKeySystemAccess;
12
- const originalLogError = shaka.log.error;
13
- const originalBatchTime = shaka.media.DrmEngine.KEY_STATUS_BATCH_TIME;
14
- const originalDecodingInfo = navigator.mediaCapabilities.decodingInfo;
15
-
16
- /** @type {!jasmine.Spy} */
17
- let decodingInfoSpy;
18
- /** @type {!jasmine.Spy} */
19
- let logErrorSpy;
20
- /** @type {!jasmine.Spy} */
21
- let onErrorSpy;
22
- /** @type {!jasmine.Spy} */
23
- let onKeyStatusSpy;
24
- /** @type {!jasmine.Spy} */
25
- let onExpirationSpy;
26
- /** @type {!jasmine.Spy} */
27
- let onEventSpy;
28
-
29
- /** @type {!shaka.test.FakeNetworkingEngine} */
30
- let fakeNetEngine;
31
- /** @type {!shaka.media.DrmEngine} */
32
- let drmEngine;
33
- /** @type {shaka.extern.Manifest} */
34
- let manifest;
35
- /** @type {shaka.extern.DrmConfiguration} */
36
- let config;
37
-
38
- let mockMediaKeySystemAccess;
39
- let mockMediaKeys;
40
- /** @type {!shaka.test.FakeVideo} */
41
- let mockVideo;
42
-
43
- let session1;
44
- let session2;
45
- let session3;
46
-
47
- const containing = jasmine.objectContaining;
48
-
49
- beforeAll(() => {
50
- shaka.media.DrmEngine.KEY_STATUS_BATCH_TIME = 0;
51
- });
52
-
53
- afterAll(() => {
54
- shaka.media.DrmEngine.KEY_STATUS_BATCH_TIME = originalBatchTime;
55
- });
56
-
57
- beforeEach(() => {
58
- decodingInfoSpy = jasmine.createSpy('decodingInfo');
59
- navigator.mediaCapabilities.decodingInfo =
60
- shaka.test.Util.spyFunc(decodingInfoSpy);
61
-
62
- logErrorSpy = jasmine.createSpy('shaka.log.error');
63
- shaka.log.error = shaka.test.Util.spyFunc(logErrorSpy);
64
-
65
- onErrorSpy = jasmine.createSpy('onError');
66
- onKeyStatusSpy = jasmine.createSpy('onKeyStatus');
67
- onExpirationSpy = jasmine.createSpy('onExpirationUpdated');
68
- onEventSpy = jasmine.createSpy('onEvent');
69
-
70
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
71
- manifest.addVariant(0, (variant) => {
72
- variant.addVideo(1, (stream) => {
73
- stream.encrypted = true;
74
- stream.addDrmInfo('drm.abc');
75
- stream.addDrmInfo('drm.def');
76
- stream.mime('video/foo', 'vbar');
77
- });
78
- variant.addAudio(2, (stream) => {
79
- stream.encrypted = true;
80
- stream.addDrmInfo('drm.abc');
81
- stream.addDrmInfo('drm.def');
82
- stream.mime('audio/foo', 'abar');
83
- });
84
- });
85
- });
86
-
87
- // By default, error logs and callbacks result in failure.
88
- onErrorSpy.and.callFake(fail);
89
- logErrorSpy.and.callFake(fail);
90
-
91
- // By default, allow keysystem drm.abc
92
- setDecodingInfoSpy(['drm.abc']);
93
-
94
- mockVideo = new shaka.test.FakeVideo();
95
-
96
- session1 = createMockSession();
97
- session2 = createMockSession();
98
- session3 = createMockSession();
99
-
100
- mockMediaKeySystemAccess = createMockMediaKeySystemAccess();
101
-
102
- mockMediaKeys = createMockMediaKeys();
103
- mockMediaKeys.createSession.and.callFake(() => {
104
- const index = mockMediaKeys.createSession.calls.count() - 1;
105
- return [session1, session2, session3][index];
106
- });
107
- mockMediaKeys.setServerCertificate.and.returnValue(Promise.resolve());
108
-
109
- fakeNetEngine = new shaka.test.FakeNetworkingEngine();
110
-
111
- const license = new Uint8Array(0);
112
- fakeNetEngine.setResponseValue('http://abc.drm/license', license);
113
-
114
- const playerInterface = {
115
- netEngine: fakeNetEngine,
116
- onError: shaka.test.Util.spyFunc(onErrorSpy),
117
- onKeyStatus: shaka.test.Util.spyFunc(onKeyStatusSpy),
118
- onExpirationUpdated: shaka.test.Util.spyFunc(onExpirationSpy),
119
- onEvent: shaka.test.Util.spyFunc(onEventSpy),
120
- };
121
-
122
- drmEngine = new shaka.media.DrmEngine(playerInterface);
123
-
124
- config = shaka.util.PlayerConfiguration.createDefault().drm;
125
- config.servers = {
126
- 'drm.abc': 'http://abc.drm/license',
127
- 'drm.def': 'http://def.drm/license',
128
- };
129
- // Some platforms, such as Xbox, default to parseInbandPssh: true, which
130
- // ignores encrypted events. So set it explicitly to false, and let
131
- // individual tests set it to true where relevant.
132
- config.parseInbandPsshEnabled = false;
133
-
134
- drmEngine.configure(config);
135
- });
136
-
137
- afterEach(async () => {
138
- await drmEngine.destroy();
139
-
140
- navigator.requestMediaKeySystemAccess =
141
- originalRequestMediaKeySystemAccess;
142
- navigator.mediaCapabilities.decodingInfo = originalDecodingInfo;
143
- shaka.log.error = originalLogError;
144
- });
145
-
146
- describe('supportsVariants', () => {
147
- it('supports all clear variants', async () => {
148
- const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
149
- manifest.addVariant(0, (variant) => {
150
- variant.addVideo(1, (stream) => {
151
- stream.encrypted = false;
152
- stream.addDrmInfo('drm.abc');
153
- stream.addDrmInfo('drm.def');
154
- stream.mime('video/foo', 'vbar');
155
- });
156
- });
157
- });
158
-
159
- const variants = manifest.variants;
160
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
161
-
162
- expect(drmEngine.supportsVariant(variants[0])).toBeTruthy();
163
- });
164
- });
165
-
166
- describe('init', () => {
167
- it('stops on first available key system', async () => {
168
- // Accept both drm.abc and drm.def. Only one can be chosen.
169
- setDecodingInfoSpy(['drm.abc', 'drm.def']);
170
-
171
- const variants = manifest.variants;
172
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
173
- expect(drmEngine.initialized()).toBe(true);
174
- expect(shaka.media.DrmEngine.keySystem(drmEngine.getDrmInfo()))
175
- .toBe('drm.abc');
176
- });
177
-
178
- it('tries to get the key systems in the order they appear in', async () => {
179
- // Fail both key systems.
180
- setDecodingInfoSpy([]);
181
-
182
- const variants = manifest.variants;
183
- await expectAsync(drmEngine.initForPlayback(variants,
184
- manifest.offlineSessionIds)).toBeRejected();
185
-
186
- expect(decodingInfoSpy).toHaveBeenCalledTimes(2);
187
- expect(decodingInfoSpy).toHaveBeenCalledWith(containing({
188
- keySystemConfiguration: containing({keySystem: 'drm.abc'}),
189
- }));
190
-
191
- expect(decodingInfoSpy).toHaveBeenCalledWith(containing({
192
- keySystemConfiguration: containing({keySystem: 'drm.def'}),
193
- }));
194
- });
195
-
196
- it('tries the second key system if the first fails', async () => {
197
- // Accept drm.def, but not drm.abc.
198
- setDecodingInfoSpy(['drm.def']);
199
-
200
- const variants = manifest.variants;
201
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
202
- expect(drmEngine.initialized()).toBe(true);
203
- expect(shaka.media.DrmEngine.keySystem(drmEngine.getDrmInfo()))
204
- .toBe('drm.def');
205
- });
206
-
207
- it('chooses systems by configured preferredKeySystems', async () => {
208
- // Accept both drm.abc and drm.def. Only one can be chosen.
209
- setDecodingInfoSpy(['drm.abc', 'drm.def']);
210
- config.preferredKeySystems = ['drm.def'];
211
- drmEngine.configure(config);
212
- logErrorSpy.and.stub();
213
-
214
- const variants = manifest.variants;
215
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
216
-
217
- // should be only one variant, as preferredKeySystems is propagated
218
- // to getDecodingInfos
219
- expect(variants[0].decodingInfos.length).toBe(1);
220
- expect(shaka.media.DrmEngine.keySystem(drmEngine.getDrmInfo()))
221
- .toBe('drm.def');
222
- });
223
-
224
- it('chooses systems with configured license servers', async () => {
225
- // Accept both drm.abc and drm.def. Only one can be chosen.
226
- setDecodingInfoSpy(['drm.abc', 'drm.def']);
227
-
228
- // Remove the server URI for drm.abc, which appears first in the manifest.
229
- delete config.servers['drm.abc'];
230
- drmEngine.configure(config);
231
- // Ignore error logs, which we expect to occur due to the missing server.
232
- logErrorSpy.and.stub();
233
-
234
- const variants = manifest.variants;
235
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
236
-
237
- expect(variants[0].decodingInfos.length).toBe(2);
238
- expect(shaka.media.DrmEngine.keySystem(drmEngine.getDrmInfo()))
239
- .toBe('drm.def');
240
- });
241
-
242
- it('overrides manifest with configured license servers', async () => {
243
- // Accept both drm.abc and drm.def. Only one can be chosen.
244
- setDecodingInfoSpy(['drm.abc', 'drm.def']);
245
-
246
- // Add manifest-supplied license servers for both.
247
- tweakDrmInfos((drmInfos) => {
248
- for (const drmInfo of drmInfos) {
249
- if (drmInfo.keySystem == 'drm.abc') {
250
- drmInfo.licenseServerUri = 'http://foo.bar/abc';
251
- } else if (drmInfo.keySystem == 'drm.def') {
252
- drmInfo.licenseServerUri = 'http://foo.bar/def';
253
- }
254
-
255
- // Make sure we didn't somehow choose manifest-supplied values that
256
- // match the config. This would invalidate parts of the test.
257
- const configServer = config.servers[drmInfo.keySystem];
258
- expect(drmInfo.licenseServerUri).not.toBe(configServer);
259
- }
260
- });
261
-
262
- // Remove the server URI for drm.abc from the config, so that only drm.def
263
- // could be used, in spite of the manifest-supplied license server URI.
264
- delete config.servers['drm.abc'];
265
- drmEngine.configure(config);
266
-
267
- // Ignore error logs, which we expect to occur due to the missing server.
268
- logErrorSpy.and.stub();
269
-
270
- const variants = manifest.variants;
271
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
272
-
273
- expect(variants[0].decodingInfos.length).toBe(2);
274
- const selectedDrmInfo = drmEngine.getDrmInfo();
275
- expect(selectedDrmInfo).not.toBe(null);
276
- expect(selectedDrmInfo.keySystem).toBe('drm.def');
277
- expect(selectedDrmInfo.licenseServerUri).toBe(config.servers['drm.def']);
278
- });
279
-
280
- it('detects content type capabilities of key system', async () => {
281
- setDecodingInfoSpy(['drm.abc']);
282
-
283
- const variants = manifest.variants;
284
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
285
- expect(drmEngine.initialized()).toBe(true);
286
- expect(drmEngine.willSupport('audio/webm')).toBeTruthy();
287
- expect(drmEngine.willSupport('video/mp4; codecs="fake"')).toBeTruthy();
288
- expect(drmEngine.willSupport('video/mp4; codecs="FAKE"')).toBeTruthy();
289
-
290
- // Because DrmEngine will err on being too accepting, make sure it will
291
- // reject something. However, we can only check that it is actually
292
- // thing on non-Edge browsers because of https://bit.ly/2IcEgv0
293
- if (!shaka.util.Platform.isLegacyEdge()) {
294
- expect(drmEngine.willSupport('this-should-fail')).toBeFalsy();
295
- }
296
- });
297
-
298
- it('fails to initialize if no key systems are available', async () => {
299
- // Accept no key systems.
300
- setDecodingInfoSpy([]);
301
-
302
- const expected = Util.jasmineError(new shaka.util.Error(
303
- shaka.util.Error.Severity.CRITICAL,
304
- shaka.util.Error.Category.DRM,
305
- shaka.util.Error.Code.REQUESTED_KEY_SYSTEM_CONFIG_UNAVAILABLE));
306
- const variants = manifest.variants;
307
- await expectAsync(
308
- drmEngine.initForPlayback(variants, manifest.offlineSessionIds))
309
- .toBeRejectedWith(expected);
310
-
311
- expect(drmEngine.initialized()).toBe(false);
312
-
313
- expect(variants[0].decodingInfos.length).toBe(2);
314
- });
315
-
316
- it('does not error for unencrypted assets with no EME', async () => {
317
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
318
- manifest.addVariant(0, (variant) => {
319
- variant.addVideo(1, (stream) => {
320
- stream.mime('video/foo', 'vbar');
321
- });
322
- variant.addAudio(2, (stream) => {
323
- stream.mime('audio/foo', 'abar');
324
- });
325
- });
326
- });
327
-
328
- // Accept no key systems, simulating a lack of EME.
329
- setDecodingInfoSpy([]);
330
-
331
- const variants = manifest.variants;
332
- // All that matters here is that we don't throw.
333
- await expectAsync(
334
- drmEngine.initForPlayback(variants, manifest.offlineSessionIds))
335
- .not.toBeRejected();
336
- });
337
-
338
- it('fails to initialize if no key systems are recognized', async () => {
339
- // Simulate the DASH parser inserting a blank placeholder when only
340
- // unrecognized custom schemes are found.
341
- tweakDrmInfos((drmInfos) => {
342
- drmInfos[0].keySystem = '';
343
- drmInfos[1].keySystem = '';
344
- });
345
-
346
- const expected = Util.jasmineError(new shaka.util.Error(
347
- shaka.util.Error.Severity.CRITICAL,
348
- shaka.util.Error.Category.DRM,
349
- shaka.util.Error.Code.NO_RECOGNIZED_KEY_SYSTEMS));
350
- const variants = manifest.variants;
351
- await expectAsync(
352
- drmEngine.initForPlayback(variants, manifest.offlineSessionIds))
353
- .toBeRejectedWith(expected);
354
-
355
- expect(drmEngine.initialized()).toBe(false);
356
-
357
- expect(variants[0].decodingInfos.length).toBe(1);
358
- expect(variants[0].decodingInfos[0].keySystemAccess).toBeFalsy();
359
- });
360
-
361
- it('fails to initialize if the CDM cannot be created', async () => {
362
- // The query succeeds, but we fail to create the CDM.
363
- mockMediaKeySystemAccess.createMediaKeys.and.throwError('whoops!');
364
-
365
- const expected = Util.jasmineError(new shaka.util.Error(
366
- shaka.util.Error.Severity.CRITICAL,
367
- shaka.util.Error.Category.DRM,
368
- shaka.util.Error.Code.FAILED_TO_CREATE_CDM,
369
- 'whoops!'));
370
- const variants = manifest.variants;
371
- await expectAsync(
372
- drmEngine.initForPlayback(variants, manifest.offlineSessionIds))
373
- .toBeRejectedWith(expected);
374
-
375
- expect(drmEngine.initialized()).toBe(false);
376
- expect(variants[0].decodingInfos.length).toBe(2);
377
- });
378
-
379
- it('queries audio/video capabilities', async () => {
380
- setDecodingInfoSpy([]);
381
-
382
- const variants = manifest.variants;
383
- await expectAsync(
384
- drmEngine.initForPlayback(variants, manifest.offlineSessionIds))
385
- .toBeRejected();
386
-
387
- expect(drmEngine.initialized()).toBe(false);
388
-
389
- const decodingConfig1 = containing({
390
- video: containing({
391
- contentType: 'video/foo; codecs="vbar"',
392
- }),
393
- audio: containing({
394
- contentType: 'audio/foo; codecs="abar"',
395
- }),
396
- keySystemConfiguration: containing({
397
- keySystem: 'drm.abc',
398
- persistentState: 'optional',
399
- distinctiveIdentifier: 'optional',
400
- sessionTypes: ['temporary'],
401
- initDataType: 'cenc',
402
- }),
403
- });
404
-
405
- const decodingConfig2 = containing({
406
- video: containing({
407
- contentType: 'video/foo; codecs="vbar"',
408
- }),
409
- audio: containing({
410
- contentType: 'audio/foo; codecs="abar"',
411
- }),
412
- keySystemConfiguration: containing({
413
- keySystem: 'drm.def',
414
- persistentState: 'optional',
415
- distinctiveIdentifier: 'optional',
416
- sessionTypes: ['temporary'],
417
- initDataType: 'cenc',
418
- }),
419
- });
420
- expect(decodingInfoSpy).toHaveBeenCalledTimes(2);
421
- expect(decodingInfoSpy).toHaveBeenCalledWith(decodingConfig1);
422
- expect(decodingInfoSpy).toHaveBeenCalledWith(decodingConfig2);
423
- });
424
-
425
- it('asks for persistent state and license for offline', async () => {
426
- setDecodingInfoSpy([]);
427
-
428
- const variants = manifest.variants;
429
- await expectAsync(
430
- drmEngine.initForStorage(variants, /* usePersistentLicense= */ true))
431
- .toBeRejected();
432
-
433
- expect(drmEngine.initialized()).toBe(false);
434
-
435
- expect(decodingInfoSpy).toHaveBeenCalledTimes(2);
436
- expect(decodingInfoSpy).toHaveBeenCalledWith(containing({
437
- keySystemConfiguration: containing({
438
- keySystem: 'drm.abc',
439
- distinctiveIdentifier: 'optional',
440
- persistentState: 'required',
441
- sessionTypes: ['persistent-license'],
442
- initDataType: 'cenc',
443
- }),
444
- }),
445
- );
446
-
447
- expect(decodingInfoSpy).toHaveBeenCalledWith(containing({
448
- keySystemConfiguration: containing({
449
- keySystem: 'drm.def',
450
- distinctiveIdentifier: 'optional',
451
- persistentState: 'required',
452
- sessionTypes: ['persistent-license'],
453
- initDataType: 'cenc',
454
- }),
455
- }),
456
- );
457
- });
458
-
459
- it('honors distinctive identifier and persistent state', async () => {
460
- setDecodingInfoSpy([]);
461
- tweakDrmInfos((drmInfos) => {
462
- drmInfos[0].distinctiveIdentifierRequired = true;
463
- drmInfos[1].persistentStateRequired = true;
464
- });
465
-
466
- const variants = manifest.variants;
467
- await expectAsync(
468
- drmEngine.initForPlayback(variants, manifest.offlineSessionIds))
469
- .toBeRejected();
470
-
471
- expect(drmEngine.initialized()).toBe(false);
472
-
473
- expect(decodingInfoSpy).toHaveBeenCalledTimes(2);
474
- expect(decodingInfoSpy).toHaveBeenCalledWith(containing({
475
- keySystemConfiguration: containing({
476
- keySystem: 'drm.abc',
477
- distinctiveIdentifier: 'required',
478
- persistentState: 'optional',
479
- sessionTypes: ['temporary'],
480
- }),
481
- }),
482
- );
483
-
484
- expect(decodingInfoSpy).toHaveBeenCalledWith(containing({
485
- keySystemConfiguration: containing({
486
- keySystem: 'drm.def',
487
- distinctiveIdentifier: 'optional',
488
- persistentState: 'required',
489
- sessionTypes: ['temporary'],
490
- }),
491
- }),
492
- );
493
- });
494
-
495
- it('makes no queries for key systems with clear content if no key config',
496
- async () => {
497
- setDecodingInfoSpy([]);
498
- manifest.variants[0].video.drmInfos = [];
499
- manifest.variants[0].audio.drmInfos = [];
500
- config.servers = {};
501
- config.advanced = {};
502
-
503
- drmEngine.configure(config);
504
- const variants = manifest.variants;
505
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
506
-
507
- // Gets decodingInfo for clear content with no keySystemAccess.
508
- expect(variants[0].decodingInfos.length).toBe(1);
509
- expect(variants[0].decodingInfos[0].keySystemAccess).toBeFalsy();
510
- expect(
511
- shaka.media.DrmEngine.keySystem(drmEngine.getDrmInfo())).toBe('');
512
- expect(drmEngine.initialized()).toBe(true);
513
- });
514
-
515
- it('makes queries for clear content if key is configured', async () => {
516
- setDecodingInfoSpy(['drm.abc']);
517
- manifest.variants[0].video.drmInfos = [];
518
- manifest.variants[0].audio.drmInfos = [];
519
- config.servers = {
520
- 'drm.abc': 'http://abc.drm/license',
521
- };
522
-
523
- drmEngine.configure(config);
524
- const variants = manifest.variants;
525
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
526
- expect(drmEngine.initialized()).toBe(true);
527
- expect(shaka.media.DrmEngine.keySystem(drmEngine.getDrmInfo()))
528
- .toBe('drm.abc');
529
- expect(variants[0].decodingInfos.length).toBe(1);
530
- });
531
-
532
- it('uses advanced config to fill in DrmInfo', async () => {
533
- // Leave only one drmInfo
534
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
535
- manifest.addVariant(0, (variant) => {
536
- variant.addVideo(1, (stream) => {
537
- stream.encrypted = true;
538
- stream.addDrmInfo('drm.abc');
539
- });
540
- variant.addAudio(2, (stream) => {
541
- stream.encrypted = true;
542
- stream.addDrmInfo('drm.abc');
543
- });
544
- });
545
- });
546
-
547
- setDecodingInfoSpy([]);
548
-
549
- config.advanced['drm.abc'] = {
550
- audioRobustness: 'good',
551
- videoRobustness: 'really_really_ridiculously_good',
552
- serverCertificate: null,
553
- serverCertificateUri: '',
554
- sessionType: 'persistent-license',
555
- individualizationServer: '',
556
- distinctiveIdentifierRequired: true,
557
- persistentStateRequired: true,
558
- };
559
- drmEngine.configure(config);
560
-
561
- const variants = manifest.variants;
562
- await expectAsync(
563
- drmEngine.initForPlayback(variants, manifest.offlineSessionIds))
564
- .toBeRejected();
565
-
566
- expect(drmEngine.initialized()).toBe(false);
567
- expect(decodingInfoSpy).toHaveBeenCalledTimes(1);
568
- expect(decodingInfoSpy).toHaveBeenCalledWith(containing({
569
- keySystemConfiguration: containing({
570
- keySystem: 'drm.abc',
571
- distinctiveIdentifier: 'required',
572
- persistentState: 'required',
573
- sessionTypes: ['persistent-license'],
574
- initDataType: 'cenc',
575
- audio: containing({
576
- robustness: 'good',
577
- }),
578
- video: containing({
579
- robustness: 'really_really_ridiculously_good',
580
- }),
581
- }),
582
- }));
583
- });
584
-
585
- it('prefers advanced config from manifest if present', async () => {
586
- // Leave only one drmInfo
587
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
588
- manifest.addVariant(0, (variant) => {
589
- variant.addVideo(1, (stream) => {
590
- stream.encrypted = true;
591
- stream.addDrmInfo('drm.abc');
592
- });
593
- variant.addAudio(2, (stream) => {
594
- stream.encrypted = true;
595
- stream.addDrmInfo('drm.abc');
596
- });
597
- });
598
- });
599
-
600
- setDecodingInfoSpy([]);
601
-
602
- // DrmInfo directly sets advanced settings.
603
- tweakDrmInfos((drmInfos) => {
604
- drmInfos[0].distinctiveIdentifierRequired = true;
605
- drmInfos[0].persistentStateRequired = true;
606
- drmInfos[0].audioRobustness = 'good';
607
- drmInfos[0].videoRobustness = 'really_really_ridiculously_good';
608
- });
609
-
610
- config.advanced['drm.abc'] = {
611
- audioRobustness: 'bad',
612
- videoRobustness: 'so_bad_it_hurts',
613
- serverCertificate: null,
614
- serverCertificateUri: '',
615
- sessionType: '',
616
- individualizationServer: '',
617
- distinctiveIdentifierRequired: false,
618
- persistentStateRequired: false,
619
- };
620
- drmEngine.configure(config);
621
-
622
- const variants = manifest.variants;
623
- await expectAsync(
624
- drmEngine.initForPlayback(variants, manifest.offlineSessionIds))
625
- .toBeRejected();
626
-
627
- expect(drmEngine.initialized()).toBe(false);
628
-
629
- expect(decodingInfoSpy).toHaveBeenCalledTimes(1);
630
- expect(decodingInfoSpy).toHaveBeenCalledWith(containing({
631
- keySystemConfiguration: containing({
632
- keySystem: 'drm.abc',
633
- audio: containing({
634
- robustness: 'good',
635
- }),
636
- video: containing({
637
- robustness: 'really_really_ridiculously_good',
638
- }),
639
- distinctiveIdentifier: 'required',
640
- persistentState: 'required',
641
- initDataType: 'cenc',
642
- }),
643
- }));
644
- });
645
-
646
- it('sets unique initDataTypes if specified from the initData', async () => {
647
- tweakDrmInfos((drmInfos) => {
648
- drmInfos[0].initData = [
649
- {initDataType: 'very_nice', initData: new Uint8Array(5), keyId: null},
650
- {initDataType: 'very_nice', initData: new Uint8Array(5), keyId: null},
651
- ];
652
- });
653
-
654
- drmEngine.configure(config);
655
-
656
- const variants = manifest.variants;
657
-
658
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
659
-
660
- expect(drmEngine.initialized()).toBe(true);
661
- expect(decodingInfoSpy).toHaveBeenCalledTimes(2);
662
- expect(decodingInfoSpy).toHaveBeenCalledWith(containing({
663
- keySystemConfiguration: containing({
664
- keySystem: 'drm.abc',
665
- initDataType: 'very_nice',
666
- }),
667
- }),
668
- );
669
- });
670
-
671
- it('fails if license server is not configured', async () => {
672
- setDecodingInfoSpy(['drm.abc']);
673
-
674
- config.servers = {};
675
- drmEngine.configure(config);
676
-
677
- const expected = Util.jasmineError(new shaka.util.Error(
678
- shaka.util.Error.Severity.CRITICAL,
679
- shaka.util.Error.Category.DRM,
680
- shaka.util.Error.Code.NO_LICENSE_SERVER_GIVEN,
681
- 'drm.abc'));
682
- const variants = manifest.variants;
683
- await expectAsync(
684
- drmEngine.initForPlayback(variants, manifest.offlineSessionIds))
685
- .toBeRejectedWith(expected);
686
- });
687
-
688
- it('uses key system IDs from keySystemsMapping config', async () => {
689
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
690
- manifest.addVariant(0, (variant) => {
691
- variant.addVideo(1, (stream) => {
692
- stream.encrypted = true;
693
- stream.addDrmInfo('drm.abc');
694
- });
695
- });
696
- });
697
-
698
- setDecodingInfoSpy([]);
699
-
700
- config.keySystemsMapping['drm.abc'] = 'drm.def';
701
- drmEngine.configure(config);
702
-
703
- const variants = manifest.variants;
704
- await expectAsync(
705
- drmEngine.initForPlayback(variants, manifest.offlineSessionIds))
706
- .toBeRejected();
707
-
708
- expect(drmEngine.initialized()).toBe(false);
709
- expect(decodingInfoSpy).toHaveBeenCalledTimes(1);
710
- expect(decodingInfoSpy).toHaveBeenCalledWith(containing({
711
- keySystemConfiguration: containing({
712
- keySystem: 'drm.def',
713
- }),
714
- }));
715
- });
716
-
717
- it('maps TS MIME types through the transmuxer', async () => {
718
- const originalIsSupported =
719
- shaka.transmuxer.TransmuxerEngine.isSupported;
720
- const originalConvertCodecs =
721
- shaka.transmuxer.TransmuxerEngine.convertCodecs;
722
-
723
- try {
724
- // Mock out isSupported on Transmuxer so that we don't have to care
725
- // about what MediaSource supports under that. All we really care about
726
- // is the translation of MIME types.
727
- shaka.transmuxer.TransmuxerEngine.isSupported =
728
- (mimeType, contentType) => {
729
- return mimeType.startsWith('video/mp2t');
730
- };
731
- shaka.transmuxer.TransmuxerEngine.convertCodecs =
732
- (contentType, mimeType) => {
733
- let newMimeType = mimeType.replace('mp2t', 'mp4');
734
- if (contentType == 'audio') {
735
- newMimeType = newMimeType.replace('video', 'audio');
736
- }
737
- return newMimeType;
738
- };
739
-
740
- // The default mock for this is so unrealistic, some of our test
741
- // conditions would always fail. Make it realistic enough for this
742
- // test case by returning the same types we are supposed to be querying
743
- // for. That way, supportsVariant() should work produce the correct
744
- // result after translating the types of the variant's streams.
745
- mockMediaKeySystemAccess.getConfiguration.and.callFake(() => {
746
- return {
747
- audioCapabilities: [{contentType: 'audio/mp4; codecs="abar"'}],
748
- videoCapabilities: [{contentType: 'video/mp4; codecs="vbar"'}],
749
- };
750
- });
751
-
752
- setDecodingInfoSpy(['drm.abc']);
753
-
754
- const variants = manifest.variants;
755
- variants[0].video.mimeType = 'video/mp2t';
756
- variants[0].audio.mimeType = 'video/mp2t';
757
-
758
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
759
- expect(drmEngine.initialized()).toBe(true);
760
-
761
- const decodingConfig = containing({
762
- video: containing({
763
- contentType: 'video/mp4; codecs="vbar"',
764
- }),
765
- audio: containing({
766
- contentType: 'audio/mp4; codecs="abar"',
767
- }),
768
- });
769
- expect(decodingInfoSpy).toHaveBeenCalledTimes(2);
770
- expect(decodingInfoSpy).toHaveBeenCalledWith(decodingConfig);
771
-
772
- expect(drmEngine.supportsVariant(variants[0])).toBeTruthy();
773
- } finally {
774
- // Restore the mock.
775
- shaka.transmuxer.TransmuxerEngine.isSupported = originalIsSupported;
776
- shaka.transmuxer.TransmuxerEngine.convertCodecs =
777
- originalConvertCodecs;
778
- }
779
- });
780
- }); // describe('init')
781
-
782
- describe('attach', () => {
783
- beforeEach(() => {
784
- // Both audio and video with the same key system:
785
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
786
- manifest.addVariant(0, (variant) => {
787
- variant.addVideo(1, (stream) => {
788
- stream.encrypted = true;
789
- stream.addDrmInfo('drm.abc');
790
- });
791
- variant.addAudio(2, (stream) => {
792
- stream.encrypted = true;
793
- stream.addDrmInfo('drm.abc');
794
- });
795
- });
796
- });
797
- });
798
-
799
- it('does nothing for unencrypted content', async () => {
800
- setDecodingInfoSpy([]);
801
- manifest.variants[0].video.drmInfos = [];
802
- manifest.variants[0].audio.drmInfos = [];
803
- config.servers = {};
804
- config.advanced = {};
805
-
806
- await initAndAttach();
807
- expect(mockVideo.setMediaKeys).not.toHaveBeenCalled();
808
- });
809
-
810
- it('sets server certificate if present in config', async () => {
811
- const cert = new Uint8Array(1);
812
- config.advanced['drm.abc'] = createAdvancedConfig(cert);
813
- config.advanced['drm.abc'].serverCertificateUri =
814
- 'https://drm-service.com/certificate';
815
- drmEngine.configure(config);
816
-
817
- const variants = manifest.variants;
818
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
819
-
820
- expect(fakeNetEngine.request).not.toHaveBeenCalled();
821
- // Should be set merely after init, without waiting for attach.
822
- expect(mockMediaKeys.setServerCertificate).toHaveBeenCalledWith(cert);
823
- });
824
-
825
- it('fetches and sets server certificate from uri', async () => {
826
- const cert = new Uint8Array(0);
827
- const serverCertificateUri = 'https://drm-service.com/certificate';
828
- config.advanced['drm.abc'] = createAdvancedConfig(cert);
829
- config.advanced['drm.abc'].serverCertificateUri = serverCertificateUri;
830
-
831
- fakeNetEngine.setResponseValue(
832
- serverCertificateUri,
833
- shaka.util.BufferUtils.toArrayBuffer(new Uint8Array(1)));
834
-
835
- drmEngine.configure(config);
836
-
837
- const variants = manifest.variants;
838
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
839
-
840
- fakeNetEngine.expectRequest(
841
- serverCertificateUri,
842
- shaka.net.NetworkingEngine.RequestType.SERVER_CERTIFICATE);
843
-
844
- // Should be set merely after init, without waiting for attach.
845
- expect(mockMediaKeys.setServerCertificate).toHaveBeenCalledWith(
846
- new Uint8Array(1));
847
- });
848
-
849
- it('fetches server certificate from uri and triggers error', async () => {
850
- const cert = new Uint8Array(0);
851
- const serverCertificateUri = 'https://drm-service.com/certificate';
852
- config.advanced['drm.abc'] = createAdvancedConfig(cert);
853
- config.advanced['drm.abc'].serverCertificateUri = serverCertificateUri;
854
-
855
- // Simulate a permission error from the web server.
856
- const netError = new shaka.util.Error(
857
- shaka.util.Error.Severity.CRITICAL,
858
- shaka.util.Error.Category.NETWORK,
859
- shaka.util.Error.Code.BAD_HTTP_STATUS,
860
- serverCertificateUri, 403);
861
- const operation = shaka.util.AbortableOperation.failed(netError);
862
- fakeNetEngine.request.and.returnValue(operation);
863
-
864
- drmEngine.configure(config);
865
-
866
- const expected = Util.jasmineError(new shaka.util.Error(
867
- shaka.util.Error.Severity.CRITICAL,
868
- shaka.util.Error.Category.DRM,
869
- shaka.util.Error.Code.SERVER_CERTIFICATE_REQUEST_FAILED,
870
- netError));
871
-
872
- await expectAsync(initAndAttach()).toBeRejectedWith(expected);
873
-
874
- fakeNetEngine.expectRequest(
875
- serverCertificateUri,
876
- shaka.net.NetworkingEngine.RequestType.SERVER_CERTIFICATE);
877
-
878
- // Should be set merely after init, without waiting for attach.
879
- expect(mockMediaKeys.setServerCertificate).not.toHaveBeenCalled();
880
- });
881
-
882
- it('prefers server certificate from DrmInfo', async () => {
883
- const cert1 = new Uint8Array(5);
884
- const cert2 = new Uint8Array(1);
885
- tweakDrmInfos((drmInfos) => {
886
- drmInfos[0].serverCertificate = cert1;
887
- });
888
-
889
- config.advanced['drm.abc'] = createAdvancedConfig(cert2);
890
- drmEngine.configure(config);
891
-
892
- await initAndAttach();
893
- expect(mockMediaKeys.setServerCertificate).toHaveBeenCalledWith(cert1);
894
- });
895
-
896
- it('does not set server certificate if absent', async () => {
897
- await initAndAttach();
898
- expect(mockMediaKeys.setServerCertificate).not.toHaveBeenCalled();
899
- });
900
-
901
- it('creates sessions for init data overrides', async () => {
902
- // Set up init data overrides in the manifest:
903
- /** @type {!Uint8Array} */
904
- const initData1 = new Uint8Array(5);
905
- /** @type {!Uint8Array} */
906
- const initData2 = new Uint8Array(1);
907
- /** @type {!Uint8Array} */
908
- const initData3 = new Uint8Array(10);
909
-
910
- tweakDrmInfos((drmInfos) => {
911
- drmInfos[0].initData = [
912
- {initData: initData1, initDataType: 'cenc', keyId: null},
913
- {initData: initData2, initDataType: 'webm', keyId: null},
914
- {initData: initData3, initDataType: 'cenc', keyId: null},
915
- ];
916
- });
917
-
918
- await initAndAttach();
919
- expect(mockMediaKeys.createSession).toHaveBeenCalledTimes(3);
920
- expect(session1.generateRequest)
921
- .toHaveBeenCalledWith('cenc', initData1);
922
- expect(session2.generateRequest)
923
- .toHaveBeenCalledWith('webm', initData2);
924
- expect(session3.generateRequest)
925
- .toHaveBeenCalledWith('cenc', initData3);
926
- });
927
-
928
- it('ignores duplicate init data overrides', async () => {
929
- // Set up init data overrides in the manifest;
930
- // The second initData has a different keyId from the first,
931
- // but the same initData.
932
- // The third initData has a different initData from the first,
933
- // but the same keyId.
934
- // Both should be discarded as duplicates.
935
- /** @type {!Uint8Array} */
936
- const initData1 = new Uint8Array(1);
937
- const initData2 = new Uint8Array(1);
938
- const initData3 = new Uint8Array(10);
939
-
940
- tweakDrmInfos((drmInfos) => {
941
- drmInfos[0].initData = [
942
- {initData: initData1, initDataType: 'cenc', keyId: 'abc'},
943
- {initData: initData2, initDataType: 'cenc', keyId: 'def'},
944
- {initData: initData3, initDataType: 'cenc', keyId: 'abc'},
945
- ];
946
- });
947
-
948
- await initAndAttach();
949
- expect(mockMediaKeys.createSession).toHaveBeenCalledTimes(1);
950
- expect(session1.generateRequest)
951
- .toHaveBeenCalledWith('cenc', initData1);
952
- });
953
-
954
- // https://github.com/shaka-project/shaka-player/issues/2754
955
- it('ignores duplicate init data from newInitData', async () => {
956
- /** @type {!Uint8Array} */
957
- const initData = new Uint8Array(1);
958
-
959
- tweakDrmInfos((drmInfos) => {
960
- drmInfos[0].initData =
961
- [{initData: initData, initDataType: 'cenc', keyId: 'abc'}];
962
- });
963
-
964
- await drmEngine.initForPlayback(
965
- manifest.variants, manifest.offlineSessionIds);
966
- drmEngine.newInitData('cenc', initData);
967
- await drmEngine.attach(mockVideo);
968
-
969
- expect(mockMediaKeys.createSession).toHaveBeenCalledTimes(1);
970
- expect(session1.generateRequest).toHaveBeenCalledWith('cenc', initData);
971
- });
972
-
973
- it('uses clearKeys config to override DrmInfo', async () => {
974
- tweakDrmInfos((drmInfos) => {
975
- drmInfos[0].keySystem = 'com.fake.NOT.clearkey';
976
- });
977
-
978
- setDecodingInfoSpy(['org.w3.clearkey']);
979
-
980
- // Configure clear keys (map of hex key IDs to keys)
981
- config.clearKeys = {
982
- 'deadbeefdeadbeefdeadbeefdeadbeef': '18675309186753091867530918675309',
983
- '02030507011013017019023029031037': '03050701302303204201080425098033',
984
- };
985
- drmEngine.configure(config);
986
-
987
- const session = createMockSession();
988
- mockMediaKeys.createSession.and.callFake(() => {
989
- expect(mockMediaKeys.createSession).toHaveBeenCalledTimes(1);
990
- return session;
991
- });
992
-
993
- await initAndAttach();
994
- const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
995
-
996
- tweakDrmInfos((drmInfos) => {
997
- expect(drmInfos.length).toBe(1);
998
- expect(drmInfos[0].keySystem).toBe('org.w3.clearkey');
999
- });
1000
-
1001
- expect(session.generateRequest)
1002
- .toHaveBeenCalledWith('keyids', jasmine.any(Uint8Array));
1003
-
1004
- const initData = /** @type {{kids: !Array.<string>}} */(JSON.parse(
1005
- shaka.util.StringUtils.fromUTF8(
1006
- session.generateRequest.calls.argsFor(0)[1])));
1007
- const keyId1 = Uint8ArrayUtils.toHex(
1008
- Uint8ArrayUtils.fromBase64(initData.kids[0]));
1009
- const keyId2 = Uint8ArrayUtils.toHex(
1010
- Uint8ArrayUtils.fromBase64(initData.kids[1]));
1011
- expect(keyId1).toBe('deadbeefdeadbeefdeadbeefdeadbeef');
1012
- expect(keyId2).toBe('02030507011013017019023029031037');
1013
- });
1014
-
1015
- // Regression test for #2139, in which we suppressed errors if drmInfos was
1016
- // empty and clearKeys config was given
1017
- it('fails if clearKeys config fails', async () => {
1018
- manifest.variants[0].video.drmInfos = [];
1019
- manifest.variants[0].audio.drmInfos = [];
1020
-
1021
- // Make it so that clear key setup fails by pretending we don't have it.
1022
- // In reality, it was failing because of missing codec info, but any
1023
- // failure should do for testing purposes.
1024
- setDecodingInfoSpy([]);
1025
-
1026
- // Configure clear keys (map of hex key IDs to keys)
1027
- config.clearKeys = {
1028
- 'deadbeefdeadbeefdeadbeefdeadbeef': '18675309186753091867530918675309',
1029
- '02030507011013017019023029031037': '03050701302303204201080425098033',
1030
- };
1031
- drmEngine.configure(config);
1032
-
1033
- const variants = manifest.variants;
1034
-
1035
- const expected = Util.jasmineError(new shaka.util.Error(
1036
- shaka.util.Error.Severity.CRITICAL,
1037
- shaka.util.Error.Category.DRM,
1038
- shaka.util.Error.Code.REQUESTED_KEY_SYSTEM_CONFIG_UNAVAILABLE));
1039
- await expectAsync(drmEngine.initForPlayback(variants, []))
1040
- .toBeRejectedWith(expected);
1041
- });
1042
-
1043
- it('fails with an error if setMediaKeys fails', async () => {
1044
- // Fail setMediaKeys.
1045
- mockVideo.setMediaKeys.and.returnValue(Promise.reject(
1046
- new Error('whoops!')));
1047
-
1048
- tweakDrmInfos((drmInfos) => {
1049
- drmInfos[0].initData = [
1050
- {initData: new Uint8Array(1), initDataType: 'cenc', keyId: null},
1051
- ];
1052
- });
1053
-
1054
- onErrorSpy.and.stub();
1055
-
1056
- await initAndAttach();
1057
-
1058
- expect(onErrorSpy).toHaveBeenCalled();
1059
- const error = onErrorSpy.calls.argsFor(0)[0];
1060
- shaka.test.Util.expectToEqualError(error, new shaka.util.Error(
1061
- shaka.util.Error.Severity.CRITICAL,
1062
- shaka.util.Error.Category.DRM,
1063
- shaka.util.Error.Code.FAILED_TO_ATTACH_TO_VIDEO,
1064
- 'whoops!'));
1065
- });
1066
-
1067
- it('fails with an error if setServerCertificate fails', async () => {
1068
- const cert = new Uint8Array(1);
1069
- config.advanced['drm.abc'] = createAdvancedConfig(cert);
1070
- drmEngine.configure(config);
1071
-
1072
- // Fail setServerCertificate.
1073
- mockMediaKeys.setServerCertificate.and.returnValue(Promise.reject(
1074
- new Error('whoops!')));
1075
-
1076
- const expected = Util.jasmineError(new shaka.util.Error(
1077
- shaka.util.Error.Severity.CRITICAL,
1078
- shaka.util.Error.Category.DRM,
1079
- shaka.util.Error.Code.INVALID_SERVER_CERTIFICATE,
1080
- 'whoops!'));
1081
- await expectAsync(initAndAttach()).toBeRejectedWith(expected);
1082
- });
1083
-
1084
- it('dispatches an error if generateRequest fails', async () => {
1085
- // Set up an init data override in the manifest to get an immediate call
1086
- // to generateRequest:
1087
- const initData1 = new Uint8Array(5);
1088
-
1089
- tweakDrmInfos((drmInfos) => {
1090
- drmInfos[0].initData = [
1091
- {initData: initData1, initDataType: 'cenc', keyId: null},
1092
- ];
1093
- });
1094
-
1095
- // Fail generateRequest.
1096
- const session1 = createMockSession();
1097
- const message = 'whoops!';
1098
- const nativeError = new Error(message);
1099
- session1.generateRequest.and.returnValue(Promise.reject(nativeError));
1100
- mockMediaKeys.createSession.and.returnValue(session1);
1101
-
1102
- onErrorSpy.and.stub();
1103
- await initAndAttach();
1104
- expect(onErrorSpy).toHaveBeenCalled();
1105
- const error = onErrorSpy.calls.argsFor(0)[0];
1106
- shaka.test.Util.expectToEqualError(error, new shaka.util.Error(
1107
- shaka.util.Error.Severity.CRITICAL,
1108
- shaka.util.Error.Category.DRM,
1109
- shaka.util.Error.Code.FAILED_TO_GENERATE_LICENSE_REQUEST,
1110
- message, nativeError, undefined));
1111
- });
1112
-
1113
- it('should throw a OFFLINE_SESSION_REMOVED error', async () => {
1114
- // Given persistent session is not available
1115
- session1.load.and.returnValue(false);
1116
-
1117
- onErrorSpy.and.stub();
1118
-
1119
- await drmEngine.initForPlayback(
1120
- manifest.variants, ['persistent-session-id']);
1121
- await drmEngine.attach(mockVideo);
1122
-
1123
- expect(drmEngine.initialized()).toBe(true);
1124
-
1125
- await Util.shortDelay();
1126
-
1127
- expect(mockMediaKeys.createSession).toHaveBeenCalledTimes(1);
1128
- expect(mockMediaKeys.createSession)
1129
- .toHaveBeenCalledWith('persistent-license');
1130
- expect(session1.load).toHaveBeenCalledWith('persistent-session-id');
1131
-
1132
- expect(onErrorSpy).toHaveBeenCalled();
1133
- const error = onErrorSpy.calls.argsFor(0)[0];
1134
- shaka.test.Util.expectToEqualError(error, new shaka.util.Error(
1135
- shaka.util.Error.Severity.CRITICAL,
1136
- shaka.util.Error.Category.DRM,
1137
- shaka.util.Error.Code.OFFLINE_SESSION_REMOVED));
1138
- });
1139
-
1140
- it('uses persistent session ids when available', async () => {
1141
- const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
1142
-
1143
- const keyId1 = makeKeyId(1);
1144
- const keyId2 = makeKeyId(2);
1145
-
1146
- /** @type {!Uint8Array} */
1147
- const initData1 = new Uint8Array(5);
1148
-
1149
- // Key IDs in manifest
1150
- tweakDrmInfos((drmInfos) => {
1151
- drmInfos[0].keyIds = new Set([
1152
- Uint8ArrayUtils.toHex(keyId1), Uint8ArrayUtils.toHex(keyId2),
1153
- ]);
1154
- drmInfos[0].initData = [
1155
- {initData: initData1, initDataType: 'cenc', keyId: null},
1156
- ];
1157
- });
1158
-
1159
- // Given persistent session is available
1160
- session1.load.and.returnValue(true);
1161
-
1162
- config.persistentSessionOnlinePlayback = true;
1163
- config.persistentSessionsMetadata = [{
1164
- sessionId: 'persistent-session-id',
1165
- initData: initData1,
1166
- initDataType: 'cenc'}];
1167
-
1168
- drmEngine.configure(config);
1169
-
1170
- await initAndAttach();
1171
-
1172
- await Util.shortDelay();
1173
-
1174
- session1.keyStatuses.forEach.and.callFake((callback) => {
1175
- callback(keyId1, 'usable');
1176
- callback(keyId2, 'usable');
1177
- });
1178
-
1179
- session1.on['keystatuseschange']({target: session1});
1180
-
1181
- expect(mockMediaKeys.createSession).toHaveBeenCalledTimes(1);
1182
- expect(mockMediaKeys.createSession)
1183
- .toHaveBeenCalledWith('persistent-license');
1184
- expect(session1.load).toHaveBeenCalledWith('persistent-session-id');
1185
-
1186
- expect(session2.generateRequest).not.toHaveBeenCalled();
1187
- });
1188
-
1189
- it(
1190
- 'tries persistent session ids before requesting a license',
1191
- async () => {
1192
- const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
1193
-
1194
- const keyId1 = makeKeyId(1);
1195
-
1196
- /** @type {!Uint8Array} */
1197
- const initData1 = new Uint8Array(5);
1198
-
1199
- // Key IDs in manifest
1200
- tweakDrmInfos((drmInfos) => {
1201
- drmInfos[0].keyIds = new Set([
1202
- Uint8ArrayUtils.toHex(keyId1),
1203
- ]);
1204
- drmInfos[0].sessionType = 'temporary';
1205
- drmInfos[0].initData = [
1206
- {initData: initData1, initDataType: 'cenc', keyId: null},
1207
- ];
1208
- });
1209
-
1210
- // Given persistent sessions aren't available
1211
- session1.load.and.returnValue(Promise.resolve(false));
1212
- session2.load.and.returnValue(
1213
- Promise.reject(new Error('This should be a recoverable error')));
1214
-
1215
- manifest.offlineSessionIds = ['persistent-session-id-1'];
1216
-
1217
- config.persistentSessionsMetadata = [{
1218
- sessionId: 'persistent-session-id-2',
1219
- initData: initData1,
1220
- initDataType: 'cenc'}];
1221
- config.persistentSessionOnlinePlayback = true;
1222
-
1223
- drmEngine.configure(config);
1224
-
1225
- onErrorSpy.and.stub();
1226
-
1227
- await initAndAttach();
1228
-
1229
- await Util.shortDelay();
1230
-
1231
- shaka.test.Util.expectToEqualError(
1232
- onErrorSpy.calls.argsFor(0)[0],
1233
- new shaka.util.Error(
1234
- shaka.util.Error.Severity.RECOVERABLE,
1235
- shaka.util.Error.Category.DRM,
1236
- shaka.util.Error.Code.OFFLINE_SESSION_REMOVED));
1237
-
1238
- shaka.test.Util.expectToEqualError(
1239
- onErrorSpy.calls.argsFor(1)[0],
1240
- new shaka.util.Error(
1241
- shaka.util.Error.Severity.RECOVERABLE,
1242
- shaka.util.Error.Category.DRM,
1243
- shaka.util.Error.Code.FAILED_TO_CREATE_SESSION,
1244
- 'This should be a recoverable error'));
1245
-
1246
- // We need to go through the whole license request / update,
1247
- // otherwise the DrmEngine will be destroyed while waiting for
1248
- // sessions to be marked as loaded, throwing an unhandled exception
1249
- const operation = shaka.util.AbortableOperation.completed(
1250
- new Uint8Array(0));
1251
- fakeNetEngine.request.and.returnValue(operation);
1252
-
1253
- await Util.shortDelay();
1254
-
1255
- session3.on['message']({
1256
- target: session3,
1257
- message: new Uint8Array(0),
1258
- messageType: 'license-request'});
1259
-
1260
- session3.keyStatuses.forEach.and.callFake((callback) => {
1261
- callback(keyId1, 'usable');
1262
- });
1263
-
1264
- session3.on['keystatuseschange']({target: session3});
1265
-
1266
- await Util.shortDelay();
1267
-
1268
- expect(mockMediaKeys.createSession).toHaveBeenCalledTimes(3);
1269
- expect(mockMediaKeys.createSession)
1270
- .toHaveBeenCalledWith('persistent-license');
1271
- expect(session1.load)
1272
- .toHaveBeenCalledWith('persistent-session-id-1');
1273
-
1274
- expect(mockMediaKeys.createSession)
1275
- .toHaveBeenCalledWith('persistent-license');
1276
- expect(session2.load)
1277
- .toHaveBeenCalledWith('persistent-session-id-2');
1278
-
1279
- expect(mockMediaKeys.createSession)
1280
- .toHaveBeenCalledWith('temporary');
1281
- expect(session3.generateRequest)
1282
- .toHaveBeenCalledWith('cenc', initData1);
1283
- });
1284
- }); // describe('attach')
1285
-
1286
- describe('events', () => {
1287
- describe('encrypted', () => {
1288
- it('is listened for', async () => {
1289
- await initAndAttach();
1290
- expect(mockVideo.addEventListener).toHaveBeenCalledWith(
1291
- 'encrypted', jasmine.any(Function), jasmine.anything());
1292
- });
1293
-
1294
- it('is not listened for if parseInbandPsshEnabled is true', async () => {
1295
- config.parseInbandPsshEnabled = true;
1296
- drmEngine.configure(config);
1297
- await initAndAttach();
1298
- expect(mockVideo.addEventListener).not.toHaveBeenCalledWith(
1299
- 'encrypted', jasmine.any(Function), jasmine.anything());
1300
- });
1301
-
1302
- it('triggers the creation of a session', async () => {
1303
- await initAndAttach();
1304
- const initData1 = new Uint8Array(1);
1305
- const initData2 = new Uint8Array(2);
1306
-
1307
- await sendEncryptedEvent('webm', initData1);
1308
- await sendEncryptedEvent('cenc', initData2);
1309
-
1310
- expect(mockMediaKeys.createSession).toHaveBeenCalledTimes(2);
1311
- expect(session1.generateRequest)
1312
- .toHaveBeenCalledWith('webm', initData1);
1313
- expect(session2.generateRequest)
1314
- .toHaveBeenCalledWith('cenc', initData2);
1315
- });
1316
-
1317
- it('suppresses duplicate initDatas', async () => {
1318
- await initAndAttach();
1319
-
1320
- const initData1 = new Uint8Array(1);
1321
-
1322
- await sendEncryptedEvent('webm', initData1);
1323
- await sendEncryptedEvent('cenc'); // identical to webm initData
1324
-
1325
- expect(mockMediaKeys.createSession).toHaveBeenCalledTimes(1);
1326
- expect(session1.generateRequest)
1327
- .toHaveBeenCalledWith('webm', initData1);
1328
- });
1329
-
1330
- it('set media keys when not already done at startup', async () => {
1331
- await initAndAttach();
1332
- await sendEncryptedEvent();
1333
-
1334
- expect(mockVideo.setMediaKeys).toHaveBeenCalledTimes(1);
1335
- expect(mockMediaKeys.createSession).toHaveBeenCalledTimes(1);
1336
- });
1337
-
1338
- it('dispatches an error if createSession fails', async () => {
1339
- mockMediaKeys.createSession.and.throwError('whoops!');
1340
- onErrorSpy.and.stub();
1341
-
1342
- await initAndAttach();
1343
- await sendEncryptedEvent();
1344
-
1345
- expect(onErrorSpy).toHaveBeenCalled();
1346
- const error = onErrorSpy.calls.argsFor(0)[0];
1347
- shaka.test.Util.expectToEqualError(error, new shaka.util.Error(
1348
- shaka.util.Error.Severity.CRITICAL,
1349
- shaka.util.Error.Category.DRM,
1350
- shaka.util.Error.Code.FAILED_TO_CREATE_SESSION,
1351
- 'whoops!'));
1352
- });
1353
-
1354
- it('dispatches an error if manifest says unencrypted', async () => {
1355
- manifest.variants[0].video.drmInfos = [];
1356
- manifest.variants[0].audio.drmInfos = [];
1357
- config.servers = {};
1358
- config.advanced = {};
1359
-
1360
- onErrorSpy.and.stub();
1361
-
1362
- await initAndAttach();
1363
- await sendEncryptedEvent();
1364
-
1365
- expect(onErrorSpy).toHaveBeenCalled();
1366
- const error = onErrorSpy.calls.argsFor(0)[0];
1367
- shaka.test.Util.expectToEqualError(error, new shaka.util.Error(
1368
- shaka.util.Error.Severity.CRITICAL,
1369
- shaka.util.Error.Category.DRM,
1370
- shaka.util.Error.Code.ENCRYPTED_CONTENT_WITHOUT_DRM_INFO));
1371
- });
1372
- }); // describe('encrypted')
1373
-
1374
- describe('message', () => {
1375
- it('is listened for', async () => {
1376
- await initAndAttach();
1377
- await sendEncryptedEvent();
1378
-
1379
- expect(session1.addEventListener).toHaveBeenCalledWith(
1380
- 'message', jasmine.any(Function), jasmine.anything());
1381
- });
1382
-
1383
- it('triggers a license request', async () => {
1384
- await sendMessageTest('http://abc.drm/license');
1385
- });
1386
-
1387
- it('prefers a license server URI from configuration', async () => {
1388
- tweakDrmInfos((drmInfos) => {
1389
- drmInfos[0].licenseServerUri = 'http://foo.bar/drm';
1390
- });
1391
- await sendMessageTest('http://abc.drm/license');
1392
- });
1393
-
1394
- it('handles "individualization-request" messages special', async () => {
1395
- config.advanced['drm.abc'] = createAdvancedConfig(null);
1396
- config.advanced['drm.abc'].individualizationServer =
1397
- 'http://foo.bar/drm';
1398
- expect(config.servers['drm.abc']).not.toBe('http://foo.bar/drm');
1399
-
1400
- await sendMessageTest(
1401
- 'http://foo.bar/drm', 'individualization-request');
1402
- });
1403
-
1404
- it('uses license server for "individualization-request" by default',
1405
- async () => {
1406
- config.advanced['drm.abc'] = createAdvancedConfig(null);
1407
- config.advanced['drm.abc'].individualizationServer = '';
1408
-
1409
- await sendMessageTest(
1410
- 'http://abc.drm/license', 'individualization-request');
1411
- });
1412
-
1413
- it('dispatches an error if license request fails', async () => {
1414
- onErrorSpy.and.stub();
1415
-
1416
- await initAndAttach();
1417
- await sendEncryptedEvent();
1418
-
1419
- // Simulate a permission error from the web server.
1420
- const netError = new shaka.util.Error(
1421
- shaka.util.Error.Severity.CRITICAL,
1422
- shaka.util.Error.Category.NETWORK,
1423
- shaka.util.Error.Code.BAD_HTTP_STATUS,
1424
- 'http://abc.drm/license', 403);
1425
- const operation = shaka.util.AbortableOperation.failed(netError);
1426
- fakeNetEngine.request.and.returnValue(operation);
1427
-
1428
- const message = new Uint8Array(0);
1429
- session1.on['message']({target: session1, message: message});
1430
- await shaka.test.Util.shortDelay();
1431
-
1432
- expect(onErrorSpy).toHaveBeenCalled();
1433
- const error = onErrorSpy.calls.argsFor(0)[0];
1434
- shaka.test.Util.expectToEqualError(error, new shaka.util.Error(
1435
- shaka.util.Error.Severity.CRITICAL,
1436
- shaka.util.Error.Category.DRM,
1437
- shaka.util.Error.Code.LICENSE_REQUEST_FAILED,
1438
- jasmine.objectContaining({
1439
- category: shaka.util.Error.Category.NETWORK,
1440
- code: shaka.util.Error.Code.BAD_HTTP_STATUS,
1441
- data: ['http://abc.drm/license', 403],
1442
- })));
1443
- });
1444
-
1445
- /**
1446
- * @param {string=} expectedUrl
1447
- * @param {string=} messageType
1448
- * @return {!Promise}
1449
- */
1450
- async function sendMessageTest(
1451
- expectedUrl, messageType = 'license-request') {
1452
- await initAndAttach();
1453
- await sendEncryptedEvent();
1454
-
1455
- const operation = shaka.util.AbortableOperation.completed({});
1456
- fakeNetEngine.request.and.returnValue(operation);
1457
- const message = new Uint8Array(0);
1458
- session1.on['message'](
1459
- {target: session1, message: message, messageType: messageType});
1460
-
1461
- expect(fakeNetEngine.request).toHaveBeenCalledWith(
1462
- shaka.net.NetworkingEngine.RequestType.LICENSE,
1463
- jasmine.objectContaining({
1464
- uris: [expectedUrl],
1465
- method: 'POST',
1466
- body: message,
1467
- licenseRequestType: messageType,
1468
- }));
1469
- }
1470
- }); // describe('message')
1471
-
1472
- describe('keystatuseschange', () => {
1473
- it('is listened for', async () => {
1474
- await initAndAttach();
1475
- await sendEncryptedEvent();
1476
-
1477
- expect(session1.addEventListener).toHaveBeenCalledWith(
1478
- 'keystatuseschange', jasmine.any(Function), jasmine.anything());
1479
- });
1480
-
1481
- it('triggers callback', async () => {
1482
- await initAndAttach();
1483
- await sendEncryptedEvent();
1484
-
1485
- const keyId1 = makeKeyId(1);
1486
- const keyId2 = makeKeyId(2);
1487
- const status1 = 'usable';
1488
- const status2 = 'expired';
1489
- session1.keyStatuses.forEach.and.callFake((callback) => {
1490
- callback(keyId1, status1);
1491
- callback(keyId2, status2);
1492
- });
1493
-
1494
- onKeyStatusSpy.and.callFake((statusMap) => {
1495
- expect(statusMap).toEqual({
1496
- '01': status1,
1497
- '02': status2,
1498
- });
1499
- });
1500
-
1501
- session1.on['keystatuseschange']({target: session1});
1502
- await Util.shortDelay();
1503
- expect(onKeyStatusSpy).toHaveBeenCalled();
1504
- });
1505
-
1506
- // See https://github.com/shaka-project/shaka-player/issues/1541
1507
- it('does not update public key statuses before callback', async () => {
1508
- await initAndAttach();
1509
- await sendEncryptedEvent();
1510
-
1511
- const keyId1 = makeKeyId(1);
1512
- const keyId2 = makeKeyId(2);
1513
- const status1 = 'usable';
1514
- const status2 = 'expired';
1515
- session1.keyStatuses.forEach.and.callFake((callback) => {
1516
- callback(keyId1, status1);
1517
- callback(keyId2, status2);
1518
- });
1519
-
1520
- session1.on['keystatuseschange']({target: session1});
1521
-
1522
- // The callback waits for some time to pass, to batch up status changes.
1523
- expect(onKeyStatusSpy).not.toHaveBeenCalled();
1524
-
1525
- // The publicly-accessible key statuses should not show these new
1526
- // changes yet. This shows that we have solved the race between the
1527
- // callback and any polling done by any other component.
1528
- let keyIds = Object.keys(drmEngine.getKeyStatuses());
1529
- expect(keyIds.length).toBe(0);
1530
-
1531
- // Wait for the callback to occur, then end the test.
1532
- await new Promise((resolve) => {
1533
- onKeyStatusSpy.and.callFake(resolve);
1534
- });
1535
-
1536
- // Now key statuses are available.
1537
- keyIds = Object.keys(drmEngine.getKeyStatuses());
1538
- expect(keyIds.length).toBe(2);
1539
- });
1540
-
1541
- // See https://github.com/shaka-project/shaka-player/issues/1541
1542
- it('does not invoke callback until all sessions are loaded', async () => {
1543
- // Set up init data overrides in the manifest so that we get multiple
1544
- // sessions.
1545
- const initData1 = new Uint8Array(10);
1546
- const initData2 = new Uint8Array(11);
1547
-
1548
- tweakDrmInfos((drmInfos) => {
1549
- drmInfos[0].initData = [
1550
- {initData: initData1, initDataType: 'cenc', keyId: null},
1551
- {initData: initData2, initDataType: 'cenc', keyId: null},
1552
- ];
1553
- });
1554
-
1555
- const keyId1 = makeKeyId(1);
1556
- const keyId2 = makeKeyId(2);
1557
- session1.keyStatuses.forEach.and.callFake((callback) => {
1558
- callback(keyId1, 'usable');
1559
- });
1560
- session2.keyStatuses.forEach.and.callFake((callback) => {
1561
- callback(keyId2, 'usable');
1562
- });
1563
-
1564
- await initAndAttach();
1565
-
1566
- // The callback waits for some time to pass, to batch up status changes.
1567
- // But even after some time has passed, we should not have invoked the
1568
- // callback, because we don't have a status for session2 yet.
1569
- session1.on['keystatuseschange']({target: session1});
1570
- await shaka.test.Util.shortDelay();
1571
- expect(onKeyStatusSpy).not.toHaveBeenCalled();
1572
-
1573
- // After both sessions have been loaded, we will finally invoke the
1574
- // callback.
1575
- session2.on['keystatuseschange']({target: session2});
1576
- await shaka.test.Util.shortDelay();
1577
- expect(onKeyStatusSpy).toHaveBeenCalled();
1578
- });
1579
-
1580
- it('causes an EXPIRED error when all keys expire', async () => {
1581
- onErrorSpy.and.stub();
1582
-
1583
- await initAndAttach();
1584
- expect(onErrorSpy).not.toHaveBeenCalled();
1585
-
1586
- await sendEncryptedEvent();
1587
-
1588
- const keyId1 = makeKeyId(1);
1589
- const keyId2 = makeKeyId(2);
1590
-
1591
- // Expire one key.
1592
- session1.keyStatuses.forEach.and.callFake((callback) => {
1593
- callback(keyId1, 'usable');
1594
- callback(keyId2, 'expired');
1595
- });
1596
-
1597
- await new Promise((resolve) => {
1598
- onKeyStatusSpy.and.callFake(resolve);
1599
- session1.on['keystatuseschange']({target: session1});
1600
- });
1601
-
1602
- // One key is still usable.
1603
- expect(onErrorSpy).not.toHaveBeenCalled();
1604
-
1605
- // Expire both keys.
1606
- session1.keyStatuses.forEach.and.callFake((callback) => {
1607
- callback(keyId1, 'expired');
1608
- callback(keyId2, 'expired');
1609
- });
1610
-
1611
- await new Promise((resolve) => {
1612
- onKeyStatusSpy.and.callFake(resolve);
1613
- session1.on['keystatuseschange']({target: session1});
1614
- });
1615
-
1616
- // Both keys are expired, so we should have an error.
1617
- expect(onErrorSpy).toHaveBeenCalled();
1618
- // There should be exactly one error.
1619
- expect(onErrorSpy).toHaveBeenCalledTimes(1);
1620
- const error = onErrorSpy.calls.argsFor(0)[0];
1621
- shaka.test.Util.expectToEqualError(error, new shaka.util.Error(
1622
- shaka.util.Error.Severity.CRITICAL,
1623
- shaka.util.Error.Category.DRM,
1624
- shaka.util.Error.Code.EXPIRED));
1625
- });
1626
-
1627
- it('causes only one error when two keys expire at once', async () => {
1628
- onErrorSpy.and.stub();
1629
-
1630
- await initAndAttach();
1631
- expect(onErrorSpy).not.toHaveBeenCalled();
1632
-
1633
- await sendEncryptedEvent();
1634
-
1635
- const keyId1 = makeKeyId(1);
1636
- const keyId2 = makeKeyId(2);
1637
-
1638
- // Expire both keys at once.
1639
- session1.keyStatuses.forEach.and.callFake((callback) => {
1640
- callback(keyId1, 'expired');
1641
- callback(keyId2, 'expired');
1642
- });
1643
-
1644
- await new Promise((resolve) => {
1645
- onKeyStatusSpy.and.callFake(resolve);
1646
-
1647
- // Fire change events for both keys.
1648
- session1.on['keystatuseschange']({target: session1});
1649
- session1.on['keystatuseschange']({target: session1});
1650
- });
1651
-
1652
- // Both keys are expired, so we should have an error.
1653
- expect(onErrorSpy).toHaveBeenCalled();
1654
- // There should be exactly one error.
1655
- expect(onErrorSpy).toHaveBeenCalledTimes(1);
1656
- const error = onErrorSpy.calls.argsFor(0)[0];
1657
- shaka.test.Util.expectToEqualError(error, new shaka.util.Error(
1658
- shaka.util.Error.Severity.CRITICAL,
1659
- shaka.util.Error.Category.DRM,
1660
- shaka.util.Error.Code.EXPIRED));
1661
-
1662
- // Ignore the next key status event, sleep for one second, then
1663
- // check to see if another error fired.
1664
- onKeyStatusSpy.and.stub();
1665
- await shaka.test.Util.shortDelay();
1666
- // Still only one error.
1667
- expect(onErrorSpy).toHaveBeenCalledTimes(1);
1668
- });
1669
- }); // describe('keystatuseschange')
1670
- }); // describe('events')
1671
-
1672
- describe('update', () => {
1673
- it('receives a license', async () => {
1674
- const license = new Uint8Array(0);
1675
-
1676
- await initAndAttach();
1677
- await sendEncryptedEvent();
1678
-
1679
- fakeNetEngine.setResponseValue('http://abc.drm/license', license);
1680
- const message = new Uint8Array(0);
1681
- session1.on['message']({target: session1, message: message});
1682
- session1.update.and.returnValue(Promise.resolve());
1683
-
1684
- await shaka.test.Util.shortDelay();
1685
- expect(session1.update).toHaveBeenCalledWith(license);
1686
- });
1687
-
1688
- it('uses clearKeys config to override DrmInfo', async () => {
1689
- tweakDrmInfos((drmInfos) => {
1690
- drmInfos[0].keySystem = 'com.fake.NOT.clearkey';
1691
- });
1692
- setDecodingInfoSpy(['org.w3.clearkey']);
1693
-
1694
- // Configure clear keys (map of hex key IDs to keys)
1695
- config.clearKeys = {
1696
- 'deadbeefdeadbeefdeadbeefdeadbeef': '18675309186753091867530918675309',
1697
- '02030507011013017019023029031037': '03050701302303204201080425098033',
1698
- };
1699
- drmEngine.configure(config);
1700
-
1701
- // Not mocked. Run data through real data URI parser to ensure that it is
1702
- // correctly formatted.
1703
- fakeNetEngine.request.and.callFake((type, request, context) => {
1704
- const requestType = shaka.net.NetworkingEngine.RequestType.LICENSE;
1705
-
1706
- // A dummy progress callback.
1707
- const progressUpdated = (elapsedMs, bytes, bytesRemaining) => {};
1708
-
1709
- return shaka.net.DataUriPlugin.parse(
1710
- request.uris[0], request, requestType, progressUpdated);
1711
- });
1712
-
1713
- await initAndAttach();
1714
- const message = new Uint8Array(0);
1715
- session1.on['message']({target: session1, message: message});
1716
- session1.update.and.returnValue(Promise.resolve());
1717
-
1718
- await shaka.test.Util.shortDelay();
1719
- expect(session1.update).toHaveBeenCalledTimes(1);
1720
- const licenseBuffer = session1.update.calls.argsFor(0)[0];
1721
- const licenseJson =
1722
- shaka.util.StringUtils.fromBytesAutoDetect(licenseBuffer);
1723
- const license = JSON.parse(licenseJson);
1724
- expect(license).toEqual({
1725
- keys: [
1726
- {kid: '3q2-796tvu_erb7v3q2-7w',
1727
- k: 'GGdTCRhnUwkYZ1MJGGdTCQ', kty: 'oct'},
1728
- {kid: 'AgMFBwEQEwFwGQIwKQMQNw',
1729
- k: 'AwUHATAjAyBCAQgEJQmAMw', kty: 'oct'},
1730
- ],
1731
- });
1732
- });
1733
-
1734
- it('publishes an event if update succeeds', async () => {
1735
- await initAndAttach();
1736
- await sendEncryptedEvent();
1737
-
1738
- const message = new Uint8Array(0);
1739
- session1.on['message']({target: session1, message: message});
1740
- session1.update.and.returnValue(Promise.resolve());
1741
-
1742
- await shaka.test.Util.shortDelay();
1743
- expect(onEventSpy).toHaveBeenCalledWith(
1744
- jasmine.objectContaining({type: 'drmsessionupdate'}));
1745
- });
1746
-
1747
- it('dispatches an error if update fails', async () => {
1748
- onErrorSpy.and.stub();
1749
-
1750
- const license = new Uint8Array(0);
1751
-
1752
- await initAndAttach();
1753
- await sendEncryptedEvent();
1754
-
1755
- fakeNetEngine.setResponseValue('http://abc.drm/license', license);
1756
- const message = new Uint8Array(0);
1757
- session1.on['message']({target: session1, message: message});
1758
- session1.update.and.throwError('whoops!');
1759
-
1760
- await shaka.test.Util.shortDelay();
1761
- expect(onErrorSpy).toHaveBeenCalled();
1762
- const error = onErrorSpy.calls.argsFor(0)[0];
1763
- shaka.test.Util.expectToEqualError(error, new shaka.util.Error(
1764
- shaka.util.Error.Severity.CRITICAL,
1765
- shaka.util.Error.Category.DRM,
1766
- shaka.util.Error.Code.LICENSE_RESPONSE_REJECTED,
1767
- 'whoops!'));
1768
- });
1769
- }); // describe('update')
1770
-
1771
- describe('destroy', () => {
1772
- it('tears down MediaKeys and active sessions', async () => {
1773
- await initAndAttach();
1774
-
1775
- await sendEncryptedEvent('webm');
1776
- await sendEncryptedEvent('cenc', new Uint8Array(2));
1777
-
1778
- const message = new Uint8Array(0);
1779
- session1.on['message']({target: session1, message: message});
1780
- session1.update.and.returnValue(Promise.resolve());
1781
- session2.on['message']({target: session2, message: message});
1782
- session2.update.and.returnValue(Promise.resolve());
1783
-
1784
- await shaka.test.Util.shortDelay();
1785
- mockVideo.setMediaKeys.calls.reset();
1786
- await drmEngine.destroy();
1787
- expect(session1.close).toHaveBeenCalled();
1788
- expect(session1.remove).not.toHaveBeenCalled();
1789
- expect(session2.close).toHaveBeenCalled();
1790
- expect(session2.remove).not.toHaveBeenCalled();
1791
- expect(mockVideo.setMediaKeys).toHaveBeenCalledWith(null);
1792
- });
1793
-
1794
- it('tears down & removes active persistent sessions', async () => {
1795
- config.advanced['drm.abc'] = createAdvancedConfig(null);
1796
- config.advanced['drm.abc'].sessionType = 'persistent-license';
1797
-
1798
- drmEngine.configure(config);
1799
-
1800
- await initAndAttach();
1801
- await sendEncryptedEvent('webm');
1802
- await sendEncryptedEvent('cenc', new Uint8Array(2));
1803
-
1804
- const message = new Uint8Array(0);
1805
- session1.on['message']({target: session1, message: message});
1806
- session1.update.and.returnValue(Promise.resolve());
1807
- session2.on['message']({target: session2, message: message});
1808
- session2.update.and.returnValue(Promise.resolve());
1809
-
1810
- await shaka.test.Util.shortDelay();
1811
- mockVideo.setMediaKeys.calls.reset();
1812
- await drmEngine.destroy();
1813
-
1814
- expect(session1.close).not.toHaveBeenCalled();
1815
- expect(session1.remove).toHaveBeenCalled();
1816
-
1817
- expect(session2.close).not.toHaveBeenCalled();
1818
- expect(session2.remove).toHaveBeenCalled();
1819
- });
1820
-
1821
- it(
1822
- // eslint-disable-next-line max-len
1823
- 'tears down & does not remove active persistent sessions based on configuration flag',
1824
- async () => {
1825
- config.advanced['drm.abc'] = createAdvancedConfig(null);
1826
- config.advanced['drm.abc'].sessionType = 'persistent-license';
1827
- config.persistentSessionOnlinePlayback = true;
1828
-
1829
- drmEngine.configure(config);
1830
-
1831
- await initAndAttach();
1832
- await sendEncryptedEvent('cenc', new Uint8Array(2));
1833
-
1834
- const message = new Uint8Array(0);
1835
- session1.on['message']({target: session1, message: message});
1836
- session1.update.and.returnValue(Promise.resolve());
1837
-
1838
- await shaka.test.Util.shortDelay();
1839
- mockVideo.setMediaKeys.calls.reset();
1840
- await drmEngine.destroy();
1841
-
1842
- expect(session1.close).toHaveBeenCalled();
1843
- expect(session1.remove).not.toHaveBeenCalled();
1844
- });
1845
-
1846
- it('swallows errors when closing sessions', async () => {
1847
- await initAndAttach();
1848
- await sendEncryptedEvent('webm');
1849
- await sendEncryptedEvent('cenc', new Uint8Array(2));
1850
-
1851
- const message = new Uint8Array(0);
1852
- session1.on['message']({target: session1, message: message});
1853
- session1.update.and.returnValue(Promise.resolve());
1854
- session2.on['message']({target: session2, message: message});
1855
- session2.update.and.returnValue(Promise.resolve());
1856
-
1857
- await shaka.test.Util.shortDelay();
1858
- session1.close.and.returnValue(Promise.reject(new Error('')));
1859
- session2.close.and.returnValue(Promise.reject(new Error('')));
1860
- await drmEngine.destroy();
1861
- });
1862
-
1863
- it('swallows errors when clearing MediaKeys', async () => {
1864
- await initAndAttach();
1865
- await sendEncryptedEvent('webm');
1866
- await sendEncryptedEvent('cenc', new Uint8Array(2));
1867
-
1868
- const message = new Uint8Array(0);
1869
- session1.on['message']({target: session1, message: message});
1870
- session1.update.and.returnValue(Promise.resolve());
1871
- session2.on['message']({target: session2, message: message});
1872
- session2.update.and.returnValue(Promise.resolve());
1873
-
1874
- await shaka.test.Util.shortDelay();
1875
- mockVideo.setMediaKeys.and.returnValue(Promise.reject(new Error('')));
1876
- await drmEngine.destroy();
1877
- });
1878
-
1879
- it('interrupts failing MediaKeys queries', async () => {
1880
- // Hold the MediaKeys query.
1881
- /** @type {!shaka.util.PublicPromise} */
1882
- const p = new shaka.util.PublicPromise();
1883
- decodingInfoSpy.and.returnValue(p);
1884
-
1885
- const variants = manifest.variants;
1886
- const init = drmEngine.initForPlayback(
1887
- variants, manifest.offlineSessionIds);
1888
-
1889
- // This flow should still return "success" when DrmEngine is destroyed.
1890
- await shaka.test.Util.shortDelay();
1891
-
1892
- expect(variants[0].decodingInfos.length).toBe(0);
1893
- await drmEngine.destroy();
1894
- p.reject(new Error('')); // Fail drm.abc.
1895
- await expectAsync(init).toBeRejected();
1896
- expect(drmEngine.initialized()).toBe(false);
1897
- });
1898
-
1899
- it('interrupts successful MediaKeys queries', async () => {
1900
- // Hold the MediaKeys query:
1901
- /** @type {!shaka.util.PublicPromise} */
1902
- const p = new shaka.util.PublicPromise();
1903
- decodingInfoSpy.and.returnValue(p);
1904
-
1905
- const variants = manifest.variants;
1906
- const init = drmEngine.initForPlayback(
1907
- variants, manifest.offlineSessionIds);
1908
-
1909
- await shaka.test.Util.shortDelay();
1910
- expect(variants[0].decodingInfos.length).toBe(0);
1911
- await drmEngine.destroy();
1912
- p.resolve(); // Success for drm.abc.
1913
- await expectAsync(init).toBeRejected();
1914
- // Due to the interruption, we never created MediaKeys.
1915
- expect(shaka.media.DrmEngine.keySystem(drmEngine.getDrmInfo())).toBe('');
1916
- expect(drmEngine.initialized()).toBe(false);
1917
- });
1918
-
1919
- it('interrupts successful calls to createMediaKeys', async () => {
1920
- // Hold createMediaKeys:
1921
- /** @type {!shaka.util.PublicPromise} */
1922
- const p = new shaka.util.PublicPromise();
1923
- mockMediaKeySystemAccess.createMediaKeys.and.returnValue(p);
1924
-
1925
- const variants = manifest.variants;
1926
- const init = drmEngine.initForPlayback(
1927
- variants, manifest.offlineSessionIds);
1928
-
1929
- await shaka.test.Util.shortDelay();
1930
- // We are blocked on createMediaKeys:
1931
- expect(mockMediaKeySystemAccess.createMediaKeys).toHaveBeenCalled();
1932
- await drmEngine.destroy();
1933
- p.resolve(); // Success for createMediaKeys().
1934
- await expectAsync(init).toBeRejected();
1935
- // Due to the interruption, we never finished initialization.
1936
- expect(drmEngine.initialized()).toBe(false);
1937
- });
1938
-
1939
- it('interrupts failed calls to setMediaKeys', async () => {
1940
- // Hold setMediaKeys:
1941
- /** @type {!shaka.util.PublicPromise} */
1942
- const p1 = new shaka.util.PublicPromise();
1943
- mockVideo.setMediaKeys.and.returnValue(p1);
1944
-
1945
- onErrorSpy.and.stub();
1946
-
1947
- tweakDrmInfos((drmInfos) => {
1948
- drmInfos[0].initData = [
1949
- {initData: new Uint8Array(1), initDataType: 'cenc', keyId: null},
1950
- ];
1951
- });
1952
-
1953
- const init = expectAsync(initAndAttach()).toBeRejected();
1954
-
1955
- await shaka.test.Util.shortDelay();
1956
- // We are now blocked on setMediaKeys:
1957
- expect(mockVideo.setMediaKeys).toHaveBeenCalledTimes(1);
1958
- // DrmEngine.destroy also calls setMediaKeys.
1959
- /** @type {!shaka.util.PublicPromise} */
1960
- const p2 = new shaka.util.PublicPromise();
1961
- mockVideo.setMediaKeys.and.returnValue(p2);
1962
-
1963
- const destroy = drmEngine.destroy();
1964
- const fail = async () => {
1965
- await shaka.test.Util.shortDelay();
1966
- shaka.log.warning('fail');
1967
- p1.reject(new Error('titi'));
1968
- };
1969
- const success = async () => {
1970
- await shaka.test.Util.shortDelay();
1971
- shaka.log.warning('success');
1972
- p2.resolve();
1973
- };
1974
- await Promise.all([init, destroy, fail(), success()]);
1975
- });
1976
-
1977
- it('interrupts successful calls to setMediaKeys', async () => {
1978
- // Hold setMediaKeys:
1979
- /** @type {!shaka.util.PublicPromise} */
1980
- const p1 = new shaka.util.PublicPromise();
1981
- mockVideo.setMediaKeys.and.returnValue(p1);
1982
-
1983
- tweakDrmInfos((drmInfos) => {
1984
- drmInfos[0].initData = [
1985
- {initData: new Uint8Array(1), initDataType: 'cenc', keyId: null},
1986
- ];
1987
- });
1988
-
1989
- const init = expectAsync(initAndAttach()).toBeRejected();
1990
-
1991
- await shaka.test.Util.shortDelay();
1992
- // We are now blocked on setMediaKeys:
1993
- expect(mockVideo.setMediaKeys).toHaveBeenCalledTimes(1);
1994
- // DrmEngine.destroy also calls setMediaKeys.
1995
- /** @type {!shaka.util.PublicPromise} */
1996
- const p2 = new shaka.util.PublicPromise();
1997
- mockVideo.setMediaKeys.and.returnValue(p2);
1998
-
1999
- const destroy = drmEngine.destroy();
2000
- const resolve1 = async () => {
2001
- await shaka.test.Util.shortDelay();
2002
- p1.resolve();
2003
- };
2004
- const resolve2 = async () => {
2005
- await shaka.test.Util.shortDelay();
2006
- p2.resolve();
2007
- };
2008
- await Promise.all([init, destroy, resolve1(), resolve2()]);
2009
-
2010
- // Due to the interruption, we never listened for 'encrypted' events.
2011
- expect(mockVideo.on['encrypted']).toBe(undefined);
2012
- });
2013
-
2014
- it('interrupts failed calls to setServerCertificate', async () => {
2015
- const cert = new Uint8Array(1);
2016
- config.advanced['drm.abc'] = createAdvancedConfig(cert);
2017
- drmEngine.configure(config);
2018
-
2019
- // Hold setServerCertificate:
2020
- /** @type {!shaka.util.PublicPromise} */
2021
- const p = new shaka.util.PublicPromise();
2022
- mockMediaKeys.setServerCertificate.and.returnValue(p);
2023
-
2024
- const init = initAndAttach();
2025
-
2026
- await shaka.test.Util.shortDelay();
2027
- // We are now blocked on setServerCertificate:
2028
- expect(mockMediaKeys.setServerCertificate).toHaveBeenCalledTimes(1);
2029
- await drmEngine.destroy();
2030
-
2031
- p.reject(new Error('')); // Fail setServerCertificate.
2032
- await expectAsync(init).toBeRejected();
2033
- });
2034
-
2035
- it('interrupts successful calls to setServerCertificate', async () => {
2036
- const cert = new Uint8Array(1);
2037
- config.advanced['drm.abc'] = createAdvancedConfig(cert);
2038
- drmEngine.configure(config);
2039
-
2040
- // Hold setServerCertificate:
2041
- /** @type {!shaka.util.PublicPromise} */
2042
- const p = new shaka.util.PublicPromise();
2043
- mockMediaKeys.setServerCertificate.and.returnValue(p);
2044
-
2045
- // This chain should still return "success" when DrmEngine is destroyed.
2046
- const init = initAndAttach();
2047
-
2048
- await shaka.test.Util.shortDelay();
2049
- // We are now blocked on setServerCertificate:
2050
- expect(mockMediaKeys.setServerCertificate).toHaveBeenCalledTimes(1);
2051
- await drmEngine.destroy();
2052
-
2053
- p.resolve(); // Success for setServerCertificate.
2054
- await expectAsync(init).toBeRejected();
2055
-
2056
- // Due to the interruption, we never listened for 'encrypted' events.
2057
- expect(mockVideo.on['encrypted']).toBe(undefined);
2058
- });
2059
-
2060
- it('does not trigger errors if it fails generateRequest', async () => {
2061
- /** @type {!shaka.util.PublicPromise} */
2062
- const p = new shaka.util.PublicPromise();
2063
- session1.generateRequest.and.returnValue(p);
2064
-
2065
- await initAndAttach();
2066
- await sendEncryptedEvent();
2067
-
2068
- // We are now blocked on generateRequest:
2069
- expect(session1.generateRequest).toHaveBeenCalledTimes(1);
2070
-
2071
- await drmEngine.destroy();
2072
-
2073
- p.reject(new Error('Fail')); // Fail generateRequest.
2074
- await Util.shortDelay(); // Wait for any delayed errors.
2075
- // onError is a failure by default.
2076
- });
2077
-
2078
- it('interrupts successful license requests', async () => {
2079
- /** @type {!shaka.util.PublicPromise} */
2080
- const p = new shaka.util.PublicPromise();
2081
- const operation = shaka.util.AbortableOperation.notAbortable(p);
2082
- fakeNetEngine.request.and.returnValue(operation);
2083
-
2084
- await initAndAttach();
2085
- await sendEncryptedEvent();
2086
-
2087
- const message = new Uint8Array(0);
2088
- session1.on['message']({target: session1, message: message});
2089
- session1.update.and.returnValue(Promise.resolve());
2090
-
2091
- // We are now blocked on the license request:
2092
- expect(fakeNetEngine.request).toHaveBeenCalledTimes(1);
2093
- expect(fakeNetEngine.request).toHaveBeenCalledWith(
2094
- shaka.net.NetworkingEngine.RequestType.LICENSE,
2095
- jasmine.anything());
2096
-
2097
- await drmEngine.destroy();
2098
-
2099
- // Unblock the license request.
2100
- p.resolve({data: new Uint8Array(0)});
2101
- await Util.shortDelay(); // Ensure request is handled.
2102
-
2103
- // Due to the interruption, we never updated the session.
2104
- expect(session1.update).not.toHaveBeenCalled();
2105
- });
2106
-
2107
- it('interrupts failed license requests', async () => {
2108
- /** @type {!shaka.util.PublicPromise} */
2109
- const p = new shaka.util.PublicPromise();
2110
- const operation = shaka.util.AbortableOperation.notAbortable(p);
2111
- fakeNetEngine.request.and.returnValue(operation);
2112
-
2113
- await initAndAttach();
2114
- await sendEncryptedEvent();
2115
-
2116
- const message = new Uint8Array(0);
2117
- session1.on['message']({target: session1, message: message});
2118
- session1.update.and.returnValue(Promise.resolve());
2119
-
2120
- // We are now blocked on the license request:
2121
- expect(fakeNetEngine.request).toHaveBeenCalledTimes(1);
2122
- expect(fakeNetEngine.request).toHaveBeenCalledWith(
2123
- shaka.net.NetworkingEngine.RequestType.LICENSE,
2124
- jasmine.anything());
2125
-
2126
- await drmEngine.destroy();
2127
-
2128
- // Fail the license request.
2129
- p.reject(new shaka.util.Error(
2130
- shaka.util.Error.Severity.CRITICAL,
2131
- shaka.util.Error.Category.NETWORK,
2132
- shaka.util.Error.Code.HTTP_ERROR));
2133
- await Util.shortDelay();
2134
- });
2135
-
2136
- it('does not trigger errors if it fails update', async () => {
2137
- /** @type {!shaka.util.PublicPromise} */
2138
- const p = new shaka.util.PublicPromise();
2139
- session1.update.and.returnValue(p);
2140
-
2141
- await initAndAttach();
2142
- await sendEncryptedEvent();
2143
-
2144
- const message = new Uint8Array(0);
2145
- session1.on['message']({target: session1, message: message});
2146
-
2147
- await shaka.test.Util.shortDelay();
2148
-
2149
- // We are now blocked on update:
2150
- expect(session1.update).toHaveBeenCalledTimes(1);
2151
- await drmEngine.destroy();
2152
-
2153
- // Fail the update.
2154
- p.reject(new Error('Fail'));
2155
- await Util.shortDelay();
2156
- });
2157
-
2158
- it('still completes if session is not callable', async () => {
2159
- // Before, we would use |session.closed| as part of destroy(). However,
2160
- // this doesn't work if the session is not callable (no license request
2161
- // sent). So |session.closed| should never resolve and |session.close()|
2162
- // should be rejected and destroy() should still succeed.
2163
- // https://github.com/shaka-project/shaka-player/issues/664
2164
- await initAndAttach();
2165
- session1.closed = new shaka.util.PublicPromise();
2166
- session2.closed = new shaka.util.PublicPromise();
2167
-
2168
- // Since this won't be attached to anything until much later, we must
2169
- // silence unhandled rejection errors.
2170
- const rejected = Promise.reject(new Error(''));
2171
- rejected.catch(() => {});
2172
-
2173
- session1.close.and.returnValue(rejected);
2174
- session2.close.and.returnValue(rejected);
2175
-
2176
- await sendEncryptedEvent('webm');
2177
- await sendEncryptedEvent('cenc', new Uint8Array(2));
2178
-
2179
- // Still resolve these since we are mocking close and closed. This
2180
- // ensures DrmEngine is in the correct state.
2181
- const message = new Uint8Array(0);
2182
- session1.on['message']({target: session1, message: message});
2183
- session1.update.and.returnValue(Promise.resolve());
2184
- session2.on['message']({target: session2, message: message});
2185
- session2.update.and.returnValue(Promise.resolve());
2186
-
2187
- await shaka.test.Util.shortDelay();
2188
- await drmEngine.destroy();
2189
- });
2190
- }); // describe('destroy')
2191
-
2192
- describe('isPlayReadyKeySystem', () => {
2193
- it('should return true for MS & Chromecast PlayReady', () => {
2194
- expect(shaka.media.DrmEngine.isPlayReadyKeySystem(
2195
- 'com.microsoft.playready')).toBe(true);
2196
- expect(shaka.media.DrmEngine.isPlayReadyKeySystem(
2197
- 'com.microsoft.playready.anything')).toBe(true);
2198
- expect(shaka.media.DrmEngine.isPlayReadyKeySystem(
2199
- 'com.chromecast.playready')).toBe(true);
2200
- });
2201
-
2202
- it('should return false for non-PlayReady key systems', () => {
2203
- expect(shaka.media.DrmEngine.isPlayReadyKeySystem(
2204
- 'com.widevine.alpha')).toBe(false);
2205
- expect(shaka.media.DrmEngine.isPlayReadyKeySystem(
2206
- 'com.abc.playready')).toBe(false);
2207
- });
2208
- });
2209
-
2210
- describe('isFairPlayKeySystem', () => {
2211
- it('should return true for FairPlay', () => {
2212
- expect(shaka.media.DrmEngine.isFairPlayKeySystem(
2213
- 'com.apple.fps')).toBe(true);
2214
- expect(shaka.media.DrmEngine.isFairPlayKeySystem(
2215
- 'com.apple.fps.1_0')).toBe(true);
2216
- expect(shaka.media.DrmEngine.isFairPlayKeySystem(
2217
- 'com.apple.fps.2_0')).toBe(true);
2218
- expect(shaka.media.DrmEngine.isFairPlayKeySystem(
2219
- 'com.apple.fps.3_0')).toBe(true);
2220
- });
2221
-
2222
- it('should return false for non-FairPlay key systems', () => {
2223
- expect(shaka.media.DrmEngine.isFairPlayKeySystem(
2224
- 'com.widevine.alpha')).toBe(false);
2225
- expect(shaka.media.DrmEngine.isFairPlayKeySystem(
2226
- 'com.abc.playready')).toBe(false);
2227
- });
2228
- });
2229
-
2230
- describe('getDrmInfo', () => {
2231
- it('includes correct info', async () => {
2232
- // Leave only one drmInfo
2233
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
2234
- manifest.addVariant(0, (variant) => {
2235
- variant.addVideo(1, (stream) => {
2236
- stream.encrypted = true;
2237
- stream.addDrmInfo('drm.abc');
2238
- });
2239
- variant.addAudio(2, (stream) => {
2240
- stream.encrypted = true;
2241
- stream.addDrmInfo('drm.abc');
2242
- });
2243
- });
2244
- });
2245
- setDecodingInfoSpy(['drm.abc']);
2246
-
2247
- // Key IDs in manifest
2248
- tweakDrmInfos((drmInfos) => {
2249
- drmInfos[0].keyIds = new Set(['deadbeefdeadbeefdeadbeefdeadbeef']);
2250
- });
2251
-
2252
- config.advanced['drm.abc'] = {
2253
- audioRobustness: 'good',
2254
- videoRobustness: 'really_really_ridiculously_good',
2255
- distinctiveIdentifierRequired: true,
2256
- serverCertificate: null,
2257
- serverCertificateUri: '',
2258
- sessionType: '',
2259
- individualizationServer: '',
2260
- persistentStateRequired: true,
2261
- };
2262
- drmEngine.configure(config);
2263
-
2264
- const variants = manifest.variants;
2265
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
2266
- expect(drmEngine.initialized()).toBe(true);
2267
- const drmInfo = drmEngine.getDrmInfo();
2268
- expect(drmInfo).toEqual({
2269
- keySystem: 'drm.abc',
2270
- licenseServerUri: 'http://abc.drm/license',
2271
- distinctiveIdentifierRequired: true,
2272
- persistentStateRequired: true,
2273
- audioRobustness: 'good',
2274
- videoRobustness: 'really_really_ridiculously_good',
2275
- serverCertificate: undefined,
2276
- serverCertificateUri: '',
2277
- sessionType: 'temporary',
2278
- initData: [],
2279
- keyIds: new Set(['deadbeefdeadbeefdeadbeefdeadbeef']),
2280
- });
2281
- });
2282
- }); // describe('getDrmInfo')
2283
-
2284
- describe('getCommonDrmInfos', () => {
2285
- it('returns one array if the other is empty', () => {
2286
- const drmInfo = {
2287
- keySystem: 'drm.abc',
2288
- licenseServerUri: 'http://abc.drm/license',
2289
- distinctiveIdentifierRequired: true,
2290
- persistentStateRequired: true,
2291
- audioRobustness: 'good',
2292
- videoRobustness: 'really_really_ridiculously_good',
2293
- serverCertificate: undefined,
2294
- serverCertificateUri: '',
2295
- initData: [],
2296
- keyIds: new Set(['deadbeefdeadbeefdeadbeefdeadbeef']),
2297
- };
2298
- const returnedOne =
2299
- shaka.media.DrmEngine.getCommonDrmInfos([drmInfo], []);
2300
- const returnedTwo =
2301
- shaka.media.DrmEngine.getCommonDrmInfos([], [drmInfo]);
2302
- expect(returnedOne).toEqual([drmInfo]);
2303
- expect(returnedTwo).toEqual([drmInfo]);
2304
- });
2305
-
2306
- it('merges drmInfos if two exist', () => {
2307
- const serverCert = new Uint8Array(0);
2308
- const drmInfoVideo = {
2309
- keySystem: 'drm.abc',
2310
- licenseServerUri: 'http://abc.drm/license',
2311
- distinctiveIdentifierRequired: false,
2312
- persistentStateRequired: true,
2313
- videoRobustness: 'really_really_ridiculously_good',
2314
- serverCertificate: serverCert,
2315
- serverCertificateUri: '',
2316
- initData: [{keyId: 'a'}],
2317
- keyIds: new Set(['deadbeefdeadbeefdeadbeefdeadbeef']),
2318
- };
2319
- const drmInfoAudio = {
2320
- keySystem: 'drm.abc',
2321
- licenseServerUri: undefined,
2322
- distinctiveIdentifierRequired: true,
2323
- persistentStateRequired: false,
2324
- audioRobustness: 'good',
2325
- serverCertificate: undefined,
2326
- serverCertificateUri: '',
2327
- initData: [{keyId: 'b'}],
2328
- keyIds: new Set(['eadbeefdeadbeefdeadbeefdeadbeefd']),
2329
- };
2330
- const drmInfoDesired = {
2331
- keySystem: 'drm.abc',
2332
- licenseServerUri: 'http://abc.drm/license',
2333
- distinctiveIdentifierRequired: true,
2334
- persistentStateRequired: true,
2335
- audioRobustness: 'good',
2336
- videoRobustness: 'really_really_ridiculously_good',
2337
- serverCertificate: serverCert,
2338
- serverCertificateUri: '',
2339
- initData: [{keyId: 'a'}, {keyId: 'b'}],
2340
- keyIds: new Set([
2341
- 'deadbeefdeadbeefdeadbeefdeadbeef',
2342
- 'eadbeefdeadbeefdeadbeefdeadbeefd',
2343
- ]),
2344
- };
2345
- const returned = shaka.media.DrmEngine.getCommonDrmInfos([drmInfoVideo],
2346
- [drmInfoAudio]);
2347
- expect(returned).toEqual([drmInfoDesired]);
2348
- });
2349
-
2350
- it('dedupes the merged init data based on keyId matching', () => {
2351
- const serverCert = new Uint8Array(0);
2352
- const drmInfoVideo = {
2353
- keySystem: 'drm.abc',
2354
- licenseServerUri: 'http://abc.drm/license',
2355
- distinctiveIdentifierRequired: false,
2356
- persistentStateRequired: true,
2357
- videoRobustness: 'really_really_ridiculously_good',
2358
- serverCertificate: serverCert,
2359
- serverCertificateUri: '',
2360
- initData: [{keyId: 'v-init'}],
2361
- keyIds: new Set(['deadbeefdeadbeefdeadbeefdeadbeef']),
2362
- };
2363
- const drmInfoAudio = {
2364
- keySystem: 'drm.abc',
2365
- licenseServerUri: undefined,
2366
- distinctiveIdentifierRequired: true,
2367
- persistentStateRequired: false,
2368
- audioRobustness: 'good',
2369
- serverCertificate: undefined,
2370
- serverCertificateUri: '',
2371
- initData: [{keyId: 'v-init'}, {keyId: 'a-init'}],
2372
- keyIds: new Set(['eadbeefdeadbeefdeadbeefdeadbeefd']),
2373
- };
2374
- const drmInfoDesired = {
2375
- keySystem: 'drm.abc',
2376
- licenseServerUri: 'http://abc.drm/license',
2377
- distinctiveIdentifierRequired: true,
2378
- persistentStateRequired: true,
2379
- audioRobustness: 'good',
2380
- videoRobustness: 'really_really_ridiculously_good',
2381
- serverCertificate: serverCert,
2382
- serverCertificateUri: '',
2383
- initData: [{keyId: 'v-init'}, {keyId: 'a-init'}],
2384
- keyIds: new Set([
2385
- 'deadbeefdeadbeefdeadbeefdeadbeef',
2386
- 'eadbeefdeadbeefdeadbeefdeadbeefd',
2387
- ]),
2388
- };
2389
- const returned = shaka.media.DrmEngine.getCommonDrmInfos([drmInfoVideo],
2390
- [drmInfoAudio]);
2391
- expect(returned).toEqual([drmInfoDesired]);
2392
- });
2393
-
2394
- it('does not match incompatible drmInfos', () => {
2395
- // Different key systems do not match.
2396
- const drmInfo1 = {
2397
- keySystem: 'drm.abc',
2398
- licenseServerUri: undefined,
2399
- distinctiveIdentifierRequired: false,
2400
- persistentStateRequired: false,
2401
- serverCertificate: undefined,
2402
- serverCertificateUri: '',
2403
- initData: [],
2404
- keyIds: new Set(),
2405
- };
2406
- const drmInfo2 = {
2407
- keySystem: 'drm.foobar',
2408
- licenseServerUri: undefined,
2409
- distinctiveIdentifierRequired: false,
2410
- persistentStateRequired: false,
2411
- serverCertificate: undefined,
2412
- serverCertificateUri: '',
2413
- initData: [],
2414
- keyIds: new Set(),
2415
- };
2416
- const returned1 = shaka.media.DrmEngine.getCommonDrmInfos(
2417
- [drmInfo1], [drmInfo2]);
2418
- expect(returned1).toEqual([]);
2419
- });
2420
- }); // describe('getCommonDrmInfos')
2421
-
2422
- describe('configure', () => {
2423
- it('delays initial license requests if configured to', async () => {
2424
- config.delayLicenseRequestUntilPlayed = true;
2425
- drmEngine.configure(config);
2426
- mockVideo.paused = true;
2427
-
2428
- await initAndAttach();
2429
- await sendEncryptedEvent();
2430
-
2431
- const operation = shaka.util.AbortableOperation.completed({});
2432
- fakeNetEngine.request.and.returnValue(operation);
2433
- const message = new Uint8Array(0);
2434
- session1.on['message']({target: session1, message: message});
2435
-
2436
- expect(fakeNetEngine.request).not.toHaveBeenCalled();
2437
-
2438
- mockVideo.on['play']();
2439
-
2440
- expect(fakeNetEngine.request).toHaveBeenCalledWith(
2441
- shaka.net.NetworkingEngine.RequestType.LICENSE,
2442
- jasmine.objectContaining({
2443
- uris: ['http://abc.drm/license'],
2444
- method: 'POST',
2445
- body: message,
2446
- }));
2447
- });
2448
-
2449
- it('does not delay license renewal requests', async () => {
2450
- config.delayLicenseRequestUntilPlayed = true;
2451
- drmEngine.configure(config);
2452
- mockVideo.paused = true;
2453
-
2454
- await initAndAttach();
2455
- await sendEncryptedEvent();
2456
-
2457
- const operation = shaka.util.AbortableOperation.completed({});
2458
- fakeNetEngine.request.and.returnValue(operation);
2459
- const message = new Uint8Array(0);
2460
- session1.on['message']({target: session1, message: message});
2461
-
2462
- expect(fakeNetEngine.request).not.toHaveBeenCalled();
2463
-
2464
- mockVideo.on['play']();
2465
-
2466
- expect(fakeNetEngine.request).toHaveBeenCalledWith(
2467
- shaka.net.NetworkingEngine.RequestType.LICENSE,
2468
- jasmine.objectContaining({
2469
- uris: ['http://abc.drm/license'],
2470
- method: 'POST',
2471
- body: message,
2472
- }));
2473
-
2474
- fakeNetEngine.request.calls.reset();
2475
-
2476
- mockVideo.paused = true;
2477
- session1.on['message']({target: session1, message: message});
2478
-
2479
- expect(fakeNetEngine.request).toHaveBeenCalledWith(
2480
- shaka.net.NetworkingEngine.RequestType.LICENSE,
2481
- jasmine.objectContaining({
2482
- uris: ['http://abc.drm/license'],
2483
- method: 'POST',
2484
- body: message,
2485
- }));
2486
- expect(fakeNetEngine.request).toHaveBeenCalledTimes(1);
2487
- });
2488
- }); // describe('configure')
2489
-
2490
- describe('removeSession', () => {
2491
- /** @type {!shaka.util.PublicPromise} */
2492
- let updatePromise;
2493
-
2494
- beforeEach(async () => {
2495
- session1.load.and.returnValue(Promise.resolve(true));
2496
-
2497
- // When remove() is called, it should resolve quickly and raise a
2498
- // 'message' event of type 'license-release'. The removeSessions method
2499
- // should wait until update() is complete with the response.
2500
- updatePromise = new shaka.util.PublicPromise();
2501
- session1.remove.and.callFake(() => {
2502
- // Raise the event synchronously, even though it doesn't normally.
2503
- session1.on['message']({target: session1, message: new ArrayBuffer(0)});
2504
- session1.update.and.returnValue(updatePromise);
2505
- return Promise.resolve();
2506
- });
2507
-
2508
- const variants = manifest.variants;
2509
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
2510
- });
2511
-
2512
- it('waits until update() is complete', async () => {
2513
- const update = async () => {
2514
- await shaka.test.Util.shortDelay();
2515
- updatePromise.resolve();
2516
- };
2517
-
2518
- await Promise.all([drmEngine.removeSession('abc'), update()]);
2519
- expect(session1.update).toHaveBeenCalled();
2520
- });
2521
-
2522
- it('is rejected when network request fails', async () => {
2523
- const p = fakeNetEngine.delayNextRequest();
2524
- const networkError = new shaka.util.Error(
2525
- shaka.util.Error.Severity.CRITICAL,
2526
- shaka.util.Error.Category.NETWORK,
2527
- shaka.util.Error.Code.BAD_HTTP_STATUS);
2528
- p.reject(networkError);
2529
- onErrorSpy.and.stub();
2530
-
2531
- const expected = Util.jasmineError(new shaka.util.Error(
2532
- shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.DRM,
2533
- shaka.util.Error.Code.LICENSE_REQUEST_FAILED, networkError));
2534
- await expectAsync(drmEngine.removeSession('abc'))
2535
- .toBeRejectedWith(expected);
2536
- expect(session1.update).not.toHaveBeenCalled();
2537
- });
2538
-
2539
- it('is rejected when update() is rejected', async () => {
2540
- updatePromise.reject(new Error('Error'));
2541
- onErrorSpy.and.stub();
2542
-
2543
- const expected = Util.jasmineError(new shaka.util.Error(
2544
- shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.DRM,
2545
- shaka.util.Error.Code.LICENSE_RESPONSE_REJECTED, 'Error'));
2546
- await expectAsync(drmEngine.removeSession('abc'))
2547
- .toBeRejectedWith(expected);
2548
- });
2549
-
2550
- // Regression test for #3534
2551
- it('does not remove the same session again on destroy', async () => {
2552
- updatePromise.resolve();
2553
- expect(session1.remove).not.toHaveBeenCalled();
2554
- await drmEngine.removeSession('abc');
2555
- expect(session1.remove).toHaveBeenCalled();
2556
- session1.remove.calls.reset();
2557
- await drmEngine.destroy();
2558
- // The session should only be removed ONCE. If it's double-removed, it
2559
- // will make a (non-fatal) DOMException.
2560
- expect(session1.remove).not.toHaveBeenCalled();
2561
- });
2562
- });
2563
-
2564
- describe('expiration', () => {
2565
- beforeEach(async () => {
2566
- session1.sessionId = 'abc';
2567
- session1.expiration = NaN;
2568
-
2569
- await initAndAttach();
2570
- await sendEncryptedEvent();
2571
-
2572
- const message = new Uint8Array(0);
2573
- session1.on['message']({target: session1, message: message});
2574
- session1.update.and.returnValue(Promise.resolve());
2575
- });
2576
-
2577
- it('calls the callback when the expiration changes', () => {
2578
- onExpirationSpy.calls.reset();
2579
-
2580
- session1.expiration = 10000;
2581
- checkExpiration();
2582
- expect(onExpirationSpy).toHaveBeenCalledTimes(1);
2583
- expect(onExpirationSpy).toHaveBeenCalledWith(session1.sessionId, 10000);
2584
- onExpirationSpy.calls.reset();
2585
-
2586
- session1.expiration = 50;
2587
- checkExpiration();
2588
- expect(onExpirationSpy).toHaveBeenCalledTimes(1);
2589
- expect(onExpirationSpy).toHaveBeenCalledWith(session1.sessionId, 50);
2590
- onExpirationSpy.calls.reset();
2591
-
2592
- session1.expiration = NaN;
2593
- checkExpiration();
2594
- expect(onExpirationSpy).toHaveBeenCalledTimes(1);
2595
- expect(onExpirationSpy)
2596
- .toHaveBeenCalledWith(session1.sessionId, Infinity);
2597
- });
2598
-
2599
- it('gets the current expiration times', () => {
2600
- session1.expiration = NaN;
2601
- expect(drmEngine.getExpiration()).toBe(Infinity);
2602
- session1.expiration = 12345;
2603
- expect(drmEngine.getExpiration()).toBe(12345);
2604
- });
2605
-
2606
- /** @suppress {accessControls} */
2607
- function checkExpiration() {
2608
- drmEngine.expirationTimer_.tickNow();
2609
- }
2610
- });
2611
-
2612
- describe('parseInbandPssh', () => {
2613
- const WIDEVINE_PSSH =
2614
- '00000028' + // atom size
2615
- '70737368' + // atom type='pssh'
2616
- '00000000' + // v0, flags=0
2617
- 'edef8ba979d64acea3c827dcd51d21ed' + // system id (Widevine)
2618
- '00000008' + // data size
2619
- '0102030405060708'; // data
2620
-
2621
- const PLAYREADY_PSSH =
2622
- '00000028' + // atom size
2623
- '70737368' + // atom type 'pssh'
2624
- '00000000' + // v0, flags=0
2625
- '9a04f07998404286ab92e65be0885f95' + // system id (PlayReady)
2626
- '00000008' + // data size
2627
- '0102030405060708'; // data
2628
-
2629
- const SEGMENT =
2630
- '00000058' + // atom size = 28x + 28x + 8x
2631
- '6d6f6f66' + // atom type 'moof'
2632
- WIDEVINE_PSSH +
2633
- PLAYREADY_PSSH;
2634
-
2635
- const binarySegment = shaka.util.Uint8ArrayUtils.fromHex(SEGMENT);
2636
-
2637
- it('calls newInitData when enabled', async () => {
2638
- config.parseInbandPsshEnabled = true;
2639
- await initAndAttach();
2640
-
2641
- /** @type {!jasmine.Spy} */
2642
- const newInitDataSpy = jasmine.createSpy('newInitData');
2643
- drmEngine.newInitData = shaka.test.Util.spyFunc(newInitDataSpy);
2644
-
2645
- await drmEngine.parseInbandPssh(
2646
- shaka.util.ManifestParserUtils.ContentType.VIDEO, binarySegment);
2647
- const expectedInitData = shaka.util.Uint8ArrayUtils.fromHex(
2648
- WIDEVINE_PSSH + PLAYREADY_PSSH);
2649
- expect(newInitDataSpy).toHaveBeenCalledWith('cenc', expectedInitData);
2650
- });
2651
-
2652
- it('does not call newInitData when disabled', async () => {
2653
- config.parseInbandPsshEnabled = false;
2654
- await initAndAttach();
2655
-
2656
- /** @type {!jasmine.Spy} */
2657
- const newInitDataSpy = jasmine.createSpy('newInitData');
2658
- drmEngine.newInitData = shaka.test.Util.spyFunc(newInitDataSpy);
2659
- await drmEngine.parseInbandPssh(
2660
- shaka.util.ManifestParserUtils.ContentType.VIDEO, binarySegment);
2661
- expect(newInitDataSpy).not.toHaveBeenCalled();
2662
- });
2663
- });
2664
-
2665
- async function initAndAttach() {
2666
- const variants = manifest.variants;
2667
- await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
2668
- await drmEngine.attach(mockVideo);
2669
- }
2670
-
2671
- function setDecodingInfoSpy(acceptableKeySystems) {
2672
- decodingInfoSpy.and.callFake((config) => {
2673
- const keySystem = config && config.keySystemConfiguration ?
2674
- config.keySystemConfiguration.keySystem : null;
2675
- let res;
2676
- if (!config.keySystemConfiguration) {
2677
- // Unencrypted content, return supported decodingInfo.
2678
- res = {supported: true};
2679
- } else if (!acceptableKeySystems.includes(keySystem)) {
2680
- res = {supported: false};
2681
- } else if (acceptableKeySystems.length <= 1) {
2682
- // Use the mockMediaKeySystemAccess if there's only one key system.
2683
- mockMediaKeySystemAccess.keySystem = keySystem;
2684
- res = {
2685
- supported: true,
2686
- keySystemAccess: mockMediaKeySystemAccess,
2687
- };
2688
- } else {
2689
- // Create new mediaKeySystemAccess objects for multiple key systems.
2690
- const mediaKeySystemAccess = createMockMediaKeySystemAccess();
2691
- mediaKeySystemAccess.keySystem = keySystem;
2692
- res = {
2693
- supported: true,
2694
- keySystemAccess: mediaKeySystemAccess,
2695
- };
2696
- }
2697
- return Promise.resolve(res);
2698
- });
2699
- }
2700
-
2701
- function createMockMediaKeySystemAccess() {
2702
- const mksa = {
2703
- keySystem: '',
2704
- getConfiguration: jasmine.createSpy('getConfiguration'),
2705
- createMediaKeys: jasmine.createSpy('createMediaKeys'),
2706
- };
2707
- mksa.getConfiguration.and.callFake(() => {
2708
- return {
2709
- audioCapabilities: [{contentType: 'audio/webm'}],
2710
- videoCapabilities: [{contentType: 'video/mp4; codecs="fake"'}],
2711
- };
2712
- });
2713
- mksa.createMediaKeys.and.callFake(() => {
2714
- return Promise.resolve(mockMediaKeys);
2715
- });
2716
- return mksa;
2717
- }
2718
-
2719
- function createMockMediaKeys() {
2720
- return {
2721
- createSession: jasmine.createSpy('createSession'),
2722
- setServerCertificate: jasmine.createSpy('setServerCertificate'),
2723
- };
2724
- }
2725
-
2726
- function createMockSession() {
2727
- const session = {
2728
- expiration: NaN,
2729
- closed: Promise.resolve(),
2730
- keyStatuses: {
2731
- forEach: jasmine.createSpy('forEach'),
2732
- },
2733
- generateRequest: jasmine.createSpy('generateRequest'),
2734
- load: jasmine.createSpy('load'),
2735
- update: jasmine.createSpy('update'),
2736
- close: jasmine.createSpy('close'),
2737
- remove: jasmine.createSpy('remove'),
2738
- addEventListener: jasmine.createSpy('addEventListener'),
2739
- removeEventListener: jasmine.createSpy('removeEventListener'),
2740
- dispatchEvent: jasmine.createSpy('dispatchEvent'),
2741
- on: {}, // event listeners
2742
- };
2743
- session.generateRequest.and.returnValue(Promise.resolve());
2744
- session.close.and.returnValue(Promise.resolve());
2745
- session.update.and.returnValue(Promise.resolve());
2746
- session.addEventListener.and.callFake((name, callback) => {
2747
- session.on[name] = callback;
2748
- });
2749
- return session;
2750
- }
2751
-
2752
- /**
2753
- * @param {Uint8Array} serverCert
2754
- * @return {shaka.extern.AdvancedDrmConfiguration}
2755
- */
2756
- function createAdvancedConfig(serverCert) {
2757
- return {
2758
- audioRobustness: '',
2759
- distinctiveIdentifierRequired: false,
2760
- persistentStateRequired: false,
2761
- serverCertificate: serverCert,
2762
- serverCertificateUri: '',
2763
- individualizationServer: '',
2764
- sessionType: '',
2765
- videoRobustness: '',
2766
- };
2767
- }
2768
-
2769
- /**
2770
- * @param {number} id
2771
- * @return {!ArrayBuffer}
2772
- */
2773
- function makeKeyId(id) {
2774
- return shaka.util.BufferUtils.toArrayBuffer(new Uint8Array([id]));
2775
- }
2776
-
2777
- /**
2778
- * @param {function(!Array.<shaka.extern.DrmInfo>)} callback
2779
- */
2780
- function tweakDrmInfos(callback) {
2781
- if (manifest.variants[0].video.encrypted) {
2782
- callback(manifest.variants[0].video.drmInfos);
2783
- }
2784
- if (manifest.variants[0].audio.encrypted) {
2785
- callback(manifest.variants[0].audio.drmInfos);
2786
- }
2787
- }
2788
-
2789
- /**
2790
- *
2791
- * @param {string} initDataType
2792
- * @param {Uint8Array} initData
2793
- * @param {string|null} keyId
2794
- */
2795
- async function sendEncryptedEvent(
2796
- initDataType = 'cenc', initData = new Uint8Array(1), keyId = null) {
2797
- // For some platforms, such as Xbox, where parseInbandPssh defaults to
2798
- // true, this listener may never be set.
2799
- if (mockVideo.on['encrypted']) {
2800
- mockVideo.on['encrypted']({initDataType, initData, keyId});
2801
- }
2802
-
2803
- await Util.shortDelay();
2804
- }
2805
- });