shaka-player 4.2.0 → 4.2.2

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 (88) hide show
  1. package/.github/workflows/build-and-test.yaml +31 -16
  2. package/.github/workflows/custom-actions/set-commit-status/action.yaml +1 -5
  3. package/.github/workflows/deflake.yaml +28 -0
  4. package/.github/workflows/selenium-lab-tests.yaml +168 -54
  5. package/AUTHORS +3 -0
  6. package/CHANGELOG.md +30 -0
  7. package/CONTRIBUTORS +3 -0
  8. package/demo/common/message_ids.js +1 -0
  9. package/demo/config.js +3 -1
  10. package/demo/locales/en.json +1 -0
  11. package/demo/locales/source.json +4 -0
  12. package/dist/controls.css +1 -1
  13. package/dist/controls.css.map +1 -1
  14. package/dist/demo.compiled.debug.js +7 -6
  15. package/dist/demo.compiled.debug.map +3 -3
  16. package/dist/demo.compiled.js +7 -6
  17. package/dist/demo.compiled.map +3 -3
  18. package/dist/deps.js +2 -2
  19. package/dist/locales.js +29 -29
  20. package/dist/receiver.compiled.debug.js +4 -3
  21. package/dist/receiver.compiled.debug.map +3 -3
  22. package/dist/receiver.compiled.js +4 -3
  23. package/dist/receiver.compiled.map +3 -3
  24. package/dist/shaka-player.compiled.d.ts +2 -4
  25. package/dist/shaka-player.compiled.debug.d.ts +2 -4
  26. package/dist/shaka-player.compiled.debug.externs.js +24 -26
  27. package/dist/shaka-player.compiled.debug.js +267 -260
  28. package/dist/shaka-player.compiled.debug.map +4 -4
  29. package/dist/shaka-player.compiled.externs.js +24 -26
  30. package/dist/shaka-player.compiled.js +809 -807
  31. package/dist/shaka-player.compiled.map +4 -4
  32. package/dist/shaka-player.ui.d.ts +2 -4
  33. package/dist/shaka-player.ui.debug.d.ts +2 -4
  34. package/dist/shaka-player.ui.debug.externs.js +24 -26
  35. package/dist/shaka-player.ui.debug.js +244 -236
  36. package/dist/shaka-player.ui.debug.map +4 -4
  37. package/dist/shaka-player.ui.externs.js +24 -26
  38. package/dist/shaka-player.ui.js +973 -971
  39. package/dist/shaka-player.ui.map +4 -4
  40. package/docs/jsdoc-template/publish.js +33 -0
  41. package/docs/jsdoc-template/tmpl/container.tmpl +4 -1
  42. package/docs/jsdoc.conf.json +1 -0
  43. package/externs/shaka/manifest_parser.js +4 -1
  44. package/externs/shaka/player.js +7 -1
  45. package/lib/ads/client_side_ad_manager.js +7 -0
  46. package/lib/cast/cast_sender.js +39 -14
  47. package/lib/cea/cea608_memory.js +4 -0
  48. package/lib/hls/hls_parser.js +54 -82
  49. package/lib/media/drm_engine.js +52 -1
  50. package/lib/media/media_source_engine.js +43 -15
  51. package/lib/media/segment_index.js +4 -1
  52. package/lib/media/streaming_engine.js +79 -14
  53. package/lib/offline/storage.js +1 -0
  54. package/lib/player.js +29 -5
  55. package/lib/text/ttml_text_parser.js +6 -0
  56. package/lib/text/ui_text_displayer.js +8 -0
  57. package/lib/util/error.js +2 -10
  58. package/lib/util/platform.js +24 -0
  59. package/lib/util/player_configuration.js +5 -0
  60. package/lib/util/pssh.js +2 -1
  61. package/lib/util/stream_utils.js +2 -1
  62. package/package.json +1 -1
  63. package/test/cea/cea608_memory_unit.js +88 -0
  64. package/test/dash/dash_parser_content_protection_unit.js +1 -0
  65. package/test/dash/dash_parser_live_unit.js +1 -0
  66. package/test/dash/dash_parser_manifest_unit.js +1 -0
  67. package/test/dash/dash_parser_segment_base_unit.js +1 -0
  68. package/test/dash/dash_parser_segment_list_unit.js +1 -0
  69. package/test/dash/dash_parser_segment_template_unit.js +1 -0
  70. package/test/hls/hls_live_unit.js +169 -247
  71. package/test/hls/hls_parser_unit.js +112 -3
  72. package/test/media/drm_engine_unit.js +90 -0
  73. package/test/media/media_source_engine_integration.js +36 -0
  74. package/test/media/media_source_engine_unit.js +118 -1
  75. package/test/media/segment_index_unit.js +28 -2
  76. package/test/media/streaming_engine_integration.js +9 -7
  77. package/test/media/streaming_engine_unit.js +29 -0
  78. package/test/offline/offline_integration.js +3 -3
  79. package/test/player_integration.js +2 -2
  80. package/test/player_src_equals_integration.js +2 -0
  81. package/test/player_unit.js +39 -1
  82. package/test/test/assets/small.mp4 +0 -0
  83. package/test/test/util/dash_parser_util.js +2 -0
  84. package/test/test/util/ttml_utils.js +0 -2
  85. package/test/text/ttml_text_parser_unit.js +46 -0
  86. package/test/ui/text_displayer_layout_unit.js +17 -2
  87. package/ui/controls.js +0 -7
  88. package/ui/less/ad_controls.less +4 -0
@@ -77,6 +77,7 @@ describe('HlsParser live', () => {
77
77
  isLowLatencyMode: () => false,
78
78
  isAutoLowLatencyMode: () => false,
79
79
  enableLowLatencyMode: () => {},
80
+ updateDuration: () => {},
80
81
  };
81
82
 
82
83
  parser = new shaka.hls.HlsParser();
@@ -100,13 +101,11 @@ describe('HlsParser live', () => {
100
101
  /**
101
102
  * @param {string} master
102
103
  * @param {string} initialMedia
103
- * @param {!Array} initialReferences
104
- * @param {string} updatedMedia
105
- * @param {!Array} updatedReferences
104
+ * @param {Array=} initialReferences
105
+ * @return {!Promise.<shaka.extern.Manifest>}
106
106
  */
107
- async function testUpdate(
108
- master, initialMedia, initialReferences, updatedMedia,
109
- updatedReferences) {
107
+ async function testInitialManifest(
108
+ master, initialMedia, initialReferences=null) {
110
109
  fakeNetEngine
111
110
  .setResponseText('test:/master', master)
112
111
  .setResponseText('test:/video', initialMedia)
@@ -118,32 +117,52 @@ describe('HlsParser live', () => {
118
117
  .setResponseValue('test:/main2.mp4', segmentData)
119
118
  .setResponseValue('test:/main3.mp4', segmentData)
120
119
  .setResponseValue('test:/main4.mp4', segmentData)
120
+ .setResponseValue('test:/partial.mp4', segmentData)
121
+ .setResponseValue('test:/partial2.mp4', segmentData)
121
122
  .setResponseValue('test:/selfInit.mp4', selfInitializingSegmentData);
122
123
 
123
124
  const manifest = await parser.start('test:/master', playerInterface);
124
125
 
125
- await Promise.all(manifest.variants.map(async (variant) => {
126
- await variant.video.createSegmentIndex();
127
- ManifestParser.verifySegmentIndex(variant.video, initialReferences);
128
- if (variant.audio) {
129
- await variant.audio.createSegmentIndex();
130
- ManifestParser.verifySegmentIndex(variant.audio, initialReferences);
131
- }
132
- }));
126
+ if (initialReferences) {
127
+ await Promise.all(manifest.variants.map(async (variant) => {
128
+ await variant.video.createSegmentIndex();
129
+
130
+ // The compiler doesn't count null checks done outside this callback,
131
+ // so we need an assertion here.
132
+ goog.asserts.assert(initialReferences != null, 'references non-null');
133
+ ManifestParser.verifySegmentIndex(variant.video, initialReferences);
134
+
135
+ if (variant.audio) {
136
+ await variant.audio.createSegmentIndex();
137
+ ManifestParser.verifySegmentIndex(variant.audio, initialReferences);
138
+ }
139
+ }));
140
+ }
141
+
142
+ return manifest;
143
+ }
133
144
 
145
+ /**
146
+ * @param {shaka.extern.Manifest} manifest
147
+ * @param {string} updatedMedia
148
+ * @param {Array=} updatedReferences
149
+ */
150
+ async function testUpdate(manifest, updatedMedia, updatedReferences=null) {
134
151
  // Replace the entries with the updated values.
135
152
  fakeNetEngine
136
153
  .setResponseText('test:/video', updatedMedia)
137
154
  .setResponseText('test:/redirected/video', updatedMedia)
138
155
  .setResponseText('test:/video2', updatedMedia)
139
- .setResponseText('test:/audio', updatedMedia)
140
- .setResponseText('test:/video?_HLS_skip=YES', updatedMedia);
156
+ .setResponseText('test:/audio', updatedMedia);
141
157
 
142
158
  await delayForUpdatePeriod();
143
- for (const variant of manifest.variants) {
144
- ManifestParser.verifySegmentIndex(variant.video, updatedReferences);
145
- if (variant.audio) {
146
- ManifestParser.verifySegmentIndex(variant.audio, updatedReferences);
159
+
160
+ if (updatedReferences) {
161
+ for (const variant of manifest.variants) {
162
+ ManifestParser.verifySegmentIndex(variant.video, updatedReferences);
163
+ if (variant.audio) {
164
+ ManifestParser.verifySegmentIndex(variant.audio, updatedReferences);
165
+ }
147
166
  }
148
167
  }
149
168
  }
@@ -170,13 +189,8 @@ describe('HlsParser live', () => {
170
189
  ].join('');
171
190
 
172
191
  it('treats already ended presentation like VOD', async () => {
173
- fakeNetEngine
174
- .setResponseText('test:/master', master)
175
- .setResponseText('test:/video', media + '#EXT-X-ENDLIST')
176
- .setResponseValue('test:/init.mp4', initSegmentData)
177
- .setResponseValue('test:/main.mp4', segmentData);
178
-
179
- const manifest = await parser.start('test:/master', playerInterface);
192
+ const manifest = await testInitialManifest(
193
+ master, media + '#EXT-X-ENDLIST');
180
194
  expect(manifest.presentationTimeline.isLive()).toBe(false);
181
195
  expect(manifest.presentationTimeline.isInProgress()).toBe(false);
182
196
  });
@@ -188,8 +202,8 @@ describe('HlsParser live', () => {
188
202
  const ref2 = makeReference(
189
203
  'test:/main2.mp4', 2, 4, /* syncTime= */ null);
190
204
 
191
- await testUpdate(
192
- master, media, [ref1], mediaWithAdditionalSegment, [ref1, ref2]);
205
+ const manifest = await testInitialManifest(master, media, [ref1]);
206
+ await testUpdate(manifest, mediaWithAdditionalSegment, [ref1, ref2]);
193
207
  });
194
208
 
195
209
  it('updates all variants', async () => {
@@ -205,9 +219,9 @@ describe('HlsParser live', () => {
205
219
  const ref2 = makeReference(
206
220
  'test:/main2.mp4', 2, 4, /* syncTime= */ null);
207
221
 
208
- await testUpdate(
209
- masterWithTwoVariants, media, [ref1], mediaWithAdditionalSegment,
210
- [ref1, ref2]);
222
+ const manifest = await testInitialManifest(
223
+ masterWithTwoVariants, media, [ref1]);
224
+ await testUpdate(manifest, mediaWithAdditionalSegment, [ref1, ref2]);
211
225
  });
212
226
 
213
227
  it('updates all streams', async () => {
@@ -228,9 +242,9 @@ describe('HlsParser live', () => {
228
242
  const ref2 = makeReference(
229
243
  'test:/main2.mp4', 2, 4, /* syncTime= */ null);
230
244
 
231
- await testUpdate(
232
- masterWithAudio, media, [ref1], mediaWithAdditionalSegment,
233
- [ref1, ref2]);
245
+ const manifest = await testInitialManifest(
246
+ masterWithAudio, media, [ref1]);
247
+ await testUpdate(manifest, mediaWithAdditionalSegment, [ref1, ref2]);
234
248
  });
235
249
 
236
250
  it('handles multiple updates', async () => {
@@ -253,72 +267,28 @@ describe('HlsParser live', () => {
253
267
  const ref3 = makeReference(
254
268
  'test:/main3.mp4', 4, 6, /* syncTime= */ null);
255
269
 
256
- fakeNetEngine
257
- .setResponseText('test:/master', master)
258
- .setResponseText('test:/video', media)
259
- .setResponseValue('test:/init.mp4', initSegmentData)
260
- .setResponseValue('test:/main.mp4', segmentData);
261
-
262
- const manifest = await parser.start('test:/master', playerInterface);
263
-
264
- const video = manifest.variants[0].video;
265
- await video.createSegmentIndex();
266
- ManifestParser.verifySegmentIndex(video, [ref1]);
267
-
268
- fakeNetEngine
269
- .setResponseText('test:/master', master)
270
- .setResponseText('test:/video', updatedMedia1);
271
-
272
- await delayForUpdatePeriod();
273
- ManifestParser.verifySegmentIndex(video, [ref1, ref2]);
274
-
275
- fakeNetEngine
276
- .setResponseText('test:/master', master)
277
- .setResponseText('test:/video', updatedMedia2);
278
-
279
- await delayForUpdatePeriod();
280
- ManifestParser.verifySegmentIndex(video, [ref1, ref2, ref3]);
270
+ const manifest = await testInitialManifest(master, media, [ref1]);
271
+ await testUpdate(manifest, updatedMedia1, [ref1, ref2]);
272
+ await testUpdate(manifest, updatedMedia2, [ref1, ref2, ref3]);
281
273
  });
282
274
 
283
275
  it('converts presentation to VOD when it is finished', async () => {
284
- fakeNetEngine
285
- .setResponseText('test:/master', master)
286
- .setResponseText('test:/video', media)
287
- .setResponseValue('test:/init.mp4', initSegmentData)
288
- .setResponseValue('test:/main.mp4', segmentData);
289
-
290
- const manifest = await parser.start('test:/master', playerInterface);
291
-
276
+ const manifest = await testInitialManifest(master, media);
292
277
  expect(manifest.presentationTimeline.isLive()).toBe(true);
293
- fakeNetEngine
294
- .setResponseText('test:/master', master)
295
- .setResponseText('test:/video',
296
- mediaWithAdditionalSegment + '#EXT-X-ENDLIST\n');
297
278
 
298
- await delayForUpdatePeriod();
279
+ await testUpdate(
280
+ manifest, mediaWithAdditionalSegment + '#EXT-X-ENDLIST\n');
299
281
  expect(manifest.presentationTimeline.isLive()).toBe(false);
300
282
  });
301
283
 
302
284
  it('starts presentation as VOD when ENDLIST is present', async () => {
303
- fakeNetEngine
304
- .setResponseText('test:/master', master)
305
- .setResponseText('test:/video', media + '#EXT-X-ENDLIST')
306
- .setResponseValue('test:/init.mp4', initSegmentData)
307
- .setResponseValue('test:/main.mp4', segmentData);
308
-
309
- const manifest = await parser.start('test:/master', playerInterface);
285
+ const manifest = await testInitialManifest(
286
+ master, media + '#EXT-X-ENDLIST');
310
287
  expect(manifest.presentationTimeline.isLive()).toBe(false);
311
288
  });
312
289
 
313
290
  it('does not throw when interrupted by stop', async () => {
314
- fakeNetEngine
315
- .setResponseText('test:/master', master)
316
- .setResponseText('test:/video', media)
317
- .setResponseValue('test:/init.mp4', initSegmentData)
318
- .setResponseValue('test:/main.mp4', segmentData);
319
-
320
- const manifest = await parser.start('test:/master', playerInterface);
321
-
291
+ const manifest = await testInitialManifest(master, media);
322
292
  expect(manifest.presentationTimeline.isLive()).toBe(true);
323
293
 
324
294
  // Block the next request so that update() is still happening when we
@@ -336,6 +306,74 @@ describe('HlsParser live', () => {
336
306
  // Wait for stop to complete.
337
307
  await stopPromise;
338
308
  });
309
+
310
+ it('calls notifySegments on each update', async () => {
311
+ const manifest = await testInitialManifest(master, media);
312
+ const notifySegmentsSpy = spyOn(
313
+ manifest.presentationTimeline, 'notifySegments').and.callThrough();
314
+
315
+ // Trigger an update.
316
+ await delayForUpdatePeriod();
317
+
318
+ expect(notifySegmentsSpy).toHaveBeenCalled();
319
+ notifySegmentsSpy.calls.reset();
320
+
321
+ // Trigger another update.
322
+ await delayForUpdatePeriod();
323
+
324
+ expect(notifySegmentsSpy).toHaveBeenCalled();
325
+ });
326
+
327
+ it('converts to VOD only after all playlists end', async () => {
328
+ const master = [
329
+ '#EXTM3U\n',
330
+ '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
331
+ 'URI="audio"\n',
332
+ '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",AUDIO="aud1",',
333
+ 'RESOLUTION=960x540,FRAME-RATE=60\n',
334
+ 'video\n',
335
+ ].join('');
336
+
337
+ const mediaWithEndList = media + '#EXT-X-ENDLIST';
338
+
339
+ const manifest = await testInitialManifest(master, media);
340
+ expect(manifest.presentationTimeline.isLive()).toBe(true);
341
+
342
+ // Update video only.
343
+ fakeNetEngine.setResponseText('test:/video', mediaWithEndList);
344
+ await delayForUpdatePeriod();
345
+
346
+ // Audio hasn't "ended" yet, so we're still live.
347
+ expect(manifest.presentationTimeline.isLive()).toBe(true);
348
+
349
+ // Update audio.
350
+ fakeNetEngine.setResponseText('test:/audio', mediaWithEndList);
351
+ await delayForUpdatePeriod();
352
+
353
+ // Now both have "ended", so we're no longer live.
354
+ expect(manifest.presentationTimeline.isLive()).toBe(false);
355
+ });
356
+
357
+ it('stops updating after all playlists end', async () => {
358
+ const manifest = await testInitialManifest(master, media);
359
+ expect(manifest.presentationTimeline.isLive()).toBe(true);
360
+
361
+ fakeNetEngine.request.calls.reset();
362
+ await testUpdate(
363
+ manifest, mediaWithAdditionalSegment + '#EXT-X-ENDLIST\n');
364
+
365
+ // We saw one request for the video playlist, which signalled "ENDLIST".
366
+ fakeNetEngine.expectRequest(
367
+ 'test:/video',
368
+ shaka.net.NetworkingEngine.RequestType.MANIFEST);
369
+ expect(manifest.presentationTimeline.isLive()).toBe(false);
370
+
371
+ fakeNetEngine.request.calls.reset();
372
+ await delayForUpdatePeriod();
373
+
374
+ // No new updates were requested.
375
+ expect(fakeNetEngine.request).not.toHaveBeenCalled();
376
+ });
339
377
  }); // describe('update')
340
378
  }); // describe('playlist type EVENT')
341
379
 
@@ -413,47 +451,27 @@ describe('HlsParser live', () => {
413
451
  ].join('');
414
452
 
415
453
  it('starts presentation as VOD when ENDLIST is present', async () => {
416
- fakeNetEngine
417
- .setResponseText('test:/master', master)
418
- .setResponseText('test:/video', media + '#EXT-X-ENDLIST')
419
- .setResponseValue('test:/init.mp4', initSegmentData)
420
- .setResponseValue('test:/main.mp4', segmentData);
421
-
422
- const manifest = await parser.start('test:/master', playerInterface);
454
+ const manifest = await testInitialManifest(
455
+ master, media + '#EXT-X-ENDLIST');
423
456
  expect(manifest.presentationTimeline.isLive()).toBe(false);
424
457
  });
425
458
 
426
459
  it('does not fail on a missing sequence number', async () => {
427
- fakeNetEngine
428
- .setResponseText('test:/master', master)
429
- .setResponseText('test:/video', mediaWithoutSequenceNumber)
430
- .setResponseValue('test:/init.mp4', initSegmentData)
431
- .setResponseValue('test:/main.mp4', segmentData);
432
-
433
- await parser.start('test:/master', playerInterface);
460
+ await testInitialManifest(master, mediaWithoutSequenceNumber);
434
461
  });
435
462
 
436
463
  it('sets presentation delay as configured', async () => {
437
- fakeNetEngine
438
- .setResponseText('test:/master', master)
439
- .setResponseText('test:/video', media)
440
- .setResponseValue('test:/init.mp4', initSegmentData)
441
- .setResponseValue('test:/main.mp4', segmentData);
442
464
  config.defaultPresentationDelay = 10;
443
465
  parser.configure(config);
444
- const manifest = await parser.start('test:/master', playerInterface);
466
+
467
+ const manifest = await testInitialManifest(master, media);
445
468
  expect(manifest.presentationTimeline.getDelay()).toBe(
446
469
  config.defaultPresentationDelay);
447
470
  });
448
471
 
449
472
  it('sets 3 times target duration as presentation delay if not configured',
450
473
  async () => {
451
- fakeNetEngine
452
- .setResponseText('test:/master', master)
453
- .setResponseText('test:/video', media)
454
- .setResponseValue('test:/init.mp4', initSegmentData)
455
- .setResponseValue('test:/main.mp4', segmentData);
456
- const manifest = await parser.start('test:/master', playerInterface);
474
+ const manifest = await testInitialManifest(master, media);
457
475
  expect(manifest.presentationTimeline.getDelay()).toBe(15);
458
476
  });
459
477
 
@@ -469,15 +487,9 @@ describe('HlsParser live', () => {
469
487
  'main.mp4\n',
470
488
  ].join('');
471
489
 
472
- fakeNetEngine
473
- .setResponseText('test:/master', master)
474
- .setResponseText('test:/video', mediaWithLowLatency)
475
- .setResponseValue('test:/init.mp4', initSegmentData)
476
- .setResponseValue('test:/main.mp4', segmentData);
477
-
478
490
  playerInterface.isLowLatencyMode = () => true;
479
491
 
480
- const manifest = await parser.start('test:/master', playerInterface);
492
+ const manifest = await testInitialManifest(master, mediaWithLowLatency);
481
493
  // Presentation delay should be the value of 'PART-HOLD-BACK' if not
482
494
  // configured.
483
495
  expect(manifest.presentationTimeline.getDelay()).toBe(1.8);
@@ -485,13 +497,8 @@ describe('HlsParser live', () => {
485
497
 
486
498
  describe('availabilityWindowOverride', () => {
487
499
  async function testWindowOverride(expectedWindow) {
488
- fakeNetEngine
489
- .setResponseText('test:/master', master)
490
- .setResponseText('test:/video', mediaWithManySegments)
491
- .setResponseValue('test:/init.mp4', initSegmentData)
492
- .setResponseValue('test:/main.mp4', segmentData);
493
-
494
- const manifest = await parser.start('test:/master', playerInterface);
500
+ const manifest = await testInitialManifest(
501
+ master, mediaWithManySegments);
495
502
  expect(manifest).toBeTruthy();
496
503
  const timeline = manifest.presentationTimeline;
497
504
  expect(timeline).toBeTruthy();
@@ -514,13 +521,6 @@ describe('HlsParser live', () => {
514
521
  });
515
522
 
516
523
  it('sets timestamp offset for segments with discontinuity', async () => {
517
- fakeNetEngine
518
- .setResponseText('test:/master', master)
519
- .setResponseText('test:/video', mediaWithDiscontinuity)
520
- .setResponseValue('test:/init.mp4', initSegmentData)
521
- .setResponseValue('test:/main.mp4', segmentData)
522
- .setResponseValue('test:/main2.mp4', segmentData);
523
-
524
524
  const ref1 = makeReference(
525
525
  'test:/main.mp4', 0, 2, /* syncTime= */ null,
526
526
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
@@ -533,10 +533,7 @@ describe('HlsParser live', () => {
533
533
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
534
534
  /* timestampOffset= */ 0);
535
535
 
536
- const manifest = await parser.start('test:/master', playerInterface);
537
- const video = manifest.variants[0].video;
538
- await video.createSegmentIndex();
539
- ManifestParser.verifySegmentIndex(video, [ref1, ref2]);
536
+ await testInitialManifest(master, mediaWithDiscontinuity, [ref1, ref2]);
540
537
  });
541
538
 
542
539
  // Test for https://github.com/shaka-project/shaka-player/issues/4223
@@ -562,14 +559,6 @@ describe('HlsParser live', () => {
562
559
  '#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210\n',
563
560
  ].join('');
564
561
 
565
- fakeNetEngine
566
- .setResponseText('test:/master', master)
567
- .setResponseText('test:/video', mediaWithPartialSegments)
568
- .setResponseValue('test:/init.mp4', initSegmentData)
569
- .setResponseValue('test:/main.mp4', segmentData)
570
- .setResponseValue('test:/partial.mp4', segmentData)
571
- .setResponseValue('test:/partial2.mp4', segmentData);
572
-
573
562
  const partialRef = makeReference(
574
563
  'test:/partial.mp4', 0, 2, /* syncTime= */ null,
575
564
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 199);
@@ -597,10 +586,7 @@ describe('HlsParser live', () => {
597
586
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
598
587
  /* timestampOffset= */ 0, [partialRef3, preloadRef]);
599
588
 
600
- const manifest = await parser.start('test:/master', playerInterface);
601
- const video = manifest.variants[0].video;
602
- await video.createSegmentIndex();
603
- ManifestParser.verifySegmentIndex(video, [ref, ref2]);
589
+ await testInitialManifest(master, mediaWithPartialSegments, [ref, ref2]);
604
590
  });
605
591
 
606
592
  // Test for https://github.com/shaka-project/shaka-player/issues/4223
@@ -623,14 +609,6 @@ describe('HlsParser live', () => {
623
609
  '#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210\n',
624
610
  ].join('');
625
611
 
626
- fakeNetEngine
627
- .setResponseText('test:/master', master)
628
- .setResponseText('test:/video', mediaWithPartialSegments)
629
- .setResponseValue('test:/init.mp4', initSegmentData)
630
- .setResponseValue('test:/main.mp4', segmentData)
631
- .setResponseValue('test:/partial.mp4', segmentData)
632
- .setResponseValue('test:/partial2.mp4', segmentData);
633
-
634
612
  const ref = makeReference(
635
613
  'test:/main.mp4', 0, 4, /* syncTime= */ null,
636
614
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
@@ -646,10 +624,7 @@ describe('HlsParser live', () => {
646
624
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 209,
647
625
  /* timestampOffset= */ 0, [partialRef]);
648
626
 
649
- const manifest = await parser.start('test:/master', playerInterface);
650
- const video = manifest.variants[0].video;
651
- await video.createSegmentIndex();
652
- ManifestParser.verifySegmentIndex(video, [ref, ref2]);
627
+ await testInitialManifest(master, mediaWithPartialSegments, [ref, ref2]);
653
628
  });
654
629
 
655
630
  // Test for https://github.com/shaka-project/shaka-player/issues/4185
@@ -667,12 +642,8 @@ describe('HlsParser live', () => {
667
642
  '#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210\n',
668
643
  ].join('');
669
644
 
670
- fakeNetEngine
671
- .setResponseText('test:/master', master)
672
- .setResponseText('test:/video', mediaWithPartialSegments);
673
-
674
645
  // If this throws, the test fails. Otherwise, it passes.
675
- await parser.start('test:/master', playerInterface);
646
+ await testInitialManifest(master, mediaWithPartialSegments);
676
647
  });
677
648
 
678
649
  describe('update', () => {
@@ -682,8 +653,8 @@ describe('HlsParser live', () => {
682
653
  const ref2 = makeReference(
683
654
  'test:/main2.mp4', 2, 4, /* syncTime= */ null);
684
655
 
685
- await testUpdate(
686
- master, media, [ref1], mediaWithAdditionalSegment, [ref1, ref2]);
656
+ const manifest = await testInitialManifest(master, media, [ref1]);
657
+ await testUpdate(manifest, mediaWithAdditionalSegment, [ref1, ref2]);
687
658
  });
688
659
 
689
660
  it('evicts removed segments', async () => {
@@ -692,9 +663,9 @@ describe('HlsParser live', () => {
692
663
  const ref2 = makeReference(
693
664
  'test:/main2.mp4', 2, 4, /* syncTime= */ null);
694
665
 
695
- await testUpdate(
696
- master, mediaWithAdditionalSegment, [ref1, ref2],
697
- mediaWithRemovedSegment, [ref2]);
666
+ const manifest = await testInitialManifest(
667
+ master, mediaWithAdditionalSegment, [ref1, ref2]);
668
+ await testUpdate(manifest, mediaWithRemovedSegment, [ref2]);
698
669
  });
699
670
 
700
671
  it('handles updates with redirects', async () => {
@@ -719,58 +690,32 @@ describe('HlsParser live', () => {
719
690
  }
720
691
  });
721
692
 
693
+ const manifest = await testInitialManifest(master, media, [oldRef1]);
722
694
  await testUpdate(
723
- master, media, [oldRef1], mediaWithAdditionalSegment,
724
- [newRef1, newRef2]);
695
+ manifest, mediaWithAdditionalSegment, [newRef1, newRef2]);
725
696
  });
726
697
 
727
698
  it('parses start time from mp4 segments', async () => {
728
- fakeNetEngine
729
- .setResponseText('test:/master', master)
730
- .setResponseText('test:/video', media)
731
- .setResponseValue('test:/init.mp4', initSegmentData)
732
- .setResponseValue('test:/main.mp4', segmentData);
733
-
734
- const expectedRef = makeReference(
699
+ const ref = makeReference(
735
700
  'test:/main.mp4', 0, 2, /* syncTime= */ null);
736
701
  // In live content, we do not set timestampOffset.
737
- expectedRef.timestampOffset = 0;
702
+ ref.timestampOffset = 0;
738
703
 
739
- const manifest = await parser.start('test:/master', playerInterface);
740
- const video = manifest.variants[0].video;
741
- await video.createSegmentIndex();
742
- ManifestParser.verifySegmentIndex(video, [expectedRef]);
704
+ await testInitialManifest(master, media, [ref]);
743
705
  });
744
706
 
745
707
  it('gets start time on update without segment request', async () => {
746
- fakeNetEngine
747
- .setResponseText('test:/master', master)
748
- .setResponseText('test:/video', mediaWithAdditionalSegment)
749
- .setResponseValue('test:/init.mp4', initSegmentData)
750
- .setResponseValue('test:/main.mp4', segmentData);
751
-
752
708
  const ref1 = makeReference(
753
709
  'test:/main.mp4', 0, 2, /* syncTime= */ null);
754
710
 
755
711
  const ref2 = makeReference(
756
712
  'test:/main2.mp4', 2, 4, /* syncTime= */ null);
757
713
 
758
- const manifest = await parser.start('test:/master', playerInterface);
759
- const video = manifest.variants[0].video;
760
- await video.createSegmentIndex();
761
- ManifestParser.verifySegmentIndex(video, [ref1, ref2]);
762
-
763
- fakeNetEngine
764
- .setResponseText('test:/master', master)
765
- .setResponseText('test:/video', mediaWithRemovedSegment)
766
- .setResponseValue('test:/init.mp4', initSegmentData)
767
- .setResponseValue('test:/main.mp4', segmentData)
768
- .setResponseValue('test:/main2.mp4', segmentData);
714
+ const manifest = await testInitialManifest(
715
+ master, mediaWithAdditionalSegment, [ref1, ref2]);
769
716
 
770
717
  fakeNetEngine.request.calls.reset();
771
- await delayForUpdatePeriod();
772
-
773
- ManifestParser.verifySegmentIndex(video, [ref2]);
718
+ await testUpdate(manifest, mediaWithRemovedSegment, [ref2]);
774
719
 
775
720
  // Only one request was made, and it was for the playlist.
776
721
  // No segment requests were needed to get the start time.
@@ -782,37 +727,17 @@ describe('HlsParser live', () => {
782
727
 
783
728
  it('reuses cached timestamp offset for segments with discontinuity',
784
729
  async () => {
785
- fakeNetEngine
786
- .setResponseText('test:/master', master)
787
- .setResponseText('test:/video', mediaWithDiscontinuity)
788
- .setResponseValue('test:/init.mp4', initSegmentData)
789
- .setResponseValue('test:/main.mp4', segmentData)
790
- .setResponseValue('test:/main2.mp4', segmentData);
791
-
792
730
  const ref1 = makeReference(
793
731
  'test:/main.mp4', 0, 2, /* syncTime= */ null);
794
-
795
732
  const ref2 = makeReference(
796
733
  'test:/main2.mp4', 2, 4, /* syncTime= */ null);
797
734
 
798
- const manifest =
799
- await parser.start('test:/master', playerInterface);
800
-
801
- const video = manifest.variants[0].video;
802
- await video.createSegmentIndex();
803
- ManifestParser.verifySegmentIndex(video, [ref1, ref2]);
804
-
805
- fakeNetEngine
806
- .setResponseText('test:/master', master)
807
- .setResponseText('test:/video',
808
- mediaWithUpdatedDiscontinuitySegment)
809
- .setResponseValue('test:/init.mp4', initSegmentData)
810
- .setResponseValue('test:/main2.mp4', segmentData);
735
+ const manifest = await testInitialManifest(
736
+ master, mediaWithDiscontinuity, [ref1, ref2]);
811
737
 
812
738
  fakeNetEngine.request.calls.reset();
813
- await delayForUpdatePeriod();
814
-
815
- ManifestParser.verifySegmentIndex(video, [ref2]);
739
+ await testUpdate(
740
+ manifest, mediaWithUpdatedDiscontinuitySegment, [ref2]);
816
741
 
817
742
  // Only one request should be made, and it's for the playlist.
818
743
  // Expect to use the cached timestamp offset for the main2.mp4
@@ -853,19 +778,12 @@ describe('HlsParser live', () => {
853
778
  'main3.mp4\n',
854
779
  ].join('');
855
780
 
856
- fakeNetEngine
857
- .setResponseText('test:/master', master)
858
- .setResponseText('test:/video', mediaWithDeltaUpdates)
859
- .setResponseText('test:/video?_HLS_skip=YES',
860
- mediaWithSkippedSegments)
861
- .setResponseValue('test:/init.mp4', initSegmentData)
862
- .setResponseValue('test:/main.mp4', segmentData)
863
- .setResponseValue('test:/main2.mp4', segmentData)
864
- .setResponseValue('test:/main3.mp4', segmentData);
781
+ fakeNetEngine.setResponseText(
782
+ 'test:/video?_HLS_skip=YES', mediaWithSkippedSegments);
865
783
 
866
784
  playerInterface.isLowLatencyMode = () => true;
867
- await parser.start('test:/master', playerInterface);
868
- // Replace the entries with the updated values.
785
+
786
+ await testInitialManifest(master, mediaWithDeltaUpdates);
869
787
 
870
788
  fakeNetEngine.request.calls.reset();
871
789
  await delayForUpdatePeriod();
@@ -875,7 +793,6 @@ describe('HlsParser live', () => {
875
793
  shaka.net.NetworkingEngine.RequestType.MANIFEST);
876
794
  });
877
795
 
878
-
879
796
  it('skips older segments', async () => {
880
797
  const mediaWithSkippedSegments = [
881
798
  '#EXTM3U\n',
@@ -896,12 +813,15 @@ describe('HlsParser live', () => {
896
813
  'test:/main2.mp4', 2, 4, /* syncTime= */ null);
897
814
  const ref3 = makeReference(
898
815
  'test:/main3.mp4', 4, 6, /* syncTime= */ null);
816
+
817
+ const manifest = await testInitialManifest(
818
+ master, mediaWithAdditionalSegment, [ref1, ref2]);
819
+
899
820
  // With 'SKIPPED-SEGMENTS', ref1 is skipped from the playlist,
900
821
  // and ref1 should be in the SegmentReferences list.
901
822
  // ref3 should be appended to the SegmentReferences list.
902
823
  await testUpdate(
903
- master, mediaWithAdditionalSegment, [ref1, ref2],
904
- mediaWithSkippedSegments, [ref1, ref2, ref3]);
824
+ manifest, mediaWithSkippedSegments, [ref1, ref2, ref3]);
905
825
  });
906
826
 
907
827
  it('skips older segments with discontinuity', async () => {
@@ -959,12 +879,14 @@ describe('HlsParser live', () => {
959
879
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
960
880
  /* timestampOffset= */ 0);
961
881
 
882
+ const manifest = await testInitialManifest(
883
+ master, mediaWithDiscontinuity2, [ref1, ref2, ref3]);
884
+
962
885
  // With 'SKIPPED-SEGMENTS', ref1, ref2 are skipped from the playlist,
963
886
  // and ref1,ref2 should be in the SegmentReferences list.
964
887
  // ref3,ref4 should be appended to the SegmentReferences list.
965
888
  await testUpdate(
966
- master, mediaWithDiscontinuity2, [ref1, ref2, ref3],
967
- mediaWithSkippedSegments2, [ref1, ref2, ref3, ref4]);
889
+ manifest, mediaWithSkippedSegments2, [ref1, ref2, ref3, ref4]);
968
890
  });
969
891
  }); // describe('update')
970
892
  }); // describe('playlist type LIVE')