shaka-player 4.3.7 → 4.3.9

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 (86) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +11 -0
  2. package/.github/workflows/appspot.yaml +39 -0
  3. package/.github/workflows/build-and-test.yaml +8 -0
  4. package/.github/workflows/selenium-lab-tests.yaml +3 -2
  5. package/.github/workflows/update-issues.yaml +1 -0
  6. package/CHANGELOG.md +44 -0
  7. package/CONTRIBUTORS +1 -0
  8. package/demo/custom.js +1 -1
  9. package/dist/demo.compiled.debug.js +2 -2
  10. package/dist/demo.compiled.debug.map +2 -2
  11. package/dist/demo.compiled.js +2 -2
  12. package/dist/demo.compiled.map +2 -2
  13. package/dist/deps.js +2 -2
  14. package/dist/locales.js +31 -31
  15. package/dist/shaka-player.compiled.d.ts +24 -2
  16. package/dist/shaka-player.compiled.debug.d.ts +24 -2
  17. package/dist/shaka-player.compiled.debug.js +251 -247
  18. package/dist/shaka-player.compiled.debug.map +3 -3
  19. package/dist/shaka-player.compiled.js +796 -793
  20. package/dist/shaka-player.compiled.map +4 -4
  21. package/dist/shaka-player.ui.d.ts +24 -2
  22. package/dist/shaka-player.ui.debug.d.ts +24 -2
  23. package/dist/shaka-player.ui.debug.js +289 -286
  24. package/dist/shaka-player.ui.debug.map +3 -3
  25. package/dist/shaka-player.ui.js +831 -827
  26. package/dist/shaka-player.ui.map +4 -4
  27. package/docs/tutorials/drm-config.md +9 -6
  28. package/docs/tutorials/selenium-grid-config.md +60 -8
  29. package/externs/ima.js +34 -0
  30. package/externs/shaka/manifest.js +5 -1
  31. package/externs/shaka/offline.js +5 -1
  32. package/karma.conf.js +50 -7
  33. package/lib/abr/simple_abr_manager.js +6 -6
  34. package/lib/cea/mp4_cea_parser.js +24 -18
  35. package/lib/dash/dash_parser.js +19 -3
  36. package/lib/hls/hls_parser.js +24 -4
  37. package/lib/media/drm_engine.js +14 -8
  38. package/lib/media/gap_jumping_controller.js +24 -2
  39. package/lib/media/media_source_engine.js +11 -8
  40. package/lib/media/playhead.js +11 -0
  41. package/lib/media/region_observer.js +19 -1
  42. package/lib/media/streaming_engine.js +41 -21
  43. package/lib/media/video_wrapper.js +6 -1
  44. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  45. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  46. package/lib/offline/manifest_converter.js +1 -0
  47. package/lib/offline/storage.js +1 -0
  48. package/lib/player.js +20 -9
  49. package/lib/polyfill/abort_controller.js +7 -0
  50. package/lib/polyfill/orientation.js +34 -7
  51. package/lib/text/vtt_text_parser.js +3 -1
  52. package/lib/util/manifest_parser_utils.js +5 -3
  53. package/lib/util/periods.js +2 -0
  54. package/lib/util/platform.js +14 -0
  55. package/lib/util/stream_utils.js +70 -26
  56. package/package.json +2 -2
  57. package/test/cast/cast_utils_unit.js +4 -1
  58. package/test/cea/mp4_cea_parser_unit.js +28 -5
  59. package/test/dash/dash_parser_manifest_unit.js +120 -0
  60. package/test/hls/hls_parser_unit.js +216 -0
  61. package/test/media/adaptation_set_unit.js +1 -0
  62. package/test/media/drm_engine_integration.js +2 -2
  63. package/test/media/media_source_engine_unit.js +1 -1
  64. package/test/media/region_observer_unit.js +2 -1
  65. package/test/media/segment_index_unit.js +3 -3
  66. package/test/media/streaming_engine_integration.js +14 -11
  67. package/test/media/streaming_engine_unit.js +26 -2
  68. package/test/offline/manifest_convert_unit.js +5 -0
  69. package/test/offline/offline_integration.js +6 -3
  70. package/test/player_external.js +19 -16
  71. package/test/player_integration.js +35 -48
  72. package/test/player_src_equals_integration.js +9 -5
  73. package/test/test/assets/multiple-trun-init.mp4 +0 -0
  74. package/test/test/assets/multiple-trun-segment.mp4 +0 -0
  75. package/test/test/util/fake_demo_main.js +7 -3
  76. package/test/test/util/layout_tests.js +2 -2
  77. package/test/test/util/manifest_generator.js +2 -0
  78. package/test/test/util/offline_utils.js +1 -0
  79. package/test/test/util/streaming_engine_util.js +3 -0
  80. package/test/test/util/ui_utils.js +9 -2
  81. package/test/test/util/util.js +6 -27
  82. package/test/test/util/waiter.js +73 -3
  83. package/test/ui/ad_ui_unit.js +9 -9
  84. package/test/util/stream_utils_unit.js +46 -0
  85. package/ui/range_element.js +5 -0
  86. package/ui/resolution_selection.js +7 -1
@@ -218,6 +218,7 @@ describe('AdaptationSet', () => {
218
218
  forced: false,
219
219
  trickModeVideo: null,
220
220
  type: '',
221
+ external: false,
221
222
  };
222
223
  }
223
224
  });
@@ -244,7 +244,7 @@ describe('DrmEngine', () => {
244
244
  /* hasClosedCaptions= */ false);
245
245
 
246
246
  expect(video.buffered.end(0)).toBeGreaterThan(0);
247
- video.play();
247
+ await video.play();
248
248
 
249
249
  const waiter = new shaka.test.Waiter(eventManager).timeoutAfter(15);
250
250
  waiter.setMediaSourceEngine(mediaSourceEngine);
@@ -327,7 +327,7 @@ describe('DrmEngine', () => {
327
327
  /* hasClosedCaptions= */ false);
328
328
 
329
329
  expect(video.buffered.end(0)).toBeGreaterThan(0);
330
- video.play();
330
+ await video.play();
331
331
 
332
332
  const waiter = new shaka.test.Waiter(eventManager).timeoutAfter(15);
333
333
  waiter.setMediaSourceEngine(mediaSourceEngine);
@@ -1262,7 +1262,7 @@ describe('MediaSourceEngine', () => {
1262
1262
  });
1263
1263
 
1264
1264
  it('destroys text engines', async () => {
1265
- mediaSourceEngine.reinitText('text/vtt', false);
1265
+ mediaSourceEngine.reinitText('text/vtt', false, false);
1266
1266
 
1267
1267
  await mediaSourceEngine.destroy();
1268
1268
  expect(mockTextEngine).toBeTruthy();
@@ -31,7 +31,8 @@ describe('RegionObserver', () => {
31
31
  timeline = new shaka.media.RegionTimeline(
32
32
  shaka.test.Util.spyFunc(onSeekRange));
33
33
 
34
- observer = new shaka.media.RegionObserver(timeline);
34
+ observer = new shaka.media.RegionObserver(
35
+ timeline, /* startsPastZero= */ false);
35
36
  observer.addEventListener('enter', (event) => {
36
37
  shaka.test.Util.spyFunc(onEnterRegion)(event['region'], event['seeking']);
37
38
  });
@@ -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');
@@ -279,7 +282,7 @@ describe('StreamingEngine', () => {
279
282
  // Let's go!
280
283
  streamingEngine.switchVariant(variant);
281
284
  await streamingEngine.start();
282
- video.play();
285
+ await video.play();
283
286
  // The overall test timeout is 120 seconds, and the content is 40
284
287
  // seconds. It should be possible to complete this test in 100 seconds,
285
288
  // and if not, we want the error thrown to be within the overall test's
@@ -299,7 +302,7 @@ describe('StreamingEngine', () => {
299
302
  // Let's go!
300
303
  streamingEngine.switchVariant(variant);
301
304
  await streamingEngine.start();
302
- video.play();
305
+ await video.play();
303
306
 
304
307
  // Wait for playback to begin before increasing the playback rate. This
305
308
  // improves test reliability on slow platforms like Chromecast.
@@ -313,7 +316,7 @@ describe('StreamingEngine', () => {
313
316
  // Let's go!
314
317
  streamingEngine.switchVariant(variant);
315
318
  await streamingEngine.start();
316
- video.play();
319
+ await video.play();
317
320
 
318
321
  // After 35 seconds seek back 10 seconds into the first Period.
319
322
  await waiter.timeoutAfter(80).waitUntilPlayheadReaches(video, 35);
@@ -325,7 +328,7 @@ describe('StreamingEngine', () => {
325
328
  // Let's go!
326
329
  streamingEngine.switchVariant(variant);
327
330
  await streamingEngine.start();
328
- video.play();
331
+ await video.play();
329
332
  await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 20);
330
333
  video.currentTime = 40;
331
334
  await waiter.timeoutAfter(60).waitForEnd(video);
@@ -353,7 +356,7 @@ describe('StreamingEngine', () => {
353
356
  streamingEngine.switchVariant(variant);
354
357
  await streamingEngine.start();
355
358
 
356
- video.play();
359
+ await video.play();
357
360
  await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 305);
358
361
 
359
362
  const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
@@ -373,7 +376,7 @@ describe('StreamingEngine', () => {
373
376
  // Seek outside the availability window right away. The playhead
374
377
  // should adjust the video's current time.
375
378
  video.currentTime = segmentAvailability.end + 120;
376
- video.play();
379
+ await video.play();
377
380
 
378
381
  // Wait until the repositioning is complete so we don't
379
382
  // immediately hit this case.
@@ -398,7 +401,7 @@ describe('StreamingEngine', () => {
398
401
  video.currentTime = segmentAvailability.start - 120;
399
402
  expect(video.currentTime).toBeGreaterThan(0);
400
403
 
401
- video.play();
404
+ await video.play();
402
405
  await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 305);
403
406
 
404
407
  // We are playing close to the beginning of the availability window.
@@ -426,7 +429,7 @@ describe('StreamingEngine', () => {
426
429
  // Let's go!
427
430
  streamingEngine.switchVariant(variant);
428
431
  await streamingEngine.start();
429
- video.play();
432
+ await video.play();
430
433
 
431
434
  await waiter.timeoutAfter(5).waitUntilPlayheadReaches(video, 0.01);
432
435
  expect(video.buffered.length).toBeGreaterThan(0);
@@ -441,7 +444,7 @@ describe('StreamingEngine', () => {
441
444
  // Let's go!
442
445
  streamingEngine.switchVariant(variant);
443
446
  await streamingEngine.start();
444
- video.play();
447
+ await video.play();
445
448
 
446
449
  await waiter.timeoutAfter(5).waitUntilPlayheadReaches(video, 0.01);
447
450
  expect(video.buffered.length).toBeGreaterThan(0);
@@ -460,7 +463,7 @@ describe('StreamingEngine', () => {
460
463
  await waiter.timeoutAfter(5).waitForEvent(video, 'loadeddata');
461
464
 
462
465
  video.currentTime = 8;
463
- video.play();
466
+ await video.play();
464
467
 
465
468
  await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 23);
466
469
  // Should be close enough to still have the gap buffered.
@@ -477,7 +480,7 @@ describe('StreamingEngine', () => {
477
480
  await waiter.timeoutAfter(5).waitForEvent(video, 'loadeddata');
478
481
 
479
482
  video.currentTime = 8;
480
- video.play();
483
+ await video.play();
481
484
 
482
485
  await waiter.timeoutAfter(60).waitUntilPlayheadReaches(video, 23);
483
486
  // Should be close enough to still have the gap buffered.
@@ -2913,10 +2913,14 @@ describe('StreamingEngine', () => {
2913
2913
  expect(onManifestUpdate).toHaveBeenCalled();
2914
2914
  });
2915
2915
 
2916
- it('triggers metadata event', async () => {
2916
+ it('triggers both emsg event and metadata event for ID3', async () => {
2917
2917
  setSegment0(emsgSegmentV0ID3);
2918
2918
  videoStream.emsgSchemeIdUris = [id3SchemeUri];
2919
2919
 
2920
+ onEvent.and.callFake((emsgEvent) => {
2921
+ expect(emsgEvent.type).toBe('emsg');
2922
+ });
2923
+
2920
2924
  // Here we go!
2921
2925
  streamingEngine.switchVariant(variant);
2922
2926
  streamingEngine.switchTextStream(textStream);
@@ -2924,10 +2928,30 @@ describe('StreamingEngine', () => {
2924
2928
  playing = true;
2925
2929
  await runTest();
2926
2930
 
2927
- expect(onEvent).not.toHaveBeenCalled();
2931
+ expect(onEvent).toHaveBeenCalled();
2928
2932
  expect(onMetadata).toHaveBeenCalled();
2929
2933
  });
2930
2934
 
2935
+ it('only triggers emsg event for ID3 if event canceled', async () => {
2936
+ setSegment0(emsgSegmentV0ID3);
2937
+ videoStream.emsgSchemeIdUris = [id3SchemeUri];
2938
+
2939
+ onEvent.and.callFake((emsgEvent) => {
2940
+ expect(emsgEvent.type).toBe('emsg');
2941
+ emsgEvent.preventDefault();
2942
+ });
2943
+
2944
+ // Here we go!
2945
+ streamingEngine.switchVariant(variant);
2946
+ streamingEngine.switchTextStream(textStream);
2947
+ await streamingEngine.start();
2948
+ playing = true;
2949
+ await runTest();
2950
+
2951
+ expect(onEvent).toHaveBeenCalled();
2952
+ expect(onMetadata).not.toHaveBeenCalled();
2953
+ });
2954
+
2931
2955
  it('event start matches presentation time', async () => {
2932
2956
  // This box has a non-zero event time, which doesn't matter.
2933
2957
  setSegment0(emsgSegmentV1NonZeroStart);
@@ -316,6 +316,7 @@ describe('ManifestConverter', () => {
316
316
  audioSamplingRate: null,
317
317
  spatialAudio: false,
318
318
  closedCaptions: null,
319
+ external: false,
319
320
  };
320
321
 
321
322
  return streamDB;
@@ -389,6 +390,7 @@ describe('ManifestConverter', () => {
389
390
  spatialAudio: false,
390
391
  closedCaptions: null,
391
392
  tilesLayout: undefined,
393
+ external: false,
392
394
  };
393
395
  }
394
396
 
@@ -438,6 +440,7 @@ describe('ManifestConverter', () => {
438
440
  spatialAudio: false,
439
441
  closedCaptions: null,
440
442
  tilesLayout: undefined,
443
+ external: false,
441
444
  };
442
445
  }
443
446
 
@@ -486,6 +489,7 @@ describe('ManifestConverter', () => {
486
489
  spatialAudio: false,
487
490
  closedCaptions: null,
488
491
  tilesLayout: undefined,
492
+ external: false,
489
493
  };
490
494
  }
491
495
 
@@ -531,6 +535,7 @@ describe('ManifestConverter', () => {
531
535
  spatialAudio: streamDb.spatialAudio,
532
536
  closedCaptions: streamDb.closedCaptions,
533
537
  tilesLayout: streamDb.tilesLayout,
538
+ external: streamDb.external,
534
539
  };
535
540
 
536
541
  expect(stream).toEqual(expectedStream);
@@ -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
@@ -249,7 +256,7 @@ describe('Player', () => {
249
256
  await player.load('test:sintel_realistic_compiled');
250
257
 
251
258
  // Play until a time at which the external cues would be on screen.
252
- video.play();
259
+ await video.play();
253
260
  await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 4, 20);
254
261
 
255
262
  expect(player.isTextTrackVisible()).toBe(true);
@@ -281,7 +288,7 @@ describe('Player', () => {
281
288
  await waiter.waitForEvent(player, 'texttrackvisibility');
282
289
 
283
290
  // Play until a time at which the external cues would be on screen.
284
- video.play();
291
+ await video.play();
285
292
  await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 4, 20);
286
293
 
287
294
  expect(player.isTextTrackVisible()).toBe(true);
@@ -352,7 +359,7 @@ describe('Player', () => {
352
359
  player.setTextTrackVisibility(true);
353
360
  player.selectTextLanguage('fr');
354
361
  video.currentTime = 5;
355
- video.play();
362
+ await video.play();
356
363
  await waiter.waitForMovementOrFailOnTimeout(video, 10);
357
364
 
358
365
  expect(video.textTracks[0].activeCues.length).toBe(1);
@@ -544,7 +551,7 @@ describe('Player', () => {
544
551
 
545
552
  it('at higher playback rates', async () => {
546
553
  await player.load('test:sintel_compiled');
547
- video.play();
554
+ await video.play();
548
555
  await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 1, 10);
549
556
 
550
557
  // Enabling trick play should change our playback rate to the same rate.
@@ -560,14 +567,12 @@ describe('Player', () => {
560
567
  });
561
568
 
562
569
  it('in sequence mode', async () => {
563
- const testSchemeMimeType = 'application/x-test-manifest';
564
- player = new compiledShaka.Player(video);
565
- await player.load('test:sintel_sequence_compiled', 0, testSchemeMimeType);
570
+ await player.load('test:sintel_sequence_compiled');
566
571
  expect(player.getManifest().sequenceMode).toBe(true);
567
572
 
568
573
  // Ensure the video plays.
569
- video.play();
570
- await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 5, 10);
574
+ await video.play();
575
+ await waiter.timeoutAfter(20).waitUntilPlayheadReaches(video, 5);
571
576
 
572
577
  // Seek the video, and see if it can continue playing from that point.
573
578
  video.currentTime = 20;
@@ -586,9 +591,8 @@ describe('Player', () => {
586
591
  // even if one is not specified in load().
587
592
  it('immediately after construction with MIME type', async () => {
588
593
  const testSchemeMimeType = 'application/x-test-manifest';
589
- player = new compiledShaka.Player(video);
590
594
  await player.load('test:sintel_compiled', 0, testSchemeMimeType);
591
- video.play();
595
+ await video.play();
592
596
  await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 1, 10);
593
597
  });
594
598
 
@@ -627,7 +631,7 @@ describe('Player', () => {
627
631
  // Regression test for https://github.com/shaka-project/shaka-player/issues/1187
628
632
  it('does not throw on destroy', async () => {
629
633
  await player.load('test:sintel_compiled');
630
- video.play();
634
+ await video.play();
631
635
  await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 1, 10);
632
636
  await player.unload();
633
637
  // Before we fixed #1187, the call to destroy() on textDisplayer was
@@ -873,7 +877,7 @@ describe('Player', () => {
873
877
  player.configure('streaming.observeQualityChanges', true);
874
878
 
875
879
  await player.load('test:sintel_compiled');
876
- video.play();
880
+ await video.play();
877
881
 
878
882
  // Wait for the video to start playback. If it takes longer than 10
879
883
  // seconds, fail the test.
@@ -887,7 +891,7 @@ describe('Player', () => {
887
891
  player.configure('streaming.observeQualityChanges', false);
888
892
 
889
893
  await player.load('test:sintel_compiled');
890
- video.play();
894
+ await video.play();
891
895
 
892
896
  // Wait for the video to start playback. If it takes longer than 10
893
897
  // seconds, fail the test.
@@ -916,7 +920,7 @@ describe('Player', () => {
916
920
 
917
921
  // Play the stream.
918
922
  await player.load('/base/test/test/assets/3675/dash_0.mpd');
919
- video.play();
923
+ await video.play();
920
924
 
921
925
  // Wait for the stream to be over.
922
926
  eventManager.listen(player, 'error', Util.spyFunc(onErrorSpy));
@@ -1004,22 +1008,22 @@ describe('Player', () => {
1004
1008
 
1005
1009
  await player.load('test:sintel_long_compiled');
1006
1010
  video.pause();
1007
- await waitUntilBuffered(10);
1011
+ await waiter.waitUntilBuffered(video, 10);
1008
1012
 
1009
1013
  player.configure('streaming.bufferingGoal', 30);
1010
- await waitUntilBuffered(30);
1014
+ await waiter.waitUntilBuffered(video, 30);
1011
1015
 
1012
1016
  player.configure('streaming.bufferingGoal', 60);
1013
- await waitUntilBuffered(60);
1014
- await Util.delay(0.2);
1017
+ await waiter.waitUntilBuffered(video, 60);
1018
+ await Util.delay(1);
1015
1019
  expect(getBufferedAhead()).toBeLessThan(70); // 60 + segment_size
1016
1020
 
1017
1021
  // We don't remove buffered content ahead of the playhead, so seek to
1018
1022
  // clear the buffer.
1019
1023
  player.configure('streaming.bufferingGoal', 10);
1020
1024
  video.currentTime = 120;
1021
- await waitUntilBuffered(10);
1022
- await Util.delay(0.2);
1025
+ await waiter.waitUntilBuffered(video, 10);
1026
+ await Util.delay(1);
1023
1027
  expect(getBufferedAhead()).toBeLessThan(20); // 10 + segment_size
1024
1028
  });
1025
1029
 
@@ -1029,20 +1033,22 @@ describe('Player', () => {
1029
1033
 
1030
1034
  await player.load('test:sintel_long_compiled');
1031
1035
  video.pause();
1032
- await waitUntilBuffered(30);
1036
+ await waiter.waitUntilBuffered(video, 30);
1033
1037
  video.currentTime = 20;
1034
- await waitUntilBuffered(30);
1038
+ await waiter.waitUntilBuffered(video, 30);
1035
1039
 
1036
1040
  expect(getBufferedBehind()).toBe(20); // Buffered to start still.
1037
1041
  video.currentTime = 50;
1038
- await waitUntilBuffered(30);
1042
+ await waiter.waitUntilBuffered(video, 30);
1043
+ await Util.delay(1);
1039
1044
  expect(getBufferedBehind()).toBeLessThan(40); // 30 + segment_size
1040
1045
 
1041
1046
  player.configure('streaming.bufferBehind', 10);
1042
1047
  // We only evict content when we append a segment, so increase the
1043
1048
  // buffering goal so we append another segment.
1044
1049
  player.configure('streaming.bufferingGoal', 40);
1045
- await waitUntilBuffered(40);
1050
+ await waiter.waitUntilBuffered(video, 40);
1051
+ await Util.delay(1);
1046
1052
  expect(getBufferedBehind()).toBeLessThanOrEqual(10);
1047
1053
  });
1048
1054
 
@@ -1061,25 +1067,6 @@ describe('Player', () => {
1061
1067
  }
1062
1068
  return video.currentTime - start;
1063
1069
  }
1064
-
1065
- async function waitUntilBuffered(amount) {
1066
- for (let i = 0; i < 50; i++) {
1067
- // We buffer from an internal segment, so this shouldn't take long to
1068
- // buffer.
1069
- await Util.delay(0.1); // eslint-disable-line no-await-in-loop
1070
- if (getBufferedAhead() >= amount) {
1071
- return;
1072
- }
1073
- }
1074
-
1075
- const ranges =
1076
- shaka.media.TimeRangesUtils.getBufferedInfo(video.buffered);
1077
- const currentTime = video.currentTime;
1078
- const target = currentTime + amount;
1079
-
1080
- throw new Error('Timeout waiting to buffer! ' +
1081
- JSON.stringify({ranges, currentTime, target}));
1082
- }
1083
1070
  }); // describe('buffering')
1084
1071
 
1085
1072
  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