shaka-player 4.4.3 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/.github/workflows/release-please.yaml +2 -27
  3. package/AUTHORS +2 -0
  4. package/CHANGELOG.md +156 -39
  5. package/CODE_OF_CONDUCT.md +1 -1
  6. package/CONTRIBUTORS +2 -0
  7. package/README.md +54 -42
  8. package/demo/asset_card.js +18 -21
  9. package/demo/cast_receiver/index.html +0 -1
  10. package/demo/close_button.js +0 -3
  11. package/demo/common/asset.js +33 -22
  12. package/demo/common/assets.js +249 -60
  13. package/demo/config.js +219 -253
  14. package/demo/custom.js +88 -133
  15. package/demo/front.js +7 -10
  16. package/demo/index.html +19 -22
  17. package/demo/input.js +6 -11
  18. package/demo/input_container.js +8 -9
  19. package/demo/main.js +62 -126
  20. package/demo/search.js +29 -34
  21. package/demo/service_worker.js +0 -3
  22. package/demo/tooltip.js +3 -5
  23. package/demo/visualizer.js +3 -5
  24. package/demo/visualizer_button.js +1 -20
  25. package/dist/controls.css +1 -1
  26. package/dist/controls.css.map +1 -1
  27. package/dist/demo.compiled.debug.js +211 -228
  28. package/dist/demo.compiled.debug.map +4 -4
  29. package/dist/demo.compiled.js +211 -228
  30. package/dist/demo.compiled.map +4 -4
  31. package/dist/deps.js +42 -37
  32. package/dist/locales.js +34 -30
  33. package/dist/receiver.compiled.debug.js +64 -77
  34. package/dist/receiver.compiled.debug.map +4 -4
  35. package/dist/receiver.compiled.js +64 -77
  36. package/dist/receiver.compiled.map +4 -4
  37. package/dist/shaka-player.compiled.d.ts +343 -151
  38. package/dist/shaka-player.compiled.debug.d.ts +343 -151
  39. package/dist/shaka-player.compiled.debug.externs.js +356 -117
  40. package/dist/shaka-player.compiled.debug.js +952 -811
  41. package/dist/shaka-player.compiled.debug.map +4 -4
  42. package/dist/shaka-player.compiled.externs.js +356 -117
  43. package/dist/shaka-player.compiled.js +1165 -1078
  44. package/dist/shaka-player.compiled.map +4 -4
  45. package/dist/shaka-player.ui.d.ts +359 -153
  46. package/dist/shaka-player.ui.debug.d.ts +359 -153
  47. package/dist/shaka-player.ui.debug.externs.js +382 -117
  48. package/dist/shaka-player.ui.debug.js +1084 -918
  49. package/dist/shaka-player.ui.debug.map +4 -4
  50. package/dist/shaka-player.ui.externs.js +382 -117
  51. package/dist/shaka-player.ui.js +1377 -1274
  52. package/dist/shaka-player.ui.map +4 -4
  53. package/docs/design/lcevc-integration.md +14 -14
  54. package/docs/tutorials/ad_monetization.md +54 -0
  55. package/docs/tutorials/basic-usage.md +2 -1
  56. package/docs/tutorials/errors.md +2 -1
  57. package/docs/tutorials/faq.md +27 -55
  58. package/docs/tutorials/index.json +2 -1
  59. package/docs/tutorials/lcevc.md +118 -0
  60. package/docs/tutorials/offline.md +10 -8
  61. package/docs/tutorials/plugins.md +5 -0
  62. package/docs/tutorials/ui-customization.md +17 -0
  63. package/docs/tutorials/ui.md +2 -1
  64. package/docs/tutorials/upgrade.md +3 -0
  65. package/externs/css_style_declaration.js +19 -0
  66. package/externs/lcevc.js +37 -13
  67. package/externs/managedmediasource.js +24 -0
  68. package/externs/media_remote.js +68 -0
  69. package/externs/mediatailor.js +193 -0
  70. package/externs/pictureinpicture.js +11 -0
  71. package/externs/shaka/abr_manager.js +6 -2
  72. package/externs/shaka/ads.js +27 -0
  73. package/externs/shaka/cea.js +7 -0
  74. package/externs/shaka/codecs.js +5 -3
  75. package/externs/shaka/manifest.js +31 -10
  76. package/externs/shaka/manifest_parser.js +24 -1
  77. package/externs/shaka/net.js +2 -2
  78. package/externs/shaka/offline.js +13 -2
  79. package/externs/shaka/player.js +65 -8
  80. package/externs/shaka/text.js +3 -1
  81. package/externs/shaka/transmuxer.js +1 -1
  82. package/karma.conf.js +7 -3
  83. package/lib/abr/simple_abr_manager.js +66 -9
  84. package/lib/ads/ad_manager.js +104 -50
  85. package/lib/ads/media_tailor_ad.js +297 -0
  86. package/lib/ads/media_tailor_ad_manager.js +839 -0
  87. package/lib/cast/cast_receiver.js +1 -1
  88. package/lib/cea/cea_decoder.js +28 -0
  89. package/lib/cea/dummy_caption_decoder.js +5 -0
  90. package/lib/cea/ts_cea_parser.js +15 -2
  91. package/lib/config/codec_switching_strategy.js +24 -0
  92. package/lib/dash/content_protection.js +120 -2
  93. package/lib/dash/dash_parser.js +322 -93
  94. package/lib/dash/mpd_utils.js +62 -37
  95. package/lib/dash/segment_base.js +17 -10
  96. package/lib/dash/segment_list.js +18 -9
  97. package/lib/dash/segment_template.js +122 -107
  98. package/lib/dependencies/all.js +8 -7
  99. package/lib/hls/hls_classes.js +28 -43
  100. package/lib/hls/hls_parser.js +798 -658
  101. package/lib/hls/hls_utils.js +64 -5
  102. package/lib/hls/manifest_text_parser.js +7 -11
  103. package/lib/lcevc/lcevc_dec.js +220 -0
  104. package/lib/media/adaptation_set.js +32 -14
  105. package/lib/media/adaptation_set_criteria.js +86 -16
  106. package/lib/media/closed_caption_parser.js +13 -0
  107. package/lib/media/content_workarounds.js +6 -0
  108. package/lib/media/drm_engine.js +8 -13
  109. package/lib/media/manifest_parser.js +8 -113
  110. package/lib/media/media_source_capabilities.js +10 -3
  111. package/lib/media/media_source_engine.js +286 -44
  112. package/lib/media/play_rate_controller.js +8 -38
  113. package/lib/media/presentation_timeline.js +7 -1
  114. package/lib/media/quality_observer.js +1 -1
  115. package/lib/media/segment_index.js +6 -6
  116. package/lib/media/segment_prefetch.js +92 -24
  117. package/lib/media/segment_reference.js +73 -7
  118. package/lib/media/segment_utils.js +343 -0
  119. package/lib/media/stall_detector.js +0 -3
  120. package/lib/media/streaming_engine.js +73 -38
  121. package/lib/mss/mss_parser.js +19 -2
  122. package/lib/net/networking_engine.js +67 -12
  123. package/lib/net/networking_utils.js +95 -0
  124. package/lib/offline/indexeddb/v1_storage_cell.js +3 -0
  125. package/lib/offline/indexeddb/v2_storage_cell.js +3 -0
  126. package/lib/offline/manifest_converter.js +3 -0
  127. package/lib/offline/offline_manifest_parser.js +10 -0
  128. package/lib/offline/storage.js +14 -7
  129. package/lib/player.js +1098 -1537
  130. package/lib/polyfill/mediasource.js +22 -1
  131. package/lib/text/cue.js +15 -0
  132. package/lib/text/mp4_ttml_parser.js +2 -2
  133. package/lib/text/srt_text_parser.js +2 -2
  134. package/lib/text/stub_text_displayer.js +51 -0
  135. package/lib/text/text_engine.js +3 -2
  136. package/lib/text/ttml_text_parser.js +45 -5
  137. package/lib/text/ui_text_displayer.js +8 -0
  138. package/lib/text/vtt_text_parser.js +40 -22
  139. package/lib/transmuxer/aac_transmuxer.js +1 -1
  140. package/lib/transmuxer/ac3_transmuxer.js +1 -1
  141. package/lib/transmuxer/ec3_transmuxer.js +1 -1
  142. package/lib/transmuxer/h264.js +5 -4
  143. package/lib/transmuxer/h265.js +863 -0
  144. package/lib/transmuxer/mp3_transmuxer.js +1 -1
  145. package/lib/transmuxer/mpeg_ts_transmuxer.js +4 -3
  146. package/lib/transmuxer/mss_transmuxer.js +1 -1
  147. package/lib/transmuxer/ts_transmuxer.js +187 -22
  148. package/lib/util/buffer_utils.js +26 -4
  149. package/lib/util/content_steering_manager.js +358 -0
  150. package/lib/util/error.js +30 -15
  151. package/lib/util/exp_golomb.js +30 -2
  152. package/lib/util/fairplay_utils.js +1 -1
  153. package/lib/util/fake_event.js +8 -1
  154. package/lib/util/id3_utils.js +50 -1
  155. package/lib/util/manifest_parser_utils.js +12 -8
  156. package/lib/util/mp4_generator.js +6 -8
  157. package/lib/util/mutex.js +59 -0
  158. package/lib/util/object_utils.js +1 -1
  159. package/lib/util/periods.js +156 -179
  160. package/lib/util/platform.js +44 -3
  161. package/lib/util/player_configuration.js +43 -6
  162. package/lib/util/state_history.js +6 -2
  163. package/lib/util/stream_utils.js +206 -283
  164. package/lib/util/ts_parser.js +335 -98
  165. package/lib/util/uint8array_utils.js +5 -1
  166. package/lib/util/xml_utils.js +5 -0
  167. package/maintained-branches.md +3 -2
  168. package/package.json +4 -6
  169. package/roadmap.md +25 -5
  170. package/shaka-player.uncompiled.js +2 -2
  171. package/support.html +0 -1
  172. package/test/abr/simple_abr_manager_unit.js +33 -33
  173. package/test/ads/ad_manager_unit.js +3 -2
  174. package/test/cast/cast_receiver_integration.js +50 -4
  175. package/test/cast/cast_utils_unit.js +2 -0
  176. package/test/cea/cea_decoder_unit.js +7 -0
  177. package/test/codec_switching/codec_switching_integration.js +182 -0
  178. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  179. package/test/dash/dash_parser_integration.js +74 -0
  180. package/test/dash/dash_parser_live_unit.js +2 -19
  181. package/test/dash/dash_parser_manifest_unit.js +536 -2
  182. package/test/dash/dash_parser_segment_base_unit.js +2 -0
  183. package/test/dash/dash_parser_segment_list_unit.js +2 -0
  184. package/test/dash/dash_parser_segment_template_unit.js +2 -0
  185. package/test/dash/mpd_utils_unit.js +61 -30
  186. package/test/demo/demo_unit.js +0 -16
  187. package/test/hls/hls_live_unit.js +14 -3
  188. package/test/hls/hls_parser_unit.js +385 -33
  189. package/test/hls/manifest_text_parser_unit.js +32 -99
  190. package/test/media/adaptation_set_criteria_unit.js +284 -15
  191. package/test/media/adaptation_set_unit.js +2 -0
  192. package/test/media/content_workarounds_unit.js +1 -1
  193. package/test/media/drm_engine_unit.js +3 -3
  194. package/test/media/media_source_engine_unit.js +166 -2
  195. package/test/media/play_rate_controller_unit.js +0 -48
  196. package/test/media/segment_index_unit.js +5 -4
  197. package/test/media/segment_prefetch_unit.js +1 -1
  198. package/test/media/streaming_engine_unit.js +17 -17
  199. package/test/mss/mss_parser_unit.js +2 -0
  200. package/test/mss/mss_player_integration.js +3 -2
  201. package/test/net/networking_engine_unit.js +3 -3
  202. package/test/{media/manifest_parser_unit.js → net/networking_utils_unit.js} +2 -2
  203. package/test/offline/manifest_convert_unit.js +14 -0
  204. package/test/offline/offline_integration.js +2 -1
  205. package/test/offline/storage_integration.js +22 -13
  206. package/test/player_external.js +4 -2
  207. package/test/player_integration.js +15 -4
  208. package/test/player_load_graph_integration.js +47 -151
  209. package/test/player_src_equals_external.js +1 -0
  210. package/test/player_src_equals_integration.js +71 -4
  211. package/test/player_unit.js +182 -158
  212. package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
  213. package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
  214. package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
  215. package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
  216. package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
  217. package/test/test/assets/dash-aes-128/dash.mpd +18 -0
  218. package/test/test/assets/dash-aes-128/license +1 -0
  219. package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
  220. package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
  221. package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
  222. package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
  223. package/test/test/assets/hls-ts-h265/0.ts +0 -0
  224. package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
  225. package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
  226. package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
  227. package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
  228. package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
  229. package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
  230. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
  231. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
  232. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
  233. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
  234. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
  235. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
  236. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
  237. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
  238. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
  239. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
  240. package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
  241. package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
  242. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
  243. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
  244. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
  245. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
  246. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
  247. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
  248. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
  249. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
  250. package/test/test/util/dash_parser_util.js +4 -0
  251. package/test/test/util/fake_ad_manager.js +20 -0
  252. package/test/test/util/fake_media_source_engine.js +13 -2
  253. package/test/test/util/fake_networking_engine.js +9 -1
  254. package/test/test/util/fake_segment_prefetch.js +3 -0
  255. package/test/test/util/manifest_generator.js +11 -3
  256. package/test/test/util/manifest_parser_util.js +14 -2
  257. package/test/test/util/mss_parser_util.js +4 -0
  258. package/test/test/util/offline_utils.js +2 -0
  259. package/test/test/util/simple_fakes.js +2 -2
  260. package/test/test/util/streaming_engine_util.js +10 -4
  261. package/test/test/util/test_scheme.js +6 -0
  262. package/test/test/util/ui_utils.js +4 -3
  263. package/test/text/mp4_ttml_parser_unit.js +4 -4
  264. package/test/text/srt_text_parser_unit.js +1 -1
  265. package/test/text/text_displayer_layout_unit.js +1 -1
  266. package/test/text/text_engine_unit.js +6 -0
  267. package/test/text/ttml_text_parser_unit.js +85 -2
  268. package/test/text/vtt_text_parser_unit.js +103 -31
  269. package/test/transmuxer/transmuxer_engine_integration.js +9 -0
  270. package/test/transmuxer/transmuxer_integration.js +150 -3
  271. package/test/ui/ad_ui_unit.js +2 -2
  272. package/test/ui/ui_customization_unit.js +17 -16
  273. package/test/ui/ui_integration.js +30 -20
  274. package/test/ui/ui_unit.js +28 -29
  275. package/test/util/buffer_utils_unit.js +1 -1
  276. package/test/util/content_steering_manager_unit.js +427 -0
  277. package/test/util/id3_utils_unit.js +52 -0
  278. package/test/util/stream_utils_unit.js +207 -169
  279. package/test/util/ts_parser_unit.js +3 -3
  280. package/third_party/closure-uri/uri.js +13 -1
  281. package/ui/audio_language_selection.js +9 -2
  282. package/ui/controls.js +125 -0
  283. package/ui/externs/ui.js +24 -2
  284. package/ui/language_utils.js +43 -8
  285. package/ui/less/range_elements.less +33 -0
  286. package/ui/locales/en.json +1 -0
  287. package/ui/locales/es-419.json +1 -0
  288. package/ui/locales/es.json +1 -0
  289. package/ui/locales/source.json +4 -0
  290. package/ui/localization.js +10 -0
  291. package/ui/pip_button.js +22 -120
  292. package/ui/remote_button.js +203 -0
  293. package/ui/resolution_selection.js +47 -10
  294. package/ui/seek_bar.js +296 -3
  295. package/ui/text_selection.js +2 -1
  296. package/ui/ui.js +11 -4
  297. package/demo/common/message_ids.js +0 -309
  298. package/demo/locales/en.json +0 -288
  299. package/demo/locales/source.json +0 -1146
  300. package/externs/mux.js +0 -69
  301. package/lib/lcevc/lcevc_dil.js +0 -152
  302. package/lib/routing/node.js +0 -23
  303. package/lib/routing/payload.js +0 -43
  304. package/lib/routing/walker.js +0 -587
  305. package/lib/transmuxer/muxjs_transmuxer.js +0 -242
  306. package/test/routing/walker_unit.js +0 -504
  307. package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
@@ -1,504 +0,0 @@
1
- /*! @license
2
- * Shaka Player
3
- * Copyright 2016 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- describe('Walker', () => {
8
- const AbortableOperation = shaka.util.AbortableOperation;
9
-
10
- // For our tests, we will not use the payload in our routing logic. To
11
- // avoid distracting the reader with payload details, hide them here.
12
- const payload = {
13
- factory: null,
14
- mediaElement: null,
15
- mimeType: null,
16
- startTime: null,
17
- startTimeOfLoad: NaN,
18
- uri: null,
19
- };
20
-
21
- // The graph topology that we will be using for our tests.
22
- //
23
- // [ A ] ---> [ B ] ---> [ E ]
24
- // ^ |
25
- // | v
26
- // [ D ] <--- [ C ]
27
- //
28
- /** @type {shaka.routing.Node} */
29
- const nodeA = {name: 'a'};
30
- /** @type {shaka.routing.Node} */
31
- const nodeB = {name: 'b'};
32
- /** @type {shaka.routing.Node} */
33
- const nodeC = {name: 'c'};
34
- /** @type {shaka.routing.Node} */
35
- const nodeD = {name: 'd'};
36
- /** @type {shaka.routing.Node} */
37
- const nodeE = {name: 'e'};
38
-
39
- /**
40
- * @param {shaka.routing.Node} at
41
- * @param {shaka.routing.Node} goingTo
42
- * @return {shaka.routing.Node}
43
- */
44
- function getNext(at, goingTo) {
45
- // In this graph, where you start determines where you go. The one exception
46
- // is node B, which acts as a fork between nodes C and E. This fork is
47
- // important in testing interrupts.
48
-
49
- let goTo = null;
50
-
51
- if (at == nodeA) {
52
- goTo = nodeB;
53
- }
54
-
55
- if (at == nodeB) {
56
- goTo = goingTo == nodeE ? nodeE : nodeC;
57
- }
58
-
59
- if (at == nodeC) {
60
- goTo = nodeD;
61
- }
62
-
63
- if (at == nodeD) {
64
- goTo = nodeA;
65
- }
66
-
67
- goog.asserts.assert(goTo, 'We should have found a next step.');
68
- return goTo;
69
- }
70
-
71
- /** @type {!shaka.routing.Walker} */
72
- let walker;
73
-
74
- /** @type {!jasmine.Spy} */
75
- let enterNodeSpy;
76
-
77
- /** @type {!jasmine.Spy} */
78
- let handleErrorSpy;
79
-
80
- /** @type {!jasmine.Spy} */
81
- let idleSpy;
82
-
83
- beforeEach(() => {
84
- enterNodeSpy = jasmine.createSpy('enterNode');
85
- enterNodeSpy.and.returnValue(AbortableOperation.completed(undefined));
86
-
87
- handleErrorSpy = jasmine.createSpy('handleError');
88
-
89
- idleSpy = jasmine.createSpy('idle');
90
-
91
- const implementation = {
92
- getNext: (at, has, goingTo, wants) => getNext(at, goingTo),
93
- enterNode: shaka.test.Util.spyFunc(enterNodeSpy),
94
- handleError: shaka.test.Util.spyFunc(handleErrorSpy),
95
- onIdle: shaka.test.Util.spyFunc(idleSpy),
96
- };
97
-
98
- walker = new shaka.routing.Walker(nodeA, payload, implementation);
99
- });
100
-
101
- afterEach(async () => {
102
- await walker.destroy();
103
- });
104
-
105
- it('enters idle after initialization', async () => {
106
- await waitOnSpy(idleSpy);
107
- });
108
-
109
- it('enters idle after completing route', async () => {
110
- // Execute a route but then wait a couple interrupter cycles to allow the
111
- // walker time to idle.
112
- await completesRoute(startNewRoute(nodeD, /* interruptible= */ false));
113
- await waitOnSpy(idleSpy);
114
- });
115
-
116
- it('enters idle after error', async () => {
117
- // The specific error does not matter.
118
- const error = new shaka.util.Error(
119
- shaka.util.Error.Severity.CRITICAL,
120
- shaka.util.Error.Category.TEXT,
121
- shaka.util.Error.Code.BAD_ENCODING);
122
-
123
- enterNodeSpy.and.callFake((at) => {
124
- return at == nodeC ?
125
- shaka.util.AbortableOperation.failed(error) :
126
- shaka.util.AbortableOperation.completed(undefined);
127
- });
128
-
129
- handleErrorSpy.and.returnValue(nodeA);
130
-
131
- // Go to nodeD, passing through nodeC. This will fail, calling handleError,
132
- // and returning the walker to nodeA. Wait a couple interrupter cycles to
133
- // allow the walker time to idle. The route needs to be interruptible since
134
- // we are going to return an aborted operation.
135
- await failsRoute(startNewRoute(nodeD, /* interruptible= */ true));
136
- await waitOnSpy(idleSpy);
137
- });
138
-
139
- // The walker should move node-by-node, so starting in node A (see beforeEach)
140
- // and going to nodeD, we should see the walker enter nodeB, nodeC, and nodeD.
141
- // We won't see it enter nodeA because it starts there and therefore never
142
- // "enters" that node.
143
- it('moves node-by-node', async () => {
144
- // We don't expect any errors in this test.
145
- handleErrorSpy.and.callFake(fail);
146
-
147
- await completesRoute(startNewRoute(nodeD, /* interruptible= */ false));
148
-
149
- const steps = getStepsTaken();
150
- expect(steps).toEqual([nodeB, nodeC, nodeD]);
151
- });
152
-
153
- // We want to make sure that if a route is registered as interruptible, we
154
- // can interrupt the route and start a new route.
155
- //
156
- // For this we will have the walker start going to node E, but when it
157
- // enters node B (the fork) we will interrupt it and tell it to go to
158
- // node A.
159
- it('can interrupt interruptible routes', async () => {
160
- // We don't expect any errors in this test.
161
- handleErrorSpy.and.callFake(fail);
162
-
163
- /** @type {!shaka.util.PublicPromise} */
164
- const atA = new shaka.util.PublicPromise();
165
- const interrupt = () => {
166
- const goToA = startNewRoute(nodeA, /* interruptible= */ false);
167
- goToA.onEnd = () => atA.resolve();
168
- };
169
-
170
- const goingToE = startNewRoute(nodeE, /* interruptible= */ true);
171
- goingToE.onEnter = (node) => {
172
- if (node == nodeB) {
173
- interrupt();
174
- }
175
- };
176
-
177
- await atA;
178
-
179
- const steps = getStepsTaken();
180
- expect(steps).toEqual([nodeB, nodeC, nodeD, nodeA]);
181
- });
182
-
183
- // We want to make sure that a non-interruptible route cannot be interrupted
184
- // by starting a new route. To do this, we are going to start off by going to
185
- // node c. When we get to node b, we will try to start a new route to node e.
186
- //
187
- // If the route was interrupted, we would go to straight to node e (node b is
188
- // a fork in the graph). However, since we expect the first route to finish,
189
- // we expect to see the walker go to node c and then continue around to get to
190
- // node e.
191
- it('cannot interrupt non-interruptible routes', async () => {
192
- // We don't expect any errors in this test.
193
- handleErrorSpy.and.callFake(fail);
194
-
195
- /** @type {!shaka.util.PublicPromise} */
196
- const atE = new shaka.util.PublicPromise();
197
-
198
- const interrupt = () => {
199
- const goToE = startNewRoute(nodeE, /* interruptible= */ false);
200
- goToE.onEnd = () => atE.resolve();
201
- };
202
-
203
- // Create a "trap" so that once we enter node B (the fork) that we will
204
- // issue a new route - this will ensure that we are trying to interrupt a
205
- // route mid-execution.
206
- const goingToC = startNewRoute(nodeC, /* interruptible= */ false);
207
- goingToC.onEnter = (node) => {
208
- interrupt();
209
- };
210
-
211
- await atE;
212
-
213
- const steps = getStepsTaken();
214
- expect(steps).toEqual([
215
- // First route.
216
- nodeB, nodeC,
217
- // Second route.
218
- nodeD, nodeA, nodeB, nodeE,
219
- ]);
220
- });
221
-
222
- // We do not want to execute steps for a route that will be interrupted
223
- // right after it starts. For this example, we queue-up three routes:
224
- // 1. Non-interruptible
225
- // 2. Interruptible
226
- // 3. Interruptible
227
- //
228
- // What we expect to see is that Route 1 finishes, Route 2 starts but takes
229
- // no steps, and Route 3 finishes.
230
- it('does not take steps for route interrupted before starting', async () => {
231
- /**
232
- * When a route starts, it will assign this value to its id (1, 2, or 3)
233
- * so we always know who was the most recent route to start.
234
- *
235
- * @type {?number}
236
- */
237
- let currentRoute = null;
238
-
239
- /**
240
- * We use this set to know who took steps. When the walker takes a step
241
- * we will add |currentRoute| to this set. That way we will know what
242
- * route we took steps on.
243
- *
244
- * @type {!Array.<?number>}
245
- */
246
- const tookSteps = [];
247
-
248
- enterNodeSpy.and.callFake((node) => {
249
- tookSteps.push(currentRoute);
250
- return AbortableOperation.completed(undefined);
251
- });
252
-
253
- const route1 = startNewRoute(nodeD, /* interruptible= */ false);
254
- route1.onStart = () => {
255
- currentRoute = 1;
256
- };
257
-
258
- const route2 = startNewRoute(nodeC, /* interruptible= */ true);
259
- route2.onStart = () => {
260
- currentRoute = 2;
261
- };
262
-
263
- const route3 = startNewRoute(nodeE, /* interruptible= */ true);
264
- route3.onStart = () => {
265
- currentRoute = 3;
266
- };
267
-
268
- // Wait until we get to the end of route 3, that should be the end.
269
- await completesRoute(route3);
270
-
271
- // Make sure we had the correct routes when taking each step.
272
- expect(tookSteps).toEqual([
273
- 1, // A to B
274
- 1, // B to C
275
- 1, // C to D
276
- 3, // D to A
277
- 3, // A to B
278
- 3, // B to E
279
- ]);
280
- });
281
-
282
- // When we destroy the walker, it should cancel all routes - even the
283
- // non-interruptible routes.
284
- it('cancels all routes when destroyed', async () => {
285
- // Start-up a couple routes, and then destroy the walker. We expect to see
286
- // both routes have their |onCancel| callbacks called. We make the first
287
- // be non-interruptible and the second route interruptible so that we can
288
- // see both types be cancelled by |destroy|. The non-interruptible route
289
- // must before first or else it would interrupt the other route.
290
- const goToC = startNewRoute(nodeC, /* interruptible= */ false);
291
- const goToB = startNewRoute(nodeB, /* interruptible= */ true);
292
-
293
- /** @type {!jasmine.Spy} */
294
- const canceledCSpy = jasmine.createSpy('cancel c');
295
- goToC.onCancel = shaka.test.Util.spyFunc(canceledCSpy);
296
-
297
- /** @type {!jasmine.Spy} */
298
- const canceledBSpy = jasmine.createSpy('cancel b');
299
- goToB.onCancel = shaka.test.Util.spyFunc(canceledBSpy);
300
-
301
- await walker.destroy();
302
-
303
- expect(canceledCSpy).toHaveBeenCalled();
304
- expect(canceledBSpy).toHaveBeenCalled();
305
- });
306
-
307
- it('calls handleError when step fails', async () => {
308
- // The specific error does not matter.
309
- const error = new shaka.util.Error(
310
- shaka.util.Error.Severity.CRITICAL,
311
- shaka.util.Error.Category.TEXT,
312
- shaka.util.Error.Code.BAD_ENCODING);
313
-
314
- // Make the walker fail when it hits node C. This should allow us to
315
- // exercise the |handleError| path.
316
- enterNodeSpy.and.callFake((at) => {
317
- return at == nodeC ?
318
- shaka.util.AbortableOperation.failed(error) :
319
- shaka.util.AbortableOperation.completed(undefined);
320
- });
321
-
322
- // We want to handle the error and return to a safe state, so just put the
323
- // walker back at node A.
324
- handleErrorSpy.and.returnValue(nodeA);
325
-
326
- // Go to D (passing through C). This should throw an error, so wait for the
327
- // error to be seen. The route must be abortable because we are going to
328
- // throw an abortable error.
329
- await failsRoute(startNewRoute(nodeD, /* interruptible= */ true));
330
-
331
- expect(handleErrorSpy).toHaveBeenCalled();
332
- });
333
-
334
- // When we interrupt a route that has a step that can be aborted, it should
335
- // abort the operation and enter the error recovery mode.
336
- //
337
- // To model this we will make a node be a never-resolving node. We will enter
338
- // the node and then get stuck. From there we will request a new route, the
339
- // blocked op will abort, and then we will go to our new destination.
340
- it('can abort current step', async () => {
341
- // Because we need a node to start at after resetting, we will just use A.
342
- // There is no special reason for node A.
343
- handleErrorSpy.and.returnValue(Promise.resolve(nodeA));
344
-
345
- // Block when we enter node C so that we can re-route to node E and finish a
346
- // path.
347
- blockWalkerAt(nodeC);
348
-
349
- // Wait for us to enter node d before continuing. We introduce a small delay
350
- // to ensure that we are "stuck" on the abortable operation.
351
- const goingToD = startNewRoute(nodeD, /* interruptible= */ true);
352
- await waitUntilEntering(goingToD, nodeC);
353
- await shaka.test.Util.shortDelay();
354
-
355
- await completesRoute(startNewRoute(nodeE, /* interruptible= */ true));
356
- expect(handleErrorSpy).toHaveBeenCalled();
357
- });
358
-
359
- // If we are in the middle of a node and |destroy| is called, we want to
360
- // ensure that we exit as soon as possible. If the current step is abortable
361
- // then we want to abort.
362
- it('can abort current step with destroy', async () => {
363
- // Because we need a node to start at after resetting, we will just use A.
364
- // There is no special reason for node A.
365
- handleErrorSpy.and.returnValue(Promise.resolve(nodeA));
366
-
367
- // Block when we enter node C so that we can re-route to node E and finish a
368
- // path.
369
- blockWalkerAt(nodeC);
370
-
371
- // Wait for us to enter node d before continuing. We introduce a small delay
372
- // to ensure that we are "stuck" on the abortable operation.
373
- const goingToD = startNewRoute(nodeD, /* interruptible= */ true);
374
- await waitUntilEntering(goingToD, nodeC);
375
- await shaka.test.Util.shortDelay();
376
-
377
- // We are "stuck" in nodeC. We will now destroy the walker which should
378
- // abort the nodeC step, enter error recovery mode, and then shutdown.
379
- await walker.destroy();
380
- expect(handleErrorSpy).toHaveBeenCalled();
381
- });
382
-
383
- /**
384
- * Ask the walker to start a new route. Since the requests from our tests
385
- * are very basic, wrapping the call should not hide too much information.
386
- *
387
- * @param {shaka.routing.Node} goingTo
388
- * @param {boolean} interruptible
389
- *
390
- * @return {shaka.routing.Walker.Listeners}
391
- */
392
- function startNewRoute(goingTo, interruptible) {
393
- return walker.startNewRoute((currentPayload) => {
394
- return {
395
- node: goingTo,
396
- payload: payload,
397
- interruptible: interruptible,
398
- };
399
- });
400
- }
401
-
402
- /**
403
- * Get the series of nodes that the walker went through during its "journey".
404
- *
405
- * @return {!Array.<shaka.routing.Node>}
406
- */
407
- function getStepsTaken() {
408
- // Use |onNode| to get the steps that completed.
409
- return enterNodeSpy.calls.allArgs().map((args) => args[0]);
410
- }
411
-
412
- /**
413
- * Configure the |enterNodeSpy| so that we will block when we enter |node|. In
414
- * order to unblock, the route will need to be interrupted.
415
- *
416
- * @param {shaka.routing.Node} node
417
- */
418
- function blockWalkerAt(node) {
419
- /** @type {!shaka.util.AbortableOperation} */
420
- const completedOp = AbortableOperation.completed(undefined);
421
-
422
- /** @type {!shaka.util.PublicPromise} */
423
- const waitForever = new shaka.util.PublicPromise();
424
-
425
- /** @type {!shaka.util.AbortableOperation} */
426
- const blockingOp = new AbortableOperation(
427
- waitForever,
428
- () => {
429
- waitForever.reject(new shaka.util.Error(
430
- shaka.util.Error.Severity.CRITICAL,
431
- shaka.util.Error.Category.PLAYER,
432
- shaka.util.Error.Code.OPERATION_ABORTED));
433
-
434
- return waitForever;
435
- });
436
-
437
- enterNodeSpy.and.callFake((at) => {
438
- return at == node ? blockingOp : completedOp;
439
- });
440
- }
441
-
442
- /**
443
- * Create a promise that will resolve when we enter |node| while on the route
444
- * that produced |events|.
445
- *
446
- * @param {shaka.routing.Walker.Listeners} events
447
- * @param {shaka.routing.Node} node
448
- * @return {!Promise}
449
- */
450
- function waitUntilEntering(events, node) {
451
- return new Promise((resolve) => {
452
- events.onEnter = (node) => {
453
- if (node == nodeC) {
454
- resolve();
455
- }
456
- };
457
- });
458
- }
459
-
460
- /**
461
- * Create a promise from a walker's route's listeners. This assumes that the
462
- * route should finish. The promise will resolve if the route completes and
463
- * will reject if the route fails to complete for any reason.
464
- *
465
- * @param {shaka.routing.Walker.Listeners} events
466
- * @return {!Promise}
467
- */
468
- function completesRoute(events) {
469
- return new Promise((resolve, reject) => {
470
- events.onEnd = resolve;
471
- events.onCancel = reject;
472
- events.onError = reject;
473
- });
474
- }
475
-
476
- /**
477
- * Create a promise from a walker's route's listeners. This assumes that the
478
- * route should not finish. The promise will resolve if the route fails and
479
- * will reject if the route completes.
480
- *
481
- * @param {shaka.routing.Walker.Listeners} events
482
- * @return {!Promise}
483
- */
484
- function failsRoute(events) {
485
- return new Promise((resolve, reject) => {
486
- events.onEnd = reject;
487
- events.onCancel = resolve;
488
- events.onError = resolve;
489
- });
490
- }
491
-
492
- /**
493
- * Wrap a spy in a promise so that the promise will resolve once the spy is
494
- * called.
495
- *
496
- * @param {!jasmine.Spy} spy
497
- * @return {!Promise}
498
- */
499
- function waitOnSpy(spy) {
500
- return new Promise((resolve) => {
501
- spy.and.callFake(resolve);
502
- });
503
- }
504
- });
@@ -1,177 +0,0 @@
1
- /*! @license
2
- * Shaka Player
3
- * Copyright 2016 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- describe('MuxjsTransmuxer', () => {
8
- const ContentType = shaka.util.ManifestParserUtils.ContentType;
9
-
10
- const videoSegmentUri = '/base/test/test/assets/video.ts';
11
- const audioSegmentUri = '/base/test/test/assets/audio.ts';
12
- const mp4MimeType = 'video/mp4; codecs="avc1.42E01E"';
13
- const transportStreamVideoMimeType = 'video/mp2t; codecs="avc1.42E01E"';
14
- const transportStreamAudioMimeType = 'video/mp2t; codecs="mp4a.40.2"';
15
-
16
- /** @type {!ArrayBuffer} */
17
- let videoSegment;
18
- /** @type {!ArrayBuffer} */
19
- let audioSegment;
20
- /** @type {!ArrayBuffer} */
21
- let emptySegment;
22
-
23
- /** @type {?shaka.transmuxer.MuxjsTransmuxer} */
24
- let transmuxer;
25
-
26
- function useTsTransmuxer() {
27
- transmuxer = new shaka.transmuxer.MuxjsTransmuxer('video/mp2t');
28
- }
29
-
30
- beforeAll(async () => {
31
- const responses = await Promise.all([
32
- shaka.test.Util.fetch(videoSegmentUri),
33
- shaka.test.Util.fetch(audioSegmentUri),
34
- ]);
35
- videoSegment = responses[0];
36
- audioSegment = responses[1];
37
- emptySegment = new ArrayBuffer(0);
38
- });
39
-
40
- beforeEach(() => {
41
- transmuxer = null;
42
- });
43
-
44
- afterEach(async () => {
45
- await transmuxer.destroy();
46
- });
47
-
48
- describe('isSupported', () => {
49
- it('returns whether the content type is supported', () => {
50
- useTsTransmuxer();
51
- expect(transmuxer.isSupported(
52
- mp4MimeType, ContentType.VIDEO)).toBe(false);
53
- expect(transmuxer.isSupported(
54
- transportStreamVideoMimeType, ContentType.VIDEO)).toBe(true);
55
- });
56
-
57
- // Issue #1991
58
- it('handles upper-case MIME types', () => {
59
- useTsTransmuxer();
60
- const mimeType = transportStreamVideoMimeType.replace('mp2t', 'MP2T');
61
- expect(transmuxer.isSupported(
62
- mimeType, ContentType.VIDEO)).toBe(true);
63
- });
64
- });
65
-
66
- describe('convertCodecs', () => {
67
- const convertCodecs =
68
- (type, codecs) => transmuxer.convertCodecs(type, codecs);
69
-
70
- it('returns converted codecs for TS', () => {
71
- useTsTransmuxer();
72
- const convertedVideoCodecs =
73
- convertCodecs(ContentType.VIDEO, transportStreamVideoMimeType);
74
- const convertedAudioCodecs =
75
- convertCodecs(ContentType.AUDIO, transportStreamAudioMimeType);
76
- const expectedVideoCodecs = 'video/mp4; codecs="avc1.42E01E"';
77
- const expectedAudioCodecs = 'audio/mp4; codecs="mp4a.40.2"';
78
- expect(convertedVideoCodecs).toBe(expectedVideoCodecs);
79
- expect(convertedAudioCodecs).toBe(expectedAudioCodecs);
80
- });
81
-
82
- it('converts legacy avc1 codec strings', () => {
83
- useTsTransmuxer();
84
- expect(
85
- convertCodecs(
86
- ContentType.VIDEO, 'video/mp2t; codecs="avc1.100.42"'))
87
- .toBe('video/mp4; codecs="avc1.64002a"');
88
- expect(
89
- convertCodecs(ContentType.VIDEO, 'video/mp2t; codecs="avc1.77.80"'))
90
- .toBe('video/mp4; codecs="avc1.4d0050"');
91
- expect(
92
- convertCodecs(ContentType.VIDEO, 'video/mp2t; codecs="avc1.66.1"'))
93
- .toBe('video/mp4; codecs="avc1.420001"');
94
- });
95
-
96
- // Issue #1991
97
- it('handles upper-case MIME types', () => {
98
- useTsTransmuxer();
99
- expect(convertCodecs(
100
- ContentType.VIDEO, 'video/MP2T; codecs="avc1.420001"'))
101
- .toBe('video/mp4; codecs="avc1.420001"');
102
- });
103
- });
104
-
105
- describe('transmuxing', () => {
106
- it('transmux video from TS to MP4', async () => {
107
- useTsTransmuxer();
108
- let sawMDAT = false;
109
-
110
- const transmuxedData = await transmuxer.transmux(videoSegment);
111
- expect(transmuxedData).toEqual(jasmine.any(Uint8Array));
112
- expect(transmuxedData.length).toBeGreaterThan(0);
113
- new shaka.util.Mp4Parser()
114
- .box('mdat', shaka.util.Mp4Parser.allData((data) => {
115
- sawMDAT = true;
116
- expect(data.byteLength).toBeGreaterThan(0);
117
- }))
118
- .parse(transmuxedData);
119
- expect(sawMDAT).toBeTruthy();
120
- });
121
-
122
- it('transmux audio from TS to MP4', async () => {
123
- useTsTransmuxer();
124
- let sawMDAT = false;
125
- const transmuxedData = await transmuxer.transmux(audioSegment);
126
- expect(transmuxedData).toEqual(jasmine.any(Uint8Array));
127
- expect(transmuxedData.length).toBeGreaterThan(0);
128
- new shaka.util.Mp4Parser()
129
- .box('mdat', shaka.util.Mp4Parser.allData((data) => {
130
- sawMDAT = true;
131
- expect(data.byteLength).toBeGreaterThan(0);
132
- }))
133
- .parse(transmuxedData);
134
- expect(sawMDAT).toBeTruthy();
135
- });
136
-
137
- it('transmux empty video from TS to MP4', async () => {
138
- useTsTransmuxer();
139
- let sawMDAT = false;
140
- const transmuxedData = await transmuxer.transmux(emptySegment);
141
- expect(transmuxedData).toEqual(jasmine.any(Uint8Array));
142
- new shaka.util.Mp4Parser()
143
- .box('mdat', shaka.util.Mp4Parser.allData((data) => {
144
- sawMDAT = true;
145
- }))
146
- .parse(transmuxedData);
147
- expect(sawMDAT).toBeFalsy();
148
- });
149
-
150
- it('passes through true timestamps', async () => {
151
- useTsTransmuxer();
152
- let parsed = false;
153
- const expectedMp4Timestamp = 5166000; // in timescale units
154
- let mp4Timestamp;
155
-
156
- const transmuxedData = await transmuxer.transmux(videoSegment);
157
- const Mp4Parser = shaka.util.Mp4Parser;
158
-
159
- new Mp4Parser()
160
- .box('moof', Mp4Parser.children)
161
- .box('traf', Mp4Parser.children)
162
- .fullBox('tfdt', (box) => {
163
- goog.asserts.assert(
164
- box.version == 0 || box.version == 1,
165
- 'TFDT version can only be 0 or 1');
166
- const parsedTFDTBox = shaka.util.Mp4BoxParsers.parseTFDT(
167
- box.reader, box.version);
168
- mp4Timestamp = parsedTFDTBox.baseMediaDecodeTime;
169
- parsed = true;
170
- })
171
- .parse(transmuxedData);
172
-
173
- expect(parsed).toBe(true);
174
- expect(mp4Timestamp).toBe(expectedMp4Timestamp);
175
- });
176
- });
177
- });