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
@@ -49,6 +49,90 @@ describe('AdaptationSetCriteria', () => {
49
49
  ]);
50
50
  });
51
51
 
52
+ it('should not filter varaints when codec switching startegy is smooth '+
53
+ 'and changeType is supported', () => {
54
+ const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
55
+ manifest.addVariant(1, (variant) => {
56
+ variant.addAudio(10, (stream) => {
57
+ stream.codecs = 'mp4a.69';
58
+ });
59
+ variant.addVideo(11, (stream) => {
60
+ stream.codecs = 'avc1';
61
+ });
62
+ });
63
+ manifest.addVariant(2, (variant) => {
64
+ variant.addAudio(12, (stream) => {
65
+ stream.codecs = 'mp4a.66';
66
+ });
67
+ variant.addVideo(13, (stream) => {
68
+ stream.codecs = 'hvc1';
69
+ });
70
+ });
71
+ manifest.addVariant(3, (variant) => {
72
+ variant.addAudio(14, (stream) => {
73
+ stream.codecs = 'mp4a.a6';
74
+ });
75
+ variant.addVideo(14, (stream) => {
76
+ stream.codecs = 'dvh1';
77
+ });
78
+ });
79
+ });
80
+
81
+ const originalIsChangeTypeSupported = shaka.media.Capabilities
82
+ .isChangeTypeSupported;
83
+
84
+ try {
85
+ shaka.media.Capabilities.isChangeTypeSupported = () => {
86
+ return true;
87
+ };
88
+
89
+ const builder = new shaka.media.PreferenceBasedCriteria('en', '', 0, '',
90
+ undefined, shaka.config.CodecSwitchingStrategy.SMOOTH);
91
+ const set = builder.create(manifest.variants);
92
+
93
+ expect(Array.from(set.values()).length).toBe(3);
94
+ } finally {
95
+ shaka.media.Capabilities
96
+ .isChangeTypeSupported = originalIsChangeTypeSupported;
97
+ }
98
+ });
99
+
100
+ it('should filter varaints when codec switching startegy'+
101
+ 'is not SMOOTH', () => {
102
+ const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
103
+ manifest.addVariant(1, (variant) => {
104
+ variant.addAudio(10, (stream) => {
105
+ stream.codecs = 'mp4a.69';
106
+ });
107
+ variant.addVideo(11, (stream) => {
108
+ stream.codecs = 'avc1';
109
+ });
110
+ });
111
+ manifest.addVariant(2, (variant) => {
112
+ variant.addAudio(12, (stream) => {
113
+ stream.codecs = 'mp4a.66';
114
+ });
115
+ variant.addVideo(13, (stream) => {
116
+ stream.codecs = 'hvc1';
117
+ });
118
+ });
119
+ manifest.addVariant(3, (variant) => {
120
+ variant.addAudio(14, (stream) => {
121
+ stream.codecs = 'mp4a.a6';
122
+ });
123
+ variant.addVideo(14, (stream) => {
124
+ stream.codecs = 'dvh1';
125
+ });
126
+ });
127
+ });
128
+
129
+ const builder = new shaka.media.PreferenceBasedCriteria('en', '', 0, '',
130
+ undefined, shaka.config.CodecSwitchingStrategy.RELOAD);
131
+ const set = builder.create(manifest.variants);
132
+
133
+ expect(Array.from(set.values()).length).toBe(1);
134
+ });
135
+
52
136
  it('chooses variants in preferred language and role', () => {
53
137
  const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
54
138
  manifest.addVariant(1, (variant) => {
@@ -524,6 +608,40 @@ describe('AdaptationSetCriteria', () => {
524
608
  manifest.variants[2],
525
609
  ]);
526
610
  });
611
+
612
+ it('filters by audio group if present', () => {
613
+ const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
614
+ manifest.addVariant(1, (variant) => {
615
+ variant.language = 'en';
616
+ variant.bandwidth = 300;
617
+ variant.addAudio(10, (stream) => {
618
+ stream.groupId = '1';
619
+ });
620
+ });
621
+ manifest.addVariant(2, (variant) => {
622
+ variant.language = 'en';
623
+ variant.bandwidth = 400;
624
+ variant.addAudio(11, (stream) => {
625
+ stream.groupId = '2';
626
+ });
627
+ });
628
+ manifest.addVariant(3, (variant) => {
629
+ variant.language = 'en';
630
+ variant.bandwidth = 500;
631
+ variant.addAudio(12, (stream) => {
632
+ stream.groupId = '1';
633
+ });
634
+ });
635
+ });
636
+
637
+ const builder = new shaka.media.PreferenceBasedCriteria('en', '', 0, '');
638
+ const set = builder.create(manifest.variants);
639
+
640
+ checkSet(set, [
641
+ manifest.variants[0],
642
+ manifest.variants[2],
643
+ ]);
644
+ });
527
645
  });
528
646
 
529
647
  /**
@@ -221,6 +221,7 @@ describe('AdaptationSet', () => {
221
221
  type: '',
222
222
  accessibilityPurpose: null,
223
223
  external: false,
224
+ groupId: null,
224
225
  };
225
226
  }
226
227
  });
@@ -116,7 +116,13 @@ describe('MediaSourceEngine', () => {
116
116
  mockMediaSource = createMockMediaSource();
117
117
  mockMediaSource.addSourceBuffer.and.callFake((mimeType) => {
118
118
  const type = mimeType.split('/')[0];
119
- return type == 'audio' ? audioSourceBuffer : videoSourceBuffer;
119
+ const buffer = type == 'audio' ? audioSourceBuffer : videoSourceBuffer;
120
+ // reset buffer params
121
+ buffer.timestampOffset = 0;
122
+ buffer.appendWindowEnd = Infinity;
123
+ buffer.appendWindowStart = 0;
124
+
125
+ return buffer;
120
126
  });
121
127
  mockTransmuxer = new shaka.test.FakeTransmuxer();
122
128
  shaka.transmuxer.TransmuxerEngine.findTransmuxer =
@@ -167,10 +173,12 @@ describe('MediaSourceEngine', () => {
167
173
  goog.asserts.assert(attr == 'src', 'Unexpected removeAttribute() call');
168
174
  mockVideo.src = '';
169
175
  },
176
+ addEventListener: jasmine.createSpy('addVideoEventListener'),
170
177
  load: /** @this {HTMLVideoElement} */ () => {
171
178
  // This assertion alerts us if the requirements for this mock change.
172
179
  goog.asserts.assert(mockVideo.src == '', 'Unexpected load() call');
173
180
  },
181
+ play: jasmine.createSpy('play'),
174
182
  };
175
183
  video = /** @type {HTMLMediaElement} */(mockVideo);
176
184
  mockClosedCaptionParser = new shaka.test.FakeClosedCaptionParser();
@@ -1136,6 +1144,161 @@ describe('MediaSourceEngine', () => {
1136
1144
  });
1137
1145
  });
1138
1146
 
1147
+ describe('reload codec switching', () => {
1148
+ beforeEach(
1149
+ /** @suppress {visibility, checkTypes} */
1150
+ () => {
1151
+ mediaSourceEngine.eventManager_.listenOnce =
1152
+ jasmine.createSpy('listener');
1153
+ mediaSourceEngine.eventManager_.listen =
1154
+ jasmine.createSpy('eventListener');
1155
+ });
1156
+ const initObject = new Map();
1157
+ initObject.set(ContentType.VIDEO, fakeVideoStream);
1158
+ initObject.set(ContentType.AUDIO, fakeAudioStream);
1159
+
1160
+ it('should re-create a new MediaSource',
1161
+ /** @suppress {visibility} */ async () => {
1162
+ await mediaSourceEngine.init(initObject, false);
1163
+ mediaSourceEngine.reset_(initObject);
1164
+ expect(createMediaSourceSpy).toHaveBeenCalled();
1165
+ });
1166
+
1167
+ it('should re-create the audio & video source buffers',
1168
+ /** @suppress {invalidCasts, visibility, checkTypes} */ async () => {
1169
+ await mediaSourceEngine.init(initObject, false);
1170
+ mediaSourceEngine.reset_(initObject);
1171
+ expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledTimes(2);
1172
+ });
1173
+
1174
+ it('should persist the previous source buffer parameters',
1175
+ /** @suppress {invalidCasts, visibility, checkTypes} */async () => {
1176
+ await mediaSourceEngine.init(initObject, false);
1177
+
1178
+ audioSourceBuffer.timestampOffset = 10;
1179
+ audioSourceBuffer.appendWindowStart = 5;
1180
+ audioSourceBuffer.appendWindowEnd = 20;
1181
+
1182
+ videoSourceBuffer.timestampOffset = 20;
1183
+ videoSourceBuffer.appendWindowStart = 15;
1184
+ videoSourceBuffer.appendWindowEnd = 30;
1185
+
1186
+ mediaSourceEngine.reset_(initObject);
1187
+
1188
+ expect(audioSourceBuffer.timestampOffset).toBe(10);
1189
+ expect(audioSourceBuffer.appendWindowStart).toBe(5);
1190
+ expect(audioSourceBuffer.appendWindowEnd).toBe(20);
1191
+
1192
+ expect(videoSourceBuffer.timestampOffset).toBe(20);
1193
+ expect(videoSourceBuffer.appendWindowStart).toBe(15);
1194
+ expect(videoSourceBuffer.appendWindowEnd).toBe(30);
1195
+ });
1196
+
1197
+ it('should preserve autoplay state',
1198
+ /** @suppress {invalidCasts, visibility, checkTypes} */
1199
+ async () => {
1200
+ const originalInitSourceBuffer = mediaSourceEngine.initSourceBuffer_;
1201
+ try {
1202
+ await mediaSourceEngine.init(initObject, false);
1203
+ video.autoplay = true;
1204
+ video.paused = true;
1205
+ const playSpy = /** @type {jasmine.Spy} */ (video.play);
1206
+ const addListenOnceSpy =
1207
+ /** @type {jasmine.Spy} */
1208
+ (mediaSourceEngine.eventManager_.listenOnce);
1209
+ const addEventListenerSpy =
1210
+ /** @type {jasmine.Spy} */
1211
+ (mediaSourceEngine.eventManager_.listen);
1212
+ mediaSourceEngine.playbackHasBegun_ = true;
1213
+ mediaSourceEngine.initSourceBuffer_ =
1214
+ jasmine.createSpy('initSourceBuffer');
1215
+ const initSourceBufferSpy =
1216
+ /** @type {jasmine.Spy} */
1217
+ (mediaSourceEngine.initSourceBuffer_);
1218
+ addEventListenerSpy.and.callFake((o, e, c) => {
1219
+ c(); // audio
1220
+ c(); // video
1221
+ });
1222
+ await mediaSourceEngine.reset_(initObject);
1223
+ const callback = addListenOnceSpy.calls.argsFor(0)[2];
1224
+ callback();
1225
+ expect(initSourceBufferSpy).toHaveBeenCalled();
1226
+ expect(addListenOnceSpy.calls.argsFor(0)[1]).toBe('canplay');
1227
+ expect(video.autoplay).toBe(true);
1228
+ expect(playSpy).not.toHaveBeenCalled();
1229
+ } finally {
1230
+ mediaSourceEngine.initSourceBuffer_ = originalInitSourceBuffer;
1231
+ }
1232
+ });
1233
+
1234
+ it('should not set autoplay to false if playback has not begun',
1235
+ /** @suppress {invalidCasts, visibility, checkTypes} */
1236
+ async () => {
1237
+ const originalInitSourceBuffer = mediaSourceEngine.initSourceBuffer_;
1238
+ try {
1239
+ await mediaSourceEngine.init(initObject, false);
1240
+ video.autoplay = true;
1241
+ let setCount = 0;
1242
+ const addEventListenerSpy =
1243
+ /** @type {jasmine.Spy} */
1244
+ (mediaSourceEngine.eventManager_.listen);
1245
+ addEventListenerSpy.and.callFake((o, e, c) => {
1246
+ c(); // audio
1247
+ c(); // video
1248
+ });
1249
+ mediaSourceEngine.initSourceBuffer_ =
1250
+ jasmine.createSpy('initSourceBuffer');
1251
+ Object.defineProperty(video, 'autoplay', {
1252
+ get: () => true,
1253
+ set: () => {
1254
+ setCount++;
1255
+ },
1256
+ });
1257
+ await mediaSourceEngine.reset_(initObject);
1258
+ expect(setCount).toBe(0);
1259
+ } finally {
1260
+ mediaSourceEngine.initSourceBuffer_ = originalInitSourceBuffer;
1261
+ }
1262
+ });
1263
+
1264
+ it('should preserve playing state',
1265
+ /** @suppress {invalidCasts, visibility, checkTypes} */
1266
+ async () => {
1267
+ const originalInitSourceBuffer = mediaSourceEngine.initSourceBuffer_;
1268
+ try {
1269
+ await mediaSourceEngine.init(initObject, false);
1270
+ video.autoplay = false;
1271
+ video.paused = false;
1272
+ const playSpy = /** @type {jasmine.Spy} */ (video.play);
1273
+ const addListenOnceSpy =
1274
+ /** @type {jasmine.Spy} */
1275
+ (mediaSourceEngine.eventManager_.listenOnce);
1276
+ const addEventListenerSpy =
1277
+ /** @type {jasmine.Spy} */
1278
+ (mediaSourceEngine.eventManager_.listen);
1279
+ mediaSourceEngine.playbackHasBegun_ = true;
1280
+ mediaSourceEngine.initSourceBuffer_ =
1281
+ jasmine.createSpy('initSourceBuffer');
1282
+ const initSourceBufferSpy =
1283
+ /** @type {jasmine.Spy} */
1284
+ (mediaSourceEngine.initSourceBuffer_);
1285
+ addEventListenerSpy.and.callFake((o, e, c) => {
1286
+ c(); // audio
1287
+ c(); // video
1288
+ });
1289
+ await mediaSourceEngine.reset_(initObject);
1290
+ const callback = addListenOnceSpy.calls.argsFor(0)[2];
1291
+ callback();
1292
+ expect(initSourceBufferSpy).toHaveBeenCalled();
1293
+ expect(addListenOnceSpy.calls.argsFor(0)[1]).toBe('canplay');
1294
+ expect(video.autoplay).toBe(false);
1295
+ expect(playSpy).toHaveBeenCalled();
1296
+ } finally {
1297
+ mediaSourceEngine.initSourceBuffer_ = originalInitSourceBuffer;
1298
+ }
1299
+ });
1300
+ });
1301
+
1139
1302
  describe('destroy', () => {
1140
1303
  beforeEach(async () => {
1141
1304
  captureEvents(audioSourceBuffer, ['updateend', 'error']);
@@ -1259,6 +1422,7 @@ describe('MediaSourceEngine', () => {
1259
1422
  function createMockMediaSource() {
1260
1423
  const mediaSource = {
1261
1424
  readyState: 'open',
1425
+ sourceBuffers: document.createElement('div'),
1262
1426
  addSourceBuffer: jasmine.createSpy('addSourceBuffer'),
1263
1427
  endOfStream: jasmine.createSpy('endOfStream'),
1264
1428
  durationGetter: jasmine.createSpy('duration getter'),
@@ -223,7 +223,7 @@ describe('SegmentIndex', /** @suppress {accessControls} */ () => {
223
223
 
224
224
  index.fit(/* windowStart= */ 0, /* windowEnd= */ 10);
225
225
  expect(
226
- index.references[index.references.length - 1].hlsAes128Key,
226
+ index.references[index.references.length - 1].aes128Key,
227
227
  ).toEqual({method: 'AES-128', firstMediaSequenceNumber: 0});
228
228
  });
229
229
  });
@@ -1054,11 +1054,11 @@ describe('SegmentIndex', /** @suppress {accessControls} */ () => {
1054
1054
  * @param {number} startTime
1055
1055
  * @param {number} endTime
1056
1056
  * @param {!Array.<!shaka.media.SegmentReference>=} partialReferences
1057
- * @param {?shaka.extern.HlsAes128Key=} hlsAes128Key
1057
+ * @param {?shaka.extern.aes128Key=} aes128Key
1058
1058
  * @return {shaka.media.SegmentReference}
1059
1059
  */
1060
1060
  function makeReference(uri, startTime, endTime, partialReferences = [],
1061
- hlsAes128Key = null) {
1061
+ aes128Key = null) {
1062
1062
  return new shaka.media.SegmentReference(
1063
1063
  startTime,
1064
1064
  endTime,
@@ -1074,6 +1074,6 @@ describe('SegmentIndex', /** @suppress {accessControls} */ () => {
1074
1074
  /* tileDuration= */ undefined,
1075
1075
  /* syncTime= */ undefined,
1076
1076
  /* status= */ undefined,
1077
- /* hlsAes128Key= */ hlsAes128Key);
1077
+ /* aes128Key= */ aes128Key);
1078
1078
  }
1079
1079
  });
@@ -201,7 +201,7 @@ describe('SegmentPrefetch', () => {
201
201
  /* tileDuration= */ undefined,
202
202
  /* syncTime= */ undefined,
203
203
  /* status= */ undefined,
204
- /* hlsAes128Key= */ null);
204
+ /* aes128Key= */ null);
205
205
  }
206
206
 
207
207
  /**
@@ -109,10 +109,10 @@ describe('StreamingEngine', () => {
109
109
  /**
110
110
  * @param {boolean=} trickMode
111
111
  * @param {number=} mediaOffset The offset from 0 for the segment start times
112
- * @param {shaka.extern.HlsAes128Key=} hlsAes128Key The AES-128 key to put in
112
+ * @param {shaka.extern.aes128Key=} aes128Key The AES-128 key to put in
113
113
  * the manifest, if one should exist
114
114
  */
115
- function setupVod(trickMode, mediaOffset, hlsAes128Key) {
115
+ function setupVod(trickMode, mediaOffset, aes128Key) {
116
116
  // For VOD, we fake a presentation that has 2 Periods of equal duration
117
117
  // (20 seconds), where each Period has 1 Variant and 1 text stream.
118
118
  //
@@ -219,7 +219,7 @@ describe('StreamingEngine', () => {
219
219
  /* firstPeriodStartTime= */ 0,
220
220
  /* secondPeriodStartTime= */ 20,
221
221
  /* presentationDuration= */ 40,
222
- hlsAes128Key);
222
+ aes128Key);
223
223
  }
224
224
 
225
225
  function setupLive() {
@@ -370,11 +370,11 @@ describe('StreamingEngine', () => {
370
370
  * @param {number} firstPeriodStartTime
371
371
  * @param {number} secondPeriodStartTime
372
372
  * @param {number} presentationDuration
373
- * @param {shaka.extern.HlsAes128Key=} hlsAes128Key
373
+ * @param {shaka.extern.aes128Key=} aes128Key
374
374
  */
375
375
  function setupManifest(
376
376
  firstPeriodStartTime, secondPeriodStartTime, presentationDuration,
377
- hlsAes128Key) {
377
+ aes128Key) {
378
378
  const segmentDurations = {
379
379
  audio: segmentData[ContentType.AUDIO].segmentDuration,
380
380
  video: segmentData[ContentType.VIDEO].segmentDuration,
@@ -397,7 +397,7 @@ describe('StreamingEngine', () => {
397
397
  /** @type {!shaka.media.PresentationTimeline} */(timeline),
398
398
  [firstPeriodStartTime, secondPeriodStartTime],
399
399
  presentationDuration, segmentDurations, initSegmentRanges,
400
- timestampOffsets, hlsAes128Key);
400
+ timestampOffsets, aes128Key);
401
401
 
402
402
  audioStream = manifest.variants[0].audio;
403
403
  videoStream = manifest.variants[0].video;
@@ -3809,8 +3809,8 @@ describe('StreamingEngine', () => {
3809
3809
 
3810
3810
  describe('AES-128', () => {
3811
3811
  let key;
3812
- /** @type {!shaka.extern.HlsAes128Key} */
3813
- let hlsAes128Key;
3812
+ /** @type {!shaka.extern.aes128Key} */
3813
+ let aes128Key;
3814
3814
 
3815
3815
  beforeEach(async () => {
3816
3816
  // Get a key.
@@ -3823,10 +3823,10 @@ describe('StreamingEngine', () => {
3823
3823
  // Set up a manifest with AES-128 key info.
3824
3824
  // We don't actually provide the imported key OR the key fetching function
3825
3825
  // here, though, so that the individual tests can choose what the starting
3826
- // state of the hlsAes128Key object is.
3827
- hlsAes128Key = {method: 'AES-128', firstMediaSequenceNumber: 0};
3826
+ // state of the aes128Key object is.
3827
+ aes128Key = {method: 'AES-128', firstMediaSequenceNumber: 0};
3828
3828
 
3829
- setupVod(false, 0, hlsAes128Key);
3829
+ setupVod(false, 0, aes128Key);
3830
3830
  mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData);
3831
3831
  presentationTimeInSeconds = 0;
3832
3832
  createStreamingEngine();
@@ -3851,22 +3851,22 @@ describe('StreamingEngine', () => {
3851
3851
  }
3852
3852
 
3853
3853
  it('decrypts segments', async () => {
3854
- hlsAes128Key.cryptoKey = key;
3854
+ aes128Key.cryptoKey = key;
3855
3855
  await runTest();
3856
3856
  });
3857
3857
 
3858
3858
  it('downloads key if not pre-filled', async () => {
3859
- hlsAes128Key.fetchKey = () => {
3860
- hlsAes128Key.cryptoKey = key;
3861
- hlsAes128Key.fetchKey = undefined;
3859
+ aes128Key.fetchKey = () => {
3860
+ aes128Key.cryptoKey = key;
3861
+ aes128Key.fetchKey = undefined;
3862
3862
  return Promise.resolve();
3863
3863
  };
3864
3864
 
3865
3865
  await runTest();
3866
3866
 
3867
3867
  // The key should have been fetched.
3868
- expect(hlsAes128Key.cryptoKey).not.toBeUndefined();
3869
- expect(hlsAes128Key.fetchKey).toBeUndefined();
3868
+ expect(aes128Key.cryptoKey).not.toBeUndefined();
3869
+ expect(aes128Key.fetchKey).toBeUndefined();
3870
3870
  });
3871
3871
  });
3872
3872
 
@@ -79,6 +79,8 @@ describe('MssParser Manifest', () => {
79
79
  enableLowLatencyMode: () => {},
80
80
  updateDuration: () => {},
81
81
  newDrmInfo: (stream) => {},
82
+ onManifestUpdated: () => {},
83
+ getBandwidthEstimate: () => 1e6,
82
84
  };
83
85
  });
84
86
 
@@ -298,6 +298,7 @@ describe('ManifestConverter', () => {
298
298
  const streamDB = {
299
299
  id,
300
300
  originalId: id.toString(),
301
+ groupId: null,
301
302
  primary: false,
302
303
  type,
303
304
  mimeType: '',
@@ -355,6 +356,7 @@ describe('ManifestConverter', () => {
355
356
  return {
356
357
  id,
357
358
  originalId: id.toString(),
359
+ groupId: null,
358
360
  primary: false,
359
361
  type: ContentType.VIDEO,
360
362
  mimeType: 'video/mp4',
@@ -407,6 +409,7 @@ describe('ManifestConverter', () => {
407
409
  return {
408
410
  id,
409
411
  originalId: id.toString(),
412
+ groupId: null,
410
413
  primary: false,
411
414
  type: ContentType.AUDIO,
412
415
  mimeType: 'audio/mp4',
@@ -458,6 +461,7 @@ describe('ManifestConverter', () => {
458
461
  return {
459
462
  id,
460
463
  originalId: id.toString(),
464
+ groupId: null,
461
465
  primary: false,
462
466
  type: ContentType.TEXT,
463
467
  mimeType: 'text/vtt',
@@ -516,6 +520,7 @@ describe('ManifestConverter', () => {
516
520
  const expectedStream = {
517
521
  id: jasmine.any(Number),
518
522
  originalId: jasmine.any(String),
523
+ groupId: streamDb.groupId,
519
524
  createSegmentIndex: jasmine.any(Function),
520
525
  segmentIndex: jasmine.any(shaka.media.SegmentIndex),
521
526
  mimeType: streamDb.mimeType,
@@ -1530,10 +1530,7 @@ filterDescribe('Storage', storageSupport, () => {
1530
1530
  manifest.addVariant(3, (variant) => {
1531
1531
  variant.language = frenchCanadian;
1532
1532
  variant.bandwidth = kbps(13);
1533
- variant.addVideo(4, (stream) => {
1534
- stream.bandwidth = kbps(10);
1535
- stream.size(100, 200);
1536
- });
1533
+ variant.addExistingStream(1);
1537
1534
  variant.addAudio(5, (stream) => {
1538
1535
  stream.language = frenchCanadian;
1539
1536
  stream.bandwidth = kbps(3);