shaka-player 4.3.11 → 4.4.1

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 (315) hide show
  1. package/AUTHORS +9 -0
  2. package/CHANGELOG.md +303 -202
  3. package/CONTRIBUTORS +8 -0
  4. package/LICENSE +32 -0
  5. package/README.md +63 -10
  6. package/demo/autoTemplate.txt +40 -5
  7. package/demo/close_button.js +11 -0
  8. package/demo/common/asset.js +13 -1
  9. package/demo/common/assets.js +53 -3
  10. package/demo/common/message_ids.js +25 -1
  11. package/demo/config.js +69 -10
  12. package/demo/customWarning.txt +2 -2
  13. package/demo/index.html +3 -1
  14. package/demo/locales/en.json +26 -2
  15. package/demo/locales/source.json +105 -9
  16. package/demo/main.js +52 -9
  17. package/demo/search.js +3 -1
  18. package/demo/service_worker.js +3 -0
  19. package/dist/controls.css +1 -1
  20. package/dist/controls.css.map +1 -1
  21. package/dist/demo.compiled.debug.js +124 -112
  22. package/dist/demo.compiled.debug.map +3 -3
  23. package/dist/demo.compiled.js +124 -112
  24. package/dist/demo.compiled.map +3 -3
  25. package/dist/deps.js +46 -28
  26. package/dist/locales.js +33 -33
  27. package/dist/receiver.compiled.debug.js +52 -46
  28. package/dist/receiver.compiled.debug.map +3 -3
  29. package/dist/receiver.compiled.js +52 -46
  30. package/dist/receiver.compiled.map +3 -3
  31. package/dist/shaka-player.compiled.d.ts +676 -391
  32. package/dist/shaka-player.compiled.debug.d.ts +676 -391
  33. package/dist/shaka-player.compiled.debug.externs.js +1188 -616
  34. package/dist/shaka-player.compiled.debug.js +1043 -699
  35. package/dist/shaka-player.compiled.debug.map +4 -4
  36. package/dist/shaka-player.compiled.externs.js +1188 -616
  37. package/dist/shaka-player.compiled.js +1091 -929
  38. package/dist/shaka-player.compiled.map +4 -4
  39. package/dist/shaka-player.ui.d.ts +677 -392
  40. package/dist/shaka-player.ui.debug.d.ts +677 -392
  41. package/dist/shaka-player.ui.debug.externs.js +1023 -451
  42. package/dist/shaka-player.ui.debug.js +1098 -737
  43. package/dist/shaka-player.ui.debug.map +4 -4
  44. package/dist/shaka-player.ui.externs.js +1023 -451
  45. package/dist/shaka-player.ui.js +1246 -1071
  46. package/dist/shaka-player.ui.map +4 -4
  47. package/docs/tutorials/ad_monetization.md +15 -1
  48. package/docs/tutorials/application-level-redirects.md +1 -1
  49. package/docs/tutorials/config.md +9 -5
  50. package/docs/tutorials/drm-config.md +61 -0
  51. package/docs/tutorials/fairplay.md +19 -4
  52. package/docs/tutorials/license-server-auth.md +4 -4
  53. package/docs/tutorials/license-wrapping.md +2 -2
  54. package/docs/tutorials/ui-customization.md +7 -3
  55. package/docs/tutorials/ui.md +7 -7
  56. package/docs/tutorials/upgrade.md +3 -0
  57. package/externs/ima.js +123 -2
  58. package/externs/isoboxer.js +217 -0
  59. package/externs/mediakeys.js +18 -0
  60. package/externs/mux.js +1 -105
  61. package/externs/pictureinpicture.js +48 -0
  62. package/externs/shaka/ads.js +61 -1
  63. package/externs/shaka/cea.js +110 -0
  64. package/externs/shaka/codecs.js +32 -0
  65. package/externs/shaka/manifest.js +101 -1
  66. package/externs/shaka/manifest_parser.js +0 -10
  67. package/externs/shaka/net.js +36 -7
  68. package/externs/shaka/offline.js +8 -1
  69. package/externs/shaka/player.js +220 -21
  70. package/externs/shaka/text.js +1 -382
  71. package/externs/shaka/transmuxer.js +60 -0
  72. package/karma.conf.js +13 -0
  73. package/lib/abr/simple_abr_manager.js +6 -3
  74. package/lib/ads/ad_manager.js +60 -2
  75. package/lib/ads/client_side_ad.js +86 -0
  76. package/lib/ads/client_side_ad_manager.js +79 -3
  77. package/lib/ads/server_side_ad.js +86 -0
  78. package/lib/ads/server_side_ad_manager.js +13 -0
  79. package/lib/cast/cast_utils.js +1 -0
  80. package/lib/cea/cea608_data_channel.js +24 -14
  81. package/lib/cea/cea608_memory.js +5 -2
  82. package/lib/cea/cea708_service.js +8 -9
  83. package/lib/cea/cea708_window.js +1 -2
  84. package/lib/cea/cea_decoder.js +23 -6
  85. package/lib/cea/cea_utils.js +25 -2
  86. package/lib/cea/dummy_caption_decoder.js +21 -0
  87. package/lib/cea/dummy_cea_parser.js +1 -3
  88. package/lib/cea/mp4_cea_parser.js +15 -10
  89. package/lib/cea/ts_cea_parser.js +69 -0
  90. package/lib/dash/content_protection.js +32 -2
  91. package/lib/dash/dash_parser.js +93 -31
  92. package/lib/dash/mpd_utils.js +6 -25
  93. package/lib/dash/segment_base.js +12 -14
  94. package/lib/dash/segment_list.js +10 -6
  95. package/lib/dash/segment_template.js +349 -32
  96. package/lib/dependencies/all.js +8 -0
  97. package/lib/hls/hls_classes.js +33 -8
  98. package/lib/hls/hls_parser.js +805 -191
  99. package/lib/hls/manifest_text_parser.js +4 -14
  100. package/lib/media/adaptation_set_criteria.js +43 -3
  101. package/lib/media/closed_caption_parser.js +74 -12
  102. package/lib/media/drm_engine.js +189 -49
  103. package/lib/media/gap_jumping_controller.js +1 -1
  104. package/lib/media/manifest_parser.js +34 -0
  105. package/lib/media/media_source_capabilities.js +10 -0
  106. package/lib/media/media_source_engine.js +495 -231
  107. package/lib/media/playhead.js +1 -1
  108. package/lib/media/presentation_timeline.js +62 -0
  109. package/lib/media/segment_index.js +50 -14
  110. package/lib/media/segment_prefetch.js +277 -0
  111. package/lib/media/segment_reference.js +70 -4
  112. package/lib/media/streaming_engine.js +258 -81
  113. package/lib/media/video_wrapper.js +15 -7
  114. package/lib/mss/content_protection.js +353 -0
  115. package/lib/mss/mss_parser.js +1082 -0
  116. package/lib/net/networking_engine.js +60 -10
  117. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  118. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  119. package/lib/offline/manifest_converter.js +6 -0
  120. package/lib/offline/storage.js +2 -4
  121. package/lib/player.js +309 -105
  122. package/lib/polyfill/media_capabilities.js +43 -3
  123. package/lib/polyfill/patchedmediakeys_apple.js +5 -0
  124. package/lib/polyfill/patchedmediakeys_nop.js +5 -0
  125. package/lib/polyfill/patchedmediakeys_webkit.js +5 -0
  126. package/lib/text/cue.js +208 -130
  127. package/lib/text/lrc_text_parser.js +2 -2
  128. package/lib/text/mp4_vtt_parser.js +2 -2
  129. package/lib/text/sbv_text_parser.js +1 -1
  130. package/lib/text/simple_text_displayer.js +1 -1
  131. package/lib/text/srt_text_parser.js +9 -1
  132. package/lib/text/ssa_text_parser.js +2 -2
  133. package/lib/text/text_engine.js +3 -21
  134. package/lib/text/text_utils.js +71 -20
  135. package/lib/text/ui_text_displayer.js +14 -14
  136. package/lib/text/vtt_text_parser.js +22 -14
  137. package/lib/transmuxer/aac_transmuxer.js +224 -0
  138. package/lib/transmuxer/ac3.js +142 -0
  139. package/lib/transmuxer/ac3_transmuxer.js +213 -0
  140. package/lib/transmuxer/adts.js +232 -0
  141. package/lib/transmuxer/ec3.js +103 -0
  142. package/lib/transmuxer/ec3_transmuxer.js +213 -0
  143. package/lib/transmuxer/h264.js +324 -0
  144. package/lib/transmuxer/mp3_transmuxer.js +205 -0
  145. package/lib/transmuxer/mpeg_audio.js +196 -0
  146. package/lib/transmuxer/mpeg_ts_transmuxer.js +182 -0
  147. package/lib/transmuxer/mss_transmuxer.js +389 -0
  148. package/lib/{media/transmuxer.js → transmuxer/muxjs_transmuxer.js} +34 -80
  149. package/lib/transmuxer/transmuxer_engine.js +161 -0
  150. package/lib/transmuxer/ts_transmuxer.js +721 -0
  151. package/lib/util/cmcd_manager.js +131 -71
  152. package/lib/util/error.js +62 -26
  153. package/lib/util/exp_golomb.js +220 -0
  154. package/lib/util/fairplay_utils.js +64 -13
  155. package/lib/util/id3_utils.js +56 -3
  156. package/lib/util/language_utils.js +11 -8
  157. package/lib/util/manifest_parser_utils.js +3 -0
  158. package/lib/util/mime_utils.js +44 -7
  159. package/lib/util/mp4_box_parsers.js +233 -5
  160. package/lib/util/mp4_generator.js +1388 -0
  161. package/lib/util/periods.js +40 -34
  162. package/lib/util/platform.js +17 -3
  163. package/lib/util/player_configuration.js +38 -1
  164. package/lib/util/stream_utils.js +138 -27
  165. package/lib/util/text_parser.js +1 -1
  166. package/lib/util/ts_parser.js +460 -74
  167. package/lib/util/xml_utils.js +16 -3
  168. package/maintained-branches.md +2 -2
  169. package/package.json +3 -1
  170. package/roadmap.md +21 -6
  171. package/shaka-player.uncompiled.js +18 -0
  172. package/test/abr/simple_abr_manager_unit.js +32 -4
  173. package/test/ads/ad_manager_unit.js +18 -2
  174. package/test/cast/cast_utils_unit.js +7 -2
  175. package/test/cea/cea608_memory_unit.js +24 -0
  176. package/test/cea/cea_decoder_unit.js +33 -0
  177. package/test/dash/dash_parser_content_protection_unit.js +93 -3
  178. package/test/dash/dash_parser_live_unit.js +56 -13
  179. package/test/dash/dash_parser_manifest_unit.js +70 -2
  180. package/test/dash/dash_parser_segment_base_unit.js +14 -9
  181. package/test/dash/dash_parser_segment_template_unit.js +286 -6
  182. package/test/demo/demo_unit.js +5 -1
  183. package/test/hls/hls_live_unit.js +188 -28
  184. package/test/hls/hls_parser_unit.js +250 -109
  185. package/test/hls/manifest_text_parser_unit.js +18 -13
  186. package/test/media/adaptation_set_criteria_unit.js +46 -14
  187. package/test/media/adaptation_set_unit.js +2 -0
  188. package/test/media/drm_engine_integration.js +11 -8
  189. package/test/media/drm_engine_unit.js +220 -7
  190. package/test/media/media_source_engine_integration.js +124 -40
  191. package/test/media/media_source_engine_unit.js +133 -153
  192. package/test/media/playhead_unit.js +3 -0
  193. package/test/media/presentation_timeline_unit.js +51 -0
  194. package/test/media/segment_index_unit.js +52 -0
  195. package/test/media/segment_prefetch_unit.js +243 -0
  196. package/test/media/streaming_engine_integration.js +9 -3
  197. package/test/media/streaming_engine_unit.js +440 -59
  198. package/test/mss/mss_parser_content_protection_unit.js +49 -0
  199. package/test/mss/mss_parser_unit.js +472 -0
  200. package/test/mss/mss_player_integration.js +123 -0
  201. package/test/offline/manifest_convert_unit.js +9 -0
  202. package/test/offline/storage_integration.js +6 -1
  203. package/test/player_unit.js +386 -133
  204. package/test/polyfill/media_capabilities_unit.js +18 -0
  205. package/test/test/assets/hls-raw-aac/fileSequence0.aac +0 -0
  206. package/test/test/assets/hls-raw-aac/fileSequence1.aac +0 -0
  207. package/test/test/assets/hls-raw-aac/fileSequence2.aac +0 -0
  208. package/test/test/assets/hls-raw-aac/fileSequence3.aac +0 -0
  209. package/test/test/assets/hls-raw-aac/manifest.m3u8 +4 -0
  210. package/test/test/assets/hls-raw-aac/stream.m4a.m3u8 +14 -0
  211. package/test/test/assets/hls-raw-ac3/fileSequence0.ac3 +0 -0
  212. package/test/test/assets/hls-raw-ac3/fileSequence1.ac3 +0 -0
  213. package/test/test/assets/hls-raw-ac3/fileSequence2.ac3 +0 -0
  214. package/test/test/assets/hls-raw-ac3/fileSequence3.ac3 +0 -0
  215. package/test/test/assets/hls-raw-ac3/fileSequence4.ac3 +0 -0
  216. package/test/test/assets/hls-raw-ac3/fileSequence5.ac3 +0 -0
  217. package/test/test/assets/hls-raw-ac3/fileSequence6.ac3 +0 -0
  218. package/test/test/assets/hls-raw-ac3/fileSequence7.ac3 +0 -0
  219. package/test/test/assets/hls-raw-ac3/prog_index.m3u8 +31 -0
  220. package/test/test/assets/hls-raw-ec3/fileSequence0.ec3 +0 -0
  221. package/test/test/assets/hls-raw-ec3/fileSequence1.ec3 +0 -0
  222. package/test/test/assets/hls-raw-ec3/fileSequence2.ec3 +0 -0
  223. package/test/test/assets/hls-raw-ec3/fileSequence3.ec3 +0 -0
  224. package/test/test/assets/hls-raw-ec3/fileSequence4.ec3 +0 -0
  225. package/test/test/assets/hls-raw-ec3/fileSequence5.ec3 +0 -0
  226. package/test/test/assets/hls-raw-ec3/fileSequence6.ec3 +0 -0
  227. package/test/test/assets/hls-raw-ec3/fileSequence7.ec3 +0 -0
  228. package/test/test/assets/hls-raw-ec3/prog_index.m3u8 +31 -0
  229. package/test/test/assets/hls-raw-mp3/chunklist_w905519204.m3u8 +13 -0
  230. package/test/test/assets/hls-raw-mp3/media_w905519204_0.mp3 +0 -0
  231. package/test/test/assets/hls-raw-mp3/media_w905519204_1.mp3 +0 -0
  232. package/test/test/assets/hls-raw-mp3/media_w905519204_2.mp3 +0 -0
  233. package/test/test/assets/hls-raw-mp3/media_w905519204_3.mp3 +0 -0
  234. package/test/test/assets/hls-raw-mp3/playlist.m3u8 +4 -0
  235. package/test/test/assets/hls-ts-aac/playlist.m3u8 +23 -0
  236. package/test/test/assets/hls-ts-aac/segment_0.ts +0 -0
  237. package/test/test/assets/hls-ts-aac/segment_1.ts +0 -0
  238. package/test/test/assets/hls-ts-aac/segment_2.ts +0 -0
  239. package/test/test/assets/hls-ts-aac/segment_3.ts +0 -0
  240. package/test/test/assets/hls-ts-aac/segment_4.ts +0 -0
  241. package/test/test/assets/hls-ts-aac/segment_5.ts +0 -0
  242. package/test/test/assets/hls-ts-aac/segment_6.ts +0 -0
  243. package/test/test/assets/hls-ts-aac/segment_7.ts +0 -0
  244. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0000.ts +0 -0
  245. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0001.ts +0 -0
  246. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0002.ts +0 -0
  247. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0003.ts +0 -0
  248. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0004.ts +0 -0
  249. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0005.ts +0 -0
  250. package/test/test/assets/hls-ts-ac3/prog_index.m3u8 +19 -0
  251. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0000.ts +0 -0
  252. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0001.ts +0 -0
  253. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0002.ts +0 -0
  254. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0003.ts +0 -0
  255. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0004.ts +0 -0
  256. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0005.ts +0 -0
  257. package/test/test/assets/hls-ts-ec3/prog_index.m3u8 +19 -0
  258. package/test/test/assets/hls-ts-h264/fileSequence0.ts +0 -0
  259. package/test/test/assets/hls-ts-h264/fileSequence1.ts +0 -0
  260. package/test/test/assets/hls-ts-h264/fileSequence2.ts +0 -0
  261. package/test/test/assets/hls-ts-h264/fileSequence3.ts +0 -0
  262. package/test/test/assets/hls-ts-h264/fileSequence4.ts +0 -0
  263. package/test/test/assets/hls-ts-h264/fileSequence5.ts +0 -0
  264. package/test/test/assets/hls-ts-h264/prog_index.m3u8 +25 -0
  265. package/test/test/assets/hls-ts-mp3/manifest.m3u8 +13 -0
  266. package/test/test/assets/hls-ts-mp3/media_w239891843_0.ts +0 -0
  267. package/test/test/assets/hls-ts-mp3/media_w239891843_1.ts +0 -0
  268. package/test/test/assets/hls-ts-mp3/media_w239891843_2.ts +0 -0
  269. package/test/test/assets/hls-ts-mp3/media_w239891843_3.ts +0 -0
  270. package/test/test/assets/hls-ts-muxed-aac-h264/chunk.m3u8 +17 -0
  271. package/test/test/assets/hls-ts-muxed-aac-h264/n_0_0_0.ts +0 -0
  272. package/test/test/assets/hls-ts-muxed-aac-h264/n_1_0_0.ts +0 -0
  273. package/test/test/assets/hls-ts-muxed-aac-h264/n_2_0_0.ts +0 -0
  274. package/test/test/assets/hls-ts-muxed-aac-h264/n_3_0_0.ts +0 -0
  275. package/test/test/assets/hls-ts-muxed-aac-h264/n_4_0_0.ts +0 -0
  276. package/test/test/assets/hls-ts-muxed-aac-h264/n_5_0_0.ts +0 -0
  277. package/test/test/assets/hls-ts-muxed-aac-h264/playlist.m3u8 +4 -0
  278. package/test/test/boot.js +7 -2
  279. package/test/test/util/fake_ad.js +99 -0
  280. package/test/test/util/fake_ad_manager.js +7 -1
  281. package/test/test/util/fake_networking_engine.js +41 -14
  282. package/test/test/util/fake_segment_prefetch.js +81 -0
  283. package/test/test/util/manifest_generator.js +19 -5
  284. package/test/test/util/mss_parser_util.js +115 -0
  285. package/test/test/util/offline_utils.js +1 -0
  286. package/test/test/util/simple_fakes.js +12 -3
  287. package/test/test/util/streaming_engine_util.js +14 -4
  288. package/test/test/util/ttml_utils.js +2 -2
  289. package/test/text/cue_integration.js +1 -1
  290. package/test/text/srt_text_parser_unit.js +78 -0
  291. package/test/text/text_engine_unit.js +17 -8
  292. package/test/text/ui_text_displayer_unit.js +4 -4
  293. package/test/text/vtt_text_parser_unit.js +59 -40
  294. package/test/text/web_vtt_generator_unit.js +9 -3
  295. package/test/{media/transmuxer_integration.js → transmuxer/muxjs_transmuxer_integration.js} +30 -33
  296. package/test/transmuxer/transmuxer_engine_integration.js +60 -0
  297. package/test/transmuxer/transmuxer_integration.js +296 -0
  298. package/test/util/cmcd_manager_unit.js +162 -13
  299. package/test/util/language_utils_unit.js +9 -2
  300. package/test/util/mp4_box_parsers_unit.js +39 -4
  301. package/test/util/periods_unit.js +34 -26
  302. package/test/util/stream_utils_unit.js +60 -107
  303. package/ui/controls.js +19 -1
  304. package/ui/controls.less +1 -0
  305. package/ui/externs/ui.js +11 -1
  306. package/ui/language_utils.js +15 -0
  307. package/ui/less/thumbnails.less +26 -0
  308. package/ui/locales/oc.json +42 -0
  309. package/ui/pip_button.js +83 -2
  310. package/ui/range_element.js +15 -0
  311. package/ui/resolution_selection.js +9 -2
  312. package/ui/seek_bar.js +223 -0
  313. package/ui/ui.js +5 -0
  314. package/lib/cea/i_caption_decoder.js +0 -51
  315. package/lib/cea/i_cea_parser.js +0 -68
@@ -17,6 +17,7 @@ goog.require('shaka.media.InitSegmentReference');
17
17
  goog.require('shaka.media.MediaSourceEngine');
18
18
  goog.require('shaka.media.SegmentIterator');
19
19
  goog.require('shaka.media.SegmentReference');
20
+ goog.require('shaka.media.SegmentPrefetch');
20
21
  goog.require('shaka.net.Backoff');
21
22
  goog.require('shaka.net.NetworkingEngine');
22
23
  goog.require('shaka.util.DelayedTick');
@@ -173,6 +174,21 @@ shaka.media.StreamingEngine = class {
173
174
  const autoReset = true;
174
175
  this.failureCallbackBackoff_ =
175
176
  new shaka.net.Backoff(failureRetryParams, autoReset);
177
+
178
+ // Allow configuring the segment prefetch in middle of the playback.
179
+ for (const type of this.mediaStates_.keys()) {
180
+ const state = this.mediaStates_.get(type);
181
+ if (state.segmentPrefetch) {
182
+ state.segmentPrefetch.resetLimit(config.segmentPrefetchLimit);
183
+ if (!(config.segmentPrefetchLimit > 0)) {
184
+ // ResetLimit is still needed in this case,
185
+ // to abort existing prefetch operations.
186
+ state.segmentPrefetch = null;
187
+ }
188
+ } else if (config.segmentPrefetchLimit > 0) {
189
+ state.segmentPrefetch = this.createSegmentPrefetch_(state.stream);
190
+ }
191
+ }
176
192
  }
177
193
 
178
194
 
@@ -451,6 +467,10 @@ shaka.media.StreamingEngine = class {
451
467
  return;
452
468
  }
453
469
 
470
+ if (mediaState.segmentPrefetch) {
471
+ mediaState.segmentPrefetch.switchStream(stream);
472
+ }
473
+
454
474
  if (stream.type == ContentType.TEXT) {
455
475
  // Mime types are allowed to change for text streams.
456
476
  // Reinitialize the text parser, but only if we are going to fetch the
@@ -806,10 +826,12 @@ shaka.media.StreamingEngine = class {
806
826
 
807
827
  // Init MediaSourceEngine.
808
828
  const mediaSourceEngine = this.playerInterface_.mediaSourceEngine;
809
- const forceTransmux = this.config_.forceTransmux;
810
829
 
811
- await mediaSourceEngine.init(streamsByType, forceTransmux,
812
- this.manifest_.sequenceMode);
830
+ await mediaSourceEngine.init(streamsByType,
831
+ this.manifest_.sequenceMode,
832
+ this.manifest_.type,
833
+ this.manifest_.ignoreManifestTimestampsInSegmentsMode,
834
+ );
813
835
  this.destroyer_.ensureNotDestroyed();
814
836
 
815
837
  this.updateDuration();
@@ -837,6 +859,7 @@ shaka.media.StreamingEngine = class {
837
859
  stream,
838
860
  type: stream.type,
839
861
  segmentIterator: null,
862
+ segmentPrefetch: this.createSegmentPrefetch_(stream),
840
863
  lastSegmentReference: null,
841
864
  lastInitSegmentReference: null,
842
865
  lastTimestampOffset: null,
@@ -860,6 +883,31 @@ shaka.media.StreamingEngine = class {
860
883
  });
861
884
  }
862
885
 
886
+ /**
887
+ * Creates a media state.
888
+ *
889
+ * @param {shaka.extern.Stream} stream
890
+ * @return {shaka.media.SegmentPrefetch | null}
891
+ * @private
892
+ */
893
+ createSegmentPrefetch_(stream) {
894
+ if (
895
+ stream.type !== shaka.util.ManifestParserUtils.ContentType.VIDEO &&
896
+ stream.type !== shaka.util.ManifestParserUtils.ContentType.AUDIO
897
+ ) {
898
+ return null;
899
+ }
900
+ if (this.config_.segmentPrefetchLimit > 0) {
901
+ return new shaka.media.SegmentPrefetch(
902
+ this.config_.segmentPrefetchLimit,
903
+ stream,
904
+ (reference, stream, streamDataCallback) => {
905
+ return this.dispatchFetch_(reference, stream, streamDataCallback);
906
+ },
907
+ );
908
+ }
909
+ return null;
910
+ }
863
911
 
864
912
  /**
865
913
  * Sets the MediaSource's duration.
@@ -947,7 +995,7 @@ shaka.media.StreamingEngine = class {
947
995
  mediaState.hasError = false;
948
996
  }
949
997
  } catch (error) {
950
- await this.handleStreamingError_(error);
998
+ await this.handleStreamingError_(mediaState, error);
951
999
  return;
952
1000
  }
953
1001
 
@@ -1114,6 +1162,10 @@ shaka.media.StreamingEngine = class {
1114
1162
  return this.config_.updateIntervalSeconds;
1115
1163
  }
1116
1164
 
1165
+ if (mediaState.segmentPrefetch && mediaState.segmentIterator) {
1166
+ mediaState.segmentPrefetch.prefetchSegments(reference);
1167
+ }
1168
+
1117
1169
  const p = this.fetchAndAppend_(mediaState, presentationTime, reference);
1118
1170
  p.catch(() => {}); // TODO(#1993): Handle asynchronous errors.
1119
1171
  return null;
@@ -1278,10 +1330,10 @@ shaka.media.StreamingEngine = class {
1278
1330
  stream.mimeType == 'audio/mp4';
1279
1331
  const isReadableStreamSupported = window.ReadableStream;
1280
1332
  // Enable MP4 low latency streaming with ReadableStream chunked data.
1281
- // Disabled when AES-128 is present, as we cannot decrypt part of a
1282
- // segment.
1333
+ // And only for DASH and HLS with byterange optimization.
1283
1334
  if (this.config_.lowLatencyMode && isReadableStreamSupported && isMP4 &&
1284
- !reference.hlsAes128Key) {
1335
+ (this.manifest_.type != shaka.media.ManifestParser.HLS ||
1336
+ reference.hasByterangeOptimization())) {
1285
1337
  let remaining = new Uint8Array(0);
1286
1338
  let processingResult = false;
1287
1339
  let callbackCalled = false;
@@ -1443,7 +1495,7 @@ shaka.media.StreamingEngine = class {
1443
1495
  mediaState.hasError = true;
1444
1496
 
1445
1497
  error.severity = shaka.util.Error.Severity.CRITICAL;
1446
- await this.handleStreamingError_(error);
1498
+ await this.handleStreamingError_(mediaState, error);
1447
1499
  }
1448
1500
  }
1449
1501
  }
@@ -1602,6 +1654,8 @@ shaka.media.StreamingEngine = class {
1602
1654
  * @private
1603
1655
  */
1604
1656
  async initSourceBuffer_(mediaState, reference) {
1657
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
1658
+ const MimeUtils = shaka.util.MimeUtils;
1605
1659
  const StreamingEngine = shaka.media.StreamingEngine;
1606
1660
  const logPrefix = StreamingEngine.logPrefix_(mediaState);
1607
1661
 
@@ -1620,28 +1674,69 @@ shaka.media.StreamingEngine = class {
1620
1674
  reference.startTime <= appendWindowEnd,
1621
1675
  logPrefix + ' segment should start before append window end');
1622
1676
 
1677
+ const codecs = MimeUtils.getCodecBase(mediaState.stream.codecs);
1678
+ const mimeType = MimeUtils.getBasicType(mediaState.stream.mimeType);
1623
1679
  const timestampOffset = reference.timestampOffset;
1624
1680
  if (timestampOffset != mediaState.lastTimestampOffset ||
1625
1681
  appendWindowStart != mediaState.lastAppendWindowStart ||
1626
- appendWindowEnd != mediaState.lastAppendWindowEnd) {
1682
+ appendWindowEnd != mediaState.lastAppendWindowEnd ||
1683
+ codecs != mediaState.lastCodecs ||
1684
+ mimeType != mediaState.lastMimeType) {
1627
1685
  shaka.log.v1(logPrefix, 'setting timestamp offset to ' + timestampOffset);
1628
1686
  shaka.log.v1(logPrefix,
1629
1687
  'setting append window start to ' + appendWindowStart);
1630
1688
  shaka.log.v1(logPrefix,
1631
1689
  'setting append window end to ' + appendWindowEnd);
1632
1690
 
1691
+ if ((mediaState.lastCodecs && codecs != mediaState.lastCodecs) ||
1692
+ (mediaState.lastMimeType && mimeType != mediaState.lastMimeType)) {
1693
+ if (mediaState.type === ContentType.VIDEO) {
1694
+ /** @type {shaka.media.StreamingEngine.MediaState_} */
1695
+ const audioState = this.mediaStates_.get(ContentType.AUDIO);
1696
+ if (audioState) {
1697
+ audioState.lastInitSegmentReference = null;
1698
+ this.abortOperations_(audioState);
1699
+ }
1700
+ } else if (mediaState.type === ContentType.AUDIO) {
1701
+ /** @type {shaka.media.StreamingEngine.MediaState_} */
1702
+ const videoState = this.mediaStates_.get(ContentType.VIDEO);
1703
+ if (videoState) {
1704
+ videoState.lastInitSegmentReference = null;
1705
+ this.abortOperations_(videoState);
1706
+ }
1707
+ }
1708
+ }
1709
+
1633
1710
  const setProperties = async () => {
1711
+ /**
1712
+ * @type {!Map.<shaka.util.ManifestParserUtils.ContentType,
1713
+ * shaka.extern.Stream>}
1714
+ */
1715
+ const streamsByType = new Map();
1716
+ if (this.currentVariant_.audio) {
1717
+ streamsByType.set(ContentType.AUDIO, this.currentVariant_.audio);
1718
+ }
1719
+ if (this.currentVariant_.video) {
1720
+ streamsByType.set(ContentType.VIDEO, this.currentVariant_.video);
1721
+ }
1634
1722
  try {
1635
1723
  mediaState.lastAppendWindowStart = appendWindowStart;
1636
1724
  mediaState.lastAppendWindowEnd = appendWindowEnd;
1725
+ mediaState.lastCodecs = codecs;
1726
+ mediaState.lastMimeType = mimeType;
1637
1727
  mediaState.lastTimestampOffset = timestampOffset;
1638
1728
 
1729
+ const ignoreTimestampOffset = this.manifest_.sequenceMode ||
1730
+ this.manifest_.type == shaka.media.ManifestParser.HLS;
1731
+
1639
1732
  await this.playerInterface_.mediaSourceEngine.setStreamProperties(
1640
1733
  mediaState.type, timestampOffset, appendWindowStart,
1641
- appendWindowEnd, this.manifest_.sequenceMode);
1734
+ appendWindowEnd, ignoreTimestampOffset,
1735
+ mediaState.stream, streamsByType);
1642
1736
  } catch (error) {
1643
1737
  mediaState.lastAppendWindowStart = null;
1644
1738
  mediaState.lastAppendWindowEnd = null;
1739
+ mediaState.lastCodecs = null;
1645
1740
  mediaState.lastTimestampOffset = null;
1646
1741
 
1647
1742
  throw error;
@@ -1658,22 +1753,52 @@ shaka.media.StreamingEngine = class {
1658
1753
  shaka.log.v1(logPrefix, 'fetching init segment');
1659
1754
 
1660
1755
  const fetchInit =
1661
- this.fetch_(mediaState, reference.initSegmentReference);
1756
+ this.fetch_(mediaState, reference.initSegmentReference,
1757
+ /* streamDataCallback= */ undefined, /* isInit= */ true);
1662
1758
  const append = async () => {
1663
1759
  try {
1664
1760
  const initSegment = await fetchInit;
1665
1761
  this.destroyer_.ensureNotDestroyed();
1666
1762
 
1763
+ let lastTimescale = null;
1764
+ const timescaleMap = new Map();
1765
+
1667
1766
  const parser = new shaka.util.Mp4Parser();
1668
1767
  const Mp4Parser = shaka.util.Mp4Parser;
1669
1768
  parser.box('moov', Mp4Parser.children)
1670
1769
  .box('trak', Mp4Parser.children)
1671
1770
  .box('mdia', Mp4Parser.children)
1672
1771
  .fullBox('mdhd', (box) => {
1673
- this.parseMDHD_(reference, box);
1772
+ goog.asserts.assert(
1773
+ box.version != null,
1774
+ 'MDHD is a full box and should have a valid version.');
1775
+ const parsedMDHDBox = shaka.util.Mp4BoxParsers.parseMDHD(
1776
+ box.reader, box.version);
1777
+ lastTimescale = parsedMDHDBox.timescale;
1778
+ })
1779
+ .box('hdlr', (box) => {
1780
+ const parsedHDLR = shaka.util.Mp4BoxParsers.parseHDLR(
1781
+ box.reader);
1782
+ switch (parsedHDLR.handlerType) {
1783
+ case 'soun':
1784
+ timescaleMap.set(ContentType.AUDIO, lastTimescale);
1785
+ break;
1786
+ case 'vide':
1787
+ timescaleMap.set(ContentType.VIDEO, lastTimescale);
1788
+ break;
1789
+ }
1790
+ lastTimescale = null;
1674
1791
  })
1675
1792
  .parse(initSegment);
1676
1793
 
1794
+ if (timescaleMap.has(mediaState.type)) {
1795
+ reference.initSegmentReference.timescale =
1796
+ timescaleMap.get(mediaState.type);
1797
+ } else if (lastTimescale != null) {
1798
+ // Fallback for segments without HDLR box
1799
+ reference.initSegmentReference.timescale = lastTimescale;
1800
+ }
1801
+
1677
1802
  shaka.log.v1(logPrefix, 'appending init segment');
1678
1803
  const hasClosedCaptions = mediaState.stream.closedCaptions &&
1679
1804
  mediaState.stream.closedCaptions.size > 0;
@@ -1681,7 +1806,7 @@ shaka.media.StreamingEngine = class {
1681
1806
  mediaState.type, initSegment);
1682
1807
  await this.playerInterface_.mediaSourceEngine.appendBuffer(
1683
1808
  mediaState.type, initSegment, /* reference= */ null,
1684
- hasClosedCaptions);
1809
+ mediaState.stream, hasClosedCaptions);
1685
1810
  } catch (error) {
1686
1811
  mediaState.lastInitSegmentReference = null;
1687
1812
  throw error;
@@ -1706,7 +1831,7 @@ shaka.media.StreamingEngine = class {
1706
1831
  operations.push(this.playerInterface_.mediaSourceEngine.resync(
1707
1832
  mediaState.type, reference.startTime));
1708
1833
  }
1709
- } else {
1834
+ } else if (this.manifest_.ignoreManifestTimestampsInSegmentsMode) {
1710
1835
  // In segments mode, we need to resync to set the timestampOffset
1711
1836
  // to the start of the current discontinuity sequence. This is
1712
1837
  // because individual discontinuity sequences may have internal
@@ -1789,6 +1914,7 @@ shaka.media.StreamingEngine = class {
1789
1914
  mediaState.type,
1790
1915
  segment,
1791
1916
  reference,
1917
+ stream,
1792
1918
  hasClosedCaptions,
1793
1919
  seeked,
1794
1920
  adaptation,
@@ -1920,18 +2046,6 @@ shaka.media.StreamingEngine = class {
1920
2046
  }
1921
2047
  }
1922
2048
 
1923
- /**
1924
- * Parse MDHD box.
1925
- * @param {!shaka.media.SegmentReference} reference
1926
- * @param {!shaka.extern.ParsedBox} box
1927
- * @private
1928
- */
1929
- parseMDHD_(reference, box) {
1930
- const parsedMDHDBox = shaka.util.Mp4BoxParsers.parseMDHD(
1931
- box.reader || 0, box.version || 0);
1932
- reference.initSegmentReference.timescale = parsedMDHDBox.timescale;
1933
- }
1934
-
1935
2049
  /**
1936
2050
  * Parse PRFT box.
1937
2051
  * @param {!shaka.media.SegmentReference} reference
@@ -1943,30 +2057,16 @@ shaka.media.StreamingEngine = class {
1943
2057
  !reference.initSegmentReference.timescale) {
1944
2058
  return;
1945
2059
  }
1946
- box.reader.readUint32(); // Ignore referenceTrackId
1947
- const ntpTimestampSec = box.reader.readUint32();
1948
- const ntpTimestampFrac = box.reader.readUint32();
1949
- const ntpTimestamp = ntpTimestampSec * 1000 +
1950
- ntpTimestampFrac / 2**32 * 1000;
1951
-
1952
- let mediaTime;
1953
- if (box.version === 0) {
1954
- mediaTime = box.reader.readUint32();
1955
- } else {
1956
- try {
1957
- mediaTime = box.reader.readUint64();
1958
- } catch (e) {
1959
- shaka.log.warning('parsePrft_: parsing mediatime resulted in a '+
1960
- 'MEDIA.JS_INTEGER_OVERFLOW exception');
1961
- this.parsedPrftEventRaised_ = true;
1962
- return;
1963
- }
1964
- }
2060
+ goog.asserts.assert(
2061
+ box.version == 0 || box.version == 1,
2062
+ 'PRFT version can only be 0 or 1');
2063
+ const parsed = shaka.util.Mp4BoxParsers.parsePRFTInaccurate(
2064
+ box.reader, box.version);
1965
2065
 
1966
2066
  const timescale = reference.initSegmentReference.timescale;
1967
- const wallClockTime = this.convertNtp(ntpTimestamp);
2067
+ const wallClockTime = this.convertNtp(parsed.ntpTimestamp);
1968
2068
  const programStartDate = new Date(wallClockTime -
1969
- (mediaTime / timescale) * 1000);
2069
+ (parsed.mediaTime / timescale) * 1000);
1970
2070
  const prftInfo = {
1971
2071
  wallClockTime,
1972
2072
  programStartDate,
@@ -1982,11 +2082,11 @@ shaka.media.StreamingEngine = class {
1982
2082
 
1983
2083
 
1984
2084
  /**
1985
- * Convert Ntp ntpTimeStamp to UTC Time
1986
- *
1987
- * @param {number} ntpTimeStamp
1988
- * @return {number} utcTime
1989
- */
2085
+ * Convert Ntp ntpTimeStamp to UTC Time
2086
+ *
2087
+ * @param {number} ntpTimeStamp
2088
+ * @return {number} utcTime
2089
+ */
1990
2090
  convertNtp(ntpTimeStamp) {
1991
2091
  const start = new Date(Date.UTC(1900, 0, 1, 0, 0, 0));
1992
2092
  return new Date(start.getTime() + ntpTimeStamp).getTime();
@@ -2070,14 +2170,58 @@ shaka.media.StreamingEngine = class {
2070
2170
  * @param {(!shaka.media.InitSegmentReference|!shaka.media.SegmentReference)}
2071
2171
  * reference
2072
2172
  * @param {?function(BufferSource):!Promise=} streamDataCallback
2173
+ * @param {boolean=} isInit
2073
2174
  *
2074
2175
  * @return {!Promise.<BufferSource>}
2075
2176
  * @private
2076
2177
  * @suppress {strictMissingProperties}
2077
2178
  */
2078
- async fetch_(mediaState, reference, streamDataCallback) {
2079
- const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
2179
+ async fetch_(mediaState, reference, streamDataCallback, isInit) {
2180
+ if (reference instanceof shaka.media.InitSegmentReference) {
2181
+ const segmentData = reference.getSegmentData();
2182
+ if (segmentData) {
2183
+ return segmentData;
2184
+ }
2185
+ }
2186
+ let op = null;
2187
+ if (
2188
+ mediaState.segmentPrefetch &&
2189
+ reference instanceof shaka.media.SegmentReference
2190
+ ) {
2191
+ op = mediaState.segmentPrefetch.getPrefetchedSegment(
2192
+ reference, streamDataCallback);
2193
+ }
2194
+ if (!op) {
2195
+ op = this.dispatchFetch_(
2196
+ reference, mediaState.stream, streamDataCallback, isInit,
2197
+ );
2198
+ }
2199
+
2200
+ mediaState.operation = op;
2201
+ const response = await op.promise;
2202
+ mediaState.operation = null;
2203
+ return response.data;
2204
+ }
2080
2205
 
2206
+ /**
2207
+ * Fetches the given segment.
2208
+ *
2209
+ * @param {!shaka.extern.Stream} stream
2210
+ * @param {(!shaka.media.InitSegmentReference|!shaka.media.SegmentReference)}
2211
+ * reference
2212
+ * @param {?function(BufferSource):!Promise=} streamDataCallback
2213
+ * @param {boolean=} isInit
2214
+ *
2215
+ * @return {!shaka.net.NetworkingEngine.PendingRequest}
2216
+ * @private
2217
+ */
2218
+ dispatchFetch_(reference, stream, streamDataCallback, isInit) {
2219
+ const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
2220
+ const type = isInit ?
2221
+ shaka.net.NetworkingEngine.AdvancedRequestType.INIT_SEGMENT :
2222
+ shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT;
2223
+ const segment = reference instanceof shaka.media.SegmentReference ?
2224
+ reference : undefined;
2081
2225
  const request = shaka.util.Networking.createSegmentRequest(
2082
2226
  reference.getUris(),
2083
2227
  reference.startByte,
@@ -2087,27 +2231,14 @@ shaka.media.StreamingEngine = class {
2087
2231
 
2088
2232
  shaka.log.v2('fetching: reference=', reference);
2089
2233
 
2090
- const stream = mediaState.stream;
2091
- this.playerInterface_.modifySegmentRequest(
2092
- request,
2093
- {
2094
- type: stream.type,
2095
- init: reference instanceof shaka.media.InitSegmentReference,
2096
- duration: reference.endTime - reference.startTime,
2097
- mimeType: stream.mimeType,
2098
- codecs: stream.codecs,
2099
- bandwidth: stream.bandwidth,
2100
- },
2101
- );
2102
-
2103
- const op = this.playerInterface_.netEngine.request(requestType, request);
2104
- mediaState.operation = op;
2105
- const response = await op.promise;
2106
- mediaState.operation = null;
2107
- return response.data;
2234
+ return this.playerInterface_.netEngine.request(
2235
+ requestType, request, {
2236
+ type: type,
2237
+ stream: stream,
2238
+ segment: segment,
2239
+ });
2108
2240
  }
2109
2241
 
2110
-
2111
2242
  /**
2112
2243
  * Clears the buffer and schedules another update.
2113
2244
  * The optional parameter safeMargin allows to retain a certain amount
@@ -2135,6 +2266,9 @@ shaka.media.StreamingEngine = class {
2135
2266
  mediaState.segmentIterator = null;
2136
2267
 
2137
2268
  shaka.log.debug(logPrefix, 'clearing buffer');
2269
+ if (mediaState.segmentPrefetch) {
2270
+ mediaState.segmentPrefetch.clearAll();
2271
+ }
2138
2272
 
2139
2273
  if (safeMargin) {
2140
2274
  const presentationTime = this.playerInterface_.getPresentationTime();
@@ -2150,6 +2284,7 @@ shaka.media.StreamingEngine = class {
2150
2284
  mediaState.type);
2151
2285
  }
2152
2286
  }
2287
+
2153
2288
  this.destroyer_.ensureNotDestroyed();
2154
2289
 
2155
2290
  shaka.log.debug(logPrefix, 'cleared buffer');
@@ -2230,17 +2365,31 @@ shaka.media.StreamingEngine = class {
2230
2365
  * Handle streaming errors by delaying, then notifying the application by
2231
2366
  * error callback and by streaming failure callback.
2232
2367
  *
2368
+ * @param {shaka.media.StreamingEngine.MediaState_} mediaState
2233
2369
  * @param {!shaka.util.Error} error
2234
2370
  * @return {!Promise}
2235
2371
  * @private
2236
2372
  */
2237
- async handleStreamingError_(error) {
2373
+ async handleStreamingError_(mediaState, error) {
2238
2374
  // If we invoke the callback right away, the application could trigger a
2239
2375
  // rapid retry cycle that could be very unkind to the server. Instead,
2240
2376
  // use the backoff system to delay and backoff the error handling.
2241
2377
  await this.failureCallbackBackoff_.attempt();
2242
2378
  this.destroyer_.ensureNotDestroyed();
2243
2379
 
2380
+ const maxDisabledTime = this.getDisabledTime_(error);
2381
+ // Try to recover from network errors
2382
+ if (error.category === shaka.util.Error.Category.NETWORK &&
2383
+ maxDisabledTime > 0) {
2384
+ error.handled = this.playerInterface_.disableStream(
2385
+ mediaState.stream, maxDisabledTime);
2386
+
2387
+ // Decrease the error severity to recoverable
2388
+ if (error.handled) {
2389
+ error.severity = shaka.util.Error.Severity.RECOVERABLE;
2390
+ }
2391
+ }
2392
+
2244
2393
  // First fire an error event.
2245
2394
  this.playerInterface_.onError(error);
2246
2395
 
@@ -2251,6 +2400,25 @@ shaka.media.StreamingEngine = class {
2251
2400
  }
2252
2401
  }
2253
2402
 
2403
+ /**
2404
+ * @param {!shaka.util.Error} error
2405
+ * @private
2406
+ */
2407
+ getDisabledTime_(error) {
2408
+ if (this.config_.maxDisabledTime === 0 &&
2409
+ error.code == shaka.util.Error.Code.SEGMENT_MISSING) {
2410
+ // Spec: https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-6.3.3
2411
+ // The client SHOULD NOT attempt to load Media Segments that have been
2412
+ // marked with an EXT-X-GAP tag, or to load Partial Segments with a
2413
+ // GAP=YES attribute. Instead, clients are encouraged to look for
2414
+ // another Variant Stream of the same Rendition which does not have the
2415
+ // same gap, and play that instead.
2416
+ return 1;
2417
+ }
2418
+
2419
+ return this.config_.maxDisabledTime;
2420
+ }
2421
+
2254
2422
  /**
2255
2423
  * @param {shaka.media.StreamingEngine.MediaState_} mediaState
2256
2424
  * @return {string} A log prefix of the form ($CONTENT_TYPE:$STREAM_ID), e.g.,
@@ -2267,8 +2435,6 @@ shaka.media.StreamingEngine = class {
2267
2435
  * @typedef {{
2268
2436
  * getPresentationTime: function():number,
2269
2437
  * getBandwidthEstimate: function():number,
2270
- * modifySegmentRequest: function(shaka.extern.Request,
2271
- * shaka.util.CmcdManager.SegmentInfo),
2272
2438
  * mediaSourceEngine: !shaka.media.MediaSourceEngine,
2273
2439
  * netEngine: shaka.net.NetworkingEngine,
2274
2440
  * onError: function(!shaka.util.Error),
@@ -2279,7 +2445,8 @@ shaka.media.StreamingEngine = class {
2279
2445
  * onInitSegmentAppended: function(!number,!shaka.media.InitSegmentReference),
2280
2446
  * beforeAppendSegment: function(
2281
2447
  * shaka.util.ManifestParserUtils.ContentType,!BufferSource):Promise,
2282
- * onMetadata: !function(!Array.<shaka.extern.ID3Metadata>, number, ?number)
2448
+ * onMetadata: !function(!Array.<shaka.extern.ID3Metadata>, number, ?number),
2449
+ * disableStream: function(!shaka.extern.Stream, number):boolean
2283
2450
  * }}
2284
2451
  *
2285
2452
  * @property {function():number} getPresentationTime
@@ -2287,9 +2454,6 @@ shaka.media.StreamingEngine = class {
2287
2454
  * viewer is seeing on screen right now.
2288
2455
  * @property {function():number} getBandwidthEstimate
2289
2456
  * Get the estimated bandwidth in bits per second.
2290
- * @property {function(shaka.extern.Request,
2291
- * shaka.extern.Cmcd.SegmentInfo)} modifySegmentRequest
2292
- * The request modifier
2293
2457
  * @property {!shaka.media.MediaSourceEngine} mediaSourceEngine
2294
2458
  * The MediaSourceEngine. The caller retains ownership.
2295
2459
  * @property {shaka.net.NetworkingEngine} netEngine
@@ -2315,6 +2479,9 @@ shaka.media.StreamingEngine = class {
2315
2479
  * @property
2316
2480
  * {!function(!Array.<shaka.extern.ID3Metadata>, number, ?number)} onMetadata
2317
2481
  * Called when an ID3 is found in a EMSG.
2482
+ * @property {function(!shaka.extern.Stream, number):boolean} disableStream
2483
+ * Called to temporarily disable a stream i.e. disabling all variant
2484
+ * containing said stream.
2318
2485
  */
2319
2486
  shaka.media.StreamingEngine.PlayerInterface;
2320
2487
 
@@ -2329,6 +2496,8 @@ shaka.media.StreamingEngine.PlayerInterface;
2329
2496
  * lastTimestampOffset: ?number,
2330
2497
  * lastAppendWindowStart: ?number,
2331
2498
  * lastAppendWindowEnd: ?number,
2499
+ * lastCodecs: ?string,
2500
+ * lastMimeType: ?string,
2332
2501
  * restoreStreamAfterTrickPlay: ?shaka.extern.Stream,
2333
2502
  * endOfStream: boolean,
2334
2503
  * performingUpdate: boolean,
@@ -2342,7 +2511,8 @@ shaka.media.StreamingEngine.PlayerInterface;
2342
2511
  * adaptation: boolean,
2343
2512
  * recovering: boolean,
2344
2513
  * hasError: boolean,
2345
- * operation: shaka.net.NetworkingEngine.PendingRequest
2514
+ * operation: shaka.net.NetworkingEngine.PendingRequest,
2515
+ * segmentPrefetch: shaka.media.SegmentPrefetch
2346
2516
  * }}
2347
2517
  *
2348
2518
  * @description
@@ -2366,6 +2536,10 @@ shaka.media.StreamingEngine.PlayerInterface;
2366
2536
  * The last append window start given to MediaSourceEngine for this type.
2367
2537
  * @property {?number} lastAppendWindowEnd
2368
2538
  * The last append window end given to MediaSourceEngine for this type.
2539
+ * @property {?string} lastCodecs
2540
+ * The last append codecs given to MediaSourceEngine for this type.
2541
+ * @property {?string} lastMimeType
2542
+ * The last append mime type given to MediaSourceEngine for this type.
2369
2543
  * @property {?shaka.extern.Stream} restoreStreamAfterTrickPlay
2370
2544
  * The Stream to restore after trick play mode is turned off.
2371
2545
  * @property {boolean} endOfStream
@@ -2399,6 +2573,9 @@ shaka.media.StreamingEngine.PlayerInterface;
2399
2573
  * updating.
2400
2574
  * @property {shaka.net.NetworkingEngine.PendingRequest} operation
2401
2575
  * Operation with the number of bytes to be downloaded.
2576
+ * @property {?shaka.media.SegmentPrefetch} segmentPrefetch
2577
+ * A prefetch object for managing prefetching. Null if unneeded
2578
+ * (if prefetching is disabled, etc).
2402
2579
  */
2403
2580
  shaka.media.StreamingEngine.MediaState_;
2404
2581
 
@@ -28,9 +28,9 @@ shaka.media.VideoWrapper = class {
28
28
  * @param {!HTMLMediaElement} video
29
29
  * @param {function()} onSeek Called when the video seeks.
30
30
  * @param {function(number)} onStarted Called when the video has started.
31
- * @param {number} startTime The time to start at.
31
+ * @param {function():number} getStartTime Calle to get the time to start at.
32
32
  */
33
- constructor(video, onSeek, onStarted, startTime) {
33
+ constructor(video, onSeek, onStarted, getStartTime) {
34
34
  /** @private {HTMLMediaElement} */
35
35
  this.video_ = video;
36
36
 
@@ -40,8 +40,16 @@ shaka.media.VideoWrapper = class {
40
40
  /** @private {function(number)} */
41
41
  this.onStarted_ = onStarted;
42
42
 
43
- /** @private {number} */
44
- this.startTime_ = startTime;
43
+ /** @private {?number} */
44
+ this.startTime_ = null;
45
+
46
+ /** @private {function():number} */
47
+ this.getStartTime_ = () => {
48
+ if (this.startTime_ == null) {
49
+ this.startTime_ = getStartTime();
50
+ }
51
+ return this.startTime_;
52
+ };
45
53
 
46
54
  /** @private {boolean} */
47
55
  this.started_ = false;
@@ -62,7 +70,7 @@ shaka.media.VideoWrapper = class {
62
70
  HTMLMediaElement.HAVE_METADATA,
63
71
  this.eventManager_,
64
72
  () => {
65
- this.setStartTime_(this.startTime_);
73
+ this.setStartTime_(this.getStartTime_());
66
74
  });
67
75
  }
68
76
 
@@ -90,7 +98,7 @@ shaka.media.VideoWrapper = class {
90
98
  * @return {number}
91
99
  */
92
100
  getTime() {
93
- return this.started_ ? this.video_.currentTime : this.startTime_;
101
+ return this.started_ ? this.video_.currentTime : this.getStartTime_();
94
102
  }
95
103
 
96
104
 
@@ -107,7 +115,7 @@ shaka.media.VideoWrapper = class {
107
115
  HTMLMediaElement.HAVE_METADATA,
108
116
  this.eventManager_,
109
117
  () => {
110
- this.setStartTime_(this.startTime_);
118
+ this.setStartTime_(this.getStartTime_());
111
119
  });
112
120
  }
113
121
  }