shaka-player 4.2.12 → 4.2.13

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 (42) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +11 -0
  2. package/.github/workflows/build-and-test.yaml +15 -0
  3. package/.github/workflows/selenium-lab-tests.yaml +3 -2
  4. package/.github/workflows/update-issues.yaml +1 -0
  5. package/CHANGELOG.md +17 -0
  6. package/dist/deps.js +1 -1
  7. package/dist/locales.js +31 -31
  8. package/dist/shaka-player.compiled.debug.js +23 -24
  9. package/dist/shaka-player.compiled.debug.map +3 -3
  10. package/dist/shaka-player.compiled.js +368 -369
  11. package/dist/shaka-player.compiled.map +3 -3
  12. package/dist/shaka-player.ui.debug.js +27 -29
  13. package/dist/shaka-player.ui.debug.map +3 -3
  14. package/dist/shaka-player.ui.js +383 -383
  15. package/dist/shaka-player.ui.map +2 -2
  16. package/docs/tutorials/selenium-grid-config.md +60 -8
  17. package/karma.conf.js +50 -7
  18. package/lib/abr/simple_abr_manager.js +5 -5
  19. package/lib/player.js +1 -5
  20. package/lib/polyfill/orientation.js +34 -7
  21. package/lib/text/vtt_text_parser.js +1 -0
  22. package/lib/util/manifest_parser_utils.js +4 -2
  23. package/lib/util/platform.js +14 -0
  24. package/lib/util/stream_utils.js +69 -26
  25. package/package.json +2 -2
  26. package/test/cast/cast_utils_unit.js +4 -1
  27. package/test/hls/hls_parser_unit.js +72 -0
  28. package/test/media/drm_engine_integration.js +2 -2
  29. package/test/media/segment_index_unit.js +3 -3
  30. package/test/media/streaming_engine_integration.js +14 -11
  31. package/test/offline/offline_integration.js +6 -3
  32. package/test/player_external.js +19 -16
  33. package/test/player_integration.js +35 -48
  34. package/test/player_src_equals_integration.js +9 -5
  35. package/test/test/util/fake_demo_main.js +7 -3
  36. package/test/test/util/layout_tests.js +2 -2
  37. package/test/test/util/ui_utils.js +9 -2
  38. package/test/test/util/util.js +6 -27
  39. package/test/test/util/waiter.js +73 -3
  40. package/test/ui/ad_ui_unit.js +9 -9
  41. package/test/util/stream_utils_unit.js +46 -0
  42. package/ui/range_element.js +5 -0
@@ -573,6 +573,78 @@ describe('HlsParser', () => {
573
573
  await testHlsParser(master, media, manifest);
574
574
  });
575
575
 
576
+ it('accepts fLaC codec as audio/mp4', async () => {
577
+ const master = [
578
+ '#EXTM3U\n',
579
+ '#EXT-X-STREAM-INF:BANDWIDTH=1000000,CODECS="fLaC"\n',
580
+ 'audio\n',
581
+ '#EXT-X-STREAM-INF:BANDWIDTH=1000000,CODECS="flac"\n',
582
+ 'audio2\n',
583
+ ].join('');
584
+
585
+ const media = [
586
+ '#EXTM3U\n',
587
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
588
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
589
+ '#EXTINF:5,\n',
590
+ '#EXT-X-BYTERANGE:121090@616\n',
591
+ 'main.mp4',
592
+ ].join('');
593
+
594
+ const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
595
+ manifest.anyTimeline();
596
+ manifest.addPartialVariant((variant) => {
597
+ variant.addPartialStream(ContentType.AUDIO, (stream) => {
598
+ stream.mime('audio/mp4', 'fLaC');
599
+ });
600
+ });
601
+ manifest.addPartialVariant((variant) => {
602
+ variant.addPartialStream(ContentType.AUDIO, (stream) => {
603
+ stream.mime('audio/mp4', 'flac');
604
+ });
605
+ });
606
+ manifest.sequenceMode = true;
607
+ });
608
+
609
+ await testHlsParser(master, media, manifest);
610
+ });
611
+
612
+ it('accepts Opus codec as audio/mp4', async () => {
613
+ const master = [
614
+ '#EXTM3U\n',
615
+ '#EXT-X-STREAM-INF:BANDWIDTH=128000,CODECS="Opus"\n',
616
+ 'audio\n',
617
+ '#EXT-X-STREAM-INF:BANDWIDTH=128000,CODECS="opus"\n',
618
+ 'audio2\n',
619
+ ].join('');
620
+
621
+ const media = [
622
+ '#EXTM3U\n',
623
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
624
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
625
+ '#EXTINF:5,\n',
626
+ '#EXT-X-BYTERANGE:121090@616\n',
627
+ 'main.mp4',
628
+ ].join('');
629
+
630
+ const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
631
+ manifest.anyTimeline();
632
+ manifest.addPartialVariant((variant) => {
633
+ variant.addPartialStream(ContentType.AUDIO, (stream) => {
634
+ stream.mime('audio/mp4', 'Opus');
635
+ });
636
+ });
637
+ manifest.addPartialVariant((variant) => {
638
+ variant.addPartialStream(ContentType.AUDIO, (stream) => {
639
+ stream.mime('audio/mp4', 'opus');
640
+ });
641
+ });
642
+ manifest.sequenceMode = true;
643
+ });
644
+
645
+ await testHlsParser(master, media, manifest);
646
+ });
647
+
576
648
  it('parses audio+video variant with closed captions', async () => {
577
649
  const master = [
578
650
  '#EXTM3U\n',
@@ -242,7 +242,7 @@ describe('DrmEngine', () => {
242
242
  /* hasClosedCaptions= */ false);
243
243
 
244
244
  expect(video.buffered.end(0)).toBeGreaterThan(0);
245
- video.play();
245
+ await video.play();
246
246
 
247
247
  const waiter = new shaka.test.Waiter(eventManager).timeoutAfter(15);
248
248
  waiter.setMediaSourceEngine(mediaSourceEngine);
@@ -325,7 +325,7 @@ describe('DrmEngine', () => {
325
325
  /* hasClosedCaptions= */ false);
326
326
 
327
327
  expect(video.buffered.end(0)).toBeGreaterThan(0);
328
- video.play();
328
+ await video.play();
329
329
 
330
330
  const waiter = new shaka.test.Waiter(eventManager).timeoutAfter(15);
331
331
  waiter.setMediaSourceEngine(mediaSourceEngine);
@@ -974,9 +974,9 @@ describe('SegmentIndex', /** @suppress {accessControls} */ () => {
974
974
  return [newRefs.shift()];
975
975
  });
976
976
  });
977
- // Wait long enough for all three new refs to be appended.
978
- // Or for all of the new refs to be passed out.
979
- await Promise.race([shaka.test.Util.delay(1), done]);
977
+
978
+ // Wait for the new refs to be appended.
979
+ await done;
980
980
 
981
981
  expect(Array.from(metaIndex)).toEqual(oldRefs.concat(inputRefs2));
982
982
  });
@@ -57,6 +57,9 @@ describe('StreamingEngine', () => {
57
57
  beforeEach(() => {
58
58
  config = shaka.util.PlayerConfiguration.createDefault().streaming;
59
59
 
60
+ // Disable stall detection, which can interfere with playback tests.
61
+ config.stallEnabled = false;
62
+
60
63
  onError = jasmine.createSpy('onError');
61
64
  onError.and.callFake(fail);
62
65
  onEvent = jasmine.createSpy('onEvent');
@@ -276,7 +279,7 @@ describe('StreamingEngine', () => {
276
279
  // Let's go!
277
280
  streamingEngine.switchVariant(variant);
278
281
  await streamingEngine.start();
279
- video.play();
282
+ await video.play();
280
283
  // The overall test timeout is 120 seconds, and the content is 40
281
284
  // seconds. It should be possible to complete this test in 100 seconds,
282
285
  // and if not, we want the error thrown to be within the overall test's
@@ -296,7 +299,7 @@ describe('StreamingEngine', () => {
296
299
  // Let's go!
297
300
  streamingEngine.switchVariant(variant);
298
301
  await streamingEngine.start();
299
- video.play();
302
+ await video.play();
300
303
 
301
304
  // Wait for playback to begin before increasing the playback rate. This
302
305
  // improves test reliability on slow platforms like Chromecast.
@@ -310,7 +313,7 @@ describe('StreamingEngine', () => {
310
313
  // Let's go!
311
314
  streamingEngine.switchVariant(variant);
312
315
  await streamingEngine.start();
313
- video.play();
316
+ await video.play();
314
317
 
315
318
  // After 35 seconds seek back 10 seconds into the first Period.
316
319
  await waiter.timeoutAfter(80).waitUntilPlayheadReaches(video, 35);
@@ -322,7 +325,7 @@ describe('StreamingEngine', () => {
322
325
  // Let's go!
323
326
  streamingEngine.switchVariant(variant);
324
327
  await streamingEngine.start();
325
- video.play();
328
+ await video.play();
326
329
  await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 20);
327
330
  video.currentTime = 40;
328
331
  await waiter.timeoutAfter(60).waitForEnd(video);
@@ -350,7 +353,7 @@ describe('StreamingEngine', () => {
350
353
  streamingEngine.switchVariant(variant);
351
354
  await streamingEngine.start();
352
355
 
353
- video.play();
356
+ await video.play();
354
357
  await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 305);
355
358
 
356
359
  const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
@@ -370,7 +373,7 @@ describe('StreamingEngine', () => {
370
373
  // Seek outside the availability window right away. The playhead
371
374
  // should adjust the video's current time.
372
375
  video.currentTime = segmentAvailability.end + 120;
373
- video.play();
376
+ await video.play();
374
377
 
375
378
  // Wait until the repositioning is complete so we don't
376
379
  // immediately hit this case.
@@ -395,7 +398,7 @@ describe('StreamingEngine', () => {
395
398
  video.currentTime = segmentAvailability.start - 120;
396
399
  expect(video.currentTime).toBeGreaterThan(0);
397
400
 
398
- video.play();
401
+ await video.play();
399
402
  await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 305);
400
403
 
401
404
  // We are playing close to the beginning of the availability window.
@@ -423,7 +426,7 @@ describe('StreamingEngine', () => {
423
426
  // Let's go!
424
427
  streamingEngine.switchVariant(variant);
425
428
  await streamingEngine.start();
426
- video.play();
429
+ await video.play();
427
430
 
428
431
  await waiter.timeoutAfter(5).waitUntilPlayheadReaches(video, 0.01);
429
432
  expect(video.buffered.length).toBeGreaterThan(0);
@@ -438,7 +441,7 @@ describe('StreamingEngine', () => {
438
441
  // Let's go!
439
442
  streamingEngine.switchVariant(variant);
440
443
  await streamingEngine.start();
441
- video.play();
444
+ await video.play();
442
445
 
443
446
  await waiter.timeoutAfter(5).waitUntilPlayheadReaches(video, 0.01);
444
447
  expect(video.buffered.length).toBeGreaterThan(0);
@@ -457,7 +460,7 @@ describe('StreamingEngine', () => {
457
460
  await waiter.timeoutAfter(5).waitForEvent(video, 'loadeddata');
458
461
 
459
462
  video.currentTime = 8;
460
- video.play();
463
+ await video.play();
461
464
 
462
465
  await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 23);
463
466
  // Should be close enough to still have the gap buffered.
@@ -474,7 +477,7 @@ describe('StreamingEngine', () => {
474
477
  await waiter.timeoutAfter(5).waitForEvent(video, 'loadeddata');
475
478
 
476
479
  video.currentTime = 8;
477
- video.play();
480
+ await video.play();
478
481
 
479
482
  await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 23);
480
483
  // Should be close enough to still have the gap buffered.
@@ -33,6 +33,9 @@ filterDescribe('Offline', supportsStorage, () => {
33
33
  player = new shaka.Player(video);
34
34
  player.addEventListener('error', fail);
35
35
 
36
+ // Disable stall detection, which can interfere with playback tests.
37
+ player.configure('streaming.stallEnabled', false);
38
+
36
39
  eventManager = new shaka.util.EventManager();
37
40
  waiter = new shaka.test.Waiter(eventManager);
38
41
  waiter.setPlayer(player);
@@ -67,7 +70,7 @@ filterDescribe('Offline', supportsStorage, () => {
67
70
 
68
71
  await player.load(contentUri);
69
72
 
70
- video.play();
73
+ await video.play();
71
74
  await playTo(/* end= */ 3, /* timeout= */ 20);
72
75
  await player.unload();
73
76
  await storage.remove(contentUri);
@@ -103,7 +106,7 @@ filterDescribe('Offline', supportsStorage, () => {
103
106
 
104
107
  await player.load(contentUri);
105
108
 
106
- video.play();
109
+ await video.play();
107
110
  await playTo(/* end= */ 3, /* timeout= */ 20);
108
111
  await player.unload();
109
112
  await storage.remove(contentUri);
@@ -146,7 +149,7 @@ filterDescribe('Offline', supportsStorage, () => {
146
149
 
147
150
  await player.load(contentUri);
148
151
 
149
- video.play();
152
+ await video.play();
150
153
  await playTo(/* end= */ 3, /* timeout= */ 20);
151
154
  await player.unload();
152
155
  await storage.remove(contentUri);
@@ -36,6 +36,24 @@ describe('Player', () => {
36
36
  beforeEach(() => {
37
37
  player = new compiledShaka.Player(video);
38
38
 
39
+ // Make sure we are playing the lowest res available to avoid test flake
40
+ // based on network issues. Note that disabling ABR and setting a low
41
+ // abr.defaultBandwidthEstimate would not be sufficient, because it
42
+ // would only affect the choice of track on the first period. When we
43
+ // cross a period boundary, the default bandwidth estimate will no
44
+ // longer be in effect, and AbrManager may choose higher res tracks for
45
+ // the new period. Using abr.restrictions.maxHeight will let us force
46
+ // AbrManager to the lowest resolution, which is its fallback when these
47
+ // soft restrictions cannot be met.
48
+ player.configure('abr.restrictions.maxHeight', 1);
49
+
50
+ // Make sure that live streams are synced against a good clock.
51
+ player.configure('manifest.dash.clockSyncUri',
52
+ 'https://shaka-player-demo.appspot.com/time.txt');
53
+
54
+ // Disable stall detection, which can interfere with playback tests.
55
+ player.configure('streaming.stallEnabled', false);
56
+
39
57
  // Grab event manager from the uncompiled library:
40
58
  eventManager = new shaka.util.EventManager();
41
59
  waiter = new shaka.test.Waiter(eventManager);
@@ -92,21 +110,6 @@ describe('Player', () => {
92
110
  }
93
111
  }
94
112
 
95
- // Make sure we are playing the lowest res available to avoid test flake
96
- // based on network issues. Note that disabling ABR and setting a low
97
- // abr.defaultBandwidthEstimate would not be sufficient, because it
98
- // would only affect the choice of track on the first period. When we
99
- // cross a period boundary, the default bandwidth estimate will no
100
- // longer be in effect, and AbrManager may choose higher res tracks for
101
- // the new period. Using abr.restrictions.maxHeight will let us force
102
- // AbrManager to the lowest resolution, which is its fallback when these
103
- // soft restrictions cannot be met.
104
- player.configure('abr.restrictions.maxHeight', 1);
105
-
106
- // Make sure that live streams are synced against a good clock.
107
- player.configure('manifest.dash.clockSyncUri',
108
- 'https://shaka-player-demo.appspot.com/time.txt');
109
-
110
113
  // Add asset-specific configuration.
111
114
  player.configure(asset.getConfiguration());
112
115
 
@@ -125,7 +128,7 @@ describe('Player', () => {
125
128
  const isLive = asset.features.includes(Feature.LIVE);
126
129
  expect(player.isLive()).toBe(isLive);
127
130
  }
128
- video.play();
131
+ await video.play();
129
132
 
130
133
  // Wait for the video to start playback. If it takes longer than 20
131
134
  // seconds, fail the test.
@@ -34,6 +34,9 @@ describe('Player', () => {
34
34
  await shaka.test.TestScheme.createManifests(compiledShaka, '_compiled');
35
35
  player = new compiledShaka.Player(video);
36
36
 
37
+ // Disable stall detection, which can interfere with playback tests.
38
+ player.configure('streaming.stallEnabled', false);
39
+
37
40
  // Grab event manager from the uncompiled library:
38
41
  eventManager = new shaka.util.EventManager();
39
42
  waiter = new shaka.test.Waiter(eventManager);
@@ -81,11 +84,15 @@ describe('Player', () => {
81
84
  // Unlike the other tests in this file, this uses an uncompiled build of
82
85
  // Shaka, so that we don't need to expose shaka.util.Timer.activeTimers.
83
86
  player = new shaka.Player(video);
87
+
88
+ // Disable stall detection, which can interfere with playback tests.
89
+ player.configure('streaming.stallEnabled', false);
90
+
84
91
  waiter.setPlayer(player);
85
92
 
86
93
  // Play the video for a little while.
87
94
  await player.load('test:sintel');
88
- video.play();
95
+ await video.play();
89
96
  await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 1, 10);
90
97
 
91
98
  // Destroy the player.
@@ -127,7 +134,7 @@ describe('Player', () => {
127
134
  }
128
135
  });
129
136
  await player.load('test:sintel_compiled');
130
- video.play();
137
+ await video.play();
131
138
  await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 25, 30);
132
139
  expect(results).toEqual(expected);
133
140
  });
@@ -139,7 +146,7 @@ describe('Player', () => {
139
146
  // This is tested more in player_unit.js. This is here to test the public
140
147
  // API and to check for renaming.
141
148
  await player.load('test:sintel_compiled');
142
- video.play();
149
+ await video.play();
143
150
  await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 1, 10);
144
151
 
145
152
  const stats = player.getStats();
@@ -210,7 +217,7 @@ describe('Player', () => {
210
217
 
211
218
  it('does not cause cues to be null', async () => {
212
219
  await player.load('test:sintel_compiled');
213
- video.play();
220
+ await video.play();
214
221
  await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 1, 10);
215
222
 
216
223
  // This TextTrack was created as part of load() when we set up the
@@ -331,7 +338,7 @@ describe('Player', () => {
331
338
  await player.load('test:sintel_realistic_compiled');
332
339
 
333
340
  // Play until a time at which the external cues would be on screen.
334
- video.play();
341
+ await video.play();
335
342
  await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 4, 20);
336
343
 
337
344
  expect(player.isTextTrackVisible()).toBe(true);
@@ -363,7 +370,7 @@ describe('Player', () => {
363
370
  await waiter.waitForEvent(player, 'texttrackvisibility');
364
371
 
365
372
  // Play until a time at which the external cues would be on screen.
366
- video.play();
373
+ await video.play();
367
374
  await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 4, 20);
368
375
 
369
376
  expect(player.isTextTrackVisible()).toBe(true);
@@ -434,7 +441,7 @@ describe('Player', () => {
434
441
  player.setTextTrackVisibility(true);
435
442
  player.selectTextLanguage('fr');
436
443
  video.currentTime = 5;
437
- video.play();
444
+ await video.play();
438
445
  await waiter.waitForMovementOrFailOnTimeout(video, 10);
439
446
 
440
447
  expect(video.textTracks[0].activeCues.length).toBe(1);
@@ -472,7 +479,7 @@ describe('Player', () => {
472
479
 
473
480
  it('at higher playback rates', async () => {
474
481
  await player.load('test:sintel_compiled');
475
- video.play();
482
+ await video.play();
476
483
  await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 1, 10);
477
484
 
478
485
  // Enabling trick play should change our playback rate to the same rate.
@@ -488,14 +495,12 @@ describe('Player', () => {
488
495
  });
489
496
 
490
497
  it('in sequence mode', async () => {
491
- const testSchemeMimeType = 'application/x-test-manifest';
492
- player = new compiledShaka.Player(video);
493
- await player.load('test:sintel_sequence_compiled', 0, testSchemeMimeType);
498
+ await player.load('test:sintel_sequence_compiled');
494
499
  expect(player.getManifest().sequenceMode).toBe(true);
495
500
 
496
501
  // Ensure the video plays.
497
- video.play();
498
- await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 5, 10);
502
+ await video.play();
503
+ await waiter.timeoutAfter(20).waitUntilPlayheadReaches(video, 5);
499
504
 
500
505
  // Seek the video, and see if it can continue playing from that point.
501
506
  video.currentTime = 20;
@@ -514,9 +519,8 @@ describe('Player', () => {
514
519
  // even if one is not specified in load().
515
520
  it('immediately after construction with MIME type', async () => {
516
521
  const testSchemeMimeType = 'application/x-test-manifest';
517
- player = new compiledShaka.Player(video);
518
522
  await player.load('test:sintel_compiled', 0, testSchemeMimeType);
519
- video.play();
523
+ await video.play();
520
524
  await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 1, 10);
521
525
  });
522
526
 
@@ -555,7 +559,7 @@ describe('Player', () => {
555
559
  // Regression test for https://github.com/shaka-project/shaka-player/issues/1187
556
560
  it('does not throw on destroy', async () => {
557
561
  await player.load('test:sintel_compiled');
558
- video.play();
562
+ await video.play();
559
563
  await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 1, 10);
560
564
  await player.unload();
561
565
  // Before we fixed #1187, the call to destroy() on textDisplayer was
@@ -801,7 +805,7 @@ describe('Player', () => {
801
805
  player.configure('streaming.observeQualityChanges', true);
802
806
 
803
807
  await player.load('test:sintel_compiled');
804
- video.play();
808
+ await video.play();
805
809
 
806
810
  // Wait for the video to start playback. If it takes longer than 10
807
811
  // seconds, fail the test.
@@ -815,7 +819,7 @@ describe('Player', () => {
815
819
  player.configure('streaming.observeQualityChanges', false);
816
820
 
817
821
  await player.load('test:sintel_compiled');
818
- video.play();
822
+ await video.play();
819
823
 
820
824
  // Wait for the video to start playback. If it takes longer than 10
821
825
  // seconds, fail the test.
@@ -844,7 +848,7 @@ describe('Player', () => {
844
848
 
845
849
  // Play the stream.
846
850
  await player.load('/base/test/test/assets/3675/dash_0.mpd');
847
- video.play();
851
+ await video.play();
848
852
 
849
853
  // Wait for the stream to be over.
850
854
  eventManager.listen(player, 'error', Util.spyFunc(onErrorSpy));
@@ -932,22 +936,22 @@ describe('Player', () => {
932
936
 
933
937
  await player.load('test:sintel_long_compiled');
934
938
  video.pause();
935
- await waitUntilBuffered(10);
939
+ await waiter.waitUntilBuffered(video, 10);
936
940
 
937
941
  player.configure('streaming.bufferingGoal', 30);
938
- await waitUntilBuffered(30);
942
+ await waiter.waitUntilBuffered(video, 30);
939
943
 
940
944
  player.configure('streaming.bufferingGoal', 60);
941
- await waitUntilBuffered(60);
942
- await Util.delay(0.2);
945
+ await waiter.waitUntilBuffered(video, 60);
946
+ await Util.delay(1);
943
947
  expect(getBufferedAhead()).toBeLessThan(70); // 60 + segment_size
944
948
 
945
949
  // We don't remove buffered content ahead of the playhead, so seek to
946
950
  // clear the buffer.
947
951
  player.configure('streaming.bufferingGoal', 10);
948
952
  video.currentTime = 120;
949
- await waitUntilBuffered(10);
950
- await Util.delay(0.2);
953
+ await waiter.waitUntilBuffered(video, 10);
954
+ await Util.delay(1);
951
955
  expect(getBufferedAhead()).toBeLessThan(20); // 10 + segment_size
952
956
  });
953
957
 
@@ -957,20 +961,22 @@ describe('Player', () => {
957
961
 
958
962
  await player.load('test:sintel_long_compiled');
959
963
  video.pause();
960
- await waitUntilBuffered(30);
964
+ await waiter.waitUntilBuffered(video, 30);
961
965
  video.currentTime = 20;
962
- await waitUntilBuffered(30);
966
+ await waiter.waitUntilBuffered(video, 30);
963
967
 
964
968
  expect(getBufferedBehind()).toBe(20); // Buffered to start still.
965
969
  video.currentTime = 50;
966
- await waitUntilBuffered(30);
970
+ await waiter.waitUntilBuffered(video, 30);
971
+ await Util.delay(1);
967
972
  expect(getBufferedBehind()).toBeLessThan(40); // 30 + segment_size
968
973
 
969
974
  player.configure('streaming.bufferBehind', 10);
970
975
  // We only evict content when we append a segment, so increase the
971
976
  // buffering goal so we append another segment.
972
977
  player.configure('streaming.bufferingGoal', 40);
973
- await waitUntilBuffered(40);
978
+ await waiter.waitUntilBuffered(video, 40);
979
+ await Util.delay(1);
974
980
  expect(getBufferedBehind()).toBeLessThanOrEqual(10);
975
981
  });
976
982
 
@@ -989,25 +995,6 @@ describe('Player', () => {
989
995
  }
990
996
  return video.currentTime - start;
991
997
  }
992
-
993
- async function waitUntilBuffered(amount) {
994
- for (let i = 0; i < 50; i++) {
995
- // We buffer from an internal segment, so this shouldn't take long to
996
- // buffer.
997
- await Util.delay(0.1); // eslint-disable-line no-await-in-loop
998
- if (getBufferedAhead() >= amount) {
999
- return;
1000
- }
1001
- }
1002
-
1003
- const ranges =
1004
- shaka.media.TimeRangesUtils.getBufferedInfo(video.buffered);
1005
- const currentTime = video.currentTime;
1006
- const target = currentTime + amount;
1007
-
1008
- throw new Error('Timeout waiting to buffer! ' +
1009
- JSON.stringify({ranges, currentTime, target}));
1010
- }
1011
998
  }); // describe('buffering')
1012
999
 
1013
1000
  describe('configuration', () => {
@@ -27,6 +27,10 @@ describe('Player Src Equals', () => {
27
27
  beforeEach(() => {
28
28
  player = new shaka.Player();
29
29
  player.addEventListener('error', fail);
30
+
31
+ // Disable stall detection, which can interfere with playback tests.
32
+ player.configure('streaming.stallEnabled', false);
33
+
30
34
  eventManager = new shaka.util.EventManager();
31
35
  waiter = new shaka.test.Waiter(eventManager);
32
36
  });
@@ -101,7 +105,7 @@ describe('Player Src Equals', () => {
101
105
  expect(video.duration).not.toBeCloseTo(0);
102
106
 
103
107
  // Start playback and wait for the playhead to move.
104
- video.play();
108
+ await video.play();
105
109
  await waiter.waitForMovementOrFailOnTimeout(video, /* timeout= */10);
106
110
 
107
111
  // Make sure the playhead is roughly where we expect it to be before
@@ -138,7 +142,7 @@ describe('Player Src Equals', () => {
138
142
  await loadWithSrcEquals(SMALL_MP4_CONTENT_URI, /* startTime= */ null);
139
143
 
140
144
  // For playback to begin so that we have some content buffered.
141
- video.play();
145
+ await video.play();
142
146
  await waiter.waitForMovementOrFailOnTimeout(video, /* timeout= */10);
143
147
 
144
148
  const buffered = player.getBufferedInfo();
@@ -162,7 +166,7 @@ describe('Player Src Equals', () => {
162
166
  await loadWithSrcEquals(SMALL_MP4_CONTENT_URI, /* startTime= */ null);
163
167
 
164
168
  // Let playback run for a little.
165
- video.play();
169
+ await video.play();
166
170
  await waiter.waitForMovementOrFailOnTimeout(video, /* timeout= */10);
167
171
 
168
172
  let videoRateChange = false;
@@ -279,7 +283,7 @@ describe('Player Src Equals', () => {
279
283
  expect(video.currentTime).toBeCloseTo(0);
280
284
 
281
285
  // Start playback and wait. We should see the playhead move.
282
- video.play();
286
+ await video.play();
283
287
  await waiter.waitForMovementOrFailOnTimeout(video, /* timeout= */10);
284
288
  await shaka.test.Util.delay(1.5);
285
289
 
@@ -296,7 +300,7 @@ describe('Player Src Equals', () => {
296
300
 
297
301
  // Wait some time for playback to start so that we will have a load latency
298
302
  // value.
299
- video.play();
303
+ await video.play();
300
304
  await waiter.waitForMovementOrFailOnTimeout(video, /* timeout= */10);
301
305
 
302
306
  // Get the stats and check that some stats have been filled in.
@@ -12,9 +12,13 @@
12
12
  */
13
13
  shaka.test.FakeDemoMain = class {
14
14
  constructor() {
15
- this.video = /** @type {!HTMLVideoElement} */ (
16
- document.createElement('video'));
17
- this.player = new shaka.Player(this.video);
15
+ // Using the player's constructor argument to attach a video element seems
16
+ // to cause flaky timeouts on teardown. If a video element is needed in
17
+ // the future, please explicitly call attach(video) and await the result
18
+ // during the test setup.
19
+ /** @type {!shaka.Player} */
20
+ this.player = new shaka.Player();
21
+
18
22
  this.config_ = this.player.getConfiguration();
19
23
  this.selectedAsset = null;
20
24
 
@@ -395,7 +395,7 @@ shaka.test.NativeTextLayoutTests = class extends shaka.test.TextLayoutTests {
395
395
  // The this.video must be played a little now, after the cues were appended,
396
396
  // but before the screenshot.
397
397
  this.video.playbackRate = 1;
398
- this.video.play();
398
+ await this.video.play();
399
399
  await this.waiter.failOnTimeout(false).timeoutAfter(5)
400
400
  .waitForMovement(this.video);
401
401
  this.video.pause();
@@ -404,7 +404,7 @@ shaka.test.NativeTextLayoutTests = class extends shaka.test.TextLayoutTests {
404
404
  this.video.currentTime = time;
405
405
  // Get into a playing state, but without movement.
406
406
  this.video.playbackRate = 0;
407
- this.video.play();
407
+ await this.video.play();
408
408
 
409
409
  // Add a short delay to ensure that the system has caught up and that
410
410
  // native text displayers have been updated by the browser.
@@ -115,11 +115,18 @@ shaka.test.UiUtils = class {
115
115
  // Destroying the UI destroys the controls and player inside.
116
116
  destroys.push(ui.destroy());
117
117
  }
118
- await Promise.all(destroys);
118
+
119
+ const allDestroyed = Promise.all(destroys);
120
+ // 10 seconds should be more than enough to tear down the UI.
121
+ // Adding this silent timeout fixes several tests that inconsistently hang
122
+ // during teardown and cause failures in afterEach() clauses.
123
+ await Promise.race([allDestroyed, shaka.test.Util.delay(10)]);
119
124
 
120
125
  // Now remove all the containers from the DOM.
121
126
  for (const container of containers) {
122
- container.parentElement.removeChild(container);
127
+ if (container.parentElement) {
128
+ container.parentElement.removeChild(container);
129
+ }
123
130
  }
124
131
  }
125
132