shaka-player 4.3.9 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (321) hide show
  1. package/.github/workflows/build-and-test.yaml +11 -18
  2. package/.github/workflows/compute-incremental-coverage.py +3 -0
  3. package/.github/workflows/release-please.yaml +7 -0
  4. package/.github/workflows/selenium-lab-tests.yaml +45 -10
  5. package/AUTHORS +9 -0
  6. package/CHANGELOG.md +295 -190
  7. package/CONTRIBUTORS +8 -0
  8. package/LICENSE +32 -0
  9. package/README.md +63 -10
  10. package/demo/autoTemplate.txt +40 -5
  11. package/demo/close_button.js +11 -0
  12. package/demo/common/asset.js +13 -1
  13. package/demo/common/assets.js +112 -28
  14. package/demo/common/message_ids.js +25 -1
  15. package/demo/config.js +69 -10
  16. package/demo/customWarning.txt +2 -2
  17. package/demo/index.html +3 -1
  18. package/demo/locales/en.json +26 -2
  19. package/demo/locales/source.json +105 -9
  20. package/demo/main.js +57 -9
  21. package/demo/search.js +3 -1
  22. package/demo/service_worker.js +3 -0
  23. package/dist/controls.css +1 -1
  24. package/dist/controls.css.map +1 -1
  25. package/dist/demo.compiled.debug.js +132 -118
  26. package/dist/demo.compiled.debug.map +3 -3
  27. package/dist/demo.compiled.js +132 -118
  28. package/dist/demo.compiled.map +3 -3
  29. package/dist/deps.js +46 -28
  30. package/dist/locales.js +31 -31
  31. package/dist/receiver.compiled.debug.js +60 -52
  32. package/dist/receiver.compiled.debug.map +3 -3
  33. package/dist/receiver.compiled.js +60 -52
  34. package/dist/receiver.compiled.map +3 -3
  35. package/dist/shaka-player.compiled.d.ts +676 -391
  36. package/dist/shaka-player.compiled.debug.d.ts +676 -391
  37. package/dist/shaka-player.compiled.debug.externs.js +1188 -616
  38. package/dist/shaka-player.compiled.debug.js +1046 -700
  39. package/dist/shaka-player.compiled.debug.map +4 -4
  40. package/dist/shaka-player.compiled.externs.js +1188 -616
  41. package/dist/shaka-player.compiled.js +1094 -933
  42. package/dist/shaka-player.compiled.map +4 -4
  43. package/dist/shaka-player.ui.d.ts +677 -392
  44. package/dist/shaka-player.ui.debug.d.ts +677 -392
  45. package/dist/shaka-player.ui.debug.externs.js +1023 -451
  46. package/dist/shaka-player.ui.debug.js +1101 -738
  47. package/dist/shaka-player.ui.debug.map +4 -4
  48. package/dist/shaka-player.ui.externs.js +1023 -451
  49. package/dist/shaka-player.ui.js +1244 -1071
  50. package/dist/shaka-player.ui.map +4 -4
  51. package/docs/tutorials/ad_monetization.md +15 -1
  52. package/docs/tutorials/application-level-redirects.md +1 -1
  53. package/docs/tutorials/config.md +9 -5
  54. package/docs/tutorials/drm-config.md +61 -0
  55. package/docs/tutorials/fairplay.md +19 -4
  56. package/docs/tutorials/license-server-auth.md +4 -4
  57. package/docs/tutorials/license-wrapping.md +2 -2
  58. package/docs/tutorials/ui-customization.md +7 -3
  59. package/docs/tutorials/ui.md +7 -7
  60. package/docs/tutorials/upgrade.md +3 -0
  61. package/externs/ima.js +123 -2
  62. package/externs/isoboxer.js +217 -0
  63. package/externs/mediakeys.js +18 -0
  64. package/externs/mux.js +1 -105
  65. package/externs/pictureinpicture.js +48 -0
  66. package/externs/shaka/ads.js +61 -1
  67. package/externs/shaka/cea.js +110 -0
  68. package/externs/shaka/codecs.js +32 -0
  69. package/externs/shaka/manifest.js +101 -1
  70. package/externs/shaka/manifest_parser.js +0 -10
  71. package/externs/shaka/net.js +36 -7
  72. package/externs/shaka/offline.js +8 -1
  73. package/externs/shaka/player.js +220 -21
  74. package/externs/shaka/text.js +1 -382
  75. package/externs/shaka/transmuxer.js +59 -0
  76. package/karma.conf.js +15 -0
  77. package/lib/abr/simple_abr_manager.js +6 -3
  78. package/lib/ads/ad_manager.js +60 -2
  79. package/lib/ads/client_side_ad.js +86 -0
  80. package/lib/ads/client_side_ad_manager.js +93 -5
  81. package/lib/ads/server_side_ad.js +86 -0
  82. package/lib/ads/server_side_ad_manager.js +13 -0
  83. package/lib/cast/cast_utils.js +1 -0
  84. package/lib/cea/cea608_data_channel.js +24 -14
  85. package/lib/cea/cea608_memory.js +5 -2
  86. package/lib/cea/cea708_service.js +8 -9
  87. package/lib/cea/cea708_window.js +1 -2
  88. package/lib/cea/cea_decoder.js +23 -6
  89. package/lib/cea/cea_utils.js +25 -2
  90. package/lib/cea/dummy_caption_decoder.js +21 -0
  91. package/lib/cea/dummy_cea_parser.js +1 -3
  92. package/lib/cea/mp4_cea_parser.js +15 -10
  93. package/lib/cea/ts_cea_parser.js +69 -0
  94. package/lib/dash/content_protection.js +32 -2
  95. package/lib/dash/dash_parser.js +93 -31
  96. package/lib/dash/mpd_utils.js +6 -25
  97. package/lib/dash/segment_base.js +12 -14
  98. package/lib/dash/segment_list.js +10 -6
  99. package/lib/dash/segment_template.js +349 -32
  100. package/lib/dependencies/all.js +8 -0
  101. package/lib/hls/hls_classes.js +33 -8
  102. package/lib/hls/hls_parser.js +805 -191
  103. package/lib/hls/manifest_text_parser.js +4 -14
  104. package/lib/media/adaptation_set_criteria.js +43 -3
  105. package/lib/media/closed_caption_parser.js +74 -12
  106. package/lib/media/drm_engine.js +189 -49
  107. package/lib/media/gap_jumping_controller.js +1 -1
  108. package/lib/media/manifest_parser.js +34 -0
  109. package/lib/media/media_source_capabilities.js +10 -0
  110. package/lib/media/media_source_engine.js +475 -231
  111. package/lib/media/playhead.js +1 -1
  112. package/lib/media/presentation_timeline.js +62 -0
  113. package/lib/media/segment_index.js +50 -14
  114. package/lib/media/segment_prefetch.js +277 -0
  115. package/lib/media/segment_reference.js +70 -4
  116. package/lib/media/streaming_engine.js +258 -81
  117. package/lib/media/video_wrapper.js +15 -7
  118. package/lib/mss/content_protection.js +353 -0
  119. package/lib/mss/mss_parser.js +1081 -0
  120. package/lib/net/networking_engine.js +60 -10
  121. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  122. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  123. package/lib/offline/manifest_converter.js +6 -0
  124. package/lib/offline/storage.js +2 -4
  125. package/lib/player.js +309 -105
  126. package/lib/polyfill/media_capabilities.js +43 -3
  127. package/lib/polyfill/patchedmediakeys_apple.js +5 -0
  128. package/lib/polyfill/patchedmediakeys_nop.js +5 -0
  129. package/lib/polyfill/patchedmediakeys_webkit.js +5 -0
  130. package/lib/text/cue.js +208 -130
  131. package/lib/text/lrc_text_parser.js +2 -2
  132. package/lib/text/mp4_vtt_parser.js +2 -2
  133. package/lib/text/sbv_text_parser.js +1 -1
  134. package/lib/text/simple_text_displayer.js +2 -1
  135. package/lib/text/srt_text_parser.js +9 -1
  136. package/lib/text/ssa_text_parser.js +2 -2
  137. package/lib/text/text_engine.js +3 -21
  138. package/lib/text/text_utils.js +71 -20
  139. package/lib/text/ui_text_displayer.js +14 -14
  140. package/lib/text/vtt_text_parser.js +22 -14
  141. package/lib/transmuxer/aac_transmuxer.js +224 -0
  142. package/lib/transmuxer/ac3.js +142 -0
  143. package/lib/transmuxer/ac3_transmuxer.js +212 -0
  144. package/lib/transmuxer/adts.js +232 -0
  145. package/lib/transmuxer/ec3.js +103 -0
  146. package/lib/transmuxer/ec3_transmuxer.js +212 -0
  147. package/lib/transmuxer/h264.js +324 -0
  148. package/lib/transmuxer/mp3_transmuxer.js +204 -0
  149. package/lib/transmuxer/mpeg_audio.js +196 -0
  150. package/lib/transmuxer/mpeg_ts_transmuxer.js +182 -0
  151. package/lib/transmuxer/mss_transmuxer.js +389 -0
  152. package/lib/{media/transmuxer.js → transmuxer/muxjs_transmuxer.js} +34 -80
  153. package/lib/transmuxer/transmuxer_engine.js +161 -0
  154. package/lib/transmuxer/ts_transmuxer.js +738 -0
  155. package/lib/util/cmcd_manager.js +131 -71
  156. package/lib/util/error.js +62 -26
  157. package/lib/util/exp_golomb.js +220 -0
  158. package/lib/util/fairplay_utils.js +64 -13
  159. package/lib/util/id3_utils.js +56 -3
  160. package/lib/util/language_utils.js +11 -8
  161. package/lib/util/manifest_parser_utils.js +3 -0
  162. package/lib/util/mime_utils.js +44 -7
  163. package/lib/util/mp4_box_parsers.js +233 -5
  164. package/lib/util/mp4_generator.js +1381 -0
  165. package/lib/util/periods.js +40 -34
  166. package/lib/util/platform.js +25 -3
  167. package/lib/util/player_configuration.js +38 -1
  168. package/lib/util/stream_utils.js +138 -27
  169. package/lib/util/text_parser.js +1 -1
  170. package/lib/util/ts_parser.js +470 -47
  171. package/lib/util/xml_utils.js +16 -3
  172. package/maintained-branches.md +2 -2
  173. package/package.json +4 -2
  174. package/roadmap.md +21 -6
  175. package/shaka-player.uncompiled.js +18 -0
  176. package/test/abr/simple_abr_manager_unit.js +32 -4
  177. package/test/ads/ad_manager_unit.js +18 -2
  178. package/test/cast/cast_utils_unit.js +7 -2
  179. package/test/cea/cea608_memory_unit.js +24 -0
  180. package/test/cea/cea_decoder_unit.js +33 -0
  181. package/test/dash/dash_parser_content_protection_unit.js +93 -3
  182. package/test/dash/dash_parser_live_unit.js +56 -13
  183. package/test/dash/dash_parser_manifest_unit.js +70 -2
  184. package/test/dash/dash_parser_segment_base_unit.js +14 -9
  185. package/test/dash/dash_parser_segment_template_unit.js +286 -6
  186. package/test/demo/demo_unit.js +5 -1
  187. package/test/hls/hls_live_unit.js +188 -28
  188. package/test/hls/hls_parser_unit.js +250 -109
  189. package/test/hls/manifest_text_parser_unit.js +18 -13
  190. package/test/media/adaptation_set_criteria_unit.js +46 -14
  191. package/test/media/adaptation_set_unit.js +2 -0
  192. package/test/media/drm_engine_integration.js +11 -8
  193. package/test/media/drm_engine_unit.js +220 -7
  194. package/test/media/media_source_engine_integration.js +122 -38
  195. package/test/media/media_source_engine_unit.js +133 -153
  196. package/test/media/playhead_unit.js +3 -0
  197. package/test/media/presentation_timeline_unit.js +51 -0
  198. package/test/media/segment_index_unit.js +52 -0
  199. package/test/media/segment_prefetch_unit.js +243 -0
  200. package/test/media/streaming_engine_integration.js +9 -3
  201. package/test/media/streaming_engine_unit.js +440 -59
  202. package/test/mss/mss_parser_content_protection_unit.js +49 -0
  203. package/test/mss/mss_parser_unit.js +472 -0
  204. package/test/mss/mss_player_integration.js +123 -0
  205. package/test/offline/manifest_convert_unit.js +9 -0
  206. package/test/offline/storage_integration.js +6 -1
  207. package/test/player_integration.js +4 -1
  208. package/test/player_unit.js +386 -133
  209. package/test/polyfill/media_capabilities_unit.js +18 -0
  210. package/test/test/assets/hls-raw-aac/fileSequence0.aac +0 -0
  211. package/test/test/assets/hls-raw-aac/fileSequence1.aac +0 -0
  212. package/test/test/assets/hls-raw-aac/fileSequence2.aac +0 -0
  213. package/test/test/assets/hls-raw-aac/fileSequence3.aac +0 -0
  214. package/test/test/assets/hls-raw-aac/manifest.m3u8 +4 -0
  215. package/test/test/assets/hls-raw-aac/stream.m4a.m3u8 +14 -0
  216. package/test/test/assets/hls-raw-ac3/fileSequence0.ac3 +0 -0
  217. package/test/test/assets/hls-raw-ac3/fileSequence1.ac3 +0 -0
  218. package/test/test/assets/hls-raw-ac3/fileSequence2.ac3 +0 -0
  219. package/test/test/assets/hls-raw-ac3/fileSequence3.ac3 +0 -0
  220. package/test/test/assets/hls-raw-ac3/fileSequence4.ac3 +0 -0
  221. package/test/test/assets/hls-raw-ac3/fileSequence5.ac3 +0 -0
  222. package/test/test/assets/hls-raw-ac3/fileSequence6.ac3 +0 -0
  223. package/test/test/assets/hls-raw-ac3/fileSequence7.ac3 +0 -0
  224. package/test/test/assets/hls-raw-ac3/prog_index.m3u8 +31 -0
  225. package/test/test/assets/hls-raw-ec3/fileSequence0.ec3 +0 -0
  226. package/test/test/assets/hls-raw-ec3/fileSequence1.ec3 +0 -0
  227. package/test/test/assets/hls-raw-ec3/fileSequence2.ec3 +0 -0
  228. package/test/test/assets/hls-raw-ec3/fileSequence3.ec3 +0 -0
  229. package/test/test/assets/hls-raw-ec3/fileSequence4.ec3 +0 -0
  230. package/test/test/assets/hls-raw-ec3/fileSequence5.ec3 +0 -0
  231. package/test/test/assets/hls-raw-ec3/fileSequence6.ec3 +0 -0
  232. package/test/test/assets/hls-raw-ec3/fileSequence7.ec3 +0 -0
  233. package/test/test/assets/hls-raw-ec3/prog_index.m3u8 +31 -0
  234. package/test/test/assets/hls-raw-mp3/chunklist_w905519204.m3u8 +13 -0
  235. package/test/test/assets/hls-raw-mp3/media_w905519204_0.mp3 +0 -0
  236. package/test/test/assets/hls-raw-mp3/media_w905519204_1.mp3 +0 -0
  237. package/test/test/assets/hls-raw-mp3/media_w905519204_2.mp3 +0 -0
  238. package/test/test/assets/hls-raw-mp3/media_w905519204_3.mp3 +0 -0
  239. package/test/test/assets/hls-raw-mp3/playlist.m3u8 +4 -0
  240. package/test/test/assets/hls-ts-aac/playlist.m3u8 +23 -0
  241. package/test/test/assets/hls-ts-aac/segment_0.ts +0 -0
  242. package/test/test/assets/hls-ts-aac/segment_1.ts +0 -0
  243. package/test/test/assets/hls-ts-aac/segment_2.ts +0 -0
  244. package/test/test/assets/hls-ts-aac/segment_3.ts +0 -0
  245. package/test/test/assets/hls-ts-aac/segment_4.ts +0 -0
  246. package/test/test/assets/hls-ts-aac/segment_5.ts +0 -0
  247. package/test/test/assets/hls-ts-aac/segment_6.ts +0 -0
  248. package/test/test/assets/hls-ts-aac/segment_7.ts +0 -0
  249. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0000.ts +0 -0
  250. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0001.ts +0 -0
  251. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0002.ts +0 -0
  252. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0003.ts +0 -0
  253. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0004.ts +0 -0
  254. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0005.ts +0 -0
  255. package/test/test/assets/hls-ts-ac3/prog_index.m3u8 +19 -0
  256. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0000.ts +0 -0
  257. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0001.ts +0 -0
  258. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0002.ts +0 -0
  259. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0003.ts +0 -0
  260. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0004.ts +0 -0
  261. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0005.ts +0 -0
  262. package/test/test/assets/hls-ts-ec3/prog_index.m3u8 +19 -0
  263. package/test/test/assets/hls-ts-h264/fileSequence0.ts +0 -0
  264. package/test/test/assets/hls-ts-h264/fileSequence1.ts +0 -0
  265. package/test/test/assets/hls-ts-h264/fileSequence2.ts +0 -0
  266. package/test/test/assets/hls-ts-h264/fileSequence3.ts +0 -0
  267. package/test/test/assets/hls-ts-h264/fileSequence4.ts +0 -0
  268. package/test/test/assets/hls-ts-h264/fileSequence5.ts +0 -0
  269. package/test/test/assets/hls-ts-h264/prog_index.m3u8 +25 -0
  270. package/test/test/assets/hls-ts-mp3/manifest.m3u8 +13 -0
  271. package/test/test/assets/hls-ts-mp3/media_w239891843_0.ts +0 -0
  272. package/test/test/assets/hls-ts-mp3/media_w239891843_1.ts +0 -0
  273. package/test/test/assets/hls-ts-mp3/media_w239891843_2.ts +0 -0
  274. package/test/test/assets/hls-ts-mp3/media_w239891843_3.ts +0 -0
  275. package/test/test/assets/hls-ts-muxed-aac-h264/chunk.m3u8 +17 -0
  276. package/test/test/assets/hls-ts-muxed-aac-h264/n_0_0_0.ts +0 -0
  277. package/test/test/assets/hls-ts-muxed-aac-h264/n_1_0_0.ts +0 -0
  278. package/test/test/assets/hls-ts-muxed-aac-h264/n_2_0_0.ts +0 -0
  279. package/test/test/assets/hls-ts-muxed-aac-h264/n_3_0_0.ts +0 -0
  280. package/test/test/assets/hls-ts-muxed-aac-h264/n_4_0_0.ts +0 -0
  281. package/test/test/assets/hls-ts-muxed-aac-h264/n_5_0_0.ts +0 -0
  282. package/test/test/assets/hls-ts-muxed-aac-h264/playlist.m3u8 +4 -0
  283. package/test/test/boot.js +7 -2
  284. package/test/test/util/fake_ad.js +99 -0
  285. package/test/test/util/fake_ad_manager.js +7 -1
  286. package/test/test/util/fake_networking_engine.js +41 -14
  287. package/test/test/util/fake_segment_prefetch.js +81 -0
  288. package/test/test/util/manifest_generator.js +19 -5
  289. package/test/test/util/mss_parser_util.js +115 -0
  290. package/test/test/util/offline_utils.js +1 -0
  291. package/test/test/util/simple_fakes.js +12 -3
  292. package/test/test/util/streaming_engine_util.js +14 -4
  293. package/test/test/util/ttml_utils.js +2 -2
  294. package/test/test/util/ui_utils.js +5 -1
  295. package/test/text/cue_integration.js +1 -1
  296. package/test/text/srt_text_parser_unit.js +78 -0
  297. package/test/text/text_engine_unit.js +17 -8
  298. package/test/text/ui_text_displayer_unit.js +4 -4
  299. package/test/text/vtt_text_parser_unit.js +59 -40
  300. package/test/text/web_vtt_generator_unit.js +9 -3
  301. package/test/{media/transmuxer_integration.js → transmuxer/muxjs_transmuxer_integration.js} +30 -33
  302. package/test/transmuxer/transmuxer_engine_integration.js +60 -0
  303. package/test/transmuxer/transmuxer_integration.js +296 -0
  304. package/test/util/cmcd_manager_unit.js +162 -13
  305. package/test/util/language_utils_unit.js +9 -2
  306. package/test/util/mp4_box_parsers_unit.js +39 -4
  307. package/test/util/periods_unit.js +34 -26
  308. package/test/util/stream_utils_unit.js +60 -107
  309. package/ui/controls.js +19 -1
  310. package/ui/controls.less +1 -0
  311. package/ui/externs/ui.js +13 -3
  312. package/ui/language_utils.js +15 -0
  313. package/ui/less/thumbnails.less +26 -0
  314. package/ui/locales/oc.json +42 -0
  315. package/ui/pip_button.js +83 -2
  316. package/ui/range_element.js +15 -0
  317. package/ui/resolution_selection.js +9 -2
  318. package/ui/seek_bar.js +230 -1
  319. package/ui/ui.js +5 -0
  320. package/lib/cea/i_caption_decoder.js +0 -51
  321. package/lib/cea/i_cea_parser.js +0 -68
@@ -26,8 +26,6 @@ describe('DashParser Live', () => {
26
26
  parser.configure(shaka.util.PlayerConfiguration.createDefault().manifest);
27
27
  playerInterface = {
28
28
  networkingEngine: fakeNetEngine,
29
- modifyManifestRequest: (request, manifestInfo) => {},
30
- modifySegmentRequest: (request, segmentInfo) => {},
31
29
  filter: (manifest) => Promise.resolve(),
32
30
  makeTextStreamsForClosedCaptions: (manifest) => {},
33
31
  onTimelineRegionAdded: fail, // Should not have any EventStream elements.
@@ -591,6 +589,8 @@ describe('DashParser Live', () => {
591
589
  const onError = jasmine.createSpy('onError');
592
590
  playerInterface.onError = Util.spyFunc(onError);
593
591
 
592
+ const updateTick = updateTickSpy();
593
+
594
594
  fakeNetEngine.setResponseText('dummy://foo', manifestText);
595
595
  await parser.start('dummy://foo', playerInterface);
596
596
 
@@ -605,6 +605,39 @@ describe('DashParser Live', () => {
605
605
 
606
606
  await updateManifest();
607
607
  expect(onError).toHaveBeenCalledTimes(1);
608
+ expect(updateTick).toHaveBeenCalledTimes(2);
609
+ });
610
+
611
+ it('fatal error on manifest update request failure when ' +
612
+ 'raiseFatalErrorOnManifestUpdateRequestFailure is true', async () => {
613
+ const manifestConfig =
614
+ shaka.util.PlayerConfiguration.createDefault().manifest;
615
+ manifestConfig.raiseFatalErrorOnManifestUpdateRequestFailure = true;
616
+ parser.configure(manifestConfig);
617
+
618
+ const updateTick = updateTickSpy();
619
+
620
+ const lines = [
621
+ '<SegmentTemplate startNumber="1" media="s$Number$.mp4" duration="2"/>',
622
+ ];
623
+ const manifestText = makeSimpleLiveManifestText(lines, updateTime);
624
+ /** @type {!jasmine.Spy} */
625
+ const onError = jasmine.createSpy('onError');
626
+ playerInterface.onError = Util.spyFunc(onError);
627
+
628
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
629
+ await parser.start('dummy://foo', playerInterface);
630
+
631
+ const error = new shaka.util.Error(
632
+ shaka.util.Error.Severity.CRITICAL,
633
+ shaka.util.Error.Category.NETWORK,
634
+ shaka.util.Error.Code.BAD_HTTP_STATUS);
635
+ const operation = shaka.util.AbortableOperation.failed(error);
636
+ fakeNetEngine.request.and.returnValue(operation);
637
+
638
+ await updateManifest();
639
+ expect(onError).toHaveBeenCalledWith(error);
640
+ expect(updateTick).toHaveBeenCalledTimes(1);
608
641
  });
609
642
 
610
643
  it('uses @minimumUpdatePeriod', async () => {
@@ -640,10 +673,9 @@ describe('DashParser Live', () => {
640
673
  fakeNetEngine.setResponseText('dummy://foo', manifestText);
641
674
  await parser.start('dummy://foo', playerInterface);
642
675
 
643
- const waitTime = shaka.dash.DashParser['MIN_UPDATE_PERIOD_'];
644
676
  expect(tickAfter).toHaveBeenCalledTimes(1);
645
677
  const delay = tickAfter.calls.mostRecent().args[0];
646
- expect(delay).toBe(waitTime);
678
+ expect(delay).toBe(0);
647
679
  });
648
680
 
649
681
  it('does not update when @minimumUpdatePeriod is missing', async () => {
@@ -668,8 +700,7 @@ describe('DashParser Live', () => {
668
700
  '<SegmentTemplate startNumber="1" media="s$Number$.mp4" duration="2" />',
669
701
  ];
670
702
  const extraWaitTime = 15.0;
671
- const idealUpdateTime = shaka.dash.DashParser['MIN_UPDATE_PERIOD_'];
672
- const manifestText = makeSimpleLiveManifestText(lines, idealUpdateTime);
703
+ const manifestText = makeSimpleLiveManifestText(lines, 3);
673
704
 
674
705
  let now = 0;
675
706
  Date.now = () => now;
@@ -709,17 +740,21 @@ describe('DashParser Live', () => {
709
740
  fakeNetEngine.setResponseText('dummy://foo', manifestText);
710
741
 
711
742
  const manifestRequest = shaka.net.NetworkingEngine.RequestType.MANIFEST;
743
+ const manifestContext = {
744
+ type: shaka.net.NetworkingEngine.AdvancedRequestType.MPD,
745
+ };
712
746
  await parser.start('dummy://foo', playerInterface);
713
747
 
714
748
  expect(fakeNetEngine.request).toHaveBeenCalledTimes(1);
715
- fakeNetEngine.expectRequest('dummy://foo', manifestRequest);
749
+ fakeNetEngine.expectRequest('dummy://foo', manifestRequest, manifestContext);
716
750
  fakeNetEngine.request.calls.reset();
717
751
 
718
752
  // Create a mock so we can verify it gives two URIs.
719
753
  // The third location is a relative url, and should be resolved as an
720
754
  // absolute url.
721
- fakeNetEngine.request.and.callFake((type, request) => {
755
+ fakeNetEngine.request.and.callFake((type, request, context) => {
722
756
  expect(type).toBe(manifestRequest);
757
+ expect(context).toEqual(manifestContext);
723
758
  expect(request.uris).toEqual(
724
759
  ['http://foobar', 'http://foobar2', 'dummy://foo/foobar3']);
725
760
  const data = shaka.util.StringUtils.toUTF8(manifestText);
@@ -952,6 +987,9 @@ describe('DashParser Live', () => {
952
987
 
953
988
  describe('stop', () => {
954
989
  const manifestRequestType = shaka.net.NetworkingEngine.RequestType.MANIFEST;
990
+ const manifestContext = {
991
+ type: shaka.net.NetworkingEngine.AdvancedRequestType.MPD,
992
+ };
955
993
  const dateRequestType = shaka.net.NetworkingEngine.RequestType.TIMING;
956
994
  const manifestUri = 'dummy://foo';
957
995
  const dateUri = 'http://foo.bar/date';
@@ -983,7 +1021,8 @@ describe('DashParser Live', () => {
983
1021
  it('stops updates', async () => {
984
1022
  await parser.start(manifestUri, playerInterface);
985
1023
 
986
- fakeNetEngine.expectRequest(manifestUri, manifestRequestType);
1024
+ fakeNetEngine.expectRequest(
1025
+ manifestUri, manifestRequestType, manifestContext);
987
1026
  fakeNetEngine.request.calls.reset();
988
1027
 
989
1028
  parser.stop();
@@ -1001,7 +1040,8 @@ describe('DashParser Live', () => {
1001
1040
  parser.stop();
1002
1041
  await expectation;
1003
1042
 
1004
- fakeNetEngine.expectRequest(manifestUri, manifestRequestType);
1043
+ fakeNetEngine.expectRequest(
1044
+ manifestUri, manifestRequestType, manifestContext);
1005
1045
  fakeNetEngine.request.calls.reset();
1006
1046
  await updateManifest();
1007
1047
  // An update should not occur.
@@ -1012,7 +1052,8 @@ describe('DashParser Live', () => {
1012
1052
  const manifest = await parser.start('dummy://foo', playerInterface);
1013
1053
 
1014
1054
  expect(manifest).toBeTruthy();
1015
- fakeNetEngine.expectRequest(manifestUri, manifestRequestType);
1055
+ fakeNetEngine.expectRequest(
1056
+ manifestUri, manifestRequestType, manifestContext);
1016
1057
  fakeNetEngine.request.calls.reset();
1017
1058
  /** @type {!shaka.util.PublicPromise} */
1018
1059
  const delay = fakeNetEngine.delayNextRequest();
@@ -1020,7 +1061,8 @@ describe('DashParser Live', () => {
1020
1061
  await updateManifest();
1021
1062
  // The request was made but should not be resolved yet.
1022
1063
  expect(fakeNetEngine.request).toHaveBeenCalledTimes(1);
1023
- fakeNetEngine.expectRequest(manifestUri, manifestRequestType);
1064
+ fakeNetEngine.expectRequest(
1065
+ manifestUri, manifestRequestType, manifestContext);
1024
1066
  fakeNetEngine.request.calls.reset();
1025
1067
  parser.stop();
1026
1068
  delay.resolve();
@@ -1041,7 +1083,8 @@ describe('DashParser Live', () => {
1041
1083
  await Util.shortDelay();
1042
1084
  // This is the initial manifest request.
1043
1085
  expect(fakeNetEngine.request).toHaveBeenCalledTimes(1);
1044
- fakeNetEngine.expectRequest(manifestUri, manifestRequestType);
1086
+ fakeNetEngine.expectRequest(
1087
+ manifestUri, manifestRequestType, manifestContext);
1045
1088
  fakeNetEngine.request.calls.reset();
1046
1089
  // Resolve the manifest request and wait on the UTCTiming request.
1047
1090
  delay.resolve();
@@ -140,7 +140,7 @@ describe('DashParser Manifest', () => {
140
140
  ' <Representation bandwidth="50" width="576" height="432" />',
141
141
  ' </AdaptationSet>',
142
142
  ' <AdaptationSet mimeType="text/vtt"',
143
- ' lang="es" label="spanish">',
143
+ ' lang="spa" label="spanish">',
144
144
  ' <Role value="caption" />',
145
145
  ' <Role value="main" />',
146
146
  ' <Representation bandwidth="100" />',
@@ -155,6 +155,7 @@ describe('DashParser Manifest', () => {
155
155
  ],
156
156
  shaka.test.ManifestGenerator.generate((manifest) => {
157
157
  manifest.sequenceMode = true;
158
+ manifest.type = shaka.media.ManifestParser.DASH;
158
159
  manifest.anyTimeline();
159
160
  manifest.minBufferTime = 75;
160
161
  manifest.addPartialVariant((variant) => {
@@ -193,6 +194,7 @@ describe('DashParser Manifest', () => {
193
194
  });
194
195
  manifest.addPartialTextStream((stream) => {
195
196
  stream.language = 'es';
197
+ stream.originalLanguage = 'spa';
196
198
  stream.label = 'spanish';
197
199
  stream.primary = true;
198
200
  stream.mimeType = 'text/vtt';
@@ -239,6 +241,7 @@ describe('DashParser Manifest', () => {
239
241
  ],
240
242
  shaka.test.ManifestGenerator.generate((manifest) => {
241
243
  manifest.sequenceMode = false;
244
+ manifest.type = shaka.media.ManifestParser.DASH;
242
245
  manifest.anyTimeline();
243
246
  manifest.minBufferTime = 75;
244
247
  manifest.addPartialVariant((variant) => {
@@ -725,7 +728,7 @@ describe('DashParser Manifest', () => {
725
728
  ' value="http://foo.bar/date" />',
726
729
  ]);
727
730
 
728
- fakeNetEngine.request.and.callFake((type, request) => {
731
+ fakeNetEngine.request.and.callFake((type, request, context) => {
729
732
  if (request.uris[0] == 'http://foo.bar/manifest') {
730
733
  const data = shaka.util.StringUtils.toUTF8(source);
731
734
  return shaka.util.AbortableOperation.completed({
@@ -1862,6 +1865,49 @@ describe('DashParser Manifest', () => {
1862
1865
  expect(stream).toBeUndefined();
1863
1866
  });
1864
1867
 
1868
+ it('reads accessibility purpose elements', async () => {
1869
+ const manifestText = [
1870
+ '<MPD minBufferTime="PT75S">',
1871
+ ' <Period id="1" duration="PT30S">',
1872
+ ' <AdaptationSet id="1" contentType="text">',
1873
+ ' <Accessibility ',
1874
+ ' schemeIdUri="urn:tva:metadata:cs:AudioPurposeCS:2007"',
1875
+ ' value="2" />',
1876
+ ' <Representation id="text-en" mimeType="text/webvtt">',
1877
+ ' <BaseURL>t-en.vtt</BaseURL>',
1878
+ ' </Representation>',
1879
+ ' </AdaptationSet>',
1880
+ ' <AdaptationSet id="1" mimeType="video/mp4">',
1881
+ ' <Representation id="video-sd" width="640" height="480">',
1882
+ ' <BaseURL>v-sd.mp4</BaseURL>',
1883
+ ' <SegmentBase indexRange="100-200" />',
1884
+ ' </Representation>',
1885
+ ' </AdaptationSet>',
1886
+ ' <AdaptationSet id="1" mimeType="audio/mp4">',
1887
+ ' <Accessibility ',
1888
+ ' schemeIdUri="urn:tva:metadata:cs:AudioPurposeCS:2007"',
1889
+ ' value="1" />',
1890
+ ' <Representation id="audio-sd" width="640" height="480">',
1891
+ ' <BaseURL>v-sd.mp4</BaseURL>',
1892
+ ' <SegmentBase indexRange="100-200" />',
1893
+ ' </Representation>',
1894
+ ' </AdaptationSet>',
1895
+ ' </Period>',
1896
+ '</MPD>',
1897
+ ].join('\n');
1898
+
1899
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
1900
+ /** @type {shaka.extern.Manifest} */
1901
+ const manifest = await parser.start('dummy://foo', playerInterface);
1902
+ const textStream = manifest.textStreams[0];
1903
+ expect(textStream.accessibilityPurpose).toBe(
1904
+ shaka.media.ManifestParser.AccessibilityPurpose.HARD_OF_HEARING);
1905
+ const variant = manifest.variants[0];
1906
+ expect(variant.video.accessibilityPurpose).toBeUndefined();
1907
+ expect(variant.audio.accessibilityPurpose).toBe(
1908
+ shaka.media.ManifestParser.AccessibilityPurpose.VISUALLY_IMPAIRED);
1909
+ });
1910
+
1865
1911
  it('converts Accessibility element to "kind"', async () => {
1866
1912
  const manifestText = [
1867
1913
  '<MPD minBufferTime="PT75S">',
@@ -2511,4 +2557,26 @@ describe('DashParser Manifest', () => {
2511
2557
  expect(segments[0][1].startTime).toBe(15);
2512
2558
  expect(segments[1][1].startTime).toBe(15);
2513
2559
  });
2560
+
2561
+ describe('Parses ServiceDescription', () => {
2562
+ it('with PlaybackRate and Latency', async () => {
2563
+ const source = [
2564
+ '<MPD minBufferTime="PT75S" type="dynamic"',
2565
+ ' availabilityStartTime="1970-01-01T00:00:00Z">',
2566
+ ' <ServiceDescription id="0">',
2567
+ ' <Latency max="2000" min="2000" referenceId="0" target="4000" />',
2568
+ ' <PlaybackRate max="1.10" min="0.96" />',
2569
+ ' </ServiceDescription>',
2570
+ '</MPD>',
2571
+ ].join('\n');
2572
+
2573
+ fakeNetEngine.setResponseText('dummy://foo', source);
2574
+
2575
+ /** @type {shaka.extern.Manifest} */
2576
+ const manifest = await parser.start('dummy://foo', playerInterface);
2577
+
2578
+ expect(manifest.serviceDescription.maxLatency).toBe(2);
2579
+ expect(manifest.serviceDescription.maxPlaybackRate).toBe(1.1);
2580
+ });
2581
+ });
2514
2582
  });
@@ -87,13 +87,13 @@ describe('DashParser SegmentBase', () => {
87
87
 
88
88
  // Expect calls to fetch part of the media and init segments of each stream.
89
89
  fakeNetEngine.expectRangeRequest(
90
- 'http://example.com/media-1.webm', 100, 200);
90
+ 'http://example.com/media-1.webm', 100, 200, /* isInit= */ false);
91
91
  fakeNetEngine.expectRangeRequest(
92
- 'http://example.com/init-1.webm', 201, 300);
92
+ 'http://example.com/init-1.webm', 201, 300, /* isInit= */ true);
93
93
  fakeNetEngine.expectRangeRequest(
94
- 'http://example.com/media-2.webm', 1100, 1200);
94
+ 'http://example.com/media-2.webm', 1100, 1200, /* isInit= */ false);
95
95
  fakeNetEngine.expectRangeRequest(
96
- 'http://example.com/init-2.webm', 1201, 1300);
96
+ 'http://example.com/init-2.webm', 1201, 1300, /* isInit= */ true);
97
97
  });
98
98
 
99
99
  it('inherits from Period', async () => {
@@ -125,7 +125,8 @@ describe('DashParser SegmentBase', () => {
125
125
  expect(initSegmentReference.getEndByte()).toBe(300);
126
126
 
127
127
  expect(fakeNetEngine.request).toHaveBeenCalledTimes(2);
128
- fakeNetEngine.expectRangeRequest('http://example.com', 100, 200);
128
+ fakeNetEngine.expectRangeRequest(
129
+ 'http://example.com', 100, 200, /* isInit= */ false);
129
130
  });
130
131
 
131
132
  it('inherits from AdaptationSet', async () => {
@@ -157,7 +158,8 @@ describe('DashParser SegmentBase', () => {
157
158
  expect(initSegmentReference.getEndByte()).toBe(300);
158
159
 
159
160
  expect(fakeNetEngine.request).toHaveBeenCalledTimes(2);
160
- fakeNetEngine.expectRangeRequest('http://example.com', 100, 200);
161
+ fakeNetEngine.expectRangeRequest(
162
+ 'http://example.com', 100, 200, /* isInit= */ false);
161
163
  });
162
164
 
163
165
  it('does not require sourceURL in Initialization', async () => {
@@ -190,7 +192,8 @@ describe('DashParser SegmentBase', () => {
190
192
  expect(initSegmentReference.getEndByte()).toBe(300);
191
193
 
192
194
  expect(fakeNetEngine.request).toHaveBeenCalledTimes(2);
193
- fakeNetEngine.expectRangeRequest('http://example.com/stream.mp4', 100, 200);
195
+ fakeNetEngine.expectRangeRequest(
196
+ 'http://example.com/stream.mp4', 100, 200, /* isInit= */ false);
194
197
  });
195
198
 
196
199
  it('merges across levels', async () => {
@@ -230,7 +233,8 @@ describe('DashParser SegmentBase', () => {
230
233
  expect(segmentReference.timestampOffset).toBe(-10);
231
234
 
232
235
  expect(fakeNetEngine.request).toHaveBeenCalledTimes(2);
233
- fakeNetEngine.expectRangeRequest('http://example.com/index.mp4', 5, 2000);
236
+ fakeNetEngine.expectRangeRequest(
237
+ 'http://example.com/index.mp4', 5, 2000, /* isInit= */ false);
234
238
  });
235
239
 
236
240
  it('merges and overrides across levels', async () => {
@@ -269,7 +273,8 @@ describe('DashParser SegmentBase', () => {
269
273
  expect(segmentReference.timestampOffset).toBe(-20);
270
274
 
271
275
  expect(fakeNetEngine.request).toHaveBeenCalledTimes(2);
272
- fakeNetEngine.expectRangeRequest('http://example.com', 30, 900);
276
+ fakeNetEngine.expectRangeRequest(
277
+ 'http://example.com', 30, 900, /* isInit= */ false);
273
278
  });
274
279
 
275
280
  it('does not assume the same timescale as media', async () => {
@@ -198,7 +198,7 @@ describe('DashParser SegmentTemplate', () => {
198
198
 
199
199
  expect(fakeNetEngine.request).toHaveBeenCalledTimes(2);
200
200
  fakeNetEngine.expectRangeRequest(
201
- 'http://example.com/index-500.mp4', 0, null);
201
+ 'http://example.com/index-500.mp4', 0, null, /* isInit= */ false);
202
202
  });
203
203
 
204
204
  it('defaults to index with multiple segment sources', async () => {
@@ -226,7 +226,7 @@ describe('DashParser SegmentTemplate', () => {
226
226
 
227
227
  expect(fakeNetEngine.request).toHaveBeenCalledTimes(2);
228
228
  fakeNetEngine.expectRangeRequest(
229
- 'http://example.com/index-500.mp4', 0, null);
229
+ 'http://example.com/index-500.mp4', 0, null, /* isInit= */ false);
230
230
  });
231
231
 
232
232
  it('requests init data for WebM', async () => {
@@ -261,9 +261,9 @@ describe('DashParser SegmentTemplate', () => {
261
261
 
262
262
  expect(fakeNetEngine.request).toHaveBeenCalledTimes(3);
263
263
  fakeNetEngine.expectRangeRequest(
264
- 'http://example.com/init-500.webm', 0, null);
264
+ 'http://example.com/init-500.webm', 0, null, /* isInit= */ true);
265
265
  fakeNetEngine.expectRangeRequest(
266
- 'http://example.com/index-500.webm', 0, null);
266
+ 'http://example.com/index-500.webm', 0, null, /* isInit= */ false);
267
267
  });
268
268
 
269
269
  it('inherits from Period', async () => {
@@ -295,7 +295,7 @@ describe('DashParser SegmentTemplate', () => {
295
295
 
296
296
  expect(fakeNetEngine.request).toHaveBeenCalledTimes(2);
297
297
  fakeNetEngine.expectRangeRequest(
298
- 'http://example.com/index-500.mp4', 0, null);
298
+ 'http://example.com/index-500.mp4', 0, null, /* isInit= */ false);
299
299
  });
300
300
 
301
301
  it('inherits from AdaptationSet', async () => {
@@ -327,7 +327,7 @@ describe('DashParser SegmentTemplate', () => {
327
327
 
328
328
  expect(fakeNetEngine.request).toHaveBeenCalledTimes(2);
329
329
  fakeNetEngine.expectRangeRequest(
330
- 'http://example.com/index-500.mp4', 0, null);
330
+ 'http://example.com/index-500.mp4', 0, null, /* isInit= */ false);
331
331
  });
332
332
  });
333
333
 
@@ -578,4 +578,284 @@ describe('DashParser SegmentTemplate', () => {
578
578
  await Dash.testFails(source, error);
579
579
  });
580
580
  });
581
+
582
+ describe('TimelineSegmentIndex', () => {
583
+ describe('find', () => {
584
+ it('finds the correct references', async () => {
585
+ const info = makeTemplateInfo(makeRanges(0, 2.0, 10));
586
+ const infoClone = shaka.util.ObjectUtils.cloneObject(info);
587
+ const index = await makeTimelineSegmentIndex(infoClone,
588
+ /* delayPeriodEnd= */ true,
589
+ /* shouldFit= */ true);
590
+
591
+ const pos1 = index.find(1.0);
592
+ expect(pos1).toBe(0);
593
+ const pos2 = index.find(2.0);
594
+ expect(pos2).toBe(1);
595
+
596
+ // After the end of the last reference but before the end of the period
597
+ // should return index of the last reference
598
+ const lastRef = info.timeline[info.timeline.length - 1];
599
+ const pos3 = index.find(lastRef.end + 0.5);
600
+ expect(pos3).toBe(info.timeline.length - 1);
601
+
602
+ const pos4 = index.find(123.45);
603
+ expect(pos4).toBeNull();
604
+ });
605
+
606
+ it('finds correct position if time is in gap', async () => {
607
+ const ranges = [
608
+ {
609
+ start: 0,
610
+ end: 2,
611
+ unscaledStart: 0,
612
+ },
613
+ {
614
+ start: 3,
615
+ end: 5,
616
+ unscaledStart: 3 * 90000,
617
+ },
618
+ ];
619
+ const info = makeTemplateInfo(ranges);
620
+ const index = await makeTimelineSegmentIndex(info);
621
+ const pos = index.find(2.5);
622
+ expect(pos).toBe(0);
623
+ });
624
+
625
+ it('finds correct position if time === first start time', async () => {
626
+ const info = makeTemplateInfo(makeRanges(0, 2.0, 10));
627
+ const index = await makeTimelineSegmentIndex(info);
628
+
629
+ const pos = index.find(0);
630
+ expect(pos).toBe(0);
631
+ });
632
+
633
+ it('finds correct position if time === first end time', async () => {
634
+ const ranges = [
635
+ {
636
+ start: 0,
637
+ end: 2,
638
+ unscaledStart: 0,
639
+ },
640
+ {
641
+ start: 2.1,
642
+ end: 5,
643
+ unscaledStart: 3 * 90000,
644
+ },
645
+ ];
646
+ const info = makeTemplateInfo(ranges);
647
+ const index = await makeTimelineSegmentIndex(info);
648
+
649
+ const pos = index.find(2.0);
650
+ expect(pos).toBe(0);
651
+ });
652
+
653
+ it('finds correct position if time === second start time', async () => {
654
+ const ranges = [
655
+ {
656
+ start: 0,
657
+ end: 2,
658
+ unscaledStart: 0,
659
+ },
660
+ {
661
+ start: 2.1,
662
+ end: 5,
663
+ unscaledStart: 3 * 90000,
664
+ },
665
+ ];
666
+ const info = makeTemplateInfo(ranges);
667
+ const index = await makeTimelineSegmentIndex(info);
668
+
669
+ const pos = index.find(2.1);
670
+ expect(pos).toBe(1);
671
+ });
672
+
673
+
674
+ it('returns null if time === last end time', async () => {
675
+ const info = makeTemplateInfo(makeRanges(0, 2.0, 2));
676
+ const index = await makeTimelineSegmentIndex(info, false);
677
+
678
+ const pos = index.find(4.0);
679
+ expect(pos).toBeNull();
680
+ });
681
+
682
+ it('returns null if time > last end time', async () => {
683
+ const info = makeTemplateInfo(makeRanges(0, 2.0, 2));
684
+ const index = await makeTimelineSegmentIndex(info, false);
685
+
686
+ const pos = index.find(6.0);
687
+ expect(pos).toBeNull();
688
+ });
689
+ });
690
+ describe('get', () => {
691
+ it('creates a segment reference for a given position', async () => {
692
+ const info = makeTemplateInfo(makeRanges(0, 2.0, 10));
693
+ const index = await makeTimelineSegmentIndex(info);
694
+ const pos = index.find(2.0);
695
+ goog.asserts.assert(pos != null, 'Null position!');
696
+ const ref = index.get(pos);
697
+ expect(ref).toEqual(jasmine.objectContaining({
698
+ 'startTime': 2,
699
+ 'endTime': 4,
700
+ 'trueEndTime': 4,
701
+ 'startByte': 0,
702
+ 'endByte': null,
703
+ 'timestampOffset': 0,
704
+ 'appendWindowStart': 0,
705
+ 'appendWindowEnd': 21,
706
+ 'partialReferences': [],
707
+ 'tilesLayout': '',
708
+ 'tileDuration': null,
709
+ }));
710
+ });
711
+
712
+ it('returns null if a position is unknown', async () => {
713
+ const info = makeTemplateInfo(makeRanges(0, 2.0, 10));
714
+ const index = await makeTimelineSegmentIndex(info);
715
+ const ref = index.get(12345);
716
+ expect(ref).toBeNull();
717
+ });
718
+
719
+ it('returns null if a position < 0', async () => {
720
+ const info = makeTemplateInfo(makeRanges(0, 2.0, 10));
721
+ const index = await makeTimelineSegmentIndex(info);
722
+ const ref = index.get(-12);
723
+ expect(ref).toBeNull();
724
+ });
725
+ });
726
+
727
+ describe('appendTemplateInfo', () => {
728
+ it('appends new timeline to existing', async () => {
729
+ const initialRanges = makeRanges(0, 2.0, 10);
730
+ const info = makeTemplateInfo(initialRanges);
731
+ const index = await makeTimelineSegmentIndex(info, false);
732
+
733
+ const newStart = initialRanges[initialRanges.length - 1].end;
734
+ expect(index.find(newStart)).toBeNull();
735
+
736
+ const newRanges = makeRanges(newStart, 2.0, 10);
737
+ const newTemplateInfo = makeTemplateInfo(newRanges);
738
+
739
+ const newEnd = newRanges[newRanges.length - 1].end;
740
+ index.appendTemplateInfo(newTemplateInfo, newEnd);
741
+ expect(index.find(newStart)).toBe(10);
742
+ expect(index.find(newEnd - 1.0)).toBe(19);
743
+ });
744
+ });
745
+
746
+ describe('evict', () => {
747
+ it('evicts old entries and maintains position', async () => {
748
+ const initialRanges = makeRanges(0, 2.0, 10);
749
+ const info = makeTemplateInfo(initialRanges);
750
+ const index = await makeTimelineSegmentIndex(info, false);
751
+
752
+ index.evict(4.0);
753
+ expect(index.find(2.0)).toBe(2);
754
+ expect(index.find(6.0)).toBe(3);
755
+ });
756
+ });
757
+ });
758
+
759
+ /**
760
+ *
761
+ * @param {shaka.dash.SegmentTemplate.SegmentTemplateInfo} info
762
+ * @param {boolean} delayPeriodEnd
763
+ * @param {boolean} shouldFit
764
+ * @return {?}
765
+ */
766
+ async function makeTimelineSegmentIndex(info, delayPeriodEnd = true,
767
+ shouldFit = false) {
768
+ // Period end may be a bit after the last timeline entry
769
+ let periodEnd = info.timeline[info.timeline.length - 1].end;
770
+ if (delayPeriodEnd) {
771
+ periodEnd += 1.0;
772
+ }
773
+
774
+ const dummySource = Dash.makeSimpleManifestText([
775
+ '<SegmentTemplate startNumber="0" duration="10"',
776
+ ' media="$Number$-$Time$-$Bandwidth$.mp4">',
777
+ ' <SegmentTimeline>',
778
+ ' <S t="0" d="15" r="2" />',
779
+ ' </SegmentTimeline>',
780
+ '</SegmentTemplate>',
781
+ ], /* duration= */ 45);
782
+
783
+ fakeNetEngine.setResponseText('dummy://foo', dummySource);
784
+ const manifest = await parser.start('dummy://foo', playerInterface);
785
+
786
+ expect(manifest.variants.length).toBe(1);
787
+
788
+ const stream = manifest.variants[0].video;
789
+ expect(stream).toBeTruthy();
790
+ await stream.createSegmentIndex();
791
+
792
+ /** @type {?} */
793
+ const index = stream.segmentIndex;
794
+ index.release();
795
+ index.appendTemplateInfo(info, info.timeline[0].start,
796
+ periodEnd, shouldFit);
797
+
798
+ return index;
799
+ }
581
800
  });
801
+
802
+ /**
803
+ * Creates a URI string.
804
+ *
805
+ * @param {number} x
806
+ * @return {string}
807
+ */
808
+ function uri(x) {
809
+ return 'http://example.com/video_' + x + '.m4s';
810
+ }
811
+
812
+ /**
813
+ *
814
+ * @return {shaka.media.InitSegmentReference}
815
+ */
816
+ function makeInitSegmentReference() {
817
+ return new shaka.media.InitSegmentReference(() => [], 0, null);
818
+ }
819
+
820
+ /**
821
+ * Create a list of continuous time ranges
822
+ * @param {number} start
823
+ * @param {number} duration
824
+ * @param {number} num
825
+ * @return {Array<shaka.media.PresentationTimeline.TimeRange>}
826
+ */
827
+ function makeRanges(start, duration, num) {
828
+ const ranges = [];
829
+ let currentPos = start;
830
+ for (let i = 0; i < num; i += 1) {
831
+ ranges.push({
832
+ start: currentPos,
833
+ end: currentPos + duration,
834
+ unscaledStart: currentPos * 90000,
835
+ });
836
+ currentPos += duration;
837
+ }
838
+ return ranges;
839
+ }
840
+
841
+ /**
842
+ * Creates a real SegmentReference. This is distinct from the fake ones used
843
+ * in ManifestParser tests because it can be on the left-hand side of an
844
+ * expect(). You can't expect jasmine.any(Number) to equal
845
+ * jasmine.any(Number). :-(
846
+ *
847
+ * @param {Array<shaka.media.PresentationTimeline.TimeRange>} timeline
848
+ * @return {shaka.dash.SegmentTemplate.SegmentTemplateInfo}
849
+ */
850
+ function makeTemplateInfo(timeline) {
851
+ return {
852
+ 'segmentDuration': null,
853
+ 'timescale': 90000,
854
+ 'startNumber': 1,
855
+ 'scaledPresentationTimeOffset': 0,
856
+ 'unscaledPresentationTimeOffset': 0,
857
+ 'timeline': timeline,
858
+ 'mediaTemplate': 'master_540_2997_$Number%09d$.cmfv',
859
+ 'indexTemplate': null,
860
+ };
861
+ }
@@ -95,8 +95,12 @@ describe('Demo', () => {
95
95
  .add('playRangeEnd')
96
96
  .add('manifest.dash.keySystemsByURI')
97
97
  .add('manifest.hls.mediaPlaylistFullMimeType')
98
+ .add('manifest.mss.keySystemsBySystemId')
98
99
  .add('drm.keySystemsMapping')
99
- .add('streaming.parsePrftBox');
100
+ .add('streaming.parsePrftBox')
101
+ .add('manifest.raiseFatalErrorOnManifestUpdateRequestFailure')
102
+ .add('drm.persistentSessionOnlinePlayback')
103
+ .add('drm.persistentSessionsMetadata');
100
104
 
101
105
  /**
102
106
  * @param {!Object} section