shaka-player 4.3.9 → 4.4.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 (321) hide show
  1. package/.github/workflows/build-and-test.yaml +11 -18
  2. package/.github/workflows/compute-incremental-coverage.py +3 -0
  3. package/.github/workflows/release-please.yaml +7 -0
  4. package/.github/workflows/selenium-lab-tests.yaml +45 -10
  5. package/AUTHORS +9 -0
  6. package/CHANGELOG.md +295 -190
  7. package/CONTRIBUTORS +8 -0
  8. package/LICENSE +32 -0
  9. package/README.md +63 -10
  10. package/demo/autoTemplate.txt +40 -5
  11. package/demo/close_button.js +11 -0
  12. package/demo/common/asset.js +13 -1
  13. package/demo/common/assets.js +112 -28
  14. package/demo/common/message_ids.js +25 -1
  15. package/demo/config.js +69 -10
  16. package/demo/customWarning.txt +2 -2
  17. package/demo/index.html +3 -1
  18. package/demo/locales/en.json +26 -2
  19. package/demo/locales/source.json +105 -9
  20. package/demo/main.js +57 -9
  21. package/demo/search.js +3 -1
  22. package/demo/service_worker.js +3 -0
  23. package/dist/controls.css +1 -1
  24. package/dist/controls.css.map +1 -1
  25. package/dist/demo.compiled.debug.js +132 -118
  26. package/dist/demo.compiled.debug.map +3 -3
  27. package/dist/demo.compiled.js +132 -118
  28. package/dist/demo.compiled.map +3 -3
  29. package/dist/deps.js +46 -28
  30. package/dist/locales.js +31 -31
  31. package/dist/receiver.compiled.debug.js +60 -52
  32. package/dist/receiver.compiled.debug.map +3 -3
  33. package/dist/receiver.compiled.js +60 -52
  34. package/dist/receiver.compiled.map +3 -3
  35. package/dist/shaka-player.compiled.d.ts +676 -391
  36. package/dist/shaka-player.compiled.debug.d.ts +676 -391
  37. package/dist/shaka-player.compiled.debug.externs.js +1188 -616
  38. package/dist/shaka-player.compiled.debug.js +1046 -700
  39. package/dist/shaka-player.compiled.debug.map +4 -4
  40. package/dist/shaka-player.compiled.externs.js +1188 -616
  41. package/dist/shaka-player.compiled.js +1094 -933
  42. package/dist/shaka-player.compiled.map +4 -4
  43. package/dist/shaka-player.ui.d.ts +677 -392
  44. package/dist/shaka-player.ui.debug.d.ts +677 -392
  45. package/dist/shaka-player.ui.debug.externs.js +1023 -451
  46. package/dist/shaka-player.ui.debug.js +1101 -738
  47. package/dist/shaka-player.ui.debug.map +4 -4
  48. package/dist/shaka-player.ui.externs.js +1023 -451
  49. package/dist/shaka-player.ui.js +1244 -1071
  50. package/dist/shaka-player.ui.map +4 -4
  51. package/docs/tutorials/ad_monetization.md +15 -1
  52. package/docs/tutorials/application-level-redirects.md +1 -1
  53. package/docs/tutorials/config.md +9 -5
  54. package/docs/tutorials/drm-config.md +61 -0
  55. package/docs/tutorials/fairplay.md +19 -4
  56. package/docs/tutorials/license-server-auth.md +4 -4
  57. package/docs/tutorials/license-wrapping.md +2 -2
  58. package/docs/tutorials/ui-customization.md +7 -3
  59. package/docs/tutorials/ui.md +7 -7
  60. package/docs/tutorials/upgrade.md +3 -0
  61. package/externs/ima.js +123 -2
  62. package/externs/isoboxer.js +217 -0
  63. package/externs/mediakeys.js +18 -0
  64. package/externs/mux.js +1 -105
  65. package/externs/pictureinpicture.js +48 -0
  66. package/externs/shaka/ads.js +61 -1
  67. package/externs/shaka/cea.js +110 -0
  68. package/externs/shaka/codecs.js +32 -0
  69. package/externs/shaka/manifest.js +101 -1
  70. package/externs/shaka/manifest_parser.js +0 -10
  71. package/externs/shaka/net.js +36 -7
  72. package/externs/shaka/offline.js +8 -1
  73. package/externs/shaka/player.js +220 -21
  74. package/externs/shaka/text.js +1 -382
  75. package/externs/shaka/transmuxer.js +59 -0
  76. package/karma.conf.js +15 -0
  77. package/lib/abr/simple_abr_manager.js +6 -3
  78. package/lib/ads/ad_manager.js +60 -2
  79. package/lib/ads/client_side_ad.js +86 -0
  80. package/lib/ads/client_side_ad_manager.js +93 -5
  81. package/lib/ads/server_side_ad.js +86 -0
  82. package/lib/ads/server_side_ad_manager.js +13 -0
  83. package/lib/cast/cast_utils.js +1 -0
  84. package/lib/cea/cea608_data_channel.js +24 -14
  85. package/lib/cea/cea608_memory.js +5 -2
  86. package/lib/cea/cea708_service.js +8 -9
  87. package/lib/cea/cea708_window.js +1 -2
  88. package/lib/cea/cea_decoder.js +23 -6
  89. package/lib/cea/cea_utils.js +25 -2
  90. package/lib/cea/dummy_caption_decoder.js +21 -0
  91. package/lib/cea/dummy_cea_parser.js +1 -3
  92. package/lib/cea/mp4_cea_parser.js +15 -10
  93. package/lib/cea/ts_cea_parser.js +69 -0
  94. package/lib/dash/content_protection.js +32 -2
  95. package/lib/dash/dash_parser.js +93 -31
  96. package/lib/dash/mpd_utils.js +6 -25
  97. package/lib/dash/segment_base.js +12 -14
  98. package/lib/dash/segment_list.js +10 -6
  99. package/lib/dash/segment_template.js +349 -32
  100. package/lib/dependencies/all.js +8 -0
  101. package/lib/hls/hls_classes.js +33 -8
  102. package/lib/hls/hls_parser.js +805 -191
  103. package/lib/hls/manifest_text_parser.js +4 -14
  104. package/lib/media/adaptation_set_criteria.js +43 -3
  105. package/lib/media/closed_caption_parser.js +74 -12
  106. package/lib/media/drm_engine.js +189 -49
  107. package/lib/media/gap_jumping_controller.js +1 -1
  108. package/lib/media/manifest_parser.js +34 -0
  109. package/lib/media/media_source_capabilities.js +10 -0
  110. package/lib/media/media_source_engine.js +475 -231
  111. package/lib/media/playhead.js +1 -1
  112. package/lib/media/presentation_timeline.js +62 -0
  113. package/lib/media/segment_index.js +50 -14
  114. package/lib/media/segment_prefetch.js +277 -0
  115. package/lib/media/segment_reference.js +70 -4
  116. package/lib/media/streaming_engine.js +258 -81
  117. package/lib/media/video_wrapper.js +15 -7
  118. package/lib/mss/content_protection.js +353 -0
  119. package/lib/mss/mss_parser.js +1081 -0
  120. package/lib/net/networking_engine.js +60 -10
  121. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  122. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  123. package/lib/offline/manifest_converter.js +6 -0
  124. package/lib/offline/storage.js +2 -4
  125. package/lib/player.js +309 -105
  126. package/lib/polyfill/media_capabilities.js +43 -3
  127. package/lib/polyfill/patchedmediakeys_apple.js +5 -0
  128. package/lib/polyfill/patchedmediakeys_nop.js +5 -0
  129. package/lib/polyfill/patchedmediakeys_webkit.js +5 -0
  130. package/lib/text/cue.js +208 -130
  131. package/lib/text/lrc_text_parser.js +2 -2
  132. package/lib/text/mp4_vtt_parser.js +2 -2
  133. package/lib/text/sbv_text_parser.js +1 -1
  134. package/lib/text/simple_text_displayer.js +2 -1
  135. package/lib/text/srt_text_parser.js +9 -1
  136. package/lib/text/ssa_text_parser.js +2 -2
  137. package/lib/text/text_engine.js +3 -21
  138. package/lib/text/text_utils.js +71 -20
  139. package/lib/text/ui_text_displayer.js +14 -14
  140. package/lib/text/vtt_text_parser.js +22 -14
  141. package/lib/transmuxer/aac_transmuxer.js +224 -0
  142. package/lib/transmuxer/ac3.js +142 -0
  143. package/lib/transmuxer/ac3_transmuxer.js +212 -0
  144. package/lib/transmuxer/adts.js +232 -0
  145. package/lib/transmuxer/ec3.js +103 -0
  146. package/lib/transmuxer/ec3_transmuxer.js +212 -0
  147. package/lib/transmuxer/h264.js +324 -0
  148. package/lib/transmuxer/mp3_transmuxer.js +204 -0
  149. package/lib/transmuxer/mpeg_audio.js +196 -0
  150. package/lib/transmuxer/mpeg_ts_transmuxer.js +182 -0
  151. package/lib/transmuxer/mss_transmuxer.js +389 -0
  152. package/lib/{media/transmuxer.js → transmuxer/muxjs_transmuxer.js} +34 -80
  153. package/lib/transmuxer/transmuxer_engine.js +161 -0
  154. package/lib/transmuxer/ts_transmuxer.js +738 -0
  155. package/lib/util/cmcd_manager.js +131 -71
  156. package/lib/util/error.js +62 -26
  157. package/lib/util/exp_golomb.js +220 -0
  158. package/lib/util/fairplay_utils.js +64 -13
  159. package/lib/util/id3_utils.js +56 -3
  160. package/lib/util/language_utils.js +11 -8
  161. package/lib/util/manifest_parser_utils.js +3 -0
  162. package/lib/util/mime_utils.js +44 -7
  163. package/lib/util/mp4_box_parsers.js +233 -5
  164. package/lib/util/mp4_generator.js +1381 -0
  165. package/lib/util/periods.js +40 -34
  166. package/lib/util/platform.js +25 -3
  167. package/lib/util/player_configuration.js +38 -1
  168. package/lib/util/stream_utils.js +138 -27
  169. package/lib/util/text_parser.js +1 -1
  170. package/lib/util/ts_parser.js +470 -47
  171. package/lib/util/xml_utils.js +16 -3
  172. package/maintained-branches.md +2 -2
  173. package/package.json +4 -2
  174. package/roadmap.md +21 -6
  175. package/shaka-player.uncompiled.js +18 -0
  176. package/test/abr/simple_abr_manager_unit.js +32 -4
  177. package/test/ads/ad_manager_unit.js +18 -2
  178. package/test/cast/cast_utils_unit.js +7 -2
  179. package/test/cea/cea608_memory_unit.js +24 -0
  180. package/test/cea/cea_decoder_unit.js +33 -0
  181. package/test/dash/dash_parser_content_protection_unit.js +93 -3
  182. package/test/dash/dash_parser_live_unit.js +56 -13
  183. package/test/dash/dash_parser_manifest_unit.js +70 -2
  184. package/test/dash/dash_parser_segment_base_unit.js +14 -9
  185. package/test/dash/dash_parser_segment_template_unit.js +286 -6
  186. package/test/demo/demo_unit.js +5 -1
  187. package/test/hls/hls_live_unit.js +188 -28
  188. package/test/hls/hls_parser_unit.js +250 -109
  189. package/test/hls/manifest_text_parser_unit.js +18 -13
  190. package/test/media/adaptation_set_criteria_unit.js +46 -14
  191. package/test/media/adaptation_set_unit.js +2 -0
  192. package/test/media/drm_engine_integration.js +11 -8
  193. package/test/media/drm_engine_unit.js +220 -7
  194. package/test/media/media_source_engine_integration.js +122 -38
  195. package/test/media/media_source_engine_unit.js +133 -153
  196. package/test/media/playhead_unit.js +3 -0
  197. package/test/media/presentation_timeline_unit.js +51 -0
  198. package/test/media/segment_index_unit.js +52 -0
  199. package/test/media/segment_prefetch_unit.js +243 -0
  200. package/test/media/streaming_engine_integration.js +9 -3
  201. package/test/media/streaming_engine_unit.js +440 -59
  202. package/test/mss/mss_parser_content_protection_unit.js +49 -0
  203. package/test/mss/mss_parser_unit.js +472 -0
  204. package/test/mss/mss_player_integration.js +123 -0
  205. package/test/offline/manifest_convert_unit.js +9 -0
  206. package/test/offline/storage_integration.js +6 -1
  207. package/test/player_integration.js +4 -1
  208. package/test/player_unit.js +386 -133
  209. package/test/polyfill/media_capabilities_unit.js +18 -0
  210. package/test/test/assets/hls-raw-aac/fileSequence0.aac +0 -0
  211. package/test/test/assets/hls-raw-aac/fileSequence1.aac +0 -0
  212. package/test/test/assets/hls-raw-aac/fileSequence2.aac +0 -0
  213. package/test/test/assets/hls-raw-aac/fileSequence3.aac +0 -0
  214. package/test/test/assets/hls-raw-aac/manifest.m3u8 +4 -0
  215. package/test/test/assets/hls-raw-aac/stream.m4a.m3u8 +14 -0
  216. package/test/test/assets/hls-raw-ac3/fileSequence0.ac3 +0 -0
  217. package/test/test/assets/hls-raw-ac3/fileSequence1.ac3 +0 -0
  218. package/test/test/assets/hls-raw-ac3/fileSequence2.ac3 +0 -0
  219. package/test/test/assets/hls-raw-ac3/fileSequence3.ac3 +0 -0
  220. package/test/test/assets/hls-raw-ac3/fileSequence4.ac3 +0 -0
  221. package/test/test/assets/hls-raw-ac3/fileSequence5.ac3 +0 -0
  222. package/test/test/assets/hls-raw-ac3/fileSequence6.ac3 +0 -0
  223. package/test/test/assets/hls-raw-ac3/fileSequence7.ac3 +0 -0
  224. package/test/test/assets/hls-raw-ac3/prog_index.m3u8 +31 -0
  225. package/test/test/assets/hls-raw-ec3/fileSequence0.ec3 +0 -0
  226. package/test/test/assets/hls-raw-ec3/fileSequence1.ec3 +0 -0
  227. package/test/test/assets/hls-raw-ec3/fileSequence2.ec3 +0 -0
  228. package/test/test/assets/hls-raw-ec3/fileSequence3.ec3 +0 -0
  229. package/test/test/assets/hls-raw-ec3/fileSequence4.ec3 +0 -0
  230. package/test/test/assets/hls-raw-ec3/fileSequence5.ec3 +0 -0
  231. package/test/test/assets/hls-raw-ec3/fileSequence6.ec3 +0 -0
  232. package/test/test/assets/hls-raw-ec3/fileSequence7.ec3 +0 -0
  233. package/test/test/assets/hls-raw-ec3/prog_index.m3u8 +31 -0
  234. package/test/test/assets/hls-raw-mp3/chunklist_w905519204.m3u8 +13 -0
  235. package/test/test/assets/hls-raw-mp3/media_w905519204_0.mp3 +0 -0
  236. package/test/test/assets/hls-raw-mp3/media_w905519204_1.mp3 +0 -0
  237. package/test/test/assets/hls-raw-mp3/media_w905519204_2.mp3 +0 -0
  238. package/test/test/assets/hls-raw-mp3/media_w905519204_3.mp3 +0 -0
  239. package/test/test/assets/hls-raw-mp3/playlist.m3u8 +4 -0
  240. package/test/test/assets/hls-ts-aac/playlist.m3u8 +23 -0
  241. package/test/test/assets/hls-ts-aac/segment_0.ts +0 -0
  242. package/test/test/assets/hls-ts-aac/segment_1.ts +0 -0
  243. package/test/test/assets/hls-ts-aac/segment_2.ts +0 -0
  244. package/test/test/assets/hls-ts-aac/segment_3.ts +0 -0
  245. package/test/test/assets/hls-ts-aac/segment_4.ts +0 -0
  246. package/test/test/assets/hls-ts-aac/segment_5.ts +0 -0
  247. package/test/test/assets/hls-ts-aac/segment_6.ts +0 -0
  248. package/test/test/assets/hls-ts-aac/segment_7.ts +0 -0
  249. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0000.ts +0 -0
  250. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0001.ts +0 -0
  251. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0002.ts +0 -0
  252. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0003.ts +0 -0
  253. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0004.ts +0 -0
  254. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0005.ts +0 -0
  255. package/test/test/assets/hls-ts-ac3/prog_index.m3u8 +19 -0
  256. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0000.ts +0 -0
  257. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0001.ts +0 -0
  258. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0002.ts +0 -0
  259. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0003.ts +0 -0
  260. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0004.ts +0 -0
  261. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0005.ts +0 -0
  262. package/test/test/assets/hls-ts-ec3/prog_index.m3u8 +19 -0
  263. package/test/test/assets/hls-ts-h264/fileSequence0.ts +0 -0
  264. package/test/test/assets/hls-ts-h264/fileSequence1.ts +0 -0
  265. package/test/test/assets/hls-ts-h264/fileSequence2.ts +0 -0
  266. package/test/test/assets/hls-ts-h264/fileSequence3.ts +0 -0
  267. package/test/test/assets/hls-ts-h264/fileSequence4.ts +0 -0
  268. package/test/test/assets/hls-ts-h264/fileSequence5.ts +0 -0
  269. package/test/test/assets/hls-ts-h264/prog_index.m3u8 +25 -0
  270. package/test/test/assets/hls-ts-mp3/manifest.m3u8 +13 -0
  271. package/test/test/assets/hls-ts-mp3/media_w239891843_0.ts +0 -0
  272. package/test/test/assets/hls-ts-mp3/media_w239891843_1.ts +0 -0
  273. package/test/test/assets/hls-ts-mp3/media_w239891843_2.ts +0 -0
  274. package/test/test/assets/hls-ts-mp3/media_w239891843_3.ts +0 -0
  275. package/test/test/assets/hls-ts-muxed-aac-h264/chunk.m3u8 +17 -0
  276. package/test/test/assets/hls-ts-muxed-aac-h264/n_0_0_0.ts +0 -0
  277. package/test/test/assets/hls-ts-muxed-aac-h264/n_1_0_0.ts +0 -0
  278. package/test/test/assets/hls-ts-muxed-aac-h264/n_2_0_0.ts +0 -0
  279. package/test/test/assets/hls-ts-muxed-aac-h264/n_3_0_0.ts +0 -0
  280. package/test/test/assets/hls-ts-muxed-aac-h264/n_4_0_0.ts +0 -0
  281. package/test/test/assets/hls-ts-muxed-aac-h264/n_5_0_0.ts +0 -0
  282. package/test/test/assets/hls-ts-muxed-aac-h264/playlist.m3u8 +4 -0
  283. package/test/test/boot.js +7 -2
  284. package/test/test/util/fake_ad.js +99 -0
  285. package/test/test/util/fake_ad_manager.js +7 -1
  286. package/test/test/util/fake_networking_engine.js +41 -14
  287. package/test/test/util/fake_segment_prefetch.js +81 -0
  288. package/test/test/util/manifest_generator.js +19 -5
  289. package/test/test/util/mss_parser_util.js +115 -0
  290. package/test/test/util/offline_utils.js +1 -0
  291. package/test/test/util/simple_fakes.js +12 -3
  292. package/test/test/util/streaming_engine_util.js +14 -4
  293. package/test/test/util/ttml_utils.js +2 -2
  294. package/test/test/util/ui_utils.js +5 -1
  295. package/test/text/cue_integration.js +1 -1
  296. package/test/text/srt_text_parser_unit.js +78 -0
  297. package/test/text/text_engine_unit.js +17 -8
  298. package/test/text/ui_text_displayer_unit.js +4 -4
  299. package/test/text/vtt_text_parser_unit.js +59 -40
  300. package/test/text/web_vtt_generator_unit.js +9 -3
  301. package/test/{media/transmuxer_integration.js → transmuxer/muxjs_transmuxer_integration.js} +30 -33
  302. package/test/transmuxer/transmuxer_engine_integration.js +60 -0
  303. package/test/transmuxer/transmuxer_integration.js +296 -0
  304. package/test/util/cmcd_manager_unit.js +162 -13
  305. package/test/util/language_utils_unit.js +9 -2
  306. package/test/util/mp4_box_parsers_unit.js +39 -4
  307. package/test/util/periods_unit.js +34 -26
  308. package/test/util/stream_utils_unit.js +60 -107
  309. package/ui/controls.js +19 -1
  310. package/ui/controls.less +1 -0
  311. package/ui/externs/ui.js +13 -3
  312. package/ui/language_utils.js +15 -0
  313. package/ui/less/thumbnails.less +26 -0
  314. package/ui/locales/oc.json +42 -0
  315. package/ui/pip_button.js +83 -2
  316. package/ui/range_element.js +15 -0
  317. package/ui/resolution_selection.js +9 -2
  318. package/ui/seek_bar.js +230 -1
  319. package/ui/ui.js +5 -0
  320. package/lib/cea/i_caption_decoder.js +0 -51
  321. package/lib/cea/i_cea_parser.js +0 -68
@@ -0,0 +1,49 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ // Test DRM-related parsing.
8
+ describe('MssParser ContentProtection', () => {
9
+ const ContentProtection = shaka.mss.ContentProtection;
10
+
11
+ const strToXml = (str) => {
12
+ const parser = new DOMParser();
13
+ return parser.parseFromString(str, 'application/xml').documentElement;
14
+ };
15
+
16
+ it('getPlayReadyLicenseURL', () => {
17
+ const laurl = [
18
+ '<WRMHEADER>',
19
+ ' <DATA>',
20
+ ' <LA_URL>www.example.com</LA_URL>',
21
+ ' </DATA>',
22
+ '</WRMHEADER>',
23
+ ].join('\n');
24
+ const laurlCodes = laurl.split('').map((c) => {
25
+ return c.charCodeAt();
26
+ });
27
+ const prBytes = new Uint16Array([
28
+ // pr object size (in num bytes).
29
+ // + 10 for PRO size, count, and type
30
+ laurl.length * 2 + 10, 0,
31
+ // record count
32
+ 1,
33
+ // type
34
+ ContentProtection.PLAYREADY_RECORD_TYPES.RIGHTS_MANAGEMENT,
35
+ // record size (in num bytes)
36
+ laurl.length * 2,
37
+ // value
38
+ ].concat(laurlCodes));
39
+
40
+ const encodedPrObject = shaka.util.Uint8ArrayUtils.toBase64(prBytes);
41
+ const input = strToXml([
42
+ '<ProtectionHeader SystemID="9a04f079-9840-4286-ab92-e65be0885f95">',
43
+ encodedPrObject,
44
+ '</ProtectionHeader>',
45
+ ].join('\n'));
46
+ const actual = ContentProtection.getPlayReadyLicenseUrl(input);
47
+ expect(actual).toBe('www.example.com');
48
+ });
49
+ });
@@ -0,0 +1,472 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ // Test basic manifest parsing functionality.
8
+ describe('MssParser Manifest', () => {
9
+ // const ManifestParser = shaka.test.ManifestParser;
10
+ const Mss = shaka.test.Mss;
11
+
12
+ /** @type {!shaka.test.FakeNetworkingEngine} */
13
+ let fakeNetEngine;
14
+ /** @type {!shaka.mss.MssParser} */
15
+ let parser;
16
+ /** @type {!jasmine.Spy} */
17
+ let onEventSpy;
18
+ /** @type {shaka.extern.ManifestParser.PlayerInterface} */
19
+ let playerInterface;
20
+
21
+ const h264CodecPrivateData = '000000016764001FAC2CA5014016EFFC100010014808' +
22
+ '080A000007D200017700C100005A648000B4C9FE31C6080002D3240005A64FF18E1DA' +
23
+ '12251600000000168E9093525';
24
+
25
+ const aacCodecPrivateData = '1210';
26
+
27
+ // From https://test.playready.microsoft.com/smoothstreaming/SSWSS720H264PR/S
28
+ // uperSpeedway_720.ism/Manifest
29
+ const protectionHeader = 'jAMAAAEAAQCCAzwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0A' +
30
+ 'bABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzA' +
31
+ 'G8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQ' +
32
+ 'BhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4' +
33
+ 'AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZ' +
34
+ 'AEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQ' +
35
+ 'wBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AE' +
36
+ 'sASQBEAD4AQQBtAGYAagBDAFQATwBQAGIARQBPAGwAMwBXAEQALwA1AG0AYwBlAGMAQQA' +
37
+ '9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBCAEcAdwAxAGEAWQBaADEA' +
38
+ 'WQBYAE0APQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABDAFUAUwBUAE8ATQBBAFQAVABSA' +
39
+ 'EkAQgBVAFQARQBTAD4APABJAEkAUwBfAEQAUgBNAF8AVgBFAFIAUwBJAE8ATgA+ADcALg' +
40
+ 'AxAC4AMQAwADYANAAuADAAPAAvAEkASQBTAF8ARABSAE0AXwBWAEUAUgBTAEkATwBOAD4' +
41
+ 'APAAvAEMAVQBTAFQATwBNAEEAVABUAFIASQBCAFUAVABFAFMAPgA8AEwAQQBfAFUAUgBM' +
42
+ 'AD4AaAB0AHQAcAA6AC8ALwBwAGwAYQB5AHIAZQBhAGQAeQAuAGQAaQByAGUAYwB0AHQAY' +
43
+ 'QBwAHMALgBuAGUAdAAvAHAAcgAvAHMAdgBjAC8AcgBpAGcAaAB0AHMAbQBhAG4AYQBnAG' +
44
+ 'UAcgAuAGEAcwBtAHgAPAAvAEwAQQBfAFUAUgBMAD4APABEAFMAXwBJAEQAPgBBAEgAKwA' +
45
+ 'wADMAagB1AEsAYgBVAEcAYgBIAGwAMQBWAC8AUQBJAHcAUgBBAD0APQA8AC8ARABTAF8A' +
46
+ 'SQBEAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA=';
47
+
48
+ /** @param {!shaka.extern.Manifest} manifest */
49
+ async function loadAllStreamsFor(manifest) {
50
+ const promises = [];
51
+ for (const variant of manifest.variants) {
52
+ for (const stream of [variant.video, variant.audio]) {
53
+ if (stream) {
54
+ promises.push(stream.createSegmentIndex());
55
+ }
56
+ }
57
+ }
58
+ for (const text of manifest.textStreams) {
59
+ promises.push(text.createSegmentIndex());
60
+ }
61
+ await Promise.all(promises);
62
+ }
63
+
64
+ beforeEach(() => {
65
+ fakeNetEngine = new shaka.test.FakeNetworkingEngine();
66
+ parser = Mss.makeMssParser();
67
+ onEventSpy = jasmine.createSpy('onEvent');
68
+ playerInterface = {
69
+ networkingEngine: fakeNetEngine,
70
+ modifyManifestRequest: (request, manifestInfo) => {},
71
+ modifySegmentRequest: (request, segmentInfo) => {},
72
+ filter: (manifest) => Promise.resolve(),
73
+ makeTextStreamsForClosedCaptions: (manifest) => {},
74
+ onTimelineRegionAdded: fail, // Should not have any EventStream elements.
75
+ onEvent: shaka.test.Util.spyFunc(onEventSpy),
76
+ onError: fail,
77
+ isLowLatencyMode: () => false,
78
+ isAutoLowLatencyMode: () => false,
79
+ enableLowLatencyMode: () => {},
80
+ updateDuration: () => {},
81
+ newDrmInfo: (stream) => {},
82
+ };
83
+ });
84
+
85
+ describe('fails for', () => {
86
+ it('invalid XML', async () => {
87
+ const source = '<not XML';
88
+ const error = new shaka.util.Error(
89
+ shaka.util.Error.Severity.CRITICAL,
90
+ shaka.util.Error.Category.MANIFEST,
91
+ shaka.util.Error.Code.MSS_INVALID_XML,
92
+ 'dummy://foo');
93
+ await Mss.testFails(source, error);
94
+ });
95
+
96
+ it('XML with inner errors', async () => {
97
+ const source = [
98
+ '<SmoothStreamingMedia Duration="1209510000">',
99
+ ' <StreamIndex Name="audio" Type="audio" Url="uri">',
100
+ ' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
101
+ aacCodecPrivateData,
102
+ '" FourCC="AACL"/>',
103
+ ' <c d="20201360"/>',
104
+ ' </StreamIndex', // Missing a close bracket.
105
+ '</SmoothStreamingMedia>',
106
+ ].join('\n');
107
+ const error = new shaka.util.Error(
108
+ shaka.util.Error.Severity.CRITICAL,
109
+ shaka.util.Error.Category.MANIFEST,
110
+ shaka.util.Error.Code.MSS_INVALID_XML,
111
+ 'dummy://foo');
112
+ await Mss.testFails(source, error);
113
+ });
114
+
115
+ it('failed network requests', async () => {
116
+ const expectedError = new shaka.util.Error(
117
+ shaka.util.Error.Severity.CRITICAL,
118
+ shaka.util.Error.Category.NETWORK,
119
+ shaka.util.Error.Code.BAD_HTTP_STATUS);
120
+
121
+ fakeNetEngine.request.and.returnValue(
122
+ shaka.util.AbortableOperation.failed(expectedError));
123
+ await expectAsync(parser.start('', playerInterface))
124
+ .toBeRejectedWith(shaka.test.Util.jasmineError(expectedError));
125
+ });
126
+
127
+ it('missing SmoothStreamingMedia element', async () => {
128
+ const source = '<XML></XML>';
129
+ const error = new shaka.util.Error(
130
+ shaka.util.Error.Severity.CRITICAL,
131
+ shaka.util.Error.Category.MANIFEST,
132
+ shaka.util.Error.Code.MSS_INVALID_XML,
133
+ 'dummy://foo');
134
+ await Mss.testFails(source, error);
135
+ });
136
+
137
+ it('live content ', async () => {
138
+ const source = [
139
+ '<SmoothStreamingMedia Duration="1209510000" IsLive="true">',
140
+ ' <StreamIndex Name="audio" Type="audio" Url="uri">',
141
+ ' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
142
+ aacCodecPrivateData,
143
+ '" FourCC="AACL"/>',
144
+ ' <c d="20201360"/>',
145
+ ' </StreamIndex>',
146
+ '</SmoothStreamingMedia>',
147
+ ].join('\n');
148
+ const error = new shaka.util.Error(
149
+ shaka.util.Error.Severity.CRITICAL,
150
+ shaka.util.Error.Category.MANIFEST,
151
+ shaka.util.Error.Code.MSS_LIVE_CONTENT_NOT_SUPPORTED);
152
+ await Mss.testFails(source, error);
153
+ });
154
+ });
155
+
156
+ it('Disable audio does not create audio streams', async () => {
157
+ const manifestText = [
158
+ '<SmoothStreamingMedia Duration="1209510000">',
159
+ ' <StreamIndex Type="video" Url="uri">',
160
+ ' <QualityLevel Bitrate="2962000" CodecPrivateData="',
161
+ h264CodecPrivateData,
162
+ '" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
163
+ ' <c d="20020000"/>',
164
+ ' </StreamIndex>',
165
+ ' <StreamIndex Name="audio" Type="audio" Url="uri">',
166
+ ' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
167
+ aacCodecPrivateData,
168
+ '" FourCC="AACL"/>',
169
+ ' <c d="20201360"/>',
170
+ ' </StreamIndex>',
171
+ '</SmoothStreamingMedia>',
172
+ ].join('\n');
173
+
174
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
175
+ const config = shaka.util.PlayerConfiguration.createDefault().manifest;
176
+ config.disableAudio = true;
177
+ parser.configure(config);
178
+
179
+ /** @type {shaka.extern.Manifest} */
180
+ const manifest = await parser.start('dummy://foo', playerInterface);
181
+ const variant = manifest.variants[0];
182
+ expect(variant.audio).toBe(null);
183
+ expect(variant.video).toBeTruthy();
184
+ });
185
+
186
+ it('Disable video does not create video streams', async () => {
187
+ const manifestText = [
188
+ '<SmoothStreamingMedia Duration="1209510000">',
189
+ ' <StreamIndex Type="video" Url="uri">',
190
+ ' <QualityLevel Bitrate="2962000" CodecPrivateData="',
191
+ h264CodecPrivateData,
192
+ '" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
193
+ ' <c d="20020000"/>',
194
+ ' </StreamIndex>',
195
+ ' <StreamIndex Name="audio" Type="audio" Url="uri">',
196
+ ' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
197
+ aacCodecPrivateData,
198
+ '" FourCC="AACL"/>',
199
+ ' <c d="20201360"/>',
200
+ ' </StreamIndex>',
201
+ '</SmoothStreamingMedia>',
202
+ ].join('\n');
203
+
204
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
205
+ const config = shaka.util.PlayerConfiguration.createDefault().manifest;
206
+ config.disableVideo = true;
207
+ parser.configure(config);
208
+
209
+ /** @type {shaka.extern.Manifest} */
210
+ const manifest = await parser.start('dummy://foo', playerInterface);
211
+ const variant = manifest.variants[0];
212
+ expect(variant.audio).toBeTruthy();
213
+ expect(variant.video).toBe(null);
214
+ });
215
+
216
+ it('Disable text does not create text streams', async () => {
217
+ const manifestText = [
218
+ '<SmoothStreamingMedia Duration="1209510000">',
219
+ ' <StreamIndex Type="video" Url="uri">',
220
+ ' <QualityLevel Bitrate="2962000" CodecPrivateData="',
221
+ h264CodecPrivateData,
222
+ '" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
223
+ ' <c d="20020000"/>',
224
+ ' </StreamIndex>',
225
+ ' <StreamIndex Name="audio" Type="audio" Url="uri">',
226
+ ' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
227
+ aacCodecPrivateData,
228
+ '" FourCC="AACL"/>',
229
+ ' <c d="20201360"/>',
230
+ ' </StreamIndex>',
231
+ ' <StreamIndex Name="text" Type="text" Url="uri">',
232
+ ' <QualityLevel Bitrate="1000" FourCC="TTML"/>',
233
+ ' <c d="20201360"/>',
234
+ ' </StreamIndex>',
235
+ '</SmoothStreamingMedia>',
236
+ ].join('\n');
237
+
238
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
239
+ const config = shaka.util.PlayerConfiguration.createDefault().manifest;
240
+ config.disableText = true;
241
+ parser.configure(config);
242
+
243
+ /** @type {shaka.extern.Manifest} */
244
+ const manifest = await parser.start('dummy://foo', playerInterface);
245
+ const stream = manifest.textStreams[0];
246
+ expect(stream).toBeUndefined();
247
+ });
248
+
249
+ it('Invokes manifestPreprocessor in config', async () => {
250
+ const manifestText = [
251
+ '<SmoothStreamingMedia Duration="1209510000">',
252
+ ' <StreamIndex Type="video" Url="uri">',
253
+ ' <QualityLevel Bitrate="2962000" CodecPrivateData="',
254
+ h264CodecPrivateData,
255
+ '" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
256
+ ' <c d="20020000"/>',
257
+ ' </StreamIndex>',
258
+ ' <StreamIndex Name="audio" Type="audio" Url="uri">',
259
+ ' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
260
+ aacCodecPrivateData,
261
+ '" FourCC="AACL"/>',
262
+ ' <c d="20201360"/>',
263
+ ' </StreamIndex>',
264
+ ' <StreamIndex Name="text" Type="text" Url="uri">',
265
+ ' <QualityLevel Bitrate="1000" FourCC="TTML"/>',
266
+ ' <c d="20201360"/>',
267
+ ' </StreamIndex>',
268
+ '</SmoothStreamingMedia>',
269
+ ].join('\n');
270
+
271
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
272
+ const config = shaka.util.PlayerConfiguration.createDefault().manifest;
273
+ config.mss.manifestPreprocessor = (mss) => {
274
+ const selector = 'StreamIndex[Name="text"';
275
+ const vttElements = mss.querySelectorAll(selector);
276
+ for (const element of vttElements) {
277
+ element.parentNode.removeChild(element);
278
+ }
279
+ };
280
+ parser.configure(config);
281
+
282
+ /** @type {shaka.extern.Manifest} */
283
+ const manifest = await parser.start('dummy://foo', playerInterface);
284
+ const stream = manifest.textStreams[0];
285
+ expect(stream).toBeUndefined();
286
+ });
287
+
288
+ it('generate a fake init segment', async () => {
289
+ const manifestText = [
290
+ '<SmoothStreamingMedia Duration="3600000000">',
291
+ ' <StreamIndex Name="audio" Type="audio" Url="{bitrate}/{start time}">',
292
+ ' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
293
+ aacCodecPrivateData,
294
+ '" FourCC="AACL"/>',
295
+ ' <c t="0" d="30000000" r="12"/>',
296
+ ' </StreamIndex>',
297
+ '</SmoothStreamingMedia>',
298
+ ].join('\n');
299
+
300
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
301
+
302
+ const manifest = await parser.start('dummy://foo', playerInterface);
303
+ const segmentReference =
304
+ await Mss.getFirstAudioSegmentReference(manifest);
305
+ const initSegmentReference = segmentReference.initSegmentReference;
306
+ expect(initSegmentReference.getUris()).toEqual([]);
307
+ expect(initSegmentReference.getStartByte()).toBe(0);
308
+ expect(initSegmentReference.getEndByte()).toBe(null);
309
+ expect(initSegmentReference.getSegmentData()).toBeDefined();
310
+ });
311
+
312
+ it('skip video stream without CodecPrivateData', async () => {
313
+ const manifestText = [
314
+ '<SmoothStreamingMedia Duration="1209510000">',
315
+ ' <StreamIndex Type="video" Url="uri">',
316
+ ' <QualityLevel Bitrate="2962000" FourCC="H264" MaxHeight="720" ',
317
+ ' MaxWidth="1280"/>',
318
+ ' <c d="20020000"/>',
319
+ ' </StreamIndex>',
320
+ ' <StreamIndex Name="audio" Type="audio" Url="uri">',
321
+ ' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
322
+ aacCodecPrivateData,
323
+ '" FourCC="AACL"/>',
324
+ ' <c d="20201360"/>',
325
+ ' </StreamIndex>',
326
+ '</SmoothStreamingMedia>',
327
+ ].join('\n');
328
+
329
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
330
+
331
+ /** @type {shaka.extern.Manifest} */
332
+ const manifest = await parser.start('dummy://foo', playerInterface);
333
+ const variant = manifest.variants[0];
334
+ expect(variant.audio).toBeTruthy();
335
+ expect(variant.video).toBe(null);
336
+ });
337
+
338
+ it('skip video stream without FourCC', async () => {
339
+ const manifestText = [
340
+ '<SmoothStreamingMedia Duration="1209510000">',
341
+ ' <StreamIndex Type="video" Url="uri">',
342
+ ' <QualityLevel Bitrate="2962000" CodecPrivateData="',
343
+ h264CodecPrivateData,
344
+ '" MaxHeight="720" MaxWidth="1280"/>',
345
+ ' <c d="20020000"/>',
346
+ ' </StreamIndex>',
347
+ ' <StreamIndex Name="audio" Type="audio" Url="uri">',
348
+ ' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
349
+ aacCodecPrivateData,
350
+ '" FourCC="AACL"/>',
351
+ ' <c d="20201360"/>',
352
+ ' </StreamIndex>',
353
+ '</SmoothStreamingMedia>',
354
+ ].join('\n');
355
+
356
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
357
+
358
+ /** @type {shaka.extern.Manifest} */
359
+ const manifest = await parser.start('dummy://foo', playerInterface);
360
+ const variant = manifest.variants[0];
361
+ expect(variant.audio).toBeTruthy();
362
+ expect(variant.video).toBe(null);
363
+ });
364
+
365
+ it('supports audio stream without FourCC', async () => {
366
+ const manifestText = [
367
+ '<SmoothStreamingMedia Duration="1209510000">',
368
+ ' <StreamIndex Type="video" Url="uri">',
369
+ ' <QualityLevel Bitrate="2962000" CodecPrivateData="',
370
+ h264CodecPrivateData,
371
+ '" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
372
+ ' <c d="20020000"/>',
373
+ ' </StreamIndex>',
374
+ ' <StreamIndex Name="audio" Type="audio" Url="uri">',
375
+ ' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
376
+ aacCodecPrivateData,
377
+ '"/>',
378
+ ' <c d="20201360"/>',
379
+ ' </StreamIndex>',
380
+ '</SmoothStreamingMedia>',
381
+ ].join('\n');
382
+
383
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
384
+
385
+ /** @type {shaka.extern.Manifest} */
386
+ const manifest = await parser.start('dummy://foo', playerInterface);
387
+ const variant = manifest.variants[0];
388
+ expect(variant.audio).toBeTruthy();
389
+ expect(variant.video).toBeTruthy();
390
+ });
391
+
392
+ it('supports AACL stream without CodecPrivateData', async () => {
393
+ const manifestText = [
394
+ '<SmoothStreamingMedia Duration="1209510000">',
395
+ ' <StreamIndex Type="video" Url="uri">',
396
+ ' <QualityLevel Bitrate="2962000" CodecPrivateData="',
397
+ h264CodecPrivateData,
398
+ '" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
399
+ ' <c d="20020000"/>',
400
+ ' </StreamIndex>',
401
+ ' <StreamIndex Name="audio" Type="audio" Url="uri">',
402
+ ' <QualityLevel Bitrate="128000" Channels="2" FourCC="AACL"/>',
403
+ ' <c d="20201360"/>',
404
+ ' </StreamIndex>',
405
+ '</SmoothStreamingMedia>',
406
+ ].join('\n');
407
+
408
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
409
+
410
+ /** @type {shaka.extern.Manifest} */
411
+ const manifest = await parser.start('dummy://foo', playerInterface);
412
+ const variant = manifest.variants[0];
413
+ expect(variant.audio).toBeTruthy();
414
+ expect(variant.video).toBeTruthy();
415
+ });
416
+
417
+ it('supports AACH stream without CodecPrivateData', async () => {
418
+ const manifestText = [
419
+ '<SmoothStreamingMedia Duration="1209510000">',
420
+ ' <StreamIndex Type="video" Url="uri">',
421
+ ' <QualityLevel Bitrate="2962000" CodecPrivateData="',
422
+ h264CodecPrivateData,
423
+ '" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
424
+ ' <c d="20020000"/>',
425
+ ' </StreamIndex>',
426
+ ' <StreamIndex Name="audio" Type="audio" Url="uri">',
427
+ ' <QualityLevel Bitrate="128000" Channels="2" FourCC="AACH"/>',
428
+ ' <c d="20201360"/>',
429
+ ' </StreamIndex>',
430
+ '</SmoothStreamingMedia>',
431
+ ].join('\n');
432
+
433
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
434
+
435
+ /** @type {shaka.extern.Manifest} */
436
+ const manifest = await parser.start('dummy://foo', playerInterface);
437
+ const variant = manifest.variants[0];
438
+ expect(variant.audio).toBeTruthy();
439
+ expect(variant.video).toBeTruthy();
440
+ });
441
+
442
+ it('recognizes PlayReady System ID with mixed cases', async () => {
443
+ const manifestText = [
444
+ '<SmoothStreamingMedia Duration="1209510000">',
445
+ ' <StreamIndex Type="video" Url="uri">',
446
+ ' <QualityLevel Bitrate="2962000" CodecPrivateData="',
447
+ h264CodecPrivateData,
448
+ '" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
449
+ ' <c d="20020000"/>',
450
+ ' </StreamIndex>',
451
+ ' <Protection>',
452
+ ' <ProtectionHeader SystemID="9a04F079-9840-4286-aB92-e65BE0885f95">',
453
+ protectionHeader,
454
+ ' </ProtectionHeader>',
455
+ ' </Protection>',
456
+ '</SmoothStreamingMedia>',
457
+ ].join('\n');
458
+
459
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
460
+
461
+ /** @type {shaka.extern.Manifest} */
462
+ const manifest = await parser.start('dummy://foo', playerInterface);
463
+ const variant = manifest.variants[0];
464
+ expect(variant.video.drmInfos.length).toBe(1);
465
+ expect(variant.video.drmInfos[0].keySystem).toBe('com.microsoft.playready');
466
+ // Also able to parse KID correctly
467
+ expect(variant.video.drmInfos[0].keyIds.size).toBe(1);
468
+ // Expected KID: https://testweb.playready.microsoft.com/Content/Content2X
469
+ expect([...(variant.video.drmInfos[0].keyIds.values())][0]).toBe(
470
+ '09E367028F33436CA5DD60FFE6671E70'.toLowerCase());
471
+ });
472
+ });
@@ -0,0 +1,123 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ describe('MSS Player', () => {
8
+ const Util = shaka.test.Util;
9
+
10
+ /** @type {!jasmine.Spy} */
11
+ let onErrorSpy;
12
+
13
+ /** @type {!HTMLVideoElement} */
14
+ let video;
15
+ /** @type {shaka.Player} */
16
+ let player;
17
+ /** @type {!shaka.util.EventManager} */
18
+ let eventManager;
19
+
20
+ let compiledShaka;
21
+
22
+ /** @type {!shaka.test.Waiter} */
23
+ let waiter;
24
+
25
+ // eslint-disable-next-line max-len
26
+ const url = 'https://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/Manifest';
27
+
28
+ // eslint-disable-next-line max-len
29
+ const playreadyUrl = 'https://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/Manifest';
30
+
31
+ // eslint-disable-next-line max-len
32
+ const playreadyLicenseUrl = 'https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)';
33
+
34
+ beforeAll(async () => {
35
+ video = shaka.test.UiUtils.createVideoElement();
36
+ document.body.appendChild(video);
37
+ compiledShaka =
38
+ await shaka.test.Loader.loadShaka(getClientArg('uncompiled'));
39
+ });
40
+
41
+ beforeEach(() => {
42
+ player = new compiledShaka.Player(video);
43
+
44
+ // Make sure we are playing the lowest res available to avoid test flake
45
+ // based on network issues. Note that disabling ABR and setting a low
46
+ // abr.defaultBandwidthEstimate would not be sufficient, because it
47
+ // would only affect the choice of track on the first period. When we
48
+ // cross a period boundary, the default bandwidth estimate will no
49
+ // longer be in effect, and AbrManager may choose higher res tracks for
50
+ // the new period. Using abr.restrictions.maxHeight will let us force
51
+ // AbrManager to the lowest resolution, which is its fallback when these
52
+ // soft restrictions cannot be met.
53
+ player.configure('abr.restrictions.maxHeight', 1);
54
+
55
+ // Disable stall detection, which can interfere with playback tests.
56
+ player.configure('streaming.stallEnabled', false);
57
+
58
+ // Grab event manager from the uncompiled library:
59
+ eventManager = new shaka.util.EventManager();
60
+ waiter = new shaka.test.Waiter(eventManager);
61
+ waiter.setPlayer(player);
62
+
63
+ onErrorSpy = jasmine.createSpy('onError');
64
+ onErrorSpy.and.callFake((event) => fail(event.detail));
65
+ eventManager.listen(player, 'error', Util.spyFunc(onErrorSpy));
66
+ });
67
+
68
+ afterEach(async () => {
69
+ eventManager.release();
70
+ await player.destroy();
71
+ });
72
+
73
+ afterAll(() => {
74
+ document.body.removeChild(video);
75
+ });
76
+
77
+ it('MSS VoD', async () => {
78
+ await player.load(url, /* startTime= */ null,
79
+ /* mimeType= */ 'application/vnd.ms-sstr+xml');
80
+ await video.play();
81
+ expect(player.isLive()).toBe(false);
82
+
83
+ // Wait for the video to start playback. If it takes longer than 10
84
+ // seconds, fail the test.
85
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
86
+
87
+ // Play for 5 seconds, but stop early if the video ends. If it takes
88
+ // longer than 10 seconds, fail the test.
89
+ await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 5, 10);
90
+
91
+ await player.unload();
92
+ });
93
+
94
+ it('MSS VoD PlayReady', async () => {
95
+ const support = await shaka.media.DrmEngine.probeSupport();
96
+ if (!support['com.microsoft.playready']) {
97
+ return;
98
+ }
99
+
100
+ player.configure({
101
+ drm: {
102
+ servers: {
103
+ 'com.microsoft.playready': playreadyLicenseUrl,
104
+ },
105
+ },
106
+ });
107
+
108
+ await player.load(playreadyUrl, /* startTime= */ null,
109
+ /* mimeType= */ 'application/vnd.ms-sstr+xml');
110
+ await video.play();
111
+ expect(player.isLive()).toBe(false);
112
+
113
+ // Wait for the video to start playback. If it takes longer than 10
114
+ // seconds, fail the test.
115
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
116
+
117
+ // Play for 5 seconds, but stop early if the video ends. If it takes
118
+ // longer than 10 seconds, fail the test.
119
+ await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 5, 10);
120
+
121
+ await player.unload();
122
+ });
123
+ });