shaka-player 4.2.3 → 4.2.4
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/AUTHORS +1 -0
- package/CHANGELOG.md +15 -0
- package/CONTRIBUTORS +1 -0
- package/dist/deps.js +2 -2
- package/dist/locales.js +26 -26
- package/dist/shaka-player.compiled.d.ts +5 -1
- package/dist/shaka-player.compiled.debug.d.ts +5 -1
- package/dist/shaka-player.compiled.debug.externs.js +2 -1
- package/dist/shaka-player.compiled.debug.js +83 -80
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +2 -1
- package/dist/shaka-player.compiled.js +565 -562
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +5 -1
- package/dist/shaka-player.ui.debug.d.ts +5 -1
- package/dist/shaka-player.ui.debug.externs.js +2 -1
- package/dist/shaka-player.ui.debug.js +99 -96
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +2 -1
- package/dist/shaka-player.ui.js +694 -691
- package/dist/shaka-player.ui.map +3 -3
- package/externs/mux.js +3 -0
- package/lib/cast/cast_proxy.js +2 -1
- package/lib/cast/cast_receiver.js +19 -5
- package/lib/cast/cast_sender.js +2 -1
- package/lib/cast/cast_utils.js +16 -6
- package/lib/hls/hls_parser.js +9 -2
- package/lib/media/media_source_engine.js +6 -0
- package/lib/media/playhead.js +23 -1
- package/lib/media/streaming_engine.js +3 -12
- package/lib/media/transmuxer.js +6 -0
- package/lib/player.js +24 -11
- package/lib/util/manifest_parser_utils.js +4 -0
- package/package.json +1 -1
- package/roadmap.md +24 -6
- package/test/cast/cast_receiver_integration.js +97 -16
- package/test/cast/cast_receiver_unit.js +17 -12
- package/test/cast/cast_utils_unit.js +1 -0
- package/test/media/media_source_engine_integration.js +31 -0
- package/test/media/playhead_unit.js +41 -0
- package/test/media/streaming_engine_integration.js +13 -0
- package/test/media/streaming_engine_unit.js +36 -23
- package/test/player_unit.js +87 -0
- package/test/test/util/simple_fakes.js +3 -0
- package/ui/controls.js +4 -1
- package/ui/settings_menu.js +11 -2
|
@@ -70,6 +70,18 @@ describe('MediaSourceEngine', () => {
|
|
|
70
70
|
type, segment, reference, /* hasClosedCaptions= */ false);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
function appendWithSeek(type, segmentNumber) {
|
|
74
|
+
const segment = generators[type]
|
|
75
|
+
.getSegment(segmentNumber, Date.now() / 1000);
|
|
76
|
+
const reference = dummyReference(type, segmentNumber);
|
|
77
|
+
return mediaSourceEngine.appendBuffer(
|
|
78
|
+
type,
|
|
79
|
+
segment,
|
|
80
|
+
reference,
|
|
81
|
+
/* hasClosedCaptions= */ false,
|
|
82
|
+
/* seeked= */ true);
|
|
83
|
+
}
|
|
84
|
+
|
|
73
85
|
function appendInitWithClosedCaptions(type) {
|
|
74
86
|
const segment = generators[type].getInitSegment(Date.now() / 1000);
|
|
75
87
|
const reference = null;
|
|
@@ -380,6 +392,25 @@ describe('MediaSourceEngine', () => {
|
|
|
380
392
|
expect(textDisplayer.appendSpy).toHaveBeenCalledTimes(3);
|
|
381
393
|
});
|
|
382
394
|
|
|
395
|
+
it('extracts CEA-708 captions from previous segment from hls', async () => {
|
|
396
|
+
// Load TS file with CEA-708 captions.
|
|
397
|
+
metadata = shaka.test.TestScheme.DATA['cea-708_ts'];
|
|
398
|
+
generators = shaka.test.TestScheme.GENERATORS['cea-708_ts'];
|
|
399
|
+
|
|
400
|
+
const initObject = new Map();
|
|
401
|
+
initObject.set(ContentType.VIDEO, getFakeStream(metadata.video));
|
|
402
|
+
initObject.set(ContentType.TEXT, getFakeStream(metadata.text));
|
|
403
|
+
// Call with forceTransmux = true, so that it will transmux even on
|
|
404
|
+
// platforms with native TS support.
|
|
405
|
+
await mediaSourceEngine.init(initObject, /* forceTransmux= */ true);
|
|
406
|
+
mediaSourceEngine.setSelectedClosedCaptionId('CC1');
|
|
407
|
+
|
|
408
|
+
await append(ContentType.VIDEO, 2);
|
|
409
|
+
await appendWithSeek(ContentType.VIDEO, 0);
|
|
410
|
+
|
|
411
|
+
expect(textDisplayer.appendSpy).toHaveBeenCalledTimes(6);
|
|
412
|
+
});
|
|
413
|
+
|
|
383
414
|
it('buffers partial TS video segments in sequence mode', async () => {
|
|
384
415
|
metadata = shaka.test.TestScheme.DATA['cea-708_ts'];
|
|
385
416
|
generators = shaka.test.TestScheme.GENERATORS['cea-708_ts'];
|
|
@@ -161,6 +161,8 @@ describe('Playhead', () => {
|
|
|
161
161
|
Util.spyFunc(onSeek),
|
|
162
162
|
Util.spyFunc(onEvent));
|
|
163
163
|
|
|
164
|
+
playhead.ready();
|
|
165
|
+
|
|
164
166
|
expect(video.currentTime).toBe(5);
|
|
165
167
|
expect(playhead.getTime()).toBe(5);
|
|
166
168
|
|
|
@@ -182,6 +184,8 @@ describe('Playhead', () => {
|
|
|
182
184
|
Util.spyFunc(onSeek),
|
|
183
185
|
Util.spyFunc(onEvent));
|
|
184
186
|
|
|
187
|
+
playhead.ready();
|
|
188
|
+
|
|
185
189
|
expect(video.addEventListener).toHaveBeenCalledWith(
|
|
186
190
|
'loadedmetadata', jasmine.any(Function), jasmine.anything());
|
|
187
191
|
expect(video.addEventListener).not.toHaveBeenCalledWith(
|
|
@@ -223,6 +227,8 @@ describe('Playhead', () => {
|
|
|
223
227
|
Util.spyFunc(onSeek),
|
|
224
228
|
Util.spyFunc(onEvent));
|
|
225
229
|
|
|
230
|
+
playhead.ready();
|
|
231
|
+
|
|
226
232
|
video.on['seeking']();
|
|
227
233
|
expect(playhead.getTime()).toBe(5);
|
|
228
234
|
expect(video.currentTime).toBe(5);
|
|
@@ -264,6 +270,8 @@ describe('Playhead', () => {
|
|
|
264
270
|
Util.spyFunc(onSeek),
|
|
265
271
|
Util.spyFunc(onEvent));
|
|
266
272
|
|
|
273
|
+
playhead.ready();
|
|
274
|
+
|
|
267
275
|
expect(playhead.getTime()).toBe(59); // duration - durationBackoff
|
|
268
276
|
expect(video.currentTime).toBe(59); // duration - durationBackoff
|
|
269
277
|
});
|
|
@@ -302,6 +310,8 @@ describe('Playhead', () => {
|
|
|
302
310
|
Util.spyFunc(onSeek),
|
|
303
311
|
Util.spyFunc(onEvent));
|
|
304
312
|
|
|
313
|
+
playhead.ready();
|
|
314
|
+
|
|
305
315
|
expect(playhead.getTime()).toBe(30);
|
|
306
316
|
});
|
|
307
317
|
|
|
@@ -314,6 +324,8 @@ describe('Playhead', () => {
|
|
|
314
324
|
Util.spyFunc(onSeek),
|
|
315
325
|
Util.spyFunc(onEvent));
|
|
316
326
|
|
|
327
|
+
playhead.ready();
|
|
328
|
+
|
|
317
329
|
expect(video.addEventListener).toHaveBeenCalledWith(
|
|
318
330
|
'loadedmetadata', jasmine.any(Function), jasmine.anything());
|
|
319
331
|
|
|
@@ -347,6 +359,8 @@ describe('Playhead', () => {
|
|
|
347
359
|
Util.spyFunc(onSeek),
|
|
348
360
|
Util.spyFunc(onEvent));
|
|
349
361
|
|
|
362
|
+
playhead.ready();
|
|
363
|
+
|
|
350
364
|
expect(video.addEventListener).toHaveBeenCalledWith(
|
|
351
365
|
'loadedmetadata', jasmine.any(Function), jasmine.anything());
|
|
352
366
|
|
|
@@ -380,6 +394,8 @@ describe('Playhead', () => {
|
|
|
380
394
|
Util.spyFunc(onSeek),
|
|
381
395
|
Util.spyFunc(onEvent));
|
|
382
396
|
|
|
397
|
+
playhead.ready();
|
|
398
|
+
|
|
383
399
|
// This has to periodically increment the mock date to allow the onSeeking_
|
|
384
400
|
// handler to seek, if appropriate.
|
|
385
401
|
|
|
@@ -652,6 +668,8 @@ describe('Playhead', () => {
|
|
|
652
668
|
expect(currentTime).toBe(1000);
|
|
653
669
|
seekCount = 0;
|
|
654
670
|
|
|
671
|
+
playhead.ready();
|
|
672
|
+
|
|
655
673
|
// The availability window slips ahead.
|
|
656
674
|
timeline.getSeekRangeStart.and.returnValue(1030);
|
|
657
675
|
timeline.getSeekRangeEnd.and.returnValue(1030);
|
|
@@ -696,6 +714,8 @@ describe('Playhead', () => {
|
|
|
696
714
|
Util.spyFunc(onSeek),
|
|
697
715
|
Util.spyFunc(onEvent));
|
|
698
716
|
|
|
717
|
+
playhead.ready();
|
|
718
|
+
|
|
699
719
|
video.on['seeking']();
|
|
700
720
|
expect(video.currentTime).toBe(5);
|
|
701
721
|
expect(playhead.getTime()).toBe(5);
|
|
@@ -728,6 +748,8 @@ describe('Playhead', () => {
|
|
|
728
748
|
Util.spyFunc(onSeek),
|
|
729
749
|
Util.spyFunc(onEvent));
|
|
730
750
|
|
|
751
|
+
playhead.ready();
|
|
752
|
+
|
|
731
753
|
video.on['seeking']();
|
|
732
754
|
expect(video.currentTime).toBe(5);
|
|
733
755
|
expect(playhead.getTime()).toBe(5);
|
|
@@ -765,6 +787,9 @@ describe('Playhead', () => {
|
|
|
765
787
|
|
|
766
788
|
video.currentTime = 0;
|
|
767
789
|
video.seeking = true;
|
|
790
|
+
|
|
791
|
+
playhead.ready();
|
|
792
|
+
|
|
768
793
|
// "video.seeking" stays true until the buffered range intersects with
|
|
769
794
|
// "video.currentTime". Playhead should correct anyway.
|
|
770
795
|
video.on['seeking']();
|
|
@@ -809,6 +834,8 @@ describe('Playhead', () => {
|
|
|
809
834
|
Util.spyFunc(onSeek),
|
|
810
835
|
Util.spyFunc(onEvent));
|
|
811
836
|
|
|
837
|
+
playhead.ready();
|
|
838
|
+
|
|
812
839
|
/**
|
|
813
840
|
* Prevent retries on the initial start time seek. This will ensure that
|
|
814
841
|
* only one call is made for the initial seek, and that any additional calls
|
|
@@ -933,6 +960,8 @@ describe('Playhead', () => {
|
|
|
933
960
|
Util.spyFunc(onSeek),
|
|
934
961
|
Util.spyFunc(onEvent));
|
|
935
962
|
|
|
963
|
+
playhead.ready();
|
|
964
|
+
|
|
936
965
|
jasmine.clock().tick(500);
|
|
937
966
|
for (let time = data.start; time < data.waitingAt; time++) {
|
|
938
967
|
// We don't want to run tick() for 1 second because it will trigger
|
|
@@ -1142,6 +1171,8 @@ describe('Playhead', () => {
|
|
|
1142
1171
|
Util.spyFunc(onSeek),
|
|
1143
1172
|
Util.spyFunc(onEvent));
|
|
1144
1173
|
|
|
1174
|
+
playhead.ready();
|
|
1175
|
+
|
|
1145
1176
|
jasmine.clock().tick(500);
|
|
1146
1177
|
expect(onEvent).not.toHaveBeenCalled();
|
|
1147
1178
|
|
|
@@ -1190,6 +1221,8 @@ describe('Playhead', () => {
|
|
|
1190
1221
|
Util.spyFunc(onSeek),
|
|
1191
1222
|
Util.spyFunc(onEvent));
|
|
1192
1223
|
|
|
1224
|
+
playhead.ready();
|
|
1225
|
+
|
|
1193
1226
|
playhead.notifyOfBufferingChange();
|
|
1194
1227
|
jasmine.clock().tick(500);
|
|
1195
1228
|
|
|
@@ -1212,6 +1245,8 @@ describe('Playhead', () => {
|
|
|
1212
1245
|
Util.spyFunc(onSeek),
|
|
1213
1246
|
Util.spyFunc(onEvent));
|
|
1214
1247
|
|
|
1248
|
+
playhead.ready();
|
|
1249
|
+
|
|
1215
1250
|
playhead.notifyOfBufferingChange();
|
|
1216
1251
|
jasmine.clock().tick(500);
|
|
1217
1252
|
|
|
@@ -1236,6 +1271,8 @@ describe('Playhead', () => {
|
|
|
1236
1271
|
Util.spyFunc(onSeek),
|
|
1237
1272
|
Util.spyFunc(onEvent));
|
|
1238
1273
|
|
|
1274
|
+
playhead.ready();
|
|
1275
|
+
|
|
1239
1276
|
playhead.notifyOfBufferingChange();
|
|
1240
1277
|
jasmine.clock().tick(500);
|
|
1241
1278
|
|
|
@@ -1260,6 +1297,8 @@ describe('Playhead', () => {
|
|
|
1260
1297
|
Util.spyFunc(onSeek),
|
|
1261
1298
|
Util.spyFunc(onEvent));
|
|
1262
1299
|
|
|
1300
|
+
playhead.ready();
|
|
1301
|
+
|
|
1263
1302
|
playhead.notifyOfBufferingChange();
|
|
1264
1303
|
jasmine.clock().tick(500);
|
|
1265
1304
|
|
|
@@ -1287,6 +1326,8 @@ describe('Playhead', () => {
|
|
|
1287
1326
|
Util.spyFunc(onSeek),
|
|
1288
1327
|
Util.spyFunc(onEvent));
|
|
1289
1328
|
|
|
1329
|
+
playhead.ready();
|
|
1330
|
+
|
|
1290
1331
|
jasmine.clock().tick(500);
|
|
1291
1332
|
expect(onEvent).not.toHaveBeenCalled();
|
|
1292
1333
|
|
|
@@ -154,6 +154,19 @@ describe('StreamingEngine', () => {
|
|
|
154
154
|
/* presentationDuration= */ Infinity);
|
|
155
155
|
setupPlayhead();
|
|
156
156
|
|
|
157
|
+
// Retry on failure for live streams.
|
|
158
|
+
config.failureCallback = () => streamingEngine.retry(0.1);
|
|
159
|
+
|
|
160
|
+
// Ignore 404 errors in live stream tests.
|
|
161
|
+
onError.and.callFake((error) => {
|
|
162
|
+
if (error.code == shaka.util.Error.Code.BAD_HTTP_STATUS &&
|
|
163
|
+
error.data[1] == 404) {
|
|
164
|
+
// 404 error
|
|
165
|
+
} else {
|
|
166
|
+
fail(error);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
157
170
|
createStreamingEngine();
|
|
158
171
|
}
|
|
159
172
|
|
|
@@ -878,7 +878,7 @@ describe('StreamingEngine', () => {
|
|
|
878
878
|
|
|
879
879
|
const config = shaka.util.PlayerConfiguration.createDefault().streaming;
|
|
880
880
|
config.bufferingGoal = 60;
|
|
881
|
-
config.failureCallback = () => streamingEngine.retry();
|
|
881
|
+
config.failureCallback = () => streamingEngine.retry(0.1);
|
|
882
882
|
createStreamingEngine(config);
|
|
883
883
|
|
|
884
884
|
// Make requests for different types take different amounts of time.
|
|
@@ -1737,8 +1737,23 @@ describe('StreamingEngine', () => {
|
|
|
1737
1737
|
beforeEach(() => {
|
|
1738
1738
|
setupLive();
|
|
1739
1739
|
mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData, 0);
|
|
1740
|
-
|
|
1740
|
+
|
|
1741
|
+
// Retry on failure for live streams.
|
|
1742
|
+
const config = shaka.util.PlayerConfiguration.createDefault().streaming;
|
|
1743
|
+
config.failureCallback = () => streamingEngine.retry(0.1);
|
|
1744
|
+
|
|
1745
|
+
createStreamingEngine(config);
|
|
1741
1746
|
presentationTimeInSeconds = 100;
|
|
1747
|
+
|
|
1748
|
+
// Ignore 404 errors in live stream tests.
|
|
1749
|
+
onError.and.callFake((error) => {
|
|
1750
|
+
if (error.code == shaka.util.Error.Code.BAD_HTTP_STATUS &&
|
|
1751
|
+
error.data[1] == 404) {
|
|
1752
|
+
// 404 error
|
|
1753
|
+
} else {
|
|
1754
|
+
fail(error);
|
|
1755
|
+
}
|
|
1756
|
+
});
|
|
1742
1757
|
});
|
|
1743
1758
|
|
|
1744
1759
|
it('outside segment availability window', async () => {
|
|
@@ -1768,24 +1783,22 @@ describe('StreamingEngine', () => {
|
|
|
1768
1783
|
const originalAppendBuffer =
|
|
1769
1784
|
// eslint-disable-next-line no-restricted-syntax
|
|
1770
1785
|
shaka.test.FakeMediaSourceEngine.prototype.appendBufferImpl;
|
|
1771
|
-
mediaSourceEngine.appendBuffer.and.callFake(
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
originalAppendBuffer);
|
|
1783
|
-
}
|
|
1786
|
+
mediaSourceEngine.appendBuffer.and.callFake((type, data, reference) => {
|
|
1787
|
+
expect(presentationTimeInSeconds).toBe(125);
|
|
1788
|
+
// Ignore a possible call for the first Period.
|
|
1789
|
+
if (reference && reference.startTime >= 100) {
|
|
1790
|
+
expect(Util.invokeSpy(timeline.getSegmentAvailabilityStart))
|
|
1791
|
+
.not.toBeLessThan(100);
|
|
1792
|
+
expect(Util.invokeSpy(timeline.getSegmentAvailabilityEnd))
|
|
1793
|
+
.not.toBeLessThan(120);
|
|
1794
|
+
playing = true;
|
|
1795
|
+
mediaSourceEngine.appendBuffer.and.callFake(originalAppendBuffer);
|
|
1796
|
+
}
|
|
1784
1797
|
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1798
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
1799
|
+
return originalAppendBuffer.call(
|
|
1800
|
+
mediaSourceEngine, type, data, reference);
|
|
1801
|
+
});
|
|
1789
1802
|
|
|
1790
1803
|
await runTest(slideSegmentAvailabilityWindow);
|
|
1791
1804
|
// Verify buffers.
|
|
@@ -2001,7 +2014,7 @@ describe('StreamingEngine', () => {
|
|
|
2001
2014
|
mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData);
|
|
2002
2015
|
|
|
2003
2016
|
const config = shaka.util.PlayerConfiguration.createDefault().streaming;
|
|
2004
|
-
config.failureCallback = () => streamingEngine.retry();
|
|
2017
|
+
config.failureCallback = () => streamingEngine.retry(0.1);
|
|
2005
2018
|
createStreamingEngine(config);
|
|
2006
2019
|
|
|
2007
2020
|
presentationTimeInSeconds = 100;
|
|
@@ -2162,7 +2175,7 @@ describe('StreamingEngine', () => {
|
|
|
2162
2175
|
netEngine.request.calls.reset();
|
|
2163
2176
|
|
|
2164
2177
|
// Retry streaming.
|
|
2165
|
-
expect(streamingEngine.retry()).toBe(true);
|
|
2178
|
+
expect(streamingEngine.retry(0.1)).toBe(true);
|
|
2166
2179
|
});
|
|
2167
2180
|
|
|
2168
2181
|
// Here we go!
|
|
@@ -2192,7 +2205,7 @@ describe('StreamingEngine', () => {
|
|
|
2192
2205
|
|
|
2193
2206
|
// Retry streaming, which should fail and return false.
|
|
2194
2207
|
netEngine.request.calls.reset();
|
|
2195
|
-
expect(streamingEngine.retry()).toBe(false);
|
|
2208
|
+
expect(streamingEngine.retry(0.1)).toBe(false);
|
|
2196
2209
|
});
|
|
2197
2210
|
|
|
2198
2211
|
// Here we go!
|
|
@@ -2244,7 +2257,7 @@ describe('StreamingEngine', () => {
|
|
|
2244
2257
|
|
|
2245
2258
|
// Retry streaming, which should fail and return false.
|
|
2246
2259
|
netEngine.request.calls.reset();
|
|
2247
|
-
expect(streamingEngine.retry()).toBe(false);
|
|
2260
|
+
expect(streamingEngine.retry(0.1)).toBe(false);
|
|
2248
2261
|
}
|
|
2249
2262
|
});
|
|
2250
2263
|
|
package/test/player_unit.js
CHANGED
|
@@ -3940,6 +3940,93 @@ describe('Player', () => {
|
|
|
3940
3940
|
});
|
|
3941
3941
|
});
|
|
3942
3942
|
|
|
3943
|
+
describe('config streaming.failureCallback default', () => {
|
|
3944
|
+
/** @type {jasmine.Spy} */
|
|
3945
|
+
let retryStreaming;
|
|
3946
|
+
/** @type {jasmine.Spy} */
|
|
3947
|
+
let isLive;
|
|
3948
|
+
|
|
3949
|
+
/**
|
|
3950
|
+
* @suppress {accessControls}
|
|
3951
|
+
* @param {!shaka.util.Error} error
|
|
3952
|
+
*/
|
|
3953
|
+
function defaultStreamingFailureCallback(error) {
|
|
3954
|
+
player.defaultStreamingFailureCallback_(error);
|
|
3955
|
+
}
|
|
3956
|
+
|
|
3957
|
+
beforeEach(() => {
|
|
3958
|
+
retryStreaming = jasmine.createSpy('retryStreaming');
|
|
3959
|
+
isLive = jasmine.createSpy('isLive');
|
|
3960
|
+
|
|
3961
|
+
player.retryStreaming = Util.spyFunc(retryStreaming);
|
|
3962
|
+
player.isLive = Util.spyFunc(isLive);
|
|
3963
|
+
});
|
|
3964
|
+
|
|
3965
|
+
it('ignores VOD failures', () => {
|
|
3966
|
+
isLive.and.returnValue(false);
|
|
3967
|
+
|
|
3968
|
+
const error = new shaka.util.Error(
|
|
3969
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
3970
|
+
shaka.util.Error.Category.NETWORK,
|
|
3971
|
+
shaka.util.Error.Code.BAD_HTTP_STATUS,
|
|
3972
|
+
/* url= */ '',
|
|
3973
|
+
/* http_status= */ 404);
|
|
3974
|
+
|
|
3975
|
+
defaultStreamingFailureCallback(error);
|
|
3976
|
+
expect(retryStreaming).not.toHaveBeenCalled();
|
|
3977
|
+
});
|
|
3978
|
+
|
|
3979
|
+
it('retries live on HTTP 404', () => {
|
|
3980
|
+
isLive.and.returnValue(true);
|
|
3981
|
+
|
|
3982
|
+
const error = new shaka.util.Error(
|
|
3983
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
3984
|
+
shaka.util.Error.Category.NETWORK,
|
|
3985
|
+
shaka.util.Error.Code.BAD_HTTP_STATUS,
|
|
3986
|
+
/* url= */ '',
|
|
3987
|
+
/* http_status= */ 404);
|
|
3988
|
+
|
|
3989
|
+
defaultStreamingFailureCallback(error);
|
|
3990
|
+
expect(retryStreaming).toHaveBeenCalled();
|
|
3991
|
+
});
|
|
3992
|
+
|
|
3993
|
+
it('retries live on generic HTTP error', () => {
|
|
3994
|
+
isLive.and.returnValue(true);
|
|
3995
|
+
|
|
3996
|
+
const error = new shaka.util.Error(
|
|
3997
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
3998
|
+
shaka.util.Error.Category.NETWORK,
|
|
3999
|
+
shaka.util.Error.Code.HTTP_ERROR);
|
|
4000
|
+
|
|
4001
|
+
defaultStreamingFailureCallback(error);
|
|
4002
|
+
expect(retryStreaming).toHaveBeenCalled();
|
|
4003
|
+
});
|
|
4004
|
+
|
|
4005
|
+
it('retries live on HTTP timeout', () => {
|
|
4006
|
+
isLive.and.returnValue(true);
|
|
4007
|
+
|
|
4008
|
+
const error = new shaka.util.Error(
|
|
4009
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
4010
|
+
shaka.util.Error.Category.NETWORK,
|
|
4011
|
+
shaka.util.Error.Code.TIMEOUT);
|
|
4012
|
+
|
|
4013
|
+
defaultStreamingFailureCallback(error);
|
|
4014
|
+
expect(retryStreaming).toHaveBeenCalled();
|
|
4015
|
+
});
|
|
4016
|
+
|
|
4017
|
+
it('ignores other live failures', () => {
|
|
4018
|
+
isLive.and.returnValue(true);
|
|
4019
|
+
|
|
4020
|
+
const error = new shaka.util.Error(
|
|
4021
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
4022
|
+
shaka.util.Error.Category.MEDIA,
|
|
4023
|
+
shaka.util.Error.Code.VIDEO_ERROR);
|
|
4024
|
+
|
|
4025
|
+
defaultStreamingFailureCallback(error);
|
|
4026
|
+
expect(retryStreaming).not.toHaveBeenCalled();
|
|
4027
|
+
});
|
|
4028
|
+
});
|
|
4029
|
+
|
|
3943
4030
|
/**
|
|
3944
4031
|
* Gets the currently active variant track.
|
|
3945
4032
|
* @return {shaka.extern.Track}
|
|
@@ -339,6 +339,9 @@ shaka.test.FakePlayhead = class {
|
|
|
339
339
|
/** @private {number} */
|
|
340
340
|
this.stallsDetected_ = 0;
|
|
341
341
|
|
|
342
|
+
/** @type {!jasmine.Spy} */
|
|
343
|
+
this.ready = jasmine.createSpy('ready');
|
|
344
|
+
|
|
342
345
|
/** @type {!jasmine.Spy} */
|
|
343
346
|
this.setStartTime = jasmine.createSpy('setStartTime')
|
|
344
347
|
.and.callFake((value) => {
|
package/ui/controls.js
CHANGED
|
@@ -1024,7 +1024,10 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
|
|
|
1024
1024
|
if (!this.video_ ||
|
|
1025
1025
|
this.video_.readyState == 0 ||
|
|
1026
1026
|
this.castProxy_.isCasting() ||
|
|
1027
|
-
!this.config_.enableFullscreenOnRotation
|
|
1027
|
+
!this.config_.enableFullscreenOnRotation ||
|
|
1028
|
+
!this.isFullScreenSupported()) {
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1028
1031
|
|
|
1029
1032
|
if (screen.orientation.type.includes('landscape') &&
|
|
1030
1033
|
!document.fullscreenElement) {
|
package/ui/settings_menu.js
CHANGED
|
@@ -12,6 +12,7 @@ goog.require('shaka.ui.Enums');
|
|
|
12
12
|
goog.require('shaka.ui.Utils');
|
|
13
13
|
goog.require('shaka.util.Dom');
|
|
14
14
|
goog.require('shaka.util.FakeEvent');
|
|
15
|
+
goog.require('shaka.util.Iterables');
|
|
15
16
|
goog.requireType('shaka.ui.Controls');
|
|
16
17
|
|
|
17
18
|
|
|
@@ -116,8 +117,16 @@ shaka.ui.SettingsMenu = class extends shaka.ui.Element {
|
|
|
116
117
|
this.eventManager.listen(this.backButton, 'click', () => {
|
|
117
118
|
shaka.ui.Utils.setDisplay(this.parent, true);
|
|
118
119
|
|
|
119
|
-
|
|
120
|
-
(
|
|
120
|
+
const isDisplayed =
|
|
121
|
+
(element) => element.classList.contains('shaka-hidden') == false;
|
|
122
|
+
|
|
123
|
+
const Iterables = shaka.util.Iterables;
|
|
124
|
+
if (Iterables.some(this.parent.childNodes, isDisplayed)) {
|
|
125
|
+
// Focus on the first visible child of the overflow menu
|
|
126
|
+
const visibleElements =
|
|
127
|
+
Iterables.filter(this.parent.childNodes, isDisplayed);
|
|
128
|
+
/** @type {!HTMLElement} */ (visibleElements[0]).focus();
|
|
129
|
+
}
|
|
121
130
|
|
|
122
131
|
// Make sure controls are displayed
|
|
123
132
|
this.controls.computeOpacity();
|