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
@@ -42,7 +42,13 @@ describe('MediaSourceEngine', () => {
42
42
  const originalCreateMediaSource =
43
43
  // eslint-disable-next-line no-restricted-syntax
44
44
  shaka.media.MediaSourceEngine.prototype.createMediaSource;
45
- const originalTransmuxer = shaka.media.Transmuxer;
45
+
46
+ const originalFindTransmuxer =
47
+ shaka.transmuxer.TransmuxerEngine.findTransmuxer;
48
+ const originalConvertCodecs =
49
+ shaka.transmuxer.TransmuxerEngine.convertCodecs;
50
+ const originalIsSupported =
51
+ shaka.transmuxer.TransmuxerEngine.isSupported;
46
52
 
47
53
  // Jasmine Spies don't handle toHaveBeenCalledWith well with objects, so use
48
54
  // some numbers instead.
@@ -50,11 +56,14 @@ describe('MediaSourceEngine', () => {
50
56
  const buffer2 = /** @type {!ArrayBuffer} */ (/** @type {?} */ (2));
51
57
  const buffer3 = /** @type {!ArrayBuffer} */ (/** @type {?} */ (3));
52
58
 
53
- const fakeVideoStream = {mimeType: 'video/foo', drmInfos: []};
54
- const fakeAudioStream = {mimeType: 'audio/foo', drmInfos: []};
55
- const fakeTextStream = {mimeType: 'text/foo', drmInfos: []};
59
+ const fakeVideoStream = {mimeType: 'video/mp4', drmInfos: [{}]};
60
+ const fakeAudioStream = {mimeType: 'audio/mp4', drmInfos: []};
61
+ const fakeTextStream = {mimeType: 'text/mp4', drmInfos: []};
56
62
  const fakeTransportStream = {mimeType: 'tsMimetype', drmInfos: []};
57
63
 
64
+ /** @type {shaka.extern.Stream} */
65
+ const fakeStream = shaka.test.StreamingEngineUtil.createMockVideoStream(1);
66
+
58
67
  let audioSourceBuffer;
59
68
  let videoSourceBuffer;
60
69
  let mockVideo;
@@ -73,6 +82,10 @@ describe('MediaSourceEngine', () => {
73
82
 
74
83
  /** @type {!jasmine.Spy} */
75
84
  let createMediaSourceSpy;
85
+ /** @type {!jasmine.Spy} */
86
+ let requiresEncryptionInfoInAllInitSegmentsSpy;
87
+ /** @type {!jasmine.Spy} */
88
+ let fakeEncryptionSpy;
76
89
 
77
90
  /** @type {!shaka.media.MediaSourceEngine} */
78
91
  let mediaSourceEngine;
@@ -89,7 +102,12 @@ describe('MediaSourceEngine', () => {
89
102
 
90
103
  afterAll(() => {
91
104
  window.MediaSource.isTypeSupported = originalIsTypeSupported;
92
- shaka.media.Transmuxer = originalTransmuxer;
105
+ shaka.transmuxer.TransmuxerEngine.findTransmuxer =
106
+ originalFindTransmuxer;
107
+ shaka.transmuxer.TransmuxerEngine.convertCodecs =
108
+ originalConvertCodecs;
109
+ shaka.transmuxer.TransmuxerEngine.isSupported =
110
+ originalIsSupported;
93
111
  });
94
112
 
95
113
  beforeEach(/** @suppress {invalidCasts} */ () => {
@@ -101,17 +119,18 @@ describe('MediaSourceEngine', () => {
101
119
  return type == 'audio' ? audioSourceBuffer : videoSourceBuffer;
102
120
  });
103
121
  mockTransmuxer = new shaka.test.FakeTransmuxer();
104
-
105
- // eslint-disable-next-line no-restricted-syntax
106
- shaka.media.Transmuxer = /** @type {?} */ (function() {
107
- return /** @type {?} */ (mockTransmuxer);
108
- });
109
- shaka.media.Transmuxer.convertCodecs = (mimeType, contentType) => {
110
- return 'video/mp4; codecs="avc1.42E01E"';
111
- };
112
- shaka.media.Transmuxer.isSupported = (mimeType, contentType) => {
113
- return mimeType == 'tsMimetype';
114
- };
122
+ shaka.transmuxer.TransmuxerEngine.findTransmuxer =
123
+ (mimeType) => {
124
+ return () => mockTransmuxer;
125
+ };
126
+ shaka.transmuxer.TransmuxerEngine.convertCodecs =
127
+ (mimeType, contentType) => {
128
+ return 'video/mp4; codecs="avc1.42E01E"';
129
+ };
130
+ shaka.transmuxer.TransmuxerEngine.isSupported =
131
+ (mimeType, contentType) => {
132
+ return mimeType == 'tsMimetype';
133
+ };
115
134
 
116
135
  shaka.text.TextEngine = createMockTextEngineCtor();
117
136
 
@@ -124,6 +143,12 @@ describe('MediaSourceEngine', () => {
124
143
  shaka.media.MediaSourceEngine.prototype.createMediaSource =
125
144
  Util.spyFunc(createMediaSourceSpy);
126
145
 
146
+ requiresEncryptionInfoInAllInitSegmentsSpy = spyOn(shaka.util.Platform,
147
+ 'requiresEncryptionInfoInAllInitSegments').and.returnValue(false);
148
+
149
+ fakeEncryptionSpy = spyOn(shaka.media.ContentWorkarounds, 'fakeEncryption')
150
+ .and.callFake((data) => data + 100);
151
+
127
152
  // MediaSourceEngine uses video to:
128
153
  // - set src attribute
129
154
  // - read error codes when operations fail
@@ -254,8 +279,8 @@ describe('MediaSourceEngine', () => {
254
279
  initObject.set(ContentType.AUDIO, fakeAudioStream);
255
280
  initObject.set(ContentType.VIDEO, fakeVideoStream);
256
281
  await mediaSourceEngine.init(initObject, false);
257
- expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledWith('audio/foo');
258
- expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledWith('video/foo');
282
+ expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledWith('audio/mp4');
283
+ expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledWith('video/mp4');
259
284
  expect(shaka.text.TextEngine).not.toHaveBeenCalled();
260
285
  });
261
286
 
@@ -381,9 +406,45 @@ describe('MediaSourceEngine', () => {
381
406
  await mediaSourceEngine.init(initObject, false);
382
407
  });
383
408
 
409
+ it('should apply fake encryption by default', async () => {
410
+ requiresEncryptionInfoInAllInitSegmentsSpy.and.returnValue(true);
411
+
412
+ const p = mediaSourceEngine.appendBuffer(
413
+ ContentType.VIDEO, buffer, null, fakeStream,
414
+ /* hasClosedCaptions= */ false);
415
+
416
+ expect(fakeEncryptionSpy).toHaveBeenCalled();
417
+
418
+ expect(videoSourceBuffer.appendBuffer)
419
+ .toHaveBeenCalledWith((buffer + 100));
420
+ videoSourceBuffer.updateend();
421
+
422
+ await p;
423
+ });
424
+
425
+ it('should not apply fake encryption when config is off', async () => {
426
+ requiresEncryptionInfoInAllInitSegmentsSpy.and.returnValue(true);
427
+
428
+ const config = shaka.util.PlayerConfiguration.createDefault().mediaSource;
429
+ config.insertFakeEncryptionInInit = false;
430
+
431
+ mediaSourceEngine.configure(config);
432
+
433
+ const p = mediaSourceEngine.appendBuffer(
434
+ ContentType.VIDEO, buffer, null, fakeStream,
435
+ /* hasClosedCaptions= */ false);
436
+
437
+ expect(fakeEncryptionSpy).not.toHaveBeenCalled();
438
+
439
+ expect(videoSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
440
+ videoSourceBuffer.updateend();
441
+
442
+ await p;
443
+ });
444
+
384
445
  it('appends the given data', async () => {
385
446
  const p = mediaSourceEngine.appendBuffer(
386
- ContentType.AUDIO, buffer, null,
447
+ ContentType.AUDIO, buffer, null, fakeStream,
387
448
  /* hasClosedCaptions= */ false);
388
449
  expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
389
450
  audioSourceBuffer.updateend();
@@ -392,15 +453,16 @@ describe('MediaSourceEngine', () => {
392
453
 
393
454
  it('rejects promise when operation throws', async () => {
394
455
  audioSourceBuffer.appendBuffer.and.throwError('fail!');
395
- mockVideo.error = {code: 5};
456
+ mockVideo.error = {code: 5, message: 'something failed'};
396
457
  const expected = Util.jasmineError(new shaka.util.Error(
397
458
  shaka.util.Error.Severity.CRITICAL,
398
459
  shaka.util.Error.Category.MEDIA,
399
460
  shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_THREW,
400
- jasmine.objectContaining({message: 'fail!'})));
461
+ jasmine.objectContaining({message: 'fail!'}),
462
+ {code: 5, message: 'something failed'}));
401
463
  await expectAsync(
402
464
  mediaSourceEngine.appendBuffer(
403
- ContentType.AUDIO, buffer, null,
465
+ ContentType.AUDIO, buffer, null, fakeStream,
404
466
  /* hasClosedCaptions= */ false))
405
467
  .toBeRejectedWith(expected);
406
468
  expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
@@ -419,7 +481,7 @@ describe('MediaSourceEngine', () => {
419
481
  ContentType.AUDIO));
420
482
  await expectAsync(
421
483
  mediaSourceEngine.appendBuffer(
422
- ContentType.AUDIO, buffer, null,
484
+ ContentType.AUDIO, buffer, null, fakeStream,
423
485
  /* hasClosedCaptions= */ false))
424
486
  .toBeRejectedWith(expected);
425
487
  expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
@@ -440,10 +502,10 @@ describe('MediaSourceEngine', () => {
440
502
  ContentType.AUDIO));
441
503
 
442
504
  const p1 = mediaSourceEngine.appendBuffer(
443
- ContentType.AUDIO, buffer, null,
505
+ ContentType.AUDIO, buffer, null, fakeStream,
444
506
  /* hasClosedCaptions= */ false);
445
507
  const p2 = mediaSourceEngine.appendBuffer(
446
- ContentType.AUDIO, buffer, null,
508
+ ContentType.AUDIO, buffer, null, fakeStream,
447
509
  /* hasClosedCaptions= */ false);
448
510
  audioSourceBuffer.updateend();
449
511
  await expectAsync(p1).toBeResolved();
@@ -453,7 +515,7 @@ describe('MediaSourceEngine', () => {
453
515
  it('rejects the promise if this operation fails async', async () => {
454
516
  mockVideo.error = {code: 5};
455
517
  const p = mediaSourceEngine.appendBuffer(
456
- ContentType.AUDIO, buffer, null,
518
+ ContentType.AUDIO, buffer, null, fakeStream,
457
519
  /* hasClosedCaptions= */ false);
458
520
  audioSourceBuffer.error();
459
521
  audioSourceBuffer.updateend();
@@ -470,11 +532,11 @@ describe('MediaSourceEngine', () => {
470
532
  it('queues operations on a single SourceBuffer', async () => {
471
533
  /** @type {!shaka.test.StatusPromise} */
472
534
  const p1 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
473
- ContentType.AUDIO, buffer, null,
535
+ ContentType.AUDIO, buffer, null, fakeStream,
474
536
  /* hasClosedCaptions= */ false));
475
537
  /** @type {!shaka.test.StatusPromise} */
476
538
  const p2 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
477
- ContentType.AUDIO, buffer2, null,
539
+ ContentType.AUDIO, buffer2, null, fakeStream,
478
540
  /* hasClosedCaptions= */ false));
479
541
 
480
542
  expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
@@ -493,15 +555,15 @@ describe('MediaSourceEngine', () => {
493
555
  it('queues operations independently for different types', async () => {
494
556
  /** @type {!shaka.test.StatusPromise} */
495
557
  const p1 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
496
- ContentType.AUDIO, buffer, null,
558
+ ContentType.AUDIO, buffer, null, fakeStream,
497
559
  /* hasClosedCaptions= */ false));
498
560
  /** @type {!shaka.test.StatusPromise} */
499
561
  const p2 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
500
- ContentType.AUDIO, buffer2, null,
562
+ ContentType.AUDIO, buffer2, null, fakeStream,
501
563
  /* hasClosedCaptions= */ false));
502
564
  /** @type {!shaka.test.StatusPromise} */
503
565
  const p3 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
504
- ContentType.VIDEO, buffer3, null,
566
+ ContentType.VIDEO, buffer3, null, fakeStream,
505
567
  /* hasClosedCaptions= */ false));
506
568
 
507
569
  expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
@@ -536,13 +598,13 @@ describe('MediaSourceEngine', () => {
536
598
  });
537
599
 
538
600
  const p1 = mediaSourceEngine.appendBuffer(
539
- ContentType.AUDIO, buffer, null,
601
+ ContentType.AUDIO, buffer, null, fakeStream,
540
602
  /* hasClosedCaptions= */ false);
541
603
  const p2 = mediaSourceEngine.appendBuffer(
542
- ContentType.AUDIO, buffer2, null,
604
+ ContentType.AUDIO, buffer2, null, fakeStream,
543
605
  /* hasClosedCaptions= */ false);
544
606
  const p3 = mediaSourceEngine.appendBuffer(
545
- ContentType.AUDIO, buffer3, null,
607
+ ContentType.AUDIO, buffer3, null, fakeStream,
546
608
  /* hasClosedCaptions= */ false);
547
609
 
548
610
  await expectAsync(p1).toBeResolved();
@@ -558,12 +620,13 @@ describe('MediaSourceEngine', () => {
558
620
  expect(mockTextEngine.appendBuffer).not.toHaveBeenCalled();
559
621
  const reference = dummyReference(0, 10);
560
622
  await mediaSourceEngine.appendBuffer(
561
- ContentType.TEXT, data, reference, /* hasClosedCaptions= */ false);
623
+ ContentType.TEXT, data, reference, fakeStream,
624
+ /* hasClosedCaptions= */ false);
562
625
  expect(mockTextEngine.appendBuffer).toHaveBeenCalledWith(
563
626
  data, 0, 10);
564
627
  });
565
628
 
566
- it('appends transmuxed data and captions', async () => {
629
+ it('appends transmuxed data', async () => {
567
630
  const initObject = new Map();
568
631
  initObject.set(ContentType.VIDEO, fakeTransportStream);
569
632
 
@@ -576,9 +639,8 @@ describe('MediaSourceEngine', () => {
576
639
  const init = async () => {
577
640
  await mediaSourceEngine.init(initObject, false);
578
641
  await mediaSourceEngine.appendBuffer(
579
- ContentType.VIDEO, buffer, null,
642
+ ContentType.VIDEO, buffer, null, fakeStream,
580
643
  /* hasClosedCaptions= */ false);
581
- expect(mockTextEngine.storeAndAppendClosedCaptions).toHaveBeenCalled();
582
644
  expect(videoSourceBuffer.appendBuffer).toHaveBeenCalled();
583
645
  };
584
646
 
@@ -593,38 +655,6 @@ describe('MediaSourceEngine', () => {
593
655
  await Promise.all([init(), delay()]);
594
656
  });
595
657
 
596
- it('appends only transmuxed data without embedded text', async () => {
597
- const initObject = new Map();
598
- initObject.set(ContentType.VIDEO, fakeTransportStream);
599
-
600
- const output = {
601
- data: new Uint8Array(1),
602
- captions: [],
603
- };
604
- mockTransmuxer.transmux.and.returnValue(Promise.resolve(output));
605
-
606
- const init = async () => {
607
- await mediaSourceEngine.init(initObject, false);
608
- await mediaSourceEngine.appendBuffer(
609
- ContentType.VIDEO, buffer, null,
610
- /* hasClosedCaptions= */ false);
611
- expect(mockTextEngine.storeAndAppendClosedCaptions)
612
- .not.toHaveBeenCalled();
613
- expect(videoSourceBuffer.appendBuffer)
614
- .toHaveBeenCalledWith(output.data);
615
- };
616
-
617
- // The 'updateend' event fires once the data is done appending to the
618
- // media source. We only append to the media source once transmuxing is
619
- // done. Since transmuxing is done using Promises, we need to delay the
620
- // event until MediaSourceEngine calls appendBuffer.
621
- const delay = async () => {
622
- await Util.shortDelay();
623
- videoSourceBuffer.updateend();
624
- };
625
- await Promise.all([init(), delay()]);
626
- });
627
-
628
658
  it('appends parsed closed captions from CaptionParser', async () => {
629
659
  const initObject = new Map();
630
660
  initObject.set(ContentType.VIDEO, fakeVideoStream);
@@ -637,7 +667,7 @@ describe('MediaSourceEngine', () => {
637
667
 
638
668
  // Initialize the closed caption parser.
639
669
  const appendInit = mediaSourceEngine.appendBuffer(
640
- ContentType.VIDEO, buffer, null,
670
+ ContentType.VIDEO, buffer, null, fakeStream,
641
671
  /* hasClosedCaptions= */ true);
642
672
  // In MediaSourceEngine, appendBuffer() is async and Promise-based, but
643
673
  // at the browser level, it's event-based.
@@ -653,7 +683,8 @@ describe('MediaSourceEngine', () => {
653
683
  // Parse and append the closed captions embedded in video stream.
654
684
  const reference = dummyReference(0, 1000);
655
685
  const appendVideo = mediaSourceEngine.appendBuffer(
656
- ContentType.VIDEO, buffer, reference, true);
686
+ ContentType.VIDEO, buffer, reference, fakeStream,
687
+ /* hasClosedCaptions= */ true);
657
688
  videoSourceBuffer.updateend();
658
689
  await appendVideo;
659
690
 
@@ -665,8 +696,7 @@ describe('MediaSourceEngine', () => {
665
696
  initObject.set(ContentType.VIDEO, fakeVideoStream);
666
697
  videoSourceBuffer.mode = 'sequence';
667
698
 
668
- await mediaSourceEngine.init(
669
- initObject, /* forceTransmux= */ false, /* sequenceMode= */ true);
699
+ await mediaSourceEngine.init(initObject, /* sequenceMode= */ true);
670
700
 
671
701
  expect(videoSourceBuffer.timestampOffset).toBe(0);
672
702
 
@@ -675,67 +705,14 @@ describe('MediaSourceEngine', () => {
675
705
  const reference = dummyReference(0, 1000);
676
706
  reference.startTime = 0.50;
677
707
  const appendVideo = mediaSourceEngine.appendBuffer(
678
- ContentType.VIDEO, buffer, reference, /* hasClosedCaptions= */ false,
708
+ ContentType.VIDEO, buffer, reference, fakeStream,
709
+ /* hasClosedCaptions= */ false,
679
710
  /* seeked= */ false, /* adaptation= */ true);
680
711
  videoSourceBuffer.updateend();
681
712
  await appendVideo;
682
713
 
683
714
  expect(videoSourceBuffer.timestampOffset).toBe(0.50);
684
715
  });
685
-
686
- it('calls abort before setting timestampOffset', async () => {
687
- const simulateUpdate = async () => {
688
- await Util.shortDelay();
689
- videoSourceBuffer.updateend();
690
- };
691
- const initObject = new Map();
692
- initObject.set(ContentType.VIDEO, fakeVideoStream);
693
-
694
- await mediaSourceEngine.init(
695
- initObject, /* forceTransmux= */ false, /* sequenceMode= */ true);
696
-
697
- // First, mock the scenario where timestampOffset is set to help align
698
- // text segments. In this case, SourceBuffer mode is still 'segments'.
699
- let reference = dummyReference(0, 1000);
700
- let appendVideo = mediaSourceEngine.appendBuffer(
701
- ContentType.VIDEO, buffer, reference, /* hasClosedCaptions= */ false);
702
- // Wait for the first appendBuffer(), in segments mode.
703
- await simulateUpdate();
704
- // Next, wait for abort(), used to reset the parser state for a safe
705
- // setting of timestampOffset. Shaka fakes an updateend event on abort(),
706
- // so simulateUpdate() isn't needed.
707
- await Util.shortDelay();
708
- // Next, wait for remove(), used to clear the SourceBuffer from the
709
- // initial append.
710
- await simulateUpdate();
711
- // Next, wait for the second appendBuffer(), falling through to normal
712
- // operations.
713
- await simulateUpdate();
714
- // Lastly, wait for the function-scoped MediaSourceEngine#appendBuffer()
715
- // promise to resolve.
716
- await appendVideo;
717
- expect(videoSourceBuffer.abort).toHaveBeenCalledTimes(1);
718
-
719
- // Second, mock the scenario where timestampOffset is set during an
720
- // unbuffered seek or adaptation. SourceBuffer mode is 'sequence' now.
721
- reference = dummyReference(0, 1000);
722
- appendVideo = mediaSourceEngine.appendBuffer(
723
- ContentType.VIDEO, buffer, reference, /* hasClosedCaptions= */ false,
724
- /* seeked= */ true);
725
- // First, wait for abort(), used to reset the parser state for a safe
726
- // setting of timestampOffset.
727
- await Util.shortDelay();
728
- // The subsequent setTimestampOffset() fakes an updateend event for us, so
729
- // simulateUpdate() isn't needed.
730
- await Util.shortDelay();
731
- // Next, wait for the second appendBuffer(), falling through to normal
732
- // operations.
733
- await simulateUpdate();
734
- // Lastly, wait for the function-scoped MediaSourceEngine#appendBuffer()
735
- // promise to resolve.
736
- await appendVideo;
737
- expect(videoSourceBuffer.abort).toHaveBeenCalledTimes(2);
738
- });
739
716
  });
740
717
 
741
718
  describe('remove', () => {
@@ -765,7 +742,8 @@ describe('MediaSourceEngine', () => {
765
742
  shaka.util.Error.Severity.CRITICAL,
766
743
  shaka.util.Error.Category.MEDIA,
767
744
  shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_THREW,
768
- jasmine.objectContaining({message: 'fail!'})));
745
+ jasmine.objectContaining({message: 'fail!'}),
746
+ {code: 5}));
769
747
  await expectAsync(mediaSourceEngine.remove(ContentType.AUDIO, 1, 5))
770
748
  .toBeRejectedWith(expected);
771
749
  expect(audioSourceBuffer.remove).toHaveBeenCalledWith(1, 5);
@@ -930,7 +908,9 @@ describe('MediaSourceEngine', () => {
930
908
  /* timestampOffset= */ 10,
931
909
  /* appendWindowStart= */ 0,
932
910
  /* appendWindowEnd= */ 20,
933
- /* sequenceMode= */ false);
911
+ /* sequenceMode= */ false,
912
+ fakeStream,
913
+ /* streamsByType= */ new Map());
934
914
  expect(mockTextEngine.setTimestampOffset).toHaveBeenCalledWith(10);
935
915
  expect(mockTextEngine.setAppendWindow).toHaveBeenCalledWith(0, 20);
936
916
  });
@@ -954,11 +934,11 @@ describe('MediaSourceEngine', () => {
954
934
  it('waits for all previous operations to complete', async () => {
955
935
  /** @type {!shaka.test.StatusPromise} */
956
936
  const p1 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
957
- ContentType.AUDIO, buffer, null,
937
+ ContentType.AUDIO, buffer, null, fakeStream,
958
938
  /* hasClosedCaptions= */ false));
959
939
  /** @type {!shaka.test.StatusPromise} */
960
940
  const p2 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
961
- ContentType.VIDEO, buffer, null,
941
+ ContentType.VIDEO, buffer, null, fakeStream,
962
942
  /* hasClosedCaptions= */ false));
963
943
  /** @type {!shaka.test.StatusPromise} */
964
944
  const p3 = new shaka.test.StatusPromise(mediaSourceEngine.endOfStream());
@@ -982,11 +962,11 @@ describe('MediaSourceEngine', () => {
982
962
  /** @type {!Promise} */
983
963
  const p1 = mediaSourceEngine.endOfStream();
984
964
  mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
985
- /* hasClosedCaptions= */ false);
965
+ fakeStream, /* hasClosedCaptions= */ false);
986
966
  mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer, null,
987
- /* hasClosedCaptions= */ false);
967
+ fakeStream, /* hasClosedCaptions= */ false);
988
968
  mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer2, null,
989
- /* hasClosedCaptions= */ false);
969
+ fakeStream, /* hasClosedCaptions= */ false);
990
970
 
991
971
  // endOfStream hasn't been called yet because blocking multiple queues
992
972
  // takes an extra tick, even when they are empty.
@@ -1014,7 +994,7 @@ describe('MediaSourceEngine', () => {
1014
994
  /** @type {!Promise} */
1015
995
  const p1 = mediaSourceEngine.endOfStream();
1016
996
  mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
1017
- /* hasClosedCaptions= */ false);
997
+ fakeStream, /* hasClosedCaptions= */ false);
1018
998
 
1019
999
  expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalled();
1020
1000
 
@@ -1045,11 +1025,11 @@ describe('MediaSourceEngine', () => {
1045
1025
  it('waits for all previous operations to complete', async () => {
1046
1026
  /** @type {!shaka.test.StatusPromise} */
1047
1027
  const p1 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
1048
- ContentType.AUDIO, buffer, null,
1028
+ ContentType.AUDIO, buffer, null, fakeStream,
1049
1029
  /* hasClosedCaptions= */ false));
1050
1030
  /** @type {!shaka.test.StatusPromise} */
1051
1031
  const p2 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
1052
- ContentType.VIDEO, buffer, null,
1032
+ ContentType.VIDEO, buffer, null, fakeStream,
1053
1033
  /* hasClosedCaptions= */ false));
1054
1034
  /** @type {!shaka.test.StatusPromise} */
1055
1035
  const p3 =
@@ -1074,11 +1054,11 @@ describe('MediaSourceEngine', () => {
1074
1054
  /** @type {!Promise} */
1075
1055
  const p1 = mediaSourceEngine.setDuration(100);
1076
1056
  mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
1077
- /* hasClosedCaptions= */ false);
1057
+ fakeStream, /* hasClosedCaptions= */ false);
1078
1058
  mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer, null,
1079
- /* hasClosedCaptions= */ false);
1059
+ fakeStream, /* hasClosedCaptions= */ false);
1080
1060
  mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer2, null,
1081
- /* hasClosedCaptions= */ false);
1061
+ fakeStream, /* hasClosedCaptions= */ false);
1082
1062
 
1083
1063
  // The setter hasn't been called yet because blocking multiple queues
1084
1064
  // takes an extra tick, even when they are empty.
@@ -1107,7 +1087,7 @@ describe('MediaSourceEngine', () => {
1107
1087
  /** @type {!Promise} */
1108
1088
  const p1 = mediaSourceEngine.setDuration(100);
1109
1089
  mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
1110
- /* hasClosedCaptions= */ false);
1090
+ fakeStream, /* hasClosedCaptions= */ false);
1111
1091
 
1112
1092
  expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalled();
1113
1093
 
@@ -1146,9 +1126,9 @@ describe('MediaSourceEngine', () => {
1146
1126
  // This is tested because shrinking duration generates 'updateend'
1147
1127
  // events, and we want to show that the queue still operates correctly.
1148
1128
  const a1 = mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
1149
- /* hasClosedCaptions= */ false);
1129
+ fakeStream, /* hasClosedCaptions= */ false);
1150
1130
  const a2 = mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer, null,
1151
- /* hasClosedCaptions= */ false);
1131
+ fakeStream, /* hasClosedCaptions= */ false);
1152
1132
 
1153
1133
  await p1;
1154
1134
  await a1;
@@ -1168,9 +1148,9 @@ describe('MediaSourceEngine', () => {
1168
1148
 
1169
1149
  it('waits for all operations to complete', async () => {
1170
1150
  mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
1171
- /* hasClosedCaptions= */ false);
1151
+ fakeStream, /* hasClosedCaptions= */ false);
1172
1152
  mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer, null,
1173
- /* hasClosedCaptions= */ false);
1153
+ fakeStream, /* hasClosedCaptions= */ false);
1174
1154
 
1175
1155
  /** @type {!shaka.test.StatusPromise} */
1176
1156
  const d = new shaka.test.StatusPromise(mediaSourceEngine.destroy());
@@ -1187,7 +1167,7 @@ describe('MediaSourceEngine', () => {
1187
1167
 
1188
1168
  it('resolves even when a pending operation fails', async () => {
1189
1169
  const p = mediaSourceEngine.appendBuffer(
1190
- ContentType.AUDIO, buffer, null,
1170
+ ContentType.AUDIO, buffer, null, fakeStream,
1191
1171
  /* hasClosedCaptions= */ false);
1192
1172
  const d = mediaSourceEngine.destroy();
1193
1173
 
@@ -1212,10 +1192,10 @@ describe('MediaSourceEngine', () => {
1212
1192
 
1213
1193
  it('cancels operations that have not yet started', async () => {
1214
1194
  mediaSourceEngine.appendBuffer(
1215
- ContentType.AUDIO, buffer, null,
1195
+ ContentType.AUDIO, buffer, null, fakeStream,
1216
1196
  /* hasClosedCaptions= */ false);
1217
1197
  const rejected = mediaSourceEngine.appendBuffer(
1218
- ContentType.AUDIO, buffer2, null,
1198
+ ContentType.AUDIO, buffer2, null, fakeStream,
1219
1199
  /* hasClosedCaptions= */ false);
1220
1200
  // Create the expectation first so we don't get unhandled rejection errors
1221
1201
  const expected = expectAsync(rejected).toBeRejected();
@@ -1239,7 +1219,7 @@ describe('MediaSourceEngine', () => {
1239
1219
 
1240
1220
  it('cancels blocking operations that have not yet started', async () => {
1241
1221
  const p1 = mediaSourceEngine.appendBuffer(
1242
- ContentType.AUDIO, buffer, null,
1222
+ ContentType.AUDIO, buffer, null, fakeStream,
1243
1223
  /* hasClosedCaptions= */ false);
1244
1224
  const p2 = mediaSourceEngine.endOfStream();
1245
1225
  const d = mediaSourceEngine.destroy();
@@ -1254,7 +1234,7 @@ describe('MediaSourceEngine', () => {
1254
1234
  const d = mediaSourceEngine.destroy();
1255
1235
  await expectAsync(
1256
1236
  mediaSourceEngine.appendBuffer(
1257
- ContentType.AUDIO, buffer, null,
1237
+ ContentType.AUDIO, buffer, null, fakeStream,
1258
1238
  /* hasClosedCaptions= */ false))
1259
1239
  .toBeRejected();
1260
1240
  await d;
@@ -1328,7 +1308,7 @@ describe('MediaSourceEngine', () => {
1328
1308
  mockTextEngine = jasmine.createSpyObj('TextEngine', [
1329
1309
  'initParser', 'destroy', 'appendBuffer', 'remove', 'setTimestampOffset',
1330
1310
  'setAppendWindow', 'bufferStart', 'bufferEnd', 'bufferedAheadOf',
1331
- 'storeAndAppendClosedCaptions', 'convertMuxjsCaptionsToShakaCaptions',
1311
+ 'storeAndAppendClosedCaptions',
1332
1312
  ]);
1333
1313
 
1334
1314
  const resolve = () => Promise.resolve();
@@ -134,6 +134,9 @@ describe('Playhead', () => {
134
134
  minBufferTime: 10,
135
135
  offlineSessionIds: [],
136
136
  sequenceMode: false,
137
+ ignoreManifestTimestampsInSegmentsMode: false,
138
+ type: 'UNKNOWN',
139
+ serviceDescription: null,
137
140
  };
138
141
 
139
142
  config = shaka.util.PlayerConfiguration.createDefault().streaming;
@@ -114,6 +114,57 @@ describe('PresentationTimeline', () => {
114
114
  return timeline;
115
115
  }
116
116
 
117
+ const makeTimeRange = (startTime, endTime) => {
118
+ return {
119
+ start: startTime,
120
+ end: endTime,
121
+ };
122
+ };
123
+
124
+ describe('notifyTimeRange', () => {
125
+ it('calculates time based on segment times when available', () => {
126
+ const timeline = makeLiveTimeline(/* availability= */ 20);
127
+
128
+ const timeRanges = [
129
+ makeTimeRange(0, 10),
130
+ makeTimeRange(10, 20),
131
+ makeTimeRange(20, 30),
132
+ makeTimeRange(30, 40),
133
+ makeTimeRange(40, 50),
134
+ ];
135
+
136
+
137
+ // In spite of the current time, the explicit segment times will decide
138
+ // the availability window.
139
+ // See https://github.com/shaka-project/shaka-player/issues/999
140
+ setElapsed(1000);
141
+ timeline.notifyTimeRange(timeRanges, 0);
142
+
143
+ // last segment time (50) - availability (20)
144
+ expect(timeline.getSegmentAvailabilityStart()).toBe(30);
145
+ });
146
+
147
+ it('ignores segment times when configured to', () => {
148
+ const timeline = makeLiveTimeline(
149
+ /* availability= */ 20, /* drift= */ 0,
150
+ /* autoCorrectDrift= */ false);
151
+
152
+ const timeRanges = [
153
+ makeTimeRange(0, 10),
154
+ makeTimeRange(10, 20),
155
+ makeTimeRange(20, 30),
156
+ makeTimeRange(30, 40),
157
+ makeTimeRange(40, 50),
158
+ ];
159
+
160
+ setElapsed(100);
161
+ timeline.notifyTimeRange(timeRanges, 0);
162
+
163
+ // now (100) - max segment duration (10) - availability start time (0)
164
+ expect(timeline.getSegmentAvailabilityEnd()).toBe(90);
165
+ });
166
+ });
167
+
117
168
  describe('getSegmentAvailabilityStart', () => {
118
169
  it('returns 0 for VOD and IPR', () => {
119
170
  const timeline1 = makeVodTimeline(/* duration= */ 60);