shaka-player 4.4.2 → 4.5.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 (202) hide show
  1. package/.github/workflows/release-please.yaml +2 -27
  2. package/CHANGELOG.md +67 -25
  3. package/README.md +16 -10
  4. package/demo/asset_card.js +18 -21
  5. package/demo/cast_receiver/index.html +0 -1
  6. package/demo/close_button.js +0 -3
  7. package/demo/common/asset.js +27 -5
  8. package/demo/common/assets.js +150 -52
  9. package/demo/config.js +192 -253
  10. package/demo/custom.js +39 -98
  11. package/demo/front.js +7 -10
  12. package/demo/index.html +19 -22
  13. package/demo/input.js +6 -11
  14. package/demo/input_container.js +8 -9
  15. package/demo/main.js +52 -124
  16. package/demo/search.js +23 -35
  17. package/demo/service_worker.js +0 -3
  18. package/demo/tooltip.js +3 -5
  19. package/demo/visualizer.js +3 -5
  20. package/demo/visualizer_button.js +1 -20
  21. package/dist/demo.compiled.debug.js +187 -211
  22. package/dist/demo.compiled.debug.map +4 -4
  23. package/dist/demo.compiled.js +187 -211
  24. package/dist/demo.compiled.map +4 -4
  25. package/dist/deps.js +27 -24
  26. package/dist/locales.js +31 -31
  27. package/dist/receiver.compiled.debug.js +42 -61
  28. package/dist/receiver.compiled.debug.map +4 -4
  29. package/dist/receiver.compiled.js +42 -61
  30. package/dist/receiver.compiled.map +4 -4
  31. package/dist/shaka-player.compiled.d.ts +728 -365
  32. package/dist/shaka-player.compiled.debug.d.ts +728 -365
  33. package/dist/shaka-player.compiled.debug.externs.js +475 -51
  34. package/dist/shaka-player.compiled.debug.js +576 -480
  35. package/dist/shaka-player.compiled.debug.map +4 -4
  36. package/dist/shaka-player.compiled.externs.js +475 -51
  37. package/dist/shaka-player.compiled.js +1117 -1056
  38. package/dist/shaka-player.compiled.map +4 -4
  39. package/dist/shaka-player.ui.d.ts +783 -410
  40. package/dist/shaka-player.ui.debug.d.ts +783 -410
  41. package/dist/shaka-player.ui.debug.externs.js +496 -51
  42. package/dist/shaka-player.ui.debug.js +647 -542
  43. package/dist/shaka-player.ui.debug.map +4 -4
  44. package/dist/shaka-player.ui.externs.js +496 -51
  45. package/dist/shaka-player.ui.js +1260 -1194
  46. package/dist/shaka-player.ui.map +4 -4
  47. package/docs/design/lcevc-integration.md +14 -14
  48. package/docs/tutorials/faq.md +27 -55
  49. package/docs/tutorials/index.json +2 -1
  50. package/docs/tutorials/lcevc.md +118 -0
  51. package/docs/tutorials/offline.md +1 -1
  52. package/docs/tutorials/ui-customization.md +4 -0
  53. package/externs/css_style_declaration.js +19 -0
  54. package/externs/lcevc.js +37 -13
  55. package/externs/media_remote.js +68 -0
  56. package/externs/mediatailor.js +193 -0
  57. package/externs/pictureinpicture.js +11 -0
  58. package/externs/shaka/ads.js +27 -0
  59. package/externs/shaka/manifest.js +10 -5
  60. package/externs/shaka/manifest_parser.js +7 -1
  61. package/externs/shaka/offline.js +4 -0
  62. package/externs/shaka/player.js +12 -1
  63. package/karma.conf.js +7 -3
  64. package/lib/abr/simple_abr_manager.js +43 -3
  65. package/lib/ads/ad_manager.js +104 -50
  66. package/lib/ads/media_tailor_ad.js +297 -0
  67. package/lib/ads/media_tailor_ad_manager.js +828 -0
  68. package/lib/cea/ts_cea_parser.js +15 -2
  69. package/lib/config/codec_switching_strategy.js +24 -0
  70. package/lib/dash/content_protection.js +120 -2
  71. package/lib/dash/dash_parser.js +79 -13
  72. package/lib/dash/mpd_utils.js +10 -6
  73. package/lib/dash/segment_base.js +13 -5
  74. package/lib/dash/segment_list.js +13 -5
  75. package/lib/dash/segment_template.js +43 -85
  76. package/lib/dependencies/all.js +8 -7
  77. package/lib/hls/hls_parser.js +101 -37
  78. package/lib/lcevc/lcevc_dec.js +220 -0
  79. package/lib/media/adaptation_set.js +22 -11
  80. package/lib/media/adaptation_set_criteria.js +25 -7
  81. package/lib/media/media_source_engine.js +215 -27
  82. package/lib/media/segment_index.js +5 -5
  83. package/lib/media/segment_reference.js +10 -5
  84. package/lib/media/streaming_engine.js +44 -39
  85. package/lib/mss/mss_parser.js +1 -0
  86. package/lib/net/networking_engine.js +1 -0
  87. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  88. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  89. package/lib/offline/manifest_converter.js +1 -0
  90. package/lib/offline/storage.js +3 -0
  91. package/lib/player.js +142 -72
  92. package/lib/routing/payload.js +5 -1
  93. package/lib/text/cue.js +62 -47
  94. package/lib/text/ttml_text_parser.js +17 -0
  95. package/lib/text/ui_text_displayer.js +4 -0
  96. package/lib/text/vtt_text_parser.js +35 -22
  97. package/lib/transmuxer/h265.js +862 -0
  98. package/lib/transmuxer/mpeg_ts_transmuxer.js +3 -2
  99. package/lib/transmuxer/ts_transmuxer.js +160 -15
  100. package/lib/util/cmcd_manager.js +6 -1
  101. package/lib/util/error.js +28 -9
  102. package/lib/util/exp_golomb.js +30 -2
  103. package/lib/util/fake_event.js +3 -0
  104. package/lib/util/manifest_parser_utils.js +10 -4
  105. package/lib/util/mp4_generator.js +4 -4
  106. package/lib/util/periods.js +2 -0
  107. package/lib/util/platform.js +54 -0
  108. package/lib/util/player_configuration.js +8 -0
  109. package/lib/util/state_history.js +6 -2
  110. package/lib/util/stream_utils.js +133 -217
  111. package/lib/util/ts_parser.js +229 -43
  112. package/maintained-branches.md +3 -2
  113. package/package.json +4 -6
  114. package/roadmap.md +15 -5
  115. package/shaka-player.uncompiled.js +2 -1
  116. package/support.html +0 -1
  117. package/test/cast/cast_receiver_integration.js +47 -0
  118. package/test/codec_switching/codec_switching_integration.js +181 -0
  119. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  120. package/test/dash/dash_parser_integration.js +73 -0
  121. package/test/dash/dash_parser_live_unit.js +2 -0
  122. package/test/dash/dash_parser_manifest_unit.js +47 -0
  123. package/test/dash/dash_parser_segment_base_unit.js +7 -0
  124. package/test/dash/dash_parser_segment_list_unit.js +23 -17
  125. package/test/dash/dash_parser_segment_template_unit.js +49 -0
  126. package/test/demo/demo_unit.js +0 -16
  127. package/test/hls/hls_live_unit.js +35 -0
  128. package/test/hls/hls_parser_unit.js +8 -61
  129. package/test/media/adaptation_set_criteria_unit.js +118 -0
  130. package/test/media/adaptation_set_unit.js +1 -0
  131. package/test/media/media_source_engine_unit.js +165 -1
  132. package/test/media/segment_index_unit.js +4 -4
  133. package/test/media/segment_prefetch_unit.js +1 -1
  134. package/test/media/streaming_engine_unit.js +17 -17
  135. package/test/mss/mss_parser_unit.js +2 -0
  136. package/test/offline/manifest_convert_unit.js +5 -0
  137. package/test/offline/storage_integration.js +1 -4
  138. package/test/player_unit.js +102 -131
  139. package/test/routing/walker_unit.js +1 -0
  140. package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
  141. package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
  142. package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
  143. package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
  144. package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
  145. package/test/test/assets/dash-aes-128/dash.mpd +18 -0
  146. package/test/test/assets/dash-aes-128/license +1 -0
  147. package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
  148. package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
  149. package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
  150. package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
  151. package/test/test/assets/hls-ts-h265/0.ts +0 -0
  152. package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
  153. package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
  154. package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
  155. package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
  156. package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
  157. package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
  158. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
  159. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
  160. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
  161. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
  162. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
  163. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
  164. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
  165. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
  166. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
  167. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
  168. package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
  169. package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
  170. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
  171. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
  172. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
  173. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
  174. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
  175. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
  176. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
  177. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
  178. package/test/test/util/dash_parser_util.js +20 -7
  179. package/test/test/util/fake_ad_manager.js +20 -0
  180. package/test/test/util/fake_media_source_engine.js +8 -2
  181. package/test/test/util/manifest_generator.js +7 -3
  182. package/test/test/util/mss_parser_util.js +4 -0
  183. package/test/test/util/offline_utils.js +1 -0
  184. package/test/test/util/streaming_engine_util.js +7 -4
  185. package/test/text/ttml_text_parser_unit.js +52 -0
  186. package/test/text/vtt_text_parser_unit.js +105 -48
  187. package/test/transmuxer/transmuxer_integration.js +121 -4
  188. package/test/ui/ui_unit.js +3 -10
  189. package/test/util/stream_utils_unit.js +208 -74
  190. package/test/util/ts_parser_unit.js +1 -1
  191. package/ui/controls.js +125 -0
  192. package/ui/externs/ui.js +8 -1
  193. package/ui/pip_button.js +22 -120
  194. package/ui/remote_button.js +201 -0
  195. package/ui/ui.js +5 -2
  196. package/demo/common/message_ids.js +0 -309
  197. package/demo/locales/en.json +0 -287
  198. package/demo/locales/source.json +0 -1142
  199. package/externs/mux.js +0 -69
  200. package/lib/lcevc/lcevc_dil.js +0 -152
  201. package/lib/transmuxer/muxjs_transmuxer.js +0 -242
  202. package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
@@ -0,0 +1,181 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ describe('Codec Switching', () => {
8
+ /** @type {!HTMLVideoElement} */
9
+ let video;
10
+ /** @type {shaka.Player} */
11
+ let player;
12
+ /** @type {!shaka.util.EventManager} */
13
+ let eventManager;
14
+
15
+ let compiledShaka;
16
+
17
+ /** @type {!shaka.test.Waiter} */
18
+ let waiter;
19
+
20
+ beforeAll(async () => {
21
+ video = shaka.test.UiUtils.createVideoElement();
22
+ document.body.appendChild(video);
23
+ compiledShaka =
24
+ await shaka.test.Loader.loadShaka(getClientArg('uncompiled'));
25
+ });
26
+
27
+ beforeEach(async () => {
28
+ await shaka.test.TestScheme.createManifests(compiledShaka, '_compiled');
29
+ player = new compiledShaka.Player(video);
30
+
31
+ // Disable stall detection, which can interfere with playback tests.
32
+ player.configure('streaming.stallEnabled', false);
33
+
34
+ eventManager = new shaka.util.EventManager();
35
+ waiter = new shaka.test.Waiter(eventManager);
36
+ waiter.setPlayer(player);
37
+ });
38
+
39
+ afterEach(async () => {
40
+ eventManager.release();
41
+ await player.destroy();
42
+ });
43
+
44
+ afterAll(() => {
45
+ document.body.removeChild(video);
46
+ });
47
+
48
+ describe('for audio and only-audio content', () => {
49
+ it('can switch codecs RELOAD', async () => {
50
+ if (!MediaSource.isTypeSupported('audio/webm; codecs="opus"')) {
51
+ pending('Codec OPUS in WEBM is not supported by the platform.');
52
+ }
53
+ const preferredAudioLanguage = 'en';
54
+ player.configure({preferredAudioLanguage: preferredAudioLanguage});
55
+ player.configure('manifest.disableVideo', true);
56
+ player.configure('streaming.mediaSource.codecSwitchingStrategy',
57
+ shaka.config.CodecSwitchingStrategy.RELOAD);
58
+
59
+ await player.load('/base/test/test/assets/dash-multi-codec/dash.mpd', 9);
60
+ await video.play();
61
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
62
+
63
+ expect(player.isLive()).toBe(false);
64
+
65
+ let variants = player.getVariantTracks();
66
+
67
+ expect(variants.length).toBe(2);
68
+ expect(variants.find((v) => !!v.active).language).toBe('en');
69
+
70
+ player.selectAudioLanguage('es');
71
+ await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 10, 45);
72
+
73
+ variants = player.getVariantTracks();
74
+
75
+ expect(variants.find((v) => !!v.active).language).toBe('es');
76
+
77
+ await player.unload();
78
+ });
79
+
80
+ it('can switch codecs SMOOTH', async () => {
81
+ if (!shaka.util.Platform.supportsSmoothCodecSwitching()) {
82
+ pending('Mediasource.ChangeType is not considered ' +
83
+ 'reliable on this device');
84
+ }
85
+ if (!MediaSource.isTypeSupported('audio/webm; codecs="opus"')) {
86
+ pending('Codec OPUS in WEBM is not supported by the platform.');
87
+ }
88
+ const preferredAudioLanguage = 'en';
89
+ player.configure({preferredAudioLanguage: preferredAudioLanguage});
90
+ player.configure('manifest.disableVideo', true);
91
+ player.configure('streaming.mediaSource.codecSwitchingStrategy',
92
+ shaka.config.CodecSwitchingStrategy.SMOOTH);
93
+
94
+ await player.load('/base/test/test/assets/dash-multi-codec/dash.mpd', 9);
95
+ await video.play();
96
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
97
+
98
+ expect(player.isLive()).toBe(false);
99
+
100
+ let variants = player.getVariantTracks();
101
+
102
+ expect(variants.length).toBe(2);
103
+ expect(variants.find((v) => !!v.active).language).toBe('en');
104
+
105
+ player.selectAudioLanguage('es');
106
+ await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 10, 45);
107
+
108
+ variants = player.getVariantTracks();
109
+
110
+ expect(variants.find((v) => !!v.active).language).toBe('es');
111
+
112
+ await player.unload();
113
+ });
114
+ });
115
+
116
+ describe('for audio', () => {
117
+ it('can switch codecs RELOAD', async () => {
118
+ if (!MediaSource.isTypeSupported('audio/webm; codecs="opus"')) {
119
+ pending('Codec OPUS in WEBM is not supported by the platform.');
120
+ }
121
+ const preferredAudioLanguage = 'en';
122
+ player.configure({preferredAudioLanguage: preferredAudioLanguage});
123
+ player.configure('streaming.mediaSource.codecSwitchingStrategy',
124
+ shaka.config.CodecSwitchingStrategy.RELOAD);
125
+
126
+ await player.load('/base/test/test/assets/dash-multi-codec/dash.mpd', 9);
127
+ await video.play();
128
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
129
+
130
+ expect(player.isLive()).toBe(false);
131
+
132
+ let variants = player.getVariantTracks();
133
+
134
+ expect(variants.length).toBe(2);
135
+ expect(variants.find((v) => !!v.active).language).toBe('en');
136
+
137
+ player.selectAudioLanguage('es');
138
+ await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 10, 45);
139
+
140
+ variants = player.getVariantTracks();
141
+
142
+ expect(variants.find((v) => !!v.active).language).toBe('es');
143
+
144
+ await player.unload();
145
+ });
146
+
147
+ it('can switch codecs SMOOTH', async () => {
148
+ if (!shaka.util.Platform.supportsSmoothCodecSwitching()) {
149
+ pending('Mediasource.ChangeType is not considered ' +
150
+ 'reliable on this device');
151
+ }
152
+ if (!MediaSource.isTypeSupported('audio/webm; codecs="opus"')) {
153
+ pending('Codec OPUS in WEBM is not supported by the platform.');
154
+ }
155
+ const preferredAudioLanguage = 'en';
156
+ player.configure({preferredAudioLanguage: preferredAudioLanguage});
157
+ player.configure('streaming.mediaSource.codecSwitchingStrategy',
158
+ shaka.config.CodecSwitchingStrategy.SMOOTH);
159
+
160
+ await player.load('/base/test/test/assets/dash-multi-codec/dash.mpd', 9);
161
+ await video.play();
162
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
163
+
164
+ expect(player.isLive()).toBe(false);
165
+
166
+ let variants = player.getVariantTracks();
167
+
168
+ expect(variants.length).toBe(2);
169
+ expect(variants.find((v) => !!v.active).language).toBe('en');
170
+
171
+ player.selectAudioLanguage('es');
172
+ await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 10, 45);
173
+
174
+ variants = player.getVariantTracks();
175
+
176
+ expect(variants.find((v) => !!v.active).language).toBe('es');
177
+
178
+ await player.unload();
179
+ });
180
+ });
181
+ });
@@ -45,6 +45,8 @@ describe('DashParser ContentProtection', () => {
45
45
  enableLowLatencyMode: () => {},
46
46
  updateDuration: () => {},
47
47
  newDrmInfo: (stream) => {},
48
+ onManifestUpdated: () => {},
49
+ getBandwidthEstimate: () => 1e6,
48
50
  };
49
51
 
50
52
  const actual = await dashParser.start(
@@ -0,0 +1,73 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ describe('DashParser', () => {
8
+ const Util = shaka.test.Util;
9
+
10
+ /** @type {!jasmine.Spy} */
11
+ let onErrorSpy;
12
+
13
+ /** @type {!HTMLVideoElement} */
14
+ let video;
15
+ /** @type {shaka.Player} */
16
+ let player;
17
+ /** @type {!shaka.util.EventManager} */
18
+ let eventManager;
19
+
20
+ let compiledShaka;
21
+
22
+ /** @type {!shaka.test.Waiter} */
23
+ let waiter;
24
+
25
+ beforeAll(async () => {
26
+ video = shaka.test.UiUtils.createVideoElement();
27
+ document.body.appendChild(video);
28
+ compiledShaka =
29
+ await shaka.test.Loader.loadShaka(getClientArg('uncompiled'));
30
+ });
31
+
32
+ beforeEach(async () => {
33
+ await shaka.test.TestScheme.createManifests(compiledShaka, '_compiled');
34
+ player = new compiledShaka.Player(video);
35
+
36
+ // Disable stall detection, which can interfere with playback tests.
37
+ player.configure('streaming.stallEnabled', false);
38
+
39
+ // Grab event manager from the uncompiled library:
40
+ eventManager = new shaka.util.EventManager();
41
+ waiter = new shaka.test.Waiter(eventManager);
42
+ waiter.setPlayer(player);
43
+
44
+ onErrorSpy = jasmine.createSpy('onError');
45
+ onErrorSpy.and.callFake((event) => fail(event.detail));
46
+ eventManager.listen(player, 'error', Util.spyFunc(onErrorSpy));
47
+ });
48
+
49
+ afterEach(async () => {
50
+ eventManager.release();
51
+ await player.destroy();
52
+ });
53
+
54
+ afterAll(() => {
55
+ document.body.removeChild(video);
56
+ });
57
+
58
+ it('supports AES-128 streaming', async () => {
59
+ await player.load('/base/test/test/assets/dash-aes-128/dash.mpd');
60
+ await video.play();
61
+ expect(player.isLive()).toBe(false);
62
+
63
+ // Wait for the video to start playback. If it takes longer than 10
64
+ // seconds, fail the test.
65
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
66
+
67
+ // Play for 10 seconds, but stop early if the video ends. If it takes
68
+ // longer than 30 seconds, fail the test.
69
+ await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 10, 30);
70
+
71
+ await player.unload();
72
+ });
73
+ });
@@ -36,6 +36,8 @@ describe('DashParser Live', () => {
36
36
  enableLowLatencyMode: () => {},
37
37
  updateDuration: () => {},
38
38
  newDrmInfo: (stream) => {},
39
+ onManifestUpdated: () => {},
40
+ getBandwidthEstimate: () => 1e6,
39
41
  };
40
42
  });
41
43
 
@@ -54,9 +54,16 @@ describe('DashParser Manifest', () => {
54
54
  enableLowLatencyMode: () => {},
55
55
  updateDuration: () => {},
56
56
  newDrmInfo: (stream) => {},
57
+ onManifestUpdated: () => {},
58
+ getBandwidthEstimate: () => 1e6,
57
59
  };
58
60
  });
59
61
 
62
+ afterEach(() => {
63
+ // Dash parser stop is synchronous.
64
+ parser.stop();
65
+ });
66
+
60
67
  /**
61
68
  * Makes a series of tests for the given manifest type.
62
69
  *
@@ -1175,6 +1182,46 @@ describe('DashParser Manifest', () => {
1175
1182
  expect(trickModeVideo).toBe(null);
1176
1183
  });
1177
1184
 
1185
+ it('populates groupId if configuration enabled', async () => {
1186
+ const manifestText = [
1187
+ '<MPD minBufferTime="PT75S">',
1188
+ ' <Period id="1" duration="PT30S">',
1189
+ ' <AdaptationSet id="1" contentType="text">',
1190
+ ' <Representation id="text-en" mimeType="text/webvtt">',
1191
+ ' <BaseURL>t-en.vtt</BaseURL>',
1192
+ ' </Representation>',
1193
+ ' </AdaptationSet>',
1194
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
1195
+ ' <Representation id="video-sd" width="640" height="480">',
1196
+ ' <BaseURL>v-sd.mp4</BaseURL>',
1197
+ ' <SegmentBase indexRange="100-200" />',
1198
+ ' </Representation>',
1199
+ ' </AdaptationSet>',
1200
+ ' <AdaptationSet id="3" mimeType="audio/mp4">',
1201
+ ' <Representation id="audio-en">',
1202
+ ' <BaseURL>a-en.mp4</BaseURL>',
1203
+ ' <SegmentBase indexRange="100-200" />',
1204
+ ' </Representation>',
1205
+ ' </AdaptationSet>',
1206
+ ' </Period>',
1207
+ '</MPD>',
1208
+ ].join('\n');
1209
+
1210
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
1211
+
1212
+ const config = shaka.util.PlayerConfiguration.createDefault().manifest;
1213
+ config.dash.enableAudioGroups = true;
1214
+ parser.configure(config);
1215
+
1216
+ /** @type {shaka.extern.Manifest} */
1217
+ const manifest = await parser.start('dummy://foo', playerInterface);
1218
+
1219
+
1220
+ expect(manifest.variants.length).toBe(1);
1221
+ const variant = manifest.variants[0];
1222
+ expect(variant.audio.groupId).toBe('3');
1223
+ });
1224
+
1178
1225
  it('sets contentType to text for embedded text mime types', async () => {
1179
1226
  // One MIME type for embedded TTML, one for embedded WebVTT.
1180
1227
  // One MIME type specified on AdaptationSet, on one Representation.
@@ -40,9 +40,16 @@ describe('DashParser SegmentBase', () => {
40
40
  enableLowLatencyMode: () => {},
41
41
  updateDuration: () => {},
42
42
  newDrmInfo: (stream) => {},
43
+ onManifestUpdated: () => {},
44
+ getBandwidthEstimate: () => 1e6,
43
45
  };
44
46
  });
45
47
 
48
+ afterEach(() => {
49
+ // Dash parser stop is synchronous.
50
+ parser.stop();
51
+ });
52
+
46
53
  it('requests init data for WebM', async () => {
47
54
  const source = [
48
55
  '<MPD mediaPresentationDuration="PT75S">',
@@ -350,25 +350,31 @@ describe('DashParser SegmentList', () => {
350
350
  enableLowLatencyMode: () => {},
351
351
  updateDuration: () => {},
352
352
  newDrmInfo: (stream) => {},
353
+ onManifestUpdated: () => {},
354
+ getBandwidthEstimate: () => 1e6,
353
355
  };
354
- const manifest = await dashParser.start('dummy://foo', playerInterface);
355
- const stream = manifest.variants[0].video;
356
- await stream.createSegmentIndex();
357
- goog.asserts.assert(stream.segmentIndex, 'Expected index to be created');
356
+ try {
357
+ const manifest = await dashParser.start('dummy://foo', playerInterface);
358
+ const stream = manifest.variants[0].video;
359
+ await stream.createSegmentIndex();
360
+ goog.asserts.assert(stream.segmentIndex, 'Expected index to be created');
358
361
 
359
- // Don't use Dash.testSegmentIndex since it uses SegmentIndex.find, which
360
- // doesn't reproduce this issue. We want to use Array.from which uses the
361
- // iterator.
362
- const expected = [
363
- ManifestParser.makeReference('s1.mp4', 0, 10, baseUri),
364
- ManifestParser.makeReference('s2.mp4', 10, 20, baseUri),
365
- ManifestParser.makeReference('s3.mp4', 20, 30, baseUri),
362
+ // Don't use Dash.testSegmentIndex since it uses SegmentIndex.find, which
363
+ // doesn't reproduce this issue. We want to use Array.from which uses
364
+ // the iterator.
365
+ const expected = [
366
+ ManifestParser.makeReference('s1.mp4', 0, 10, baseUri),
367
+ ManifestParser.makeReference('s2.mp4', 10, 20, baseUri),
368
+ ManifestParser.makeReference('s3.mp4', 20, 30, baseUri),
366
369
 
367
- ManifestParser.makeReference('s3.mp4', 30, 40, baseUri),
368
- ManifestParser.makeReference('s4.mp4', 40, 50, baseUri),
369
- ManifestParser.makeReference('s5.mp4', 50, 60, baseUri),
370
- ];
371
- const actual = Array.from(stream.segmentIndex);
372
- expect(actual).toEqual(expected);
370
+ ManifestParser.makeReference('s3.mp4', 30, 40, baseUri),
371
+ ManifestParser.makeReference('s4.mp4', 40, 50, baseUri),
372
+ ManifestParser.makeReference('s5.mp4', 50, 60, baseUri),
373
+ ];
374
+ const actual = Array.from(stream.segmentIndex);
375
+ expect(actual).toEqual(expected);
376
+ } finally {
377
+ dashParser.stop();
378
+ }
373
379
  });
374
380
  });
@@ -49,9 +49,16 @@ describe('DashParser SegmentTemplate', () => {
49
49
  enableLowLatencyMode: () => {},
50
50
  updateDuration: () => {},
51
51
  newDrmInfo: (stream) => {},
52
+ onManifestUpdated: () => {},
53
+ getBandwidthEstimate: () => 1e6,
52
54
  };
53
55
  });
54
56
 
57
+ afterEach(() => {
58
+ // Dash parser stop is synchronous.
59
+ parser.stop();
60
+ });
61
+
55
62
  shaka.test.Dash.makeTimelineTests(
56
63
  'SegmentTemplate', 'media="s$Number$.mp4"', []);
57
64
 
@@ -670,6 +677,48 @@ describe('DashParser SegmentTemplate', () => {
670
677
  expect(pos).toBe(1);
671
678
  });
672
679
 
680
+ it('finds correct position in multiperiod content', async () => {
681
+ const source = [
682
+ '<MPD type="static" availabilityStartTime="1970-01-01T00:00:00Z">',
683
+ ' <Period duration="PT30S">',
684
+ ' <AdaptationSet mimeType="video/mp4">',
685
+ ' <Representation bandwidth="500">',
686
+ ' <BaseURL>http://example.com</BaseURL>',
687
+ ' <SegmentTemplate startNumber="0"',
688
+ ' media="$Number$-$Time$-$Bandwidth$.mp4">',
689
+ ' <SegmentTimeline>',
690
+ ' <S t="0" d="5" r="6" />',
691
+ ' </SegmentTimeline>',
692
+ ' </SegmentTemplate>',
693
+ ' </Representation>',
694
+ ' </AdaptationSet>',
695
+ ' </Period>',
696
+ ' <Period duration="PT30S">',
697
+ ' <AdaptationSet mimeType="video/mp4">',
698
+ ' <Representation bandwidth="500">',
699
+ ' <BaseURL>http://example.com</BaseURL>',
700
+ ' <SegmentTemplate startNumber="6"',
701
+ ' media="$Number$-$Time$-$Bandwidth$.mp4">',
702
+ ' <SegmentTimeline>',
703
+ ' <S t="0" d="5" r="6" />',
704
+ ' </SegmentTimeline>',
705
+ ' </SegmentTemplate>',
706
+ ' </Representation>',
707
+ ' </AdaptationSet>',
708
+ ' </Period>',
709
+ '</MPD>',
710
+ ].join('\n');
711
+
712
+ fakeNetEngine.setResponseText('dummy://foo', source);
713
+ const manifest = await parser.start('dummy://foo', playerInterface);
714
+ const stream = manifest.variants[0].video;
715
+ await stream.createSegmentIndex();
716
+
717
+ // simulate a seek into the second period
718
+ const segmentIterator = stream.segmentIndex.getIteratorForTime(42);
719
+ const ref = segmentIterator.next().value;
720
+ expect(ref.startTime).toBe(40);
721
+ });
673
722
 
674
723
  it('returns null if time === last end time', async () => {
675
724
  const info = makeTemplateInfo(makeRanges(0, 2.0, 2));
@@ -33,22 +33,6 @@ describe('Demo', () => {
33
33
  await shakaDemoMain.cleanup();
34
34
  });
35
35
 
36
- it('has all messages defined', async () => {
37
- const englishBuffer =
38
- await shaka.test.Util.fetch('/base/demo/locales/en.json');
39
- const englishMessages = JSON.parse(shaka.util.StringUtils.fromUTF8(
40
- englishBuffer));
41
- const sourceBuffer =
42
- await shaka.test.Util.fetch('/base/demo/locales/source.json');
43
- const sourceMessages = JSON.parse(shaka.util.StringUtils.fromUTF8(
44
- sourceBuffer));
45
-
46
- for (const id of Object.values(shakaDemo.MessageIds)) {
47
- expect(englishMessages[id]).withContext(`id=${id}, English`).toBeTruthy();
48
- expect(sourceMessages[id]).withContext(`id=${id}, source`).toBeTruthy();
49
- }
50
- });
51
-
52
36
  describe('config', () => {
53
37
  it('does not have entries for invalid config options', () => {
54
38
  // We determine whether a config option has been made or not by looking at
@@ -77,6 +77,8 @@ describe('HlsParser live', () => {
77
77
  enableLowLatencyMode: () => {},
78
78
  updateDuration: () => {},
79
79
  newDrmInfo: (stream) => {},
80
+ onManifestUpdated: () => {},
81
+ getBandwidthEstimate: () => 1e6,
80
82
  };
81
83
 
82
84
  parser = new shaka.hls.HlsParser();
@@ -540,10 +542,43 @@ describe('HlsParser live', () => {
540
542
 
541
543
  it('sets 3 times target duration as presentation delay if not configured',
542
544
  async () => {
545
+ const media = [
546
+ '#EXTM3U\n',
547
+ '#EXT-X-TARGETDURATION:5\n',
548
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
549
+ '#EXT-X-MEDIA-SEQUENCE:0\n',
550
+ '#EXTINF:2,\n',
551
+ 'main.mp4\n',
552
+ '#EXTINF:2,\n',
553
+ 'main.mp4\n',
554
+ '#EXTINF:2,\n',
555
+ 'main.mp4\n',
556
+ '#EXTINF:2,\n',
557
+ 'main.mp4\n',
558
+ '#EXTINF:2,\n',
559
+ 'main.mp4\n',
560
+ '#EXTINF:2,\n',
561
+ 'main.mp4\n',
562
+ ].join('');
543
563
  const manifest = await testInitialManifest(master, media);
544
564
  expect(manifest.presentationTimeline.getDelay()).toBe(15);
545
565
  });
546
566
 
567
+ it('sets 1 times target duration as presentation delay if there are not enough segments', async () => { // eslint-disable-line max-len
568
+ const media = [
569
+ '#EXTM3U\n',
570
+ '#EXT-X-TARGETDURATION:5\n',
571
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
572
+ '#EXT-X-MEDIA-SEQUENCE:0\n',
573
+ '#EXTINF:2,\n',
574
+ 'main.mp4\n',
575
+ '#EXTINF:2,\n',
576
+ 'main.mp4\n',
577
+ ].join('');
578
+ const manifest = await testInitialManifest(master, media);
579
+ expect(manifest.presentationTimeline.getDelay()).toBe(5);
580
+ });
581
+
547
582
  it('sets presentation delay if defined', async () => {
548
583
  const media = [
549
584
  '#EXTM3U\n',
@@ -90,6 +90,8 @@ describe('HlsParser', () => {
90
90
  enableLowLatencyMode: () => {},
91
91
  updateDuration: () => {},
92
92
  newDrmInfo: shaka.test.Util.spyFunc(newDrmInfoSpy),
93
+ onManifestUpdated: () => {},
94
+ getBandwidthEstimate: () => 1e6,
93
95
  };
94
96
 
95
97
  parser = new shaka.hls.HlsParser();
@@ -1136,63 +1138,6 @@ describe('HlsParser', () => {
1136
1138
  expect(references[6].discontinuitySequence).toBe(3);
1137
1139
  });
1138
1140
 
1139
- it('sets reference timetampOffset based on discontinuity start time',
1140
- async () => {
1141
- const master = [
1142
- '#EXTM3U\n',
1143
- '#EXT-X-STREAM-INF:BANDWIDTH=2000000,CODECS="avc1"\n',
1144
- 'video\n',
1145
- ].join('');
1146
-
1147
- const media = [
1148
- '#EXTM3U\n',
1149
- '#EXT-X-VERSION:3\n',
1150
- '#EXT-X-TARGETDURATION:5\n',
1151
- '#EXT-X-MEDIA-SEQUENCE:0\n',
1152
- '#EXTINF:3,\n',
1153
- 'clip0-video-0.ts\n',
1154
- '#EXTINF:1,\n',
1155
- 'clip0-video-1.ts\n',
1156
- '#EXT-X-DISCONTINUITY\n',
1157
- '#EXTINF:2,\n',
1158
- 'clip1-video-1.ts\n',
1159
- '#EXTINF:3,\n',
1160
- 'clip1-video-2.ts\n',
1161
- '#EXT-X-DISCONTINUITY\n',
1162
- '#EXTINF:1,\n',
1163
- 'media-clip2-video-0.ts\n',
1164
- '#EXTINF:1,\n',
1165
- 'media-clip2-video-1.ts\n',
1166
- '#EXT-X-DISCONTINUITY\n',
1167
- '#EXTINF:4,\n',
1168
- 'media-clip3-video-1.ts\n',
1169
- '#EXT-X-ENDLIST\n',
1170
- ].join('');
1171
-
1172
- fakeNetEngine
1173
- .setResponseText('test:/master', master)
1174
- .setResponseText('test:/video', media);
1175
-
1176
- const manifest = await parser.start('test:/master', playerInterface);
1177
- await manifest.variants[0].video.createSegmentIndex();
1178
-
1179
- const segmentIndex = manifest.variants[0].video.segmentIndex;
1180
- const references = [];
1181
-
1182
- for (let i = 0; i < 7; i++) {
1183
- references.push(segmentIndex.get(i));
1184
- }
1185
-
1186
- expect(references[0].timestampOffset).toBe(0);
1187
- expect(references[1].timestampOffset).toBe(0);
1188
- expect(references[2].timestampOffset).toBe(4);
1189
- expect(references[3].timestampOffset).toBe(4);
1190
- expect(references[4].timestampOffset).toBe(9);
1191
- expect(references[5].timestampOffset).toBe(9);
1192
- expect(references[6].timestampOffset).toBe(11);
1193
- },
1194
- );
1195
-
1196
1141
  it('parses characteristics from audio tags', async () => {
1197
1142
  const master = [
1198
1143
  '#EXTM3U\n',
@@ -3181,9 +3126,11 @@ describe('HlsParser', () => {
3181
3126
  'Null segmentIndex!');
3182
3127
 
3183
3128
  const firstMp4Segment = mp4AesEncryptionVideo.segmentIndex.get(0);
3184
- expect(firstMp4Segment.hlsAes128Key).toBeDefined();
3129
+ expect(firstMp4Segment.aes128Key).toBeDefined();
3130
+ expect(firstMp4Segment.initSegmentReference.aes128Key).toBeDefined();
3185
3131
  const secondMp4Segment = mp4AesEncryptionVideo.segmentIndex.get(1);
3186
- expect(secondMp4Segment.hlsAes128Key).toBeNull();
3132
+ expect(secondMp4Segment.aes128Key).toBeNull();
3133
+ expect(secondMp4Segment.initSegmentReference.aes128Key).toBeDefined();
3187
3134
 
3188
3135
  const tsAesEncryptionVideo = actual.variants[2].video;
3189
3136
  await tsAesEncryptionVideo.createSegmentIndex();
@@ -3191,9 +3138,9 @@ describe('HlsParser', () => {
3191
3138
  'Null segmentIndex!');
3192
3139
 
3193
3140
  const firstTsSegment = tsAesEncryptionVideo.segmentIndex.get(0);
3194
- expect(firstTsSegment.hlsAes128Key).toBeDefined();
3141
+ expect(firstTsSegment.aes128Key).toBeDefined();
3195
3142
  const secondTsSegment = tsAesEncryptionVideo.segmentIndex.get(1);
3196
- expect(secondTsSegment.hlsAes128Key).toBeNull();
3143
+ expect(secondTsSegment.aes128Key).toBeNull();
3197
3144
  });
3198
3145
 
3199
3146
  it('fails on AES-128 if WebCrypto APIs are not available', async () => {