shaka-player 4.6.3 → 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 (608) 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 +13 -9
  5. package/dist/locales.js +33 -33
  6. package/dist/shaka-player.compiled.d.ts +47 -4
  7. package/dist/shaka-player.compiled.debug.d.ts +47 -4
  8. package/dist/shaka-player.compiled.debug.externs.js +50 -2
  9. package/dist/shaka-player.compiled.debug.js +408 -376
  10. package/dist/shaka-player.compiled.debug.map +4 -4
  11. package/dist/shaka-player.compiled.externs.js +50 -2
  12. package/dist/shaka-player.compiled.js +1134 -1118
  13. package/dist/shaka-player.compiled.map +4 -4
  14. package/dist/shaka-player.ui.d.ts +69 -5
  15. package/dist/shaka-player.ui.debug.d.ts +69 -5
  16. package/dist/shaka-player.ui.debug.externs.js +82 -2
  17. package/dist/shaka-player.ui.debug.js +457 -420
  18. package/dist/shaka-player.ui.debug.map +4 -4
  19. package/dist/shaka-player.ui.externs.js +82 -2
  20. package/dist/shaka-player.ui.js +1305 -1289
  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/ads/client_side_ad_manager.js +4 -0
  28. package/lib/ads/media_tailor_ad_manager.js +5 -0
  29. package/lib/ads/server_side_ad_manager.js +4 -0
  30. package/lib/cea/cea708_service.js +1 -1
  31. package/lib/cea/cea708_window.js +95 -7
  32. package/lib/dash/dash_parser.js +55 -11
  33. package/lib/hls/hls_parser.js +17 -5
  34. package/lib/media/adaptation_set_criteria.js +76 -10
  35. package/lib/media/drm_engine.js +0 -3
  36. package/lib/media/media_source_engine.js +42 -18
  37. package/lib/media/segment_reference.js +12 -0
  38. package/lib/media/streaming_engine.js +58 -5
  39. package/lib/media/video_wrapper.js +4 -3
  40. package/lib/player.js +95 -11
  41. package/lib/text/simple_text_displayer.js +8 -7
  42. package/lib/text/text_utils.js +39 -13
  43. package/lib/text/ui_text_displayer.js +20 -11
  44. package/lib/text/web_vtt_generator.js +1 -1
  45. package/lib/util/cmsd_manager.js +269 -0
  46. package/lib/util/content_steering_manager.js +5 -1
  47. package/lib/util/mime_utils.js +6 -2
  48. package/lib/util/periods.js +108 -39
  49. package/lib/util/player_configuration.js +19 -5
  50. package/lib/util/stream_utils.js +82 -13
  51. package/package.json +1 -1
  52. package/ui/audio_language_selection.js +3 -0
  53. package/ui/controls.js +60 -0
  54. package/ui/externs/ui.js +12 -1
  55. package/ui/hidden_fast_forward_button.js +32 -0
  56. package/ui/hidden_rewind_button.js +32 -0
  57. package/ui/hidden_seek_button.js +121 -0
  58. package/ui/less/buttons.less +50 -0
  59. package/ui/less/containers.less +18 -0
  60. package/ui/resolution_selection.js +2 -0
  61. package/ui/ui.js +2 -0
  62. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -75
  63. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -26
  64. package/.github/ISSUE_TEMPLATE/question.md +0 -26
  65. package/.github/config.yml +0 -1
  66. package/.github/workflows/appspot.yaml +0 -39
  67. package/.github/workflows/build-and-test.yaml +0 -222
  68. package/.github/workflows/compute-incremental-coverage.py +0 -265
  69. package/.github/workflows/custom-actions/prep-for-appspot/action.yaml +0 -56
  70. package/.github/workflows/custom-actions/set-commit-status/action.yaml +0 -37
  71. package/.github/workflows/deflake.yaml +0 -31
  72. package/.github/workflows/demo-version-index.yaml +0 -43
  73. package/.github/workflows/nightly-demo.yaml +0 -42
  74. package/.github/workflows/release-please.yaml +0 -193
  75. package/.github/workflows/report-incremental-coverage.yaml +0 -39
  76. package/.github/workflows/safari-homedir-launcher.sh +0 -18
  77. package/.github/workflows/selenium-lab-tests.yaml +0 -370
  78. package/.github/workflows/shaka-bot-commands/command-help.sh +0 -27
  79. package/.github/workflows/shaka-bot-commands/command-test.sh +0 -56
  80. package/.github/workflows/shaka-bot-commands/lib.sh +0 -83
  81. package/.github/workflows/shaka-bot-commands/main.sh +0 -51
  82. package/.github/workflows/sync-labels.yaml +0 -33
  83. package/.github/workflows/talk-to-shaka-bot.yaml +0 -29
  84. package/.github/workflows/update-issues.yaml +0 -31
  85. package/.github/workflows/update-screenshots.yaml +0 -142
  86. package/.github/workflows/validate-pr-title.yaml +0 -27
  87. package/CHANGELOG.md +0 -5764
  88. package/CODE_OF_CONDUCT.md +0 -93
  89. package/CONTRIBUTING.md +0 -76
  90. package/demo/TengwarTelcontar.woff2 +0 -0
  91. package/demo/app_logo_144.png +0 -0
  92. package/demo/app_logo_192.png +0 -0
  93. package/demo/app_logo_256.png +0 -0
  94. package/demo/app_logo_384.png +0 -0
  95. package/demo/app_logo_512.png +0 -0
  96. package/demo/app_manifest.json +0 -29
  97. package/demo/asset_card.js +0 -410
  98. package/demo/autoTemplate.txt +0 -61
  99. package/demo/cast_receiver/idle1.jpg +0 -0
  100. package/demo/cast_receiver/idle2.jpg +0 -0
  101. package/demo/cast_receiver/idle3.jpg +0 -0
  102. package/demo/cast_receiver/index.html +0 -75
  103. package/demo/cast_receiver/receiver_app.css +0 -111
  104. package/demo/cast_receiver/receiver_app.js +0 -158
  105. package/demo/close_button.js +0 -60
  106. package/demo/common/asset.js +0 -511
  107. package/demo/common/assets.js +0 -1635
  108. package/demo/config.js +0 -859
  109. package/demo/custom.js +0 -907
  110. package/demo/customWarning.txt +0 -8
  111. package/demo/demo.less +0 -591
  112. package/demo/demo_uncompiled.js +0 -11
  113. package/demo/demo_utils.js +0 -113
  114. package/demo/favicon.ico +0 -0
  115. package/demo/front.js +0 -156
  116. package/demo/icons/README.md +0 -4
  117. package/demo/icons/baseline-audiotrack-24px.svg +0 -1
  118. package/demo/icons/baseline-closed_caption-24px.svg +0 -1
  119. package/demo/icons/baseline-fast_forward-24px.svg +0 -1
  120. package/demo/icons/baseline-language-24px.svg +0 -1
  121. package/demo/icons/baseline-live_tv-24px.svg +0 -1
  122. package/demo/icons/baseline-subtitles-24px.svg +0 -1
  123. package/demo/icons/baseline-surround_sound-24px.svg +0 -1
  124. package/demo/icons/custom_ad.svg +0 -1
  125. package/demo/icons/custom_box_with_text.svg +0 -1
  126. package/demo/icons/custom_clear_key.svg +0 -1
  127. package/demo/icons/custom_high_definition.svg +0 -1
  128. package/demo/icons/custom_playready.svg +0 -1
  129. package/demo/icons/custom_ultra_high_definition.svg +0 -1
  130. package/demo/icons/custom_widevine.svg +0 -1
  131. package/demo/index.html +0 -173
  132. package/demo/input.js +0 -270
  133. package/demo/input_container.js +0 -218
  134. package/demo/load.js +0 -156
  135. package/demo/main.js +0 -1854
  136. package/demo/search.js +0 -452
  137. package/demo/service_worker.js +0 -355
  138. package/demo/shaka_logo_trans.png +0 -0
  139. package/demo/tooltip.js +0 -29
  140. package/demo/visualizer.js +0 -335
  141. package/demo/visualizer_button.js +0 -84
  142. package/dist/demo.compiled.debug.js +0 -340
  143. package/dist/demo.compiled.debug.map +0 -8
  144. package/dist/demo.compiled.js +0 -340
  145. package/dist/demo.compiled.map +0 -8
  146. package/dist/demo.css +0 -6
  147. package/dist/demo.css.map +0 -1
  148. package/dist/receiver.compiled.debug.js +0 -187
  149. package/dist/receiver.compiled.debug.map +0 -8
  150. package/dist/receiver.compiled.js +0 -187
  151. package/dist/receiver.compiled.map +0 -8
  152. package/docs/announcement-list-join-group.png +0 -0
  153. package/docs/api-mainpage.md +0 -28
  154. package/docs/design/REDESIGN.md +0 -283
  155. package/docs/design/architecture.md +0 -13
  156. package/docs/design/bg-fetch-after.gv +0 -29
  157. package/docs/design/bg-fetch-after.gv.png +0 -0
  158. package/docs/design/bg-fetch-before.gv +0 -18
  159. package/docs/design/bg-fetch-before.gv.png +0 -0
  160. package/docs/design/bg-fetch.md +0 -134
  161. package/docs/design/cast.gv +0 -35
  162. package/docs/design/cast.gv.png +0 -0
  163. package/docs/design/chromecast.md +0 -151
  164. package/docs/design/codec_preferences.md +0 -158
  165. package/docs/design/dash-audio-channels.md +0 -123
  166. package/docs/design/dash-manifests.md +0 -248
  167. package/docs/design/dash-timeline.svg +0 -4
  168. package/docs/design/dataflow.gv +0 -66
  169. package/docs/design/dataflow.gv.png +0 -0
  170. package/docs/design/export.md +0 -70
  171. package/docs/design/fuzzy-locale-matching.md +0 -40
  172. package/docs/design/gap-jumping.md +0 -151
  173. package/docs/design/lcevc-architecture.png +0 -0
  174. package/docs/design/lcevc-demo.png +0 -0
  175. package/docs/design/lcevc-integration.md +0 -72
  176. package/docs/design/locale_compatibility.svg +0 -1
  177. package/docs/design/locales_tree.svg +0 -1
  178. package/docs/design/localization-design-principles.md +0 -158
  179. package/docs/design/newdemo.gv +0 -83
  180. package/docs/design/newdemo.gv.png +0 -0
  181. package/docs/design/offline.gv +0 -43
  182. package/docs/design/offline.gv.png +0 -0
  183. package/docs/design/offline.md +0 -153
  184. package/docs/design/ownership.gv +0 -76
  185. package/docs/design/ownership.gv.png +0 -0
  186. package/docs/design/preload.md +0 -299
  187. package/docs/design/preload.png +0 -0
  188. package/docs/design/talking-about-languages.md +0 -46
  189. package/docs/design/timeline.svg +0 -152
  190. package/docs/design/ui.md +0 -31
  191. package/docs/design/ui_player_relationships.svg +0 -1
  192. package/docs/jsdoc-plugin.js +0 -74
  193. package/docs/jsdoc-template/README.md +0 -1
  194. package/docs/jsdoc-template/publish.js +0 -879
  195. package/docs/jsdoc-template/static/fonts/OpenSans-Bold-webfont.eot +0 -0
  196. package/docs/jsdoc-template/static/fonts/OpenSans-Bold-webfont.svg +0 -1830
  197. package/docs/jsdoc-template/static/fonts/OpenSans-Bold-webfont.woff +0 -0
  198. package/docs/jsdoc-template/static/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
  199. package/docs/jsdoc-template/static/fonts/OpenSans-BoldItalic-webfont.svg +0 -1830
  200. package/docs/jsdoc-template/static/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
  201. package/docs/jsdoc-template/static/fonts/OpenSans-Italic-webfont.eot +0 -0
  202. package/docs/jsdoc-template/static/fonts/OpenSans-Italic-webfont.svg +0 -1830
  203. package/docs/jsdoc-template/static/fonts/OpenSans-Italic-webfont.woff +0 -0
  204. package/docs/jsdoc-template/static/fonts/OpenSans-Light-webfont.eot +0 -0
  205. package/docs/jsdoc-template/static/fonts/OpenSans-Light-webfont.svg +0 -1831
  206. package/docs/jsdoc-template/static/fonts/OpenSans-Light-webfont.woff +0 -0
  207. package/docs/jsdoc-template/static/fonts/OpenSans-LightItalic-webfont.eot +0 -0
  208. package/docs/jsdoc-template/static/fonts/OpenSans-LightItalic-webfont.svg +0 -1835
  209. package/docs/jsdoc-template/static/fonts/OpenSans-LightItalic-webfont.woff +0 -0
  210. package/docs/jsdoc-template/static/fonts/OpenSans-Regular-webfont.eot +0 -0
  211. package/docs/jsdoc-template/static/fonts/OpenSans-Regular-webfont.svg +0 -1831
  212. package/docs/jsdoc-template/static/fonts/OpenSans-Regular-webfont.woff +0 -0
  213. package/docs/jsdoc-template/static/scripts/linenumber.js +0 -44
  214. package/docs/jsdoc-template/static/scripts/show-widget.js +0 -55
  215. package/docs/jsdoc-template/static/styles/jsdoc-default.css +0 -438
  216. package/docs/jsdoc-template/tmpl/augments.tmpl +0 -10
  217. package/docs/jsdoc-template/tmpl/container.tmpl +0 -205
  218. package/docs/jsdoc-template/tmpl/details.tmpl +0 -152
  219. package/docs/jsdoc-template/tmpl/example.tmpl +0 -2
  220. package/docs/jsdoc-template/tmpl/examples.tmpl +0 -13
  221. package/docs/jsdoc-template/tmpl/exceptions.tmpl +0 -32
  222. package/docs/jsdoc-template/tmpl/layout.tmpl +0 -50
  223. package/docs/jsdoc-template/tmpl/mainpage.tmpl +0 -14
  224. package/docs/jsdoc-template/tmpl/members.tmpl +0 -47
  225. package/docs/jsdoc-template/tmpl/method.tmpl +0 -140
  226. package/docs/jsdoc-template/tmpl/modifies.tmpl +0 -14
  227. package/docs/jsdoc-template/tmpl/params.tmpl +0 -131
  228. package/docs/jsdoc-template/tmpl/properties.tmpl +0 -125
  229. package/docs/jsdoc-template/tmpl/returns.tmpl +0 -19
  230. package/docs/jsdoc-template/tmpl/source.tmpl +0 -8
  231. package/docs/jsdoc-template/tmpl/tutorial.tmpl +0 -21
  232. package/docs/jsdoc-template/tmpl/type.tmpl +0 -7
  233. package/docs/jsdoc.conf.json +0 -38
  234. package/docs/shaka-player-logo.png +0 -0
  235. package/docs/style.md +0 -174
  236. package/docs/tutorials/a11y.md +0 -64
  237. package/docs/tutorials/ad_monetization.md +0 -292
  238. package/docs/tutorials/application-level-redirects.md +0 -94
  239. package/docs/tutorials/architecture.md +0 -32
  240. package/docs/tutorials/basic-usage.md +0 -89
  241. package/docs/tutorials/blob-url.md +0 -15
  242. package/docs/tutorials/config.md +0 -148
  243. package/docs/tutorials/debugging.md +0 -189
  244. package/docs/tutorials/drm-config.md +0 -274
  245. package/docs/tutorials/errors.md +0 -95
  246. package/docs/tutorials/fairplay.md +0 -242
  247. package/docs/tutorials/faq.md +0 -252
  248. package/docs/tutorials/index.json +0 -29
  249. package/docs/tutorials/lcevc.md +0 -118
  250. package/docs/tutorials/license-server-auth.md +0 -248
  251. package/docs/tutorials/license-wrapping.md +0 -168
  252. package/docs/tutorials/manifest-parser.md +0 -365
  253. package/docs/tutorials/network-and-buffering-config.md +0 -119
  254. package/docs/tutorials/offline.md +0 -683
  255. package/docs/tutorials/plugins.md +0 -184
  256. package/docs/tutorials/selenium-grid-config.md +0 -174
  257. package/docs/tutorials/service-worker.md +0 -106
  258. package/docs/tutorials/ui-customization.md +0 -288
  259. package/docs/tutorials/ui.md +0 -230
  260. package/docs/tutorials/upgrade-manifest.md +0 -281
  261. package/docs/tutorials/upgrade.md +0 -104
  262. package/docs/tutorials/welcome.md +0 -108
  263. package/docs/tutorials/widevine-service-certs.md +0 -45
  264. package/karma.conf.js +0 -879
  265. package/maintained-branches.md +0 -15
  266. package/roadmap.md +0 -186
  267. package/test/abr/simple_abr_manager_unit.js +0 -398
  268. package/test/ads/ad_manager_unit.js +0 -260
  269. package/test/assumptions/uint8_array_unit.js +0 -22
  270. package/test/cast/cast_proxy_unit.js +0 -736
  271. package/test/cast/cast_receiver_integration.js +0 -488
  272. package/test/cast/cast_receiver_unit.js +0 -1183
  273. package/test/cast/cast_sender_unit.js +0 -973
  274. package/test/cast/cast_utils_unit.js +0 -311
  275. package/test/cea/cea608_memory_unit.js +0 -411
  276. package/test/cea/cea708_service_unit.js +0 -674
  277. package/test/cea/cea708_window_unit.js +0 -373
  278. package/test/cea/cea_decoder_unit.js +0 -615
  279. package/test/cea/dtvcc_packet_builder_unit.js +0 -158
  280. package/test/cea/dtvcc_packet_unit.js +0 -60
  281. package/test/cea/mp4_cea_parser_unit.js +0 -127
  282. package/test/codec_switching/codec_switching_integration.js +0 -182
  283. package/test/dash/dash_parser_content_protection_unit.js +0 -998
  284. package/test/dash/dash_parser_integration.js +0 -74
  285. package/test/dash/dash_parser_live_unit.js +0 -1542
  286. package/test/dash/dash_parser_manifest_unit.js +0 -3121
  287. package/test/dash/dash_parser_segment_base_unit.js +0 -421
  288. package/test/dash/dash_parser_segment_list_unit.js +0 -380
  289. package/test/dash/dash_parser_segment_template_unit.js +0 -910
  290. package/test/dash/mpd_utils_unit.js +0 -794
  291. package/test/demo/demo_unit.js +0 -108
  292. package/test/deprecate/enforcer_unit.js +0 -74
  293. package/test/deprecate/version_unit.js +0 -57
  294. package/test/hls/hls_live_unit.js +0 -1330
  295. package/test/hls/hls_parser_unit.js +0 -5276
  296. package/test/hls/manifest_text_parser_unit.js +0 -545
  297. package/test/media/adaptation_set_criteria_unit.js +0 -806
  298. package/test/media/adaptation_set_unit.js +0 -229
  299. package/test/media/buffering_observer_unit.js +0 -143
  300. package/test/media/closed_caption_parser_unit.js +0 -18
  301. package/test/media/content_workarounds_unit.js +0 -43
  302. package/test/media/drm_engine_integration.js +0 -356
  303. package/test/media/drm_engine_unit.js +0 -2778
  304. package/test/media/media_source_engine_integration.js +0 -691
  305. package/test/media/media_source_engine_unit.js +0 -1512
  306. package/test/media/mp4_segment_index_parser_unit.js +0 -80
  307. package/test/media/play_rate_controller_unit.js +0 -69
  308. package/test/media/playhead_unit.js +0 -1394
  309. package/test/media/presentation_timeline_unit.js +0 -477
  310. package/test/media/quality_observer_unit.js +0 -138
  311. package/test/media/region_observer_unit.js +0 -374
  312. package/test/media/region_timeline_unit.js +0 -139
  313. package/test/media/segment_index_unit.js +0 -1080
  314. package/test/media/segment_prefetch_unit.js +0 -243
  315. package/test/media/segment_reference_unit.js +0 -63
  316. package/test/media/stall_detector_unit.js +0 -184
  317. package/test/media/streaming_engine_integration.js +0 -632
  318. package/test/media/streaming_engine_unit.js +0 -4211
  319. package/test/media/time_ranges_utils_unit.js +0 -123
  320. package/test/media/webm_segment_index_parser_unit.js +0 -90
  321. package/test/mss/mss_parser_content_protection_unit.js +0 -49
  322. package/test/mss/mss_parser_unit.js +0 -474
  323. package/test/mss/mss_player_integration.js +0 -124
  324. package/test/net/data_uri_plugin_unit.js +0 -105
  325. package/test/net/http_plugin_unit.js +0 -439
  326. package/test/net/networking_engine_unit.js +0 -1236
  327. package/test/net/networking_utils_unit.js +0 -37
  328. package/test/offline/download_progress_estimator_unit.js +0 -90
  329. package/test/offline/indexeddb_storage_unit.js +0 -192
  330. package/test/offline/manifest_convert_unit.js +0 -622
  331. package/test/offline/offline_integration.js +0 -168
  332. package/test/offline/offline_manifest_parser_unit.js +0 -231
  333. package/test/offline/offline_scheme_unit.js +0 -154
  334. package/test/offline/offline_uri_unit.js +0 -59
  335. package/test/offline/storage_compatibility_unit.js +0 -344
  336. package/test/offline/storage_integration.js +0 -1858
  337. package/test/player_external.js +0 -237
  338. package/test/player_integration.js +0 -1371
  339. package/test/player_load_graph_integration.js +0 -865
  340. package/test/player_src_equals_external.js +0 -154
  341. package/test/player_src_equals_integration.js +0 -527
  342. package/test/player_unit.js +0 -4434
  343. package/test/polyfill/media_capabilities_unit.js +0 -277
  344. package/test/polyfill/patchedmediakeys_apple_unit.js +0 -130
  345. package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
  346. package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
  347. package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
  348. package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
  349. package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
  350. package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
  351. package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
  352. package/test/test/assets/3675/dash_0.mpd +0 -30
  353. package/test/test/assets/3675/dash_1.mpd +0 -30
  354. package/test/test/assets/3675/dash_2.mpd +0 -30
  355. package/test/test/assets/3675/dash_3.mpd +0 -30
  356. package/test/test/assets/3675/dash_4.mpd +0 -30
  357. package/test/test/assets/3675/dash_5.mpd +0 -26
  358. package/test/test/assets/3675/init-stream0.m4s +0 -0
  359. package/test/test/assets/audio-xhe-aac.mp4 +0 -0
  360. package/test/test/assets/audio.ts +0 -0
  361. package/test/test/assets/captions-test.ts +0 -0
  362. package/test/test/assets/cea-init.mp4 +0 -0
  363. package/test/test/assets/cea-segment.mp4 +0 -0
  364. package/test/test/assets/chapters.srt +0 -11
  365. package/test/test/assets/chapters.vtt +0 -10
  366. package/test/test/assets/chapters2.vtt +0 -10
  367. package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
  368. package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
  369. package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
  370. package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
  371. package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
  372. package/test/test/assets/dash-aes-128/dash.mpd +0 -18
  373. package/test/test/assets/dash-aes-128/license +0 -1
  374. package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
  375. package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
  376. package/test/test/assets/dash-multi-codec/dash.mpd +0 -32
  377. package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
  378. package/test/test/assets/db-dump-v1.json +0 -1
  379. package/test/test/assets/db-dump-v2-broken.json +0 -1
  380. package/test/test/assets/db-dump-v2-clean.json +0 -1
  381. package/test/test/assets/db-dump-v3.json +0 -1
  382. package/test/test/assets/db-dump-v4-broken.json +0 -1
  383. package/test/test/assets/db-dump-v5.json +0 -1
  384. package/test/test/assets/empty_caption_video_init.mp4 +0 -0
  385. package/test/test/assets/empty_caption_video_segment.mp4 +0 -0
  386. package/test/test/assets/encrypted-sintel-audio-init.mp4 +0 -0
  387. package/test/test/assets/encrypted-sintel-audio-segment.mp4 +0 -0
  388. package/test/test/assets/encrypted-sintel-video-init.mp4 +0 -0
  389. package/test/test/assets/encrypted-sintel-video-segment.mp4 +0 -0
  390. package/test/test/assets/green-pixel.mp4 +0 -0
  391. package/test/test/assets/green-pixel.txt +0 -15
  392. package/test/test/assets/h265-cea-init.mp4 +0 -0
  393. package/test/test/assets/h265-cea-segment.mp4 +0 -0
  394. package/test/test/assets/hls-raw-aac/fileSequence0.aac +0 -0
  395. package/test/test/assets/hls-raw-aac/fileSequence1.aac +0 -0
  396. package/test/test/assets/hls-raw-aac/fileSequence2.aac +0 -0
  397. package/test/test/assets/hls-raw-aac/fileSequence3.aac +0 -0
  398. package/test/test/assets/hls-raw-aac/manifest.m3u8 +0 -4
  399. package/test/test/assets/hls-raw-aac/stream.m4a.m3u8 +0 -14
  400. package/test/test/assets/hls-raw-ac3/fileSequence0.ac3 +0 -0
  401. package/test/test/assets/hls-raw-ac3/fileSequence1.ac3 +0 -0
  402. package/test/test/assets/hls-raw-ac3/fileSequence2.ac3 +0 -0
  403. package/test/test/assets/hls-raw-ac3/fileSequence3.ac3 +0 -0
  404. package/test/test/assets/hls-raw-ac3/fileSequence4.ac3 +0 -0
  405. package/test/test/assets/hls-raw-ac3/fileSequence5.ac3 +0 -0
  406. package/test/test/assets/hls-raw-ac3/fileSequence6.ac3 +0 -0
  407. package/test/test/assets/hls-raw-ac3/fileSequence7.ac3 +0 -0
  408. package/test/test/assets/hls-raw-ac3/prog_index.m3u8 +0 -31
  409. package/test/test/assets/hls-raw-ec3/fileSequence0.ec3 +0 -0
  410. package/test/test/assets/hls-raw-ec3/fileSequence1.ec3 +0 -0
  411. package/test/test/assets/hls-raw-ec3/fileSequence2.ec3 +0 -0
  412. package/test/test/assets/hls-raw-ec3/fileSequence3.ec3 +0 -0
  413. package/test/test/assets/hls-raw-ec3/fileSequence4.ec3 +0 -0
  414. package/test/test/assets/hls-raw-ec3/fileSequence5.ec3 +0 -0
  415. package/test/test/assets/hls-raw-ec3/fileSequence6.ec3 +0 -0
  416. package/test/test/assets/hls-raw-ec3/fileSequence7.ec3 +0 -0
  417. package/test/test/assets/hls-raw-ec3/prog_index.m3u8 +0 -31
  418. package/test/test/assets/hls-raw-mp3/chunklist_w905519204.m3u8 +0 -13
  419. package/test/test/assets/hls-raw-mp3/media_w905519204_0.mp3 +0 -0
  420. package/test/test/assets/hls-raw-mp3/media_w905519204_1.mp3 +0 -0
  421. package/test/test/assets/hls-raw-mp3/media_w905519204_2.mp3 +0 -0
  422. package/test/test/assets/hls-raw-mp3/media_w905519204_3.mp3 +0 -0
  423. package/test/test/assets/hls-raw-mp3/playlist.m3u8 +0 -4
  424. package/test/test/assets/hls-ts-aac/playlist.m3u8 +0 -23
  425. package/test/test/assets/hls-ts-aac/segment_0.ts +0 -0
  426. package/test/test/assets/hls-ts-aac/segment_1.ts +0 -0
  427. package/test/test/assets/hls-ts-aac/segment_2.ts +0 -0
  428. package/test/test/assets/hls-ts-aac/segment_3.ts +0 -0
  429. package/test/test/assets/hls-ts-aac/segment_4.ts +0 -0
  430. package/test/test/assets/hls-ts-aac/segment_5.ts +0 -0
  431. package/test/test/assets/hls-ts-aac/segment_6.ts +0 -0
  432. package/test/test/assets/hls-ts-aac/segment_7.ts +0 -0
  433. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0000.ts +0 -0
  434. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0001.ts +0 -0
  435. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0002.ts +0 -0
  436. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0003.ts +0 -0
  437. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0004.ts +0 -0
  438. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0005.ts +0 -0
  439. package/test/test/assets/hls-ts-ac3/prog_index.m3u8 +0 -19
  440. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0000.ts +0 -0
  441. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0001.ts +0 -0
  442. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0002.ts +0 -0
  443. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0003.ts +0 -0
  444. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0004.ts +0 -0
  445. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0005.ts +0 -0
  446. package/test/test/assets/hls-ts-ec3/prog_index.m3u8 +0 -19
  447. package/test/test/assets/hls-ts-h264/fileSequence0.ts +0 -0
  448. package/test/test/assets/hls-ts-h264/fileSequence1.ts +0 -0
  449. package/test/test/assets/hls-ts-h264/fileSequence2.ts +0 -0
  450. package/test/test/assets/hls-ts-h264/fileSequence3.ts +0 -0
  451. package/test/test/assets/hls-ts-h264/fileSequence4.ts +0 -0
  452. package/test/test/assets/hls-ts-h264/fileSequence5.ts +0 -0
  453. package/test/test/assets/hls-ts-h264/prog_index.m3u8 +0 -25
  454. package/test/test/assets/hls-ts-h265/0.ts +0 -0
  455. package/test/test/assets/hls-ts-h265/hevc.m3u8 +0 -6
  456. package/test/test/assets/hls-ts-h265/index.m3u8 +0 -7
  457. package/test/test/assets/hls-ts-mp3/manifest.m3u8 +0 -13
  458. package/test/test/assets/hls-ts-mp3/media_w239891843_0.ts +0 -0
  459. package/test/test/assets/hls-ts-mp3/media_w239891843_1.ts +0 -0
  460. package/test/test/assets/hls-ts-mp3/media_w239891843_2.ts +0 -0
  461. package/test/test/assets/hls-ts-mp3/media_w239891843_3.ts +0 -0
  462. package/test/test/assets/hls-ts-muxed-aac-h264/chunk.m3u8 +0 -17
  463. package/test/test/assets/hls-ts-muxed-aac-h264/n_0_0_0.ts +0 -0
  464. package/test/test/assets/hls-ts-muxed-aac-h264/n_1_0_0.ts +0 -0
  465. package/test/test/assets/hls-ts-muxed-aac-h264/n_2_0_0.ts +0 -0
  466. package/test/test/assets/hls-ts-muxed-aac-h264/n_3_0_0.ts +0 -0
  467. package/test/test/assets/hls-ts-muxed-aac-h264/n_4_0_0.ts +0 -0
  468. package/test/test/assets/hls-ts-muxed-aac-h264/n_5_0_0.ts +0 -0
  469. package/test/test/assets/hls-ts-muxed-aac-h264/playlist.m3u8 +0 -4
  470. package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
  471. package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
  472. package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +0 -9
  473. package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +0 -24
  474. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
  475. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
  476. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
  477. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
  478. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
  479. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
  480. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
  481. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
  482. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
  483. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
  484. package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +0 -14
  485. package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +0 -23
  486. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
  487. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
  488. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
  489. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
  490. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
  491. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
  492. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
  493. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
  494. package/test/test/assets/id3-metadata.aac +0 -0
  495. package/test/test/assets/id3-metadata.ts +0 -0
  496. package/test/test/assets/index-segment.mp4 +0 -0
  497. package/test/test/assets/index-segment.webm +0 -0
  498. package/test/test/assets/init-segment.webm +0 -0
  499. package/test/test/assets/large_file.mpd +0 -4930
  500. package/test/test/assets/multidrm-audio-init.mp4 +0 -0
  501. package/test/test/assets/multidrm-audio-segment.mp4 +0 -0
  502. package/test/test/assets/multidrm-video-init.mp4 +0 -0
  503. package/test/test/assets/multidrm-video-segment.mp4 +0 -0
  504. package/test/test/assets/multiple-trun-init.mp4 +0 -0
  505. package/test/test/assets/multiple-trun-segment.mp4 +0 -0
  506. package/test/test/assets/sintel-audio-init.mp4 +0 -0
  507. package/test/test/assets/sintel-audio-segment.mp4 +0 -0
  508. package/test/test/assets/sintel-video-init.mp4 +0 -0
  509. package/test/test/assets/sintel-video-segment.mp4 +0 -0
  510. package/test/test/assets/small.mp4 +0 -0
  511. package/test/test/assets/text-clip-alt.vtt +0 -63
  512. package/test/test/assets/text-clip.vtt +0 -63
  513. package/test/test/assets/thumbnails-sprites.vtt +0 -10
  514. package/test/test/assets/thumbnails.vtt +0 -10
  515. package/test/test/assets/ttml-init.mp4 +0 -0
  516. package/test/test/assets/ttml-segment-multiplemdat.mp4 +0 -0
  517. package/test/test/assets/ttml-segment.mp4 +0 -0
  518. package/test/test/assets/video.ts +0 -0
  519. package/test/test/assets/vtt-init.mp4 +0 -0
  520. package/test/test/assets/vtt-segment-multi-payload.mp4 +0 -0
  521. package/test/test/assets/vtt-segment-no-duration.mp4 +0 -0
  522. package/test/test/assets/vtt-segment-settings.mp4 +0 -0
  523. package/test/test/assets/vtt-segment.mp4 +0 -0
  524. package/test/test/boot.js +0 -495
  525. package/test/test/externs/filters.js +0 -44
  526. package/test/test/externs/fontfaceonload.js +0 -29
  527. package/test/test/externs/jasmine.js +0 -670
  528. package/test/test/externs/karma.js +0 -26
  529. package/test/test/externs/require.js +0 -21
  530. package/test/test/externs/sprintf.js +0 -18
  531. package/test/test/namespace.js +0 -10
  532. package/test/test/util/canned_idb.js +0 -379
  533. package/test/test/util/cea_utils.js +0 -60
  534. package/test/test/util/dash_parser_util.js +0 -329
  535. package/test/test/util/fake_ad.js +0 -321
  536. package/test/test/util/fake_ad_manager.js +0 -122
  537. package/test/test/util/fake_demo_main.js +0 -144
  538. package/test/test/util/fake_drm_engine.js +0 -103
  539. package/test/test/util/fake_media_source_engine.js +0 -464
  540. package/test/test/util/fake_networking_engine.js +0 -381
  541. package/test/test/util/fake_segment_prefetch.js +0 -84
  542. package/test/test/util/fake_text_displayer.js +0 -60
  543. package/test/test/util/id3_generator.js +0 -100
  544. package/test/test/util/indexeddb_utils.js +0 -124
  545. package/test/test/util/jasmine_fetch.js +0 -382
  546. package/test/test/util/layout_tests.js +0 -434
  547. package/test/test/util/loader.js +0 -88
  548. package/test/test/util/manifest_generator.js +0 -705
  549. package/test/test/util/manifest_parser_util.js +0 -101
  550. package/test/test/util/mss_parser_util.js +0 -119
  551. package/test/test/util/offline_utils.js +0 -105
  552. package/test/test/util/simple_fakes.js +0 -535
  553. package/test/test/util/stream_generator.js +0 -676
  554. package/test/test/util/streaming_engine_util.js +0 -506
  555. package/test/test/util/test_scheme.js +0 -778
  556. package/test/test/util/ttml_utils.js +0 -77
  557. package/test/test/util/ui_utils.js +0 -183
  558. package/test/test/util/util.js +0 -374
  559. package/test/test/util/waiter.js +0 -406
  560. package/test/text/cue_integration.js +0 -51
  561. package/test/text/lrc_text_parser_unit.js +0 -98
  562. package/test/text/mp4_ttml_parser_unit.js +0 -171
  563. package/test/text/mp4_vtt_parser_unit.js +0 -195
  564. package/test/text/sbv_text_parser_unit.js +0 -81
  565. package/test/text/simple_text_displayer_unit.js +0 -468
  566. package/test/text/srt_text_parser_unit.js +0 -163
  567. package/test/text/ssa_text_parser_unit.js +0 -382
  568. package/test/text/text_displayer_layout_unit.js +0 -323
  569. package/test/text/text_engine_unit.js +0 -500
  570. package/test/text/text_track_integration.js +0 -186
  571. package/test/text/ttml_text_parser_unit.js +0 -2176
  572. package/test/text/ui_text_displayer_unit.js +0 -608
  573. package/test/text/vtt_text_parser_unit.js +0 -1363
  574. package/test/text/web_vtt_generator_unit.js +0 -144
  575. package/test/text/web_vtt_layout_integration.js +0 -524
  576. package/test/transmuxer/transmuxer_engine_integration.js +0 -69
  577. package/test/transmuxer/transmuxer_integration.js +0 -443
  578. package/test/ui/ad_ui_unit.js +0 -369
  579. package/test/ui/localization_unit.js +0 -508
  580. package/test/ui/ui_customization_unit.js +0 -208
  581. package/test/ui/ui_integration.js +0 -669
  582. package/test/ui/ui_unit.js +0 -902
  583. package/test/util/abortable_operation_unit.js +0 -624
  584. package/test/util/array_utils_unit.js +0 -58
  585. package/test/util/buffer_utils_unit.js +0 -185
  586. package/test/util/cmcd_manager_unit.js +0 -440
  587. package/test/util/content_steering_manager_unit.js +0 -427
  588. package/test/util/data_view_reader_unit.js +0 -254
  589. package/test/util/ebml_parser_unit.js +0 -297
  590. package/test/util/event_manager_unit.js +0 -185
  591. package/test/util/fake_event_target_unit.js +0 -123
  592. package/test/util/id3_utils_unit.js +0 -168
  593. package/test/util/iterables_unit.js +0 -68
  594. package/test/util/language_utils_unit.js +0 -240
  595. package/test/util/manifest_parser_utils_unit.js +0 -55
  596. package/test/util/mime_utils_unit.js +0 -64
  597. package/test/util/mp4_box_parsers_unit.js +0 -246
  598. package/test/util/mp4_parser_unit.js +0 -373
  599. package/test/util/multi_map_unit.js +0 -94
  600. package/test/util/object_utils_unit.js +0 -79
  601. package/test/util/periods_unit.js +0 -1623
  602. package/test/util/pssh_unit.js +0 -226
  603. package/test/util/state_history_unit.js +0 -101
  604. package/test/util/stream_utils_unit.js +0 -1068
  605. package/test/util/string_utils_unit.js +0 -166
  606. package/test/util/text_parser_unit.js +0 -165
  607. package/test/util/ts_parser_unit.js +0 -77
  608. package/test/util/xml_utils_unit.js +0 -444
@@ -1,1512 +0,0 @@
1
- /*! @license
2
- * Shaka Player
3
- * Copyright 2016 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- /**
8
- * @typedef {{
9
- * length: number,
10
- * start: jasmine.Spy,
11
- * end: jasmine.Spy
12
- * }}
13
- */
14
- let MockTimeRanges;
15
-
16
-
17
- /**
18
- * @typedef {{
19
- * abort: jasmine.Spy,
20
- * appendBuffer: jasmine.Spy,
21
- * remove: jasmine.Spy,
22
- * updating: boolean,
23
- * addEventListener: jasmine.Spy,
24
- * removeEventListener: jasmine.Spy,
25
- * buffered: (MockTimeRanges|TimeRanges),
26
- * timestampOffset: number,
27
- * appendWindowEnd: number,
28
- * updateend: function(),
29
- * error: function(),
30
- * mode: string
31
- * }}
32
- */
33
- let MockSourceBuffer;
34
-
35
-
36
- describe('MediaSourceEngine', () => {
37
- const Util = shaka.test.Util;
38
- const ContentType = shaka.util.ManifestParserUtils.ContentType;
39
-
40
- const originalIsTypeSupported = window.MediaSource.isTypeSupported;
41
- const originalTextEngine = shaka.text.TextEngine;
42
- const originalCreateMediaSource =
43
- // eslint-disable-next-line no-restricted-syntax
44
- shaka.media.MediaSourceEngine.prototype.createMediaSource;
45
-
46
- const originalFindTransmuxer =
47
- shaka.transmuxer.TransmuxerEngine.findTransmuxer;
48
- const originalConvertCodecs =
49
- shaka.transmuxer.TransmuxerEngine.convertCodecs;
50
- const originalIsSupported =
51
- shaka.transmuxer.TransmuxerEngine.isSupported;
52
-
53
- // Jasmine Spies don't handle toHaveBeenCalledWith well with objects, so use
54
- // some numbers instead.
55
- const buffer = /** @type {!ArrayBuffer} */ (/** @type {?} */ (1));
56
- const buffer2 = /** @type {!ArrayBuffer} */ (/** @type {?} */ (2));
57
- const buffer3 = /** @type {!ArrayBuffer} */ (/** @type {?} */ (3));
58
-
59
- const fakeVideoStream = {mimeType: 'video/mp4', drmInfos: [{}]};
60
- const fakeAudioStream = {mimeType: 'audio/mp4', drmInfos: []};
61
- const fakeTextStream = {mimeType: 'text/mp4', drmInfos: []};
62
- const fakeTransportStream = {mimeType: 'tsMimetype', drmInfos: []};
63
-
64
- /** @type {shaka.extern.Stream} */
65
- const fakeStream = shaka.test.StreamingEngineUtil.createMockVideoStream(1);
66
-
67
- let audioSourceBuffer;
68
- let videoSourceBuffer;
69
- let mockVideo;
70
-
71
- /** @type {HTMLMediaElement} */
72
- let video;
73
- let mockMediaSource;
74
-
75
- let mockTextEngine;
76
- /** @type {!shaka.test.FakeTextDisplayer} */
77
- let mockTextDisplayer;
78
- /** @type {!shaka.test.FakeClosedCaptionParser} */
79
- let mockClosedCaptionParser;
80
- /** @type {!shaka.test.FakeTransmuxer} */
81
- let mockTransmuxer;
82
-
83
- /** @type {!jasmine.Spy} */
84
- let createMediaSourceSpy;
85
- /** @type {!jasmine.Spy} */
86
- let requiresEncryptionInfoInAllInitSegmentsSpy;
87
- /** @type {!jasmine.Spy} */
88
- let fakeEncryptionSpy;
89
-
90
- /** @type {!shaka.media.MediaSourceEngine} */
91
- let mediaSourceEngine;
92
-
93
- beforeAll(() => {
94
- // Since this is not an integration test, we don't want MediaSourceEngine to
95
- // fail assertions based on browser support for types. Pretend that all
96
- // video and audio types are supported.
97
- window.MediaSource.isTypeSupported = (mimeType) => {
98
- const type = mimeType.split('/')[0];
99
- return type == 'video' || type == 'audio';
100
- };
101
- });
102
-
103
- afterAll(() => {
104
- window.MediaSource.isTypeSupported = originalIsTypeSupported;
105
- shaka.transmuxer.TransmuxerEngine.findTransmuxer =
106
- originalFindTransmuxer;
107
- shaka.transmuxer.TransmuxerEngine.convertCodecs =
108
- originalConvertCodecs;
109
- shaka.transmuxer.TransmuxerEngine.isSupported =
110
- originalIsSupported;
111
- });
112
-
113
- beforeEach(/** @suppress {invalidCasts} */ () => {
114
- audioSourceBuffer = createMockSourceBuffer();
115
- videoSourceBuffer = createMockSourceBuffer();
116
- mockMediaSource = createMockMediaSource();
117
- mockMediaSource.addSourceBuffer.and.callFake((mimeType) => {
118
- const type = mimeType.split('/')[0];
119
- const buffer = type == 'audio' ? audioSourceBuffer : videoSourceBuffer;
120
- // reset buffer params
121
- buffer.timestampOffset = 0;
122
- buffer.appendWindowEnd = Infinity;
123
- buffer.appendWindowStart = 0;
124
-
125
- return buffer;
126
- });
127
- mockTransmuxer = new shaka.test.FakeTransmuxer();
128
- shaka.transmuxer.TransmuxerEngine.findTransmuxer =
129
- (mimeType) => {
130
- return () => mockTransmuxer;
131
- };
132
- shaka.transmuxer.TransmuxerEngine.convertCodecs =
133
- (mimeType, contentType) => {
134
- return 'video/mp4; codecs="avc1.42E01E"';
135
- };
136
- shaka.transmuxer.TransmuxerEngine.isSupported =
137
- (mimeType, contentType) => {
138
- return mimeType == 'tsMimetype';
139
- };
140
-
141
- shaka.text.TextEngine = createMockTextEngineCtor();
142
-
143
- createMediaSourceSpy = jasmine.createSpy('createMediaSource');
144
- createMediaSourceSpy.and.callFake((p) => {
145
- p.resolve();
146
- return mockMediaSource;
147
- });
148
- // eslint-disable-next-line no-restricted-syntax
149
- shaka.media.MediaSourceEngine.prototype.createMediaSource =
150
- Util.spyFunc(createMediaSourceSpy);
151
-
152
- requiresEncryptionInfoInAllInitSegmentsSpy = spyOn(shaka.util.Platform,
153
- 'requiresEncryptionInfoInAllInitSegments').and.returnValue(false);
154
-
155
- fakeEncryptionSpy = spyOn(shaka.media.ContentWorkarounds, 'fakeEncryption')
156
- .and.callFake((data) => data + 100);
157
-
158
- // MediaSourceEngine uses video to:
159
- // - set src attribute
160
- // - read error codes when operations fail
161
- // - seek to flush the pipeline on some platforms
162
- // - check buffered.length to assert that flushing the pipeline is okay
163
- mockVideo = {
164
- src: '',
165
- error: null,
166
- currentTime: 0,
167
- buffered: {
168
- length: 0,
169
- },
170
- removeAttribute: /** @this {HTMLVideoElement} */ (attr) => {
171
- // Only called with attr == 'src'.
172
- // This assertion alerts us if the requirements for this mock change.
173
- goog.asserts.assert(attr == 'src', 'Unexpected removeAttribute() call');
174
- mockVideo.src = '';
175
- },
176
- addEventListener: jasmine.createSpy('addVideoEventListener'),
177
- load: /** @this {HTMLVideoElement} */ () => {
178
- // This assertion alerts us if the requirements for this mock change.
179
- goog.asserts.assert(mockVideo.src == '', 'Unexpected load() call');
180
- },
181
- play: jasmine.createSpy('play'),
182
- };
183
- video = /** @type {HTMLMediaElement} */(mockVideo);
184
- mockClosedCaptionParser = new shaka.test.FakeClosedCaptionParser();
185
- mockTextDisplayer = new shaka.test.FakeTextDisplayer();
186
- mediaSourceEngine = new shaka.media.MediaSourceEngine(
187
- video,
188
- mockTextDisplayer);
189
- mediaSourceEngine.getCaptionParser = () => {
190
- return mockClosedCaptionParser;
191
- };
192
- const config = shaka.util.PlayerConfiguration.createDefault().mediaSource;
193
- mediaSourceEngine.configure(config);
194
- });
195
-
196
- afterEach(() => {
197
- mockTextEngine = null;
198
- shaka.text.TextEngine = originalTextEngine;
199
- // eslint-disable-next-line no-restricted-syntax
200
- shaka.media.MediaSourceEngine.prototype.createMediaSource =
201
- originalCreateMediaSource;
202
- });
203
-
204
- describe('constructor', () => {
205
- const originalCreateObjectURL =
206
- shaka.media.MediaSourceEngine.createObjectURL;
207
- const originalRevokeObjectURL = window.URL.revokeObjectURL;
208
- const originalMediaSource = window.MediaSource;
209
- /** @type {jasmine.Spy} */
210
- let createObjectURLSpy;
211
- /** @type {jasmine.Spy} */
212
- let revokeObjectURLSpy;
213
-
214
- beforeEach(async () => {
215
- // Mock out MediaSource so we can test the production version of
216
- // createMediaSource. To do this, the test must call the
217
- // MediaSourceEngine constructor again. The call beforeEach was done with
218
- // a mocked createMediaSource.
219
- createMediaSourceSpy.calls.reset();
220
- createMediaSourceSpy.and.callFake(originalCreateMediaSource);
221
-
222
- createObjectURLSpy = jasmine.createSpy('createObjectURL');
223
- createObjectURLSpy.and.returnValue('blob:foo');
224
- shaka.media.MediaSourceEngine.createObjectURL =
225
- Util.spyFunc(createObjectURLSpy);
226
-
227
- revokeObjectURLSpy = jasmine.createSpy('revokeObjectURL');
228
- window.URL.revokeObjectURL = Util.spyFunc(revokeObjectURLSpy);
229
-
230
- const mediaSourceSpy = jasmine.createSpy('MediaSource');
231
- // Because this is a fake constructor, it must be callable with "new".
232
- // This will cause jasmine to invoke the callback with "new" as well, so
233
- // the callback must be a "function". This detail is hidden when babel
234
- // transpiles the tests.
235
- // eslint-disable-next-line prefer-arrow-callback, no-restricted-syntax
236
- mediaSourceSpy.and.callFake(function() {
237
- return mockMediaSource;
238
- });
239
- window.MediaSource = Util.spyFunc(mediaSourceSpy);
240
-
241
- await mediaSourceEngine.destroy();
242
- });
243
-
244
- afterAll(() => {
245
- shaka.media.MediaSourceEngine.createObjectURL = originalCreateObjectURL;
246
- window.MediaSource = originalMediaSource;
247
- window.URL.revokeObjectURL = originalRevokeObjectURL;
248
- });
249
-
250
- it('creates a MediaSource object and sets video.src', () => {
251
- mediaSourceEngine = new shaka.media.MediaSourceEngine(
252
- video,
253
- new shaka.test.FakeTextDisplayer());
254
-
255
- expect(createMediaSourceSpy).toHaveBeenCalled();
256
- expect(createObjectURLSpy).toHaveBeenCalled();
257
- expect(mockVideo.src).toBe('blob:foo');
258
- });
259
-
260
- it('revokes object URL after MediaSource opens', () => {
261
- let onSourceOpenListener;
262
-
263
- mockMediaSource.addEventListener.and.callFake((event, callback, _) => {
264
- if (event == 'sourceopen') {
265
- onSourceOpenListener = callback;
266
- }
267
- });
268
-
269
- mediaSourceEngine = new shaka.media.MediaSourceEngine(
270
- video,
271
- new shaka.test.FakeTextDisplayer());
272
-
273
- expect(mockMediaSource.addEventListener).toHaveBeenCalledTimes(1);
274
- expect(mockMediaSource.addEventListener.calls.mostRecent().args[0])
275
- .toBe('sourceopen');
276
- expect(typeof onSourceOpenListener).toBe(typeof Function);
277
-
278
- onSourceOpenListener();
279
-
280
- expect(revokeObjectURLSpy).toHaveBeenCalledWith('blob:foo');
281
- });
282
- });
283
-
284
- describe('init', () => {
285
- it('creates SourceBuffers for the given types', async () => {
286
- const initObject = new Map();
287
- initObject.set(ContentType.AUDIO, fakeAudioStream);
288
- initObject.set(ContentType.VIDEO, fakeVideoStream);
289
- await mediaSourceEngine.init(initObject, false);
290
- expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledWith('audio/mp4');
291
- expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledWith('video/mp4');
292
- expect(shaka.text.TextEngine).not.toHaveBeenCalled();
293
- });
294
-
295
- it('creates TextEngines for text types', async () => {
296
- const initObject = new Map();
297
- initObject.set(ContentType.TEXT, fakeTextStream);
298
- await mediaSourceEngine.init(initObject, false);
299
- expect(mockMediaSource.addSourceBuffer).not.toHaveBeenCalled();
300
- expect(shaka.text.TextEngine).toHaveBeenCalled();
301
- });
302
- });
303
-
304
- describe('bufferStart and bufferEnd', () => {
305
- beforeEach(async () => {
306
- const initObject = new Map();
307
- initObject.set(ContentType.AUDIO, fakeAudioStream);
308
- initObject.set(ContentType.TEXT, fakeTextStream);
309
- await mediaSourceEngine.init(initObject, false);
310
- });
311
-
312
- it('returns correct timestamps for one range', () => {
313
- audioSourceBuffer.buffered = createFakeBuffered([{start: 0, end: 10}]);
314
-
315
- expect(mediaSourceEngine.bufferStart(ContentType.AUDIO)).toBeCloseTo(0);
316
- expect(mediaSourceEngine.bufferEnd(ContentType.AUDIO)).toBeCloseTo(10);
317
- });
318
-
319
- it('returns correct timestamps for multiple ranges', () => {
320
- audioSourceBuffer.buffered =
321
- createFakeBuffered([{start: 5, end: 10}, {start: 20, end: 30}]);
322
-
323
- expect(mediaSourceEngine.bufferStart(ContentType.AUDIO)).toBeCloseTo(5);
324
- expect(mediaSourceEngine.bufferEnd(ContentType.AUDIO)).toBeCloseTo(30);
325
- });
326
-
327
- it('returns null if there are no ranges', () => {
328
- audioSourceBuffer.buffered = createFakeBuffered([]);
329
-
330
- expect(mediaSourceEngine.bufferStart(ContentType.AUDIO)).toBeNull();
331
- expect(mediaSourceEngine.bufferEnd(ContentType.AUDIO)).toBeNull();
332
- });
333
-
334
- it('will forward to TextEngine', () => {
335
- mockTextEngine.bufferStart.and.returnValue(10);
336
- mockTextEngine.bufferEnd.and.returnValue(20);
337
-
338
- expect(mockTextEngine.bufferStart).not.toHaveBeenCalled();
339
- expect(mediaSourceEngine.bufferStart(ContentType.TEXT)).toBe(10);
340
- expect(mockTextEngine.bufferStart).toHaveBeenCalled();
341
-
342
- expect(mockTextEngine.bufferEnd).not.toHaveBeenCalled();
343
- expect(mediaSourceEngine.bufferEnd(ContentType.TEXT)).toBe(20);
344
- expect(mockTextEngine.bufferEnd).toHaveBeenCalled();
345
- });
346
- });
347
-
348
- describe('bufferedAheadOf', () => {
349
- beforeEach(async () => {
350
- const initObject = new Map();
351
- initObject.set(ContentType.AUDIO, fakeAudioStream);
352
- initObject.set(ContentType.TEXT, fakeTextStream);
353
- await mediaSourceEngine.init(initObject, false);
354
- });
355
-
356
- it('returns the amount of data ahead of the given position', () => {
357
- audioSourceBuffer.buffered = createFakeBuffered([{start: 0, end: 10}]);
358
-
359
- expect(mediaSourceEngine.bufferedAheadOf(ContentType.AUDIO, 0))
360
- .toBeCloseTo(10);
361
- expect(mediaSourceEngine.bufferedAheadOf(ContentType.AUDIO, 5))
362
- .toBeCloseTo(5);
363
- expect(mediaSourceEngine.bufferedAheadOf(ContentType.AUDIO, 9.9))
364
- .toBeCloseTo(0.1);
365
- });
366
-
367
- it('returns zero when given an unbuffered time', () => {
368
- audioSourceBuffer.buffered = createFakeBuffered([{start: 5, end: 10}]);
369
-
370
- expect(mediaSourceEngine.bufferedAheadOf(ContentType.AUDIO, 10))
371
- .toBeCloseTo(0);
372
- expect(mediaSourceEngine.bufferedAheadOf(ContentType.AUDIO, 100))
373
- .toBeCloseTo(0);
374
- });
375
-
376
- it('returns the correct amount with multiple ranges', () => {
377
- audioSourceBuffer.buffered =
378
- createFakeBuffered([{start: 1, end: 3}, {start: 6, end: 10}]);
379
-
380
- // in range 0
381
- expect(mediaSourceEngine.bufferedAheadOf(ContentType.AUDIO, 1))
382
- .toBeCloseTo(6);
383
- expect(mediaSourceEngine.bufferedAheadOf(ContentType.AUDIO, 2.5))
384
- .toBeCloseTo(4.5);
385
-
386
- // between range 0 and 1
387
- expect(mediaSourceEngine.bufferedAheadOf(ContentType.AUDIO, 5))
388
- .toBeCloseTo(4);
389
-
390
- // in range 1
391
- expect(mediaSourceEngine.bufferedAheadOf(ContentType.AUDIO, 6))
392
- .toBeCloseTo(4);
393
- expect(mediaSourceEngine.bufferedAheadOf(ContentType.AUDIO, 9.9))
394
- .toBeCloseTo(0.1);
395
- });
396
-
397
- it('will forward to TextEngine', () => {
398
- mockTextEngine.bufferedAheadOf.and.returnValue(10);
399
-
400
- expect(mockTextEngine.bufferedAheadOf).not.toHaveBeenCalled();
401
- expect(mediaSourceEngine.bufferedAheadOf(ContentType.TEXT, 5)).toBe(10);
402
- expect(mockTextEngine.bufferedAheadOf).toHaveBeenCalledWith(5);
403
- });
404
- });
405
-
406
- describe('appendBuffer', () => {
407
- beforeEach(async () => {
408
- captureEvents(audioSourceBuffer, ['updateend', 'error']);
409
- captureEvents(videoSourceBuffer, ['updateend', 'error']);
410
- const initObject = new Map();
411
- initObject.set(ContentType.AUDIO, fakeAudioStream);
412
- initObject.set(ContentType.VIDEO, fakeVideoStream);
413
- initObject.set(ContentType.TEXT, fakeTextStream);
414
- await mediaSourceEngine.init(initObject, false);
415
- });
416
-
417
- it('should apply fake encryption by default', async () => {
418
- requiresEncryptionInfoInAllInitSegmentsSpy.and.returnValue(true);
419
-
420
- const p = mediaSourceEngine.appendBuffer(
421
- ContentType.VIDEO, buffer, null, fakeStream,
422
- /* hasClosedCaptions= */ false);
423
-
424
- expect(fakeEncryptionSpy).toHaveBeenCalled();
425
-
426
- expect(videoSourceBuffer.appendBuffer)
427
- .toHaveBeenCalledWith((buffer + 100));
428
- videoSourceBuffer.updateend();
429
-
430
- await p;
431
- });
432
-
433
- it('should not apply fake encryption when config is off', async () => {
434
- requiresEncryptionInfoInAllInitSegmentsSpy.and.returnValue(true);
435
-
436
- const config = shaka.util.PlayerConfiguration.createDefault().mediaSource;
437
- config.insertFakeEncryptionInInit = false;
438
-
439
- mediaSourceEngine.configure(config);
440
-
441
- const p = mediaSourceEngine.appendBuffer(
442
- ContentType.VIDEO, buffer, null, fakeStream,
443
- /* hasClosedCaptions= */ false);
444
-
445
- expect(fakeEncryptionSpy).not.toHaveBeenCalled();
446
-
447
- expect(videoSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
448
- videoSourceBuffer.updateend();
449
-
450
- await p;
451
- });
452
-
453
- it('appends the given data', async () => {
454
- const p = mediaSourceEngine.appendBuffer(
455
- ContentType.AUDIO, buffer, null, fakeStream,
456
- /* hasClosedCaptions= */ false);
457
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
458
- audioSourceBuffer.updateend();
459
- await p;
460
- });
461
-
462
- it('rejects promise when operation throws', async () => {
463
- audioSourceBuffer.appendBuffer.and.throwError('fail!');
464
- mockVideo.error = {code: 5, message: 'something failed'};
465
- const expected = Util.jasmineError(new shaka.util.Error(
466
- shaka.util.Error.Severity.CRITICAL,
467
- shaka.util.Error.Category.MEDIA,
468
- shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_THREW,
469
- jasmine.objectContaining({message: 'fail!'}),
470
- {code: 5, message: 'something failed'}));
471
- await expectAsync(
472
- mediaSourceEngine.appendBuffer(
473
- ContentType.AUDIO, buffer, null, fakeStream,
474
- /* hasClosedCaptions= */ false))
475
- .toBeRejectedWith(expected);
476
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
477
- });
478
-
479
- it('rejects promise when op. throws QuotaExceededError', async () => {
480
- const fakeDOMException = {name: 'QuotaExceededError'};
481
- audioSourceBuffer.appendBuffer.and.callFake(() => {
482
- throw fakeDOMException;
483
- });
484
- mockVideo.error = {code: 5};
485
- const expected = Util.jasmineError(new shaka.util.Error(
486
- shaka.util.Error.Severity.CRITICAL,
487
- shaka.util.Error.Category.MEDIA,
488
- shaka.util.Error.Code.QUOTA_EXCEEDED_ERROR,
489
- ContentType.AUDIO));
490
- await expectAsync(
491
- mediaSourceEngine.appendBuffer(
492
- ContentType.AUDIO, buffer, null, fakeStream,
493
- /* hasClosedCaptions= */ false))
494
- .toBeRejectedWith(expected);
495
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
496
- });
497
-
498
- it('handles QuotaExceededError for pending operations', async () => {
499
- const fakeDOMException = {name: 'QuotaExceededError'};
500
- audioSourceBuffer.appendBuffer.and.callFake(() => {
501
- if (audioSourceBuffer.appendBuffer.calls.count() > 1) {
502
- throw fakeDOMException;
503
- }
504
- });
505
- mockVideo.error = {code: 5};
506
- const expected = Util.jasmineError(new shaka.util.Error(
507
- shaka.util.Error.Severity.CRITICAL,
508
- shaka.util.Error.Category.MEDIA,
509
- shaka.util.Error.Code.QUOTA_EXCEEDED_ERROR,
510
- ContentType.AUDIO));
511
-
512
- const p1 = mediaSourceEngine.appendBuffer(
513
- ContentType.AUDIO, buffer, null, fakeStream,
514
- /* hasClosedCaptions= */ false);
515
- const p2 = mediaSourceEngine.appendBuffer(
516
- ContentType.AUDIO, buffer, null, fakeStream,
517
- /* hasClosedCaptions= */ false);
518
- audioSourceBuffer.updateend();
519
- await expectAsync(p1).toBeResolved();
520
- await expectAsync(p2).toBeRejectedWith(expected);
521
- });
522
-
523
- it('rejects the promise if this operation fails async', async () => {
524
- mockVideo.error = {code: 5};
525
- const p = mediaSourceEngine.appendBuffer(
526
- ContentType.AUDIO, buffer, null, fakeStream,
527
- /* hasClosedCaptions= */ false);
528
- audioSourceBuffer.error();
529
- audioSourceBuffer.updateend();
530
-
531
- const expected = Util.jasmineError(new shaka.util.Error(
532
- shaka.util.Error.Severity.CRITICAL,
533
- shaka.util.Error.Category.MEDIA,
534
- shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_FAILED,
535
- 5));
536
- await expectAsync(p).toBeRejectedWith(expected);
537
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
538
- });
539
-
540
- it('queues operations on a single SourceBuffer', async () => {
541
- /** @type {!shaka.test.StatusPromise} */
542
- const p1 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
543
- ContentType.AUDIO, buffer, null, fakeStream,
544
- /* hasClosedCaptions= */ false));
545
- /** @type {!shaka.test.StatusPromise} */
546
- const p2 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
547
- ContentType.AUDIO, buffer2, null, fakeStream,
548
- /* hasClosedCaptions= */ false));
549
-
550
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
551
- expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalledWith(buffer2);
552
- expect(p1.status).toBe('pending');
553
- expect(p2.status).toBe('pending');
554
-
555
- audioSourceBuffer.updateend();
556
- await p1;
557
- expect(p2.status).toBe('pending');
558
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer2);
559
- audioSourceBuffer.updateend();
560
- await p2;
561
- });
562
-
563
- it('queues operations independently for different types', async () => {
564
- /** @type {!shaka.test.StatusPromise} */
565
- const p1 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
566
- ContentType.AUDIO, buffer, null, fakeStream,
567
- /* hasClosedCaptions= */ false));
568
- /** @type {!shaka.test.StatusPromise} */
569
- const p2 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
570
- ContentType.AUDIO, buffer2, null, fakeStream,
571
- /* hasClosedCaptions= */ false));
572
- /** @type {!shaka.test.StatusPromise} */
573
- const p3 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
574
- ContentType.VIDEO, buffer3, null, fakeStream,
575
- /* hasClosedCaptions= */ false));
576
-
577
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
578
- expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalledWith(buffer2);
579
- expect(videoSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer3);
580
- expect(p1.status).toBe('pending');
581
- expect(p2.status).toBe('pending');
582
- expect(p3.status).toBe('pending');
583
-
584
- audioSourceBuffer.updateend();
585
- videoSourceBuffer.updateend();
586
- // Wait a tick between each updateend() and the status check that follows.
587
- await p1;
588
- expect(p2.status).toBe('pending');
589
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer2);
590
- await p3;
591
- audioSourceBuffer.updateend();
592
- await p2;
593
- });
594
-
595
- it('continues if an operation throws', async () => {
596
- audioSourceBuffer.appendBuffer.and.callFake((value) => {
597
- if (value == 2) {
598
- // throw synchronously.
599
- throw new Error();
600
- } else {
601
- // complete successfully asynchronously.
602
- Promise.resolve().then(() => {
603
- audioSourceBuffer.updateend();
604
- });
605
- }
606
- });
607
-
608
- const p1 = mediaSourceEngine.appendBuffer(
609
- ContentType.AUDIO, buffer, null, fakeStream,
610
- /* hasClosedCaptions= */ false);
611
- const p2 = mediaSourceEngine.appendBuffer(
612
- ContentType.AUDIO, buffer2, null, fakeStream,
613
- /* hasClosedCaptions= */ false);
614
- const p3 = mediaSourceEngine.appendBuffer(
615
- ContentType.AUDIO, buffer3, null, fakeStream,
616
- /* hasClosedCaptions= */ false);
617
-
618
- await expectAsync(p1).toBeResolved();
619
- await expectAsync(p2).toBeRejected();
620
- await expectAsync(p3).toBeResolved();
621
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
622
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer2);
623
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer3);
624
- });
625
-
626
- it('forwards to TextEngine', async () => {
627
- const data = new ArrayBuffer(0);
628
- expect(mockTextEngine.appendBuffer).not.toHaveBeenCalled();
629
- const reference = dummyReference(0, 10);
630
- await mediaSourceEngine.appendBuffer(
631
- ContentType.TEXT, data, reference, fakeStream,
632
- /* hasClosedCaptions= */ false);
633
- expect(mockTextEngine.appendBuffer).toHaveBeenCalledWith(
634
- data, 0, 10, 'foo://bar');
635
- });
636
-
637
- it('appends transmuxed data', async () => {
638
- const initObject = new Map();
639
- initObject.set(ContentType.VIDEO, fakeTransportStream);
640
-
641
- const output = {
642
- data: new Uint8Array(1),
643
- captions: [{}],
644
- };
645
- mockTransmuxer.transmux.and.returnValue(Promise.resolve(output));
646
-
647
- const init = async () => {
648
- await mediaSourceEngine.init(initObject, false);
649
- await mediaSourceEngine.appendBuffer(
650
- ContentType.VIDEO, buffer, null, fakeStream,
651
- /* hasClosedCaptions= */ false);
652
- expect(videoSourceBuffer.appendBuffer).toHaveBeenCalled();
653
- };
654
-
655
- // The 'updateend' event fires once the data is done appending to the
656
- // media source. We only append to the media source once transmuxing is
657
- // done. Since transmuxing is done using Promises, we need to delay the
658
- // event until MediaSourceEngine calls appendBuffer.
659
- const delay = async () => {
660
- await Util.shortDelay();
661
- videoSourceBuffer.updateend();
662
- };
663
- await Promise.all([init(), delay()]);
664
- });
665
-
666
- it('appends parsed closed captions from CaptionParser', async () => {
667
- const initObject = new Map();
668
- initObject.set(ContentType.VIDEO, fakeVideoStream);
669
-
670
- mockClosedCaptionParser.parseFromSpy.and.callFake((data) => {
671
- return ['foo', 'bar'];
672
- });
673
-
674
- await mediaSourceEngine.init(initObject, false);
675
-
676
- // Initialize the closed caption parser.
677
- const appendInit = mediaSourceEngine.appendBuffer(
678
- ContentType.VIDEO, buffer, null, fakeStream,
679
- /* hasClosedCaptions= */ true);
680
- // In MediaSourceEngine, appendBuffer() is async and Promise-based, but
681
- // at the browser level, it's event-based.
682
- // MediaSourceEngine waits for the 'updateend' event from the
683
- // SourceBuffer, and uses that to resolve the appendBuffer Promise.
684
- // Here, we must trigger the event on the fake/mock SourceBuffer before
685
- // waiting on the appendBuffer Promise.
686
- videoSourceBuffer.updateend();
687
- await appendInit;
688
-
689
- expect(mockTextEngine.storeAndAppendClosedCaptions).not
690
- .toHaveBeenCalled();
691
- // Parse and append the closed captions embedded in video stream.
692
- const reference = dummyReference(0, 1000);
693
- const appendVideo = mediaSourceEngine.appendBuffer(
694
- ContentType.VIDEO, buffer, reference, fakeStream,
695
- /* hasClosedCaptions= */ true);
696
- videoSourceBuffer.updateend();
697
- await appendVideo;
698
-
699
- expect(mockTextEngine.storeAndAppendClosedCaptions).toHaveBeenCalled();
700
- });
701
-
702
- it('sets timestampOffset on adaptations in sequence mode', async () => {
703
- const initObject = new Map();
704
- initObject.set(ContentType.VIDEO, fakeVideoStream);
705
- videoSourceBuffer.mode = 'sequence';
706
-
707
- await mediaSourceEngine.init(initObject, /* sequenceMode= */ true);
708
-
709
- expect(videoSourceBuffer.timestampOffset).toBe(0);
710
-
711
- // Mocks appending a segment from a newly adapted variant with a 0.50
712
- // second misalignment from the old variant.
713
- const reference = dummyReference(0, 1000);
714
- reference.startTime = 0.50;
715
- const appendVideo = mediaSourceEngine.appendBuffer(
716
- ContentType.VIDEO, buffer, reference, fakeStream,
717
- /* hasClosedCaptions= */ false,
718
- /* seeked= */ false, /* adaptation= */ true);
719
- videoSourceBuffer.updateend();
720
- await appendVideo;
721
-
722
- expect(videoSourceBuffer.timestampOffset).toBe(0.50);
723
- });
724
- });
725
-
726
- describe('remove', () => {
727
- beforeEach(async () => {
728
- captureEvents(audioSourceBuffer, ['updateend', 'error']);
729
- captureEvents(videoSourceBuffer, ['updateend', 'error']);
730
- const initObject = new Map();
731
- initObject.set(ContentType.AUDIO, fakeAudioStream);
732
- initObject.set(ContentType.VIDEO, fakeVideoStream);
733
- initObject.set(ContentType.TEXT, fakeTextStream);
734
- await mediaSourceEngine.init(initObject, false);
735
- });
736
-
737
- it('removes the given data', async () => {
738
- const p = mediaSourceEngine.remove(ContentType.AUDIO, 1, 5);
739
- audioSourceBuffer.updateend();
740
-
741
- await p;
742
- expect(audioSourceBuffer.remove).toHaveBeenCalledWith(1, 5);
743
- });
744
-
745
- it('rejects promise when operation throws', async () => {
746
- audioSourceBuffer.remove.and.throwError('fail!');
747
- mockVideo.error = {code: 5};
748
-
749
- const expected = Util.jasmineError(new shaka.util.Error(
750
- shaka.util.Error.Severity.CRITICAL,
751
- shaka.util.Error.Category.MEDIA,
752
- shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_THREW,
753
- jasmine.objectContaining({message: 'fail!'}),
754
- {code: 5}));
755
- await expectAsync(mediaSourceEngine.remove(ContentType.AUDIO, 1, 5))
756
- .toBeRejectedWith(expected);
757
- expect(audioSourceBuffer.remove).toHaveBeenCalledWith(1, 5);
758
- });
759
-
760
- it('rejects the promise if this operation fails async', async () => {
761
- mockVideo.error = {code: 5};
762
- const p = mediaSourceEngine.remove(ContentType.AUDIO, 1, 5);
763
- audioSourceBuffer.error();
764
- audioSourceBuffer.updateend();
765
-
766
- const expected = Util.jasmineError(new shaka.util.Error(
767
- shaka.util.Error.Severity.CRITICAL,
768
- shaka.util.Error.Category.MEDIA,
769
- shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_FAILED,
770
- 5));
771
- await expectAsync(p).toBeRejectedWith(expected);
772
- expect(audioSourceBuffer.remove).toHaveBeenCalledWith(1, 5);
773
- });
774
-
775
- it('queues operations on a single SourceBuffer', async () => {
776
- /** @type {!shaka.test.StatusPromise} */
777
- const p1 = new shaka.test.StatusPromise(
778
- mediaSourceEngine.remove(ContentType.AUDIO, 1, 5));
779
- /** @type {!shaka.test.StatusPromise} */
780
- const p2 = new shaka.test.StatusPromise(
781
- mediaSourceEngine.remove(ContentType.AUDIO, 6, 10));
782
-
783
- expect(audioSourceBuffer.remove).toHaveBeenCalledWith(1, 5);
784
- expect(audioSourceBuffer.remove).not.toHaveBeenCalledWith(6, 10);
785
- expect(p1.status).toBe('pending');
786
- expect(p2.status).toBe('pending');
787
-
788
- audioSourceBuffer.updateend();
789
- await p1;
790
- expect(p2.status).toBe('pending');
791
- expect(audioSourceBuffer.remove).toHaveBeenCalledWith(6, 10);
792
- audioSourceBuffer.updateend();
793
- await p2;
794
- });
795
-
796
- it('queues operations independently for different types', async () => {
797
- /** @type {!shaka.test.StatusPromise} */
798
- const p1 = new shaka.test.StatusPromise(
799
- mediaSourceEngine.remove(ContentType.AUDIO, 1, 5));
800
- /** @type {!shaka.test.StatusPromise} */
801
- const p2 = new shaka.test.StatusPromise(
802
- mediaSourceEngine.remove(ContentType.AUDIO, 6, 10));
803
- /** @type {!shaka.test.StatusPromise} */
804
- const p3 = new shaka.test.StatusPromise(
805
- mediaSourceEngine.remove(ContentType.VIDEO, 3, 8));
806
-
807
- expect(audioSourceBuffer.remove).toHaveBeenCalledWith(1, 5);
808
- expect(audioSourceBuffer.remove).not.toHaveBeenCalledWith(6, 10);
809
- expect(videoSourceBuffer.remove).toHaveBeenCalledWith(3, 8);
810
- expect(p1.status).toBe('pending');
811
- expect(p2.status).toBe('pending');
812
- expect(p3.status).toBe('pending');
813
-
814
- audioSourceBuffer.updateend();
815
- videoSourceBuffer.updateend();
816
- await p1;
817
- expect(p2.status).toBe('pending');
818
- expect(audioSourceBuffer.remove).toHaveBeenCalledWith(6, 10);
819
- await p3;
820
- audioSourceBuffer.updateend();
821
- await p2;
822
- });
823
-
824
- it('continues if an operation throws', async () => {
825
- audioSourceBuffer.remove.and.callFake((start, end) => {
826
- if (start == 2) {
827
- // throw synchronously.
828
- throw new Error();
829
- } else {
830
- // complete successfully asynchronously.
831
- Promise.resolve().then(() => {
832
- audioSourceBuffer.updateend();
833
- });
834
- }
835
- });
836
-
837
- const p1 = mediaSourceEngine.remove(ContentType.AUDIO, 1, 2);
838
- const p2 = mediaSourceEngine.remove(ContentType.AUDIO, 2, 3);
839
- const p3 = mediaSourceEngine.remove(ContentType.AUDIO, 3, 4);
840
-
841
- await expectAsync(p1).toBeResolved();
842
- await expectAsync(p2).toBeRejected();
843
- await expectAsync(p3).toBeResolved();
844
- expect(audioSourceBuffer.remove).toHaveBeenCalledWith(1, 2);
845
- expect(audioSourceBuffer.remove).toHaveBeenCalledWith(2, 3);
846
- expect(audioSourceBuffer.remove).toHaveBeenCalledWith(3, 4);
847
- });
848
-
849
- it('will forward to TextEngine', async () => {
850
- expect(mockTextEngine.remove).not.toHaveBeenCalled();
851
- await mediaSourceEngine.remove(ContentType.TEXT, 10, 20);
852
- expect(mockTextEngine.remove).toHaveBeenCalledWith(10, 20);
853
- });
854
- });
855
-
856
- describe('clear', () => {
857
- beforeEach(async () => {
858
- captureEvents(audioSourceBuffer, ['updateend', 'error']);
859
- captureEvents(videoSourceBuffer, ['updateend', 'error']);
860
- const initObject = new Map();
861
- initObject.set(ContentType.AUDIO, fakeAudioStream);
862
- initObject.set(ContentType.VIDEO, fakeVideoStream);
863
- initObject.set(ContentType.TEXT, fakeTextStream);
864
- await mediaSourceEngine.init(initObject, false);
865
- });
866
-
867
- it('clears the given data', async () => {
868
- mockMediaSource.durationGetter.and.returnValue(20);
869
- const p = mediaSourceEngine.clear(ContentType.AUDIO);
870
- audioSourceBuffer.updateend();
871
-
872
- await p;
873
- expect(audioSourceBuffer.remove).toHaveBeenCalledTimes(1);
874
- expect(audioSourceBuffer.remove.calls.argsFor(0)[0]).toBe(0);
875
- expect(audioSourceBuffer.remove.calls.argsFor(0)[1] >= 20).toBeTruthy();
876
- });
877
-
878
- it('does not seek', async () => {
879
- // We had a bug in which we got into a seek loop. Seeking caused
880
- // StreamingEngine to call clear(). Clearing triggered a pipeline flush
881
- // which was implemented by seeking. See issue #569.
882
-
883
- // This loop is difficult to test for directly.
884
-
885
- // A unit test on StreamingEngine would not suffice, since reproduction of
886
- // the bug would involve making the mock MediaSourceEngine seek on clear.
887
- // Since the fix was to remove the implicit seek, this behavior would then
888
- // be removed from the mock, which would render the test useless.
889
-
890
- // An integration test involving both StreamingEngine and MediaSourcEngine
891
- // would also be problematic. The bug involved a race, so it would be
892
- // difficult to reproduce the necessary timing. And if we succeeded, it
893
- // would be tough to detect that we were definitely in a seek loop, since
894
- // nothing was mocked.
895
-
896
- // So the best option seems to be to enforce that clear() does not result
897
- // in a seek. This can be done here, in a unit test on MediaSourceEngine.
898
- // It does not reproduce the seek loop, but it does ensure that the test
899
- // would fail if we ever reintroduced this behavior.
900
-
901
- const originalTime = 10;
902
- mockVideo.currentTime = originalTime;
903
-
904
- mockMediaSource.durationGetter.and.returnValue(20);
905
- const p = mediaSourceEngine.clear(ContentType.AUDIO);
906
- audioSourceBuffer.updateend();
907
-
908
- await p;
909
- expect(mockVideo.currentTime).toBe(originalTime);
910
- });
911
-
912
- it('will forward to TextEngine', async () => {
913
- expect(mockTextEngine.setTimestampOffset).not.toHaveBeenCalled();
914
- expect(mockTextEngine.setAppendWindow).not.toHaveBeenCalled();
915
- await mediaSourceEngine.setStreamProperties(ContentType.TEXT,
916
- /* timestampOffset= */ 10,
917
- /* appendWindowStart= */ 0,
918
- /* appendWindowEnd= */ 20,
919
- /* sequenceMode= */ false,
920
- fakeStream,
921
- /* streamsByType= */ new Map());
922
- expect(mockTextEngine.setTimestampOffset).toHaveBeenCalledWith(10);
923
- expect(mockTextEngine.setAppendWindow).toHaveBeenCalledWith(0, 20);
924
- });
925
- });
926
-
927
- describe('endOfStream', () => {
928
- beforeEach(async () => {
929
- captureEvents(audioSourceBuffer, ['updateend', 'error']);
930
- captureEvents(videoSourceBuffer, ['updateend', 'error']);
931
- const initObject = new Map();
932
- initObject.set(ContentType.AUDIO, fakeAudioStream);
933
- initObject.set(ContentType.VIDEO, fakeVideoStream);
934
- await mediaSourceEngine.init(initObject, false);
935
- });
936
-
937
- it('ends the MediaSource stream with the given reason', async () => {
938
- await mediaSourceEngine.endOfStream('foo');
939
- expect(mockMediaSource.endOfStream).toHaveBeenCalledWith('foo');
940
- });
941
-
942
- it('waits for all previous operations to complete', async () => {
943
- /** @type {!shaka.test.StatusPromise} */
944
- const p1 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
945
- ContentType.AUDIO, buffer, null, fakeStream,
946
- /* hasClosedCaptions= */ false));
947
- /** @type {!shaka.test.StatusPromise} */
948
- const p2 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
949
- ContentType.VIDEO, buffer, null, fakeStream,
950
- /* hasClosedCaptions= */ false));
951
- /** @type {!shaka.test.StatusPromise} */
952
- const p3 = new shaka.test.StatusPromise(mediaSourceEngine.endOfStream());
953
-
954
- expect(mockMediaSource.endOfStream).not.toHaveBeenCalled();
955
- expect(p1.status).toBe('pending');
956
- expect(p2.status).toBe('pending');
957
- expect(p3.status).toBe('pending');
958
-
959
- audioSourceBuffer.updateend();
960
- await p1;
961
- expect(p2.status).toBe('pending');
962
- expect(p3.status).toBe('pending');
963
- videoSourceBuffer.updateend();
964
- await p2;
965
- await p3;
966
- expect(mockMediaSource.endOfStream).toHaveBeenCalled();
967
- });
968
-
969
- it('makes subsequent operations wait', async () => {
970
- /** @type {!Promise} */
971
- const p1 = mediaSourceEngine.endOfStream();
972
- mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
973
- fakeStream, /* hasClosedCaptions= */ false);
974
- mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer, null,
975
- fakeStream, /* hasClosedCaptions= */ false);
976
- mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer2, null,
977
- fakeStream, /* hasClosedCaptions= */ false);
978
-
979
- // endOfStream hasn't been called yet because blocking multiple queues
980
- // takes an extra tick, even when they are empty.
981
- expect(mockMediaSource.endOfStream).not.toHaveBeenCalled();
982
-
983
- expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalled();
984
- expect(videoSourceBuffer.appendBuffer).not.toHaveBeenCalled();
985
-
986
- await p1;
987
- expect(mockMediaSource.endOfStream).toHaveBeenCalled();
988
- // The next operations have already been kicked off.
989
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
990
- expect(videoSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
991
- // This one is still in queue.
992
- expect(videoSourceBuffer.appendBuffer).not.toHaveBeenCalledWith(buffer2);
993
- audioSourceBuffer.updateend();
994
- videoSourceBuffer.updateend();
995
- await Promise.resolve();
996
- expect(videoSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer2);
997
- videoSourceBuffer.updateend();
998
- });
999
-
1000
- it('runs subsequent operations if this operation throws', async () => {
1001
- mockMediaSource.endOfStream.and.throwError(new Error());
1002
- /** @type {!Promise} */
1003
- const p1 = mediaSourceEngine.endOfStream();
1004
- mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
1005
- fakeStream, /* hasClosedCaptions= */ false);
1006
-
1007
- expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalled();
1008
-
1009
- await expectAsync(p1).toBeRejected();
1010
- expect(mockMediaSource.endOfStream).toHaveBeenCalled();
1011
- await Util.shortDelay();
1012
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(1);
1013
- audioSourceBuffer.updateend();
1014
- });
1015
- });
1016
-
1017
- describe('setDuration', () => {
1018
- beforeEach(async () => {
1019
- mockMediaSource.durationGetter.and.returnValue(0);
1020
- captureEvents(audioSourceBuffer, ['updateend', 'error']);
1021
- captureEvents(videoSourceBuffer, ['updateend', 'error']);
1022
- const initObject = new Map();
1023
- initObject.set(ContentType.AUDIO, fakeAudioStream);
1024
- initObject.set(ContentType.VIDEO, fakeVideoStream);
1025
- await mediaSourceEngine.init(initObject, false);
1026
- });
1027
-
1028
- it('sets the given duration', async () => {
1029
- await mediaSourceEngine.setDuration(100);
1030
- expect(mockMediaSource.durationSetter).toHaveBeenCalledWith(100);
1031
- });
1032
-
1033
- it('waits for all previous operations to complete', async () => {
1034
- /** @type {!shaka.test.StatusPromise} */
1035
- const p1 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
1036
- ContentType.AUDIO, buffer, null, fakeStream,
1037
- /* hasClosedCaptions= */ false));
1038
- /** @type {!shaka.test.StatusPromise} */
1039
- const p2 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
1040
- ContentType.VIDEO, buffer, null, fakeStream,
1041
- /* hasClosedCaptions= */ false));
1042
- /** @type {!shaka.test.StatusPromise} */
1043
- const p3 =
1044
- new shaka.test.StatusPromise(mediaSourceEngine.setDuration(100));
1045
-
1046
- expect(mockMediaSource.durationSetter).not.toHaveBeenCalled();
1047
- expect(p1.status).toBe('pending');
1048
- expect(p2.status).toBe('pending');
1049
- expect(p3.status).toBe('pending');
1050
-
1051
- audioSourceBuffer.updateend();
1052
- await p1;
1053
- expect(p2.status).toBe('pending');
1054
- expect(p3.status).toBe('pending');
1055
- videoSourceBuffer.updateend();
1056
- await p2;
1057
- await p3;
1058
- expect(mockMediaSource.durationSetter).toHaveBeenCalledWith(100);
1059
- });
1060
-
1061
- it('makes subsequent operations wait', async () => {
1062
- /** @type {!Promise} */
1063
- const p1 = mediaSourceEngine.setDuration(100);
1064
- mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
1065
- fakeStream, /* hasClosedCaptions= */ false);
1066
- mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer, null,
1067
- fakeStream, /* hasClosedCaptions= */ false);
1068
- mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer2, null,
1069
- fakeStream, /* hasClosedCaptions= */ false);
1070
-
1071
- // The setter hasn't been called yet because blocking multiple queues
1072
- // takes an extra tick, even when they are empty.
1073
- expect(mockMediaSource.durationSetter).not.toHaveBeenCalled();
1074
-
1075
- expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalled();
1076
- expect(videoSourceBuffer.appendBuffer).not.toHaveBeenCalled();
1077
-
1078
- await p1;
1079
- expect(mockMediaSource.durationSetter).toHaveBeenCalled();
1080
- // The next operations have already been kicked off.
1081
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
1082
- expect(videoSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
1083
- // This one is still in queue.
1084
- expect(videoSourceBuffer.appendBuffer)
1085
- .not.toHaveBeenCalledWith(buffer2);
1086
- audioSourceBuffer.updateend();
1087
- videoSourceBuffer.updateend();
1088
- await Promise.resolve();
1089
- expect(videoSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer2);
1090
- videoSourceBuffer.updateend();
1091
- });
1092
-
1093
- it('runs subsequent operations if this operation throws', async () => {
1094
- mockMediaSource.durationSetter.and.throwError(new Error());
1095
- /** @type {!Promise} */
1096
- const p1 = mediaSourceEngine.setDuration(100);
1097
- mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
1098
- fakeStream, /* hasClosedCaptions= */ false);
1099
-
1100
- expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalled();
1101
-
1102
- await expectAsync(p1).toBeRejected();
1103
- expect(mockMediaSource.durationSetter).toHaveBeenCalled();
1104
- await Util.shortDelay();
1105
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
1106
- audioSourceBuffer.updateend();
1107
- });
1108
-
1109
- it('allows duration to be shrunk', async () => {
1110
- // Pretend the initial duration was 100.
1111
- mockMediaSource.durationGetter.and.returnValue(100);
1112
-
1113
- // When duration is shrunk, 'updateend' events are generated. This is
1114
- // because reducing the duration triggers the MSE removal algorithm to
1115
- // run.
1116
- mockMediaSource.durationSetter.and.callFake((duration) => {
1117
- expect(duration).toBe(50);
1118
- videoSourceBuffer.updateend();
1119
- audioSourceBuffer.updateend();
1120
- });
1121
-
1122
- audioSourceBuffer.appendBuffer.and.callFake(() => {
1123
- audioSourceBuffer.updateend();
1124
- });
1125
- videoSourceBuffer.appendBuffer.and.callFake(() => {
1126
- videoSourceBuffer.updateend();
1127
- });
1128
-
1129
- /** @type {!Promise} */
1130
- const p1 = mediaSourceEngine.setDuration(50);
1131
- expect(mockMediaSource.durationSetter).not.toHaveBeenCalled();
1132
-
1133
- // These operations should be blocked until after duration is shrunk.
1134
- // This is tested because shrinking duration generates 'updateend'
1135
- // events, and we want to show that the queue still operates correctly.
1136
- const a1 = mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
1137
- fakeStream, /* hasClosedCaptions= */ false);
1138
- const a2 = mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer, null,
1139
- fakeStream, /* hasClosedCaptions= */ false);
1140
-
1141
- await p1;
1142
- await a1;
1143
- await a2;
1144
- });
1145
- });
1146
-
1147
- describe('reload codec switching', () => {
1148
- beforeEach(
1149
- /** @suppress {visibility, checkTypes} */
1150
- () => {
1151
- mediaSourceEngine.eventManager_.listenOnce =
1152
- jasmine.createSpy('listener');
1153
- mediaSourceEngine.eventManager_.listen =
1154
- jasmine.createSpy('eventListener');
1155
- });
1156
- const initObject = new Map();
1157
- initObject.set(ContentType.VIDEO, fakeVideoStream);
1158
- initObject.set(ContentType.AUDIO, fakeAudioStream);
1159
-
1160
- it('should re-create a new MediaSource',
1161
- /** @suppress {visibility} */ async () => {
1162
- await mediaSourceEngine.init(initObject, false);
1163
- mediaSourceEngine.reset_(initObject);
1164
- expect(createMediaSourceSpy).toHaveBeenCalled();
1165
- });
1166
-
1167
- it('should re-create the audio & video source buffers',
1168
- /** @suppress {invalidCasts, visibility, checkTypes} */ async () => {
1169
- await mediaSourceEngine.init(initObject, false);
1170
- mediaSourceEngine.reset_(initObject);
1171
- expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledTimes(2);
1172
- });
1173
-
1174
- it('should persist the previous source buffer parameters',
1175
- /** @suppress {invalidCasts, visibility, checkTypes} */async () => {
1176
- await mediaSourceEngine.init(initObject, false);
1177
-
1178
- audioSourceBuffer.timestampOffset = 10;
1179
- audioSourceBuffer.appendWindowStart = 5;
1180
- audioSourceBuffer.appendWindowEnd = 20;
1181
-
1182
- videoSourceBuffer.timestampOffset = 20;
1183
- videoSourceBuffer.appendWindowStart = 15;
1184
- videoSourceBuffer.appendWindowEnd = 30;
1185
-
1186
- mediaSourceEngine.reset_(initObject);
1187
-
1188
- expect(audioSourceBuffer.timestampOffset).toBe(10);
1189
- expect(audioSourceBuffer.appendWindowStart).toBe(5);
1190
- expect(audioSourceBuffer.appendWindowEnd).toBe(20);
1191
-
1192
- expect(videoSourceBuffer.timestampOffset).toBe(20);
1193
- expect(videoSourceBuffer.appendWindowStart).toBe(15);
1194
- expect(videoSourceBuffer.appendWindowEnd).toBe(30);
1195
- });
1196
-
1197
- it('should preserve autoplay state',
1198
- /** @suppress {invalidCasts, visibility, checkTypes} */
1199
- async () => {
1200
- const originalInitSourceBuffer = mediaSourceEngine.initSourceBuffer_;
1201
- try {
1202
- await mediaSourceEngine.init(initObject, false);
1203
- video.autoplay = true;
1204
- video.paused = true;
1205
- const playSpy = /** @type {jasmine.Spy} */ (video.play);
1206
- const addListenOnceSpy =
1207
- /** @type {jasmine.Spy} */
1208
- (mediaSourceEngine.eventManager_.listenOnce);
1209
- const addEventListenerSpy =
1210
- /** @type {jasmine.Spy} */
1211
- (mediaSourceEngine.eventManager_.listen);
1212
- mediaSourceEngine.playbackHasBegun_ = true;
1213
- mediaSourceEngine.initSourceBuffer_ =
1214
- jasmine.createSpy('initSourceBuffer');
1215
- const initSourceBufferSpy =
1216
- /** @type {jasmine.Spy} */
1217
- (mediaSourceEngine.initSourceBuffer_);
1218
- addEventListenerSpy.and.callFake((o, e, c) => {
1219
- c(); // audio
1220
- c(); // video
1221
- });
1222
- await mediaSourceEngine.reset_(initObject);
1223
- const callback = addListenOnceSpy.calls.argsFor(0)[2];
1224
- callback();
1225
- expect(initSourceBufferSpy).toHaveBeenCalled();
1226
- expect(addListenOnceSpy.calls.argsFor(0)[1]).toBe('canplay');
1227
- expect(video.autoplay).toBe(true);
1228
- expect(playSpy).not.toHaveBeenCalled();
1229
- } finally {
1230
- mediaSourceEngine.initSourceBuffer_ = originalInitSourceBuffer;
1231
- }
1232
- });
1233
-
1234
- it('should not set autoplay to false if playback has not begun',
1235
- /** @suppress {invalidCasts, visibility, checkTypes} */
1236
- async () => {
1237
- const originalInitSourceBuffer = mediaSourceEngine.initSourceBuffer_;
1238
- try {
1239
- await mediaSourceEngine.init(initObject, false);
1240
- video.autoplay = true;
1241
- let setCount = 0;
1242
- const addEventListenerSpy =
1243
- /** @type {jasmine.Spy} */
1244
- (mediaSourceEngine.eventManager_.listen);
1245
- addEventListenerSpy.and.callFake((o, e, c) => {
1246
- c(); // audio
1247
- c(); // video
1248
- });
1249
- mediaSourceEngine.initSourceBuffer_ =
1250
- jasmine.createSpy('initSourceBuffer');
1251
- Object.defineProperty(video, 'autoplay', {
1252
- get: () => true,
1253
- set: () => {
1254
- setCount++;
1255
- },
1256
- });
1257
- await mediaSourceEngine.reset_(initObject);
1258
- expect(setCount).toBe(0);
1259
- } finally {
1260
- mediaSourceEngine.initSourceBuffer_ = originalInitSourceBuffer;
1261
- }
1262
- });
1263
-
1264
- it('should preserve playing state',
1265
- /** @suppress {invalidCasts, visibility, checkTypes} */
1266
- async () => {
1267
- const originalInitSourceBuffer = mediaSourceEngine.initSourceBuffer_;
1268
- try {
1269
- await mediaSourceEngine.init(initObject, false);
1270
- video.autoplay = false;
1271
- video.paused = false;
1272
- const playSpy = /** @type {jasmine.Spy} */ (video.play);
1273
- const addListenOnceSpy =
1274
- /** @type {jasmine.Spy} */
1275
- (mediaSourceEngine.eventManager_.listenOnce);
1276
- const addEventListenerSpy =
1277
- /** @type {jasmine.Spy} */
1278
- (mediaSourceEngine.eventManager_.listen);
1279
- mediaSourceEngine.playbackHasBegun_ = true;
1280
- mediaSourceEngine.initSourceBuffer_ =
1281
- jasmine.createSpy('initSourceBuffer');
1282
- const initSourceBufferSpy =
1283
- /** @type {jasmine.Spy} */
1284
- (mediaSourceEngine.initSourceBuffer_);
1285
- addEventListenerSpy.and.callFake((o, e, c) => {
1286
- c(); // audio
1287
- c(); // video
1288
- });
1289
- await mediaSourceEngine.reset_(initObject);
1290
- const callback = addListenOnceSpy.calls.argsFor(0)[2];
1291
- callback();
1292
- expect(initSourceBufferSpy).toHaveBeenCalled();
1293
- expect(addListenOnceSpy.calls.argsFor(0)[1]).toBe('canplay');
1294
- expect(video.autoplay).toBe(false);
1295
- expect(playSpy).toHaveBeenCalled();
1296
- } finally {
1297
- mediaSourceEngine.initSourceBuffer_ = originalInitSourceBuffer;
1298
- }
1299
- });
1300
- });
1301
-
1302
- describe('destroy', () => {
1303
- beforeEach(async () => {
1304
- captureEvents(audioSourceBuffer, ['updateend', 'error']);
1305
- captureEvents(videoSourceBuffer, ['updateend', 'error']);
1306
- const initObject = new Map();
1307
- initObject.set(ContentType.AUDIO, fakeAudioStream);
1308
- initObject.set(ContentType.VIDEO, fakeVideoStream);
1309
- await mediaSourceEngine.init(initObject, false);
1310
- });
1311
-
1312
- it('waits for all operations to complete', async () => {
1313
- mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
1314
- fakeStream, /* hasClosedCaptions= */ false);
1315
- mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer, null,
1316
- fakeStream, /* hasClosedCaptions= */ false);
1317
-
1318
- /** @type {!shaka.test.StatusPromise} */
1319
- const d = new shaka.test.StatusPromise(mediaSourceEngine.destroy());
1320
-
1321
- expect(d.status).toBe('pending');
1322
- await Util.shortDelay();
1323
- expect(d.status).toBe('pending');
1324
- audioSourceBuffer.updateend();
1325
- await Util.shortDelay();
1326
- expect(d.status).toBe('pending');
1327
- videoSourceBuffer.updateend();
1328
- await d;
1329
- });
1330
-
1331
- it('resolves even when a pending operation fails', async () => {
1332
- const p = mediaSourceEngine.appendBuffer(
1333
- ContentType.AUDIO, buffer, null, fakeStream,
1334
- /* hasClosedCaptions= */ false);
1335
- const d = mediaSourceEngine.destroy();
1336
-
1337
- audioSourceBuffer.error();
1338
- audioSourceBuffer.updateend();
1339
- await expectAsync(p).toBeRejected();
1340
- await d;
1341
- });
1342
-
1343
- it('waits for blocking operations to complete', async () => {
1344
- /** @type {!shaka.test.StatusPromise} */
1345
- const p = new shaka.test.StatusPromise(mediaSourceEngine.endOfStream());
1346
- /** @type {!shaka.test.StatusPromise} */
1347
- const d = new shaka.test.StatusPromise(mediaSourceEngine.destroy());
1348
-
1349
- expect(p.status).toBe('pending');
1350
- expect(d.status).toBe('pending');
1351
- await p;
1352
- expect(d.status).toBe('pending');
1353
- await d;
1354
- });
1355
-
1356
- it('cancels operations that have not yet started', async () => {
1357
- mediaSourceEngine.appendBuffer(
1358
- ContentType.AUDIO, buffer, null, fakeStream,
1359
- /* hasClosedCaptions= */ false);
1360
- const rejected = mediaSourceEngine.appendBuffer(
1361
- ContentType.AUDIO, buffer2, null, fakeStream,
1362
- /* hasClosedCaptions= */ false);
1363
- // Create the expectation first so we don't get unhandled rejection errors
1364
- const expected = expectAsync(rejected).toBeRejected();
1365
-
1366
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
1367
- expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalledWith(buffer2);
1368
-
1369
- /** @type {!shaka.test.StatusPromise} */
1370
- const d = new shaka.test.StatusPromise(mediaSourceEngine.destroy());
1371
-
1372
- expect(d.status).toBe('pending');
1373
- await Util.shortDelay();
1374
- expect(d.status).toBe('pending');
1375
- await expected;
1376
- expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
1377
- expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalledWith(buffer2);
1378
- audioSourceBuffer.updateend();
1379
- await d;
1380
- expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalledWith(buffer2);
1381
- });
1382
-
1383
- it('cancels blocking operations that have not yet started', async () => {
1384
- const p1 = mediaSourceEngine.appendBuffer(
1385
- ContentType.AUDIO, buffer, null, fakeStream,
1386
- /* hasClosedCaptions= */ false);
1387
- const p2 = mediaSourceEngine.endOfStream();
1388
- const d = mediaSourceEngine.destroy();
1389
-
1390
- audioSourceBuffer.updateend();
1391
- await expectAsync(p1).toBeResolved();
1392
- await expectAsync(p2).toBeRejected();
1393
- await d;
1394
- });
1395
-
1396
- it('prevents new operations from being added', async () => {
1397
- const d = mediaSourceEngine.destroy();
1398
- await expectAsync(
1399
- mediaSourceEngine.appendBuffer(
1400
- ContentType.AUDIO, buffer, null, fakeStream,
1401
- /* hasClosedCaptions= */ false))
1402
- .toBeRejected();
1403
- await d;
1404
- expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalled();
1405
- });
1406
-
1407
- it('destroys text engines', async () => {
1408
- mediaSourceEngine.reinitText('text/vtt', false, false);
1409
-
1410
- await mediaSourceEngine.destroy();
1411
- expect(mockTextEngine).toBeTruthy();
1412
- expect(mockTextEngine.destroy).toHaveBeenCalled();
1413
- });
1414
-
1415
- // Regression test for https://github.com/shaka-project/shaka-player/issues/984
1416
- it('destroys TextDisplayer on destroy', async () => {
1417
- await mediaSourceEngine.destroy();
1418
- expect(mockTextDisplayer.destroySpy).toHaveBeenCalled();
1419
- });
1420
- });
1421
-
1422
- function createMockMediaSource() {
1423
- const mediaSource = {
1424
- readyState: 'open',
1425
- sourceBuffers: document.createElement('div'),
1426
- addSourceBuffer: jasmine.createSpy('addSourceBuffer'),
1427
- endOfStream: jasmine.createSpy('endOfStream'),
1428
- durationGetter: jasmine.createSpy('duration getter'),
1429
- durationSetter: jasmine.createSpy('duration setter'),
1430
- addEventListener: jasmine.createSpy('addEventListener'),
1431
- removeEventListener: () => {},
1432
- };
1433
- Object.defineProperty(mediaSource, 'duration', {
1434
- get: Util.spyFunc(mediaSource.durationGetter),
1435
- set: Util.spyFunc(mediaSource.durationSetter),
1436
- });
1437
- return mediaSource;
1438
- }
1439
-
1440
- /** @return {MockSourceBuffer} */
1441
- function createMockSourceBuffer() {
1442
- return {
1443
- abort: jasmine.createSpy('abort'),
1444
- appendBuffer: jasmine.createSpy('appendBuffer'),
1445
- remove: jasmine.createSpy('remove'),
1446
- updating: false,
1447
- addEventListener: jasmine.createSpy('addEventListener'),
1448
- removeEventListener: jasmine.createSpy('removeEventListener'),
1449
- buffered: {
1450
- length: 0,
1451
- start: jasmine.createSpy('buffered.start'),
1452
- end: jasmine.createSpy('buffered.end'),
1453
- },
1454
- timestampOffset: 0,
1455
- appendWindowEnd: Infinity,
1456
- updateend: () => {},
1457
- error: () => {},
1458
- mode: 'segments',
1459
- };
1460
- }
1461
-
1462
- function createMockTextEngineCtor() {
1463
- const ctor = jasmine.createSpy('TextEngine');
1464
- ctor['isTypeSupported'] = () => true;
1465
- // Because this is a fake constructor, it must be callable with "new".
1466
- // This will cause jasmine to invoke the callback with "new" as well, so
1467
- // the callback must be a "function". This detail is hidden when babel
1468
- // transpiles the tests.
1469
- // eslint-disable-next-line prefer-arrow-callback, no-restricted-syntax
1470
- ctor.and.callFake(function() {
1471
- expect(mockTextEngine).toBeFalsy();
1472
- mockTextEngine = jasmine.createSpyObj('TextEngine', [
1473
- 'initParser', 'destroy', 'appendBuffer', 'remove', 'setTimestampOffset',
1474
- 'setAppendWindow', 'bufferStart', 'bufferEnd', 'bufferedAheadOf',
1475
- 'storeAndAppendClosedCaptions',
1476
- ]);
1477
-
1478
- const resolve = () => Promise.resolve();
1479
- mockTextEngine.destroy.and.callFake(resolve);
1480
- mockTextEngine.appendBuffer.and.callFake(resolve);
1481
- mockTextEngine.remove.and.callFake(resolve);
1482
- return mockTextEngine;
1483
- });
1484
- return ctor;
1485
- }
1486
-
1487
- function captureEvents(object, targetEventNames) {
1488
- object.addEventListener.and.callFake((eventName, listener) => {
1489
- if (targetEventNames.includes(eventName)) {
1490
- object[eventName] = listener;
1491
- }
1492
- });
1493
- object.removeEventListener.and.callFake((eventName, listener) => {
1494
- if (targetEventNames.includes(eventName)) {
1495
- expect(object[eventName]).toBe(listener);
1496
- object[eventName] = null;
1497
- }
1498
- });
1499
- }
1500
-
1501
- function dummyReference(startTime, endTime) {
1502
- return new shaka.media.SegmentReference(
1503
- startTime, endTime,
1504
- /* uris= */ () => ['foo://bar'],
1505
- /* startByte= */ 0,
1506
- /* endByte= */ null,
1507
- /* initSegmentReference= */ null,
1508
- /* timestampOffset= */ 0,
1509
- /* appendWindowStart= */ 0,
1510
- /* appendWindowEnd= */ Infinity);
1511
- }
1512
- });