shaka-player 3.3.2 → 4.0.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 (389) hide show
  1. package/.csslintrc +11 -1
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  3. package/.github/pull_request_template.md +6 -34
  4. package/.github/workflows/build-and-test.yaml +129 -0
  5. package/.github/workflows/custom-actions/prep-for-appspot/action.yaml +56 -0
  6. package/.github/workflows/custom-actions/set-commit-status/action.yaml +41 -0
  7. package/.github/workflows/demo-version-index.yaml +37 -0
  8. package/.github/workflows/nightly-demo.yaml +42 -0
  9. package/.github/workflows/release-please.yaml +168 -0
  10. package/.github/workflows/safari-homedir-launcher.sh +18 -0
  11. package/.github/workflows/selenium-lab-tests.yaml +92 -0
  12. package/.github/workflows/sync-labels.yaml +33 -0
  13. package/.github/workflows/update-issues.yaml +29 -0
  14. package/.github/workflows/validate-pr-title.yaml +35 -0
  15. package/AUTHORS +3 -0
  16. package/CHANGELOG.md +1866 -1675
  17. package/CONTRIBUTING.md +2 -2
  18. package/CONTRIBUTORS +3 -0
  19. package/README.md +16 -13
  20. package/app-engine/README.md +9 -0
  21. package/app-engine/demo-version-index/README.md +14 -0
  22. package/app-engine/demo-version-index/app.yaml +28 -0
  23. package/app-engine/demo-version-index/generate.py +164 -0
  24. package/app-engine/demo-version-index/main.py +11 -0
  25. package/app-engine/demo-version-index/requirements.txt +5 -0
  26. package/app-engine/demo-version-index/templates/index.html +114 -0
  27. package/app-engine/shaka-player-demo/README.md +18 -0
  28. package/app-engine/shaka-player-demo/app.yaml +61 -0
  29. package/app-engine/shaka-player-demo/main.py +95 -0
  30. package/app-engine/shaka-player-demo/posters/10yo.png +0 -0
  31. package/app-engine/shaka-player-demo/posters/10yo.xcf +0 -0
  32. package/app-engine/shaka-player-demo/posters/1yo.jpg +0 -0
  33. package/app-engine/shaka-player-demo/posters/2yo.png +0 -0
  34. package/app-engine/shaka-player-demo/posters/2yo.xcf +0 -0
  35. package/app-engine/shaka-player-demo/posters/3yo.png +0 -0
  36. package/app-engine/shaka-player-demo/posters/3yo.xcf +0 -0
  37. package/app-engine/shaka-player-demo/posters/4yo.png +0 -0
  38. package/app-engine/shaka-player-demo/posters/4yo.xcf +0 -0
  39. package/app-engine/shaka-player-demo/posters/5yo.png +0 -0
  40. package/app-engine/shaka-player-demo/posters/5yo.xcf +0 -0
  41. package/app-engine/shaka-player-demo/posters/6yo.png +0 -0
  42. package/app-engine/shaka-player-demo/posters/6yo.xcf +0 -0
  43. package/app-engine/shaka-player-demo/posters/7yo.png +0 -0
  44. package/app-engine/shaka-player-demo/posters/7yo.xcf +0 -0
  45. package/app-engine/shaka-player-demo/posters/8yo.png +0 -0
  46. package/app-engine/shaka-player-demo/posters/8yo.xcf +0 -0
  47. package/app-engine/shaka-player-demo/posters/9yo.png +0 -0
  48. package/app-engine/shaka-player-demo/posters/9yo.xcf +0 -0
  49. package/app-engine/shaka-player-demo/posters/audioOnly.gif +0 -0
  50. package/app-engine/shaka-player-demo/posters/audioRickRoll.gif +0 -0
  51. package/app-engine/shaka-player-demo/posters/colorbars.gif +0 -0
  52. package/app-engine/shaka-player-demo/posters/fireworks.jpg +0 -0
  53. package/app-engine/shaka-player-demo/posters/party-hat.png +0 -0
  54. package/app-engine/shaka-player-demo/posters/sources.txt +46 -0
  55. package/app-engine/shaka-player-demo/posters/standard.png +0 -0
  56. package/app-engine/shaka-player-demo/posters/trek.jpg +0 -0
  57. package/app-engine/shaka-player-demo/posters/valentines.png +0 -0
  58. package/app-engine/shaka-player-demo/posters/zombie.jpg +0 -0
  59. package/app-engine/shaka-player-demo/posters.py +110 -0
  60. package/app-engine/shaka-player-demo/requirements.txt +5 -0
  61. package/app-engine/shaka-player-demo/time.txt +1 -0
  62. package/build/README.md +3 -3
  63. package/build/checkversion.py +1 -1
  64. package/build/compiler.py +1 -1
  65. package/build/conformance.textproto +13 -0
  66. package/build/docker/Dockerfile +20 -0
  67. package/build/docker/docker-compose.yml +10 -0
  68. package/build/gendeps.py +18 -15
  69. package/build/shaka-lab.yaml +161 -0
  70. package/build/shakaBuildHelpers.py +4 -29
  71. package/build/test.py +94 -29
  72. package/build/types/core +0 -1
  73. package/build/types/polyfill +1 -3
  74. package/build/wrapper.template.js +2 -2
  75. package/demo/TengwarTelcontar.woff2 +0 -0
  76. package/demo/asset_card.js +1 -2
  77. package/demo/cast_receiver/index.html +1 -1
  78. package/demo/cast_receiver/receiver_app.css +14 -14
  79. package/demo/common/asset.js +17 -1
  80. package/demo/common/assets.js +31 -0
  81. package/demo/common/message_ids.js +6 -3
  82. package/demo/config.js +10 -12
  83. package/demo/custom.js +39 -1
  84. package/demo/customWarning.txt +2 -2
  85. package/demo/demo.less +29 -18
  86. package/demo/demo_uncompiled.js +1 -13
  87. package/demo/demo_utils.js +0 -1
  88. package/demo/index.html +1 -1
  89. package/demo/locales/en.json +6 -3
  90. package/demo/locales/source.json +22 -10
  91. package/demo/main.js +12 -9
  92. package/demo/search.js +2 -1
  93. package/dist/controls.css +3 -3
  94. package/dist/controls.css.map +1 -1
  95. package/dist/demo.compiled.debug.js +236 -232
  96. package/dist/demo.compiled.debug.map +4 -4
  97. package/dist/demo.compiled.js +236 -232
  98. package/dist/demo.compiled.map +4 -4
  99. package/dist/demo.css +1 -1
  100. package/dist/demo.css.map +1 -1
  101. package/dist/deps.js +229 -226
  102. package/dist/locales.js +34 -32
  103. package/dist/receiver.compiled.debug.js +75 -73
  104. package/dist/receiver.compiled.debug.map +4 -4
  105. package/dist/receiver.compiled.js +75 -73
  106. package/dist/receiver.compiled.map +4 -4
  107. package/dist/shaka-player.compiled.d.ts +321 -314
  108. package/dist/shaka-player.compiled.debug.d.ts +321 -314
  109. package/dist/shaka-player.compiled.debug.externs.js +140 -129
  110. package/dist/shaka-player.compiled.debug.js +527 -592
  111. package/dist/shaka-player.compiled.debug.map +4 -4
  112. package/dist/shaka-player.compiled.externs.js +140 -129
  113. package/dist/shaka-player.compiled.js +836 -860
  114. package/dist/shaka-player.compiled.map +4 -4
  115. package/dist/shaka-player.ui.d.ts +367 -358
  116. package/dist/shaka-player.ui.debug.d.ts +367 -358
  117. package/dist/shaka-player.ui.debug.externs.js +148 -129
  118. package/dist/shaka-player.ui.debug.js +586 -649
  119. package/dist/shaka-player.ui.debug.map +4 -4
  120. package/dist/shaka-player.ui.externs.js +148 -129
  121. package/dist/shaka-player.ui.js +1008 -1028
  122. package/dist/shaka-player.ui.map +4 -4
  123. package/docs/design/REDESIGN.md +33 -33
  124. package/docs/design/bg-fetch.md +2 -2
  125. package/docs/design/codec_preferences.md +1 -1
  126. package/docs/design/dash-audio-channels.md +3 -3
  127. package/docs/design/dash-manifests.md +1 -1
  128. package/docs/design/gap-jumping.md +3 -3
  129. package/docs/design/preload.md +2 -2
  130. package/docs/tutorials/config.md +0 -2
  131. package/docs/tutorials/drm-config.md +5 -0
  132. package/docs/tutorials/fairplay.md +7 -22
  133. package/docs/tutorials/faq.md +8 -19
  134. package/docs/tutorials/index.json +3 -8
  135. package/docs/tutorials/plugins.md +4 -6
  136. package/docs/tutorials/selenium-grid-config.md +122 -0
  137. package/docs/tutorials/upgrade.md +83 -11
  138. package/docs/tutorials/welcome.md +10 -2
  139. package/externs/cmcd.js +1 -1
  140. package/externs/polyfill.js +15 -0
  141. package/externs/shaka/manifest.js +5 -1
  142. package/externs/shaka/net.js +12 -0
  143. package/externs/shaka/offline.js +5 -1
  144. package/externs/shaka/player.js +39 -32
  145. package/externs/shaka/text.js +12 -12
  146. package/externs/sourcebuffer.js +15 -0
  147. package/karma.conf.js +137 -30
  148. package/lib/abr/simple_abr_manager.js +12 -6
  149. package/lib/ads/client_side_ad.js +13 -2
  150. package/lib/ads/client_side_ad_manager.js +22 -4
  151. package/lib/cast/cast_proxy.js +3 -4
  152. package/lib/cast/cast_utils.js +0 -1
  153. package/lib/cea/cea608_data_channel.js +2 -2
  154. package/lib/cea/cea708_service.js +5 -4
  155. package/lib/cea/mp4_cea_parser.js +11 -5
  156. package/lib/cea/sei_processor.js +6 -3
  157. package/lib/dash/content_protection.js +85 -5
  158. package/lib/dash/dash_parser.js +10 -12
  159. package/lib/dash/mpd_utils.js +4 -5
  160. package/lib/dash/segment_list.js +1 -2
  161. package/lib/dash/segment_template.js +3 -3
  162. package/lib/hls/hls_parser.js +386 -749
  163. package/lib/hls/manifest_text_parser.js +5 -6
  164. package/lib/media/adaptation_set.js +1 -2
  165. package/lib/media/content_workarounds.js +2 -2
  166. package/lib/media/drm_engine.js +105 -55
  167. package/lib/media/gap_jumping_controller.js +10 -45
  168. package/lib/media/media_source_engine.js +90 -17
  169. package/lib/media/mp4_segment_index_parser.js +1 -4
  170. package/lib/media/playhead.js +4 -7
  171. package/lib/media/presentation_timeline.js +19 -10
  172. package/lib/media/segment_index.js +13 -46
  173. package/lib/media/segment_reference.js +47 -1
  174. package/lib/media/streaming_engine.js +35 -17
  175. package/lib/media/time_ranges_utils.js +5 -12
  176. package/lib/media/video_wrapper.js +1 -1
  177. package/lib/net/networking_engine.js +4 -1
  178. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  179. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  180. package/lib/offline/manifest_converter.js +1 -0
  181. package/lib/offline/storage.js +104 -136
  182. package/lib/player.js +50 -216
  183. package/lib/polyfill/all.js +2 -3
  184. package/lib/polyfill/encryption_scheme.js +1 -1
  185. package/lib/polyfill/media_capabilities.js +15 -9
  186. package/lib/polyfill/mediasource.js +0 -28
  187. package/lib/polyfill/patchedmediakeys_nop.js +2 -0
  188. package/lib/polyfill/patchedmediakeys_webkit.js +2 -0
  189. package/lib/polyfill/symbol.js +46 -0
  190. package/lib/text/cue.js +1 -7
  191. package/lib/text/lrc_text_parser.js +8 -0
  192. package/lib/text/mp4_ttml_parser.js +8 -0
  193. package/lib/text/mp4_vtt_parser.js +8 -0
  194. package/lib/text/sbv_text_parser.js +8 -0
  195. package/lib/text/simple_text_displayer.js +3 -8
  196. package/lib/text/srt_text_parser.js +8 -0
  197. package/lib/text/ssa_text_parser.js +8 -0
  198. package/lib/text/text_engine.js +19 -3
  199. package/lib/text/ttml_text_parser.js +16 -5
  200. package/lib/text/ui_text_displayer.js +2 -8
  201. package/lib/text/vtt_text_parser.js +24 -2
  202. package/lib/text/web_vtt_generator.js +1 -7
  203. package/lib/util/buffer_utils.js +1 -3
  204. package/lib/util/ebml_parser.js +3 -3
  205. package/lib/util/error.js +10 -14
  206. package/lib/util/fairplay_utils.js +109 -0
  207. package/lib/util/functional.js +0 -42
  208. package/lib/util/iterables.js +0 -46
  209. package/lib/util/mime_utils.js +2 -0
  210. package/lib/util/mp4_box_parsers.js +1 -4
  211. package/lib/util/mp4_parser.js +5 -7
  212. package/lib/util/periods.js +10 -11
  213. package/lib/util/platform.js +48 -3
  214. package/lib/util/player_configuration.js +12 -6
  215. package/lib/util/pssh.js +24 -8
  216. package/lib/util/stream_utils.js +96 -25
  217. package/lib/util/string_utils.js +3 -5
  218. package/lib/util/uint8array_utils.js +3 -21
  219. package/lib/util/xml_utils.js +16 -8
  220. package/package.json +61 -36
  221. package/roadmap.md +27 -27
  222. package/shaka-player.uncompiled.js +1 -3
  223. package/test/abr/simple_abr_manager_unit.js +3 -8
  224. package/test/ads/ad_manager_unit.js +0 -6
  225. package/test/cast/cast_proxy_unit.js +0 -8
  226. package/test/cast/cast_receiver_integration.js +1 -18
  227. package/test/cast/cast_receiver_unit.js +1 -9
  228. package/test/cast/cast_sender_unit.js +0 -6
  229. package/test/cast/cast_utils_unit.js +1 -13
  230. package/test/cea/cea608_memory_unit.js +0 -5
  231. package/test/cea/cea708_service_unit.js +0 -7
  232. package/test/cea/cea708_window_unit.js +0 -5
  233. package/test/cea/cea_decoder_unit.js +0 -6
  234. package/test/cea/dtvcc_packet_builder_unit.js +0 -3
  235. package/test/cea/dtvcc_packet_unit.js +0 -5
  236. package/test/cea/mp4_cea_parser_unit.js +0 -4
  237. package/test/dash/dash_parser_content_protection_unit.js +45 -10
  238. package/test/dash/dash_parser_live_unit.js +2 -15
  239. package/test/dash/dash_parser_manifest_unit.js +2 -40
  240. package/test/dash/dash_parser_segment_base_unit.js +1 -8
  241. package/test/dash/dash_parser_segment_list_unit.js +1 -7
  242. package/test/dash/dash_parser_segment_template_unit.js +3 -13
  243. package/test/dash/mpd_utils_unit.js +3 -11
  244. package/test/demo/demo_unit.js +2 -6
  245. package/test/deprecate/enforcer_unit.js +0 -4
  246. package/test/deprecate/version_unit.js +0 -2
  247. package/test/hls/hls_live_unit.js +101 -234
  248. package/test/hls/hls_parser_unit.js +517 -447
  249. package/test/hls/manifest_text_parser_unit.js +0 -10
  250. package/test/media/adaptation_set_criteria_unit.js +3 -7
  251. package/test/media/adaptation_set_unit.js +0 -2
  252. package/test/media/buffering_observer_unit.js +1 -4
  253. package/test/media/closed_caption_parser_unit.js +0 -3
  254. package/test/media/drm_engine_integration.js +2 -15
  255. package/test/media/drm_engine_unit.js +90 -144
  256. package/test/media/manifest_parser_unit.js +0 -4
  257. package/test/media/media_source_engine_integration.js +26 -10
  258. package/test/media/media_source_engine_unit.js +8 -20
  259. package/test/media/mp4_segment_index_parser_unit.js +0 -4
  260. package/test/media/play_rate_controller_unit.js +0 -4
  261. package/test/media/playhead_unit.js +35 -207
  262. package/test/media/presentation_timeline_unit.js +4 -7
  263. package/test/media/quality_observer_unit.js +0 -4
  264. package/test/media/region_observer_unit.js +1 -6
  265. package/test/media/region_timeline_unit.js +0 -3
  266. package/test/media/segment_index_unit.js +15 -31
  267. package/test/media/segment_reference_unit.js +0 -3
  268. package/test/media/stall_detector_unit.js +0 -5
  269. package/test/media/streaming_engine_integration.js +13 -75
  270. package/test/media/streaming_engine_unit.js +14 -37
  271. package/test/media/time_ranges_utils_unit.js +0 -7
  272. package/test/media/transmuxer_integration.js +0 -6
  273. package/test/media/webm_segment_index_parser_unit.js +0 -4
  274. package/test/net/data_uri_plugin_unit.js +0 -7
  275. package/test/net/http_plugin_unit.js +0 -9
  276. package/test/net/networking_engine_unit.js +0 -11
  277. package/test/offline/download_progress_estimator_unit.js +0 -2
  278. package/test/offline/indexeddb_storage_unit.js +0 -6
  279. package/test/offline/manifest_convert_unit.js +34 -12
  280. package/test/offline/offline_integration.js +1 -10
  281. package/test/offline/offline_manifest_parser_unit.js +1 -6
  282. package/test/offline/offline_scheme_unit.js +0 -8
  283. package/test/offline/offline_uri_unit.js +0 -2
  284. package/test/offline/storage_compatibility_unit.js +1 -14
  285. package/test/offline/storage_integration.js +6 -31
  286. package/test/player_external.js +1 -15
  287. package/test/player_integration.js +38 -28
  288. package/test/player_load_graph_integration.js +1 -6
  289. package/test/player_src_equals_external.js +3 -9
  290. package/test/player_src_equals_integration.js +0 -7
  291. package/test/player_unit.js +78 -37
  292. package/test/routing/walker_unit.js +0 -8
  293. package/test/test/assets/large_file.mpd +1 -1
  294. package/test/test/boot.js +75 -22
  295. package/test/test/externs/jasmine.js +2 -2
  296. package/test/test/externs/karma.js +4 -0
  297. package/test/test/namespace.js +10 -0
  298. package/test/test/util/canned_idb.js +0 -8
  299. package/test/test/util/cea_utils.js +0 -6
  300. package/test/test/util/dash_parser_util.js +0 -13
  301. package/test/test/util/fake_ad.js +0 -3
  302. package/test/test/util/fake_ad_manager.js +0 -9
  303. package/test/test/util/fake_demo_main.js +0 -5
  304. package/test/test/util/fake_drm_engine.js +0 -6
  305. package/test/test/util/fake_media_source_engine.js +11 -11
  306. package/test/test/util/fake_networking_engine.js +0 -5
  307. package/test/test/util/fake_text_displayer.js +0 -5
  308. package/test/test/util/indexeddb_utils.js +1 -10
  309. package/test/test/util/jasmine_fetch.js +0 -1
  310. package/test/test/util/loader.js +0 -18
  311. package/test/test/util/manifest_generator.js +12 -15
  312. package/test/test/util/manifest_parser_util.js +4 -7
  313. package/test/test/util/offline_utils.js +1 -5
  314. package/test/test/util/simple_fakes.js +9 -26
  315. package/test/test/util/stream_generator.js +0 -14
  316. package/test/test/util/streaming_engine_util.js +1 -15
  317. package/test/test/util/test_scheme.js +25 -20
  318. package/test/test/util/ttml_utils.js +0 -2
  319. package/test/test/util/ui_utils.js +0 -9
  320. package/test/test/util/util.js +9 -23
  321. package/test/test/util/waiter.js +84 -43
  322. package/test/text/cue_integration.js +2 -6
  323. package/test/text/lrc_text_parser_unit.js +6 -11
  324. package/test/text/mp4_ttml_parser_unit.js +6 -10
  325. package/test/text/mp4_vtt_parser_unit.js +7 -12
  326. package/test/text/sbv_text_parser_unit.js +5 -10
  327. package/test/text/simple_text_displayer_unit.js +1 -8
  328. package/test/text/srt_text_parser_unit.js +5 -10
  329. package/test/text/ssa_text_parser_unit.js +17 -34
  330. package/test/text/text_engine_unit.js +47 -12
  331. package/test/text/text_track_integration.js +0 -2
  332. package/test/text/ttml_text_parser_unit.js +79 -88
  333. package/test/text/ui_text_displayer_unit.js +44 -41
  334. package/test/text/vtt_text_parser_unit.js +55 -66
  335. package/test/text/web_vtt_generator_unit.js +0 -3
  336. package/test/ui/ad_ui_unit.js +0 -11
  337. package/test/ui/localization_unit.js +0 -3
  338. package/test/ui/text_displayer_layout_unit.js +1 -12
  339. package/test/ui/ui_customization_unit.js +0 -6
  340. package/test/ui/ui_integration.js +0 -32
  341. package/test/ui/ui_unit.js +28 -17
  342. package/test/util/abortable_operation_unit.js +4 -9
  343. package/test/util/array_utils_unit.js +0 -2
  344. package/test/util/buffer_utils_unit.js +0 -2
  345. package/test/util/cmcd_manager_unit.js +3 -3
  346. package/test/util/data_view_reader_unit.js +0 -4
  347. package/test/util/ebml_parser_unit.js +0 -4
  348. package/test/util/event_manager_unit.js +0 -3
  349. package/test/util/fake_event_target_unit.js +0 -5
  350. package/test/util/iterables_unit.js +0 -64
  351. package/test/util/language_utils_unit.js +0 -3
  352. package/test/util/manifest_parser_utils_unit.js +0 -2
  353. package/test/util/mp4_box_parsers_unit.js +0 -5
  354. package/test/util/mp4_parser_unit.js +0 -4
  355. package/test/util/multi_map_unit.js +0 -3
  356. package/test/util/object_utils_unit.js +0 -2
  357. package/test/util/periods_unit.js +14 -7
  358. package/test/util/pssh_unit.js +0 -5
  359. package/test/util/state_history_unit.js +0 -2
  360. package/test/util/stream_utils_unit.js +26 -15
  361. package/test/util/string_utils_unit.js +0 -6
  362. package/test/util/text_parser_unit.js +0 -2
  363. package/test/util/xml_utils_unit.js +0 -4
  364. package/ui/controls.js +65 -40
  365. package/ui/fullscreen_button.js +26 -6
  366. package/ui/less/ad_controls.less +6 -6
  367. package/ui/less/buttons.less +6 -6
  368. package/ui/less/containers.less +10 -12
  369. package/ui/less/overflow_menu.less +4 -4
  370. package/ui/less/range_elements.less +7 -2
  371. package/ui/less/tooltip.less +4 -4
  372. package/ui/locales/en.json +1 -0
  373. package/ui/locales/sjn-translations.yaml +257 -0
  374. package/ui/locales/sjn.json +42 -0
  375. package/ui/locales/source.json +5 -0
  376. package/ui/resolution_selection.js +31 -33
  377. package/ui/seek_bar.js +2 -1
  378. package/ui/ui.js +0 -17
  379. package/.github/workflows/build_and_test.yaml +0 -73
  380. package/.github/workflows/release.yaml +0 -53
  381. package/docs/tutorials/upgrade-v2-5.md +0 -441
  382. package/docs/tutorials/upgrade-v3.md +0 -38
  383. package/externs/svgelement.js +0 -18
  384. package/externs/webcrypto.js +0 -18
  385. package/lib/polyfill/mathround.js +0 -49
  386. package/lib/polyfill/patchedmediakeys_apple.js +0 -744
  387. package/lib/polyfill/patchedmediakeys_ms.js +0 -698
  388. package/lib/util/mutex.js +0 -52
  389. package/test/util/functional_unit.js +0 -82
@@ -4,22 +4,8 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- goog.require('goog.asserts');
8
- goog.require('shaka.hls.HlsParser');
9
- goog.require('shaka.log');
10
- goog.require('shaka.net.NetworkingEngine');
11
- goog.require('shaka.test.FakeNetworkingEngine');
12
- goog.require('shaka.test.ManifestGenerator');
13
- goog.require('shaka.test.ManifestParser');
14
- goog.require('shaka.test.Util');
15
- goog.require('shaka.util.Error');
16
- goog.require('shaka.util.ManifestParserUtils');
17
- goog.require('shaka.util.PlayerConfiguration');
18
- goog.require('shaka.util.Uint8ArrayUtils');
19
-
20
7
  describe('HlsParser', () => {
21
8
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
22
- const ManifestParser = shaka.test.ManifestParser;
23
9
  const TextStreamKind = shaka.util.ManifestParserUtils.TextStreamKind;
24
10
  const Util = shaka.test.Util;
25
11
  const originalAlwaysWarn = shaka.log.alwaysWarn;
@@ -169,6 +155,7 @@ describe('HlsParser', () => {
169
155
  ].join('');
170
156
 
171
157
  const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
158
+ manifest.sequenceMode = true;
172
159
  manifest.anyTimeline();
173
160
  manifest.addPartialVariant((variant) => {
174
161
  variant.language = 'en';
@@ -243,6 +230,7 @@ describe('HlsParser', () => {
243
230
  ].join('');
244
231
 
245
232
  const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
233
+ manifest.sequenceMode = true;
246
234
  manifest.anyTimeline();
247
235
  manifest.addPartialVariant((variant) => {
248
236
  variant.language = 'en';
@@ -313,6 +301,7 @@ describe('HlsParser', () => {
313
301
  stream.size(960, 540);
314
302
  });
315
303
  });
304
+ manifest.sequenceMode = true;
316
305
  });
317
306
 
318
307
  fakeNetEngine
@@ -349,6 +338,7 @@ describe('HlsParser', () => {
349
338
  stream.mime('video/mp4', 'avc1.4d001e');
350
339
  });
351
340
  });
341
+ manifest.sequenceMode = true;
352
342
  });
353
343
 
354
344
  await testHlsParser(master, media, manifest);
@@ -378,6 +368,7 @@ describe('HlsParser', () => {
378
368
  stream.mime('video/mp4', 'avc1');
379
369
  });
380
370
  });
371
+ manifest.sequenceMode = true;
381
372
  });
382
373
 
383
374
  await testHlsParser(master, media, manifest);
@@ -406,6 +397,7 @@ describe('HlsParser', () => {
406
397
  stream.mime('video/mp4', 'avc1');
407
398
  });
408
399
  });
400
+ manifest.sequenceMode = true;
409
401
  });
410
402
 
411
403
  await testHlsParser(master, media, manifest);
@@ -437,6 +429,7 @@ describe('HlsParser', () => {
437
429
  stream.mime('video/mp4', 'avc1');
438
430
  });
439
431
  });
432
+ manifest.sequenceMode = true;
440
433
  });
441
434
 
442
435
  await testHlsParser(master, media, manifest);
@@ -465,6 +458,7 @@ describe('HlsParser', () => {
465
458
  stream.mime('audio/mp4', 'mp4a');
466
459
  });
467
460
  });
461
+ manifest.sequenceMode = true;
468
462
  });
469
463
 
470
464
  await testHlsParser(master, media, manifest);
@@ -499,6 +493,7 @@ describe('HlsParser', () => {
499
493
  stream.mime('audio/mp4', 'mp4a');
500
494
  });
501
495
  });
496
+ manifest.sequenceMode = true;
502
497
  });
503
498
 
504
499
  await testHlsParser(master, media, manifest);
@@ -533,6 +528,35 @@ describe('HlsParser', () => {
533
528
  stream.mime('audio/mp4', '');
534
529
  });
535
530
  });
531
+ manifest.sequenceMode = true;
532
+ });
533
+
534
+ await testHlsParser(master, media, manifest);
535
+ });
536
+
537
+ it('accepts containerless streams', async () => {
538
+ const master = [
539
+ '#EXTM3U\n',
540
+ '#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=41457,CODECS="mp4a.40.2"\n',
541
+ 'audio\n',
542
+ ].join('');
543
+
544
+ const media = [
545
+ '#EXTM3U\n',
546
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
547
+ '#EXTINF:5,\n',
548
+ '#EXT-X-BYTERANGE:121090@616\n',
549
+ 'main.aac',
550
+ ].join('');
551
+
552
+ const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
553
+ manifest.anyTimeline();
554
+ manifest.addPartialVariant((variant) => {
555
+ variant.addPartialStream(ContentType.AUDIO, (stream) => {
556
+ stream.mime('audio/aac', '');
557
+ });
558
+ });
559
+ manifest.sequenceMode = true;
536
560
  });
537
561
 
538
562
  await testHlsParser(master, media, manifest);
@@ -571,6 +595,7 @@ describe('HlsParser', () => {
571
595
  stream.mime('audio/mp4', 'mp4a');
572
596
  });
573
597
  });
598
+ manifest.sequenceMode = true;
574
599
  });
575
600
 
576
601
  await testHlsParser(master, media, manifest);
@@ -607,6 +632,7 @@ describe('HlsParser', () => {
607
632
  stream.mime('audio/mp4', 'mp4a');
608
633
  });
609
634
  });
635
+ manifest.sequenceMode = true;
610
636
  });
611
637
 
612
638
  await testHlsParser(master, media, manifest);
@@ -637,66 +663,12 @@ describe('HlsParser', () => {
637
663
  stream.mime('audio/mp4', 'mp4a');
638
664
  });
639
665
  });
666
+ manifest.sequenceMode = true;
640
667
  });
641
668
 
642
669
  await testHlsParser(master, media, manifest);
643
670
  });
644
671
 
645
- it('sets seek range correctly for non-zero start', async () => {
646
- const master = [
647
- '#EXTM3U\n',
648
- '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
649
- 'RESOLUTION=960x540,FRAME-RATE=60\n',
650
- 'video',
651
- ].join('');
652
-
653
- const media = [
654
- '#EXTM3U\n',
655
- '#EXT-X-PLAYLIST-TYPE:VOD\n',
656
- '#EXT-X-MEDIA-SEQUENCE:131\n',
657
- '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
658
- '#EXTINF:5,\n',
659
- '#EXT-X-BYTERANGE:121090@616\n',
660
- 'main.mp4',
661
- ].join('');
662
-
663
- segmentData = new Uint8Array([
664
- 0x00, 0x00, 0x00, 0x24, // size (36)
665
- 0x6D, 0x6F, 0x6F, 0x66, // type (moof)
666
- 0x00, 0x00, 0x00, 0x1C, // traf size (28)
667
- 0x74, 0x72, 0x61, 0x66, // type (traf)
668
-
669
- 0x00, 0x00, 0x00, 0x14, // tfdt size (20)
670
- 0x74, 0x66, 0x64, 0x74, // type (tfdt)
671
- 0x01, 0x00, 0x00, 0x00, // version and flags
672
-
673
- 0x00, 0x00, 0x00, 0x00, // baseMediaDecodeTime first 4 bytes (0)
674
- 0x00, 0x0A, 0x00, 0x00, // baseMediaDecodeTime last 4 bytes (655360)
675
- ]);
676
-
677
- fakeNetEngine
678
- .setResponseText('test:/master', master)
679
- .setResponseText('test:/video', media)
680
- .setResponseValue('test:/init.mp4', initSegmentData)
681
- .setResponseValue('test:/main.mp4', segmentData);
682
-
683
- const manifest = await parser.start('test:/master', playerInterface);
684
- const presentationTimeline = manifest.presentationTimeline;
685
- const stream = manifest.variants[0].video;
686
- await stream.createSegmentIndex();
687
- goog.asserts.assert(stream.segmentIndex != null, 'Null segmentIndex!');
688
-
689
- const ref = Array.from(stream.segmentIndex)[0];
690
- expect(ref).not.toBe(null);
691
- if (ref) {
692
- expect(ref.startTime).toBe(0);
693
- // baseMediaDecodeTime (655360) / timescale (1000)
694
- expect(ref.timestampOffset).toBe(-655.36);
695
- }
696
- expect(presentationTimeline.getSeekRangeStart()).toBe(0);
697
- expect(presentationTimeline.getSeekRangeEnd()).toBe(5);
698
- });
699
-
700
672
  it('parses multiplexed variant', async () => {
701
673
  const master = [
702
674
  '#EXTM3U\n',
@@ -721,6 +693,7 @@ describe('HlsParser', () => {
721
693
  stream.mime('video/mp4', 'avc1,mp4a');
722
694
  });
723
695
  });
696
+ manifest.sequenceMode = true;
724
697
  });
725
698
 
726
699
  await testHlsParser(master, media, manifest);
@@ -750,6 +723,7 @@ describe('HlsParser', () => {
750
723
  stream.mime('video/mp4', /** @type {?} */ (jasmine.any(String)));
751
724
  });
752
725
  });
726
+ manifest.sequenceMode = true;
753
727
  });
754
728
 
755
729
  await testHlsParser(master, media, manifest);
@@ -784,6 +758,7 @@ describe('HlsParser', () => {
784
758
  stream.mime('audio/mp4', /** @type {?} */ (jasmine.any(String)));
785
759
  });
786
760
  });
761
+ manifest.sequenceMode = true;
787
762
  });
788
763
 
789
764
  await testHlsParser(master, media, manifest);
@@ -814,6 +789,7 @@ describe('HlsParser', () => {
814
789
  stream.mime('video/mp4', /** @type {?} */ (jasmine.any(String)));
815
790
  });
816
791
  });
792
+ manifest.sequenceMode = true;
817
793
  });
818
794
 
819
795
  await testHlsParser(master, media, manifest);
@@ -844,6 +820,7 @@ describe('HlsParser', () => {
844
820
  stream.mime('audio/mp4', /** @type {?} */ (jasmine.any(String)));
845
821
  });
846
822
  });
823
+ manifest.sequenceMode = true;
847
824
  });
848
825
 
849
826
  await testHlsParser(master, media, manifest);
@@ -895,6 +872,7 @@ describe('HlsParser', () => {
895
872
  stream.language = 'fr';
896
873
  });
897
874
  });
875
+ manifest.sequenceMode = true;
898
876
  });
899
877
 
900
878
  await testHlsParser(master, media, manifest);
@@ -937,6 +915,7 @@ describe('HlsParser', () => {
937
915
  stream.language = 'fr';
938
916
  });
939
917
  });
918
+ manifest.sequenceMode = true;
940
919
  });
941
920
 
942
921
  await testHlsParser(master, media, manifest);
@@ -984,63 +963,12 @@ describe('HlsParser', () => {
984
963
  ];
985
964
  });
986
965
  });
966
+ manifest.sequenceMode = true;
987
967
  });
988
968
 
989
969
  await testHlsParser(master, media, manifest);
990
970
  });
991
971
 
992
- it('fetch the start time for one audio/video stream and reuse for the others',
993
- async () => {
994
- const SEGMENT = shaka.net.NetworkingEngine.RequestType.SEGMENT;
995
- const master = [
996
- '#EXTM3U\n',
997
- '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
998
- 'CHANNELS="2",URI="audio"\n',
999
- '#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="sub1",LANGUAGE="eng",',
1000
- 'URI="text"\n',
1001
- '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
1002
- 'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1"\n',
1003
- 'video\n',
1004
- ].join('');
1005
-
1006
- const media = [
1007
- '#EXTM3U\n',
1008
- '#EXT-X-PLAYLIST-TYPE:VOD\n',
1009
- '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
1010
- '#EXTINF:5,\n',
1011
- '#EXT-X-BYTERANGE:121090@616\n',
1012
- 'main.mp4',
1013
- ].join('');
1014
-
1015
- const textMedia = [
1016
- '#EXTM3U\n',
1017
- '#EXT-X-PLAYLIST-TYPE:VOD\n',
1018
- '#EXTINF:5,\n',
1019
- '#EXT-X-BYTERANGE:121090@616\n',
1020
- 'main.vtt',
1021
- ].join('');
1022
-
1023
- fakeNetEngine
1024
- .setResponseText('test:/master', master)
1025
- .setResponseText('test:/audio', media)
1026
- .setResponseText('test:/video', media)
1027
- .setResponseText('test:/text', textMedia)
1028
- .setResponseText('test:/main.vtt', vttText)
1029
- .setResponseValue('test:/init.mp4', initSegmentData)
1030
- .setResponseValue('test:/main.mp4', segmentData);
1031
-
1032
- await parser.start('test:/master', playerInterface);
1033
- // The start time of audio should be fetched first, and then video and
1034
- // text streams should reuse the start time from audio.
1035
- // Thus, there should be 2 segment requests, for fetching audio init
1036
- // and main segments, and not for video and text segments.
1037
- expect(fakeNetEngine.request.calls.allArgs().filter((args) => {
1038
- return args[0] == SEGMENT;
1039
- }).length).toBe(2);
1040
- fakeNetEngine.expectRequest('test:/init.mp4', SEGMENT);
1041
- fakeNetEngine.expectRequest('test:/main.mp4', SEGMENT);
1042
- });
1043
-
1044
972
  it('gets mime type from header request', async () => {
1045
973
  const master = [
1046
974
  '#EXTM3U\n',
@@ -1065,6 +993,7 @@ describe('HlsParser', () => {
1065
993
  stream.mime('video/mp4', 'avc1');
1066
994
  });
1067
995
  });
996
+ manifest.sequenceMode = true;
1068
997
  });
1069
998
 
1070
999
  // The extra parameters should be stripped by the parser.
@@ -1122,6 +1051,7 @@ describe('HlsParser', () => {
1122
1051
  stream.kind = TextStreamKind.SUBTITLE;
1123
1052
  stream.mime('text/vtt', '');
1124
1053
  });
1054
+ manifest.sequenceMode = true;
1125
1055
  });
1126
1056
 
1127
1057
  fakeNetEngine
@@ -1191,6 +1121,7 @@ describe('HlsParser', () => {
1191
1121
  stream.kind = TextStreamKind.SUBTITLE;
1192
1122
  stream.mime('text/vtt', '');
1193
1123
  });
1124
+ manifest.sequenceMode = true;
1194
1125
  });
1195
1126
 
1196
1127
  fakeNetEngine
@@ -1207,6 +1138,69 @@ describe('HlsParser', () => {
1207
1138
  expect(actual).toEqual(manifest);
1208
1139
  });
1209
1140
 
1141
+ it('gets mime type of SUBTITLES from header request', async () => {
1142
+ const master = [
1143
+ '#EXTM3U\n',
1144
+ '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
1145
+ 'URI="audio"\n',
1146
+ '#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="sub1",LANGUAGE="eng",',
1147
+ 'URI="text"\n',
1148
+ '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
1149
+ 'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1",SUBTITLES="sub1"\n',
1150
+ 'video\n',
1151
+ ].join('');
1152
+
1153
+ const media = [
1154
+ '#EXTM3U\n',
1155
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
1156
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
1157
+ '#EXTINF:5,\n',
1158
+ '#EXT-X-BYTERANGE:121090@616\n',
1159
+ 'main.mp4',
1160
+ ].join('');
1161
+
1162
+ const textMedia = [
1163
+ '#EXTM3U\n',
1164
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
1165
+ '#EXTINF:5,\n',
1166
+ '#EXT-X-BYTERANGE:121090@616\n',
1167
+ 'main.subs',
1168
+ ].join('');
1169
+
1170
+ const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
1171
+ manifest.anyTimeline();
1172
+ manifest.addPartialVariant((variant) => {
1173
+ variant.addPartialStream(ContentType.VIDEO, (stream) => {
1174
+ stream.mime('video/mp4', 'avc1');
1175
+ });
1176
+ variant.addPartialStream(ContentType.AUDIO, (stream) => {
1177
+ stream.mime('audio/mp4', 'mp4a');
1178
+ });
1179
+ });
1180
+ manifest.addPartialTextStream((stream) => {
1181
+ stream.language = 'en';
1182
+ stream.kind = TextStreamKind.SUBTITLE;
1183
+ stream.mime('application/mp4', '');
1184
+ });
1185
+ manifest.sequenceMode = true;
1186
+ });
1187
+
1188
+ fakeNetEngine
1189
+ .setResponseText('test:/master', master)
1190
+ .setResponseText('test:/audio', media)
1191
+ .setResponseText('test:/video', media)
1192
+ .setResponseText('test:/text', textMedia)
1193
+ .setResponseText('test:/main.subs', vttText)
1194
+ .setHeaders('test:/main.subs', {
1195
+ 'content-type': 'application/mp4; foo=bar',
1196
+ })
1197
+ .setResponseValue('test:/init.mp4', initSegmentData)
1198
+ .setResponseValue('test:/main.mp4', segmentData);
1199
+
1200
+ const actual = await parser.start('test:/master', playerInterface);
1201
+ expect(actual).toEqual(manifest);
1202
+ });
1203
+
1210
1204
  it('parses manifest with FORCED SUBTITLES', async () => {
1211
1205
  const master = [
1212
1206
  '#EXTM3U\n',
@@ -1252,6 +1246,7 @@ describe('HlsParser', () => {
1252
1246
  stream.kind = TextStreamKind.SUBTITLE;
1253
1247
  stream.mime('text/vtt', '');
1254
1248
  });
1249
+ manifest.sequenceMode = true;
1255
1250
  });
1256
1251
 
1257
1252
  fakeNetEngine
@@ -1313,6 +1308,7 @@ describe('HlsParser', () => {
1313
1308
  stream.kind = TextStreamKind.SUBTITLE;
1314
1309
  stream.mime('text/vtt', '');
1315
1310
  });
1311
+ manifest.sequenceMode = true;
1316
1312
  });
1317
1313
 
1318
1314
  fakeNetEngine
@@ -1491,6 +1487,105 @@ describe('HlsParser', () => {
1491
1487
  }
1492
1488
  });
1493
1489
 
1490
+ it('parse EXT-X-GAP', async () => {
1491
+ const master = [
1492
+ '#EXTM3U\n',
1493
+ '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
1494
+ 'CHANNELS="2",URI="audio"\n',
1495
+ '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
1496
+ 'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1"\n',
1497
+ 'video\n',
1498
+ ].join('');
1499
+
1500
+ const video = [
1501
+ '#EXTM3U\n',
1502
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
1503
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
1504
+ '#EXTINF:5,\n',
1505
+ 'main.mp4\n',
1506
+ '#EXTINF:5,\n',
1507
+ '#EXT-X-GAP\n',
1508
+ 'main.mp4\n',
1509
+ '#EXTINF:5,\n',
1510
+ 'main.mp4\n',
1511
+ ].join('');
1512
+
1513
+ const audio = [
1514
+ '#EXTM3U\n',
1515
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
1516
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
1517
+ '#EXTINF:5,\n',
1518
+ 'main.mp4\n',
1519
+ '#EXTINF:5,\n',
1520
+ '#EXT-X-GAP\n',
1521
+ 'main.mp4\n',
1522
+ '#EXTINF:5,\n',
1523
+ 'main.mp4\n',
1524
+ ].join('');
1525
+
1526
+ fakeNetEngine
1527
+ .setResponseText('test:/master', master)
1528
+ .setResponseText('test:/audio', audio)
1529
+ .setResponseText('test:/video', video)
1530
+ .setResponseValue('test:/init.mp4', initSegmentData)
1531
+ .setResponseValue('test:/main.mp4', segmentData);
1532
+
1533
+ const actual = await parser.start('test:/master', playerInterface);
1534
+
1535
+ expect(actual.variants.length).toBe(1);
1536
+
1537
+ const variant = actual.variants[0];
1538
+ expect(variant.video).toBeTruthy();
1539
+ expect(variant.audio).toBeTruthy();
1540
+
1541
+ const available = shaka.media.SegmentReference.Status.AVAILABLE;
1542
+ const missing = shaka.media.SegmentReference.Status.MISSING;
1543
+
1544
+ await variant.video.createSegmentIndex();
1545
+ goog.asserts.assert(variant.video.segmentIndex != null,
1546
+ 'Null segmentIndex!');
1547
+
1548
+ const firstVideoReference = variant.video.segmentIndex.get(0);
1549
+ const secondVideoReference = variant.video.segmentIndex.get(1);
1550
+ const thirdVideoReference = variant.video.segmentIndex.get(2);
1551
+
1552
+ expect(firstVideoReference).not.toBe(null);
1553
+ expect(secondVideoReference).not.toBe(null);
1554
+ expect(thirdVideoReference).not.toBe(null);
1555
+
1556
+ if (firstVideoReference) {
1557
+ expect(firstVideoReference.getStatus()).toBe(available);
1558
+ }
1559
+ if (secondVideoReference) {
1560
+ expect(secondVideoReference.getStatus()).toBe(missing);
1561
+ }
1562
+ if (thirdVideoReference) {
1563
+ expect(thirdVideoReference.getStatus()).toBe(available);
1564
+ }
1565
+
1566
+ await variant.audio.createSegmentIndex();
1567
+ goog.asserts.assert(variant.audio.segmentIndex != null,
1568
+ 'Null segmentIndex!');
1569
+
1570
+ const firstAudioReference = variant.audio.segmentIndex.get(0);
1571
+ const secondAudioReference = variant.audio.segmentIndex.get(1);
1572
+ const thirdAudioReference = variant.audio.segmentIndex.get(2);
1573
+
1574
+ expect(firstAudioReference).not.toBe(null);
1575
+ expect(secondAudioReference).not.toBe(null);
1576
+ expect(thirdAudioReference).not.toBe(null);
1577
+
1578
+ if (firstAudioReference) {
1579
+ expect(firstAudioReference.getStatus()).toBe(available);
1580
+ }
1581
+ if (secondAudioReference) {
1582
+ expect(secondAudioReference.getStatus()).toBe(missing);
1583
+ }
1584
+ if (thirdAudioReference) {
1585
+ expect(thirdAudioReference.getStatus()).toBe(available);
1586
+ }
1587
+ });
1588
+
1494
1589
  it('Disable audio does not create audio streams', async () => {
1495
1590
  const master = [
1496
1591
  '#EXTM3U\n',
@@ -1817,6 +1912,7 @@ describe('HlsParser', () => {
1817
1912
  stream.language = 'en';
1818
1913
  stream.mime('application/mp4', 'stpp.ttml.im1t');
1819
1914
  });
1915
+ manifest.sequenceMode = true;
1820
1916
  });
1821
1917
 
1822
1918
  fakeNetEngine
@@ -1866,6 +1962,7 @@ describe('HlsParser', () => {
1866
1962
  manifest.addPartialTextStream((stream) => {
1867
1963
  stream.mime('text/vtt', 'vtt');
1868
1964
  });
1965
+ manifest.sequenceMode = true;
1869
1966
  });
1870
1967
 
1871
1968
  fakeNetEngine
@@ -1908,6 +2005,7 @@ describe('HlsParser', () => {
1908
2005
  manifest.addPartialTextStream((stream) => {
1909
2006
  stream.kind = TextStreamKind.SUBTITLE;
1910
2007
  });
2008
+ manifest.sequenceMode = true;
1911
2009
  });
1912
2010
 
1913
2011
  fakeNetEngine
@@ -1922,6 +2020,173 @@ describe('HlsParser', () => {
1922
2020
  expect(actual).toEqual(manifest);
1923
2021
  });
1924
2022
 
2023
+ describe('produces syncTime', () => {
2024
+ /**
2025
+ * @param {number} startTime
2026
+ * @param {number} endTime
2027
+ * @param {number} syncTime
2028
+ * @return {!shaka.media.SegmentReference}
2029
+ */
2030
+ function makeReference(startTime, endTime, syncTime) {
2031
+ const initUris = () => ['test:/init.mp4'];
2032
+ const init = new shaka.media.InitSegmentReference(initUris, 0, 615);
2033
+ const uris = () => ['test:/main.mp4'];
2034
+ return new shaka.media.SegmentReference(
2035
+ startTime, endTime, uris, 0, null, init, 0, 0, Infinity,
2036
+ [], undefined, undefined, syncTime);
2037
+ }
2038
+
2039
+ /**
2040
+ * @param {string} media
2041
+ * @param {!Array.<number>} startTimes
2042
+ * @param {(function(!shaka.media.SegmentReference))=} modifyFn
2043
+ */
2044
+ async function test(media, startTimes, modifyFn) {
2045
+ const master = [
2046
+ '#EXTM3U\n',
2047
+ '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,vtt",',
2048
+ 'RESOLUTION=960x540,FRAME-RATE=60\n',
2049
+ 'video\n',
2050
+ ].join('');
2051
+
2052
+ const segments = [];
2053
+ for (let i = 0; i < startTimes.length - 1; i++) {
2054
+ const startTime = startTimes[i];
2055
+ const endTime = startTimes[i + 1];
2056
+ const reference = makeReference(startTime, endTime, startTime);
2057
+ if (modifyFn) {
2058
+ modifyFn(reference);
2059
+ }
2060
+ segments.push(reference);
2061
+ }
2062
+
2063
+ const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
2064
+ manifest.anyTimeline();
2065
+ manifest.addPartialVariant((variant) => {
2066
+ variant.addPartialStream(ContentType.VIDEO, (stream) => {
2067
+ stream.segmentIndex = new shaka.media.SegmentIndex(segments);
2068
+ });
2069
+ });
2070
+ manifest.sequenceMode = true;
2071
+ });
2072
+
2073
+ fakeNetEngine
2074
+ .setResponseText('test:/master', master)
2075
+ .setResponseText('test:/video', media)
2076
+ .setResponseValue('test:/init.mp4', initSegmentData)
2077
+ .setResponseValue('test:/main.mp4', segmentData);
2078
+
2079
+ const actual = await parser.start('test:/master', playerInterface);
2080
+ expect(actual).toEqual(manifest);
2081
+ }
2082
+
2083
+ it('from EXT-X-PROGRAM-DATE-TIME', async () => {
2084
+ await test([
2085
+ '#EXTM3U\n',
2086
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
2087
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
2088
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:05.00Z\n',
2089
+ '#EXTINF:5,\n',
2090
+ 'main.mp4\n',
2091
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:10.00Z\n',
2092
+ '#EXTINF:5,\n',
2093
+ 'main.mp4\n',
2094
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:15.00Z\n',
2095
+ '#EXTINF:5,\n',
2096
+ 'main.mp4\n',
2097
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:20.00Z\n',
2098
+ '#EXTINF:5,\n',
2099
+ 'main.mp4\n',
2100
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:25.00Z\n',
2101
+ '#EXTINF:5,\n',
2102
+ 'main.mp4',
2103
+ ].join(''), [0, 5, 10, 15, 20, 25]);
2104
+ });
2105
+
2106
+ it('when some EXT-X-PROGRAM-DATE-TIME values are missing', async () => {
2107
+ await test([
2108
+ '#EXTM3U\n',
2109
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
2110
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
2111
+ '#EXTINF:2,\n',
2112
+ 'main.mp4\n',
2113
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:10.00Z\n',
2114
+ '#EXTINF:5,\n',
2115
+ 'main.mp4\n',
2116
+ '#EXTINF:5,\n',
2117
+ 'main.mp4\n',
2118
+ '#EXTINF:5,\n',
2119
+ 'main.mp4\n',
2120
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:25.00Z\n',
2121
+ '#EXTINF:2,\n',
2122
+ 'main.mp4\n',
2123
+ '#EXTINF:4,\n',
2124
+ 'main.mp4',
2125
+ ].join(''), [0, 2, 7, 12, 17, 19, 23]);
2126
+ });
2127
+
2128
+ it('except when ignoreManifestProgramDateTime is set', async () => {
2129
+ const config = shaka.util.PlayerConfiguration.createDefault().manifest;
2130
+ config.hls.ignoreManifestProgramDateTime = true;
2131
+ parser.configure(config);
2132
+ await test([
2133
+ '#EXTM3U\n',
2134
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
2135
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
2136
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:05.00Z\n',
2137
+ '#EXTINF:5,\n',
2138
+ 'main.mp4\n',
2139
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:10.00Z\n',
2140
+ '#EXTINF:5,\n',
2141
+ 'main.mp4\n',
2142
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:15.00Z\n',
2143
+ '#EXTINF:5,\n',
2144
+ 'main.mp4\n',
2145
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:20.00Z\n',
2146
+ '#EXTINF:5,\n',
2147
+ 'main.mp4\n',
2148
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:25.00Z\n',
2149
+ '#EXTINF:5,\n',
2150
+ 'main.mp4',
2151
+ ].join(''), [0, 5, 10, 15, 20, 25], (reference) => {
2152
+ reference.syncTime = null;
2153
+ });
2154
+ });
2155
+
2156
+ it('when there are partial segments', async () => {
2157
+ playerInterface.isLowLatencyMode = () => true;
2158
+ await test([
2159
+ '#EXTM3U\n',
2160
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
2161
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
2162
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:05.00Z\n',
2163
+ '#EXTINF:5,\n',
2164
+ 'main.mp4\n',
2165
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:10.00Z\n',
2166
+ '#EXTINF:5,\n',
2167
+ 'main.mp4\n',
2168
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:15.00Z\n',
2169
+ '#EXT-X-PART:DURATION=2.5,URI="main.mp4"\n',
2170
+ '#EXT-X-PART:DURATION=2.5,URI="main.mp4"\n',
2171
+ '#EXTINF:5,\n',
2172
+ 'main.mp4\n',
2173
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:20.00Z\n',
2174
+ '#EXTINF:5,\n',
2175
+ 'main.mp4\n',
2176
+ '#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:25.00Z\n',
2177
+ '#EXTINF:5,\n',
2178
+ 'main.mp4',
2179
+ ].join(''), [0, 5, 10, 15, 20, 25], (reference) => {
2180
+ if (reference.startTime == 10) {
2181
+ reference.partialReferences = [
2182
+ makeReference(10, 12.5, 10),
2183
+ makeReference(12.5, 15, 12.5),
2184
+ ];
2185
+ }
2186
+ });
2187
+ });
2188
+ });
2189
+
1925
2190
  it('drops failed text streams when configured to', async () => {
1926
2191
  const master = [
1927
2192
  '#EXTM3U\n',
@@ -1945,6 +2210,7 @@ describe('HlsParser', () => {
1945
2210
  manifest.addPartialVariant((variant) => {
1946
2211
  variant.addPartialStream(ContentType.VIDEO);
1947
2212
  });
2213
+ manifest.sequenceMode = true;
1948
2214
  });
1949
2215
 
1950
2216
  fakeNetEngine
@@ -1982,6 +2248,7 @@ describe('HlsParser', () => {
1982
2248
  manifest.addPartialVariant((variant) => {
1983
2249
  variant.addPartialStream(ContentType.VIDEO);
1984
2250
  });
2251
+ manifest.sequenceMode = true;
1985
2252
  });
1986
2253
 
1987
2254
  fakeNetEngine
@@ -2024,6 +2291,7 @@ describe('HlsParser', () => {
2024
2291
  });
2025
2292
  variant.addPartialStream(ContentType.AUDIO);
2026
2293
  });
2294
+ manifest.sequenceMode = true;
2027
2295
  });
2028
2296
 
2029
2297
  await testHlsParser(master, media, manifest);
@@ -2108,6 +2376,7 @@ describe('HlsParser', () => {
2108
2376
  stream.mime('audio/mp4', 'mp4a');
2109
2377
  });
2110
2378
  });
2379
+ manifest.sequenceMode = true;
2111
2380
  });
2112
2381
 
2113
2382
  await testHlsParser(master, media, manifest);
@@ -2203,6 +2472,7 @@ describe('HlsParser', () => {
2203
2472
  stream.language = 'en';
2204
2473
  });
2205
2474
  });
2475
+ manifest.sequenceMode = true;
2206
2476
  });
2207
2477
 
2208
2478
  fakeNetEngine
@@ -2261,6 +2531,7 @@ describe('HlsParser', () => {
2261
2531
  });
2262
2532
  });
2263
2533
  });
2534
+ manifest.sequenceMode = true;
2264
2535
  });
2265
2536
 
2266
2537
  await testHlsParser(master, media, manifest);
@@ -2300,6 +2571,44 @@ describe('HlsParser', () => {
2300
2571
  });
2301
2572
  });
2302
2573
  });
2574
+ manifest.sequenceMode = true;
2575
+ });
2576
+
2577
+ await testHlsParser(master, media, manifest);
2578
+ });
2579
+
2580
+ it('constructs DrmInfo for FairPlay', async () => {
2581
+ const master = [
2582
+ '#EXTM3U\n',
2583
+ '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
2584
+ 'RESOLUTION=960x540,FRAME-RATE=60\n',
2585
+ 'video\n',
2586
+ ].join('');
2587
+
2588
+ const media = [
2589
+ '#EXTM3U\n',
2590
+ '#EXT-X-TARGETDURATION:6\n',
2591
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
2592
+ '#EXT-X-KEY:METHOD=SAMPLE-AES-CTR,',
2593
+ 'KEYFORMAT="com.apple.streamingkeydelivery",',
2594
+ 'URI="skd://f93d4e700d7ddde90529a27735d9e7cb",\n',
2595
+ '#EXT-X-MAP:URI="init.mp4"\n',
2596
+ '#EXTINF:5,\n',
2597
+ '#EXT-X-BYTERANGE:121090@616\n',
2598
+ 'main.mp4',
2599
+ ].join('');
2600
+
2601
+ const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
2602
+ manifest.anyTimeline();
2603
+ manifest.addPartialVariant((variant) => {
2604
+ variant.addPartialStream(ContentType.VIDEO, (stream) => {
2605
+ stream.encrypted = true;
2606
+ stream.addDrmInfo('com.apple.fps', (drmInfo) => {
2607
+ drmInfo.addInitData('sinf', new Uint8Array(0));
2608
+ });
2609
+ });
2610
+ });
2611
+ manifest.sequenceMode = true;
2303
2612
  });
2304
2613
 
2305
2614
  await testHlsParser(master, media, manifest);
@@ -2333,6 +2642,7 @@ describe('HlsParser', () => {
2333
2642
  stream.mime('audio/mp4', 'mp4a');
2334
2643
  });
2335
2644
  });
2645
+ manifest.sequenceMode = true;
2336
2646
  });
2337
2647
 
2338
2648
  fakeNetEngine.setHeaders(
@@ -2501,6 +2811,34 @@ describe('HlsParser', () => {
2501
2811
  });
2502
2812
  });
2503
2813
 
2814
+ it('if FairPlay encryption with MSE and mp2t content', async () => {
2815
+ const master = [
2816
+ '#EXTM3U\n',
2817
+ '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
2818
+ 'RESOLUTION=960x540,FRAME-RATE=60\n',
2819
+ 'video\n',
2820
+ ].join('');
2821
+
2822
+ const media = [
2823
+ '#EXTM3U\n',
2824
+ '#EXT-X-TARGETDURATION:6\n',
2825
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
2826
+ '#EXT-X-KEY:METHOD=SAMPLE-AES-CTR,',
2827
+ 'KEYFORMAT="com.apple.streamingkeydelivery",',
2828
+ 'URI="skd://f93d4e700d7ddde90529a27735d9e7cb",\n',
2829
+ '#EXTINF:5,\n',
2830
+ '#EXT-X-BYTERANGE:121090@616\n',
2831
+ 'main.ts',
2832
+ ].join('');
2833
+
2834
+ const error = new shaka.util.Error(
2835
+ shaka.util.Error.Severity.CRITICAL,
2836
+ shaka.util.Error.Category.MANIFEST,
2837
+ Code.HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED);
2838
+
2839
+ await verifyError(master, media, error);
2840
+ });
2841
+
2504
2842
  describe('if required tags are missing', () => {
2505
2843
  /**
2506
2844
  * @param {string} master
@@ -2539,261 +2877,6 @@ describe('HlsParser', () => {
2539
2877
  });
2540
2878
  }); // Errors out
2541
2879
 
2542
- describe('getStartTime_', () => {
2543
- /** @type {number} */
2544
- let segmentDataStartTime;
2545
- /** @type {!Uint8Array} */
2546
- let tsSegmentData;
2547
- /** @type {!Uint8Array} */
2548
- let nullTsPacketData;
2549
-
2550
- const master = [
2551
- '#EXTM3U\n',
2552
- '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
2553
- 'RESOLUTION=960x540,FRAME-RATE=60\n',
2554
- 'video',
2555
- ].join('');
2556
-
2557
- const media = [
2558
- '#EXTM3U\n',
2559
- '#EXT-X-PLAYLIST-TYPE:VOD\n',
2560
- '#EXT-X-MAP:URI="init.mp4"\n',
2561
- '#EXTINF:5,\n',
2562
- '#EXT-X-BYTERANGE:121090@616\n',
2563
- 'main.mp4',
2564
- ].join('');
2565
-
2566
- // TODO: Add separate tests to cover correct handling of BYTERANGE in
2567
- // constructing references. Here it is covered incidentally.
2568
- const expectedStartByte = 616;
2569
- const expectedEndByte = 121705;
2570
- // Nit: this value is an implementation detail of the fix for #1106
2571
- const partialEndByte = expectedStartByte + 2048 - 1;
2572
-
2573
- beforeEach(() => {
2574
- // TODO: use StreamGenerator?
2575
- segmentData = new Uint8Array([
2576
- 0x00, 0x00, 0x00, 0x24, // size (36)
2577
- 0x6D, 0x6F, 0x6F, 0x66, // type (moof)
2578
- 0x00, 0x00, 0x00, 0x1C, // traf size (28)
2579
- 0x74, 0x72, 0x61, 0x66, // type (traf)
2580
- 0x00, 0x00, 0x00, 0x14, // tfdt size (20)
2581
- 0x74, 0x66, 0x64, 0x74, // type (tfdt)
2582
- 0x01, 0x00, 0x00, 0x00, // version and flags
2583
-
2584
- 0x00, 0x00, 0x00, 0x00, // baseMediaDecodeTime first 4 bytes
2585
- 0x00, 0x00, 0x07, 0xd0, // baseMediaDecodeTime last 4 bytes (2000)
2586
- ]);
2587
- tsSegmentData = new Uint8Array([
2588
- 0x47, // TS sync byte (fixed value)
2589
- 0x41, 0x01, // not corrupt, payload follows, packet ID 257
2590
- 0x10, // not scrambled, no adaptation field, payload only, seq #0
2591
- 0x00, 0x00, 0x01, // PES start code (fixed value)
2592
- 0xe0, // stream ID (video stream 0)
2593
- 0x00, 0x00, // PES packet length (doesn't matter)
2594
- 0x80, // marker bits (fixed value), not scrambled, not priority
2595
- 0x80, // PTS only, no DTS, other flags 0 (don't matter)
2596
- 0x05, // remaining PES header length == 5 (one timestamp)
2597
- 0x21, 0x00, 0x0b, 0x7e, 0x41, // PTS = 180000, encoded into 5 bytes
2598
- ]);
2599
- // 180000 (TS PTS) divided by fixed TS timescale (90000) = 2s.
2600
- // 2000 (MP4 PTS) divided by parsed MP4 timescale (1000) = 2s.
2601
- segmentDataStartTime = 2;
2602
- nullTsPacketData = new Uint8Array([
2603
- 0x47, // TS sync byte (fixed value)
2604
- 0x1f, 0xff, // null packet (packet ID 8191)
2605
- ]);
2606
- });
2607
-
2608
- it('parses start time from mp4 segment', async () => {
2609
- fakeNetEngine
2610
- .setResponseText('test:/master', master)
2611
- .setResponseText('test:/video', media)
2612
- .setResponseValue('test:/init.mp4', initSegmentData)
2613
- .setResponseValue('test:/main.mp4', segmentData);
2614
-
2615
- const expectedRef = ManifestParser.makeReference(
2616
- /* uri= */ 'test:/main.mp4',
2617
- /* startTime= */ 0,
2618
- /* endTime= */ 5,
2619
- /* baseUri= */ '',
2620
- expectedStartByte,
2621
- expectedEndByte);
2622
- // In VOD content, we set the timestampOffset to align the
2623
- // content to presentation time 0.
2624
- expectedRef.timestampOffset = -segmentDataStartTime;
2625
-
2626
- const manifest = await parser.start('test:/master', playerInterface);
2627
- const video = manifest.variants[0].video;
2628
- await video.createSegmentIndex();
2629
- ManifestParser.verifySegmentIndex(video, [expectedRef]);
2630
-
2631
- // Make sure the segment data was fetched with the correct byte
2632
- // range.
2633
- fakeNetEngine.expectRangeRequest(
2634
- 'test:/main.mp4',
2635
- expectedStartByte,
2636
- partialEndByte);
2637
- });
2638
-
2639
- it('parses start time from ts segments', async () => {
2640
- const tsMediaPlaylist = media.replace(/\.mp4/g, '.ts');
2641
-
2642
- fakeNetEngine
2643
- .setResponseText('test:/master', master)
2644
- .setResponseText('test:/video', tsMediaPlaylist)
2645
- .setResponseValue('test:/main.ts', tsSegmentData);
2646
-
2647
- const expectedRef = ManifestParser.makeReference(
2648
- /* uri= */ 'test:/main.ts',
2649
- /* startTime= */ 0,
2650
- /* endTime= */ 5,
2651
- /* baseUri= */ '',
2652
- expectedStartByte,
2653
- expectedEndByte);
2654
- // In VOD content, we set the timestampOffset to align the
2655
- // content to presentation time 0.
2656
- expectedRef.timestampOffset = -segmentDataStartTime;
2657
-
2658
- const manifest = await parser.start('test:/master', playerInterface);
2659
- const video = manifest.variants[0].video;
2660
- await video.createSegmentIndex();
2661
- ManifestParser.verifySegmentIndex(video, [expectedRef]);
2662
-
2663
- // Make sure the segment data was fetched with the correct byte
2664
- // range.
2665
- fakeNetEngine.expectRangeRequest(
2666
- 'test:/main.ts',
2667
- expectedStartByte,
2668
- partialEndByte);
2669
- });
2670
-
2671
- it('parses start time from ts segments with null packets', async () => {
2672
- const tsMediaPlaylist = media.replace(/\.mp4/g, '.ts');
2673
-
2674
- // Each packet is 188 bytes, so allocate space for 3.
2675
- const tsSegmentWithNullPackets = new Uint8Array(188 * 3);
2676
- // The first two are "null" packets.
2677
- tsSegmentWithNullPackets.set(nullTsPacketData, /* offset= */ 0);
2678
- tsSegmentWithNullPackets.set(nullTsPacketData, /* offset= */ 188);
2679
- // The third has a timestamp.
2680
- tsSegmentWithNullPackets.set(tsSegmentData, /* offset= */ 188 * 2);
2681
-
2682
- fakeNetEngine
2683
- .setResponseText('test:/master', master)
2684
- .setResponseText('test:/video', tsMediaPlaylist)
2685
- .setResponseValue('test:/main.ts', tsSegmentWithNullPackets);
2686
-
2687
- const expectedRef = ManifestParser.makeReference(
2688
- /* uri= */ 'test:/main.ts',
2689
- /* startTime= */ 0,
2690
- /* endTime= */ 5,
2691
- /* baseUri= */ '',
2692
- expectedStartByte,
2693
- expectedEndByte);
2694
- // In VOD content, we set the timestampOffset to align the
2695
- // content to presentation time 0.
2696
- expectedRef.timestampOffset = -segmentDataStartTime;
2697
-
2698
- const manifest = await parser.start('test:/master', playerInterface);
2699
- const video = manifest.variants[0].video;
2700
- await video.createSegmentIndex();
2701
- ManifestParser.verifySegmentIndex(video, [expectedRef]);
2702
-
2703
- // Make sure the segment data was fetched with the correct byte
2704
- // range.
2705
- fakeNetEngine.expectRangeRequest(
2706
- 'test:/main.ts',
2707
- expectedStartByte,
2708
- partialEndByte);
2709
- });
2710
-
2711
- // We want to make sure that we can interrupt the parser while it is getting
2712
- // the start time. This is a regression test for Issue #1788 where
2713
- // interrupting the partial network request would be misinterpreted as the
2714
- // server not supporting range requests.
2715
- it('can be interrupted', async () => {
2716
- fakeNetEngine
2717
- .setResponseText('test:/master', master)
2718
- .setResponseText('test:/video', media)
2719
- .setResponseValue('test:/init.mp4', initSegmentData);
2720
-
2721
- // We are assuming that the time will be pulled out of the main mp4
2722
- // segment, so if we see a request that has a range header, we will stop
2723
- // the parser.
2724
- /** @type {!Map.<string, !BufferSource>} */
2725
- const responses = new Map();
2726
- responses.set('test:/main.mp4', segmentData);
2727
- responses.set('test:/init.mp4', initSegmentData);
2728
-
2729
- responses.forEach((data, uri) => {
2730
- fakeNetEngine.setResponse(uri, () => {
2731
- // Now that we are stopping the parser, we don't want to see any more
2732
- // requests. So if there is another request, fail the test.
2733
- responses.forEach((data, uri) => {
2734
- fakeNetEngine.setResponse(uri, fail);
2735
- });
2736
-
2737
- // Stop the parser, but don't wait on it or else we will hit deadlock.
2738
- parser.stop();
2739
-
2740
- return Promise.resolve(data);
2741
- });
2742
- });
2743
-
2744
- const expected = Util.jasmineError(new shaka.util.Error(
2745
- shaka.util.Error.Severity.CRITICAL,
2746
- shaka.util.Error.Category.PLAYER,
2747
- shaka.util.Error.Code.OPERATION_ABORTED));
2748
- await expectAsync(parser.start('test:/master', playerInterface))
2749
- .toBeRejectedWith(expected);
2750
- });
2751
-
2752
- it('sets duration with respect to presentation offset', async () => {
2753
- fakeNetEngine
2754
- .setResponseText('test:/master', master)
2755
- .setResponseText('test:/video', media)
2756
- .setResponseValue('test:/init.mp4', initSegmentData)
2757
- .setResponseValue('test:/main.mp4', segmentData);
2758
-
2759
- const manifest = await parser.start('test:/master', playerInterface);
2760
- const presentationTimeline = manifest.presentationTimeline;
2761
-
2762
- const video = manifest.variants[0].video;
2763
- await video.createSegmentIndex();
2764
- goog.asserts.assert(video.segmentIndex != null, 'Null segmentIndex!');
2765
-
2766
- const refs = Array.from(video.segmentIndex);
2767
- expect(refs.length).toBe(1);
2768
-
2769
- expect(refs[0].timestampOffset).toBe(-segmentDataStartTime);
2770
- // The duration should be set to the sum of the segment durations (5),
2771
- // even though the endTime of the segment is larger.
2772
- expect(refs[0].endTime - refs[0].startTime).toBe(5);
2773
- expect(presentationTimeline.getDuration()).toBe(5);
2774
- });
2775
-
2776
- it('forces full segment request', async () => {
2777
- fakeNetEngine
2778
- .setResponseText('test:/master', master)
2779
- .setResponseText('test:/video', media)
2780
- .setResponseValue('test:/init.mp4', initSegmentData)
2781
- .setResponseValue('test:/main.mp4', segmentData);
2782
-
2783
- const config = shaka.util.PlayerConfiguration.createDefault().manifest;
2784
- config.hls.useFullSegmentsForStartTime = true;
2785
- parser.configure(config);
2786
- await parser.start('test:/master', playerInterface);
2787
-
2788
- // Make sure the segment data was fetched with the correct byte
2789
- // range.
2790
- fakeNetEngine.expectRangeRequest(
2791
- 'test:/main.mp4',
2792
- expectedStartByte,
2793
- expectedEndByte);
2794
- });
2795
- });
2796
-
2797
2880
  it('correctly detects VOD streams as non-live', async () => {
2798
2881
  const master = [
2799
2882
  '#EXTM3U\n',
@@ -2944,7 +3027,7 @@ describe('HlsParser', () => {
2944
3027
  expect(audio0).toBe(audio1);
2945
3028
  });
2946
3029
 
2947
- // https://github.com/google/shaka-player/issues/1664
3030
+ // https://github.com/shaka-project/shaka-player/issues/1664
2948
3031
  it('correctly resolves relative playlist URIs', async () => {
2949
3032
  const master = [
2950
3033
  '#EXTM3U\n',
@@ -2987,7 +3070,7 @@ describe('HlsParser', () => {
2987
3070
  expect(manifest.variants.length).toBe(1);
2988
3071
  });
2989
3072
 
2990
- // https://github.com/google/shaka-player/issues/1908
3073
+ // https://github.com/shaka-project/shaka-player/issues/1908
2991
3074
  it('correctly pairs variants with multiple video and audio', async () => {
2992
3075
  const master = [
2993
3076
  '#EXTM3U\n',
@@ -3050,80 +3133,12 @@ describe('HlsParser', () => {
3050
3133
  stream.language = 'fr';
3051
3134
  });
3052
3135
  });
3136
+ manifest.sequenceMode = true;
3053
3137
  });
3054
3138
 
3055
3139
  await testHlsParser(master, media, manifest);
3056
3140
  });
3057
3141
 
3058
- it('skips raw audio formats', async () => {
3059
- const master = [
3060
- '#EXTM3U\n',
3061
- '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",URI="audio1"\n',
3062
- '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",URI="audio2"\n',
3063
- '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",URI="audio3"\n',
3064
- '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",URI="audio4"\n',
3065
- '#EXT-X-STREAM-INF:BANDWIDTH=400,CODECS="avc1,mp4a",',
3066
- 'RESOLUTION=1280x720,AUDIO="audio"\n',
3067
- 'video\n',
3068
- ].join('');
3069
-
3070
- const videoMedia = [
3071
- '#EXTM3U\n',
3072
- '#EXT-X-PLAYLIST-TYPE:VOD\n',
3073
- '#EXT-X-MAP:URI="v-init.mp4"\n',
3074
- '#EXTINF:5,\n',
3075
- 'v1.mp4',
3076
- ].join('');
3077
-
3078
- const audioMedia1 = [
3079
- '#EXTM3U\n',
3080
- '#EXT-X-PLAYLIST-TYPE:VOD\n',
3081
- '#EXTINF:5,\n',
3082
- 'a1.mp3',
3083
- ].join('');
3084
-
3085
- const audioMedia2 = [
3086
- '#EXTM3U\n',
3087
- '#EXT-X-PLAYLIST-TYPE:VOD\n',
3088
- '#EXTINF:5,\n',
3089
- 'a1.aac',
3090
- ].join('');
3091
-
3092
- const audioMedia3 = [
3093
- '#EXTM3U\n',
3094
- '#EXT-X-PLAYLIST-TYPE:VOD\n',
3095
- '#EXTINF:5,\n',
3096
- 'a1.ac3',
3097
- ].join('');
3098
-
3099
- const audioMedia4 = [
3100
- '#EXTM3U\n',
3101
- '#EXT-X-PLAYLIST-TYPE:VOD\n',
3102
- '#EXTINF:5,\n',
3103
- 'a1.ec3',
3104
- ].join('');
3105
-
3106
- fakeNetEngine
3107
- .setResponseText('test:/master', master)
3108
- .setResponseText('test:/video', videoMedia)
3109
- .setResponseText('test:/audio1', audioMedia1)
3110
- .setResponseText('test:/audio2', audioMedia2)
3111
- .setResponseText('test:/audio3', audioMedia3)
3112
- .setResponseText('test:/audio4', audioMedia4)
3113
- .setResponseValue('test:/v-init.mp4', initSegmentData)
3114
- .setResponseValue('test:/v1.mp4', segmentData);
3115
-
3116
- const alwaysWarnSpy = jasmine.createSpy('shaka.log.alwaysWarn');
3117
- shaka.log.alwaysWarn = shaka.test.Util.spyFunc(alwaysWarnSpy);
3118
-
3119
- const manifest = await parser.start('test:/master', playerInterface);
3120
- expect(manifest.variants.length).toBe(1);
3121
- expect(manifest.variants[0].audio).toBe(null);
3122
-
3123
- // We should log a warning when this happens.
3124
- expect(alwaysWarnSpy).toHaveBeenCalled();
3125
- });
3126
-
3127
3142
  // Issue #1875
3128
3143
  it('ignores audio groups on audio-only content', async () => {
3129
3144
  // NOTE: To reproduce the original issue accurately, the two audio playlist
@@ -3159,6 +3174,7 @@ describe('HlsParser', () => {
3159
3174
  stream.mime('audio/mp4', 'mp4a');
3160
3175
  });
3161
3176
  });
3177
+ manifest.sequenceMode = true;
3162
3178
  });
3163
3179
 
3164
3180
  fakeNetEngine
@@ -3341,6 +3357,7 @@ describe('HlsParser', () => {
3341
3357
  stream.mime('audio/mp4', 'mp4a');
3342
3358
  });
3343
3359
  });
3360
+ manifest.sequenceMode = true;
3344
3361
  });
3345
3362
 
3346
3363
  await testHlsParser(master, media, manifest);
@@ -3378,6 +3395,7 @@ describe('HlsParser', () => {
3378
3395
  stream.mime('audio/mp4', 'mp4a');
3379
3396
  });
3380
3397
  });
3398
+ manifest.sequenceMode = true;
3381
3399
  });
3382
3400
 
3383
3401
  await testHlsParser(master, media, manifest);
@@ -3416,6 +3434,7 @@ describe('HlsParser', () => {
3416
3434
  stream.mime('audio/mp4', 'mp4a');
3417
3435
  });
3418
3436
  });
3437
+ manifest.sequenceMode = true;
3419
3438
  });
3420
3439
 
3421
3440
  await testHlsParser(master, media, manifest);
@@ -3455,6 +3474,7 @@ describe('HlsParser', () => {
3455
3474
  stream.mime('audio/mp4', 'mp4a');
3456
3475
  });
3457
3476
  });
3477
+ manifest.sequenceMode = true;
3458
3478
  });
3459
3479
 
3460
3480
  await testHlsParser(master, media, manifest);
@@ -3485,4 +3505,54 @@ describe('HlsParser', () => {
3485
3505
  jasmine.objectContaining(eventValue3));
3486
3506
  });
3487
3507
  });
3508
+
3509
+ it('parses media playlists directly', async () => {
3510
+ const media = [
3511
+ '#EXTM3U\n',
3512
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
3513
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
3514
+ '#EXTINF:5,\n',
3515
+ '#EXT-X-BYTERANGE:121090@616\n',
3516
+ 'main.mp4',
3517
+ ].join('');
3518
+
3519
+ const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3520
+ manifest.sequenceMode = true;
3521
+ manifest.anyTimeline();
3522
+ manifest.addPartialVariant((variant) => {
3523
+ variant.addPartialStream(ContentType.VIDEO, (stream) => {
3524
+ stream.mime('video/mp2t', 'avc1.42E01E, mp4a.40.2');
3525
+ });
3526
+ });
3527
+ });
3528
+
3529
+ await testHlsParser(media, '', manifest);
3530
+ });
3531
+
3532
+ it('honors hls.mediaPlaylistFullMimeType', async () => {
3533
+ const media = [
3534
+ '#EXTM3U\n',
3535
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
3536
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
3537
+ '#EXTINF:5,\n',
3538
+ '#EXT-X-BYTERANGE:121090@616\n',
3539
+ 'main.mp4',
3540
+ ].join('');
3541
+
3542
+ const config = shaka.util.PlayerConfiguration.createDefault().manifest;
3543
+ config.hls.mediaPlaylistFullMimeType = 'audio/webm; codecs="vorbis"';
3544
+ parser.configure(config);
3545
+
3546
+ const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3547
+ manifest.sequenceMode = true;
3548
+ manifest.anyTimeline();
3549
+ manifest.addPartialVariant((variant) => {
3550
+ variant.addPartialStream(ContentType.AUDIO, (stream) => {
3551
+ stream.mime('audio/webm', 'vorbis');
3552
+ });
3553
+ });
3554
+ });
3555
+
3556
+ await testHlsParser(media, '', manifest);
3557
+ });
3488
3558
  });