shaka-player 4.3.15 → 4.3.16
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/workflows/appspot.yaml +4 -4
- package/.github/workflows/build-and-test.yaml +23 -10
- package/.github/workflows/custom-actions/set-commit-status/action.yaml +29 -7
- package/.github/workflows/demo-version-index.yaml +3 -3
- package/.github/workflows/nightly-demo.yaml +4 -4
- package/.github/workflows/release-please.yaml +25 -24
- package/.github/workflows/report-incremental-coverage.yaml +1 -1
- package/.github/workflows/selenium-lab-tests.yaml +30 -18
- package/.github/workflows/sync-labels.yaml +1 -1
- package/.github/workflows/talk-to-shaka-bot.yaml +1 -1
- package/.github/workflows/update-issues.yaml +1 -1
- package/.github/workflows/update-screenshots.yaml +25 -38
- package/CHANGELOG.md +28 -0
- package/demo/demo.less +1 -5
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +0 -1
- package/dist/locales.js +31 -31
- package/dist/shaka-player.compiled.d.ts +6 -10
- package/dist/shaka-player.compiled.debug.d.ts +6 -10
- package/dist/shaka-player.compiled.debug.externs.js +13 -11
- package/dist/shaka-player.compiled.debug.js +209 -206
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +13 -11
- package/dist/shaka-player.compiled.js +854 -852
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +6 -10
- package/dist/shaka-player.ui.debug.d.ts +6 -10
- package/dist/shaka-player.ui.debug.externs.js +13 -11
- package/dist/shaka-player.ui.debug.js +158 -155
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +13 -11
- package/dist/shaka-player.ui.js +949 -947
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/faq.md +25 -0
- package/docs/tutorials/offline.md +3 -0
- package/docs/tutorials/ui.md +4 -4
- package/externs/shaka/player.js +32 -19
- package/lib/cast/cast_proxy.js +1 -3
- package/lib/cast/cast_sender.js +8 -11
- package/lib/cea/cea608_memory.js +1 -1
- package/lib/dash/dash_parser.js +3 -0
- package/lib/dash/segment_template.js +5 -0
- package/lib/hls/hls_parser.js +18 -16
- package/lib/media/drm_engine.js +17 -3
- package/lib/media/presentation_timeline.js +23 -0
- package/lib/media/segment_index.js +10 -0
- package/lib/media/streaming_engine.js +1 -13
- package/lib/player.js +18 -4
- package/lib/text/ui_text_displayer.js +10 -1
- package/lib/util/manifest_parser_utils.js +1 -0
- package/lib/util/stream_utils.js +8 -5
- package/package.json +1 -1
- package/test/cast/cast_proxy_unit.js +0 -46
- package/test/cast/cast_sender_unit.js +26 -26
- package/test/cea/cea608_memory_unit.js +3 -2
- package/test/hls/hls_live_unit.js +52 -0
- package/test/media/media_source_engine_integration.js +1 -1
- package/test/player_unit.js +13 -1
- package/lib/polyfill/storage_estimate.js +0 -57
|
@@ -114,52 +114,6 @@ describe('CastProxy', () => {
|
|
|
114
114
|
});
|
|
115
115
|
|
|
116
116
|
describe('cast', () => {
|
|
117
|
-
it('pauses the local video', () => {
|
|
118
|
-
proxy.cast();
|
|
119
|
-
expect(mockVideo.pause).toHaveBeenCalled();
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('passes initial state to sender', () => {
|
|
123
|
-
mockVideo.loop = true;
|
|
124
|
-
mockVideo.playbackRate = 3;
|
|
125
|
-
mockVideo.currentTime = 12;
|
|
126
|
-
const fakeConfig = {key: 'value'};
|
|
127
|
-
mockPlayer.getConfiguration.and.returnValue(fakeConfig);
|
|
128
|
-
mockPlayer.isTextTrackVisible.and.returnValue(false);
|
|
129
|
-
const fakeManifestUri = 'foo://bar';
|
|
130
|
-
mockPlayer.getAssetUri.and.returnValue(fakeManifestUri);
|
|
131
|
-
|
|
132
|
-
proxy.cast();
|
|
133
|
-
const calls = mockSender.cast.calls;
|
|
134
|
-
expect(calls.count()).toBe(1);
|
|
135
|
-
if (calls.count()) {
|
|
136
|
-
const state = calls.argsFor(0)[0];
|
|
137
|
-
// Video state goes directly:
|
|
138
|
-
expect(state.video.loop).toBe(mockVideo.loop);
|
|
139
|
-
expect(state.video.playbackRate).toBe(mockVideo.playbackRate);
|
|
140
|
-
// Player state uses corresponding setter names:
|
|
141
|
-
expect(state.player.configure).toEqual(fakeConfig);
|
|
142
|
-
expect(state['playerAfterLoad'].setTextTrackVisibility).toBe(false);
|
|
143
|
-
// Manifest URI:
|
|
144
|
-
expect(state.manifest).toBe(fakeManifestUri);
|
|
145
|
-
// Start time:
|
|
146
|
-
expect(state.startTime).toBe(mockVideo.currentTime);
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('does not provide a start time if the video has ended', () => {
|
|
151
|
-
mockVideo.ended = true;
|
|
152
|
-
mockVideo.currentTime = 12;
|
|
153
|
-
|
|
154
|
-
proxy.cast();
|
|
155
|
-
const calls = mockSender.cast.calls;
|
|
156
|
-
expect(calls.count()).toBe(1);
|
|
157
|
-
if (calls.count()) {
|
|
158
|
-
const state = calls.argsFor(0)[0];
|
|
159
|
-
expect(state.startTime).toBe(null);
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
|
|
163
117
|
it('unloads the local player after casting is complete', async () => {
|
|
164
118
|
/** @type {!shaka.util.PublicPromise} */
|
|
165
119
|
const p = new shaka.util.PublicPromise();
|
|
@@ -157,7 +157,7 @@ describe('CastSender', () => {
|
|
|
157
157
|
shaka.util.Error.Severity.RECOVERABLE,
|
|
158
158
|
shaka.util.Error.Category.CAST,
|
|
159
159
|
shaka.util.Error.Code.CAST_API_UNAVAILABLE));
|
|
160
|
-
await expectAsync(sender.cast(
|
|
160
|
+
await expectAsync(sender.cast()).toBeRejectedWith(expected);
|
|
161
161
|
});
|
|
162
162
|
|
|
163
163
|
it('fails when there are no receivers', async () => {
|
|
@@ -168,7 +168,7 @@ describe('CastSender', () => {
|
|
|
168
168
|
shaka.util.Error.Severity.RECOVERABLE,
|
|
169
169
|
shaka.util.Error.Category.CAST,
|
|
170
170
|
shaka.util.Error.Code.NO_CAST_RECEIVERS));
|
|
171
|
-
await expectAsync(sender.cast(
|
|
171
|
+
await expectAsync(sender.cast()).toBeRejectedWith(expected);
|
|
172
172
|
});
|
|
173
173
|
|
|
174
174
|
it('creates a session and sends an "init" message', async () => {
|
|
@@ -177,7 +177,7 @@ describe('CastSender', () => {
|
|
|
177
177
|
fakeReceiverAvailability(true);
|
|
178
178
|
expect(sender.hasReceivers()).toBe(true);
|
|
179
179
|
|
|
180
|
-
const p = sender.cast(
|
|
180
|
+
const p = sender.cast();
|
|
181
181
|
fakeSessionConnection();
|
|
182
182
|
|
|
183
183
|
await p;
|
|
@@ -220,7 +220,7 @@ describe('CastSender', () => {
|
|
|
220
220
|
sender.init();
|
|
221
221
|
fakeReceiverAvailability(true);
|
|
222
222
|
|
|
223
|
-
const p = sender.cast(
|
|
223
|
+
const p = sender.cast();
|
|
224
224
|
fakeSessionConnectionFailure(metadata.castErrorCode);
|
|
225
225
|
|
|
226
226
|
const expected = Util.jasmineError(new shaka.util.Error(
|
|
@@ -236,7 +236,7 @@ describe('CastSender', () => {
|
|
|
236
236
|
sender.init();
|
|
237
237
|
fakeReceiverAvailability(true);
|
|
238
238
|
|
|
239
|
-
const p = sender.cast(
|
|
239
|
+
const p = sender.cast();
|
|
240
240
|
fakeSessionConnection();
|
|
241
241
|
|
|
242
242
|
await p;
|
|
@@ -244,14 +244,14 @@ describe('CastSender', () => {
|
|
|
244
244
|
shaka.util.Error.Severity.RECOVERABLE,
|
|
245
245
|
shaka.util.Error.Category.CAST,
|
|
246
246
|
shaka.util.Error.Code.ALREADY_CASTING));
|
|
247
|
-
await expectAsync(sender.cast(
|
|
247
|
+
await expectAsync(sender.cast()).toBeRejectedWith(expected);
|
|
248
248
|
});
|
|
249
249
|
});
|
|
250
250
|
|
|
251
251
|
it('re-uses old sessions', async () => {
|
|
252
252
|
sender.init();
|
|
253
253
|
fakeReceiverAvailability(true);
|
|
254
|
-
const p = sender.cast(
|
|
254
|
+
const p = sender.cast();
|
|
255
255
|
fakeSessionConnection();
|
|
256
256
|
const oldMockSession = mockSession;
|
|
257
257
|
await p;
|
|
@@ -289,7 +289,7 @@ describe('CastSender', () => {
|
|
|
289
289
|
it('doesn\'t re-use stopped sessions', async () => {
|
|
290
290
|
sender.init();
|
|
291
291
|
fakeReceiverAvailability(true);
|
|
292
|
-
const p = sender.cast(
|
|
292
|
+
const p = sender.cast();
|
|
293
293
|
fakeSessionConnection();
|
|
294
294
|
await p;
|
|
295
295
|
await sender.destroy();
|
|
@@ -334,7 +334,7 @@ describe('CastSender', () => {
|
|
|
334
334
|
sender.init();
|
|
335
335
|
fakeReceiverAvailability(true);
|
|
336
336
|
sender.setAppData(fakeAppData);
|
|
337
|
-
const p = sender.cast(
|
|
337
|
+
const p = sender.cast();
|
|
338
338
|
fakeSessionConnection();
|
|
339
339
|
|
|
340
340
|
await p;
|
|
@@ -347,7 +347,7 @@ describe('CastSender', () => {
|
|
|
347
347
|
it('sends a special "appData" message if casting', async () => {
|
|
348
348
|
sender.init();
|
|
349
349
|
fakeReceiverAvailability(true);
|
|
350
|
-
const p = sender.cast(
|
|
350
|
+
const p = sender.cast();
|
|
351
351
|
fakeSessionConnection();
|
|
352
352
|
await p;
|
|
353
353
|
|
|
@@ -390,7 +390,7 @@ describe('CastSender', () => {
|
|
|
390
390
|
it('is not triggered if making a new session', async () => {
|
|
391
391
|
sender.init();
|
|
392
392
|
fakeReceiverAvailability(true);
|
|
393
|
-
const p = sender.cast(
|
|
393
|
+
const p = sender.cast();
|
|
394
394
|
fakeSessionConnection();
|
|
395
395
|
await p;
|
|
396
396
|
|
|
@@ -437,7 +437,7 @@ describe('CastSender', () => {
|
|
|
437
437
|
it('is triggered by an "event" message', async () => {
|
|
438
438
|
sender.init();
|
|
439
439
|
fakeReceiverAvailability(true);
|
|
440
|
-
const p = sender.cast(
|
|
440
|
+
const p = sender.cast();
|
|
441
441
|
fakeSessionConnection();
|
|
442
442
|
await p;
|
|
443
443
|
|
|
@@ -460,7 +460,7 @@ describe('CastSender', () => {
|
|
|
460
460
|
it('is triggered when casting ends', async () => {
|
|
461
461
|
sender.init();
|
|
462
462
|
fakeReceiverAvailability(true);
|
|
463
|
-
const p = sender.cast(
|
|
463
|
+
const p = sender.cast();
|
|
464
464
|
fakeSessionConnection();
|
|
465
465
|
await p;
|
|
466
466
|
|
|
@@ -477,7 +477,7 @@ describe('CastSender', () => {
|
|
|
477
477
|
it('opens the dialog if we are casting', async () => {
|
|
478
478
|
sender.init();
|
|
479
479
|
fakeReceiverAvailability(true);
|
|
480
|
-
const p = sender.cast(
|
|
480
|
+
const p = sender.cast();
|
|
481
481
|
fakeSessionConnection();
|
|
482
482
|
await p;
|
|
483
483
|
|
|
@@ -502,7 +502,7 @@ describe('CastSender', () => {
|
|
|
502
502
|
it('returns most recent properties from "update" messages', async () => {
|
|
503
503
|
sender.init();
|
|
504
504
|
fakeReceiverAvailability(true);
|
|
505
|
-
const p = sender.cast(
|
|
505
|
+
const p = sender.cast();
|
|
506
506
|
fakeSessionConnection();
|
|
507
507
|
await p;
|
|
508
508
|
|
|
@@ -545,7 +545,7 @@ describe('CastSender', () => {
|
|
|
545
545
|
it('simple methods trigger "call" messages', async () => {
|
|
546
546
|
sender.init();
|
|
547
547
|
fakeReceiverAvailability(true);
|
|
548
|
-
const p = sender.cast(
|
|
548
|
+
const p = sender.cast();
|
|
549
549
|
fakeSessionConnection();
|
|
550
550
|
await p;
|
|
551
551
|
|
|
@@ -568,7 +568,7 @@ describe('CastSender', () => {
|
|
|
568
568
|
method = null;
|
|
569
569
|
sender.init();
|
|
570
570
|
fakeReceiverAvailability(true);
|
|
571
|
-
const p = sender.cast(
|
|
571
|
+
const p = sender.cast();
|
|
572
572
|
fakeSessionConnection();
|
|
573
573
|
await p;
|
|
574
574
|
|
|
@@ -655,7 +655,7 @@ describe('CastSender', () => {
|
|
|
655
655
|
it('overrides any cached properties', async () => {
|
|
656
656
|
sender.init();
|
|
657
657
|
fakeReceiverAvailability(true);
|
|
658
|
-
const p = sender.cast(
|
|
658
|
+
const p = sender.cast();
|
|
659
659
|
fakeSessionConnection();
|
|
660
660
|
await p;
|
|
661
661
|
|
|
@@ -675,7 +675,7 @@ describe('CastSender', () => {
|
|
|
675
675
|
it('causes a "set" message to be sent', async () => {
|
|
676
676
|
sender.init();
|
|
677
677
|
fakeReceiverAvailability(true);
|
|
678
|
-
const p = sender.cast(
|
|
678
|
+
const p = sender.cast();
|
|
679
679
|
fakeSessionConnection();
|
|
680
680
|
await p;
|
|
681
681
|
|
|
@@ -691,7 +691,7 @@ describe('CastSender', () => {
|
|
|
691
691
|
it('can be used before we have an "update" message', async () => {
|
|
692
692
|
sender.init();
|
|
693
693
|
fakeReceiverAvailability(true);
|
|
694
|
-
const p = sender.cast(
|
|
694
|
+
const p = sender.cast();
|
|
695
695
|
fakeSessionConnection();
|
|
696
696
|
await p;
|
|
697
697
|
|
|
@@ -705,7 +705,7 @@ describe('CastSender', () => {
|
|
|
705
705
|
it('is true only after we have an "update" message', async () => {
|
|
706
706
|
sender.init();
|
|
707
707
|
fakeReceiverAvailability(true);
|
|
708
|
-
const p = sender.cast(
|
|
708
|
+
const p = sender.cast();
|
|
709
709
|
fakeSessionConnection();
|
|
710
710
|
await p;
|
|
711
711
|
|
|
@@ -723,7 +723,7 @@ describe('CastSender', () => {
|
|
|
723
723
|
it('disconnects and cancels all async operations', async () => {
|
|
724
724
|
sender.init();
|
|
725
725
|
fakeReceiverAvailability(true);
|
|
726
|
-
const cast = sender.cast(
|
|
726
|
+
const cast = sender.cast();
|
|
727
727
|
fakeSessionConnection();
|
|
728
728
|
await cast;
|
|
729
729
|
|
|
@@ -756,7 +756,7 @@ describe('CastSender', () => {
|
|
|
756
756
|
it('transfers playback to local device', async () => {
|
|
757
757
|
sender.init();
|
|
758
758
|
fakeReceiverAvailability(true);
|
|
759
|
-
const cast = sender.cast(
|
|
759
|
+
const cast = sender.cast();
|
|
760
760
|
fakeSessionConnection();
|
|
761
761
|
await cast;
|
|
762
762
|
|
|
@@ -772,7 +772,7 @@ describe('CastSender', () => {
|
|
|
772
772
|
it('succeeds even if session.stop() throws', async () => {
|
|
773
773
|
sender.init();
|
|
774
774
|
fakeReceiverAvailability(true);
|
|
775
|
-
const cast = sender.cast(
|
|
775
|
+
const cast = sender.cast();
|
|
776
776
|
fakeSessionConnection();
|
|
777
777
|
await cast;
|
|
778
778
|
|
|
@@ -792,7 +792,7 @@ describe('CastSender', () => {
|
|
|
792
792
|
beforeEach(async () => {
|
|
793
793
|
sender.init();
|
|
794
794
|
fakeReceiverAvailability(true);
|
|
795
|
-
const cast = sender.cast(
|
|
795
|
+
const cast = sender.cast();
|
|
796
796
|
fakeSessionConnection();
|
|
797
797
|
await cast;
|
|
798
798
|
|
|
@@ -837,7 +837,7 @@ describe('CastSender', () => {
|
|
|
837
837
|
it('cancels all async operations', async () => {
|
|
838
838
|
sender.init();
|
|
839
839
|
fakeReceiverAvailability(true);
|
|
840
|
-
const cast = sender.cast(
|
|
840
|
+
const cast = sender.cast();
|
|
841
841
|
fakeSessionConnection();
|
|
842
842
|
await cast;
|
|
843
843
|
|
|
@@ -46,11 +46,12 @@ describe('Cea608Memory', () => {
|
|
|
46
46
|
it('adds and emits a series of special characters from the buffer', () => {
|
|
47
47
|
const startTime = 1;
|
|
48
48
|
const endTime = 2;
|
|
49
|
-
const expectedText = '
|
|
49
|
+
const expectedText = '½¿ èôÇ©ë»ö{ß│';
|
|
50
50
|
const charGroups = [
|
|
51
51
|
{
|
|
52
52
|
set: CharSet.SPECIAL_NORTH_AMERICAN,
|
|
53
|
-
|
|
53
|
+
// Note TS is not at either end to avoid side effect of trim()
|
|
54
|
+
chars: [0x32, 0x33, 0x39, 0x3a, 0x3e], // ½, ¿, TS, è, ô
|
|
54
55
|
},
|
|
55
56
|
|
|
56
57
|
{
|
|
@@ -776,6 +776,58 @@ describe('HlsParser live', () => {
|
|
|
776
776
|
manifest.variants[1].video, [ref4]);
|
|
777
777
|
});
|
|
778
778
|
|
|
779
|
+
describe('when ignoreManifestProgramDateTime is set', () => {
|
|
780
|
+
const config = shaka.util.PlayerConfiguration.createDefault().manifest;
|
|
781
|
+
config.hls.ignoreManifestProgramDateTime = true;
|
|
782
|
+
|
|
783
|
+
it('does not reset segment times when switching', async () => {
|
|
784
|
+
parser.configure(config);
|
|
785
|
+
|
|
786
|
+
const ref1 = makeReference(
|
|
787
|
+
'test:/main.mp4', 0, 2, /* syncTime= */ null);
|
|
788
|
+
const ref2 = makeReference(
|
|
789
|
+
'test:/main2.mp4', 2, 4, /* syncTime= */ null);
|
|
790
|
+
|
|
791
|
+
const secondVariant = [
|
|
792
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=300,CODECS="avc1",',
|
|
793
|
+
'RESOLUTION=1200x940,FRAME-RATE=60\n',
|
|
794
|
+
'video2',
|
|
795
|
+
].join('');
|
|
796
|
+
const masterWithTwoVariants = master + secondVariant;
|
|
797
|
+
configureNetEngineForInitialManifest(masterWithTwoVariants,
|
|
798
|
+
mediaWithAdditionalSegment, mediaWithAdditionalSegment2);
|
|
799
|
+
|
|
800
|
+
const manifest = await parser.start('test:/master', playerInterface);
|
|
801
|
+
await manifest.variants[0].video.createSegmentIndex();
|
|
802
|
+
ManifestParser.verifySegmentIndex(
|
|
803
|
+
manifest.variants[0].video, [ref1, ref2]);
|
|
804
|
+
expect(manifest.variants[1].video.segmentIndex).toBeNull();
|
|
805
|
+
|
|
806
|
+
// In the initial playlist, we know the earliest start time is 0, at
|
|
807
|
+
// EXT-X-MEDIA-SEQUENCE of 0.
|
|
808
|
+
expect(
|
|
809
|
+
manifest.variants[0].video.segmentIndex.earliestReference()
|
|
810
|
+
.getStartTime())
|
|
811
|
+
.toBe(0);
|
|
812
|
+
|
|
813
|
+
// Update.
|
|
814
|
+
fakeNetEngine
|
|
815
|
+
.setResponseText('test:/video', mediaWithRemovedSegment)
|
|
816
|
+
.setResponseText('test:/video2', mediaWithRemovedSegment2);
|
|
817
|
+
await delayForUpdatePeriod();
|
|
818
|
+
|
|
819
|
+
// Switch. The new variant starts at EXT-X-MEDIA-SEQUENCE of 1.
|
|
820
|
+
await manifest.variants[0].video.closeSegmentIndex();
|
|
821
|
+
await manifest.variants[1].video.createSegmentIndex();
|
|
822
|
+
|
|
823
|
+
// The earliest start time of the new segmentIndex should therefore be
|
|
824
|
+
// 2.
|
|
825
|
+
expect(manifest.variants[0].video.segmentIndex).toBeNull();
|
|
826
|
+
const segIdx = manifest.variants[1].video.segmentIndex;
|
|
827
|
+
expect(segIdx.earliestReference().getStartTime()).toBe(2);
|
|
828
|
+
});
|
|
829
|
+
});
|
|
830
|
+
|
|
779
831
|
it('handles switching during update', async () => {
|
|
780
832
|
const ref1 = makeReference(
|
|
781
833
|
'test:/main.mp4', 0, 2, /* syncTime= */ null);
|
package/test/player_unit.js
CHANGED
|
@@ -3519,11 +3519,14 @@ describe('Player', () => {
|
|
|
3519
3519
|
});
|
|
3520
3520
|
|
|
3521
3521
|
describe('getPlayheadTimeAsDate()', () => {
|
|
3522
|
+
/** @type {?shaka.media.PresentationTimeline} */
|
|
3523
|
+
let timeline;
|
|
3522
3524
|
beforeEach(async () => {
|
|
3523
|
-
|
|
3525
|
+
timeline = new shaka.media.PresentationTimeline(300, 0);
|
|
3524
3526
|
timeline.setStatic(false);
|
|
3525
3527
|
|
|
3526
3528
|
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
3529
|
+
goog.asserts.assert(timeline, 'timeline must be non-null');
|
|
3527
3530
|
manifest.presentationTimeline = timeline;
|
|
3528
3531
|
manifest.addVariant(0, (variant) => {
|
|
3529
3532
|
variant.addVideo(1);
|
|
@@ -3541,6 +3544,15 @@ describe('Player', () => {
|
|
|
3541
3544
|
// (300 (presentation start time) + 20 (playhead time)) * 1000 (ms/sec)
|
|
3542
3545
|
expect(liveTimeUtc).toEqual(new Date(320 * 1000));
|
|
3543
3546
|
});
|
|
3547
|
+
|
|
3548
|
+
it('uses program date time', () => {
|
|
3549
|
+
timeline.setInitialProgramDateTime(100);
|
|
3550
|
+
playhead.getTime.and.returnValue(20);
|
|
3551
|
+
|
|
3552
|
+
const liveTimeUtc = player.getPlayheadTimeAsDate();
|
|
3553
|
+
// (100 (program date time) + 20 (playhead time)) * 1000 (ms/sec)
|
|
3554
|
+
expect(liveTimeUtc).toEqual(new Date(120 * 1000));
|
|
3555
|
+
});
|
|
3544
3556
|
});
|
|
3545
3557
|
|
|
3546
3558
|
it('rejects empty manifests', async () => {
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/*! @license
|
|
2
|
-
* Shaka Player
|
|
3
|
-
* Copyright 2016 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
goog.provide('shaka.polyfill.StorageEstimate');
|
|
8
|
-
|
|
9
|
-
goog.require('shaka.polyfill');
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @summary A polyfill to provide navigator.storage.estimate in old
|
|
14
|
-
* webkit browsers.
|
|
15
|
-
* See: https://developers.google.com/web/updates/2017/08/estimating-available-storage-space#the-present
|
|
16
|
-
* @export
|
|
17
|
-
*/
|
|
18
|
-
shaka.polyfill.StorageEstimate = class {
|
|
19
|
-
/**
|
|
20
|
-
* Install the polyfill if needed.
|
|
21
|
-
* @export
|
|
22
|
-
*/
|
|
23
|
-
static install() {
|
|
24
|
-
if (navigator.storage && navigator.storage.estimate) {
|
|
25
|
-
// No need.
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (navigator.webkitTemporaryStorage &&
|
|
30
|
-
navigator.webkitTemporaryStorage.queryUsageAndQuota) {
|
|
31
|
-
if (!('storage' in navigator)) {
|
|
32
|
-
navigator.storage = /** @type {!StorageManager} */ ({});
|
|
33
|
-
}
|
|
34
|
-
navigator.storage.estimate =
|
|
35
|
-
shaka.polyfill.StorageEstimate.storageEstimate_;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* @this {StorageManager}
|
|
41
|
-
* @return {!Promise}
|
|
42
|
-
* @private
|
|
43
|
-
*/
|
|
44
|
-
static storageEstimate_() {
|
|
45
|
-
return new Promise((resolve, reject) => {
|
|
46
|
-
navigator.webkitTemporaryStorage.queryUsageAndQuota(
|
|
47
|
-
(usage, quota) => {
|
|
48
|
-
resolve({usage: usage, quota: quota});
|
|
49
|
-
},
|
|
50
|
-
reject,
|
|
51
|
-
);
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
shaka.polyfill.register(shaka.polyfill.StorageEstimate.install);
|