shaka-player 4.3.8 → 4.3.10
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.
- package/.github/ISSUE_TEMPLATE/bug_report.md +11 -0
- package/.github/workflows/build-and-test.yaml +15 -14
- package/.github/workflows/compute-incremental-coverage.py +3 -0
- package/.github/workflows/selenium-lab-tests.yaml +48 -12
- package/.github/workflows/update-issues.yaml +1 -0
- package/CHANGELOG.md +29 -0
- package/demo/common/assets.js +59 -25
- package/demo/main.js +5 -0
- package/dist/demo.compiled.debug.js +15 -13
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +15 -13
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +1 -1
- package/dist/locales.js +33 -33
- package/dist/receiver.compiled.debug.js +13 -11
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +13 -11
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +2 -2
- package/dist/shaka-player.compiled.debug.d.ts +2 -2
- package/dist/shaka-player.compiled.debug.js +56 -53
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +418 -418
- package/dist/shaka-player.compiled.map +2 -2
- package/dist/shaka-player.ui.d.ts +2 -2
- package/dist/shaka-player.ui.debug.d.ts +2 -2
- package/dist/shaka-player.ui.debug.js +66 -62
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +442 -441
- package/dist/shaka-player.ui.map +3 -3
- package/docs/tutorials/selenium-grid-config.md +60 -8
- package/externs/shaka/manifest.js +5 -1
- package/externs/shaka/offline.js +5 -1
- package/karma.conf.js +52 -7
- package/lib/abr/simple_abr_manager.js +5 -5
- package/lib/ads/client_side_ad_manager.js +14 -2
- package/lib/dash/dash_parser.js +1 -0
- package/lib/hls/hls_parser.js +1 -0
- package/lib/media/media_source_engine.js +6 -5
- package/lib/media/streaming_engine.js +2 -2
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/manifest_converter.js +1 -0
- package/lib/offline/storage.js +1 -0
- package/lib/player.js +9 -5
- package/lib/polyfill/orientation.js +34 -7
- package/lib/text/vtt_text_parser.js +1 -0
- package/lib/util/manifest_parser_utils.js +4 -2
- package/lib/util/periods.js +2 -0
- package/lib/util/platform.js +22 -0
- package/lib/util/stream_utils.js +69 -26
- package/package.json +3 -3
- package/test/cast/cast_utils_unit.js +4 -1
- package/test/hls/hls_parser_unit.js +72 -0
- package/test/media/adaptation_set_unit.js +1 -0
- package/test/media/drm_engine_integration.js +2 -2
- package/test/media/media_source_engine_unit.js +1 -1
- package/test/media/segment_index_unit.js +3 -3
- package/test/media/streaming_engine_integration.js +14 -11
- package/test/offline/manifest_convert_unit.js +5 -0
- package/test/offline/offline_integration.js +6 -3
- package/test/player_external.js +19 -16
- package/test/player_integration.js +39 -49
- package/test/player_src_equals_integration.js +9 -5
- package/test/test/util/fake_demo_main.js +7 -3
- package/test/test/util/layout_tests.js +2 -2
- package/test/test/util/manifest_generator.js +2 -0
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/streaming_engine_util.js +3 -0
- package/test/test/util/ui_utils.js +14 -3
- package/test/test/util/util.js +6 -27
- package/test/test/util/waiter.js +73 -3
- package/test/ui/ad_ui_unit.js +9 -9
- package/test/util/stream_utils_unit.js +46 -0
- package/ui/externs/ui.js +2 -2
- package/ui/range_element.js +5 -0
- package/ui/seek_bar.js +7 -1
|
@@ -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,17 +567,18 @@ describe('Player', () => {
|
|
|
560
567
|
});
|
|
561
568
|
|
|
562
569
|
it('in sequence mode', async () => {
|
|
563
|
-
|
|
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.
|
|
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
|
+
// If this is a multiple of 10, it tends to flake on Tizen with stall
|
|
579
|
+
// detection disabled. So use 25.
|
|
580
|
+
video.currentTime = 25;
|
|
581
|
+
|
|
574
582
|
// Expect that we can then reach the end of the video.
|
|
575
583
|
await waiter.timeoutAfter(40).waitForEnd(video);
|
|
576
584
|
});
|
|
@@ -586,9 +594,8 @@ describe('Player', () => {
|
|
|
586
594
|
// even if one is not specified in load().
|
|
587
595
|
it('immediately after construction with MIME type', async () => {
|
|
588
596
|
const testSchemeMimeType = 'application/x-test-manifest';
|
|
589
|
-
player = new compiledShaka.Player(video);
|
|
590
597
|
await player.load('test:sintel_compiled', 0, testSchemeMimeType);
|
|
591
|
-
video.play();
|
|
598
|
+
await video.play();
|
|
592
599
|
await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 1, 10);
|
|
593
600
|
});
|
|
594
601
|
|
|
@@ -627,7 +634,7 @@ describe('Player', () => {
|
|
|
627
634
|
// Regression test for https://github.com/shaka-project/shaka-player/issues/1187
|
|
628
635
|
it('does not throw on destroy', async () => {
|
|
629
636
|
await player.load('test:sintel_compiled');
|
|
630
|
-
video.play();
|
|
637
|
+
await video.play();
|
|
631
638
|
await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 1, 10);
|
|
632
639
|
await player.unload();
|
|
633
640
|
// Before we fixed #1187, the call to destroy() on textDisplayer was
|
|
@@ -873,7 +880,7 @@ describe('Player', () => {
|
|
|
873
880
|
player.configure('streaming.observeQualityChanges', true);
|
|
874
881
|
|
|
875
882
|
await player.load('test:sintel_compiled');
|
|
876
|
-
video.play();
|
|
883
|
+
await video.play();
|
|
877
884
|
|
|
878
885
|
// Wait for the video to start playback. If it takes longer than 10
|
|
879
886
|
// seconds, fail the test.
|
|
@@ -887,7 +894,7 @@ describe('Player', () => {
|
|
|
887
894
|
player.configure('streaming.observeQualityChanges', false);
|
|
888
895
|
|
|
889
896
|
await player.load('test:sintel_compiled');
|
|
890
|
-
video.play();
|
|
897
|
+
await video.play();
|
|
891
898
|
|
|
892
899
|
// Wait for the video to start playback. If it takes longer than 10
|
|
893
900
|
// seconds, fail the test.
|
|
@@ -916,7 +923,7 @@ describe('Player', () => {
|
|
|
916
923
|
|
|
917
924
|
// Play the stream.
|
|
918
925
|
await player.load('/base/test/test/assets/3675/dash_0.mpd');
|
|
919
|
-
video.play();
|
|
926
|
+
await video.play();
|
|
920
927
|
|
|
921
928
|
// Wait for the stream to be over.
|
|
922
929
|
eventManager.listen(player, 'error', Util.spyFunc(onErrorSpy));
|
|
@@ -1004,22 +1011,22 @@ describe('Player', () => {
|
|
|
1004
1011
|
|
|
1005
1012
|
await player.load('test:sintel_long_compiled');
|
|
1006
1013
|
video.pause();
|
|
1007
|
-
await waitUntilBuffered(10);
|
|
1014
|
+
await waiter.waitUntilBuffered(video, 10);
|
|
1008
1015
|
|
|
1009
1016
|
player.configure('streaming.bufferingGoal', 30);
|
|
1010
|
-
await waitUntilBuffered(30);
|
|
1017
|
+
await waiter.waitUntilBuffered(video, 30);
|
|
1011
1018
|
|
|
1012
1019
|
player.configure('streaming.bufferingGoal', 60);
|
|
1013
|
-
await waitUntilBuffered(60);
|
|
1014
|
-
await Util.delay(
|
|
1020
|
+
await waiter.waitUntilBuffered(video, 60);
|
|
1021
|
+
await Util.delay(1);
|
|
1015
1022
|
expect(getBufferedAhead()).toBeLessThan(70); // 60 + segment_size
|
|
1016
1023
|
|
|
1017
1024
|
// We don't remove buffered content ahead of the playhead, so seek to
|
|
1018
1025
|
// clear the buffer.
|
|
1019
1026
|
player.configure('streaming.bufferingGoal', 10);
|
|
1020
1027
|
video.currentTime = 120;
|
|
1021
|
-
await waitUntilBuffered(10);
|
|
1022
|
-
await Util.delay(
|
|
1028
|
+
await waiter.waitUntilBuffered(video, 10);
|
|
1029
|
+
await Util.delay(1);
|
|
1023
1030
|
expect(getBufferedAhead()).toBeLessThan(20); // 10 + segment_size
|
|
1024
1031
|
});
|
|
1025
1032
|
|
|
@@ -1029,20 +1036,22 @@ describe('Player', () => {
|
|
|
1029
1036
|
|
|
1030
1037
|
await player.load('test:sintel_long_compiled');
|
|
1031
1038
|
video.pause();
|
|
1032
|
-
await waitUntilBuffered(30);
|
|
1039
|
+
await waiter.waitUntilBuffered(video, 30);
|
|
1033
1040
|
video.currentTime = 20;
|
|
1034
|
-
await waitUntilBuffered(30);
|
|
1041
|
+
await waiter.waitUntilBuffered(video, 30);
|
|
1035
1042
|
|
|
1036
1043
|
expect(getBufferedBehind()).toBe(20); // Buffered to start still.
|
|
1037
1044
|
video.currentTime = 50;
|
|
1038
|
-
await waitUntilBuffered(30);
|
|
1045
|
+
await waiter.waitUntilBuffered(video, 30);
|
|
1046
|
+
await Util.delay(1);
|
|
1039
1047
|
expect(getBufferedBehind()).toBeLessThan(40); // 30 + segment_size
|
|
1040
1048
|
|
|
1041
1049
|
player.configure('streaming.bufferBehind', 10);
|
|
1042
1050
|
// We only evict content when we append a segment, so increase the
|
|
1043
1051
|
// buffering goal so we append another segment.
|
|
1044
1052
|
player.configure('streaming.bufferingGoal', 40);
|
|
1045
|
-
await waitUntilBuffered(40);
|
|
1053
|
+
await waiter.waitUntilBuffered(video, 40);
|
|
1054
|
+
await Util.delay(1);
|
|
1046
1055
|
expect(getBufferedBehind()).toBeLessThanOrEqual(10);
|
|
1047
1056
|
});
|
|
1048
1057
|
|
|
@@ -1061,25 +1070,6 @@ describe('Player', () => {
|
|
|
1061
1070
|
}
|
|
1062
1071
|
return video.currentTime - start;
|
|
1063
1072
|
}
|
|
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
1073
|
}); // describe('buffering')
|
|
1084
1074
|
|
|
1085
1075
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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.
|
|
@@ -410,6 +410,7 @@ shaka.test.StreamingEngineUtil = class {
|
|
|
410
410
|
roles: [],
|
|
411
411
|
forced: false,
|
|
412
412
|
spatialAudio: false,
|
|
413
|
+
external: false,
|
|
413
414
|
};
|
|
414
415
|
}
|
|
415
416
|
|
|
@@ -447,6 +448,7 @@ shaka.test.StreamingEngineUtil = class {
|
|
|
447
448
|
roles: [],
|
|
448
449
|
forced: false,
|
|
449
450
|
spatialAudio: false,
|
|
451
|
+
external: false,
|
|
450
452
|
};
|
|
451
453
|
}
|
|
452
454
|
|
|
@@ -482,6 +484,7 @@ shaka.test.StreamingEngineUtil = class {
|
|
|
482
484
|
roles: [],
|
|
483
485
|
forced: false,
|
|
484
486
|
spatialAudio: false,
|
|
487
|
+
external: false,
|
|
485
488
|
};
|
|
486
489
|
}
|
|
487
490
|
};
|
|
@@ -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
|
-
|
|
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
|
|
127
|
+
if (container.parentElement) {
|
|
128
|
+
container.parentElement.removeChild(container);
|
|
129
|
+
}
|
|
123
130
|
}
|
|
124
131
|
}
|
|
125
132
|
|
|
@@ -162,7 +169,11 @@ shaka.test.UiUtils = class {
|
|
|
162
169
|
const video = /** @type {!HTMLVideoElement} */(document.createElement(
|
|
163
170
|
'video'));
|
|
164
171
|
|
|
165
|
-
|
|
172
|
+
// Tizen has issues with audio-only playbacks on muted video elements.
|
|
173
|
+
// Don't mute Tizen.
|
|
174
|
+
if (!shaka.util.Platform.isTizen()) {
|
|
175
|
+
video.muted = true;
|
|
176
|
+
}
|
|
166
177
|
video.width = 600;
|
|
167
178
|
video.height = 400;
|
|
168
179
|
|
package/test/test/util/util.js
CHANGED
|
@@ -255,33 +255,12 @@ shaka.test.Util = class {
|
|
|
255
255
|
* @param {string} uri
|
|
256
256
|
* @return {!Promise.<!ArrayBuffer>}
|
|
257
257
|
*/
|
|
258
|
-
static fetch(uri) {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
xhr.onload = (event) => {
|
|
265
|
-
if (xhr.status >= 200 &&
|
|
266
|
-
xhr.status <= 299 &&
|
|
267
|
-
!!xhr.response) {
|
|
268
|
-
resolve(/** @type {!ArrayBuffer} */(xhr.response));
|
|
269
|
-
} else {
|
|
270
|
-
let message = '';
|
|
271
|
-
if (xhr.response) {
|
|
272
|
-
message = ': ' + shaka.util.StringUtils.fromUTF8(
|
|
273
|
-
/** @type {!ArrayBuffer} */(xhr.response));
|
|
274
|
-
}
|
|
275
|
-
reject(xhr.status + message);
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
xhr.onerror = (event) => {
|
|
280
|
-
reject('shaka.test.Util.fetch failed: ' + uri);
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
xhr.send(/* body= */ null);
|
|
284
|
-
}));
|
|
258
|
+
static async fetch(uri) {
|
|
259
|
+
const response = await fetch(uri);
|
|
260
|
+
if (!response.ok) {
|
|
261
|
+
throw new Error('shaka.test.Util.fetch failed: ' + uri);
|
|
262
|
+
}
|
|
263
|
+
return response.arrayBuffer();
|
|
285
264
|
}
|
|
286
265
|
|
|
287
266
|
/**
|
package/test/test/util/waiter.js
CHANGED
|
@@ -109,6 +109,8 @@ shaka.test.Waiter = class {
|
|
|
109
109
|
* @return {!Promise}
|
|
110
110
|
*/
|
|
111
111
|
waitUntilPlayheadReaches(mediaElement, timeGoal) {
|
|
112
|
+
this.macPlaybackWorkaround_(mediaElement);
|
|
113
|
+
|
|
112
114
|
// The name of what we're waiting for
|
|
113
115
|
const goalName = 'movement from ' + mediaElement.currentTime +
|
|
114
116
|
' to ' + timeGoal;
|
|
@@ -153,6 +155,8 @@ shaka.test.Waiter = class {
|
|
|
153
155
|
* @return {!Promise}
|
|
154
156
|
*/
|
|
155
157
|
waitForEnd(mediaElement) {
|
|
158
|
+
this.macPlaybackWorkaround_(mediaElement);
|
|
159
|
+
|
|
156
160
|
// The name of what we're waiting for.
|
|
157
161
|
const goalName = 'end of media';
|
|
158
162
|
|
|
@@ -207,13 +211,64 @@ shaka.test.Waiter = class {
|
|
|
207
211
|
* Wait for the video to end or for |timeout| seconds to pass, whichever
|
|
208
212
|
* occurs first. The Promise is resolved when either of these happens.
|
|
209
213
|
*
|
|
210
|
-
* @param {!HTMLMediaElement}
|
|
214
|
+
* @param {!HTMLMediaElement} mediaElement
|
|
211
215
|
* @param {number} timeout in seconds, after which the Promise succeeds
|
|
212
216
|
* @return {!Promise}
|
|
213
217
|
*/
|
|
214
|
-
waitForEndOrTimeout(
|
|
218
|
+
waitForEndOrTimeout(mediaElement, timeout) {
|
|
215
219
|
this.failOnTimeout(false).timeoutAfter(timeout);
|
|
216
|
-
return this.waitForEnd(
|
|
220
|
+
return this.waitForEnd(mediaElement);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Wait until a certain amount of content is buffered.
|
|
225
|
+
*
|
|
226
|
+
* @param {!HTMLMediaElement} mediaElement
|
|
227
|
+
* @param {number} bufferingGoal in seconds, after which the Promise succeeds
|
|
228
|
+
* @return {!Promise}
|
|
229
|
+
*/
|
|
230
|
+
waitUntilBuffered(mediaElement, bufferingGoal) {
|
|
231
|
+
// The name of what we're waiting for.
|
|
232
|
+
const goalName = `${bufferingGoal} seconds buffered`;
|
|
233
|
+
|
|
234
|
+
// The conditions for success.
|
|
235
|
+
const bufferedEnough = () => {
|
|
236
|
+
const end = shaka.media.TimeRangesUtils.bufferEnd(mediaElement.buffered);
|
|
237
|
+
if (end == null) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
return end - mediaElement.currentTime >= bufferingGoal;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
if (bufferedEnough()) {
|
|
244
|
+
return Promise.resolve();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Cleanup on timeout.
|
|
248
|
+
let timer = null;
|
|
249
|
+
const cleanup = () => {
|
|
250
|
+
if (timer) {
|
|
251
|
+
timer.stop();
|
|
252
|
+
}
|
|
253
|
+
this.eventManager_.unlisten(mediaElement, 'timeupdate');
|
|
254
|
+
this.eventManager_.unlisten(mediaElement, 'ended');
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
const p = new Promise((resolve) => {
|
|
258
|
+
const check = () => {
|
|
259
|
+
if (bufferedEnough()) {
|
|
260
|
+
cleanup();
|
|
261
|
+
resolve();
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
timer = new shaka.util.Timer(check);
|
|
266
|
+
timer.tickEvery(/* seconds= */ 1);
|
|
267
|
+
this.eventManager_.listen(mediaElement, 'timeupdate', check);
|
|
268
|
+
this.eventManager_.listen(mediaElement, 'ended', check);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
return this.waitUntilGeneric_(goalName, p, cleanup, mediaElement);
|
|
217
272
|
}
|
|
218
273
|
|
|
219
274
|
/**
|
|
@@ -333,4 +388,19 @@ shaka.test.Waiter = class {
|
|
|
333
388
|
`buffered: ${JSON.stringify(buffered)}\n`;
|
|
334
389
|
shaka.log.error(error.message);
|
|
335
390
|
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* @param {!HTMLMediaElement} mediaElement
|
|
394
|
+
* @private
|
|
395
|
+
*/
|
|
396
|
+
macPlaybackWorkaround_(mediaElement) {
|
|
397
|
+
if (shaka.util.Platform.isMac()) {
|
|
398
|
+
// Work around bizarre playback slowdowns that only seem to occur with
|
|
399
|
+
// WebDriver and only on Mac. Increasing the playback rate allows tests
|
|
400
|
+
// to complete without timing out.
|
|
401
|
+
if (mediaElement.playbackRate == 1) {
|
|
402
|
+
mediaElement.playbackRate = 2;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
336
406
|
};
|
package/test/ui/ad_ui_unit.js
CHANGED
|
@@ -25,15 +25,6 @@ describe('Ad UI', () => {
|
|
|
25
25
|
shaka.Player.setAdManagerFactory(() => new shaka.test.FakeAdManager());
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
afterEach(async () => {
|
|
29
|
-
await UiUtils.cleanupUI();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
afterAll(() => {
|
|
33
|
-
document.head.removeChild(cssLink);
|
|
34
|
-
shaka.Player.setAdManagerFactory(() => new shaka.ads.AdManager());
|
|
35
|
-
});
|
|
36
|
-
|
|
37
28
|
beforeEach(() => {
|
|
38
29
|
container =
|
|
39
30
|
/** @type {!HTMLElement} */ (document.createElement('div'));
|
|
@@ -45,6 +36,15 @@ describe('Ad UI', () => {
|
|
|
45
36
|
adManager = video['ui'].getControls().getPlayer().getAdManager();
|
|
46
37
|
});
|
|
47
38
|
|
|
39
|
+
afterEach(async () => {
|
|
40
|
+
await UiUtils.cleanupUI();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
afterAll(() => {
|
|
44
|
+
document.head.removeChild(cssLink);
|
|
45
|
+
shaka.Player.setAdManagerFactory(() => new shaka.ads.AdManager());
|
|
46
|
+
});
|
|
47
|
+
|
|
48
48
|
it('is invisible if no ad is playing', () => {
|
|
49
49
|
const adControlsContainer =
|
|
50
50
|
UiUtils.getElementByClassName(container, 'shaka-ad-controls');
|
|
@@ -718,6 +718,52 @@ describe('StreamUtils', () => {
|
|
|
718
718
|
expect(manifest.variants.length).toBe(1);
|
|
719
719
|
});
|
|
720
720
|
|
|
721
|
+
it('supports fLaC codec', async () => {
|
|
722
|
+
if (!MediaSource.isTypeSupported('audio/mp4; codecs="flac"')) {
|
|
723
|
+
pending('Codec fLaC is not supported by the platform.');
|
|
724
|
+
}
|
|
725
|
+
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
726
|
+
manifest.addVariant(0, (variant) => {
|
|
727
|
+
variant.addAudio(1, (stream) => {
|
|
728
|
+
stream.mime('audio/mp4', 'fLaC');
|
|
729
|
+
});
|
|
730
|
+
});
|
|
731
|
+
manifest.addVariant(2, (variant) => {
|
|
732
|
+
variant.addAudio(3, (stream) => {
|
|
733
|
+
stream.mime('audio/mp4', 'flac');
|
|
734
|
+
});
|
|
735
|
+
});
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
await shaka.util.StreamUtils.filterManifest(
|
|
739
|
+
fakeDrmEngine, /* currentVariant= */ null, manifest);
|
|
740
|
+
|
|
741
|
+
expect(manifest.variants.length).toBe(2);
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
it('supports Opus codec', async () => {
|
|
745
|
+
if (!MediaSource.isTypeSupported('audio/mp4; codecs="opus"')) {
|
|
746
|
+
pending('Codec Opus is not supported by the platform.');
|
|
747
|
+
}
|
|
748
|
+
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
749
|
+
manifest.addVariant(0, (variant) => {
|
|
750
|
+
variant.addAudio(1, (stream) => {
|
|
751
|
+
stream.mime('audio/mp4', 'Opus');
|
|
752
|
+
});
|
|
753
|
+
});
|
|
754
|
+
manifest.addVariant(2, (variant) => {
|
|
755
|
+
variant.addAudio(3, (stream) => {
|
|
756
|
+
stream.mime('audio/mp4', 'opus');
|
|
757
|
+
});
|
|
758
|
+
});
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
await shaka.util.StreamUtils.filterManifest(
|
|
762
|
+
fakeDrmEngine, /* currentVariant= */ null, manifest);
|
|
763
|
+
|
|
764
|
+
expect(manifest.variants.length).toBe(2);
|
|
765
|
+
});
|
|
766
|
+
|
|
721
767
|
it('supports legacy AVC1 codec', async () => {
|
|
722
768
|
if (!MediaSource.isTypeSupported('video/mp4; codecs="avc1.42001e"')) {
|
|
723
769
|
pending('Codec avc1.42001e is not supported by the platform.');
|
package/ui/externs/ui.js
CHANGED
|
@@ -147,8 +147,8 @@ shaka.extern.UIVolumeBarColors;
|
|
|
147
147
|
* ROLE means that only the role of the item is shown.
|
|
148
148
|
* LANGUAGE_ROLE means both language and role are shown, or just language if
|
|
149
149
|
* there is no role.
|
|
150
|
-
* LABEL means the non-standard DASH "label" attribute or the
|
|
151
|
-
* attribute are shown.
|
|
150
|
+
* LABEL means the non-standard DASH "label" attribute or the standard DASH
|
|
151
|
+
* "Label" element or the HLS "NAME" attribute are shown.
|
|
152
152
|
* Defaults to LANGUAGE.
|
|
153
153
|
* @property {number} fadeDelay
|
|
154
154
|
* The delay (in seconds) before fading out the controls once the user stops
|
package/ui/range_element.js
CHANGED
|
@@ -110,6 +110,11 @@ shaka.ui.RangeElement = class extends shaka.ui.Element {
|
|
|
110
110
|
this.onChangeEnd();
|
|
111
111
|
}
|
|
112
112
|
});
|
|
113
|
+
|
|
114
|
+
this.eventManager.listen(this.bar, 'contextmenu', (e) => {
|
|
115
|
+
e.preventDefault();
|
|
116
|
+
e.stopPropagation();
|
|
117
|
+
});
|
|
113
118
|
}
|
|
114
119
|
|
|
115
120
|
/** @override */
|
package/ui/seek_bar.js
CHANGED
|
@@ -59,7 +59,13 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement {
|
|
|
59
59
|
* @private {shaka.util.Timer}
|
|
60
60
|
*/
|
|
61
61
|
this.seekTimer_ = new shaka.util.Timer(() => {
|
|
62
|
-
|
|
62
|
+
let newCurrentTime = this.getValue();
|
|
63
|
+
if (!this.player.isLive()) {
|
|
64
|
+
if (newCurrentTime == this.video.duration) {
|
|
65
|
+
newCurrentTime -= 0.001;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
this.video.currentTime = newCurrentTime;
|
|
63
69
|
});
|
|
64
70
|
|
|
65
71
|
|