hls.js 1.6.0-beta.3.0.canary.10981 → 1.6.0-beta.3.0.canary.10984
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/dist/hls.d.mts +15 -6
- package/dist/hls.d.ts +15 -6
- package/dist/hls.js +182 -120
- package/dist/hls.js.d.ts +15 -6
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +7 -5
- package/dist/hls.light.js.map +1 -1
- package/dist/hls.light.min.js +1 -1
- package/dist/hls.light.min.js.map +1 -1
- package/dist/hls.light.mjs +7 -5
- package/dist/hls.light.mjs.map +1 -1
- package/dist/hls.min.js +1 -1
- package/dist/hls.min.js.map +1 -1
- package/dist/hls.mjs +144 -83
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/package.json +2 -2
- package/src/config.ts +4 -4
- package/src/controller/base-stream-controller.ts +2 -2
- package/src/controller/id3-track-controller.ts +1 -1
- package/src/controller/interstitial-player.ts +15 -5
- package/src/controller/interstitials-controller.ts +146 -84
- package/src/controller/stream-controller.ts +8 -6
- package/src/define-plugin.d.ts +1 -1
- package/src/hls.ts +4 -1
- package/src/loader/interstitial-event.ts +2 -2
@@ -461,7 +461,7 @@ class ID3TrackController implements ComponentAPI {
|
|
461
461
|
this.id3Track.addCue(cue);
|
462
462
|
cues[key] = cue;
|
463
463
|
if (
|
464
|
-
|
464
|
+
__USE_INTERSTITIALS__ &&
|
465
465
|
this.hls.config.interstitialsController
|
466
466
|
) {
|
467
467
|
if (key === 'X-ASSET-LIST' || key === 'X-ASSET-URL') {
|
@@ -9,9 +9,17 @@ import {
|
|
9
9
|
} from '../loader/interstitial-event';
|
10
10
|
import { BufferHelper } from '../utils/buffer-helper';
|
11
11
|
import type { HlsConfig } from '../config';
|
12
|
+
import type { InterstitialScheduleEventItem } from '../controller/interstitials-schedule';
|
12
13
|
import type Hls from '../hls';
|
13
14
|
import type { BufferCodecsData, MediaAttachingData } from '../types/events';
|
14
15
|
|
16
|
+
export interface InterstitialPlayer {
|
17
|
+
currentTime: number;
|
18
|
+
duration: number;
|
19
|
+
assetPlayers: (HlsAssetPlayer | null)[];
|
20
|
+
playingIndex: number;
|
21
|
+
scheduleItem: InterstitialScheduleEventItem | null;
|
22
|
+
}
|
15
23
|
export class HlsAssetPlayer {
|
16
24
|
public readonly hls: Hls;
|
17
25
|
public readonly interstitial: InterstitialEvent;
|
@@ -19,7 +27,6 @@ export class HlsAssetPlayer {
|
|
19
27
|
public tracks: Partial<BufferCodecsData> | null = null;
|
20
28
|
private hasDetails: boolean = false;
|
21
29
|
private mediaAttached: HTMLMediaElement | null = null;
|
22
|
-
private playoutOffset: number = 0;
|
23
30
|
|
24
31
|
constructor(
|
25
32
|
HlsPlayerClass: typeof Hls,
|
@@ -49,8 +56,6 @@ export class HlsAssetPlayer {
|
|
49
56
|
this.mediaAttached = media;
|
50
57
|
const event = this.interstitial;
|
51
58
|
if (event.playoutLimit) {
|
52
|
-
this.playoutOffset =
|
53
|
-
event.assetList[event.assetList.indexOf(assetItem)]?.startOffset || 0;
|
54
59
|
media.addEventListener('timeupdate', this.checkPlayout);
|
55
60
|
}
|
56
61
|
});
|
@@ -59,7 +64,8 @@ export class HlsAssetPlayer {
|
|
59
64
|
private checkPlayout = () => {
|
60
65
|
const interstitial = this.interstitial;
|
61
66
|
const playoutLimit = interstitial.playoutLimit;
|
62
|
-
|
67
|
+
const currentTime = this.currentTime;
|
68
|
+
if (this.startOffset + currentTime >= playoutLimit) {
|
63
69
|
this.hls.trigger(Events.PLAYOUT_LIMIT_REACHED, {});
|
64
70
|
}
|
65
71
|
};
|
@@ -98,7 +104,7 @@ export class HlsAssetPlayer {
|
|
98
104
|
}
|
99
105
|
|
100
106
|
get duration(): number {
|
101
|
-
const duration = this.assetItem
|
107
|
+
const duration = this.assetItem.duration;
|
102
108
|
if (!duration) {
|
103
109
|
return 0;
|
104
110
|
}
|
@@ -113,6 +119,10 @@ export class HlsAssetPlayer {
|
|
113
119
|
return Math.max(0, duration - this.currentTime);
|
114
120
|
}
|
115
121
|
|
122
|
+
get startOffset(): number {
|
123
|
+
return this.assetItem.startOffset;
|
124
|
+
}
|
125
|
+
|
116
126
|
get timelineOffset(): number {
|
117
127
|
return this.hls?.config.timelineOffset || 0;
|
118
128
|
}
|
@@ -31,6 +31,7 @@ import { Logger } from '../utils/logger';
|
|
31
31
|
import { isCompatibleTrackChange } from '../utils/mediasource-helper';
|
32
32
|
import { getBasicSelectionOption } from '../utils/rendition-helper';
|
33
33
|
import { stringify } from '../utils/safe-json-stringify';
|
34
|
+
import type { InterstitialPlayer } from './interstitial-player';
|
34
35
|
import type { HlsConfig } from '../config';
|
35
36
|
import type Hls from '../hls';
|
36
37
|
import type { LevelDetails } from '../loader/level-details';
|
@@ -55,18 +56,16 @@ import type { MediaPlaylist, MediaSelection } from '../types/media-playlist';
|
|
55
56
|
|
56
57
|
export interface InterstitialsManager {
|
57
58
|
events: InterstitialEvent[];
|
58
|
-
playerQueue: HlsAssetPlayer[];
|
59
59
|
schedule: InterstitialScheduleItem[];
|
60
|
-
|
60
|
+
interstitialPlayer: InterstitialPlayer | null;
|
61
|
+
playerQueue: HlsAssetPlayer[];
|
61
62
|
bufferingAsset: InterstitialAssetItem | null;
|
62
63
|
bufferingItem: InterstitialScheduleItem | null;
|
63
64
|
bufferingIndex: number;
|
64
65
|
playingAsset: InterstitialAssetItem | null;
|
65
66
|
playingItem: InterstitialScheduleItem | null;
|
66
67
|
playingIndex: number;
|
67
|
-
waitingIndex: number;
|
68
68
|
primary: PlayheadTimes;
|
69
|
-
playout: PlayheadTimes;
|
70
69
|
integrated: PlayheadTimes;
|
71
70
|
skip: () => void;
|
72
71
|
}
|
@@ -76,7 +75,6 @@ export type PlayheadTimes = {
|
|
76
75
|
currentTime: number;
|
77
76
|
duration: number;
|
78
77
|
seekableStart: number;
|
79
|
-
seekTo: (time: number) => void;
|
80
78
|
};
|
81
79
|
|
82
80
|
function playWithCatch(media: HTMLMediaElement | null) {
|
@@ -122,7 +120,9 @@ export default class InterstitialsController
|
|
122
120
|
private playingItem: InterstitialScheduleItem | null = null;
|
123
121
|
private bufferingItem: InterstitialScheduleItem | null = null;
|
124
122
|
private waitingItem: InterstitialScheduleEventItem | null = null;
|
123
|
+
private endedItem: InterstitialScheduleItem | null = null;
|
125
124
|
private playingAsset: InterstitialAssetItem | null = null;
|
125
|
+
private endedAsset: InterstitialAssetItem | null = null;
|
126
126
|
private bufferingAsset: InterstitialAssetItem | null = null;
|
127
127
|
private shouldPlay: boolean = false;
|
128
128
|
|
@@ -259,7 +259,7 @@ export default class InterstitialsController
|
|
259
259
|
event: Events.MEDIA_ATTACHED,
|
260
260
|
data: MediaAttachedData,
|
261
261
|
) {
|
262
|
-
const playingItem = this.
|
262
|
+
const playingItem = this.effectivePlayingItem;
|
263
263
|
const detachedMedia = this.detachedData;
|
264
264
|
this.detachedData = null;
|
265
265
|
if (playingItem === null) {
|
@@ -276,7 +276,9 @@ export default class InterstitialsController
|
|
276
276
|
this.playingItem =
|
277
277
|
this.bufferingItem =
|
278
278
|
this.waitingItem =
|
279
|
+
this.endedItem =
|
279
280
|
this.playingAsset =
|
281
|
+
this.endedAsset =
|
280
282
|
this.bufferingAsset =
|
281
283
|
null;
|
282
284
|
}
|
@@ -298,11 +300,13 @@ export default class InterstitialsController
|
|
298
300
|
if (this.detachedData) {
|
299
301
|
const player = this.getBufferingPlayer();
|
300
302
|
if (player) {
|
301
|
-
this.playingAsset =
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
303
|
+
this.playingAsset =
|
304
|
+
this.endedAsset =
|
305
|
+
this.bufferingAsset =
|
306
|
+
this.bufferingItem =
|
307
|
+
this.waitingItem =
|
308
|
+
this.detachedData =
|
309
|
+
null;
|
306
310
|
player.detachMedia();
|
307
311
|
}
|
308
312
|
this.shouldPlay = false;
|
@@ -311,12 +315,11 @@ export default class InterstitialsController
|
|
311
315
|
|
312
316
|
public get interstitialsManager(): InterstitialsManager | null {
|
313
317
|
if (!this.manager) {
|
314
|
-
if (!this.hls
|
318
|
+
if (!this.hls) {
|
315
319
|
return null;
|
316
320
|
}
|
317
321
|
const c = this;
|
318
322
|
const effectiveBufferingItem = () => c.bufferingItem || c.waitingItem;
|
319
|
-
const effectivePlayingItem = () => c.playingItem || c.waitingItem;
|
320
323
|
const getAssetPlayer = (asset: InterstitialAssetItem | null) =>
|
321
324
|
asset ? c.getAssetPlayer(asset.identifier) : asset;
|
322
325
|
const getMappedTime = (
|
@@ -375,7 +378,7 @@ export default class InterstitialsController
|
|
375
378
|
if (value === Number.MAX_VALUE) {
|
376
379
|
return getMappedDuration('primary');
|
377
380
|
}
|
378
|
-
return value;
|
381
|
+
return Math.max(value, 0);
|
379
382
|
};
|
380
383
|
const getMappedDuration = (timelineType: TimelineType): number => {
|
381
384
|
if (c.primaryDetails?.live) {
|
@@ -385,12 +388,12 @@ export default class InterstitialsController
|
|
385
388
|
return c.schedule.durations[timelineType];
|
386
389
|
};
|
387
390
|
const seekTo = (time: number, timelineType: TimelineType) => {
|
388
|
-
const item = effectivePlayingItem
|
391
|
+
const item = c.effectivePlayingItem;
|
389
392
|
if (item?.event?.restrictions.skip) {
|
390
393
|
return;
|
391
394
|
}
|
392
395
|
c.log(`seek to ${time} "${timelineType}"`);
|
393
|
-
const playingItem = effectivePlayingItem
|
396
|
+
const playingItem = c.effectivePlayingItem;
|
394
397
|
const targetIndex = c.schedule.findItemIndexAtTime(time, timelineType);
|
395
398
|
const targetItem = c.schedule.items?.[targetIndex];
|
396
399
|
const playingInterstitial = playingItem?.event;
|
@@ -399,7 +402,7 @@ export default class InterstitialsController
|
|
399
402
|
if (playingItem && (appendInPlace || seekInItem)) {
|
400
403
|
// seek in asset player or primary media (appendInPlace)
|
401
404
|
const assetPlayer = getAssetPlayer(c.playingAsset);
|
402
|
-
const media = assetPlayer?.media || c.
|
405
|
+
const media = assetPlayer?.media || c.primaryMedia;
|
403
406
|
if (media) {
|
404
407
|
const currentTime =
|
405
408
|
timelineType === 'primary'
|
@@ -481,6 +484,68 @@ export default class InterstitialsController
|
|
481
484
|
}
|
482
485
|
}
|
483
486
|
};
|
487
|
+
const getActiveInterstitial = () => {
|
488
|
+
const playingItem = c.effectivePlayingItem;
|
489
|
+
if (c.isInterstitial(playingItem)) {
|
490
|
+
return playingItem;
|
491
|
+
}
|
492
|
+
const bufferingItem = effectiveBufferingItem();
|
493
|
+
if (c.isInterstitial(bufferingItem)) {
|
494
|
+
return bufferingItem;
|
495
|
+
}
|
496
|
+
return null;
|
497
|
+
};
|
498
|
+
const interstitialPlayer: InterstitialPlayer = {
|
499
|
+
get currentTime() {
|
500
|
+
const interstitialItem = getActiveInterstitial();
|
501
|
+
const playingItem = c.effectivePlayingItem;
|
502
|
+
if (playingItem && playingItem === interstitialItem) {
|
503
|
+
return (
|
504
|
+
getMappedTime(
|
505
|
+
playingItem,
|
506
|
+
'playout',
|
507
|
+
c.effectivePlayingAsset,
|
508
|
+
'timelinePos',
|
509
|
+
'currentTime',
|
510
|
+
) - playingItem.playout.start
|
511
|
+
);
|
512
|
+
}
|
513
|
+
return 0;
|
514
|
+
},
|
515
|
+
set currentTime(time: number) {
|
516
|
+
const interstitialItem = getActiveInterstitial();
|
517
|
+
const playingItem = c.effectivePlayingItem;
|
518
|
+
if (playingItem && playingItem === interstitialItem) {
|
519
|
+
seekTo(time + playingItem.playout.start, 'playout');
|
520
|
+
}
|
521
|
+
},
|
522
|
+
get duration() {
|
523
|
+
const interstitialItem = getActiveInterstitial();
|
524
|
+
if (interstitialItem) {
|
525
|
+
return (
|
526
|
+
interstitialItem.playout.end - interstitialItem.playout.start
|
527
|
+
);
|
528
|
+
}
|
529
|
+
return 0;
|
530
|
+
},
|
531
|
+
get assetPlayers() {
|
532
|
+
const assetList = getActiveInterstitial()?.event.assetList;
|
533
|
+
if (assetList) {
|
534
|
+
return assetList.map((asset) => c.getAssetPlayer(asset.identifier));
|
535
|
+
}
|
536
|
+
return [];
|
537
|
+
},
|
538
|
+
get playingIndex() {
|
539
|
+
const interstitial = getActiveInterstitial()?.event;
|
540
|
+
if (interstitial && c.effectivePlayingAsset) {
|
541
|
+
return interstitial.findAssetIndex(c.effectivePlayingAsset);
|
542
|
+
}
|
543
|
+
return -1;
|
544
|
+
},
|
545
|
+
get scheduleItem() {
|
546
|
+
return getActiveInterstitial();
|
547
|
+
},
|
548
|
+
};
|
484
549
|
this.manager = {
|
485
550
|
get events() {
|
486
551
|
return c.schedule?.events?.slice(0) || [];
|
@@ -488,80 +553,56 @@ export default class InterstitialsController
|
|
488
553
|
get schedule() {
|
489
554
|
return c.schedule?.items?.slice(0) || [];
|
490
555
|
},
|
556
|
+
get interstitialPlayer() {
|
557
|
+
if (getActiveInterstitial()) {
|
558
|
+
return interstitialPlayer;
|
559
|
+
}
|
560
|
+
return null;
|
561
|
+
},
|
491
562
|
get playerQueue() {
|
492
563
|
return c.playerQueue.slice(0);
|
493
564
|
},
|
494
|
-
get bufferingPlayer() {
|
495
|
-
return c.getBufferingPlayer();
|
496
|
-
},
|
497
565
|
get bufferingAsset() {
|
498
566
|
return c.bufferingAsset;
|
499
567
|
},
|
500
568
|
get bufferingItem() {
|
501
|
-
return
|
502
|
-
},
|
503
|
-
get playingAsset() {
|
504
|
-
return c.playingAsset;
|
505
|
-
},
|
506
|
-
get playingItem() {
|
507
|
-
return c.playingItem;
|
569
|
+
return effectiveBufferingItem();
|
508
570
|
},
|
509
571
|
get bufferingIndex() {
|
510
572
|
const item = effectiveBufferingItem();
|
511
573
|
return c.findItemIndex(item);
|
512
574
|
},
|
575
|
+
get playingAsset() {
|
576
|
+
return c.effectivePlayingAsset;
|
577
|
+
},
|
578
|
+
get playingItem() {
|
579
|
+
return c.effectivePlayingItem;
|
580
|
+
},
|
513
581
|
get playingIndex() {
|
514
|
-
const item = effectivePlayingItem
|
582
|
+
const item = c.effectivePlayingItem;
|
515
583
|
return c.findItemIndex(item);
|
516
584
|
},
|
517
|
-
get waitingIndex() {
|
518
|
-
return c.findItemIndex(c.waitingItem);
|
519
|
-
},
|
520
585
|
primary: {
|
521
586
|
get bufferedEnd() {
|
522
587
|
return getBufferedEnd();
|
523
588
|
},
|
524
589
|
get currentTime() {
|
525
590
|
const timelinePos = c.timelinePos;
|
591
|
+
const playingItem = c.effectivePlayingItem;
|
592
|
+
if (playingItem?.event?.appendInPlace) {
|
593
|
+
return playingItem.start;
|
594
|
+
}
|
526
595
|
return timelinePos > 0 ? timelinePos : 0;
|
527
596
|
},
|
597
|
+
set currentTime(time: number) {
|
598
|
+
seekTo(time, 'primary');
|
599
|
+
},
|
528
600
|
get duration() {
|
529
601
|
return getMappedDuration('primary');
|
530
602
|
},
|
531
603
|
get seekableStart() {
|
532
604
|
return c.primaryDetails?.fragmentStart || 0;
|
533
605
|
},
|
534
|
-
seekTo: (time) => seekTo(time, 'primary'),
|
535
|
-
},
|
536
|
-
playout: {
|
537
|
-
get bufferedEnd() {
|
538
|
-
return getMappedTime(
|
539
|
-
effectiveBufferingItem(),
|
540
|
-
'playout',
|
541
|
-
c.bufferingAsset,
|
542
|
-
'bufferedPos',
|
543
|
-
'bufferedEnd',
|
544
|
-
);
|
545
|
-
},
|
546
|
-
get currentTime() {
|
547
|
-
return getMappedTime(
|
548
|
-
effectivePlayingItem(),
|
549
|
-
'playout',
|
550
|
-
c.playingAsset,
|
551
|
-
'timelinePos',
|
552
|
-
'currentTime',
|
553
|
-
);
|
554
|
-
},
|
555
|
-
get duration() {
|
556
|
-
return getMappedDuration('playout');
|
557
|
-
},
|
558
|
-
get seekableStart() {
|
559
|
-
return findMappedTime(
|
560
|
-
c.primaryDetails?.fragmentStart || 0,
|
561
|
-
'playout',
|
562
|
-
);
|
563
|
-
},
|
564
|
-
seekTo: (time) => seekTo(time, 'playout'),
|
565
606
|
},
|
566
607
|
integrated: {
|
567
608
|
get bufferedEnd() {
|
@@ -575,13 +616,16 @@ export default class InterstitialsController
|
|
575
616
|
},
|
576
617
|
get currentTime() {
|
577
618
|
return getMappedTime(
|
578
|
-
effectivePlayingItem
|
619
|
+
c.effectivePlayingItem,
|
579
620
|
'integrated',
|
580
|
-
c.
|
621
|
+
c.effectivePlayingAsset,
|
581
622
|
'timelinePos',
|
582
623
|
'currentTime',
|
583
624
|
);
|
584
625
|
},
|
626
|
+
set currentTime(time: number) {
|
627
|
+
seekTo(time, 'integrated');
|
628
|
+
},
|
585
629
|
get duration() {
|
586
630
|
return getMappedDuration('integrated');
|
587
631
|
},
|
@@ -591,10 +635,9 @@ export default class InterstitialsController
|
|
591
635
|
'integrated',
|
592
636
|
);
|
593
637
|
},
|
594
|
-
seekTo: (time) => seekTo(time, 'integrated'),
|
595
638
|
},
|
596
639
|
skip: () => {
|
597
|
-
const item = effectivePlayingItem
|
640
|
+
const item = c.effectivePlayingItem;
|
598
641
|
const event = item?.event;
|
599
642
|
if (event && !event.restrictions.skip) {
|
600
643
|
const index = c.findItemIndex(item);
|
@@ -612,6 +655,14 @@ export default class InterstitialsController
|
|
612
655
|
}
|
613
656
|
|
614
657
|
// Schedule getters
|
658
|
+
private get effectivePlayingItem(): InterstitialScheduleItem | null {
|
659
|
+
return this.waitingItem || this.playingItem || this.endedItem;
|
660
|
+
}
|
661
|
+
|
662
|
+
private get effectivePlayingAsset(): InterstitialAssetItem | null {
|
663
|
+
return this.playingAsset || this.endedAsset;
|
664
|
+
}
|
665
|
+
|
615
666
|
private get playingLastItem(): boolean {
|
616
667
|
const playingItem = this.playingItem;
|
617
668
|
const items = this.schedule?.items;
|
@@ -623,7 +674,7 @@ export default class InterstitialsController
|
|
623
674
|
}
|
624
675
|
|
625
676
|
private get playbackStarted(): boolean {
|
626
|
-
return this.
|
677
|
+
return this.effectivePlayingItem !== null;
|
627
678
|
}
|
628
679
|
|
629
680
|
// Media getters and event callbacks
|
@@ -828,6 +879,7 @@ MediaSource ${stringify(attachMediaSourceData)} from ${logFromSource}`,
|
|
828
879
|
if (this.playingLastItem && this.isInterstitial(playingItem)) {
|
829
880
|
const restartAsset = playingItem.event.assetList[0];
|
830
881
|
if (restartAsset) {
|
882
|
+
this.endedItem = this.playingItem;
|
831
883
|
this.playingItem = null;
|
832
884
|
this.setScheduleToAssetAtTime(currentTime, restartAsset);
|
833
885
|
}
|
@@ -899,7 +951,7 @@ MediaSource ${stringify(attachMediaSourceData)} from ${logFromSource}`,
|
|
899
951
|
}
|
900
952
|
// Start stepping through schedule when playback begins for the first time and we have a pre-roll
|
901
953
|
const timelinePos = this.timelinePos;
|
902
|
-
const
|
954
|
+
const effectivePlayingItem = this.effectivePlayingItem;
|
903
955
|
if (timelinePos === -1) {
|
904
956
|
const startPosition = this.hls.startPosition;
|
905
957
|
this.timelinePos = startPosition;
|
@@ -912,8 +964,8 @@ MediaSource ${stringify(attachMediaSourceData)} from ${logFromSource}`,
|
|
912
964
|
const index = schedule.findItemIndexAtTime(start);
|
913
965
|
this.setSchedulePosition(index);
|
914
966
|
}
|
915
|
-
} else if (
|
916
|
-
const index = schedule.findItemIndex(
|
967
|
+
} else if (effectivePlayingItem && !this.playingItem) {
|
968
|
+
const index = schedule.findItemIndex(effectivePlayingItem);
|
917
969
|
this.setSchedulePosition(index);
|
918
970
|
}
|
919
971
|
}
|
@@ -986,11 +1038,12 @@ MediaSource ${stringify(attachMediaSourceData)} from ${logFromSource}`,
|
|
986
1038
|
(assetListIndex !== undefined &&
|
987
1039
|
assetId !== interstitial.assetList?.[assetListIndex].identifier))
|
988
1040
|
) {
|
989
|
-
this.playingAsset = null;
|
990
1041
|
const assetListIndex = interstitial.findAssetIndex(playingAsset);
|
991
1042
|
this.log(
|
992
1043
|
`INTERSTITIAL_ASSET_ENDED ${assetListIndex + 1}/${interstitial.assetList.length} ${eventAssetToString(playingAsset)}`,
|
993
1044
|
);
|
1045
|
+
this.endedAsset = playingAsset;
|
1046
|
+
this.playingAsset = null;
|
994
1047
|
this.hls.trigger(Events.INTERSTITIAL_ASSET_ENDED, {
|
995
1048
|
asset: playingAsset,
|
996
1049
|
assetListIndex,
|
@@ -1003,9 +1056,9 @@ MediaSource ${stringify(attachMediaSourceData)} from ${logFromSource}`,
|
|
1003
1056
|
if (player.media && !this.detachedData) {
|
1004
1057
|
player.detachMedia();
|
1005
1058
|
}
|
1006
|
-
this.clearAssetPlayer(assetId, scheduledItem);
|
1007
1059
|
}
|
1008
1060
|
if (!this.eventItemsMatch(currentItem, scheduledItem)) {
|
1061
|
+
this.endedItem = currentItem;
|
1009
1062
|
this.playingItem = null;
|
1010
1063
|
this.log(
|
1011
1064
|
`INTERSTITIAL_ENDED ${interstitial} ${segmentToString(currentItem)}`,
|
@@ -1085,7 +1138,7 @@ MediaSource ${stringify(attachMediaSourceData)} from ${logFromSource}`,
|
|
1085
1138
|
const waitingItem = this.waitingItem;
|
1086
1139
|
this.setBufferingItem(scheduledItem);
|
1087
1140
|
let player = this.preloadAssets(interstitial, assetListIndex);
|
1088
|
-
if (!this.eventItemsMatch(scheduledItem,
|
1141
|
+
if (!this.eventItemsMatch(scheduledItem, waitingItem || currentItem)) {
|
1089
1142
|
this.waitingItem = scheduledItem;
|
1090
1143
|
this.log(
|
1091
1144
|
`INTERSTITIAL_STARTED ${segmentToString(scheduledItem)} ${interstitial.appendInPlace ? 'append in place' : ''}`,
|
@@ -1113,7 +1166,7 @@ MediaSource ${stringify(attachMediaSourceData)} from ${logFromSource}`,
|
|
1113
1166
|
return;
|
1114
1167
|
}
|
1115
1168
|
// Update schedule and asset list position now that it can start
|
1116
|
-
this.waitingItem = null;
|
1169
|
+
this.waitingItem = this.endedItem = null;
|
1117
1170
|
this.playingItem = scheduledItem;
|
1118
1171
|
|
1119
1172
|
// If asset-list is empty or missing asset index, advance to next item
|
@@ -1173,6 +1226,7 @@ MediaSource ${stringify(attachMediaSourceData)} from ${logFromSource}`,
|
|
1173
1226
|
} else if (playedLastItem && this.isInterstitial(currentItem)) {
|
1174
1227
|
// Maintain playingItem state at end of schedule (setSchedulePosition(-1) called to end program)
|
1175
1228
|
// this allows onSeeking handler to update schedule position
|
1229
|
+
this.endedItem = null;
|
1176
1230
|
this.playingItem = currentItem;
|
1177
1231
|
if (!currentItem.event.appendInPlace) {
|
1178
1232
|
// Media must be re-attached to resume primary schedule if not sharing source
|
@@ -1199,8 +1253,8 @@ MediaSource ${stringify(attachMediaSourceData)} from ${logFromSource}`,
|
|
1199
1253
|
fromItem: InterstitialScheduleItem | null,
|
1200
1254
|
) {
|
1201
1255
|
this.playingItem = scheduledItem;
|
1202
|
-
this.playingAsset = null;
|
1203
|
-
this.waitingItem = null;
|
1256
|
+
this.playingAsset = this.endedAsset = null;
|
1257
|
+
this.waitingItem = this.endedItem = null;
|
1204
1258
|
|
1205
1259
|
this.bufferedToItem(scheduledItem);
|
1206
1260
|
|
@@ -1345,7 +1399,7 @@ MediaSource ${stringify(attachMediaSourceData)} from ${logFromSource}`,
|
|
1345
1399
|
this.mediaSelection = currentSelection;
|
1346
1400
|
this.schedule.parseInterstitialDateRanges(currentSelection);
|
1347
1401
|
|
1348
|
-
if (!this.
|
1402
|
+
if (!this.effectivePlayingItem && this.schedule.items) {
|
1349
1403
|
this.checkStart();
|
1350
1404
|
}
|
1351
1405
|
}
|
@@ -1420,7 +1474,7 @@ MediaSource ${stringify(attachMediaSourceData)} from ${logFromSource}`,
|
|
1420
1474
|
event: Events.BUFFER_FLUSHED,
|
1421
1475
|
data: BufferFlushedData,
|
1422
1476
|
) {
|
1423
|
-
const
|
1477
|
+
const playingItem = this.playingItem;
|
1424
1478
|
if (
|
1425
1479
|
playingItem &&
|
1426
1480
|
!this.itemsMatch(playingItem, this.bufferingItem) &&
|
@@ -1519,7 +1573,12 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
|
|
1519
1573
|
const updatedPlayingItem = this.updateItem(playingItem, this.timelinePos);
|
1520
1574
|
if (this.itemsMatch(playingItem, updatedPlayingItem)) {
|
1521
1575
|
this.playingItem = updatedPlayingItem;
|
1576
|
+
this.waitingItem = this.endedItem = null;
|
1522
1577
|
}
|
1578
|
+
} else {
|
1579
|
+
// Clear waitingItem if it has been removed from the schedule
|
1580
|
+
this.waitingItem = this.updateItem(this.waitingItem);
|
1581
|
+
this.endedItem = this.updateItem(this.endedItem);
|
1523
1582
|
}
|
1524
1583
|
// Do not replace Interstitial bufferingItem without a match - used for transfering media element or source
|
1525
1584
|
const bufferingItem = this.bufferingItem;
|
@@ -1536,8 +1595,6 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
|
|
1536
1595
|
this.clearInterstitial(bufferingItem.event, null);
|
1537
1596
|
}
|
1538
1597
|
}
|
1539
|
-
// Clear waitingItem if it has been removed from the schedule
|
1540
|
-
this.waitingItem = this.updateItem(this.waitingItem);
|
1541
1598
|
|
1542
1599
|
removedInterstitials.forEach((interstitial) => {
|
1543
1600
|
interstitial.assetList.forEach((asset) => {
|
@@ -1727,7 +1784,12 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
|
|
1727
1784
|
if (!this.playbackDisabled) {
|
1728
1785
|
if (isInterstitial) {
|
1729
1786
|
// primary fragment loading will exit early in base-stream-controller while `bufferingItem` is set to an Interstitial block
|
1730
|
-
|
1787
|
+
item.event.assetList.forEach((asset) => {
|
1788
|
+
const player = this.getAssetPlayer(asset.identifier);
|
1789
|
+
if (player) {
|
1790
|
+
player.resumeBuffering();
|
1791
|
+
}
|
1792
|
+
});
|
1731
1793
|
} else {
|
1732
1794
|
this.hls.resumeBuffering();
|
1733
1795
|
this.playerQueue.forEach((player) => player.pauseBuffering());
|
@@ -1815,7 +1877,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
|
|
1815
1877
|
);
|
1816
1878
|
const timelineStart = interstitial.timelineStart;
|
1817
1879
|
if (interstitial.appendInPlace) {
|
1818
|
-
this.flushFrontBuffer(timelineStart);
|
1880
|
+
this.flushFrontBuffer(timelineStart + 0.25);
|
1819
1881
|
}
|
1820
1882
|
const uri = interstitial.assetUrl;
|
1821
1883
|
if (uri) {
|
@@ -2181,6 +2243,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
|
|
2181
2243
|
const assetListLength = interstitial.assetList.length;
|
2182
2244
|
|
2183
2245
|
const playingAsset = this.playingAsset;
|
2246
|
+
this.endedAsset = null;
|
2184
2247
|
this.playingAsset = assetItem;
|
2185
2248
|
if (!playingAsset || playingAsset.identifier !== assetId) {
|
2186
2249
|
if (playingAsset) {
|
@@ -2194,7 +2257,6 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
|
|
2194
2257
|
this.log(
|
2195
2258
|
`INTERSTITIAL_ASSET_STARTED ${assetListIndex + 1}/${assetListLength} ${player}`,
|
2196
2259
|
);
|
2197
|
-
// player.resumeBuffering();
|
2198
2260
|
this.hls.trigger(Events.INTERSTITIAL_ASSET_STARTED, {
|
2199
2261
|
asset: assetItem,
|
2200
2262
|
assetListIndex,
|
@@ -2317,7 +2379,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))}`,
|
|
2317
2379
|
private primaryFallback(interstitial: InterstitialEvent) {
|
2318
2380
|
// Fallback to Primary by on current or future events by updating schedule to skip errored interstitials/assets
|
2319
2381
|
const flushStart = interstitial.timelineStart;
|
2320
|
-
const playingItem = this.
|
2382
|
+
const playingItem = this.effectivePlayingItem;
|
2321
2383
|
// Update schedule now that interstitial/assets are flagged with `error` for fallback
|
2322
2384
|
this.updateSchedule();
|
2323
2385
|
if (playingItem) {
|
@@ -160,7 +160,7 @@ export default class StreamController
|
|
160
160
|
// hls.nextLoadLevel remains until it is set to a new value or until a new frag is successfully loaded
|
161
161
|
hls.nextLoadLevel = startLevel;
|
162
162
|
this.level = hls.loadLevel;
|
163
|
-
this._hasEnoughToStart =
|
163
|
+
this._hasEnoughToStart = !!skipSeekToStartPosition;
|
164
164
|
}
|
165
165
|
// if startPosition undefined but lastCurrentTime set, set startPosition to last currentTime
|
166
166
|
if (
|
@@ -975,7 +975,7 @@ export default class StreamController
|
|
975
975
|
if (!media) {
|
976
976
|
return;
|
977
977
|
}
|
978
|
-
if (!this._hasEnoughToStart && media.
|
978
|
+
if (!this._hasEnoughToStart && BufferHelper.getBuffered(media).length) {
|
979
979
|
this._hasEnoughToStart = true;
|
980
980
|
this.seekToStartPos();
|
981
981
|
}
|
@@ -1492,10 +1492,12 @@ export default class StreamController
|
|
1492
1492
|
}
|
1493
1493
|
|
1494
1494
|
public getMainFwdBufferInfo(): BufferInfo | null {
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1498
|
-
|
1495
|
+
// Observe video SourceBuffer (this.mediaBuffer) only when alt-audio is used, otherwise observe combined media buffer
|
1496
|
+
const bufferOutput =
|
1497
|
+
this.mediaBuffer && this.altAudio === AlternateAudio.SWITCHED
|
1498
|
+
? this.mediaBuffer
|
1499
|
+
: this.media;
|
1500
|
+
return this.getFwdBufferInfo(bufferOutput, PlaylistLevelType.MAIN);
|
1499
1501
|
}
|
1500
1502
|
|
1501
1503
|
public get maxBufferLength(): number {
|
package/src/define-plugin.d.ts
CHANGED
@@ -9,7 +9,7 @@ declare const __USE_CONTENT_STEERING__: boolean;
|
|
9
9
|
declare const __USE_VARIABLE_SUBSTITUTION__: boolean;
|
10
10
|
declare const __USE_M2TS_ADVANCED_CODECS__: boolean;
|
11
11
|
declare const __USE_MEDIA_CAPABILITIES__: boolean;
|
12
|
-
declare const
|
12
|
+
declare const __USE_INTERSTITIALS__: boolean;
|
13
13
|
|
14
14
|
// __IN_WORKER__ is provided from a closure call around the final UMD bundle.
|
15
15
|
declare const __IN_WORKER__: boolean;
|
package/src/hls.ts
CHANGED
@@ -1324,7 +1324,10 @@ export type {
|
|
1324
1324
|
ErrorActionFlags,
|
1325
1325
|
IErrorAction,
|
1326
1326
|
} from './controller/error-controller';
|
1327
|
-
export type {
|
1327
|
+
export type {
|
1328
|
+
HlsAssetPlayer,
|
1329
|
+
InterstitialPlayer,
|
1330
|
+
} from './controller/interstitial-player';
|
1328
1331
|
export type { PlayheadTimes } from './controller/interstitials-controller';
|
1329
1332
|
export type {
|
1330
1333
|
InterstitialScheduleDurations,
|
@@ -38,8 +38,8 @@ export type InterstitialAssetItem = {
|
|
38
38
|
parentIdentifier: InterstitialId;
|
39
39
|
identifier: InterstitialAssetId;
|
40
40
|
duration: number | null;
|
41
|
-
startOffset: number;
|
42
|
-
timelineStart: number;
|
41
|
+
startOffset: number; // asset start offset from start of interstitial event
|
42
|
+
timelineStart: number; // asset start on media element timeline
|
43
43
|
uri: string;
|
44
44
|
error?: Error;
|
45
45
|
};
|