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,4434 +0,0 @@
1
- /*! @license
2
- * Shaka Player
3
- * Copyright 2016 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- describe('Player', () => {
8
- const ContentType = shaka.util.ManifestParserUtils.ContentType;
9
- const Util = shaka.test.Util;
10
-
11
- const originalLogError = shaka.log.error;
12
- const originalLogWarn = shaka.log.warning;
13
- const originalLogAlwaysWarn = shaka.log.alwaysWarn;
14
- const originalIsTypeSupported = window.MediaSource.isTypeSupported;
15
- const originalDecodingInfo = navigator.mediaCapabilities.decodingInfo;
16
-
17
- const fakeManifestUri = 'fake-manifest-uri';
18
- const fakeMimeType = 'application/test';
19
-
20
- /** @type {!jasmine.Spy} */
21
- let logErrorSpy;
22
- /** @type {!jasmine.Spy} */
23
- let logWarnSpy;
24
- /** @type {!jasmine.Spy} */
25
- let onError;
26
- /** @type {shaka.extern.Manifest} */
27
- let manifest;
28
- /** @type {!shaka.Player} */
29
- let player;
30
- /** @type {!shaka.test.FakeAbrManager} */
31
- let abrManager;
32
-
33
- /** @type {!shaka.test.FakeNetworkingEngine} */
34
- let networkingEngine;
35
- /** @type {!shaka.test.FakeStreamingEngine} */
36
- let streamingEngine;
37
- /** @type {!shaka.test.FakeDrmEngine} */
38
- let drmEngine;
39
- /** @type {!shaka.test.FakePlayhead} */
40
- let playhead;
41
- /** @type {!shaka.test.FakeTextDisplayer} */
42
- let textDisplayer;
43
- /** @type {shaka.extern.BufferedInfo} */
44
- let bufferedInfo;
45
-
46
- let mediaSourceEngine;
47
-
48
- /** @type {!shaka.test.FakeVideo} */
49
- let video;
50
-
51
- beforeEach(async () => {
52
- // By default, errors are a failure.
53
- logErrorSpy = jasmine.createSpy('shaka.log.error');
54
- logErrorSpy.calls.reset();
55
- shaka.log.error = shaka.test.Util.spyFunc(logErrorSpy);
56
- shaka.log.alwaysError = shaka.test.Util.spyFunc(logErrorSpy);
57
-
58
- logWarnSpy = jasmine.createSpy('shaka.log.warning');
59
- logErrorSpy.and.callFake(fail);
60
- shaka.log.warning = shaka.test.Util.spyFunc(logWarnSpy);
61
- shaka.log.alwaysWarn = shaka.test.Util.spyFunc(logWarnSpy);
62
-
63
- // Since this is not an integration test, we don't want MediaSourceEngine to
64
- // fail assertions based on browser support for types. Pretend that all
65
- // video and audio types are supported.
66
- window.MediaSource.isTypeSupported = (mimeType) => {
67
- const type = mimeType.split('/')[0];
68
- return type == 'video' || type == 'audio';
69
- };
70
-
71
- // Since this is not an integration test, we don't want MediaCapabilities to
72
- // fail assertions based on browser support for types. Pretend that all
73
- // video and audio types are supported.
74
- navigator.mediaCapabilities.decodingInfo = async (config) => {
75
- await Promise.resolve();
76
- const videoType = config['video'] ?
77
- config['video'].contentType.split('/')[0] : null;
78
- const audioType = config['audio'] ?
79
- config['audio'].contentType.split('/')[0] : null;
80
- if (videoType == 'video' || audioType == 'audio') {
81
- return {supported: true};
82
- } else {
83
- return {supported: false};
84
- }
85
- };
86
-
87
- // Many tests assume the existence of a manifest, so create a basic one.
88
- // Test suites can override this with more specific manifests.
89
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
90
- manifest.addVariant(0, (variant) => {
91
- variant.addAudio(1);
92
- variant.addVideo(2);
93
- });
94
- manifest.addVariant(1, (variant) => {
95
- variant.addAudio(1);
96
- variant.addVideo(4);
97
- });
98
- });
99
-
100
- shaka.media.ManifestParser.registerParserByMime(
101
- fakeMimeType, () => new shaka.test.FakeManifestParser(manifest));
102
-
103
- abrManager = new shaka.test.FakeAbrManager();
104
- textDisplayer = createTextDisplayer();
105
-
106
- bufferedInfo = {
107
- total: [],
108
- audio: [],
109
- video: [{start: 12, end: 26}],
110
- text: [],
111
- };
112
-
113
- function dependencyInjector(player) {
114
- // Create a networking engine that always returns an empty buffer.
115
- networkingEngine = new shaka.test.FakeNetworkingEngine();
116
- networkingEngine.setDefaultValue(new ArrayBuffer(0));
117
-
118
- drmEngine = new shaka.test.FakeDrmEngine();
119
- playhead = new shaka.test.FakePlayhead();
120
- streamingEngine = new shaka.test.FakeStreamingEngine();
121
- mediaSourceEngine = {
122
- init: jasmine.createSpy('init').and.returnValue(Promise.resolve()),
123
- configure: jasmine.createSpy('configure'),
124
- open: jasmine.createSpy('open').and.returnValue(Promise.resolve()),
125
- destroy:
126
- jasmine.createSpy('destroy').and.returnValue(Promise.resolve()),
127
- setTextDisplayer: jasmine.createSpy('setTextDisplayer'),
128
- setUseEmbeddedText: jasmine.createSpy('setUseEmbeddedText'),
129
- getUseEmbeddedText: jasmine.createSpy('getUseEmbeddedText'),
130
- setSegmentRelativeVttTiming:
131
- jasmine.createSpy('setSegmentRelativeVttTiming'),
132
- updateLcevcDec:
133
- jasmine.createSpy('updateLcevcDec'),
134
- getTextDisplayer: () => textDisplayer,
135
- getBufferedInfo: () => bufferedInfo,
136
- ended: jasmine.createSpy('ended').and.returnValue(false),
137
- };
138
-
139
- player.createDrmEngine = () => {
140
- return drmEngine;
141
- };
142
- player.createNetworkingEngine = () => networkingEngine;
143
- player.createPlayhead = (startTime) => {
144
- const callableSetStartTime =
145
- shaka.test.Util.spyFunc(playhead.setStartTime);
146
- callableSetStartTime(startTime);
147
- playhead.setStartTime.calls.reset();
148
- return playhead;
149
- };
150
- player.createMediaSourceEngine = () => mediaSourceEngine;
151
- player.createStreamingEngine = () => streamingEngine;
152
- }
153
-
154
- video = new shaka.test.FakeVideo(20);
155
- player = new shaka.Player(null, dependencyInjector);
156
- await player.attach(video);
157
- player.configure({
158
- // Ensures we don't get a warning about missing preference.
159
- preferredAudioLanguage: 'en',
160
- abrFactory: () => abrManager,
161
- textDisplayFactory: () => textDisplayer,
162
- });
163
-
164
- onError = jasmine.createSpy('error event');
165
- onError.and.callFake((event) => {
166
- fail(event.detail);
167
- });
168
- player.addEventListener('error', shaka.test.Util.spyFunc(onError));
169
- });
170
-
171
- afterEach(async () => {
172
- try {
173
- await player.destroy();
174
- } finally {
175
- player.releaseAllMutexes();
176
- shaka.log.error = originalLogError;
177
- shaka.log.alwaysError = originalLogError;
178
- shaka.log.warning = originalLogWarn;
179
- shaka.log.alwaysWarn = originalLogAlwaysWarn;
180
- window.MediaSource.isTypeSupported = originalIsTypeSupported;
181
- shaka.media.ManifestParser.unregisterParserByMime(fakeMimeType);
182
- navigator.mediaCapabilities.decodingInfo = originalDecodingInfo;
183
- onError.calls.reset();
184
- }
185
- });
186
-
187
- describe('destroy', () => {
188
- it('cleans up all dependencies', async () => {
189
- goog.asserts.assert(manifest, 'Manifest should be non-null');
190
- await player.load(fakeManifestUri, 0, fakeMimeType);
191
- const segmentIndexes = [];
192
- for (const variant of manifest.variants) {
193
- if (variant.audio) {
194
- segmentIndexes.push(variant.audio.segmentIndex);
195
- }
196
- if (variant.video) {
197
- segmentIndexes.push(variant.video.segmentIndex);
198
- }
199
- }
200
- for (const textStream of manifest.textStreams) {
201
- segmentIndexes.push(textStream.segmentIndex);
202
- }
203
- for (const segmentIndex of segmentIndexes) {
204
- spyOn(segmentIndex, 'release');
205
- }
206
-
207
- await player.load(fakeManifestUri, 0, fakeMimeType);
208
- await player.destroy();
209
-
210
- expect(abrManager.stop).toHaveBeenCalled();
211
- expect(abrManager.release).toHaveBeenCalled();
212
- expect(networkingEngine.destroy).toHaveBeenCalled();
213
- expect(drmEngine.destroy).toHaveBeenCalled();
214
- expect(playhead.release).toHaveBeenCalled();
215
- expect(mediaSourceEngine.destroy).toHaveBeenCalled();
216
- expect(streamingEngine.destroy).toHaveBeenCalled();
217
-
218
- for (const segmentIndex of segmentIndexes) {
219
- if (segmentIndex) {
220
- expect(segmentIndex.release).toHaveBeenCalled();
221
- }
222
- }
223
- });
224
-
225
- it('destroys mediaSourceEngine before drmEngine', async () => {
226
- goog.asserts.assert(manifest, 'Manifest should be non-null');
227
-
228
- mediaSourceEngine.destroy.and.callFake(async () => {
229
- expect(drmEngine.destroy).not.toHaveBeenCalled();
230
- await Util.shortDelay();
231
- expect(drmEngine.destroy).not.toHaveBeenCalled();
232
- });
233
-
234
- await player.load(fakeManifestUri, 0, fakeMimeType);
235
- await player.destroy();
236
-
237
- expect(mediaSourceEngine.destroy).toHaveBeenCalled();
238
- expect(drmEngine.destroy).toHaveBeenCalled();
239
- });
240
- });
241
-
242
- describe('load/unload', () => {
243
- /** @type {!jasmine.Spy} */
244
- let checkError;
245
-
246
- beforeEach(() => {
247
- goog.asserts.assert(manifest, 'manifest must be non-null');
248
- checkError = jasmine.createSpy('checkError');
249
- checkError.and.callFake((error) => {
250
- expect(error.code).toBe(shaka.util.Error.Code.LOAD_INTERRUPTED);
251
- });
252
- });
253
-
254
- describe('streaming event', () => {
255
- /** @type {jasmine.Spy} */
256
- let streamingListener;
257
-
258
- beforeEach(() => {
259
- streamingListener = jasmine.createSpy('listener');
260
- player.addEventListener('streaming', Util.spyFunc(streamingListener));
261
-
262
- // We must have two different sets of codecs for some of our tests.
263
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
264
- manifest.addVariant(0, (variant) => {
265
- variant.addAudio(1, (stream) => {
266
- stream.mime('audio/mp4', 'mp4a.40.2');
267
- });
268
- variant.addVideo(2, (stream) => {
269
- stream.mime('video/mp4', 'avc1.4d401f');
270
- });
271
- });
272
- manifest.addVariant(1, (variant) => {
273
- variant.addAudio(3, (stream) => {
274
- stream.mime('audio/webm', 'opus');
275
- });
276
- variant.addVideo(4, (stream) => {
277
- stream.mime('video/webm', 'vp9');
278
- });
279
- });
280
- });
281
- });
282
-
283
- async function runTest() {
284
- expect(streamingListener).not.toHaveBeenCalled();
285
- await player.load(fakeManifestUri, 0, fakeMimeType);
286
- expect(streamingListener).toHaveBeenCalled();
287
- }
288
-
289
- it('fires after tracks exist', async () => {
290
- streamingListener.and.callFake(() => {
291
- const tracks = player.getVariantTracks();
292
- expect(tracks).toBeDefined();
293
- expect(tracks.length).toBeGreaterThan(0);
294
- });
295
- await runTest();
296
- });
297
-
298
- it('fires before any tracks are active', async () => {
299
- streamingListener.and.callFake(() => {
300
- const activeTracks =
301
- player.getVariantTracks().filter((t) => t.active);
302
- expect(activeTracks.length).toBe(0);
303
- });
304
- await runTest();
305
- });
306
-
307
- // We used to fire the event /before/ filtering, which meant that for
308
- // multi-codec content, the application might select something which will
309
- // later be removed during filtering.
310
- // https://github.com/shaka-project/shaka-player/issues/1119
311
- it('fires after tracks have been filtered', async () => {
312
- streamingListener.and.callFake(() => {
313
- const tracks = player.getVariantTracks();
314
- // Either WebM, or MP4, but not both.
315
- expect(tracks.length).toBe(1);
316
- });
317
- await runTest();
318
- });
319
- });
320
-
321
- describe('disableStream', () => {
322
- /** @type {number} */
323
- let disableTimeInSeconds;
324
- /** @type {?jasmine.Spy} */
325
- let getBufferedInfoSpy;
326
-
327
- beforeAll(() => {
328
- jasmine.clock().install();
329
- jasmine.clock().mockDate();
330
- });
331
-
332
- afterAll(() => {
333
- jasmine.clock().uninstall();
334
- });
335
-
336
- beforeEach(() => {
337
- disableTimeInSeconds = 30;
338
- getBufferedInfoSpy = spyOn(player, 'getBufferedInfo')
339
- .and.returnValue(bufferedInfo);
340
- });
341
-
342
- async function runTest(variantIndex, streamType, expectedStatus) {
343
- await player.load(fakeManifestUri, 0, fakeMimeType);
344
-
345
- const stream =
346
- /** @type {shaka.extern.Stream} */
347
- (manifest.variants[variantIndex][streamType]);
348
- const status = player.disableStream(stream, 10);
349
-
350
- expect(status).toBe(expectedStatus);
351
- }
352
-
353
- function multiVariantManifest() {
354
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
355
- manifest.addVariant(0, (variant) => {
356
- variant.addAudio(1, (stream) => {
357
- stream.mime('audio/mp4', 'mp4a.40.2');
358
- stream.language = 'en';
359
- });
360
- variant.addVideo(2, (stream) => {
361
- stream.size(10, 10);
362
- });
363
- });
364
- manifest.addVariant(1, (variant) => {
365
- variant.addExistingStream(1);
366
- variant.addVideo(3, (stream) => {
367
- stream.size(20, 20);
368
- });
369
- });
370
- manifest.addVariant(2, (variant) => {
371
- variant.addExistingStream(1);
372
- variant.addVideo(4, (stream) => {
373
- stream.size(30, 30);
374
- });
375
- });
376
- });
377
- }
378
-
379
- it('disable and restore stream after configured time', async () => {
380
- multiVariantManifest();
381
-
382
- await player.load(fakeManifestUri, 0, fakeMimeType);
383
-
384
- const variant = manifest.variants[0];
385
- const videoStream = /** @type {shaka.extern.Stream} */ (variant.video);
386
-
387
- player.disableStream(videoStream, disableTimeInSeconds);
388
-
389
- expect(variant.disabledUntilTime).toBeGreaterThan(Date.now()/1000);
390
-
391
- await shaka.test.Util.fakeEventLoop(disableTimeInSeconds);
392
-
393
- expect(variant.disabledUntilTime).toBe(0);
394
- });
395
-
396
- it('does not restore stream if disabled time did not elapsed',
397
- async () => {
398
- multiVariantManifest();
399
-
400
- await player.load(fakeManifestUri, 0, fakeMimeType);
401
-
402
- const variant = manifest.variants[0];
403
- const videoStream =
404
- /** @type {shaka.extern.Stream} */ (variant.video);
405
-
406
- player.disableStream(videoStream, disableTimeInSeconds);
407
-
408
- expect(variant.disabledUntilTime).toBeGreaterThan(Date.now()/1000);
409
-
410
- await shaka.test.Util.fakeEventLoop(disableTimeInSeconds - 5);
411
-
412
- expect(variant.disabledUntilTime).toBeGreaterThan(Date.now()/1000);
413
- });
414
-
415
- it('updates abrManager and switch after disabling a stream', async () => {
416
- multiVariantManifest();
417
-
418
- await player.load(fakeManifestUri, 0, fakeMimeType);
419
-
420
- const variantCount = manifest.variants.length;
421
- const variant = manifest.variants[0];
422
- const videoStream =
423
- /** @type {shaka.extern.Stream} */ (variant.video);
424
-
425
- player.disableStream(videoStream, disableTimeInSeconds);
426
-
427
- // Disabled as expected?
428
- expect(variant.disabledUntilTime).toBeGreaterThan(Date.now()/1000);
429
- expect(abrManager.setVariants).toHaveBeenCalled();
430
- expect(abrManager.chooseVariant).toHaveBeenCalled();
431
- expect(streamingEngine.switchVariant).toHaveBeenCalled();
432
- expect(getBufferedInfoSpy).toHaveBeenCalled();
433
-
434
- const updatedVariants =
435
- abrManager.setVariants.calls.mostRecent().args[0];
436
- const alternateVariant =
437
- streamingEngine.switchVariant.calls.mostRecent().args[0];
438
- const safeMargin =
439
- streamingEngine.switchVariant.calls.mostRecent().args[2];
440
- const forceSwitch =
441
- streamingEngine.switchVariant.calls.mostRecent().args[3];
442
- const fromAdaptation =
443
- streamingEngine.switchVariant.calls.mostRecent().args[4];
444
-
445
- expect(updatedVariants.length).toBe(variantCount - 1);
446
- expect(alternateVariant.video).not.toEqual(variant.video);
447
- expect(safeMargin).toBe(14);
448
- expect(forceSwitch).toBeTruthy();
449
- expect(fromAdaptation).toBeFalsy();
450
- });
451
-
452
- it('updates abrManager and switch after restoring a stream', async () => {
453
- multiVariantManifest();
454
-
455
- await player.load(fakeManifestUri, 0, fakeMimeType);
456
-
457
- const variantCount = manifest.variants.length;
458
- const variant = manifest.variants[0];
459
- const videoStream = /** @type {shaka.extern.Stream} */ (variant.video);
460
-
461
- player.disableStream(videoStream, disableTimeInSeconds);
462
-
463
- await shaka.test.Util.fakeEventLoop(disableTimeInSeconds);
464
-
465
- // Restored as expected?
466
- expect(variant.disabledUntilTime).toBe(0);
467
- expect(abrManager.setVariants).toHaveBeenCalled();
468
- expect(abrManager.chooseVariant).toHaveBeenCalled();
469
- expect(streamingEngine.switchVariant).toHaveBeenCalled();
470
-
471
- const updatedVariants =
472
- abrManager.setVariants.calls.mostRecent().args[0];
473
- const forceSwitch =
474
- streamingEngine.switchVariant.calls.mostRecent().args[3];
475
- const fromAdaptation =
476
- streamingEngine.switchVariant.calls.mostRecent().args[4];
477
-
478
- expect(updatedVariants.length).toBe(variantCount);
479
- expect(forceSwitch).toBeFalsy();
480
- expect(fromAdaptation).toBeFalsy();
481
- });
482
-
483
- describe('does not disable stream if there not alternate stream', () => {
484
- it('single audio multiple videos', async () => {
485
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
486
- manifest.addVariant(0, (variant) => {
487
- variant.addAudio(1, (stream) => {
488
- stream.mime('audio/mp4', 'mp4a.40.2');
489
- stream.language = 'en';
490
- });
491
- variant.addVideo(2);
492
- });
493
- manifest.addVariant(1, (variant) => {
494
- variant.addExistingStream(1);
495
- variant.addVideo(3);
496
- });
497
- });
498
-
499
- await runTest(0, 'audio', false);
500
- });
501
-
502
- it('multiple audio different languages', async () => {
503
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
504
- manifest.addVariant(0, (variant) => {
505
- variant.addAudio(1, (stream) => {
506
- stream.mime('audio/mp4', 'mp4a.40.2');
507
- stream.language = 'en';
508
- });
509
- variant.addVideo(2);
510
- });
511
- manifest.addVariant(1, (variant) => {
512
- variant.addAudio(3, (stream) => {
513
- stream.mime('audio/mp4', 'mp4a.40.2');
514
- stream.language = 'de';
515
- });
516
- variant.addExistingStream(2);
517
- });
518
- });
519
-
520
- await runTest(1, 'audio', false);
521
- });
522
-
523
- it('single variant', async () => {
524
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
525
- manifest.addVariant(0, (variant) => {
526
- variant.addAudio(1);
527
- variant.addVideo(2);
528
- });
529
- });
530
-
531
- await runTest(0, 'audio', false);
532
- await runTest(0, 'video', false);
533
- });
534
-
535
- it('single video multiple audio', async () => {
536
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
537
- manifest.addVariant(0, (variant) => {
538
- variant.addAudio(1, (stream) => {
539
- stream.mime('audio/mp4', 'mp4a.40.2');
540
- stream.language = 'en';
541
- stream.bandwidth = 10;
542
- });
543
- variant.addVideo(2);
544
- });
545
- manifest.addVariant(1, (variant) => {
546
- variant.addAudio(3, (stream) => {
547
- stream.mime('audio/mp4', 'mp4a.40.2');
548
- stream.language = 'en';
549
- stream.bandwidth = 20;
550
- });
551
- variant.addExistingStream(2);
552
- });
553
- });
554
-
555
- await runTest(0, 'video', false);
556
- });
557
-
558
- describe('or', () => {
559
- /** @type {!Object} */
560
- let navigatorOnLineDescriptor;
561
-
562
- // eslint-disable-next-line no-restricted-syntax
563
- const navigatorPrototype = Navigator.prototype;
564
-
565
- beforeAll(() => {
566
- navigatorOnLineDescriptor =
567
- /** @type {!Object} */(Object.getOwnPropertyDescriptor(
568
- navigatorPrototype, 'onLine'));
569
- });
570
-
571
- beforeEach(() => {
572
- // Redefine the property, replacing only the getter.
573
- Object.defineProperty(navigatorPrototype, 'onLine',
574
- Object.assign(navigatorOnLineDescriptor, {
575
- get: () => false,
576
- }));
577
- });
578
-
579
- afterEach(() => {
580
- // Restore the original property definition.
581
- Object.defineProperty(
582
- navigatorPrototype, 'onLine', navigatorOnLineDescriptor);
583
- });
584
-
585
- it('browser is truly offline', async () => {
586
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
587
- manifest.addVariant(11, (variant) => {
588
- variant.addAudio(2);
589
- variant.addVideo(3);
590
- });
591
- manifest.addVariant(12, (variant) => {
592
- variant.addAudio(4);
593
- variant.addVideo(5);
594
- });
595
- });
596
-
597
- await runTest(0, 'video', false);
598
- });
599
- });
600
- });
601
- });
602
-
603
- describe('setTextTrackVisibility', () => {
604
- beforeEach(() => {
605
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
606
- manifest.addVariant(0, (variant) => {
607
- variant.addAudio(1);
608
- variant.addVideo(2);
609
- });
610
- manifest.addTextStream(3, (stream) => {
611
- stream.bandwidth = 100;
612
- stream.kind = 'caption';
613
- stream.label = 'Spanish';
614
- stream.language = 'es';
615
- });
616
- });
617
- });
618
-
619
- it('load text stream if caption is visible', async () => {
620
- await player.setTextTrackVisibility(true);
621
- await player.load(fakeManifestUri, 0, fakeMimeType);
622
- expect(streamingEngine.switchTextStream).toHaveBeenCalled();
623
- expect(shaka.test.Util.invokeSpy(streamingEngine.getCurrentTextStream))
624
- .not.toBe(null);
625
- });
626
-
627
- it('does not load text stream if caption is invisible', async () => {
628
- await player.setTextTrackVisibility(false);
629
- await player.load(fakeManifestUri, 0, fakeMimeType);
630
- expect(streamingEngine.switchTextStream).not.toHaveBeenCalled();
631
- expect(shaka.test.Util.invokeSpy(streamingEngine.getCurrentTextStream))
632
- .toBe(null);
633
- });
634
-
635
- it('loads text stream if alwaysStreamText is set', async () => {
636
- await player.setTextTrackVisibility(false);
637
- player.configure({streaming: {alwaysStreamText: true}});
638
-
639
- await player.load(fakeManifestUri, 0, fakeMimeType);
640
- expect(streamingEngine.switchTextStream).toHaveBeenCalled();
641
- expect(shaka.test.Util.invokeSpy(streamingEngine.getCurrentTextStream))
642
- .not.toBe(null);
643
- streamingEngine.switchTextStream.calls.reset();
644
-
645
- await player.setTextTrackVisibility(true);
646
- expect(streamingEngine.switchTextStream).not.toHaveBeenCalled();
647
- expect(streamingEngine.unloadTextStream).not.toHaveBeenCalled();
648
-
649
- await player.setTextTrackVisibility(false);
650
- expect(streamingEngine.switchTextStream).not.toHaveBeenCalled();
651
- expect(streamingEngine.unloadTextStream).not.toHaveBeenCalled();
652
- });
653
- });
654
-
655
- describe('when config.streaming.preferNativeHls is set to true', () => {
656
- beforeEach(() => {
657
- shaka.media.ManifestParser.registerParserByMime(
658
- 'application/x-mpegurl',
659
- () => new shaka.test.FakeManifestParser(manifest));
660
- });
661
-
662
- afterEach(() => {
663
- shaka.media.ManifestParser.unregisterParserByMime(
664
- 'application/x-mpegurl');
665
- video.canPlayType.calls.reset();
666
- });
667
-
668
- it('only applies to HLS streams', async () => {
669
- video.canPlayType.and.returnValue('maybe');
670
- spyOn(shaka.util.Platform, 'anyMediaElement').and.returnValue(video);
671
- spyOn(shaka.util.Platform, 'supportsMediaSource').and.returnValue(true);
672
- spyOn(shaka.util.Platform, 'isApple').and.returnValue(false);
673
- // Make sure player.load() resolves for src=
674
- spyOn(shaka.util.MediaReadyState, 'waitForReadyState').and.callFake(
675
- (mediaElement, readyState, eventManager, callback) => {
676
- callback();
677
- });
678
-
679
- player.configure({
680
- streaming: {
681
- preferNativeHls: true,
682
- useNativeHlsOnSafari: false,
683
- },
684
- });
685
-
686
- await player.load(fakeManifestUri, undefined, 'application/x-mpegurl');
687
-
688
- expect(player.getLoadMode()).toBe(shaka.Player.LoadMode.SRC_EQUALS);
689
- });
690
-
691
- it('does not apply to non-HLS streams', async () => {
692
- video.canPlayType.and.returnValue('maybe');
693
- spyOn(shaka.util.Platform, 'supportsMediaSource').and.returnValue(true);
694
- spyOn(shaka.util.Platform, 'isApple').and.returnValue(false);
695
-
696
- player.configure({
697
- streaming: {
698
- preferNativeHls: true,
699
- useNativeHlsOnSafari: false,
700
- },
701
- });
702
-
703
- await player.load(fakeManifestUri, 0, fakeMimeType);
704
-
705
- expect(player.getLoadMode()).toBe(shaka.Player.LoadMode.MEDIA_SOURCE);
706
- });
707
- });
708
- }); // describe('load/unload')
709
-
710
- describe('getConfiguration', () => {
711
- it('returns a copy of the configuration', () => {
712
- const config1 = player.getConfiguration();
713
- config1.streaming.bufferBehind = -99;
714
- const config2 = player.getConfiguration();
715
- expect(config1.streaming.bufferBehind).not.toBe(
716
- config2.streaming.bufferBehind);
717
- });
718
- });
719
-
720
- describe('configure', () => {
721
- it('overwrites defaults', () => {
722
- const defaultConfig = player.getConfiguration();
723
- // Make sure the default differs from our test value:
724
- expect(defaultConfig.drm.retryParameters.backoffFactor).not.toBe(5);
725
- expect(defaultConfig.manifest.retryParameters.backoffFactor).not.toBe(5);
726
-
727
- player.configure({
728
- drm: {
729
- retryParameters: {backoffFactor: 5},
730
- },
731
- });
732
-
733
- const newConfig = player.getConfiguration();
734
- // Make sure we changed the backoff for DRM, but not for manifests:
735
- expect(newConfig.drm.retryParameters.backoffFactor).toBe(5);
736
- expect(newConfig.manifest.retryParameters.backoffFactor).not.toBe(5);
737
- });
738
-
739
- it('reverts to defaults when undefined is given', () => {
740
- player.configure({
741
- streaming: {
742
- retryParameters: {backoffFactor: 5},
743
- bufferBehind: 7,
744
- },
745
- });
746
-
747
- let newConfig = player.getConfiguration();
748
- expect(newConfig.streaming.retryParameters.backoffFactor).toBe(5);
749
- expect(newConfig.streaming.bufferBehind).toBe(7);
750
-
751
- player.configure({
752
- streaming: {
753
- retryParameters: undefined,
754
- },
755
- });
756
-
757
- newConfig = player.getConfiguration();
758
- expect(newConfig.streaming.retryParameters.backoffFactor).not.toBe(5);
759
- expect(newConfig.streaming.bufferBehind).toBe(7);
760
-
761
- player.configure({streaming: undefined});
762
- newConfig = player.getConfiguration();
763
- expect(newConfig.streaming.bufferBehind).not.toBe(7);
764
- });
765
-
766
- it('restricts the types of config values', () => {
767
- logErrorSpy.and.stub();
768
- const defaultConfig = player.getConfiguration();
769
-
770
- // Try a bogus bufferBehind (string instead of number)
771
- player.configure({
772
- streaming: {bufferBehind: '77'},
773
- });
774
-
775
- let newConfig = player.getConfiguration();
776
- expect(newConfig).toEqual(defaultConfig);
777
- expect(logErrorSpy).toHaveBeenCalledWith(
778
- stringContaining('.streaming.bufferBehind'));
779
-
780
- // Try a bogus streaming config (number instead of Object)
781
- logErrorSpy.calls.reset();
782
- player.configure({
783
- drm: 5,
784
- });
785
-
786
- newConfig = player.getConfiguration();
787
- expect(newConfig).toEqual(defaultConfig);
788
- expect(logErrorSpy).toHaveBeenCalledWith(
789
- stringContaining('.drm'));
790
- });
791
-
792
- it('accepts synchronous function values for async function fields', () => {
793
- const defaultConfig = player.getConfiguration();
794
-
795
- // Make sure the default is async, or the test is invalid.
796
- const AsyncFunction = (async () => {}).constructor;
797
- expect(defaultConfig.offline.trackSelectionCallback.constructor)
798
- .toBe(AsyncFunction);
799
-
800
- // Try a synchronous callback.
801
- player.configure('offline.trackSelectionCallback', () => {});
802
- // If this fails, an error log will trigger test failure.
803
- });
804
-
805
- it('expands dictionaries that allow arbitrary keys', () => {
806
- player.configure({
807
- drm: {servers: {'com.widevine.alpha': 'http://foo/widevine'}},
808
- });
809
-
810
- let newConfig = player.getConfiguration();
811
- expect(newConfig.drm.servers).toEqual({
812
- 'com.widevine.alpha': 'http://foo/widevine',
813
- });
814
-
815
- player.configure({
816
- drm: {servers: {'com.microsoft.playready': 'http://foo/playready'}},
817
- });
818
-
819
- newConfig = player.getConfiguration();
820
- expect(newConfig.drm.servers).toEqual({
821
- 'com.widevine.alpha': 'http://foo/widevine',
822
- 'com.microsoft.playready': 'http://foo/playready',
823
- });
824
- });
825
-
826
- it('expands dictionaries but still restricts their values', () => {
827
- // Try a bogus server value (number instead of string)
828
- logErrorSpy.and.stub();
829
- player.configure({
830
- drm: {servers: {'com.widevine.alpha': 7}},
831
- });
832
-
833
- let newConfig = player.getConfiguration();
834
- expect(newConfig.drm.servers).toEqual({});
835
- expect(logErrorSpy).toHaveBeenCalledWith(
836
- stringContaining('.drm.servers.com.widevine.alpha'));
837
-
838
- // Try a valid advanced config.
839
- logErrorSpy.calls.reset();
840
- player.configure({
841
- drm: {advanced: {'ks1': {distinctiveIdentifierRequired: true}}},
842
- });
843
-
844
- newConfig = player.getConfiguration();
845
- expect(newConfig.drm.advanced).toEqual({
846
- 'ks1': jasmine.objectContaining({distinctiveIdentifierRequired: true}),
847
- });
848
- expect(logErrorSpy).not.toHaveBeenCalled();
849
- const lastGoodConfig = newConfig;
850
-
851
- // Try an invalid advanced config key.
852
- player.configure({
853
- drm: {advanced: {'ks1': {bogus: true}}},
854
- });
855
-
856
- newConfig = player.getConfiguration();
857
- expect(newConfig).toEqual(lastGoodConfig);
858
- expect(logErrorSpy).toHaveBeenCalledWith(
859
- stringContaining('.drm.advanced.ks1.bogus'));
860
- });
861
-
862
- it('removes dictionary entries when undefined is given', () => {
863
- player.configure({
864
- drm: {
865
- servers: {
866
- 'com.widevine.alpha': 'http://foo/widevine',
867
- 'com.microsoft.playready': 'http://foo/playready',
868
- },
869
- },
870
- });
871
-
872
- let newConfig = player.getConfiguration();
873
- expect(newConfig.drm.servers).toEqual({
874
- 'com.widevine.alpha': 'http://foo/widevine',
875
- 'com.microsoft.playready': 'http://foo/playready',
876
- });
877
-
878
- player.configure({
879
- drm: {servers: {'com.widevine.alpha': undefined}},
880
- });
881
-
882
- newConfig = player.getConfiguration();
883
- expect(newConfig.drm.servers).toEqual({
884
- 'com.microsoft.playready': 'http://foo/playready',
885
- });
886
-
887
- player.configure({
888
- drm: {servers: undefined},
889
- });
890
-
891
- newConfig = player.getConfiguration();
892
- expect(newConfig.drm.servers).toEqual({});
893
- });
894
-
895
- it('checks the number of arguments to functions', () => {
896
- const goodFailureCallback = (error) => {};
897
- const badFailureCallback1 = () => {}; // too few args
898
- const badFailureCallback2 = (x, y) => {}; // too many args
899
-
900
- // Takes good callback.
901
- player.configure({
902
- streaming: {failureCallback: goodFailureCallback},
903
- });
904
-
905
- let newConfig = player.getConfiguration();
906
- expect(newConfig.streaming.failureCallback).toBe(goodFailureCallback);
907
- expect(logWarnSpy).not.toHaveBeenCalled();
908
-
909
- // Warns about bad callback #1, still takes it.
910
- logWarnSpy.calls.reset();
911
- player.configure({
912
- streaming: {failureCallback: badFailureCallback1},
913
- });
914
-
915
- newConfig = player.getConfiguration();
916
- expect(newConfig.streaming.failureCallback).toBe(badFailureCallback1);
917
- expect(logWarnSpy).toHaveBeenCalledWith(
918
- stringContaining('.streaming.failureCallback'));
919
-
920
- // Warns about bad callback #2, still takes it.
921
- logWarnSpy.calls.reset();
922
- player.configure({
923
- streaming: {failureCallback: badFailureCallback2},
924
- });
925
-
926
- newConfig = player.getConfiguration();
927
- expect(newConfig.streaming.failureCallback).toBe(badFailureCallback2);
928
- expect(logWarnSpy).toHaveBeenCalledWith(
929
- stringContaining('.streaming.failureCallback'));
930
-
931
- // Resets to default if undefined.
932
- logWarnSpy.calls.reset();
933
- player.configure({
934
- streaming: {failureCallback: undefined},
935
- });
936
-
937
- newConfig = player.getConfiguration();
938
- expect(newConfig.streaming.failureCallback).not.toBe(badFailureCallback2);
939
- expect(logWarnSpy).not.toHaveBeenCalled();
940
- });
941
-
942
- // Regression test for https://github.com/shaka-project/shaka-player/issues/784
943
- it('does not throw when overwriting serverCertificate', () => {
944
- player.configure({
945
- drm: {
946
- advanced: {
947
- 'com.widevine.alpha': {
948
- serverCertificate: new Uint8Array(1),
949
- },
950
- },
951
- },
952
- });
953
-
954
- player.configure({
955
- drm: {
956
- advanced: {
957
- 'com.widevine.alpha': {
958
- serverCertificate: new Uint8Array(2),
959
- },
960
- },
961
- },
962
- });
963
- });
964
-
965
- it('checks the type of serverCertificate', () => {
966
- logErrorSpy.and.stub();
967
-
968
- player.configure({
969
- drm: {
970
- advanced: {
971
- 'com.widevine.alpha': {
972
- serverCertificate: null,
973
- },
974
- },
975
- },
976
- });
977
-
978
- expect(logErrorSpy).toHaveBeenCalledWith(
979
- stringContaining('.serverCertificate'));
980
-
981
- logErrorSpy.calls.reset();
982
- player.configure({
983
- drm: {
984
- advanced: {
985
- 'com.widevine.alpha': {
986
- serverCertificate: 'foobar',
987
- },
988
- },
989
- },
990
- });
991
-
992
- expect(logErrorSpy).toHaveBeenCalledWith(
993
- stringContaining('.serverCertificate'));
994
- });
995
-
996
- it('does not throw when null appears instead of an object', () => {
997
- logErrorSpy.and.stub();
998
-
999
- player.configure({
1000
- drm: {advanced: null},
1001
- });
1002
-
1003
- expect(logErrorSpy).toHaveBeenCalledWith(
1004
- stringContaining('.drm.advanced'));
1005
- });
1006
-
1007
- it('configures play and seek range for VOD', async () => {
1008
- const timeline = new shaka.media.PresentationTimeline(300, 0);
1009
- timeline.setStatic(true);
1010
- timeline.setDuration(300);
1011
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
1012
- manifest.presentationTimeline = timeline;
1013
- manifest.addVariant(0, (variant) => {
1014
- variant.addVideo(1);
1015
- });
1016
- });
1017
- goog.asserts.assert(manifest, 'manifest must be non-null');
1018
-
1019
- player.configure({playRangeStart: 5, playRangeEnd: 10});
1020
- await player.load(fakeManifestUri, 0, fakeMimeType);
1021
-
1022
- const seekRange = player.seekRange();
1023
- expect(seekRange.start).toBe(5);
1024
- expect(seekRange.end).toBe(10);
1025
- });
1026
-
1027
- // Test for https://github.com/shaka-project/shaka-player/issues/4026
1028
- it('configures play and seek range with notifySegments', async () => {
1029
- const timeline = new shaka.media.PresentationTimeline(300, 0);
1030
- timeline.setStatic(true);
1031
- // This duration is used by useSegmentTemplate below to decide how many
1032
- // references to generate.
1033
- timeline.setDuration(300);
1034
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
1035
- manifest.presentationTimeline = timeline;
1036
- manifest.addVariant(0, (variant) => {
1037
- variant.addVideo(1, (stream) => {
1038
- stream.useSegmentTemplate(
1039
- '$Number$.mp4', /* segmentDuration= */ 10);
1040
- });
1041
- });
1042
- });
1043
- goog.asserts.assert(manifest, 'manifest must be non-null');
1044
-
1045
- // Explicitly notify the timeline of the segment references.
1046
- const videoStream = manifest.variants[0].video;
1047
- await videoStream.createSegmentIndex();
1048
- goog.asserts.assert(videoStream.segmentIndex,
1049
- 'SegmentIndex must be non-null');
1050
- const references = Array.from(videoStream.segmentIndex);
1051
- goog.asserts.assert(references.length != 0,
1052
- 'Must have references for this test!');
1053
- timeline.notifySegments(references);
1054
-
1055
- player.configure({playRangeStart: 5, playRangeEnd: 10});
1056
- await player.load(fakeManifestUri, 0, fakeMimeType);
1057
-
1058
- const seekRange = player.seekRange();
1059
- expect(seekRange.start).toBe(5);
1060
- expect(seekRange.end).toBe(10);
1061
- });
1062
-
1063
- it('configures play and seek range after playback starts', async () => {
1064
- const timeline = new shaka.media.PresentationTimeline(300, 0);
1065
- timeline.setStatic(true);
1066
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
1067
- manifest.presentationTimeline = timeline;
1068
- manifest.addVariant(0, (variant) => {
1069
- variant.addVideo(1);
1070
- });
1071
- });
1072
- goog.asserts.assert(manifest, 'manifest must be non-null');
1073
- await player.load(fakeManifestUri, 0, fakeMimeType);
1074
- const seekRange = player.seekRange();
1075
- expect(seekRange.start).toBe(0);
1076
- expect(seekRange.end).toBe(Infinity);
1077
-
1078
- // Change the configuration after the playback starts.
1079
- player.configure({playRangeStart: 5, playRangeEnd: 10});
1080
- const seekRange2 = player.seekRange();
1081
- expect(seekRange2.start).toBe(5);
1082
- expect(seekRange2.end).toBe(10);
1083
- });
1084
-
1085
- it('does not switch for plain configuration changes', async () => {
1086
- await player.load(fakeManifestUri, 0, fakeMimeType);
1087
- streamingEngine.switchVariant.calls.reset();
1088
-
1089
- player.configure({abr: {enabled: false}});
1090
- player.configure({streaming: {bufferingGoal: 9001}});
1091
-
1092
- // Delay to ensure that the switch would have been called.
1093
- await shaka.test.Util.shortDelay();
1094
-
1095
- expect(streamingEngine.switchVariant).not.toHaveBeenCalled();
1096
- });
1097
-
1098
- it('accepts parameters in a (fieldName, value) format', () => {
1099
- const oldConfig = player.getConfiguration();
1100
- const oldDelayLicense = oldConfig.drm.delayLicenseRequestUntilPlayed;
1101
- const oldSwitchInterval = oldConfig.abr.switchInterval;
1102
- const oldPreferredLang = oldConfig.preferredAudioLanguage;
1103
-
1104
- expect(oldDelayLicense).toBe(false);
1105
- expect(oldSwitchInterval).toBe(8);
1106
- expect(oldPreferredLang).toBe('en');
1107
-
1108
- player.configure('drm.delayLicenseRequestUntilPlayed', true);
1109
- player.configure('abr.switchInterval', 10);
1110
- player.configure('preferredAudioLanguage', 'fr');
1111
-
1112
- const newConfig = player.getConfiguration();
1113
- const newDelayLicense = newConfig.drm.delayLicenseRequestUntilPlayed;
1114
- const newSwitchInterval = newConfig.abr.switchInterval;
1115
- const newPreferredLang = newConfig.preferredAudioLanguage;
1116
-
1117
- expect(newDelayLicense).toBe(true);
1118
- expect(newSwitchInterval).toBe(10);
1119
- expect(newPreferredLang).toBe('fr');
1120
- });
1121
-
1122
- it('accepts escaped "." in names', () => {
1123
- const convert = (name, value) => {
1124
- return shaka.util.ConfigUtils.convertToConfigObject(name, value);
1125
- };
1126
-
1127
- expect(convert('foo', 1)).toEqual({foo: 1});
1128
- expect(convert('foo.bar', 1)).toEqual({foo: {bar: 1}});
1129
- expect(convert('foo..bar', 1)).toEqual({foo: {'': {bar: 1}}});
1130
- expect(convert('foo.bar.baz', 1)).toEqual({foo: {bar: {baz: 1}}});
1131
- expect(convert('foo.bar\\.baz', 1)).toEqual({foo: {'bar.baz': 1}});
1132
- expect(convert('foo.baz.', 1)).toEqual({foo: {baz: {'': 1}}});
1133
- expect(convert('foo.baz\\.', 1)).toEqual({foo: {'baz.': 1}});
1134
- expect(convert('foo\\.bar', 1)).toEqual({'foo.bar': 1});
1135
- expect(convert('.foo', 1)).toEqual({'': {foo: 1}});
1136
- expect(convert('\\.foo', 1)).toEqual({'.foo': 1});
1137
- });
1138
-
1139
- it('returns whether the config was valid', () => {
1140
- logErrorSpy.and.stub();
1141
- expect(player.configure({streaming: {bufferBehind: '77'}})).toBe(false);
1142
- expect(player.configure({streaming: {bufferBehind: 77}})).toBe(true);
1143
- });
1144
-
1145
- it('still sets other fields when there are errors', () => {
1146
- logErrorSpy.and.stub();
1147
-
1148
- const changes = {
1149
- manifest: {foobar: false},
1150
- streaming: {bufferBehind: 77},
1151
- };
1152
- expect(player.configure(changes)).toBe(false);
1153
-
1154
- const newConfig = player.getConfiguration();
1155
- expect(newConfig.streaming.bufferBehind).toBe(77);
1156
- });
1157
-
1158
- // https://github.com/shaka-project/shaka-player/issues/1524
1159
- it('does not pollute other advanced DRM configs', () => {
1160
- player.configure('drm.advanced.foo', {});
1161
- player.configure('drm.advanced.bar', {});
1162
- const fooConfig1 = player.getConfiguration().drm.advanced['foo'];
1163
- const barConfig1 = player.getConfiguration().drm.advanced['bar'];
1164
- expect(fooConfig1.distinctiveIdentifierRequired).toBe(false);
1165
- expect(barConfig1.distinctiveIdentifierRequired).toBe(false);
1166
-
1167
- player.configure('drm.advanced.foo.distinctiveIdentifierRequired', true);
1168
- const fooConfig2 = player.getConfiguration().drm.advanced['foo'];
1169
- const barConfig2 = player.getConfiguration().drm.advanced['bar'];
1170
- expect(fooConfig2.distinctiveIdentifierRequired).toBe(true);
1171
- expect(barConfig2.distinctiveIdentifierRequired).toBe(false);
1172
- });
1173
-
1174
- it('sets default streaming configuration with low latency mode', () => {
1175
- player.configure({
1176
- streaming: {
1177
- lowLatencyMode: true,
1178
- rebufferingGoal: 1,
1179
- inaccurateManifestTolerance: 1,
1180
- segmentPrefetchLimit: 1,
1181
- },
1182
- });
1183
- expect(player.getConfiguration().streaming.rebufferingGoal).toBe(1);
1184
- expect(player.getConfiguration().streaming.inaccurateManifestTolerance)
1185
- .toBe(1);
1186
- expect(player.getConfiguration().streaming.segmentPrefetchLimit).toBe(1);
1187
-
1188
- // When low latency streaming gets enabled, rebufferingGoal will default
1189
- // to 0.01 if unless specified, inaccurateManifestTolerance will
1190
- // default to 0 unless specified, and segmentPrefetchLimit will
1191
- // default to 2 unless specified.
1192
- player.configure('streaming.lowLatencyMode', true);
1193
- expect(player.getConfiguration().streaming.rebufferingGoal).toBe(0.01);
1194
- expect(player.getConfiguration().streaming.inaccurateManifestTolerance)
1195
- .toBe(0);
1196
- expect(player.getConfiguration().streaming.segmentPrefetchLimit).toBe(2);
1197
- });
1198
- });
1199
-
1200
- describe('resetConfiguration', () => {
1201
- it('resets configurations to default', () => {
1202
- const default_ = player.getConfiguration().streaming.bufferingGoal;
1203
- expect(default_).not.toBe(100);
1204
- player.configure('streaming.bufferingGoal', 100);
1205
- expect(player.getConfiguration().streaming.bufferingGoal).toBe(100);
1206
- player.resetConfiguration();
1207
- expect(player.getConfiguration().streaming.bufferingGoal).toBe(default_);
1208
- });
1209
-
1210
- it('resets the arbitrary keys', () => {
1211
- player.configure('drm.servers.org\\.w3\\.clearKey', 'http://foo.com');
1212
- expect(player.getConfiguration().drm.servers).toEqual({
1213
- 'org.w3.clearKey': 'http://foo.com',
1214
- });
1215
- player.resetConfiguration();
1216
- expect(player.getConfiguration().drm.servers).toEqual({});
1217
- });
1218
-
1219
- it('keeps shared configuration the same', () => {
1220
- const config = player.getSharedConfiguration();
1221
- player.resetConfiguration();
1222
- expect(player.getSharedConfiguration()).toBe(config);
1223
- });
1224
- });
1225
-
1226
- describe('AbrManager', () => {
1227
- beforeEach(() => {
1228
- goog.asserts.assert(manifest, 'manifest must be non-null');
1229
- });
1230
-
1231
- it('sets through load', async () => {
1232
- await player.load(fakeManifestUri, 0, fakeMimeType);
1233
- expect(abrManager.init).toHaveBeenCalled();
1234
- });
1235
-
1236
- it('calls chooseVariant', async () => {
1237
- await player.load(fakeManifestUri, 0, fakeMimeType);
1238
- expect(abrManager.chooseVariant).toHaveBeenCalled();
1239
- });
1240
-
1241
- it('enables automatically', async () => {
1242
- await player.load(fakeManifestUri, 0, fakeMimeType);
1243
- expect(abrManager.enable).toHaveBeenCalled();
1244
- });
1245
-
1246
- it('does not enable if adaptation is disabled', async () => {
1247
- player.configure({abr: {enabled: false}});
1248
- await player.load(fakeManifestUri, 0, fakeMimeType);
1249
- expect(abrManager.enable).not.toHaveBeenCalled();
1250
- });
1251
-
1252
- it('enables/disables though configure', async () => {
1253
- await player.load(fakeManifestUri, 0, fakeMimeType);
1254
- abrManager.enable.calls.reset();
1255
- abrManager.disable.calls.reset();
1256
-
1257
- player.configure({abr: {enabled: false}});
1258
- expect(abrManager.disable).toHaveBeenCalled();
1259
-
1260
- player.configure({abr: {enabled: true}});
1261
- expect(abrManager.enable).toHaveBeenCalled();
1262
- });
1263
-
1264
- it('reuses AbrManager instance', async () => {
1265
- /** @type {!jasmine.Spy} */
1266
- const spy =
1267
- jasmine.createSpy('AbrManagerFactory').and.returnValue(abrManager);
1268
- player.configure({abrFactory: spy});
1269
-
1270
- await player.load(fakeManifestUri, 0, fakeMimeType);
1271
- expect(spy).toHaveBeenCalled();
1272
- spy.calls.reset();
1273
-
1274
- await player.load(fakeManifestUri, 0, fakeMimeType);
1275
- expect(spy).not.toHaveBeenCalled();
1276
- });
1277
-
1278
- it('creates new AbrManager if factory changes', async () => {
1279
- /** @type {!jasmine.Spy} */
1280
- const spy1 =
1281
- jasmine.createSpy('AbrManagerFactory').and.returnValue(abrManager);
1282
- /** @type {!jasmine.Spy} */
1283
- const spy2 =
1284
- jasmine.createSpy('AbrManagerFactory').and.returnValue(abrManager);
1285
- player.configure({abrFactory: spy1});
1286
-
1287
- await player.load(fakeManifestUri, 0, fakeMimeType);
1288
- expect(spy1).toHaveBeenCalled();
1289
- expect(spy2).not.toHaveBeenCalled();
1290
- spy1.calls.reset();
1291
-
1292
- player.configure({abrFactory: spy2});
1293
- await player.load(fakeManifestUri, 0, fakeMimeType);
1294
- expect(spy1).not.toHaveBeenCalled();
1295
- expect(spy2).toHaveBeenCalled();
1296
- });
1297
- });
1298
-
1299
- describe('filterTracks', () => {
1300
- it('retains only video+audio variants if they exist', async () => {
1301
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
1302
- manifest.addVariant(10, (variant) => {
1303
- variant.addAudio(1);
1304
- });
1305
- manifest.addVariant(11, (variant) => {
1306
- variant.addAudio(2);
1307
- variant.addVideo(3);
1308
- });
1309
- manifest.addVariant(12, (variant) => {
1310
- variant.addVideo(4);
1311
- });
1312
- });
1313
-
1314
- const variantTracks = [
1315
- jasmine.objectContaining({
1316
- id: 11,
1317
- active: true,
1318
- type: 'variant',
1319
- }),
1320
- ];
1321
-
1322
- await player.load(fakeManifestUri, 0, fakeMimeType);
1323
- const actualVariantTracks = player.getVariantTracks();
1324
- expect(actualVariantTracks).toEqual(variantTracks);
1325
- });
1326
- });
1327
-
1328
- describe('tracks', () => {
1329
- /** @type {!Array.<shaka.extern.Track>} */
1330
- let variantTracks;
1331
- /** @type {!Array.<shaka.extern.Track>} */
1332
- let textTracks;
1333
- /** @type {!Array.<shaka.extern.Track>} */
1334
- let imageTracks;
1335
-
1336
- beforeEach(async () => {
1337
- // A manifest we can use to test track expectations.
1338
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
1339
- manifest.addVariant(100, (variant) => { // main surround, low res
1340
- variant.bandwidth = 1300;
1341
- variant.language = 'en';
1342
- variant.addVideo(1, (stream) => {
1343
- stream.originalId = 'video-1kbps';
1344
- stream.bandwidth = 1000;
1345
- stream.width = 100;
1346
- stream.height = 200;
1347
- stream.frameRate = 1000000 / 42000;
1348
- stream.pixelAspectRatio = '59:54';
1349
- stream.roles = ['main'];
1350
- });
1351
- variant.addAudio(3, (stream) => {
1352
- stream.originalId = 'audio-en-6c';
1353
- stream.bandwidth = 300;
1354
- stream.channelsCount = 6;
1355
- stream.audioSamplingRate = 48000;
1356
- stream.roles = ['main'];
1357
- });
1358
- });
1359
- manifest.addVariant(101, (variant) => { // main surround, high res
1360
- variant.bandwidth = 2300;
1361
- variant.language = 'en';
1362
- variant.addVideo(2, (stream) => {
1363
- stream.originalId = 'video-2kbps';
1364
- stream.bandwidth = 2000;
1365
- stream.frameRate = 24;
1366
- stream.pixelAspectRatio = '59:54';
1367
- stream.size(200, 400);
1368
- });
1369
- variant.addExistingStream(3); // audio
1370
- });
1371
- manifest.addVariant(102, (variant) => { // main stereo, low res
1372
- variant.bandwidth = 1100;
1373
- variant.language = 'en';
1374
- variant.addExistingStream(1); // video
1375
- variant.addAudio(4, (stream) => {
1376
- stream.originalId = 'audio-en-2c';
1377
- stream.bandwidth = 100;
1378
- stream.channelsCount = 2;
1379
- stream.audioSamplingRate = 48000;
1380
- stream.roles = ['main'];
1381
- });
1382
- });
1383
- manifest.addVariant(103, (variant) => { // main stereo, high res
1384
- variant.bandwidth = 2100;
1385
- variant.language = 'en';
1386
- variant.addExistingStream(2); // video
1387
- variant.addExistingStream(4); // audio
1388
- });
1389
- manifest.addVariant(104, (variant) => { // commentary stereo, low res
1390
- variant.bandwidth = 1100;
1391
- variant.language = 'en';
1392
- variant.addExistingStream(1); // video
1393
- variant.addAudio(5, (stream) => {
1394
- stream.originalId = 'audio-commentary';
1395
- stream.bandwidth = 100;
1396
- stream.channelsCount = 2;
1397
- stream.audioSamplingRate = 48000;
1398
- stream.roles = ['commentary'];
1399
- });
1400
- });
1401
- manifest.addVariant(105, (variant) => { // commentary stereo, low res
1402
- variant.bandwidth = 2100;
1403
- variant.language = 'en';
1404
- variant.addExistingStream(2); // video
1405
- variant.addExistingStream(5); // audio
1406
- });
1407
- manifest.addVariant(106, (variant) => { // spanish stereo, low res
1408
- variant.language = 'es';
1409
- variant.bandwidth = 1100;
1410
- variant.label = 'es-label';
1411
- variant.addExistingStream(1); // video
1412
- variant.addAudio(6, (stream) => {
1413
- stream.originalId = 'audio-es';
1414
- stream.bandwidth = 100;
1415
- stream.channelsCount = 2;
1416
- stream.audioSamplingRate = 48000;
1417
- });
1418
- });
1419
- manifest.addVariant(107, (variant) => { // spanish stereo, high res
1420
- variant.language = 'es';
1421
- variant.bandwidth = 2100;
1422
- variant.label = 'es-label';
1423
- variant.addExistingStream(2); // video
1424
- variant.addExistingStream(6); // audio
1425
- });
1426
-
1427
- // All text tracks should remain, even with different MIME types.
1428
- manifest.addTextStream(50, (stream) => {
1429
- stream.originalId = 'text-es';
1430
- stream.language = 'es';
1431
- stream.originalLanguage = 'es';
1432
- stream.label = 'Spanish';
1433
- stream.bandwidth = 10;
1434
- stream.mimeType = 'text/vtt';
1435
- stream.kind = 'caption';
1436
- });
1437
- manifest.addTextStream(51, (stream) => {
1438
- stream.originalId = 'text-en';
1439
- stream.language = 'en';
1440
- stream.originalLanguage = 'en';
1441
- stream.label = 'English';
1442
- stream.bandwidth = 10;
1443
- stream.mimeType = 'application/ttml+xml';
1444
- stream.kind = 'caption';
1445
- stream.roles = ['main'];
1446
- });
1447
- manifest.addTextStream(52, (stream) => {
1448
- stream.originalId = 'text-commentary';
1449
- stream.language = 'en';
1450
- stream.originalLanguage = 'en';
1451
- stream.label = 'English';
1452
- stream.bandwidth = 10;
1453
- stream.mimeType = 'application/ttml+xml';
1454
- stream.kind = 'caption';
1455
- stream.roles = ['commentary'];
1456
- });
1457
-
1458
- // Image tracks
1459
- manifest.addImageStream(53, (stream) => {
1460
- stream.originalId = 'thumbnail';
1461
- stream.width = 200;
1462
- stream.height = 400;
1463
- stream.bandwidth = 10;
1464
- stream.mimeType = 'image/jpeg';
1465
- stream.tilesLayout = '1x1';
1466
- });
1467
- });
1468
-
1469
- variantTracks = [
1470
- {
1471
- id: 100,
1472
- active: true,
1473
- type: 'variant',
1474
- bandwidth: 1300,
1475
- language: 'en',
1476
- originalLanguage: 'en',
1477
- label: null,
1478
- kind: null,
1479
- width: 100,
1480
- height: 200,
1481
- frameRate: 1000000 / 42000,
1482
- pixelAspectRatio: '59:54',
1483
- hdr: null,
1484
- videoLayout: null,
1485
- mimeType: 'video/mp4',
1486
- audioMimeType: 'audio/mp4',
1487
- videoMimeType: 'video/mp4',
1488
- codecs: 'avc1.4d401f, mp4a.40.2',
1489
- audioCodec: 'mp4a.40.2',
1490
- videoCodec: 'avc1.4d401f',
1491
- primary: false,
1492
- roles: ['main'],
1493
- audioRoles: ['main'],
1494
- forced: false,
1495
- videoId: 1,
1496
- audioId: 3,
1497
- channelsCount: 6,
1498
- audioSamplingRate: 48000,
1499
- spatialAudio: false,
1500
- tilesLayout: null,
1501
- audioBandwidth: 300,
1502
- videoBandwidth: 1000,
1503
- originalAudioId: 'audio-en-6c',
1504
- originalVideoId: 'video-1kbps',
1505
- originalTextId: null,
1506
- originalImageId: null,
1507
- accessibilityPurpose: undefined,
1508
- },
1509
- {
1510
- id: 101,
1511
- active: false,
1512
- type: 'variant',
1513
- bandwidth: 2300,
1514
- language: 'en',
1515
- originalLanguage: 'en',
1516
- label: null,
1517
- kind: null,
1518
- width: 200,
1519
- height: 400,
1520
- frameRate: 24,
1521
- pixelAspectRatio: '59:54',
1522
- hdr: null,
1523
- videoLayout: null,
1524
- mimeType: 'video/mp4',
1525
- audioMimeType: 'audio/mp4',
1526
- videoMimeType: 'video/mp4',
1527
- codecs: 'avc1.4d401f, mp4a.40.2',
1528
- audioCodec: 'mp4a.40.2',
1529
- videoCodec: 'avc1.4d401f',
1530
- primary: false,
1531
- roles: ['main'],
1532
- audioRoles: ['main'],
1533
- forced: false,
1534
- videoId: 2,
1535
- audioId: 3,
1536
- channelsCount: 6,
1537
- audioSamplingRate: 48000,
1538
- spatialAudio: false,
1539
- tilesLayout: null,
1540
- audioBandwidth: 300,
1541
- videoBandwidth: 2000,
1542
- originalAudioId: 'audio-en-6c',
1543
- originalVideoId: 'video-2kbps',
1544
- originalTextId: null,
1545
- originalImageId: null,
1546
- accessibilityPurpose: undefined,
1547
- },
1548
- {
1549
- id: 102,
1550
- active: false,
1551
- type: 'variant',
1552
- bandwidth: 1100,
1553
- language: 'en',
1554
- originalLanguage: 'en',
1555
- label: null,
1556
- kind: null,
1557
- width: 100,
1558
- height: 200,
1559
- frameRate: 1000000 / 42000,
1560
- pixelAspectRatio: '59:54',
1561
- hdr: null,
1562
- videoLayout: null,
1563
- mimeType: 'video/mp4',
1564
- audioMimeType: 'audio/mp4',
1565
- videoMimeType: 'video/mp4',
1566
- codecs: 'avc1.4d401f, mp4a.40.2',
1567
- audioCodec: 'mp4a.40.2',
1568
- videoCodec: 'avc1.4d401f',
1569
- primary: false,
1570
- roles: ['main'],
1571
- audioRoles: ['main'],
1572
- forced: false,
1573
- videoId: 1,
1574
- audioId: 4,
1575
- channelsCount: 2,
1576
- audioSamplingRate: 48000,
1577
- spatialAudio: false,
1578
- tilesLayout: null,
1579
- audioBandwidth: 100,
1580
- videoBandwidth: 1000,
1581
- originalAudioId: 'audio-en-2c',
1582
- originalVideoId: 'video-1kbps',
1583
- originalTextId: null,
1584
- originalImageId: null,
1585
- accessibilityPurpose: undefined,
1586
- },
1587
- {
1588
- id: 103,
1589
- active: false,
1590
- type: 'variant',
1591
- bandwidth: 2100,
1592
- language: 'en',
1593
- originalLanguage: 'en',
1594
- label: null,
1595
- kind: null,
1596
- width: 200,
1597
- height: 400,
1598
- frameRate: 24,
1599
- pixelAspectRatio: '59:54',
1600
- hdr: null,
1601
- videoLayout: null,
1602
- mimeType: 'video/mp4',
1603
- audioMimeType: 'audio/mp4',
1604
- videoMimeType: 'video/mp4',
1605
- codecs: 'avc1.4d401f, mp4a.40.2',
1606
- audioCodec: 'mp4a.40.2',
1607
- videoCodec: 'avc1.4d401f',
1608
- primary: false,
1609
- roles: ['main'],
1610
- audioRoles: ['main'],
1611
- forced: false,
1612
- videoId: 2,
1613
- audioId: 4,
1614
- channelsCount: 2,
1615
- audioSamplingRate: 48000,
1616
- spatialAudio: false,
1617
- tilesLayout: null,
1618
- audioBandwidth: 100,
1619
- videoBandwidth: 2000,
1620
- originalAudioId: 'audio-en-2c',
1621
- originalVideoId: 'video-2kbps',
1622
- originalTextId: null,
1623
- originalImageId: null,
1624
- accessibilityPurpose: undefined,
1625
- },
1626
- {
1627
- id: 104,
1628
- active: false,
1629
- type: 'variant',
1630
- bandwidth: 1100,
1631
- language: 'en',
1632
- originalLanguage: 'en',
1633
- label: null,
1634
- kind: null,
1635
- width: 100,
1636
- height: 200,
1637
- frameRate: 1000000 / 42000,
1638
- pixelAspectRatio: '59:54',
1639
- hdr: null,
1640
- videoLayout: null,
1641
- mimeType: 'video/mp4',
1642
- audioMimeType: 'audio/mp4',
1643
- videoMimeType: 'video/mp4',
1644
- codecs: 'avc1.4d401f, mp4a.40.2',
1645
- audioCodec: 'mp4a.40.2',
1646
- videoCodec: 'avc1.4d401f',
1647
- primary: false,
1648
- roles: ['commentary', 'main'],
1649
- audioRoles: ['commentary'],
1650
- forced: false,
1651
- videoId: 1,
1652
- audioId: 5,
1653
- channelsCount: 2,
1654
- audioSamplingRate: 48000,
1655
- spatialAudio: false,
1656
- tilesLayout: null,
1657
- audioBandwidth: 100,
1658
- videoBandwidth: 1000,
1659
- originalAudioId: 'audio-commentary',
1660
- originalVideoId: 'video-1kbps',
1661
- originalTextId: null,
1662
- originalImageId: null,
1663
- accessibilityPurpose: undefined,
1664
- },
1665
- {
1666
- id: 105,
1667
- active: false,
1668
- type: 'variant',
1669
- bandwidth: 2100,
1670
- language: 'en',
1671
- originalLanguage: 'en',
1672
- label: null,
1673
- kind: null,
1674
- width: 200,
1675
- height: 400,
1676
- frameRate: 24,
1677
- pixelAspectRatio: '59:54',
1678
- hdr: null,
1679
- videoLayout: null,
1680
- mimeType: 'video/mp4',
1681
- audioMimeType: 'audio/mp4',
1682
- videoMimeType: 'video/mp4',
1683
- codecs: 'avc1.4d401f, mp4a.40.2',
1684
- audioCodec: 'mp4a.40.2',
1685
- videoCodec: 'avc1.4d401f',
1686
- primary: false,
1687
- roles: ['commentary'],
1688
- audioRoles: ['commentary'],
1689
- forced: false,
1690
- videoId: 2,
1691
- audioId: 5,
1692
- channelsCount: 2,
1693
- audioSamplingRate: 48000,
1694
- spatialAudio: false,
1695
- tilesLayout: null,
1696
- audioBandwidth: 100,
1697
- videoBandwidth: 2000,
1698
- originalAudioId: 'audio-commentary',
1699
- originalVideoId: 'video-2kbps',
1700
- originalTextId: null,
1701
- originalImageId: null,
1702
- accessibilityPurpose: undefined,
1703
- },
1704
- {
1705
- id: 106,
1706
- active: false,
1707
- type: 'variant',
1708
- bandwidth: 1100,
1709
- language: 'es',
1710
- label: 'es-label',
1711
- originalLanguage: 'es',
1712
- kind: null,
1713
- width: 100,
1714
- height: 200,
1715
- frameRate: 1000000 / 42000,
1716
- pixelAspectRatio: '59:54',
1717
- hdr: null,
1718
- videoLayout: null,
1719
- mimeType: 'video/mp4',
1720
- audioMimeType: 'audio/mp4',
1721
- videoMimeType: 'video/mp4',
1722
- codecs: 'avc1.4d401f, mp4a.40.2',
1723
- audioCodec: 'mp4a.40.2',
1724
- videoCodec: 'avc1.4d401f',
1725
- primary: false,
1726
- roles: ['main'],
1727
- audioRoles: [],
1728
- forced: false,
1729
- videoId: 1,
1730
- audioId: 6,
1731
- channelsCount: 2,
1732
- audioSamplingRate: 48000,
1733
- spatialAudio: false,
1734
- tilesLayout: null,
1735
- audioBandwidth: 100,
1736
- videoBandwidth: 1000,
1737
- originalAudioId: 'audio-es',
1738
- originalVideoId: 'video-1kbps',
1739
- originalTextId: null,
1740
- originalImageId: null,
1741
- accessibilityPurpose: undefined,
1742
- },
1743
- {
1744
- id: 107,
1745
- active: false,
1746
- type: 'variant',
1747
- bandwidth: 2100,
1748
- language: 'es',
1749
- label: 'es-label',
1750
- originalLanguage: 'es',
1751
- kind: null,
1752
- width: 200,
1753
- height: 400,
1754
- frameRate: 24,
1755
- pixelAspectRatio: '59:54',
1756
- hdr: null,
1757
- videoLayout: null,
1758
- mimeType: 'video/mp4',
1759
- audioMimeType: 'audio/mp4',
1760
- videoMimeType: 'video/mp4',
1761
- codecs: 'avc1.4d401f, mp4a.40.2',
1762
- audioCodec: 'mp4a.40.2',
1763
- videoCodec: 'avc1.4d401f',
1764
- primary: false,
1765
- roles: [],
1766
- audioRoles: [],
1767
- forced: false,
1768
- videoId: 2,
1769
- audioId: 6,
1770
- channelsCount: 2,
1771
- audioSamplingRate: 48000,
1772
- spatialAudio: false,
1773
- tilesLayout: null,
1774
- audioBandwidth: 100,
1775
- videoBandwidth: 2000,
1776
- originalAudioId: 'audio-es',
1777
- originalVideoId: 'video-2kbps',
1778
- originalTextId: null,
1779
- originalImageId: null,
1780
- accessibilityPurpose: undefined,
1781
- },
1782
- ];
1783
-
1784
- textTracks = [
1785
- {
1786
- id: 50,
1787
- active: true,
1788
- type: ContentType.TEXT,
1789
- language: 'es',
1790
- originalLanguage: 'es',
1791
- label: 'Spanish',
1792
- kind: 'caption',
1793
- mimeType: 'text/vtt',
1794
- audioMimeType: null,
1795
- videoMimeType: null,
1796
- codecs: null,
1797
- audioCodec: null,
1798
- videoCodec: null,
1799
- primary: false,
1800
- roles: [],
1801
- audioRoles: null,
1802
- forced: false,
1803
- channelsCount: null,
1804
- audioSamplingRate: null,
1805
- spatialAudio: false,
1806
- tilesLayout: null,
1807
- audioBandwidth: null,
1808
- videoBandwidth: null,
1809
- bandwidth: 0,
1810
- width: null,
1811
- height: null,
1812
- frameRate: null,
1813
- pixelAspectRatio: null,
1814
- hdr: null,
1815
- videoLayout: null,
1816
- videoId: null,
1817
- audioId: null,
1818
- originalAudioId: null,
1819
- originalVideoId: null,
1820
- originalTextId: 'text-es',
1821
- originalImageId: null,
1822
- accessibilityPurpose: undefined,
1823
- },
1824
- {
1825
- id: 51,
1826
- active: false,
1827
- type: ContentType.TEXT,
1828
- language: 'en',
1829
- originalLanguage: 'en',
1830
- label: 'English',
1831
- kind: 'caption',
1832
- mimeType: 'application/ttml+xml',
1833
- audioMimeType: null,
1834
- videoMimeType: null,
1835
- codecs: null,
1836
- audioCodec: null,
1837
- videoCodec: null,
1838
- primary: false,
1839
- roles: ['main'],
1840
- audioRoles: null,
1841
- forced: false,
1842
- channelsCount: null,
1843
- audioSamplingRate: null,
1844
- spatialAudio: false,
1845
- tilesLayout: null,
1846
- audioBandwidth: null,
1847
- videoBandwidth: null,
1848
- bandwidth: 0,
1849
- width: null,
1850
- height: null,
1851
- frameRate: null,
1852
- pixelAspectRatio: null,
1853
- hdr: null,
1854
- videoLayout: null,
1855
- videoId: null,
1856
- audioId: null,
1857
- originalAudioId: null,
1858
- originalVideoId: null,
1859
- originalTextId: 'text-en',
1860
- originalImageId: null,
1861
- accessibilityPurpose: undefined,
1862
- },
1863
- {
1864
- id: 52,
1865
- active: false,
1866
- type: ContentType.TEXT,
1867
- language: 'en',
1868
- originalLanguage: 'en',
1869
- label: 'English',
1870
- kind: 'caption',
1871
- mimeType: 'application/ttml+xml',
1872
- audioMimeType: null,
1873
- videoMimeType: null,
1874
- codecs: null,
1875
- audioCodec: null,
1876
- videoCodec: null,
1877
- primary: false,
1878
- roles: ['commentary'],
1879
- audioRoles: null,
1880
- forced: false,
1881
- channelsCount: null,
1882
- spatialAudio: false,
1883
- audioSamplingRate: null,
1884
- tilesLayout: null,
1885
- audioBandwidth: null,
1886
- videoBandwidth: null,
1887
- bandwidth: 0,
1888
- width: null,
1889
- height: null,
1890
- frameRate: null,
1891
- pixelAspectRatio: null,
1892
- hdr: null,
1893
- videoLayout: null,
1894
- videoId: null,
1895
- audioId: null,
1896
- originalAudioId: null,
1897
- originalVideoId: null,
1898
- originalTextId: 'text-commentary',
1899
- originalImageId: null,
1900
- accessibilityPurpose: undefined,
1901
- },
1902
- ];
1903
-
1904
- imageTracks = [
1905
- {
1906
- id: 53,
1907
- active: false,
1908
- type: ContentType.IMAGE,
1909
- language: '',
1910
- originalLanguage: null,
1911
- label: null,
1912
- kind: null,
1913
- mimeType: 'image/jpeg',
1914
- audioMimeType: null,
1915
- videoMimeType: null,
1916
- codecs: null,
1917
- audioCodec: null,
1918
- videoCodec: null,
1919
- primary: false,
1920
- roles: [],
1921
- audioRoles: null,
1922
- forced: false,
1923
- channelsCount: null,
1924
- audioSamplingRate: null,
1925
- spatialAudio: false,
1926
- tilesLayout: '1x1',
1927
- audioBandwidth: null,
1928
- videoBandwidth: null,
1929
- bandwidth: 10,
1930
- width: 200,
1931
- height: 400,
1932
- frameRate: null,
1933
- pixelAspectRatio: null,
1934
- hdr: null,
1935
- videoLayout: null,
1936
- videoId: null,
1937
- audioId: null,
1938
- originalAudioId: null,
1939
- originalVideoId: null,
1940
- originalTextId: null,
1941
- originalImageId: 'thumbnail',
1942
- accessibilityPurpose: null,
1943
- },
1944
- ];
1945
-
1946
- goog.asserts.assert(manifest, 'manifest must be non-null');
1947
-
1948
- // Language/channel prefs must be set before load. Used in
1949
- // select*Language() tests.
1950
- player.configure({
1951
- preferredAudioLanguage: 'en',
1952
- preferredTextLanguage: 'es',
1953
- preferredAudioChannelCount: 6,
1954
- });
1955
-
1956
- await player.load(fakeManifestUri, 0, fakeMimeType);
1957
- streamingEngine.switchVariant.calls.reset();
1958
- streamingEngine.switchTextStream.calls.reset();
1959
- });
1960
-
1961
- it('returns the correct tracks', () => {
1962
- expect(player.getVariantTracks()).toEqual(variantTracks);
1963
- expect(player.getTextTracks()).toEqual(textTracks);
1964
- expect(player.getImageTracks()).toEqual(imageTracks);
1965
- });
1966
-
1967
- it('returns empty arrays before tracks can be determined', async () => {
1968
- const parser = new shaka.test.FakeManifestParser(manifest);
1969
-
1970
- parser.start.and.callFake((manifestUri, playerInterface) => {
1971
- // The player does not yet have a manifest.
1972
- expect(player.getVariantTracks()).toEqual([]);
1973
- expect(player.getTextTracks()).toEqual([]);
1974
- expect(player.getImageTracks()).toEqual([]);
1975
-
1976
- parser.playerInterface = playerInterface;
1977
- return Promise.resolve(manifest);
1978
- });
1979
-
1980
- await player.load(fakeManifestUri, 0, fakeMimeType);
1981
-
1982
- expect(player.getVariantTracks()).toEqual(variantTracks);
1983
- expect(player.getTextTracks()).toEqual(textTracks);
1984
- expect(player.getImageTracks()).toEqual(imageTracks);
1985
- });
1986
-
1987
- it('doesn\'t disable AbrManager if switching variants', () => {
1988
- let config = player.getConfiguration();
1989
- expect(config.abr.enabled).toBe(true);
1990
-
1991
- const newTrack = player.getVariantTracks().filter((t) => !t.active)[0];
1992
- player.selectVariantTrack(newTrack);
1993
-
1994
- config = player.getConfiguration();
1995
- expect(config.abr.enabled).toBe(true);
1996
- });
1997
-
1998
- it('doesn\'t disable AbrManager if switching text', () => {
1999
- let config = player.getConfiguration();
2000
- expect(config.abr.enabled).toBe(true);
2001
-
2002
- const newTrack = player.getTextTracks().filter((t) => !t.active)[0];
2003
- player.selectTextTrack(newTrack);
2004
-
2005
- config = player.getConfiguration();
2006
- expect(config.abr.enabled).toBe(true);
2007
- });
2008
-
2009
- it('switches streams', () => {
2010
- const newTrack = player.getVariantTracks().filter((t) => !t.active)[0];
2011
- player.selectVariantTrack(newTrack);
2012
-
2013
- expect(streamingEngine.switchVariant).toHaveBeenCalled();
2014
- const variant = streamingEngine.switchVariant.calls.argsFor(0)[0];
2015
- expect(variant.id).toBe(newTrack.id);
2016
- });
2017
-
2018
- it('switching audio doesn\'t change selected text track', () => {
2019
- player.configure({
2020
- preferredTextLanguage: 'es',
2021
- });
2022
-
2023
- // We will manually switch from Spanish to English.
2024
- const englishTextTrack =
2025
- player.getTextTracks().filter((t) => t.language == 'en')[0];
2026
-
2027
- player.selectTextTrack(englishTextTrack);
2028
- expect(streamingEngine.switchTextStream).toHaveBeenCalled();
2029
- // We have selected an English text track explicitly.
2030
- expect(getActiveTextTrack().id).toBe(englishTextTrack.id);
2031
-
2032
- const newVariantTrack =
2033
- player.getVariantTracks().filter((t) => !t.active)[0];
2034
- player.selectVariantTrack(newVariantTrack);
2035
-
2036
- // The active text track has not changed, even though the text language
2037
- // preference is Spanish.
2038
- expect(getActiveTextTrack().id).toBe(englishTextTrack.id);
2039
- });
2040
-
2041
- it('selectAudioLanguage() takes precedence over ' +
2042
- 'preferredAudioLanguage', () => {
2043
- // This preference is set in beforeEach, before load().
2044
- expect(player.getConfiguration().preferredAudioLanguage).toBe('en');
2045
- expect(getActiveVariantTrack().language).toBe('en');
2046
-
2047
- player.selectAudioLanguage('es');
2048
-
2049
- expect(streamingEngine.switchVariant).toHaveBeenCalled();
2050
- const args = streamingEngine.switchVariant.calls.argsFor(0);
2051
- expect(args[0].language).toBe('es');
2052
- expect(args[1]).toBe(true);
2053
- expect(getActiveVariantTrack().language).toBe('es');
2054
- });
2055
-
2056
- it('selectAudioLanguage() respects selected role', () => {
2057
- expect(getActiveVariantTrack().roles).not.toContain('commentary');
2058
-
2059
- player.selectAudioLanguage('en', 'commentary');
2060
-
2061
- expect(streamingEngine.switchVariant).toHaveBeenCalled();
2062
- const args = streamingEngine.switchVariant.calls.argsFor(0);
2063
- expect(args[0].audio.roles).toContain('commentary');
2064
- expect(args[1]).toBe(true);
2065
- expect(getActiveVariantTrack().roles).toContain('commentary');
2066
- });
2067
-
2068
- it('selectAudioLanguage() applies role only to audio', () => {
2069
- expect(getActiveVariantTrack().roles).not.toContain('commentary');
2070
- player.selectAudioLanguage('en', 'commentary');
2071
- let args = streamingEngine.switchVariant.calls.argsFor(0);
2072
- expect(args[0].audio.roles).toContain('commentary');
2073
- expect(args[0].video.roles).toContain('main');
2074
-
2075
- // Switch audio role from 'commentary' to 'main'.
2076
- streamingEngine.switchVariant.calls.reset();
2077
- player.selectAudioLanguage('en', 'main');
2078
- expect(streamingEngine.switchVariant).toHaveBeenCalled();
2079
- args = streamingEngine.switchVariant.calls.argsFor(0);
2080
- expect(args[0].audio.roles).toContain('main');
2081
- expect(args[0].video.roles).toContain('main');
2082
- });
2083
-
2084
- it('selectAudioLanguage() does not change selected text track', () => {
2085
- // This came up in a custom application that allows to select
2086
- // from all tracks regardless of selected language.
2087
- // We imitate this behavior by calling selectTextLanguage()
2088
- // with one language and then selecting a track in a different
2089
- // language.
2090
- player.selectTextLanguage('en');
2091
- const spanishTextTrack = textTracks.filter((t) => t.language == 'es')[0];
2092
- player.selectTextTrack(spanishTextTrack);
2093
- player.selectAudioLanguage('es');
2094
- expect(getActiveTextTrack().id).toBe(spanishTextTrack.id);
2095
- });
2096
-
2097
- // Regression test for https://github.com/shaka-project/shaka-player/issues/2906
2098
- // and https://github.com/shaka-project/shaka-player/issues/2909.
2099
- it('selectAudioLanguage() can choose role-less tracks', async () => {
2100
- // For this test, we use a different (and simpler) manifest.
2101
- // Both audio tracks are English; one has a role, and one has no roles.
2102
- // The role=description track comes first to reproduce the conditions in
2103
- // #2909.
2104
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
2105
- manifest.addVariant(100, (variant) => {
2106
- variant.bandwidth = 1300;
2107
- variant.language = 'en';
2108
- variant.addVideo(1, (stream) => {
2109
- stream.originalId = 'video';
2110
- stream.bandwidth = 1000;
2111
- stream.width = 100;
2112
- stream.height = 200;
2113
- stream.frameRate = 1000000 / 42000;
2114
- stream.pixelAspectRatio = '59:54';
2115
- stream.roles = [];
2116
- });
2117
- variant.addAudio(2, (stream) => {
2118
- stream.originalId = 'audio-en-description';
2119
- stream.bandwidth = 100;
2120
- stream.channelsCount = 2;
2121
- stream.audioSamplingRate = 48000;
2122
- stream.roles = ['description'];
2123
- });
2124
- });
2125
- manifest.addVariant(101, (variant) => {
2126
- variant.bandwidth = 2300;
2127
- variant.language = 'en';
2128
- variant.addExistingStream(1); // video
2129
- variant.addAudio(3, (stream) => {
2130
- stream.originalId = 'audio-en';
2131
- stream.bandwidth = 100;
2132
- stream.channelsCount = 2;
2133
- stream.audioSamplingRate = 48000;
2134
- stream.roles = [];
2135
- });
2136
- });
2137
- });
2138
-
2139
- // No explicit preferred audio language is also part of #2909.
2140
- player.configure('preferredAudioLanguage', undefined);
2141
-
2142
- // Load again to get this test-specific manifest loaded.
2143
- await player.load(fakeManifestUri, 0, fakeMimeType);
2144
-
2145
- // #2909: The initial choice should be for the role-less track, even
2146
- // though it is second in the manifest.
2147
- expect(getActiveVariantTrack().audioRoles).toEqual([]);
2148
-
2149
- player.selectAudioLanguage('en', 'description');
2150
- expect(getActiveVariantTrack().audioRoles).toEqual(['description']);
2151
-
2152
- // #2906: Selecting no particular role should prefer the track without any
2153
- // roles.
2154
- player.selectAudioLanguage('en');
2155
- expect(getActiveVariantTrack().audioRoles).toEqual([]);
2156
- });
2157
-
2158
- // https://github.com/shaka-project/shaka-player/issues/3262
2159
- it('selectAudioLanguage() doesn\'t change resolution', () => {
2160
- player.configure('abr.enabled', false);
2161
- abrManager.chooseIndex = 1;
2162
- const lowResEn =
2163
- variantTracks.filter((t) => t.language == 'en' && t.height == 200)[0];
2164
- player.selectVariantTrack(lowResEn);
2165
-
2166
- // Switching to 'es' should keep the low-res stream and not choose the
2167
- // high-res version.
2168
- player.selectAudioLanguage('es');
2169
- const lowResEs =
2170
- variantTracks.filter((t) => t.language == 'es' && t.height == 200)[0];
2171
- expect(getActiveVariantTrack().id).toBe(lowResEs.id);
2172
- });
2173
-
2174
- it('selectTextLanguage() does not change selected variant track', () => {
2175
- // This came up in a custom application that allows to select
2176
- // from all tracks regardless of selected language.
2177
- // We imitate this behavior by calling selectAudioLanguage()
2178
- // with one language and then selecting a track in a different
2179
- // language.
2180
- player.selectAudioLanguage('es');
2181
- const englishVariantTrack =
2182
- variantTracks.filter((t) => t.language == 'en')[0];
2183
- player.selectVariantTrack(englishVariantTrack);
2184
- player.selectTextLanguage('es');
2185
- expect(getActiveVariantTrack().id).toBe(englishVariantTrack.id);
2186
- });
2187
-
2188
- it('selectTextLanguage() takes precedence over ' +
2189
- 'preferredTextLanguage', () => {
2190
- // This preference is set in beforeEach, before load().
2191
- expect(player.getConfiguration().preferredTextLanguage).toBe('es');
2192
- expect(getActiveTextTrack().language).toBe('es');
2193
-
2194
- player.selectTextLanguage('en');
2195
-
2196
- expect(streamingEngine.switchTextStream).toHaveBeenCalled();
2197
- const args = streamingEngine.switchTextStream.calls.argsFor(0);
2198
- expect(args[0].language).toBe('en');
2199
- expect(getActiveTextTrack().language).toBe('en');
2200
- });
2201
-
2202
- it('selectTextLanguage() respects selected role', () => {
2203
- expect(getActiveTextTrack().roles).not.toContain('commentary');
2204
-
2205
- player.selectTextLanguage('en', 'commentary');
2206
-
2207
- expect(streamingEngine.switchTextStream).toHaveBeenCalled();
2208
- const args = streamingEngine.switchTextStream.calls.argsFor(0);
2209
- expect(args[0].roles).toContain('commentary');
2210
- expect(getActiveTextTrack().roles).toContain('commentary');
2211
- });
2212
-
2213
- it('changing current audio language changes active stream', () => {
2214
- expect(getActiveVariantTrack().language).not.toBe('es');
2215
- expect(streamingEngine.switchVariant).not.toHaveBeenCalled();
2216
- player.selectAudioLanguage('es');
2217
-
2218
- expect(streamingEngine.switchVariant).toHaveBeenCalled();
2219
- const args = streamingEngine.switchVariant.calls.argsFor(0);
2220
- expect(args[0].language).toBe('es');
2221
- expect(args[1]).toBe(true);
2222
- expect(getActiveVariantTrack().language).toBe('es');
2223
- });
2224
-
2225
- it('changing current text language changes active stream', () => {
2226
- expect(getActiveTextTrack().language).not.toBe('en');
2227
- expect(streamingEngine.switchTextStream).not.toHaveBeenCalled();
2228
- player.selectTextLanguage('en');
2229
-
2230
- expect(streamingEngine.switchTextStream).toHaveBeenCalled();
2231
- const args = streamingEngine.switchTextStream.calls.argsFor(0);
2232
- expect(args[0].language).toBe('en');
2233
- expect(getActiveTextTrack().language).toBe('en');
2234
- });
2235
-
2236
- // https://github.com/shaka-project/shaka-player/issues/2010
2237
- it('changing text lang changes active stream when not streaming', () => {
2238
- player.setTextTrackVisibility(false);
2239
-
2240
- expect(getActiveTextTrack()).toBe(null);
2241
- expect(streamingEngine.switchTextStream).not.toHaveBeenCalled();
2242
- player.selectTextLanguage('en');
2243
- player.setTextTrackVisibility(true);
2244
-
2245
- expect(streamingEngine.switchTextStream).toHaveBeenCalled();
2246
- expect(getActiveTextTrack().language).toBe('en');
2247
- });
2248
-
2249
- it('remembers the channel count when ABR is reenabled', () => {
2250
- // We prefer 6 channels, and we are currently playing 6 channels.
2251
- expect(player.getConfiguration().preferredAudioChannelCount).toBe(6);
2252
- expect(getActiveVariantTrack().channelsCount).toBe(6);
2253
-
2254
- // Manually turn off ABR and select a 2-channel track.
2255
- player.configure({abr: {enabled: false}});
2256
- const newTrack =
2257
- player.getVariantTracks().filter((t) => t.channelsCount == 2)[0];
2258
- player.selectVariantTrack(newTrack);
2259
-
2260
- // See that we are playing a 2-channel track now.
2261
- expect(getActiveVariantTrack().channelsCount).toBe(2);
2262
-
2263
- // See that AbrManager has a list of 2-channel tracks now.
2264
- expect(abrManager.variants.length).toBeGreaterThan(0);
2265
- for (const v of abrManager.variants) {
2266
- expect(v.audio.channelsCount).toBe(2);
2267
- }
2268
-
2269
- // Re-enable ABR.
2270
- player.configure({abr: {enabled: true}});
2271
-
2272
- // See that AbrManager still has a list of 2-channel tracks.
2273
- expect(abrManager.variants.length).toBeGreaterThan(0);
2274
- for (const v of abrManager.variants) {
2275
- expect(v.audio.channelsCount).toBe(2);
2276
- }
2277
- // See that we are still playing a 2-channel track.
2278
- expect(getActiveVariantTrack().channelsCount).toBe(2);
2279
- });
2280
-
2281
- it('remembers the channel count across key status changes', () => {
2282
- // Simulate an encrypted stream. Mark half of the audio streams with key
2283
- // ID 'aaa', and the other half with 'bbb'. Remove all roles, so that our
2284
- // choices are limited only by channel count and key status.
2285
- for (const variant of manifest.variants) {
2286
- const keyId = (variant.audio.id % 2) ? 'aaa' : 'bbb';
2287
- variant.audio.keyIds = new Set([keyId]);
2288
- variant.video.roles = [];
2289
- variant.audio.roles = [];
2290
- }
2291
-
2292
- // We prefer 6 channels, and we are currently playing 6 channels.
2293
- expect(player.getConfiguration().preferredAudioChannelCount).toBe(6);
2294
- expect(getActiveVariantTrack().channelsCount).toBe(6);
2295
-
2296
- // Manually select a 2-channel track.
2297
- const newTrack =
2298
- player.getVariantTracks().filter((t) => t.channelsCount == 2)[0];
2299
- player.selectVariantTrack(newTrack);
2300
-
2301
- // See that we are playing a 2-channel track now.
2302
- expect(getActiveVariantTrack().channelsCount).toBe(2);
2303
-
2304
- // See that AbrManager has a list of 2-channel tracks now.
2305
- expect(abrManager.variants.length).toBeGreaterThan(0);
2306
- for (const v of abrManager.variants) {
2307
- expect(v.audio.channelsCount).toBe(2);
2308
- }
2309
-
2310
- // Simulate a key status event that would trigger the removal of some
2311
- // tracks.
2312
- onKeyStatus({
2313
- 'aaa': 'usable',
2314
- 'bbb': 'output-restricted',
2315
- });
2316
-
2317
- // See that AbrManager still has a list of 2-channel tracks.
2318
- expect(abrManager.variants.length).toBeGreaterThan(0);
2319
- for (const v of abrManager.variants) {
2320
- expect(v.audio.channelsCount).toBe(2);
2321
- }
2322
- // See that we are still playing a 2-channel track.
2323
- expect(getActiveVariantTrack().channelsCount).toBe(2);
2324
- });
2325
-
2326
- describe('only fires change event when something changes', () => {
2327
- /** @type {jasmine.Spy} */
2328
- let textChanged;
2329
-
2330
- /** @type {jasmine.Spy} */
2331
- let variantChanged;
2332
-
2333
- beforeEach(() => {
2334
- textChanged = jasmine.createSpy('textChanged');
2335
- player.addEventListener('textchanged', Util.spyFunc(textChanged));
2336
-
2337
- variantChanged = jasmine.createSpy('variantChanged');
2338
- player.addEventListener('variantchanged', Util.spyFunc(variantChanged));
2339
- });
2340
-
2341
- it('in selectTextTrack', async () => {
2342
- // Any text track we're not already streaming.
2343
- const newTrack = player.getTextTracks().filter((t) => !t.active)[0];
2344
-
2345
- // Call selectTextTrack with a new track. Expect an event to fire.
2346
- player.selectTextTrack(newTrack);
2347
- await shaka.test.Util.shortDelay();
2348
- expect(textChanged).toHaveBeenCalled();
2349
- textChanged.calls.reset();
2350
-
2351
- // Call again with the same track, and expect no event to fire, since
2352
- // nothing changed this time.
2353
- player.selectTextTrack(newTrack);
2354
- await shaka.test.Util.shortDelay();
2355
- expect(textChanged).not.toHaveBeenCalled();
2356
- });
2357
-
2358
- it('in selectVariantTrack', async () => {
2359
- // Any variant track we're not already streaming.
2360
- const newTrack = player.getVariantTracks().filter((t) => !t.active)[0];
2361
-
2362
- // Call selectVariantTrack with a new track. Expect an event to fire.
2363
- player.selectVariantTrack(newTrack);
2364
- await shaka.test.Util.shortDelay();
2365
- expect(variantChanged).toHaveBeenCalled();
2366
- variantChanged.calls.reset();
2367
-
2368
- // Call again with the same track, and expect no event to fire, since
2369
- // nothing changed this time.
2370
- player.selectVariantTrack(newTrack);
2371
- await shaka.test.Util.shortDelay();
2372
- expect(variantChanged).not.toHaveBeenCalled();
2373
- });
2374
-
2375
- it('in selectTextLanguage', async () => {
2376
- // The current text language.
2377
- const currentLanguage = player.getTextTracks()
2378
- .filter((t) => t.active)[0].language;
2379
- const newLanguage = player.getTextTracks()
2380
- .filter((t) => t.language != currentLanguage)[0].language;
2381
-
2382
- // Call selectTextLanguage with a new language. Expect an event to
2383
- // fire.
2384
- player.selectTextLanguage(newLanguage);
2385
- await shaka.test.Util.shortDelay();
2386
- expect(textChanged).toHaveBeenCalled();
2387
- textChanged.calls.reset();
2388
-
2389
- // Call again with the same language, and expect no event to fire,
2390
- // since nothing changed this time.
2391
- player.selectTextLanguage(newLanguage);
2392
- await shaka.test.Util.shortDelay();
2393
- expect(textChanged).not.toHaveBeenCalled();
2394
- });
2395
-
2396
- it('in selectAudioLanguage', async () => {
2397
- // The current audio language.
2398
- const currentLanguage = player.getVariantTracks()
2399
- .filter((t) => t.active)[0].language;
2400
- const newLanguage = player.getVariantTracks()
2401
- .filter((t) => t.language != currentLanguage)[0].language;
2402
-
2403
- // Call selectAudioLanguage with a new language. Expect an event to
2404
- // fire.
2405
- player.selectAudioLanguage(newLanguage);
2406
- await shaka.test.Util.shortDelay();
2407
- expect(variantChanged).toHaveBeenCalled();
2408
- variantChanged.calls.reset();
2409
-
2410
- // Call again with the same language, and expect no event to fire,
2411
- // since nothing changed this time.
2412
- player.selectAudioLanguage(newLanguage);
2413
- await shaka.test.Util.shortDelay();
2414
- expect(variantChanged).not.toHaveBeenCalled();
2415
- });
2416
- });
2417
-
2418
- it('chooses the configured text language and role at start', async () => {
2419
- player.configure({
2420
- preferredTextLanguage: 'en',
2421
- preferredTextRole: 'commentary',
2422
- });
2423
-
2424
- await player.load(fakeManifestUri, 0, fakeMimeType);
2425
-
2426
- // Text was turned on during startup.
2427
- expect(player.isTextTrackVisible()).toBe(true);
2428
-
2429
- expect(getActiveTextTrack()).toEqual(jasmine.objectContaining({
2430
- id: 52,
2431
- language: 'en',
2432
- roles: ['commentary'],
2433
- }));
2434
- });
2435
-
2436
- it('chooses a variant with preferred audio label', async () => {
2437
- expect(getActiveVariantTrack().label).toBe(null);
2438
-
2439
- player.configure({
2440
- preferredAudioLanguage: '',
2441
- preferredAudioLabel: 'es-label',
2442
- });
2443
-
2444
- await player.load(fakeManifestUri, 0, fakeMimeType);
2445
- expect(getActiveVariantTrack().label).toBe('es-label');
2446
- });
2447
- }); // describe('tracks')
2448
-
2449
- describe('languages', () => {
2450
- it('chooses the first as default', async () => {
2451
- await runTest(['en', 'es'], 'pt', 0);
2452
- });
2453
-
2454
- it('chooses the primary track', async () => {
2455
- await runTest(['en', 'es', '*fr'], 'pt', 2);
2456
- });
2457
-
2458
- it('chooses exact match for main language', async () => {
2459
- await runTest(['en', 'pt', 'pt-BR'], 'pt', 1);
2460
- });
2461
-
2462
- it('chooses exact match for subtags', async () => {
2463
- await runTest(['en', 'pt', 'pt-BR'], 'PT-BR', 2);
2464
- });
2465
-
2466
- it('chooses base language if exact does not exist', async () => {
2467
- await runTest(['en', 'es', 'pt'], 'pt-BR', 2);
2468
- });
2469
-
2470
- it('chooses other subtags if base language does not exist', async () => {
2471
- await runTest(['en', 'es', 'pt-BR'], 'pt-PT', 2);
2472
- });
2473
-
2474
- it('enables text if its language differs from audio at start', async () => {
2475
- // A manifest we can use to test text visibility.
2476
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
2477
- manifest.addVariant(0, (variant) => {
2478
- variant.language = 'pt';
2479
- variant.addAudio(0);
2480
- });
2481
- manifest.addVariant(1, (variant) => {
2482
- variant.language = 'en';
2483
- variant.addAudio(1);
2484
- });
2485
- manifest.addTextStream(2, (stream) => {
2486
- stream.language = 'pt';
2487
- });
2488
- manifest.addTextStream(3, (stream) => {
2489
- stream.language = 'fr';
2490
- });
2491
- });
2492
-
2493
- player.configure({
2494
- preferredAudioLanguage: 'en',
2495
- preferredTextLanguage: 'fr',
2496
- });
2497
-
2498
- expect(player.isTextTrackVisible()).toBe(false);
2499
-
2500
- await player.load(fakeManifestUri, 0, fakeMimeType);
2501
-
2502
- // Text was turned on during startup.
2503
- expect(player.isTextTrackVisible()).toBe(true);
2504
-
2505
- // Turn text back off.
2506
- await player.setTextTrackVisibility(false);
2507
- expect(player.isTextTrackVisible()).toBe(false);
2508
-
2509
- // Change text languages after startup.
2510
- player.selectTextLanguage('pt');
2511
-
2512
- // This should not turn text back on.
2513
- expect(player.isTextTrackVisible()).toBe(false);
2514
- });
2515
-
2516
- it('chooses an arbitrary language when none given', async () => {
2517
- // The Player shouldn't allow changing between languages, so it should
2518
- // choose an arbitrary language when none is given.
2519
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
2520
- manifest.addVariant(0, (variant) => {
2521
- variant.language = 'pt';
2522
- variant.addAudio(0);
2523
- });
2524
- manifest.addVariant(1, (variant) => {
2525
- variant.language = 'en';
2526
- variant.addAudio(1);
2527
- });
2528
- });
2529
-
2530
- player.configure({
2531
- preferredAudioLanguage: undefined,
2532
- });
2533
-
2534
- await player.load(fakeManifestUri, 0, fakeMimeType);
2535
-
2536
- expect(abrManager.setVariants).toHaveBeenCalled();
2537
-
2538
- // If we have chosen any arbitrary language, setVariants is provided
2539
- // with exactly one variant.
2540
- const variants = abrManager.setVariants.calls.argsFor(0)[0];
2541
- expect(variants.length).toBe(1);
2542
- });
2543
-
2544
- /**
2545
- * @param {!Array.<string>} languages
2546
- * @param {string} preference
2547
- * @param {number} expectedIndex
2548
- * @return {!Promise}
2549
- */
2550
- async function runTest(languages, preference, expectedIndex) {
2551
- // A manifest we can use to test language selection.
2552
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
2553
- for (let i = 0; i < languages.length; i++) {
2554
- const lang = languages[i];
2555
- if (lang.charAt(0) == '*') {
2556
- manifest.addVariant(i, (variant) => {
2557
- variant.primary = true;
2558
- variant.language = lang.substr(1);
2559
- variant.addAudio(i);
2560
- });
2561
- } else {
2562
- manifest.addVariant(i, (variant) => {
2563
- variant.language = lang;
2564
- variant.addAudio(i);
2565
- });
2566
- }
2567
- }
2568
- });
2569
-
2570
- // Set the user preferences, which must happen before load().
2571
- player.configure({
2572
- preferredAudioLanguage: preference,
2573
- });
2574
-
2575
- await player.load(fakeManifestUri, 0, fakeMimeType);
2576
- expect(getActiveVariantTrack().id).toBe(expectedIndex);
2577
- }
2578
- }); // describe('languages')
2579
-
2580
- describe('getStats', () => {
2581
- const oldDateNow = Date.now;
2582
-
2583
- beforeEach(async () => {
2584
- Date.now = () => 0;
2585
-
2586
- // The media element may be paused in a test, make sure that it is reset
2587
- // to avoid cross-test contamination.
2588
- video.paused = false;
2589
-
2590
- // A manifest we can use to test stats.
2591
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
2592
- manifest.addVariant(0, (variant) => {
2593
- variant.bandwidth = 200;
2594
- variant.addAudio(1, (stream) => {
2595
- stream.bandwidth = 100;
2596
- });
2597
- variant.addVideo(2, (stream) => {
2598
- stream.bandwidth = 100;
2599
- stream.size(100, 200);
2600
- });
2601
- });
2602
- manifest.addVariant(1, (variant) => {
2603
- variant.bandwidth = 300;
2604
- variant.addExistingStream(1); // audio
2605
- variant.addVideo(3, (stream) => {
2606
- stream.bandwidth = 200;
2607
- stream.size(200, 400);
2608
- });
2609
- });
2610
- manifest.addVariant(2, (variant) => {
2611
- variant.bandwidth = 300;
2612
- variant.addAudio(1, (stream) => {
2613
- stream.bandwidth = 200;
2614
- });
2615
- variant.addExistingStream(2); // video
2616
- });
2617
- manifest.addVariant(3, (variant) => {
2618
- variant.bandwidth = 400;
2619
- variant.addExistingStream(1); // audio
2620
- variant.addExistingStream(2); // video
2621
- });
2622
- });
2623
-
2624
- await player.load(fakeManifestUri, 0, fakeMimeType);
2625
- });
2626
-
2627
- afterEach(() => {
2628
- Date.now = oldDateNow;
2629
- });
2630
-
2631
- it('tracks estimated bandwidth', () => {
2632
- abrManager.getBandwidthEstimate.and.returnValue(25);
2633
- const stats = player.getStats();
2634
- expect(stats.estimatedBandwidth).toBe(25);
2635
- });
2636
-
2637
- it('tracks info about current stream', () => {
2638
- const stats = player.getStats();
2639
- // Should have chosen the first of each type of stream.
2640
- expect(stats.width).toBe(100);
2641
- expect(stats.height).toBe(200);
2642
- expect(stats.streamBandwidth).toBe(200);
2643
- });
2644
-
2645
- it('tracks frame info', () => {
2646
- // getVideoPlaybackQuality does not exist yet.
2647
- let stats = player.getStats();
2648
- expect(stats.decodedFrames).toBeNaN();
2649
- expect(stats.droppedFrames).toBeNaN();
2650
- expect(stats.corruptedFrames).toBeNaN();
2651
-
2652
- video.getVideoPlaybackQuality = () => {
2653
- return {
2654
- corruptedVideoFrames: 10,
2655
- creationTime: 0,
2656
- totalFrameDelay: 0,
2657
- totalVideoFrames: 75,
2658
- droppedVideoFrames: 125,
2659
- };
2660
- };
2661
-
2662
- // Now that it exists, theses stats should exist.
2663
- stats = player.getStats();
2664
- expect(stats.decodedFrames).toBe(75);
2665
- expect(stats.droppedFrames).toBe(125);
2666
- expect(stats.corruptedFrames).toBe(10);
2667
- });
2668
-
2669
- describe('buffer/play times', () => {
2670
- it('tracks play time', () => {
2671
- let stats = player.getStats();
2672
- expect(stats.playTime).toBeCloseTo(0);
2673
- expect(stats.bufferingTime).toBeCloseTo(0);
2674
-
2675
- // Stop buffering and start "playing".
2676
- forceBufferingTo(false);
2677
- Date.now = () => 5000;
2678
-
2679
- stats = player.getStats();
2680
- expect(stats.playTime).toBeCloseTo(5);
2681
- expect(stats.bufferingTime).toBeCloseTo(0);
2682
- });
2683
-
2684
- it('tracks buffering time', () => {
2685
- let stats = player.getStats();
2686
- expect(stats.playTime).toBeCloseTo(0);
2687
- expect(stats.bufferingTime).toBeCloseTo(0);
2688
-
2689
- forceBufferingTo(true);
2690
- Date.now = () => 5000;
2691
-
2692
- stats = player.getStats();
2693
- expect(stats.playTime).toBeCloseTo(0);
2694
- expect(stats.bufferingTime).toBeCloseTo(5);
2695
- });
2696
-
2697
- it('tracks correct time when switching states', () => {
2698
- forceBufferingTo(false);
2699
- Date.now = () => 3000;
2700
- forceBufferingTo(true);
2701
- Date.now = () => 8000;
2702
- forceBufferingTo(true);
2703
- Date.now = () => 17000;
2704
- forceBufferingTo(false);
2705
- Date.now = () => 18000;
2706
-
2707
- const stats = player.getStats();
2708
- expect(stats.playTime).toBeCloseTo(4);
2709
- expect(stats.bufferingTime).toBeCloseTo(14);
2710
- });
2711
- });
2712
-
2713
- describe('.switchHistory', () => {
2714
- it('includes original choices', () => {
2715
- // checkHistory prepends the initial stream selections.
2716
- checkHistory([]);
2717
- });
2718
-
2719
- it('includes selectVariantTrack choices', () => {
2720
- const track = player.getVariantTracks()[3];
2721
-
2722
- const variants = manifest.variants;
2723
- const variant = variants.find((variant) => variant.id == track.id);
2724
-
2725
- player.selectVariantTrack(track);
2726
-
2727
- checkHistory([{
2728
- // We are using a mock date, so this is not a race.
2729
- timestamp: Date.now() / 1000,
2730
- id: variant.id,
2731
- type: 'variant',
2732
- fromAdaptation: false,
2733
- bandwidth: variant.bandwidth,
2734
- }]);
2735
- });
2736
-
2737
- it('includes adaptation choices', () => {
2738
- const variant = manifest.variants[3];
2739
-
2740
- switch_(variant);
2741
- checkHistory(jasmine.arrayContaining([
2742
- {
2743
- timestamp: Date.now() / 1000,
2744
- id: variant.id,
2745
- type: 'variant',
2746
- fromAdaptation: true,
2747
- bandwidth: variant.bandwidth,
2748
- },
2749
- ]));
2750
- });
2751
-
2752
- /**
2753
- * Checks that the switch history is correct.
2754
- * @param {!Array.<shaka.extern.TrackChoice>} additional
2755
- */
2756
- function checkHistory(additional) {
2757
- const prefix = {
2758
- timestamp: jasmine.any(Number),
2759
- id: 0,
2760
- type: 'variant',
2761
- fromAdaptation: true,
2762
- bandwidth: 200,
2763
- };
2764
-
2765
- const switchHistory = player.getStats().switchHistory;
2766
-
2767
- expect(switchHistory[0]).toEqual(prefix);
2768
- expect(switchHistory.slice(1)).toEqual(additional);
2769
- }
2770
-
2771
- /**
2772
- * @param {shaka.extern.Variant} variant
2773
- * @suppress {accessControls}
2774
- */
2775
- function switch_(variant) {
2776
- player.switch_(variant);
2777
- }
2778
- });
2779
-
2780
- describe('.stateHistory', () => {
2781
- function history() {
2782
- return player.getStats().stateHistory;
2783
- }
2784
-
2785
- // We expect that the player will start us in the buffering state after
2786
- // loading. We should see that the only entry is a buffering entry.
2787
- it('begins with buffering state', () => {
2788
- expect(history()).toEqual([
2789
- {
2790
- timestamp: jasmine.any(Number),
2791
- duration: 0,
2792
- state: 'buffering',
2793
- },
2794
- ]);
2795
- });
2796
-
2797
- // We expect that the player will start us in the buffering state, but
2798
- // when the media element is paused, we should see that we change to the
2799
- // paused state.
2800
- it('transitions to paused if the video is paused', () => {
2801
- // Start playback, we must be playing in order to be paused. The
2802
- // buffering state takes precedent over other states, so if we are
2803
- // buffering and then paused, it will only report buffering.
2804
- forceBufferingTo(false);
2805
-
2806
- // Trigger a pause event.
2807
- video.paused = true;
2808
- video.on['pause']();
2809
-
2810
- expect(history()).toEqual([
2811
- {
2812
- timestamp: jasmine.any(Number),
2813
- duration: jasmine.any(Number),
2814
- state: 'buffering',
2815
- },
2816
- {
2817
- timestamp: jasmine.any(Number),
2818
- duration: jasmine.any(Number),
2819
- state: 'playing',
2820
- },
2821
- {
2822
- timestamp: jasmine.any(Number),
2823
- duration: jasmine.any(Number),
2824
- state: 'paused',
2825
- },
2826
- ]);
2827
- });
2828
-
2829
- // We expect that the player will start us in the buffering state, but
2830
- // once we leave that state, we should be playing.
2831
- it('transitions to playing if the video is playing', () => {
2832
- // Leave buffering (and enter playing).
2833
- forceBufferingTo(false);
2834
-
2835
- expect(history()).toEqual([
2836
- {
2837
- timestamp: jasmine.any(Number),
2838
- duration: jasmine.any(Number),
2839
- state: 'buffering',
2840
- },
2841
- {
2842
- timestamp: jasmine.any(Number),
2843
- duration: jasmine.any(Number),
2844
- state: 'playing',
2845
- },
2846
- ]);
2847
- });
2848
-
2849
- // We expect that the player will start us in the buffering state. We
2850
- // expect that once we reach the end, we will enter the ended state. Since
2851
- // we must be first playing before reaching the end, this test will
2852
- // reflect that.
2853
- it('transitions to ended when the video ends', () => {
2854
- // Stop buffering (and start playing);
2855
- forceBufferingTo(false);
2856
-
2857
- // Signal the playhead reaching the end of the content.
2858
- video.ended = true;
2859
- video.on['ended']();
2860
-
2861
- expect(history()).toEqual([
2862
- {
2863
- timestamp: jasmine.any(Number),
2864
- duration: jasmine.any(Number),
2865
- state: 'buffering',
2866
- },
2867
- {
2868
- timestamp: jasmine.any(Number),
2869
- duration: jasmine.any(Number),
2870
- state: 'playing',
2871
- },
2872
- {
2873
- timestamp: jasmine.any(Number),
2874
- duration: jasmine.any(Number),
2875
- state: 'ended',
2876
- },
2877
- ]);
2878
- });
2879
- });
2880
-
2881
- /**
2882
- * @param {boolean} buffering
2883
- * @suppress {accessControls}
2884
- */
2885
- function forceBufferingTo(buffering) {
2886
- const State = shaka.media.BufferingObserver.State;
2887
-
2888
- // Replace the |getState| method on the buffer controllers so that any
2889
- // others calls relying on the state will get the state that we want them
2890
- // to have.
2891
- player.bufferObserver_.getState = () => {
2892
- return buffering ? State.STARVING : State.SATISFIED;
2893
- };
2894
-
2895
- // Force the update.
2896
- player.updateBufferState_();
2897
- }
2898
- });
2899
-
2900
- describe('unplayable content', () => {
2901
- it('throws CONTENT_UNSUPPORTED_BY_BROWSER', async () => {
2902
- window.MediaSource.isTypeSupported = (mimeType) => false;
2903
-
2904
- navigator.mediaCapabilities.decodingInfo = async (config) => {
2905
- await Promise.resolve();
2906
- return {supported: false};
2907
- };
2908
-
2909
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
2910
- manifest.addVariant(0, (variant) => {
2911
- variant.addVideo(0);
2912
- });
2913
- });
2914
-
2915
- const expected = Util.jasmineError(new shaka.util.Error(
2916
- shaka.util.Error.Severity.CRITICAL,
2917
- shaka.util.Error.Category.MANIFEST,
2918
- shaka.util.Error.Code.CONTENT_UNSUPPORTED_BY_BROWSER));
2919
- const load = player.load(fakeManifestUri, 0, fakeMimeType);
2920
- await expectAsync(load).toBeRejectedWith(expected);
2921
- });
2922
- });
2923
-
2924
- describe('restrictions', () => {
2925
- it('switches if active is restricted by application', async () => {
2926
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
2927
- manifest.addVariant(0, (variant) => {
2928
- variant.bandwidth = 500;
2929
- variant.addVideo(1, (stream) => {
2930
- stream.size(10, 10);
2931
- });
2932
- });
2933
- manifest.addVariant(1, (variant) => {
2934
- variant.bandwidth = 100;
2935
- variant.addVideo(2, (stream) => {
2936
- stream.size(30, 30);
2937
- });
2938
- });
2939
- });
2940
-
2941
- await player.load(fakeManifestUri, 0, fakeMimeType);
2942
- let activeVariant = getActiveVariantTrack();
2943
- expect(activeVariant.id).toBe(0);
2944
-
2945
- // Ask AbrManager to choose the 0th variant from those it is given.
2946
- abrManager.chooseIndex = 0;
2947
- abrManager.chooseVariant.calls.reset();
2948
-
2949
- // This restriction should make it so that the first variant (bandwidth
2950
- // 500, id 0) cannot be selected.
2951
- player.configure({
2952
- restrictions: {maxBandwidth: 200},
2953
- });
2954
-
2955
- // The restriction change should trigger a call to AbrManager.
2956
- expect(abrManager.chooseVariant).toHaveBeenCalled();
2957
-
2958
- // The first variant is disallowed.
2959
- expect(manifest.variants[0].id).toBe(0);
2960
- expect(manifest.variants[0].allowedByApplication)
2961
- .toBe(false);
2962
-
2963
- // AbrManager chose the second variant (id 1).
2964
- activeVariant = getActiveVariantTrack();
2965
- expect(activeVariant.id).toBe(1);
2966
- });
2967
-
2968
- it('updates AbrManager for restriction changes', async () => {
2969
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
2970
- manifest.addVariant(1, (variant) => {
2971
- variant.bandwidth = 500;
2972
- variant.addVideo(10, (stream) => {
2973
- stream.size(10, 10);
2974
- });
2975
- });
2976
- manifest.addVariant(2, (variant) => {
2977
- variant.bandwidth = 100;
2978
- variant.addVideo(20, (stream) => {
2979
- stream.size(30, 30);
2980
- });
2981
- });
2982
- });
2983
-
2984
- await player.load(fakeManifestUri, 0, fakeMimeType);
2985
- abrManager.setVariants.calls.reset();
2986
-
2987
- player.configure({restrictions: {maxBandwidth: 200}});
2988
-
2989
- // AbrManager should have been updated with the restricted tracks.
2990
- // The first variant is disallowed.
2991
- expect(abrManager.setVariants).toHaveBeenCalled();
2992
- const variants = abrManager.setVariants.calls.argsFor(0)[0];
2993
- expect(variants.length).toBe(1);
2994
- expect(variants[0].id).toBe(2);
2995
-
2996
- // Now increase the restriction, AbrManager should still be updated.
2997
- // https://github.com/shaka-project/shaka-player/issues/1533
2998
- abrManager.setVariants.calls.reset();
2999
- player.configure({restrictions: {maxBandwidth: Infinity}});
3000
- expect(abrManager.setVariants).toHaveBeenCalledTimes(1);
3001
- const newVariants = abrManager.setVariants.calls.argsFor(0)[0];
3002
- expect(newVariants.length).toBe(2);
3003
- });
3004
-
3005
- it('switches if active key status is "output-restricted"', async () => {
3006
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3007
- manifest.addVariant(0, (variant) => {
3008
- variant.addVideo(1, (stream) => {
3009
- stream.keyIds = new Set(['abc']);
3010
- stream.size(10, 10);
3011
- });
3012
- });
3013
- manifest.addVariant(1, (variant) => {
3014
- variant.addVideo(2, (stream) => {
3015
- stream.size(20, 20);
3016
- });
3017
- });
3018
- });
3019
-
3020
- await player.load(fakeManifestUri, 0, fakeMimeType);
3021
- let activeVariant = getActiveVariantTrack();
3022
- expect(activeVariant.id).toBe(0);
3023
-
3024
- abrManager.chooseIndex = 0;
3025
- abrManager.chooseVariant.calls.reset();
3026
-
3027
- // This restricts the first variant, which triggers chooseVariant.
3028
- onKeyStatus({'abc': 'output-restricted'});
3029
- expect(abrManager.chooseVariant).toHaveBeenCalled();
3030
-
3031
- // The first variant is disallowed.
3032
- expect(manifest.variants[0].id).toBe(0);
3033
- expect(manifest.variants[0].allowedByKeySystem).toBe(false);
3034
-
3035
- // The second variant was chosen.
3036
- activeVariant = getActiveVariantTrack();
3037
- expect(activeVariant.id).toBe(1);
3038
- });
3039
-
3040
- it('switches if active key status is "internal-error"', async () => {
3041
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3042
- manifest.addVariant(0, (variant) => {
3043
- variant.addVideo(1, (stream) => {
3044
- stream.keyIds = new Set(['abc']);
3045
- stream.size(10, 10);
3046
- });
3047
- });
3048
- manifest.addVariant(1, (variant) => {
3049
- variant.addVideo(2, (stream) => {
3050
- stream.size(20, 20);
3051
- });
3052
- });
3053
- });
3054
-
3055
- await player.load(fakeManifestUri, 0, fakeMimeType);
3056
- let activeVariant = getActiveVariantTrack();
3057
- expect(activeVariant.id).toBe(0);
3058
-
3059
- // AbrManager should choose the second track since the first is
3060
- // restricted.
3061
- abrManager.chooseIndex = 0;
3062
- abrManager.chooseVariant.calls.reset();
3063
- onKeyStatus({'abc': 'internal-error'});
3064
- expect(abrManager.chooseVariant).toHaveBeenCalled();
3065
- expect(manifest.variants[0].id).toBe(0);
3066
- expect(manifest.variants[0].allowedByKeySystem).toBe(false);
3067
-
3068
- activeVariant = getActiveVariantTrack();
3069
- expect(activeVariant.id).toBe(1);
3070
- });
3071
-
3072
- // Regression test for https://github.com/shaka-project/shaka-player/issues/4190
3073
- it('throws only one RESTRICTIONS_CANNOT_BE_MET error', async () => {
3074
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3075
- manifest.addVariant(0, (variant) => {
3076
- variant.addVideo(1, (stream) => {
3077
- stream.keyIds = new Set(['abc']);
3078
- });
3079
- });
3080
- });
3081
-
3082
- // Check that error is RESTRICTIONS_CANNOT_BE_MET
3083
- onError.and.callFake((e) => {
3084
- const error = e.detail;
3085
- shaka.test.Util.expectToEqualError(
3086
- error,
3087
- new shaka.util.Error(
3088
- shaka.util.Error.Severity.CRITICAL,
3089
- shaka.util.Error.Category.MANIFEST,
3090
- shaka.util.Error.Code.RESTRICTIONS_CANNOT_BE_MET, {
3091
- hasAppRestrictions: false,
3092
- missingKeys: ['abc'],
3093
- restrictedKeyStatuses: [],
3094
- }));
3095
- });
3096
-
3097
- await player.load(fakeManifestUri, 0, fakeMimeType);
3098
- const activeVariant = getActiveVariantTrack();
3099
- expect(activeVariant.id).toBe(0);
3100
-
3101
- abrManager.chooseIndex = 0;
3102
- abrManager.chooseVariant.calls.reset();
3103
-
3104
- onKeyStatus({'abc': 'output-restricted'});
3105
-
3106
- // Ensure that RESTRICTIONS_CANNOT_BE_MET is thrown once
3107
- expect(onError).toHaveBeenCalledTimes(1);
3108
-
3109
- // It does not call chooseVariant
3110
- expect(abrManager.chooseVariant).not.toHaveBeenCalled();
3111
-
3112
- // The first variant is disallowed.
3113
- expect(manifest.variants[0].id).toBe(0);
3114
- expect(manifest.variants[0].allowedByKeySystem).toBe(false);
3115
- });
3116
-
3117
- it('doesn\'t switch if the active stream isn\'t restricted', async () => {
3118
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3119
- manifest.addVariant(0, (variant) => {
3120
- variant.addVideo(1, (stream) => {
3121
- stream.keyIds = new Set(['abc']);
3122
- });
3123
- });
3124
- manifest.addVariant(1, (variant) => {
3125
- variant.addVideo(2);
3126
- });
3127
- });
3128
-
3129
- await player.load(fakeManifestUri, 0, fakeMimeType);
3130
- abrManager.chooseVariant.calls.reset();
3131
-
3132
- let activeVariant = getActiveVariantTrack();
3133
- expect(activeVariant.id).toBe(0);
3134
-
3135
- onKeyStatus({'abc': 'usable'});
3136
- expect(abrManager.chooseVariant).not.toHaveBeenCalled();
3137
-
3138
- activeVariant = getActiveVariantTrack();
3139
- expect(activeVariant.id).toBe(0);
3140
- });
3141
-
3142
- it('removes if key status is "output-restricted"', async () => {
3143
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3144
- manifest.addVariant(0, (variant) => {
3145
- variant.addVideo(1, (stream) => {
3146
- stream.keyIds = new Set(['abc']);
3147
- stream.size(10, 10);
3148
- });
3149
- });
3150
- manifest.addVariant(1, (variant) => {
3151
- variant.addVideo(2, (stream) => {
3152
- stream.size(20, 20);
3153
- });
3154
- });
3155
- });
3156
-
3157
- await player.load(fakeManifestUri, 0, fakeMimeType);
3158
- expect(player.getVariantTracks().length).toBe(2);
3159
-
3160
- onKeyStatus({'abc': 'output-restricted'});
3161
-
3162
- const tracks = player.getVariantTracks();
3163
- expect(tracks.length).toBe(1);
3164
- expect(tracks[0].id).toBe(1);
3165
- });
3166
-
3167
- it('removes if key status is "internal-error"', async () => {
3168
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3169
- manifest.addVariant(0, (variant) => {
3170
- variant.addVideo(1, (stream) => {
3171
- stream.keyIds = new Set(['abc']);
3172
- stream.size(10, 10);
3173
- });
3174
- });
3175
- manifest.addVariant(1, (variant) => {
3176
- variant.addVideo(2, (stream) => {
3177
- stream.size(20, 20);
3178
- });
3179
- });
3180
- });
3181
-
3182
- await player.load(fakeManifestUri, 0, fakeMimeType);
3183
- expect(player.getVariantTracks().length).toBe(2);
3184
-
3185
- onKeyStatus({'abc': 'internal-error'});
3186
-
3187
- const tracks = player.getVariantTracks();
3188
- expect(tracks.length).toBe(1);
3189
- expect(tracks[0].id).toBe(1);
3190
- });
3191
-
3192
- it('removes if we don\'t have the required key', async () => {
3193
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3194
- manifest.addVariant(0, (variant) => {
3195
- variant.addVideo(1, (stream) => {
3196
- stream.keyIds = new Set(['abc']);
3197
- stream.size(10, 10);
3198
- });
3199
- });
3200
- manifest.addVariant(2, (variant) => {
3201
- variant.addVideo(3, (stream) => {
3202
- stream.size(20, 20);
3203
- });
3204
- });
3205
- });
3206
-
3207
- await player.load(fakeManifestUri, 0, fakeMimeType);
3208
- expect(player.getVariantTracks().length).toBe(2);
3209
-
3210
- // We have some key statuses, but not for the key IDs we know.
3211
- onKeyStatus({'foo': 'usable'});
3212
-
3213
- const tracks = player.getVariantTracks();
3214
- expect(tracks.length).toBe(1);
3215
- expect(tracks[0].id).toBe(2);
3216
- });
3217
-
3218
- it('updates key statuses for multi-key content', async () => {
3219
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3220
- manifest.addVariant(0, (variant) => {
3221
- variant.addVideo(1, (stream) => {
3222
- stream.keyIds = new Set(['abc']);
3223
- stream.size(10, 10);
3224
- });
3225
- });
3226
- manifest.addVariant(2, (variant) => {
3227
- variant.addVideo(3, (stream) => {
3228
- stream.keyIds = new Set(['def']);
3229
- stream.size(20, 20);
3230
- });
3231
- });
3232
- manifest.addVariant(4, (variant) => {
3233
- variant.addVideo(5, (stream) => {
3234
- stream.keyIds = new Set(['abc', 'def']);
3235
- stream.size(30, 30);
3236
- });
3237
- });
3238
- });
3239
-
3240
- await player.load(fakeManifestUri, 0, fakeMimeType);
3241
- onKeyStatus({'abc': 'usable'});
3242
-
3243
- expect(manifest.variants[0].allowedByKeySystem).toBe(true);
3244
- expect(manifest.variants[1].allowedByKeySystem).toBe(false);
3245
- expect(manifest.variants[2].allowedByKeySystem).toBe(false);
3246
- });
3247
-
3248
- it('does not restrict if no key statuses are available', async () => {
3249
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3250
- manifest.addVariant(0, (variant) => {
3251
- variant.addVideo(1, (stream) => {
3252
- stream.keyIds = new Set(['abc']);
3253
- stream.size(10, 10);
3254
- });
3255
- });
3256
- manifest.addVariant(2, (variant) => {
3257
- variant.addVideo(3, (stream) => {
3258
- stream.size(20, 20);
3259
- });
3260
- });
3261
- });
3262
-
3263
- await player.load(fakeManifestUri, 0, fakeMimeType);
3264
- expect(player.getVariantTracks().length).toBe(2);
3265
-
3266
- // This simulates, for example, the lack of key status on Chromecast
3267
- // when using PlayReady. See #1070.
3268
- onKeyStatus({});
3269
-
3270
- const tracks = player.getVariantTracks();
3271
- expect(tracks.length).toBe(2);
3272
- });
3273
-
3274
- it('doesn\'t remove when using synthetic key status', async () => {
3275
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3276
- manifest.addVariant(0, (variant) => {
3277
- variant.addVideo(1, (stream) => {
3278
- stream.keyIds = new Set(['abc']);
3279
- stream.size(10, 10);
3280
- });
3281
- });
3282
- manifest.addVariant(2, (variant) => {
3283
- variant.addVideo(3, (stream) => {
3284
- stream.size(20, 20);
3285
- });
3286
- });
3287
- });
3288
-
3289
- await player.load(fakeManifestUri, 0, fakeMimeType);
3290
- expect(player.getVariantTracks().length).toBe(2);
3291
-
3292
- // A synthetic key status contains a single key status with key '00'.
3293
- onKeyStatus({'00': 'usable'});
3294
-
3295
- expect(player.getVariantTracks().length).toBe(2);
3296
- });
3297
-
3298
- it('removes all encrypted tracks for errors with synthetic key status',
3299
- async () => {
3300
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3301
- manifest.addVariant(0, (variant) => {
3302
- variant.addVideo(1, (stream) => {
3303
- stream.keyIds = new Set(['abc']);
3304
- stream.size(10, 10);
3305
- });
3306
- });
3307
- manifest.addVariant(2, (variant) => {
3308
- variant.addVideo(3, (stream) => {
3309
- stream.keyIds = new Set(['xyz']);
3310
- stream.size(20, 20);
3311
- });
3312
- });
3313
- manifest.addVariant(4, (variant) => {
3314
- variant.addVideo(5, (stream) => {
3315
- stream.size(30, 30);
3316
- });
3317
- });
3318
- });
3319
-
3320
- await player.load(fakeManifestUri, 0, fakeMimeType);
3321
- expect(player.getVariantTracks().length).toBe(3);
3322
-
3323
- // A synthetic key status contains a single key status with key '00'.
3324
- onKeyStatus({'00': 'internal-error'});
3325
-
3326
- const tracks = player.getVariantTracks();
3327
- expect(tracks.length).toBe(1);
3328
- expect(tracks[0].id).toBe(4);
3329
- });
3330
-
3331
- it('removes if key system does not support codec', async () => {
3332
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3333
- manifest.addVariant(0, (variant) => {
3334
- variant.addVideo(1, (stream) => {
3335
- stream.encrypted = true;
3336
- stream.mimeType = 'video';
3337
- stream.codecs = 'unsupported';
3338
- stream.addDrmInfo('foo.bar');
3339
- });
3340
- });
3341
- manifest.addVariant(1, (variant) => {
3342
- variant.addVideo(2, (stream) => {
3343
- stream.encrypted = true;
3344
- stream.addDrmInfo('foo.bar');
3345
- });
3346
- });
3347
- });
3348
-
3349
- navigator.mediaCapabilities.decodingInfo = async (config) => {
3350
- await Promise.resolve();
3351
- const videoType = config['video'] ? config['video'].contentType : '';
3352
- if (videoType.includes('video') &&
3353
- videoType.includes('unsupported')) {
3354
- return {supported: false};
3355
- } else {
3356
- return {supported: true};
3357
- }
3358
- };
3359
-
3360
- await player.load(fakeManifestUri, 0, fakeMimeType);
3361
- const tracks = player.getVariantTracks();
3362
- expect(tracks.length).toBe(1);
3363
- expect(tracks[0].id).toBe(1);
3364
- });
3365
-
3366
- it('removes based on bandwidth', async () => {
3367
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3368
- manifest.addVariant(0, (variant) => {
3369
- variant.bandwidth = 10;
3370
- variant.addVideo(1, (stream) => {
3371
- stream.size(10, 10);
3372
- });
3373
- });
3374
- manifest.addVariant(1, (variant) => {
3375
- variant.bandwidth = 1500;
3376
- variant.addVideo(2, (stream) => {
3377
- stream.size(20, 20);
3378
- });
3379
- });
3380
- manifest.addVariant(2, (variant) => {
3381
- variant.bandwidth = 500;
3382
- variant.addVideo(3, (stream) => {
3383
- stream.size(30, 30);
3384
- });
3385
- });
3386
- });
3387
-
3388
- await player.load(fakeManifestUri, 0, fakeMimeType);
3389
- expect(player.getVariantTracks().length).toBe(3);
3390
-
3391
- player.configure({restrictions: {minBandwidth: 100, maxBandwidth: 1000}});
3392
-
3393
- const tracks = player.getVariantTracks();
3394
- expect(tracks.length).toBe(1);
3395
- expect(tracks[0].id).toBe(2);
3396
- });
3397
-
3398
- it('removes based on pixels', async () => {
3399
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3400
- manifest.addVariant(0, (variant) => {
3401
- variant.addVideo(1, (stream) => {
3402
- stream.size(900, 900);
3403
- });
3404
- });
3405
- manifest.addVariant(1, (variant) => {
3406
- variant.addVideo(2, (stream) => {
3407
- stream.size(5, 5);
3408
- });
3409
- });
3410
- manifest.addVariant(2, (variant) => {
3411
- variant.addVideo(3, (stream) => {
3412
- stream.size(190, 190);
3413
- });
3414
- });
3415
- });
3416
-
3417
- await player.load(fakeManifestUri, 0, fakeMimeType);
3418
- expect(player.getVariantTracks().length).toBe(3);
3419
-
3420
- player.configure({restrictions: {minPixels: 100, maxPixels: 800 * 800}});
3421
-
3422
- const tracks = player.getVariantTracks();
3423
- expect(tracks.length).toBe(1);
3424
- expect(tracks[0].id).toBe(2);
3425
- });
3426
-
3427
- it('removes based on width', async () => {
3428
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3429
- manifest.addVariant(0, (variant) => {
3430
- variant.addVideo(1, (stream) => {
3431
- stream.size(5, 5);
3432
- });
3433
- });
3434
- manifest.addVariant(1, (variant) => {
3435
- variant.addVideo(2, (stream) => {
3436
- stream.size(1500, 200);
3437
- });
3438
- });
3439
- manifest.addVariant(2, (variant) => {
3440
- variant.addVideo(3, (stream) => {
3441
- stream.size(190, 190);
3442
- });
3443
- });
3444
- });
3445
-
3446
- await player.load(fakeManifestUri, 0, fakeMimeType);
3447
- expect(player.getVariantTracks().length).toBe(3);
3448
-
3449
- player.configure({restrictions: {minWidth: 100, maxWidth: 1000}});
3450
-
3451
- const tracks = player.getVariantTracks();
3452
- expect(tracks.length).toBe(1);
3453
- expect(tracks[0].id).toBe(2);
3454
- });
3455
-
3456
- it('removes based on height', async () => {
3457
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3458
- manifest.addVariant(0, (variant) => {
3459
- variant.addVideo(1, (stream) => {
3460
- stream.size(5, 5);
3461
- });
3462
- });
3463
-
3464
- manifest.addVariant(1, (variant) => {
3465
- variant.addVideo(2, (stream) => {
3466
- stream.size(200, 1024);
3467
- });
3468
- });
3469
-
3470
- manifest.addVariant(2, (variant) => {
3471
- variant.addVideo(3, (stream) => {
3472
- stream.size(190, 190);
3473
- });
3474
- });
3475
- });
3476
-
3477
- await player.load(fakeManifestUri, 0, fakeMimeType);
3478
- expect(player.getVariantTracks().length).toBe(3);
3479
-
3480
- player.configure({restrictions: {minHeight: 100, maxHeight: 1000}});
3481
-
3482
- const tracks = player.getVariantTracks();
3483
- expect(tracks.length).toBe(1);
3484
- expect(tracks[0].id).toBe(2);
3485
- });
3486
-
3487
- it('removes the whole variant if one stream is restricted', async () => {
3488
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3489
- manifest.addVariant(0, (variant) => {
3490
- variant.addVideo(1, (stream) => {
3491
- stream.size(5, 5);
3492
- });
3493
- variant.addAudio(2);
3494
- });
3495
-
3496
- manifest.addVariant(1, (variant) => {
3497
- variant.addVideo(3, (stream) => {
3498
- stream.size(190, 190);
3499
- });
3500
- variant.addAudio(2);
3501
- });
3502
- });
3503
-
3504
- await player.load(fakeManifestUri, 0, fakeMimeType);
3505
- expect(player.getVariantTracks().length).toBe(2);
3506
-
3507
- player.configure({restrictions: {minHeight: 100, maxHeight: 1000}});
3508
-
3509
- const tracks = player.getVariantTracks();
3510
- expect(tracks.length).toBe(1);
3511
- expect(tracks[0].id).toBe(1);
3512
- });
3513
-
3514
- it('issues error if no streams are playable', async () => {
3515
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3516
- manifest.addVariant(0, (variant) => {
3517
- variant.addVideo(1, (stream) => {
3518
- stream.size(5, 5);
3519
- });
3520
- });
3521
-
3522
- manifest.addVariant(1, (variant) => {
3523
- variant.addVideo(2, (stream) => {
3524
- stream.size(200, 300);
3525
- });
3526
- });
3527
-
3528
- manifest.addVariant(2, (variant) => {
3529
- variant.addVideo(3, (stream) => {
3530
- stream.size(190, 190);
3531
- });
3532
- });
3533
- });
3534
-
3535
- await player.load(fakeManifestUri, 0, fakeMimeType);
3536
- expect(player.getVariantTracks().length).toBe(3);
3537
-
3538
- onError.and.callFake((e) => {
3539
- const error = e.detail;
3540
- shaka.test.Util.expectToEqualError(
3541
- error,
3542
- new shaka.util.Error(
3543
- shaka.util.Error.Severity.CRITICAL,
3544
- shaka.util.Error.Category.MANIFEST,
3545
- shaka.util.Error.Code.RESTRICTIONS_CANNOT_BE_MET, {
3546
- hasAppRestrictions: true,
3547
- missingKeys: [],
3548
- restrictedKeyStatuses: [],
3549
- }));
3550
- });
3551
-
3552
- player.configure({restrictions: {minHeight: 1000, maxHeight: 2000}});
3553
- expect(onError).toHaveBeenCalled();
3554
- });
3555
-
3556
- it('chooses efficient codecs and removes the rest', async () => {
3557
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3558
- // More efficient codecs
3559
- manifest.addVariant(0, (variant) => {
3560
- variant.bandwidth = 100;
3561
- variant.addVideo(0, (stream) => {
3562
- stream.codecs = 'good';
3563
- stream.size(10, 10);
3564
- });
3565
- });
3566
- manifest.addVariant(1, (variant) => {
3567
- variant.bandwidth = 200;
3568
- variant.addVideo(1, (stream) => {
3569
- stream.codecs = 'good';
3570
- stream.size(20, 20);
3571
- });
3572
- });
3573
- manifest.addVariant(2, (variant) => {
3574
- variant.bandwidth = 300;
3575
- variant.addVideo(2, (stream) => {
3576
- stream.codecs = 'good';
3577
- stream.size(30, 30);
3578
- });
3579
- });
3580
-
3581
- // Less efficient codecs
3582
- manifest.addVariant(3, (variant) => {
3583
- variant.bandwidth = 10000;
3584
- variant.addVideo(3, (stream) => {
3585
- stream.codecs = 'bad';
3586
- stream.size(10, 10);
3587
- });
3588
- });
3589
- manifest.addVariant(4, (variant) => {
3590
- variant.bandwidth = 20000;
3591
- variant.addVideo(4, (stream) => {
3592
- stream.codecs = 'bad';
3593
- stream.size(20, 20);
3594
- });
3595
- });
3596
- manifest.addVariant(5, (variant) => {
3597
- variant.bandwidth = 30000;
3598
- variant.addVideo(5, (stream) => {
3599
- stream.codecs = 'bad';
3600
- stream.size(30, 30);
3601
- });
3602
- });
3603
- });
3604
-
3605
- await player.load(fakeManifestUri, 0, fakeMimeType);
3606
- expect(abrManager.setVariants).toHaveBeenCalled();
3607
- const variants = abrManager.setVariants.calls.argsFor(0)[0];
3608
- // We've already chosen codecs, so only 3 tracks should remain.
3609
- expect(variants.length).toBe(3);
3610
- // They should be the low-bandwidth ones.
3611
- expect(variants[0].video.codecs).toBe('good');
3612
- expect(variants[1].video.codecs).toBe('good');
3613
- expect(variants[2].video.codecs).toBe('good');
3614
- });
3615
-
3616
- it('updates AbrManager about restricted variants', async () => {
3617
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3618
- manifest.addVariant(0, (variant) => {
3619
- variant.addVideo(1, (stream) => {
3620
- stream.keyIds = new Set(['abc']);
3621
- stream.size(10, 10);
3622
- });
3623
- });
3624
- manifest.addVariant(2, (variant) => {
3625
- variant.addVideo(3, (stream) => {
3626
- stream.size(20, 20);
3627
- });
3628
- });
3629
- });
3630
-
3631
- /** @type {!shaka.test.FakeAbrManager} */
3632
- const abrManager = new shaka.test.FakeAbrManager();
3633
- player.configure('abrFactory', () => abrManager);
3634
- await player.load(fakeManifestUri, 0, fakeMimeType);
3635
- expect(player.getVariantTracks().length).toBe(2);
3636
-
3637
- // We have some key statuses, but not for the key IDs we know.
3638
- abrManager.setVariants.calls.reset();
3639
- onKeyStatus({'foo': 'usable'});
3640
-
3641
- expect(abrManager.setVariants).toHaveBeenCalled();
3642
- const variants = abrManager.setVariants.calls.argsFor(0)[0];
3643
- expect(variants.length).toBe(1);
3644
- expect(variants[0].id).toBe(2);
3645
- });
3646
-
3647
- it('chooses codecs after considering 6-channel preference', async () => {
3648
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3649
- // Surround sound AC-3, preferred by config
3650
- manifest.addVariant(0, (variant) => {
3651
- variant.bandwidth = 300;
3652
- variant.addAudio(0, (stream) => {
3653
- stream.channelsCount = 6;
3654
- stream.audioSamplingRate = 48000;
3655
- // ac-3 is rewritten as ec-3 on Tizen, so for the stability of this
3656
- // test case, use ec-3.
3657
- stream.codecs = 'ec-3';
3658
- });
3659
- });
3660
-
3661
- // Stereo AAC, would win out based on bandwidth alone
3662
- manifest.addVariant(1, (variant) => {
3663
- variant.bandwidth = 100;
3664
- variant.addAudio(1, (stream) => {
3665
- stream.channelsCount = 2;
3666
- stream.audioSamplingRate = 48000;
3667
- stream.codecs = 'mp4a.40.2';
3668
- });
3669
- });
3670
- });
3671
-
3672
- // Configure for 6 channels.
3673
- player.configure({
3674
- preferredAudioChannelCount: 6,
3675
- });
3676
- await player.load(fakeManifestUri, 0, fakeMimeType);
3677
- expect(abrManager.setVariants).toHaveBeenCalled();
3678
- // We've chosen codecs, so only 1 track should remain.
3679
- expect(abrManager.variants.length).toBe(1);
3680
- // It should be the 6-channel variant, based on our preference.
3681
- expect(abrManager.variants[0].audio.channelsCount).toBe(6);
3682
- expect(abrManager.variants[0].audio.codecs).toBe('ec-3');
3683
- });
3684
- });
3685
-
3686
- describe('getPlayheadTimeAsDate()', () => {
3687
- beforeEach(async () => {
3688
- const timeline = new shaka.media.PresentationTimeline(300, 0);
3689
- timeline.setStatic(false);
3690
-
3691
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3692
- manifest.presentationTimeline = timeline;
3693
- manifest.addVariant(0, (variant) => {
3694
- variant.addVideo(1);
3695
- });
3696
- });
3697
-
3698
- goog.asserts.assert(manifest, 'manifest must be non-null');
3699
- await player.load(fakeManifestUri, 0, fakeMimeType);
3700
- });
3701
-
3702
- it('gets current wall clock time in UTC', () => {
3703
- playhead.getTime.and.returnValue(20);
3704
-
3705
- const liveTimeUtc = player.getPlayheadTimeAsDate();
3706
- // (300 (presentation start time) + 20 (playhead time)) * 1000 (ms/sec)
3707
- expect(liveTimeUtc).toEqual(new Date(320 * 1000));
3708
- });
3709
- });
3710
-
3711
- it('rejects empty manifests', async () => {
3712
- manifest = shaka.test.ManifestGenerator.generate();
3713
-
3714
- const expected = Util.jasmineError(new shaka.util.Error(
3715
- shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.MANIFEST,
3716
- shaka.util.Error.Code.NO_VARIANTS));
3717
- await expectAsync(player.load(fakeManifestUri, 0, fakeMimeType))
3718
- .toBeRejectedWith(expected);
3719
- });
3720
-
3721
- it('does not assert when adapting', async () => {
3722
- // Most of our Player unit tests never adapt. This allowed some assertions
3723
- // to creep in that went uncaught until they happened during manual testing.
3724
- // Repro only happens with audio+video variants in which we only adapt one
3725
- // type. This test covers https://github.com/shaka-project/shaka-player/issues/954
3726
-
3727
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3728
- manifest.addVariant(0, (variant) => {
3729
- variant.bandwidth = 100;
3730
- variant.addVideo(0, (stream) => {
3731
- stream.size(10, 10);
3732
- });
3733
- variant.addAudio(9);
3734
- });
3735
-
3736
- manifest.addVariant(1, (variant) => {
3737
- variant.bandwidth = 200;
3738
- variant.addVideo(1, (stream) => {
3739
- stream.size(20, 20);
3740
- });
3741
- variant.addExistingStream(9); // audio
3742
- });
3743
-
3744
- manifest.addVariant(2, (variant) => {
3745
- variant.bandwidth = 300;
3746
- variant.addVideo(2, (stream) => {
3747
- stream.size(30, 30);
3748
- });
3749
- variant.addExistingStream(9); // audio
3750
- });
3751
- });
3752
-
3753
- await player.load(fakeManifestUri, 0, fakeMimeType);
3754
-
3755
- // We've already loaded variants[0]. Switch to [1] and [2].
3756
- abrManager.switchCallback(manifest.variants[1]);
3757
- abrManager.switchCallback(manifest.variants[2]);
3758
- });
3759
-
3760
- describe('isTextTrackVisible', () => {
3761
- it('does not throw before load', () => {
3762
- player.isTextTrackVisible();
3763
- });
3764
- });
3765
-
3766
- describe('setTextTrackVisibility', () => {
3767
- it('does not throw before load', async () => {
3768
- await player.setTextTrackVisibility(true);
3769
- });
3770
- });
3771
-
3772
- describe('isAudioOnly', () => {
3773
- it('detects audio-only content', async () => {
3774
- // False before we've loaded anything.
3775
- expect(player.isAudioOnly()).toBe(false);
3776
-
3777
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3778
- manifest.addVariant(0, (variant) => {
3779
- variant.addVideo(0);
3780
- variant.addAudio(1);
3781
- });
3782
- });
3783
- await player.load(fakeManifestUri, 0, fakeMimeType);
3784
- // We have audio & video tracks, so this is not audio-only.
3785
- expect(player.isAudioOnly()).toBe(false);
3786
-
3787
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3788
- manifest.addVariant(0, (variant) => {
3789
- variant.addVideo(0);
3790
- });
3791
- });
3792
- await player.load(fakeManifestUri, 0, fakeMimeType);
3793
- // We have video-only tracks, so this is not audio-only.
3794
- expect(player.isAudioOnly()).toBe(false);
3795
-
3796
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3797
- manifest.addVariant(0, (variant) => {
3798
- variant.addAudio(1);
3799
- });
3800
- });
3801
- await player.load(fakeManifestUri, 0, fakeMimeType);
3802
- // We have audio-only tracks, so this is audio-only.
3803
- expect(player.isAudioOnly()).toBe(true);
3804
-
3805
- await player.unload();
3806
- // When we have nothing loaded, we go back to not audio-only status.
3807
- expect(player.isAudioOnly()).toBe(false);
3808
- });
3809
- });
3810
-
3811
- describe('load', () => {
3812
- it('tolerates bandwidth of NaN, undefined, or 0', async () => {
3813
- // Regression test for https://github.com/shaka-project/shaka-player/issues/938
3814
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3815
- manifest.addVariant(0, (variant) => {
3816
- variant.bandwidth = /** @type {?} */(undefined);
3817
- variant.addVideo(0, (stream) => {
3818
- stream.size(10, 10);
3819
- });
3820
- });
3821
- manifest.addVariant(1, (variant) => {
3822
- variant.bandwidth = NaN;
3823
- variant.addVideo(1, (stream) => {
3824
- stream.size(20, 20);
3825
- });
3826
- });
3827
- manifest.addVariant(2, (variant) => {
3828
- variant.bandwidth = 0;
3829
- variant.addVideo(2, (stream) => {
3830
- stream.size(30, 30);
3831
- });
3832
- });
3833
- });
3834
-
3835
- // Before the fix, load() would fail assertions and throw errors.
3836
- await player.load(fakeManifestUri, 0, fakeMimeType);
3837
- });
3838
-
3839
- it('respects startTime of 0', async () => {
3840
- // What we shouldn't do is treat start time of 0 as the same as startTime
3841
- // of null/undefined. 0 means timestamp 0, whereas null/undefined means
3842
- // "default". For VOD, the default is 0, but for live streams, the
3843
- // default is the live edge.
3844
-
3845
- // Create a live timeline and manifest.
3846
- const timeline = new shaka.media.PresentationTimeline(300, 0);
3847
- timeline.setStatic(false);
3848
-
3849
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3850
- manifest.presentationTimeline = timeline;
3851
- manifest.addVariant(0, (variant) => {
3852
- variant.addVideo(1);
3853
- });
3854
- });
3855
-
3856
- // To ensure that Playhead is correctly created, we must use the original
3857
- // playhead injector. To inspect the real Playhead instance, though, we
3858
- // must shim this method and keep a copy of the real Playhead. Otherwise,
3859
- // we would be merely inspecting the mock Playhead.
3860
- /** @type {shaka.media.Playhead} */
3861
- let realPlayhead = null;
3862
-
3863
- /**
3864
- * @this {shaka.Player}
3865
- * @return {!shaka.media.Playhead}
3866
- */
3867
- // eslint-disable-next-line no-restricted-syntax
3868
- player.createPlayhead = function() {
3869
- realPlayhead =
3870
- // eslint-disable-next-line no-restricted-syntax
3871
- shaka.Player.prototype.createPlayhead.apply(this, arguments);
3872
- return realPlayhead;
3873
- };
3874
-
3875
- await player.load(fakeManifestUri, /* startTime= */ 0, fakeMimeType);
3876
-
3877
- // Ensure this is seen as a live stream, or else the test is invalid.
3878
- expect(player.isLive()).toBe(true);
3879
-
3880
- // If startTime of 0 was treated as null, then getTime() would point to
3881
- // the live edge instead of 0.
3882
- expect(realPlayhead.getTime()).toBe(0);
3883
- });
3884
- });
3885
-
3886
- describe('language methods', () => {
3887
- let videoOnlyManifest;
3888
-
3889
- beforeEach(() => {
3890
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3891
- manifest.addVariant(1, (variant) => {
3892
- variant.language = 'fr';
3893
- variant.addVideo(0);
3894
- variant.addAudio(1, (stream) => {
3895
- stream.language = 'fr';
3896
- });
3897
- });
3898
-
3899
- manifest.addVariant(2, (variant) => {
3900
- variant.language = 'en';
3901
- variant.addExistingStream(0); // video
3902
- variant.addAudio(2, (stream) => {
3903
- stream.language = 'en';
3904
- stream.roles = ['main'];
3905
- });
3906
- });
3907
-
3908
- manifest.addVariant(3, (variant) => {
3909
- variant.language = 'en';
3910
- variant.addExistingStream(0); // video
3911
- variant.addAudio(3, (stream) => {
3912
- stream.language = 'en';
3913
- stream.roles = ['commentary'];
3914
- });
3915
- });
3916
-
3917
- manifest.addVariant(4, (variant) => {
3918
- variant.language = 'de';
3919
- variant.addExistingStream(0); // video
3920
- variant.addAudio(4, (stream) => {
3921
- stream.language = 'de';
3922
- stream.roles = ['foo', 'bar'];
3923
- });
3924
- });
3925
-
3926
- manifest.addTextStream(5, (stream) => {
3927
- stream.language = 'es';
3928
- stream.roles = ['baz', 'qwerty'];
3929
- });
3930
-
3931
- manifest.addTextStream(6, (stream) => {
3932
- stream.language = 'en';
3933
- stream.kind = 'caption';
3934
- stream.roles = ['main', 'caption'];
3935
- });
3936
-
3937
- manifest.addTextStream(7, (stream) => {
3938
- stream.language = 'en';
3939
- stream.kind = 'subtitle';
3940
- stream.roles = ['main', 'subtitle'];
3941
- });
3942
- });
3943
-
3944
- videoOnlyManifest = shaka.test.ManifestGenerator.generate((manifest) => {
3945
- manifest.addVariant(1, (variant) => {
3946
- variant.bandwidth = 400;
3947
- variant.addVideo(1);
3948
- });
3949
- manifest.addVariant(2, (variant) => {
3950
- variant.bandwidth = 800;
3951
- variant.addVideo(2);
3952
- });
3953
- });
3954
- });
3955
-
3956
- describe('get*Languages', () => {
3957
- it('returns a list of languages', async () => {
3958
- await player.load(fakeManifestUri, 0, fakeMimeType);
3959
- expect(player.getAudioLanguages()).toEqual(['fr', 'en', 'de']);
3960
- expect(player.getTextLanguages()).toEqual(['es', 'en']);
3961
- });
3962
-
3963
- it('returns "und" for video-only tracks', async () => {
3964
- manifest = videoOnlyManifest;
3965
-
3966
- await player.load(fakeManifestUri, 0, fakeMimeType);
3967
- expect(player.getAudioLanguages()).toEqual(['und']);
3968
- expect(player.getTextLanguages()).toEqual([]);
3969
- });
3970
- });
3971
-
3972
- describe('getAudioLanguagesAndRoles', () => {
3973
- it('ignores video roles and labels', async () => {
3974
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3975
- manifest.addVariant(0, (variant) => {
3976
- variant.language = 'en';
3977
- variant.addVideo(1, (stream) => {
3978
- stream.roles = ['video-only-role'];
3979
- stream.label = 'should not show up';
3980
- });
3981
- variant.addAudio(2, (stream) => {
3982
- stream.roles = ['audio-only-role'];
3983
- stream.language = 'en';
3984
- });
3985
- });
3986
- });
3987
-
3988
- await player.load(fakeManifestUri, 0, fakeMimeType);
3989
-
3990
- expect(player.getAudioLanguagesAndRoles()).toEqual([
3991
- {language: 'en', role: 'audio-only-role', label: null},
3992
- ]);
3993
- });
3994
-
3995
- it('lists all language-role combinations', async () => {
3996
- await player.load(fakeManifestUri, 0, fakeMimeType);
3997
- expect(player.getAudioLanguagesAndRoles()).toEqual([
3998
- {language: 'fr', role: '', label: null},
3999
- {language: 'en', role: 'main', label: null},
4000
- {language: 'en', role: 'commentary', label: null},
4001
- {language: 'de', role: 'foo', label: null},
4002
- {language: 'de', role: 'bar', label: null},
4003
- ]);
4004
- });
4005
-
4006
- it('associates audio streams with their labels', async () => {
4007
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
4008
- manifest.addVariant(0, (variant) => {
4009
- variant.language = 'en';
4010
- variant.addAudio(1, (stream) => {
4011
- stream.roles = ['role-1'];
4012
- stream.language = 'en';
4013
- stream.label = 'english';
4014
- });
4015
- });
4016
- manifest.addVariant(0, (variant) => {
4017
- variant.language = 'es';
4018
- variant.addAudio(2, (stream) => {
4019
- stream.roles = ['role-2', 'role-3'];
4020
- stream.language = 'es';
4021
- stream.label = 'spanish';
4022
- });
4023
- });
4024
- });
4025
-
4026
- await player.load(fakeManifestUri, 0, fakeMimeType);
4027
-
4028
- expect(player.getAudioLanguagesAndRoles()).toEqual([
4029
- {language: 'en', role: 'role-1', label: 'english'},
4030
- {language: 'es', role: 'role-2', label: 'spanish'},
4031
- {language: 'es', role: 'role-3', label: 'spanish'},
4032
- ]);
4033
- });
4034
-
4035
- it('uses "und" for video-only tracks', async () => {
4036
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
4037
- manifest.addVariant(0, (variant) => {
4038
- variant.addVideo(1, (stream) => {
4039
- stream.roles = ['video-only-role'];
4040
- });
4041
- });
4042
- });
4043
-
4044
- await player.load(fakeManifestUri, 0, fakeMimeType);
4045
- expect(player.getAudioLanguagesAndRoles()).toEqual([
4046
- {language: 'und', role: '', label: null},
4047
- ]);
4048
- });
4049
- });
4050
-
4051
- describe('getTextLanguageAndRoles', () => {
4052
- it('lists all language-role combinations', async () => {
4053
- await player.load(fakeManifestUri, 0, fakeMimeType);
4054
- expect(player.getTextLanguagesAndRoles()).toEqual([
4055
- {language: 'es', role: 'baz', label: null},
4056
- {language: 'es', role: 'qwerty', label: null},
4057
- {language: 'en', role: 'main', label: null},
4058
- {language: 'en', role: 'caption', label: null},
4059
- {language: 'en', role: 'subtitle', label: null},
4060
- ]);
4061
- });
4062
- });
4063
-
4064
- describe('getThumbnails', () => {
4065
- it('returns correct thumbnail position for supplied time', async () => {
4066
- const uris = () => ['thumbnail'];
4067
- const ref = new shaka.media.SegmentReference(
4068
- 0, 60, uris, 0, null, null, 0, 0, Infinity, [],
4069
- );
4070
- const index = new shaka.media.SegmentIndex([ref]);
4071
-
4072
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
4073
- manifest.addVariant(0, (variant) => {
4074
- variant.addVideo(1);
4075
- });
4076
- manifest.addImageStream(5, (stream) => {
4077
- stream.originalId = 'thumbnail';
4078
- stream.width = 200;
4079
- stream.height = 150;
4080
- stream.mimeType = 'image/jpeg';
4081
- stream.tilesLayout = '2x3';
4082
- stream.segmentIndex = index;
4083
- });
4084
- });
4085
-
4086
- await player.load(fakeManifestUri, 0, fakeMimeType);
4087
-
4088
- expect(player.getImageTracks()[0].width).toBe(100);
4089
- expect(player.getImageTracks()[0].height).toBe(50);
4090
- const thumbnail0 = await player.getThumbnails(5, 0);
4091
- const thumbnail1 = await player.getThumbnails(5, 11);
4092
- const thumbnail2 = await player.getThumbnails(5, 21);
4093
- const thumbnail5 = await player.getThumbnails(5, 51);
4094
- expect(thumbnail0).toEqual(jasmine.objectContaining({
4095
- imageHeight: 150,
4096
- imageWidth: 200,
4097
- positionX: 0,
4098
- positionY: 0,
4099
- width: 100,
4100
- height: 50,
4101
- }));
4102
- expect(thumbnail1).toEqual(jasmine.objectContaining({
4103
- imageHeight: 150,
4104
- imageWidth: 200,
4105
- positionX: 100,
4106
- positionY: 0,
4107
- width: 100,
4108
- height: 50,
4109
- }));
4110
- expect(thumbnail2).toEqual(jasmine.objectContaining({
4111
- imageHeight: 150,
4112
- imageWidth: 200,
4113
- positionX: 0,
4114
- positionY: 50,
4115
- width: 100,
4116
- height: 50,
4117
- }));
4118
- expect(thumbnail5).toEqual(jasmine.objectContaining({
4119
- imageHeight: 150,
4120
- imageWidth: 200,
4121
- positionX: 100,
4122
- positionY: 100,
4123
- width: 100,
4124
- height: 50,
4125
- }));
4126
- });
4127
-
4128
- it('returns correct duration for a partially-used segment', async () => {
4129
- const uris = () => ['thumbnail'];
4130
-
4131
- const ref1 = new shaka.media.SegmentReference(
4132
- 0, 60, uris, 0, null, null, 0, 0, Infinity);
4133
- const ref2 = new shaka.media.SegmentReference(
4134
- 60, 90, uris, 0, null, null, 0, 0, Infinity);
4135
- ref2.trueEndTime = 120;
4136
-
4137
- const index = new shaka.media.SegmentIndex([ref1, ref2]);
4138
-
4139
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
4140
- manifest.addVariant(0, (variant) => {
4141
- variant.addVideo(1);
4142
- });
4143
- manifest.addImageStream(5, (stream) => {
4144
- stream.originalId = 'thumbnail';
4145
- stream.width = 200;
4146
- stream.height = 150;
4147
- stream.mimeType = 'image/jpeg';
4148
- stream.tilesLayout = '2x3';
4149
- stream.segmentIndex = index;
4150
- });
4151
- });
4152
-
4153
- await player.load(fakeManifestUri, 0, fakeMimeType);
4154
-
4155
- const thumbnail0 = await player.getThumbnails(5, 0);
4156
- expect(thumbnail0.startTime).toBe(0);
4157
- expect(thumbnail0.duration).toBe(10);
4158
-
4159
- const thumbnail1 = await player.getThumbnails(5, 10);
4160
- expect(thumbnail1.startTime).toBe(10);
4161
- expect(thumbnail1.duration).toBe(10);
4162
-
4163
- const thumbnail6 = await player.getThumbnails(5, 60);
4164
- expect(thumbnail6.startTime).toBe(60);
4165
- expect(thumbnail6.duration).toBe(10);
4166
-
4167
- const thumbnail8 = await player.getThumbnails(5, 80);
4168
- expect(thumbnail8.startTime).toBe(80);
4169
- expect(thumbnail8.duration).toBe(10);
4170
- });
4171
- });
4172
-
4173
- describe('getAllThumbnails', () => {
4174
- it('returns all thumbnails', async () => {
4175
- const uris = () => ['thumbnail'];
4176
- const ref = new shaka.media.SegmentReference(
4177
- 0, 60, uris, 0, null, null, 0, 0, Infinity, [],
4178
- );
4179
- const index = new shaka.media.SegmentIndex([ref]);
4180
-
4181
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
4182
- manifest.addVariant(0, (variant) => {
4183
- variant.addVideo(1);
4184
- });
4185
- manifest.addImageStream(5, (stream) => {
4186
- stream.originalId = 'thumbnail';
4187
- stream.width = 200;
4188
- stream.height = 150;
4189
- stream.mimeType = 'image/jpeg';
4190
- stream.tilesLayout = '2x3';
4191
- stream.segmentIndex = index;
4192
- });
4193
- });
4194
-
4195
- await player.load(fakeManifestUri, 0, fakeMimeType);
4196
-
4197
- expect(player.getImageTracks()[0].width).toBe(100);
4198
- expect(player.getImageTracks()[0].height).toBe(50);
4199
- const thumbnails = await player.getAllThumbnails(5);
4200
- expect(thumbnails.length).toBe(6);
4201
- expect(thumbnails[0]).toEqual(jasmine.objectContaining({
4202
- imageHeight: 150,
4203
- imageWidth: 200,
4204
- positionX: 0,
4205
- positionY: 0,
4206
- width: 100,
4207
- height: 50,
4208
- }));
4209
- expect(thumbnails[1]).toEqual(jasmine.objectContaining({
4210
- imageHeight: 150,
4211
- imageWidth: 200,
4212
- positionX: 100,
4213
- positionY: 0,
4214
- width: 100,
4215
- height: 50,
4216
- }));
4217
- expect(thumbnails[2]).toEqual(jasmine.objectContaining({
4218
- imageHeight: 150,
4219
- imageWidth: 200,
4220
- positionX: 0,
4221
- positionY: 50,
4222
- width: 100,
4223
- height: 50,
4224
- }));
4225
- expect(thumbnails[5]).toEqual(jasmine.objectContaining({
4226
- imageHeight: 150,
4227
- imageWidth: 200,
4228
- positionX: 100,
4229
- positionY: 100,
4230
- width: 100,
4231
- height: 50,
4232
- }));
4233
- });
4234
- });
4235
- });
4236
-
4237
- describe('config streaming.startAtSegmentBoundary', () => {
4238
- // Test for https://github.com/shaka-project/shaka-player/issues/4188
4239
- // In that issue, using streaming.startAtSegmentBoundary in v4.0.0 caused
4240
- // an exception due to the use of a removed method.
4241
- it('adjusts start time', async () => {
4242
- player.configure('streaming.startAtSegmentBoundary', true);
4243
-
4244
- // In order to adjust the start time to a segment boundary, we need
4245
- // segment descriptions in the segment index. So create a non-default
4246
- // fake manifest.
4247
- const timeline = new shaka.media.PresentationTimeline(300, 0);
4248
- timeline.setStatic(true);
4249
- // This duration is used by useSegmentTemplate below to decide how many
4250
- // references to generate.
4251
- timeline.setDuration(300);
4252
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
4253
- manifest.presentationTimeline = timeline;
4254
- manifest.addVariant(0, (variant) => {
4255
- variant.addVideo(1, (stream) => {
4256
- stream.useSegmentTemplate(
4257
- '$Number$.mp4', /* segmentDuration= */ 10);
4258
- });
4259
- });
4260
- });
4261
-
4262
- await player.load(fakeManifestUri, 12, fakeMimeType);
4263
-
4264
- expect(playhead.setStartTime).toHaveBeenCalledWith(10);
4265
- });
4266
-
4267
- it('does not fail with no segments', async () => {
4268
- player.configure('streaming.startAtSegmentBoundary', true);
4269
-
4270
- // Without useSegmentTemplate in the fake manifest, the call to
4271
- // getIteratorForTime() in Player produces a null iterator. Using the
4272
- // default fake manifest should cover that case. But just to make sure,
4273
- // verify that we have no segments before calling load().
4274
- const variant = manifest.variants[0];
4275
- expect(variant.video.segmentIndex.getIteratorForTime(0)).toBeNull();
4276
- expect(variant.audio.segmentIndex.getIteratorForTime(0)).toBeNull();
4277
-
4278
- await player.load(fakeManifestUri, 0, fakeMimeType);
4279
- });
4280
- });
4281
-
4282
- describe('config streaming.failureCallback default', () => {
4283
- /** @type {jasmine.Spy} */
4284
- let retryStreaming;
4285
- /** @type {jasmine.Spy} */
4286
- let isLive;
4287
-
4288
- /**
4289
- * @suppress {accessControls}
4290
- * @param {!shaka.util.Error} error
4291
- */
4292
- function defaultStreamingFailureCallback(error) {
4293
- player.defaultStreamingFailureCallback_(error);
4294
- }
4295
-
4296
- beforeEach(() => {
4297
- retryStreaming = jasmine.createSpy('retryStreaming');
4298
- isLive = jasmine.createSpy('isLive');
4299
-
4300
- player.retryStreaming = Util.spyFunc(retryStreaming);
4301
- player.isLive = Util.spyFunc(isLive);
4302
- });
4303
-
4304
- it('ignores VOD failures', () => {
4305
- isLive.and.returnValue(false);
4306
-
4307
- const error = new shaka.util.Error(
4308
- shaka.util.Error.Severity.CRITICAL,
4309
- shaka.util.Error.Category.NETWORK,
4310
- shaka.util.Error.Code.BAD_HTTP_STATUS,
4311
- /* url= */ '',
4312
- /* http_status= */ 404);
4313
-
4314
- defaultStreamingFailureCallback(error);
4315
- expect(retryStreaming).not.toHaveBeenCalled();
4316
- });
4317
-
4318
- it('retries live on HTTP 404', () => {
4319
- isLive.and.returnValue(true);
4320
-
4321
- const error = new shaka.util.Error(
4322
- shaka.util.Error.Severity.CRITICAL,
4323
- shaka.util.Error.Category.NETWORK,
4324
- shaka.util.Error.Code.BAD_HTTP_STATUS,
4325
- /* url= */ '',
4326
- /* http_status= */ 404);
4327
-
4328
- defaultStreamingFailureCallback(error);
4329
- expect(retryStreaming).toHaveBeenCalled();
4330
- });
4331
-
4332
- it('retries live on generic HTTP error', () => {
4333
- isLive.and.returnValue(true);
4334
-
4335
- const error = new shaka.util.Error(
4336
- shaka.util.Error.Severity.CRITICAL,
4337
- shaka.util.Error.Category.NETWORK,
4338
- shaka.util.Error.Code.HTTP_ERROR);
4339
-
4340
- defaultStreamingFailureCallback(error);
4341
- expect(retryStreaming).toHaveBeenCalled();
4342
- });
4343
-
4344
- it('retries live on HTTP timeout', () => {
4345
- isLive.and.returnValue(true);
4346
-
4347
- const error = new shaka.util.Error(
4348
- shaka.util.Error.Severity.CRITICAL,
4349
- shaka.util.Error.Category.NETWORK,
4350
- shaka.util.Error.Code.TIMEOUT);
4351
-
4352
- defaultStreamingFailureCallback(error);
4353
- expect(retryStreaming).toHaveBeenCalled();
4354
- });
4355
-
4356
- it('ignores other live failures', () => {
4357
- isLive.and.returnValue(true);
4358
-
4359
- const error = new shaka.util.Error(
4360
- shaka.util.Error.Severity.CRITICAL,
4361
- shaka.util.Error.Category.MEDIA,
4362
- shaka.util.Error.Code.VIDEO_ERROR);
4363
-
4364
- defaultStreamingFailureCallback(error);
4365
- expect(retryStreaming).not.toHaveBeenCalled();
4366
- });
4367
- });
4368
-
4369
- /**
4370
- * Gets the currently active variant track.
4371
- * @return {shaka.extern.Track}
4372
- */
4373
- function getActiveVariantTrack() {
4374
- const activeTracks = player.getVariantTracks().filter((track) => {
4375
- return track.active;
4376
- });
4377
-
4378
- expect(activeTracks.length).toBe(1);
4379
- return activeTracks[0];
4380
- }
4381
-
4382
- /**
4383
- * Gets the currently active text track.
4384
- * @return {?shaka.extern.Track}
4385
- */
4386
- function getActiveTextTrack() {
4387
- const activeTracks = player.getTextTracks().filter((track) => {
4388
- return track.active;
4389
- });
4390
-
4391
- return activeTracks[0] || null;
4392
- }
4393
-
4394
- /**
4395
- * A Jasmine asymmetric matcher for substring matches.
4396
- * @param {string} substring
4397
- * @return {!Object}
4398
- */
4399
- function stringContaining(substring) {
4400
- return {
4401
- asymmetricMatch: (actual) => actual.includes(substring),
4402
- };
4403
- }
4404
-
4405
- /**
4406
- * @param {!Object.<string, string>} keyStatusMap
4407
- * @suppress {accessControls}
4408
- */
4409
- function onKeyStatus(keyStatusMap) {
4410
- player.onKeyStatus_(keyStatusMap);
4411
- }
4412
-
4413
- /**
4414
- * Create a fake text displayer with a little extra logic to work with the
4415
- * test cases.
4416
- *
4417
- * @return {!shaka.test.FakeTextDisplayer}
4418
- */
4419
- function createTextDisplayer() {
4420
- /** @type {!shaka.test.FakeTextDisplayer} */
4421
- const displayer = new shaka.test.FakeTextDisplayer();
4422
-
4423
- // Allow the tests to set and check if we are showing text.
4424
- let isVisible = false;
4425
- displayer.isTextVisibleSpy.and.callFake(() => {
4426
- return isVisible;
4427
- });
4428
- displayer.setTextVisibilitySpy.and.callFake((on) => {
4429
- isVisible = on;
4430
- });
4431
-
4432
- return displayer;
4433
- }
4434
- });