shaka-player 4.2.3 → 4.3.0
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/sync-labels.yaml +1 -1
- package/.github/workflows/update-issues.yaml +1 -1
- package/AUTHORS +5 -0
- package/CHANGELOG.md +85 -39
- package/CONTRIBUTORS +5 -0
- package/README.md +14 -0
- package/demo/common/assets.js +58 -0
- package/demo/common/message_ids.js +22 -1
- package/demo/config.js +89 -5
- package/demo/demo.less +7 -1
- package/demo/index.html +8 -1
- package/demo/locales/en.json +21 -1
- package/demo/locales/source.json +82 -2
- package/demo/main.js +57 -1
- package/demo/search.js +2 -0
- package/demo/visualizer.js +337 -0
- package/demo/visualizer_button.js +103 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +83 -58
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +83 -58
- package/dist/demo.compiled.map +4 -4
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +18 -11
- package/dist/locales.js +32 -32
- package/dist/receiver.compiled.debug.js +23 -19
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +23 -19
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +178 -27
- package/dist/shaka-player.compiled.debug.d.ts +178 -27
- package/dist/shaka-player.compiled.debug.externs.js +163 -32
- package/dist/shaka-player.compiled.debug.js +488 -422
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +163 -32
- package/dist/shaka-player.compiled.js +895 -857
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +178 -27
- package/dist/shaka-player.ui.debug.d.ts +178 -27
- package/dist/shaka-player.ui.debug.externs.js +163 -32
- package/dist/shaka-player.ui.debug.js +519 -450
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +163 -32
- package/dist/shaka-player.ui.js +1053 -1015
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/lcevc-architecture.png +0 -0
- package/docs/design/lcevc-demo.png +0 -0
- package/docs/design/lcevc-integration.md +72 -0
- package/docs/tutorials/fairplay.md +7 -0
- package/docs/tutorials/faq.md +1 -1
- package/docs/tutorials/ui.md +7 -7
- package/docs/tutorials/upgrade.md +6 -0
- package/externs/ima.js +13 -1
- package/externs/lcevc.js +81 -0
- package/externs/mux.js +4 -42
- package/externs/shaka/ads.js +11 -1
- package/externs/shaka/manifest_parser.js +5 -1
- package/externs/shaka/player.js +178 -15
- package/lib/abr/simple_abr_manager.js +7 -0
- package/lib/ads/ad_manager.js +0 -8
- package/lib/ads/client_side_ad.js +15 -0
- package/lib/ads/client_side_ad_manager.js +21 -8
- package/lib/ads/server_side_ad.js +15 -0
- package/lib/ads/server_side_ad_manager.js +3 -3
- 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 +18 -6
- package/lib/cea/dummy_cea_parser.js +28 -0
- package/lib/cea/i_cea_parser.js +14 -2
- package/lib/cea/mp4_cea_parser.js +87 -5
- package/lib/config/auto_show_text.js +33 -0
- package/lib/dash/dash_parser.js +1 -1
- package/lib/hls/hls_parser.js +799 -376
- package/lib/lcevc/lcevc_dil.js +152 -0
- package/lib/media/closed_caption_parser.js +9 -6
- package/lib/media/drm_engine.js +14 -6
- package/lib/media/media_source_engine.js +112 -26
- package/lib/media/playhead.js +23 -1
- package/lib/media/presentation_timeline.js +26 -11
- package/lib/media/segment_reference.js +49 -1
- package/lib/media/streaming_engine.js +145 -24
- package/lib/media/transmuxer.js +79 -18
- package/lib/offline/storage.js +1 -0
- package/lib/player.js +477 -85
- package/lib/polyfill/patchedmediakeys_apple.js +55 -1
- package/lib/text/ui_text_displayer.js +5 -5
- package/lib/text/vtt_text_parser.js +35 -1
- package/lib/util/dom_utils.js +0 -1
- package/lib/util/error.js +17 -0
- package/lib/util/fake_event.js +2 -0
- package/lib/util/id3_utils.js +300 -0
- package/lib/util/manifest_parser_utils.js +4 -0
- package/lib/util/mime_utils.js +3 -6
- package/lib/util/mp4_box_parsers.js +15 -5
- package/lib/util/platform.js +9 -1
- package/lib/util/player_configuration.js +23 -1
- package/lib/util/ts_parser.js +499 -0
- package/maintained-branches.md +2 -2
- package/package.json +4 -1
- package/roadmap.md +27 -7
- package/test/ads/ad_manager_unit.js +180 -29
- 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 +4 -1
- package/test/dash/dash_parser_content_protection_unit.js +1 -0
- package/test/dash/dash_parser_live_unit.js +1 -0
- package/test/dash/dash_parser_manifest_unit.js +93 -1
- package/test/dash/dash_parser_segment_base_unit.js +1 -0
- package/test/dash/dash_parser_segment_list_unit.js +1 -0
- package/test/dash/dash_parser_segment_template_unit.js +1 -0
- package/test/demo/demo_unit.js +2 -1
- package/test/hls/hls_live_unit.js +253 -19
- package/test/hls/hls_parser_unit.js +500 -12
- package/test/media/closed_caption_parser_unit.js +2 -1
- package/test/media/drm_engine_integration.js +3 -1
- package/test/media/media_source_engine_integration.js +102 -6
- package/test/media/media_source_engine_unit.js +10 -5
- package/test/media/playhead_unit.js +41 -0
- package/test/media/streaming_engine_integration.js +17 -1
- package/test/media/streaming_engine_unit.js +180 -24
- package/test/media/transmuxer_integration.js +21 -10
- package/test/player_integration.js +224 -82
- package/test/player_unit.js +92 -2
- package/test/polyfill/patchedmediakeys_apple_unit.js +124 -0
- package/test/test/assets/id3-metadata.aac +0 -0
- package/test/test/assets/id3-metadata.ts +0 -0
- package/test/test/assets/thumbnails-sprites.vtt +10 -0
- package/test/test/assets/thumbnails.vtt +10 -0
- package/test/test/util/dash_parser_util.js +2 -0
- package/test/test/util/fake_ad.js +21 -0
- package/test/test/util/fake_media_source_engine.js +7 -0
- package/test/test/util/id3_generator.js +100 -0
- package/test/test/util/manifest_generator.js +3 -6
- package/test/test/util/simple_fakes.js +7 -0
- package/test/test/util/stream_generator.js +38 -0
- package/test/test/util/test_scheme.js +43 -14
- package/test/text/vtt_text_parser_unit.js +11 -0
- package/test/ui/text_displayer_layout_unit.js +14 -0
- package/test/util/id3_utils_unit.js +116 -0
- package/test/util/ts_parser_unit.js +77 -0
- package/ui/controls.js +4 -1
- package/ui/less/containers.less +7 -0
- package/ui/settings_menu.js +11 -2
- package/ui/ui.js +43 -4
|
@@ -10,7 +10,8 @@ describe('ClosedCaptionParser', () => {
|
|
|
10
10
|
'base/test/test/assets/empty_caption_video_init.mp4');
|
|
11
11
|
const videoSegment = await shaka.test.Util.fetch(
|
|
12
12
|
'base/test/test/assets/empty_caption_video_segment.mp4');
|
|
13
|
-
const
|
|
13
|
+
const mimeType = 'video/mp4';
|
|
14
|
+
const parser = new shaka.media.ClosedCaptionParser(mimeType);
|
|
14
15
|
parser.init(initSegment);
|
|
15
16
|
parser.parseFrom(videoSegment);
|
|
16
17
|
});
|
|
@@ -126,8 +126,10 @@ describe('DrmEngine', () => {
|
|
|
126
126
|
|
|
127
127
|
mediaSourceEngine = new shaka.media.MediaSourceEngine(
|
|
128
128
|
video,
|
|
129
|
-
new shaka.test.FakeClosedCaptionParser(),
|
|
130
129
|
new shaka.test.FakeTextDisplayer());
|
|
130
|
+
const mediaSourceConfig =
|
|
131
|
+
shaka.util.PlayerConfiguration.createDefault().mediaSource;
|
|
132
|
+
mediaSourceEngine.configure(mediaSourceConfig);
|
|
131
133
|
|
|
132
134
|
const expectedObject = new Map();
|
|
133
135
|
expectedObject.set(ContentType.AUDIO, audioStream);
|
|
@@ -26,6 +26,9 @@ describe('MediaSourceEngine', () => {
|
|
|
26
26
|
*/
|
|
27
27
|
let textDisplayer;
|
|
28
28
|
|
|
29
|
+
/** @type {!jasmine.Spy} */
|
|
30
|
+
let onMetadata;
|
|
31
|
+
|
|
29
32
|
beforeAll(() => {
|
|
30
33
|
video = shaka.test.UiUtils.createVideoElement();
|
|
31
34
|
document.body.appendChild(video);
|
|
@@ -37,10 +40,14 @@ describe('MediaSourceEngine', () => {
|
|
|
37
40
|
|
|
38
41
|
textDisplayer = new shaka.test.FakeTextDisplayer();
|
|
39
42
|
|
|
43
|
+
onMetadata = jasmine.createSpy('onMetadata');
|
|
44
|
+
|
|
40
45
|
mediaSourceEngine = new shaka.media.MediaSourceEngine(
|
|
41
46
|
video,
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
textDisplayer,
|
|
48
|
+
shaka.test.Util.spyFunc(onMetadata));
|
|
49
|
+
const config = shaka.util.PlayerConfiguration.createDefault().mediaSource;
|
|
50
|
+
mediaSourceEngine.configure(config);
|
|
44
51
|
|
|
45
52
|
mediaSource = /** @type {?} */(mediaSourceEngine)['mediaSource_'];
|
|
46
53
|
expect(video.src).toBeTruthy();
|
|
@@ -70,6 +77,18 @@ describe('MediaSourceEngine', () => {
|
|
|
70
77
|
type, segment, reference, /* hasClosedCaptions= */ false);
|
|
71
78
|
}
|
|
72
79
|
|
|
80
|
+
function appendWithSeek(type, segmentNumber) {
|
|
81
|
+
const segment = generators[type]
|
|
82
|
+
.getSegment(segmentNumber, Date.now() / 1000);
|
|
83
|
+
const reference = dummyReference(type, segmentNumber);
|
|
84
|
+
return mediaSourceEngine.appendBuffer(
|
|
85
|
+
type,
|
|
86
|
+
segment,
|
|
87
|
+
reference,
|
|
88
|
+
/* hasClosedCaptions= */ false,
|
|
89
|
+
/* seeked= */ true);
|
|
90
|
+
}
|
|
91
|
+
|
|
73
92
|
function appendInitWithClosedCaptions(type) {
|
|
74
93
|
const segment = generators[type].getInitSegment(Date.now() / 1000);
|
|
75
94
|
const reference = null;
|
|
@@ -371,15 +390,34 @@ describe('MediaSourceEngine', () => {
|
|
|
371
390
|
const initObject = new Map();
|
|
372
391
|
initObject.set(ContentType.VIDEO, getFakeStream(metadata.video));
|
|
373
392
|
initObject.set(ContentType.TEXT, getFakeStream(metadata.text));
|
|
374
|
-
// Call with
|
|
393
|
+
// Call with forceTransmux = true, so that it will transmux even on
|
|
375
394
|
// platforms with native TS support.
|
|
376
|
-
await mediaSourceEngine.init(initObject, /*
|
|
395
|
+
await mediaSourceEngine.init(initObject, /* forceTransmux= */ true);
|
|
377
396
|
mediaSourceEngine.setSelectedClosedCaptionId('CC1');
|
|
378
397
|
await append(ContentType.VIDEO, 0);
|
|
379
398
|
|
|
380
399
|
expect(textDisplayer.appendSpy).toHaveBeenCalledTimes(3);
|
|
381
400
|
});
|
|
382
401
|
|
|
402
|
+
it('extracts CEA-708 captions from previous segment from hls', async () => {
|
|
403
|
+
// Load TS file with CEA-708 captions.
|
|
404
|
+
metadata = shaka.test.TestScheme.DATA['cea-708_ts'];
|
|
405
|
+
generators = shaka.test.TestScheme.GENERATORS['cea-708_ts'];
|
|
406
|
+
|
|
407
|
+
const initObject = new Map();
|
|
408
|
+
initObject.set(ContentType.VIDEO, getFakeStream(metadata.video));
|
|
409
|
+
initObject.set(ContentType.TEXT, getFakeStream(metadata.text));
|
|
410
|
+
// Call with forceTransmux = true, so that it will transmux even on
|
|
411
|
+
// platforms with native TS support.
|
|
412
|
+
await mediaSourceEngine.init(initObject, /* forceTransmux= */ true);
|
|
413
|
+
mediaSourceEngine.setSelectedClosedCaptionId('CC1');
|
|
414
|
+
|
|
415
|
+
await append(ContentType.VIDEO, 2);
|
|
416
|
+
await appendWithSeek(ContentType.VIDEO, 0);
|
|
417
|
+
|
|
418
|
+
expect(textDisplayer.appendSpy).toHaveBeenCalledTimes(6);
|
|
419
|
+
});
|
|
420
|
+
|
|
383
421
|
it('buffers partial TS video segments in sequence mode', async () => {
|
|
384
422
|
metadata = shaka.test.TestScheme.DATA['cea-708_ts'];
|
|
385
423
|
generators = shaka.test.TestScheme.GENERATORS['cea-708_ts'];
|
|
@@ -389,7 +427,7 @@ describe('MediaSourceEngine', () => {
|
|
|
389
427
|
initObject.set(videoType, getFakeStream(metadata.video));
|
|
390
428
|
|
|
391
429
|
await mediaSourceEngine.init(
|
|
392
|
-
initObject, /*
|
|
430
|
+
initObject, /* forceTransmux= */ false, /* sequenceMode= */ true);
|
|
393
431
|
await mediaSourceEngine.setDuration(presentationDuration);
|
|
394
432
|
await mediaSourceEngine.setStreamProperties(
|
|
395
433
|
videoType,
|
|
@@ -424,7 +462,7 @@ describe('MediaSourceEngine', () => {
|
|
|
424
462
|
const initObject = new Map();
|
|
425
463
|
initObject.set(ContentType.VIDEO, getFakeStream(metadata.video));
|
|
426
464
|
|
|
427
|
-
await mediaSourceEngine.init(initObject, /*
|
|
465
|
+
await mediaSourceEngine.init(initObject, /* forceTransmux= */ false);
|
|
428
466
|
await mediaSourceEngine.setDuration(presentationDuration);
|
|
429
467
|
await appendInitWithClosedCaptions(ContentType.VIDEO);
|
|
430
468
|
mediaSourceEngine.setSelectedClosedCaptionId('CC1');
|
|
@@ -432,4 +470,62 @@ describe('MediaSourceEngine', () => {
|
|
|
432
470
|
|
|
433
471
|
expect(textDisplayer.appendSpy).toHaveBeenCalled();
|
|
434
472
|
});
|
|
473
|
+
|
|
474
|
+
it('extracts ID3 metadata from TS', async () => {
|
|
475
|
+
metadata = shaka.test.TestScheme.DATA['id3-metadata_ts'];
|
|
476
|
+
generators = shaka.test.TestScheme.GENERATORS['id3-metadata_ts'];
|
|
477
|
+
|
|
478
|
+
const audioType = ContentType.AUDIO;
|
|
479
|
+
const initObject = new Map();
|
|
480
|
+
initObject.set(audioType, getFakeStream(metadata.audio));
|
|
481
|
+
await mediaSourceEngine.init(initObject, /* forceTransmux= */ false);
|
|
482
|
+
await append(ContentType.AUDIO, 0);
|
|
483
|
+
|
|
484
|
+
expect(onMetadata).toHaveBeenCalled();
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
it('extracts ID3 metadata from TS when transmuxing', async () => {
|
|
488
|
+
metadata = shaka.test.TestScheme.DATA['id3-metadata_ts'];
|
|
489
|
+
generators = shaka.test.TestScheme.GENERATORS['id3-metadata_ts'];
|
|
490
|
+
|
|
491
|
+
const audioType = ContentType.AUDIO;
|
|
492
|
+
const initObject = new Map();
|
|
493
|
+
initObject.set(audioType, getFakeStream(metadata.audio));
|
|
494
|
+
await mediaSourceEngine.init(initObject, /* forceTransmux= */ true);
|
|
495
|
+
await append(ContentType.AUDIO, 0);
|
|
496
|
+
|
|
497
|
+
expect(onMetadata).toHaveBeenCalled();
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
it('extracts ID3 metadata from AAC', async () => {
|
|
501
|
+
if (!MediaSource.isTypeSupported('audio/aac')) {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
metadata = shaka.test.TestScheme.DATA['id3-metadata_aac'];
|
|
505
|
+
generators = shaka.test.TestScheme.GENERATORS['id3-metadata_aac'];
|
|
506
|
+
|
|
507
|
+
const audioType = ContentType.AUDIO;
|
|
508
|
+
const initObject = new Map();
|
|
509
|
+
initObject.set(audioType, getFakeStream(metadata.audio));
|
|
510
|
+
await mediaSourceEngine.init(initObject, /* forceTransmux= */ false);
|
|
511
|
+
await append(ContentType.AUDIO, 0);
|
|
512
|
+
|
|
513
|
+
expect(onMetadata).toHaveBeenCalled();
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
it('extracts ID3 metadata from AAC when transmuxing', async () => {
|
|
517
|
+
if (!MediaSource.isTypeSupported('audio/aac')) {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
metadata = shaka.test.TestScheme.DATA['id3-metadata_aac'];
|
|
521
|
+
generators = shaka.test.TestScheme.GENERATORS['id3-metadata_aac'];
|
|
522
|
+
|
|
523
|
+
const audioType = ContentType.AUDIO;
|
|
524
|
+
const initObject = new Map();
|
|
525
|
+
initObject.set(audioType, getFakeStream(metadata.audio));
|
|
526
|
+
await mediaSourceEngine.init(initObject, /* forceTransmux= */ true);
|
|
527
|
+
await append(ContentType.AUDIO, 0);
|
|
528
|
+
|
|
529
|
+
expect(onMetadata).toHaveBeenCalled();
|
|
530
|
+
});
|
|
435
531
|
});
|
|
@@ -106,7 +106,9 @@ describe('MediaSourceEngine', () => {
|
|
|
106
106
|
shaka.media.Transmuxer = /** @type {?} */ (function() {
|
|
107
107
|
return /** @type {?} */ (mockTransmuxer);
|
|
108
108
|
});
|
|
109
|
-
shaka.media.Transmuxer.
|
|
109
|
+
shaka.media.Transmuxer.convertCodecs = (mimeType, contentType) => {
|
|
110
|
+
return 'video/mp4; codecs="avc1.42E01E"';
|
|
111
|
+
};
|
|
110
112
|
shaka.media.Transmuxer.isSupported = (mimeType, contentType) => {
|
|
111
113
|
return mimeType == 'tsMimetype';
|
|
112
114
|
};
|
|
@@ -150,8 +152,12 @@ describe('MediaSourceEngine', () => {
|
|
|
150
152
|
mockTextDisplayer = new shaka.test.FakeTextDisplayer();
|
|
151
153
|
mediaSourceEngine = new shaka.media.MediaSourceEngine(
|
|
152
154
|
video,
|
|
153
|
-
mockClosedCaptionParser,
|
|
154
155
|
mockTextDisplayer);
|
|
156
|
+
mediaSourceEngine.getCaptionParser = () => {
|
|
157
|
+
return mockClosedCaptionParser;
|
|
158
|
+
};
|
|
159
|
+
const config = shaka.util.PlayerConfiguration.createDefault().mediaSource;
|
|
160
|
+
mediaSourceEngine.configure(config);
|
|
155
161
|
});
|
|
156
162
|
|
|
157
163
|
afterEach(() => {
|
|
@@ -204,7 +210,6 @@ describe('MediaSourceEngine', () => {
|
|
|
204
210
|
it('creates a MediaSource object and sets video.src', () => {
|
|
205
211
|
mediaSourceEngine = new shaka.media.MediaSourceEngine(
|
|
206
212
|
video,
|
|
207
|
-
new shaka.test.FakeClosedCaptionParser(),
|
|
208
213
|
new shaka.test.FakeTextDisplayer());
|
|
209
214
|
|
|
210
215
|
expect(createMediaSourceSpy).toHaveBeenCalled();
|
|
@@ -631,7 +636,7 @@ describe('MediaSourceEngine', () => {
|
|
|
631
636
|
videoSourceBuffer.mode = 'sequence';
|
|
632
637
|
|
|
633
638
|
await mediaSourceEngine.init(
|
|
634
|
-
initObject, /*
|
|
639
|
+
initObject, /* forceTransmux= */ false, /* sequenceMode= */ true);
|
|
635
640
|
|
|
636
641
|
expect(videoSourceBuffer.timestampOffset).toBe(0);
|
|
637
642
|
|
|
@@ -657,7 +662,7 @@ describe('MediaSourceEngine', () => {
|
|
|
657
662
|
initObject.set(ContentType.VIDEO, fakeVideoStream);
|
|
658
663
|
|
|
659
664
|
await mediaSourceEngine.init(
|
|
660
|
-
initObject, /*
|
|
665
|
+
initObject, /* forceTransmux= */ false, /* sequenceMode= */ true);
|
|
661
666
|
|
|
662
667
|
// First, mock the scenario where timestampOffset is set to help align
|
|
663
668
|
// text segments. In this case, SourceBuffer mode is still 'segments'.
|
|
@@ -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
|
|
|
@@ -66,8 +66,10 @@ describe('StreamingEngine', () => {
|
|
|
66
66
|
|
|
67
67
|
mediaSourceEngine = new shaka.media.MediaSourceEngine(
|
|
68
68
|
video,
|
|
69
|
-
new shaka.test.FakeClosedCaptionParser(),
|
|
70
69
|
new shaka.test.FakeTextDisplayer());
|
|
70
|
+
const mediaSourceConfig =
|
|
71
|
+
shaka.util.PlayerConfiguration.createDefault().mediaSource;
|
|
72
|
+
mediaSourceEngine.configure(mediaSourceConfig);
|
|
71
73
|
waiter.setMediaSourceEngine(mediaSourceEngine);
|
|
72
74
|
});
|
|
73
75
|
|
|
@@ -154,6 +156,19 @@ describe('StreamingEngine', () => {
|
|
|
154
156
|
/* presentationDuration= */ Infinity);
|
|
155
157
|
setupPlayhead();
|
|
156
158
|
|
|
159
|
+
// Retry on failure for live streams.
|
|
160
|
+
config.failureCallback = () => streamingEngine.retry(0.1);
|
|
161
|
+
|
|
162
|
+
// Ignore 404 errors in live stream tests.
|
|
163
|
+
onError.and.callFake((error) => {
|
|
164
|
+
if (error.code == shaka.util.Error.Code.BAD_HTTP_STATUS &&
|
|
165
|
+
error.data[1] == 404) {
|
|
166
|
+
// 404 error
|
|
167
|
+
} else {
|
|
168
|
+
fail(error);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
157
172
|
createStreamingEngine();
|
|
158
173
|
}
|
|
159
174
|
|
|
@@ -248,6 +263,7 @@ describe('StreamingEngine', () => {
|
|
|
248
263
|
onSegmentAppended: () => playhead.notifyOfBufferingChange(),
|
|
249
264
|
onInitSegmentAppended: () => {},
|
|
250
265
|
beforeAppendSegment: () => Promise.resolve(),
|
|
266
|
+
onMetadata: () => {},
|
|
251
267
|
};
|
|
252
268
|
streamingEngine = new shaka.media.StreamingEngine(
|
|
253
269
|
/** @type {shaka.extern.Manifest} */(manifest), playerInterface);
|