hls.js 1.6.0-beta.2.0.canary.10924 → 1.6.0-beta.2.0.canary.10926
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 +68 -30
- package/dist/hls.d.ts +68 -30
- package/dist/hls.js +684 -496
- package/dist/hls.js.d.ts +68 -30
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +3882 -3693
- 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 +1140 -954
- 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 +684 -499
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/package.json +1 -1
- package/src/config.ts +15 -9
- package/src/controller/abr-controller.ts +2 -2
- package/src/controller/base-stream-controller.ts +16 -12
- package/src/controller/buffer-controller.ts +19 -22
- package/src/controller/error-controller.ts +2 -2
- package/src/controller/fragment-tracker.ts +1 -1
- package/src/controller/gap-controller.ts +273 -38
- package/src/controller/interstitials-controller.ts +14 -11
- package/src/controller/level-controller.ts +4 -0
- package/src/controller/stream-controller.ts +26 -73
- package/src/hls.ts +57 -3
- package/src/utils/buffer-helper.ts +35 -13
- package/src/utils/event-listener-helper.ts +16 -0
- package/src/utils/rendition-helper.ts +1 -1
@@ -1,7 +1,7 @@
|
|
1
1
|
import BaseStreamController, { State } from './base-stream-controller';
|
2
2
|
import { findFragmentByPTS } from './fragment-finders';
|
3
3
|
import { FragmentState } from './fragment-tracker';
|
4
|
-
import
|
4
|
+
import { MAX_START_GAP_JUMP } from './gap-controller';
|
5
5
|
import TransmuxerInterface from '../demux/transmuxer-interface';
|
6
6
|
import { ErrorDetails } from '../errors';
|
7
7
|
import { Events } from '../events';
|
@@ -11,13 +11,21 @@ import { PlaylistContextType, PlaylistLevelType } from '../types/loader';
|
|
11
11
|
import { ChunkMetadata } from '../types/transmuxer';
|
12
12
|
import { BufferHelper } from '../utils/buffer-helper';
|
13
13
|
import { pickMostCompleteCodecName } from '../utils/codecs';
|
14
|
+
import {
|
15
|
+
addEventListener,
|
16
|
+
removeEventListener,
|
17
|
+
} from '../utils/event-listener-helper';
|
14
18
|
import { useAlternateAudio } from '../utils/rendition-helper';
|
15
19
|
import type { FragmentTracker } from './fragment-tracker';
|
16
20
|
import type Hls from '../hls';
|
17
21
|
import type { Fragment, MediaFragment } from '../loader/fragment';
|
18
22
|
import type KeyLoader from '../loader/key-loader';
|
19
23
|
import type { LevelDetails } from '../loader/level-details';
|
20
|
-
import type {
|
24
|
+
import type {
|
25
|
+
BufferCreatedTrack,
|
26
|
+
ExtendedSourceBuffer,
|
27
|
+
SourceBufferName,
|
28
|
+
} from '../types/buffer';
|
21
29
|
import type { NetworkComponentAPI } from '../types/component-api';
|
22
30
|
import type {
|
23
31
|
AudioTrackSwitchedData,
|
@@ -56,7 +64,6 @@ export default class StreamController
|
|
56
64
|
implements NetworkComponentAPI
|
57
65
|
{
|
58
66
|
private audioCodecSwap: boolean = false;
|
59
|
-
private gapController: GapController | null = null;
|
60
67
|
private level: number = -1;
|
61
68
|
private _forceStartLoad: boolean = false;
|
62
69
|
private _hasEnoughToStart: boolean = false;
|
@@ -67,7 +74,7 @@ export default class StreamController
|
|
67
74
|
private couldBacktrack: boolean = false;
|
68
75
|
private backtrackFragment: Fragment | null = null;
|
69
76
|
private audioCodecSwitch: boolean = false;
|
70
|
-
private videoBuffer:
|
77
|
+
private videoBuffer: ExtendedSourceBuffer | null = null;
|
71
78
|
|
72
79
|
constructor(
|
73
80
|
hls: Hls,
|
@@ -123,7 +130,7 @@ export default class StreamController
|
|
123
130
|
|
124
131
|
protected onHandlerDestroying() {
|
125
132
|
// @ts-ignore
|
126
|
-
this.onMediaPlaying = this.onMediaSeeked =
|
133
|
+
this.onMediaPlaying = this.onMediaSeeked = null;
|
127
134
|
this.unregisterListeners();
|
128
135
|
super.onHandlerDestroying();
|
129
136
|
}
|
@@ -230,7 +237,9 @@ export default class StreamController
|
|
230
237
|
|
231
238
|
protected onTickEnd() {
|
232
239
|
super.onTickEnd();
|
233
|
-
this.
|
240
|
+
if (this.media?.readyState && this.media.seeking === false) {
|
241
|
+
this.lastCurrentTime = this.media.currentTime;
|
242
|
+
}
|
234
243
|
this.checkFragmentChanged();
|
235
244
|
}
|
236
245
|
|
@@ -533,17 +542,8 @@ export default class StreamController
|
|
533
542
|
) {
|
534
543
|
super.onMediaAttached(event, data);
|
535
544
|
const media = data.media;
|
536
|
-
media
|
537
|
-
media
|
538
|
-
media.removeEventListener('waiting', this.onMediaWaiting);
|
539
|
-
media.addEventListener('playing', this.onMediaPlaying);
|
540
|
-
media.addEventListener('seeked', this.onMediaSeeked);
|
541
|
-
media.addEventListener('waiting', this.onMediaWaiting);
|
542
|
-
this.gapController = new GapController(
|
543
|
-
media,
|
544
|
-
this.fragmentTracker,
|
545
|
-
this.hls,
|
546
|
-
);
|
545
|
+
addEventListener(media, 'playing', this.onMediaPlaying);
|
546
|
+
addEventListener(media, 'seeked', this.onMediaSeeked);
|
547
547
|
}
|
548
548
|
|
549
549
|
protected onMediaDetaching(
|
@@ -552,16 +552,11 @@ export default class StreamController
|
|
552
552
|
) {
|
553
553
|
const { media } = this;
|
554
554
|
if (media) {
|
555
|
-
|
556
|
-
|
557
|
-
media.removeEventListener('waiting', this.onMediaWaiting);
|
555
|
+
removeEventListener(media, 'playing', this.onMediaPlaying);
|
556
|
+
removeEventListener(media, 'seeked', this.onMediaSeeked);
|
558
557
|
}
|
559
558
|
this.videoBuffer = null;
|
560
559
|
this.fragPlaying = null;
|
561
|
-
if (this.gapController) {
|
562
|
-
this.gapController.destroy();
|
563
|
-
this.gapController = null;
|
564
|
-
}
|
565
560
|
super.onMediaDetaching(event, data);
|
566
561
|
const transferringMedia = !!data.transferMedia;
|
567
562
|
if (transferringMedia) {
|
@@ -570,20 +565,8 @@ export default class StreamController
|
|
570
565
|
this._hasEnoughToStart = false;
|
571
566
|
}
|
572
567
|
|
573
|
-
private onMediaWaiting = () => {
|
574
|
-
const gapController = this.gapController;
|
575
|
-
if (gapController) {
|
576
|
-
gapController.waiting = self.performance.now();
|
577
|
-
}
|
578
|
-
};
|
579
|
-
|
580
568
|
private onMediaPlaying = () => {
|
581
569
|
// tick to speed up FRAG_CHANGED triggering
|
582
|
-
const gapController = this.gapController;
|
583
|
-
if (gapController) {
|
584
|
-
gapController.ended = 0;
|
585
|
-
gapController.waiting = 0;
|
586
|
-
}
|
587
570
|
this.tick();
|
588
571
|
};
|
589
572
|
|
@@ -609,19 +592,6 @@ export default class StreamController
|
|
609
592
|
this.tick();
|
610
593
|
};
|
611
594
|
|
612
|
-
protected triggerEnded() {
|
613
|
-
const gapController = this.gapController;
|
614
|
-
if (gapController) {
|
615
|
-
if (gapController.ended) {
|
616
|
-
return;
|
617
|
-
}
|
618
|
-
gapController.ended = this.media?.currentTime || 1;
|
619
|
-
}
|
620
|
-
this.hls.trigger(Events.MEDIA_ENDED, {
|
621
|
-
stalled: false,
|
622
|
-
});
|
623
|
-
}
|
624
|
-
|
625
595
|
protected onManifestLoading() {
|
626
596
|
super.onManifestLoading();
|
627
597
|
// reset buffer on manifest loading
|
@@ -935,11 +905,11 @@ export default class StreamController
|
|
935
905
|
data: BufferCreatedData,
|
936
906
|
) {
|
937
907
|
const tracks = data.tracks;
|
938
|
-
let mediaTrack;
|
939
|
-
let name;
|
908
|
+
let mediaTrack: BufferCreatedTrack | undefined;
|
909
|
+
let name: string | undefined;
|
940
910
|
let alternate = false;
|
941
911
|
for (const type in tracks) {
|
942
|
-
const track = tracks[type];
|
912
|
+
const track: BufferCreatedTrack = tracks[type];
|
943
913
|
if (track.id === 'main') {
|
944
914
|
name = type;
|
945
915
|
mediaTrack = track;
|
@@ -1056,25 +1026,6 @@ export default class StreamController
|
|
1056
1026
|
}
|
1057
1027
|
}
|
1058
1028
|
|
1059
|
-
// Checks the health of the buffer and attempts to resolve playback stalls.
|
1060
|
-
private checkBuffer() {
|
1061
|
-
const { media, gapController } = this;
|
1062
|
-
if (!media || !gapController || !media.readyState) {
|
1063
|
-
// Exit early if we don't have media or if the media hasn't buffered anything yet (readyState 0)
|
1064
|
-
return;
|
1065
|
-
}
|
1066
|
-
|
1067
|
-
if (this._hasEnoughToStart || !BufferHelper.getBuffered(media).length) {
|
1068
|
-
// Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
|
1069
|
-
const state = this.state;
|
1070
|
-
const activeFrag = state !== State.IDLE ? this.fragCurrent : null;
|
1071
|
-
const levelDetails = this.getLevelDetails();
|
1072
|
-
gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
|
1073
|
-
}
|
1074
|
-
|
1075
|
-
this.lastCurrentTime = media.currentTime;
|
1076
|
-
}
|
1077
|
-
|
1078
1029
|
private onFragLoadEmergencyAborted() {
|
1079
1030
|
this.state = State.IDLE;
|
1080
1031
|
// if loadedmetadata is not set, it means that we are emergency switch down on first frag
|
@@ -1095,8 +1046,10 @@ export default class StreamController
|
|
1095
1046
|
(type === ElementaryStreamTypes.VIDEO
|
1096
1047
|
? this.videoBuffer
|
1097
1048
|
: this.mediaBuffer) || this.media;
|
1098
|
-
|
1099
|
-
|
1049
|
+
if (mediaBuffer) {
|
1050
|
+
this.afterBufferFlushed(mediaBuffer, type, PlaylistLevelType.MAIN);
|
1051
|
+
this.tick();
|
1052
|
+
}
|
1100
1053
|
}
|
1101
1054
|
}
|
1102
1055
|
|
package/src/hls.ts
CHANGED
@@ -3,6 +3,7 @@ import { EventEmitter } from 'eventemitter3';
|
|
3
3
|
import { buildAbsoluteURL } from 'url-toolkit';
|
4
4
|
import { enableStreamingMode, hlsDefaultConfig, mergeConfig } from './config';
|
5
5
|
import { FragmentTracker } from './controller/fragment-tracker';
|
6
|
+
import GapController from './controller/gap-controller';
|
6
7
|
import ID3TrackController from './controller/id3-track-controller';
|
7
8
|
import LatencyController from './controller/latency-controller';
|
8
9
|
import LevelController from './controller/level-controller';
|
@@ -14,6 +15,7 @@ import KeyLoader from './loader/key-loader';
|
|
14
15
|
import PlaylistLoader from './loader/playlist-loader';
|
15
16
|
import { MetadataSchema } from './types/demuxer';
|
16
17
|
import { type HdcpLevel, isHdcpLevel, type Level } from './types/level';
|
18
|
+
import { PlaylistLevelType } from './types/loader';
|
17
19
|
import { enableLogs, type ILogger } from './utils/logger';
|
18
20
|
import { getMediaDecodingInfoPromise } from './utils/mediacapabilities-helper';
|
19
21
|
import { getMediaSource } from './utils/mediasource-helper';
|
@@ -24,6 +26,7 @@ import type AbrController from './controller/abr-controller';
|
|
24
26
|
import type AudioStreamController from './controller/audio-stream-controller';
|
25
27
|
import type AudioTrackController from './controller/audio-track-controller';
|
26
28
|
import type BasePlaylistController from './controller/base-playlist-controller';
|
29
|
+
import type { InFlightData, State } from './controller/base-stream-controller';
|
27
30
|
import type BaseStreamController from './controller/base-stream-controller';
|
28
31
|
import type BufferController from './controller/buffer-controller';
|
29
32
|
import type CapLevelController from './controller/cap-level-controller';
|
@@ -34,6 +37,7 @@ import type ErrorController from './controller/error-controller';
|
|
34
37
|
import type FPSController from './controller/fps-controller';
|
35
38
|
import type InterstitialsController from './controller/interstitials-controller';
|
36
39
|
import type { InterstitialsManager } from './controller/interstitials-controller';
|
40
|
+
import type { SubtitleStreamController } from './controller/subtitle-stream-controller';
|
37
41
|
import type SubtitleTrackController from './controller/subtitle-track-controller';
|
38
42
|
import type Decrypter from './crypt/decrypter';
|
39
43
|
import type TransmuxerInterface from './demux/transmuxer-interface';
|
@@ -91,9 +95,12 @@ export default class Hls implements HlsEventEmitter {
|
|
91
95
|
private latencyController: LatencyController;
|
92
96
|
private levelController: LevelController;
|
93
97
|
private streamController: StreamController;
|
98
|
+
private audioStreamController?: AudioStreamController;
|
99
|
+
private subtititleStreamController?: SubtitleStreamController;
|
94
100
|
private audioTrackController?: AudioTrackController;
|
95
101
|
private subtitleTrackController?: SubtitleTrackController;
|
96
102
|
private interstitialsController?: InterstitialsController;
|
103
|
+
private gapController: GapController;
|
97
104
|
private emeController?: EMEController;
|
98
105
|
private cmcdController?: CMCDController;
|
99
106
|
private _media: HTMLMediaElement | null = null;
|
@@ -229,6 +236,11 @@ export default class Hls implements HlsEventEmitter {
|
|
229
236
|
keyLoader,
|
230
237
|
));
|
231
238
|
|
239
|
+
const gapController = (this.gapController = new GapController(
|
240
|
+
this,
|
241
|
+
fragmentTracker,
|
242
|
+
));
|
243
|
+
|
232
244
|
// Cap level controller uses streamController to flush the buffer
|
233
245
|
capLevelController.setStreamController(streamController);
|
234
246
|
// fpsController uses streamController to switch when frames are being dropped
|
@@ -250,6 +262,7 @@ export default class Hls implements HlsEventEmitter {
|
|
250
262
|
const coreComponents: ComponentAPI[] = [
|
251
263
|
abrController,
|
252
264
|
bufferController,
|
265
|
+
gapController,
|
253
266
|
capLevelController,
|
254
267
|
fpsController,
|
255
268
|
id3TrackController,
|
@@ -263,7 +276,11 @@ export default class Hls implements HlsEventEmitter {
|
|
263
276
|
const AudioStreamControllerClass = config.audioStreamController;
|
264
277
|
if (AudioStreamControllerClass) {
|
265
278
|
networkControllers.push(
|
266
|
-
new AudioStreamControllerClass(
|
279
|
+
(this.audioStreamController = new AudioStreamControllerClass(
|
280
|
+
this,
|
281
|
+
fragmentTracker,
|
282
|
+
keyLoader,
|
283
|
+
)),
|
267
284
|
);
|
268
285
|
}
|
269
286
|
// Instantiate subtitleTrackController before SubtitleStreamController to receive level events first
|
@@ -274,7 +291,11 @@ export default class Hls implements HlsEventEmitter {
|
|
274
291
|
const SubtitleStreamControllerClass = config.subtitleStreamController;
|
275
292
|
if (SubtitleStreamControllerClass) {
|
276
293
|
networkControllers.push(
|
277
|
-
new SubtitleStreamControllerClass(
|
294
|
+
(this.subtititleStreamController = new SubtitleStreamControllerClass(
|
295
|
+
this,
|
296
|
+
fragmentTracker,
|
297
|
+
keyLoader,
|
298
|
+
)),
|
278
299
|
);
|
279
300
|
}
|
280
301
|
this.createController(config.timelineController, coreComponents);
|
@@ -604,6 +625,21 @@ export default class Hls implements HlsEventEmitter {
|
|
604
625
|
}
|
605
626
|
}
|
606
627
|
|
628
|
+
get inFlightFragments(): InFlightFragments {
|
629
|
+
const inFlightData = {
|
630
|
+
[PlaylistLevelType.MAIN]: this.streamController.inFlightFrag,
|
631
|
+
};
|
632
|
+
if (this.audioStreamController) {
|
633
|
+
inFlightData[PlaylistLevelType.AUDIO] =
|
634
|
+
this.audioStreamController.inFlightFrag;
|
635
|
+
}
|
636
|
+
if (this.subtititleStreamController) {
|
637
|
+
inFlightData[PlaylistLevelType.SUBTITLE] =
|
638
|
+
this.subtititleStreamController.inFlightFrag;
|
639
|
+
}
|
640
|
+
return inFlightData;
|
641
|
+
}
|
642
|
+
|
607
643
|
/**
|
608
644
|
* Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
|
609
645
|
*/
|
@@ -654,10 +690,20 @@ export default class Hls implements HlsEventEmitter {
|
|
654
690
|
return levels ? levels : [];
|
655
691
|
}
|
656
692
|
|
693
|
+
/**
|
694
|
+
* @returns LevelDetails of last loaded level (variant) or `null` prior to loading a media playlist.
|
695
|
+
*/
|
657
696
|
get latestLevelDetails(): LevelDetails | null {
|
658
697
|
return this.streamController.getLevelDetails() || null;
|
659
698
|
}
|
660
699
|
|
700
|
+
/**
|
701
|
+
* @returns Level object of selected level (variant) or `null` prior to selecting a level or once the level is removed.
|
702
|
+
*/
|
703
|
+
get loadLevelObj(): Level | null {
|
704
|
+
return this.levelController.loadLevelObj;
|
705
|
+
}
|
706
|
+
|
661
707
|
/**
|
662
708
|
* Index of quality level (variant) currently played
|
663
709
|
*/
|
@@ -1181,6 +1227,11 @@ export default class Hls implements HlsEventEmitter {
|
|
1181
1227
|
}
|
1182
1228
|
}
|
1183
1229
|
|
1230
|
+
export type InFlightFragments = {
|
1231
|
+
[PlaylistLevelType.MAIN]: InFlightData;
|
1232
|
+
[PlaylistLevelType.AUDIO]?: InFlightData;
|
1233
|
+
[PlaylistLevelType.SUBTITLE]?: InFlightData;
|
1234
|
+
};
|
1184
1235
|
export type {
|
1185
1236
|
AudioSelectionOption,
|
1186
1237
|
SubtitleSelectionOption,
|
@@ -1211,6 +1262,7 @@ export type {
|
|
1211
1262
|
FPSController,
|
1212
1263
|
InterstitialsController,
|
1213
1264
|
StreamController,
|
1265
|
+
SubtitleStreamController,
|
1214
1266
|
SubtitleTrackController,
|
1215
1267
|
EwmaBandWidthEstimator,
|
1216
1268
|
InterstitialsManager,
|
@@ -1219,6 +1271,8 @@ export type {
|
|
1219
1271
|
KeyLoader,
|
1220
1272
|
TaskLoop,
|
1221
1273
|
TransmuxerInterface,
|
1274
|
+
InFlightData,
|
1275
|
+
State,
|
1222
1276
|
};
|
1223
1277
|
export type {
|
1224
1278
|
ABRControllerConfig,
|
@@ -1232,6 +1286,7 @@ export type {
|
|
1232
1286
|
FPSControllerConfig,
|
1233
1287
|
FragmentLoaderConfig,
|
1234
1288
|
FragmentLoaderConstructor,
|
1289
|
+
GapControllerConfig,
|
1235
1290
|
HlsLoadPolicies,
|
1236
1291
|
LevelControllerConfig,
|
1237
1292
|
LoaderConfig,
|
@@ -1270,7 +1325,6 @@ export type {
|
|
1270
1325
|
InterstitialScheduleItem,
|
1271
1326
|
InterstitialSchedulePrimaryItem,
|
1272
1327
|
} from './controller/interstitials-schedule';
|
1273
|
-
export type { SubtitleStreamController } from './controller/subtitle-stream-controller';
|
1274
1328
|
export type { TimelineController } from './controller/timeline-controller';
|
1275
1329
|
export type { DecrypterAesMode } from './crypt/decrypter-aes-mode';
|
1276
1330
|
export type { DateRange, DateRangeCue } from './loader/date-range';
|
@@ -23,6 +23,7 @@ export type BufferInfo = {
|
|
23
23
|
end: number;
|
24
24
|
nextStart?: number;
|
25
25
|
buffered?: BufferTimeRange[];
|
26
|
+
bufferedIndex: number;
|
26
27
|
};
|
27
28
|
|
28
29
|
const noopBuffered: TimeRanges = {
|
@@ -47,22 +48,34 @@ export class BufferHelper {
|
|
47
48
|
return false;
|
48
49
|
}
|
49
50
|
|
51
|
+
static bufferedRanges(media: Bufferable | null): BufferTimeRange[] {
|
52
|
+
if (media) {
|
53
|
+
const timeRanges = BufferHelper.getBuffered(media);
|
54
|
+
return BufferHelper.timeRangesToArray(timeRanges);
|
55
|
+
}
|
56
|
+
return [];
|
57
|
+
}
|
58
|
+
|
59
|
+
static timeRangesToArray(timeRanges: TimeRanges): BufferTimeRange[] {
|
60
|
+
const buffered: BufferTimeRange[] = [];
|
61
|
+
for (let i = 0; i < timeRanges.length; i++) {
|
62
|
+
buffered.push({ start: timeRanges.start(i), end: timeRanges.end(i) });
|
63
|
+
}
|
64
|
+
return buffered;
|
65
|
+
}
|
66
|
+
|
50
67
|
static bufferInfo(
|
51
68
|
media: Bufferable | null,
|
52
69
|
pos: number,
|
53
70
|
maxHoleDuration: number,
|
54
71
|
): BufferInfo {
|
55
72
|
if (media) {
|
56
|
-
const
|
57
|
-
if (
|
58
|
-
const buffered: BufferTimeRange[] = [];
|
59
|
-
for (let i = 0; i < vbuffered.length; i++) {
|
60
|
-
buffered.push({ start: vbuffered.start(i), end: vbuffered.end(i) });
|
61
|
-
}
|
73
|
+
const buffered = BufferHelper.bufferedRanges(media);
|
74
|
+
if (buffered.length) {
|
62
75
|
return BufferHelper.bufferedInfo(buffered, pos, maxHoleDuration);
|
63
76
|
}
|
64
77
|
}
|
65
|
-
return { len: 0, start: pos, end: pos };
|
78
|
+
return { len: 0, start: pos, end: pos, bufferedIndex: -1 };
|
66
79
|
}
|
67
80
|
|
68
81
|
static bufferedInfo(
|
@@ -72,14 +85,20 @@ export class BufferHelper {
|
|
72
85
|
): BufferInfo {
|
73
86
|
pos = Math.max(0, pos);
|
74
87
|
// sort on buffer.start/smaller end (IE does not always return sorted buffered range)
|
75
|
-
buffered.
|
88
|
+
if (buffered.length > 1) {
|
89
|
+
buffered.sort((a, b) => a.start - b.start || b.end - a.end);
|
90
|
+
}
|
76
91
|
|
92
|
+
let bufferedIndex: number = -1;
|
77
93
|
let buffered2: BufferTimeRange[] = [];
|
78
94
|
if (maxHoleDuration) {
|
79
95
|
// there might be some small holes between buffer time range
|
80
96
|
// consider that holes smaller than maxHoleDuration are irrelevant and build another
|
81
97
|
// buffer time range representations that discards those holes
|
82
98
|
for (let i = 0; i < buffered.length; i++) {
|
99
|
+
if (pos >= buffered[i].start && pos <= buffered[i].end) {
|
100
|
+
bufferedIndex = i;
|
101
|
+
}
|
83
102
|
const buf2len = buffered2.length;
|
84
103
|
if (buf2len) {
|
85
104
|
const buf2end = buffered2[buf2len - 1].end;
|
@@ -107,23 +126,25 @@ export class BufferHelper {
|
|
107
126
|
|
108
127
|
let bufferLen = 0;
|
109
128
|
|
110
|
-
|
111
|
-
let bufferStartNext: number | undefined;
|
129
|
+
let nextStart: number | undefined;
|
112
130
|
|
113
|
-
// bufferStart and bufferEnd are buffer boundaries around current
|
131
|
+
// bufferStart and bufferEnd are buffer boundaries around current playback position (pos)
|
114
132
|
let bufferStart: number = pos;
|
115
133
|
let bufferEnd: number = pos;
|
116
134
|
for (let i = 0; i < buffered2.length; i++) {
|
117
135
|
const start = buffered2[i].start;
|
118
136
|
const end = buffered2[i].end;
|
119
137
|
// logger.log('buf start/end:' + buffered.start(i) + '/' + buffered.end(i));
|
138
|
+
if (bufferedIndex === -1 && pos >= start && pos <= end) {
|
139
|
+
bufferedIndex = i;
|
140
|
+
}
|
120
141
|
if (pos + maxHoleDuration >= start && pos < end) {
|
121
142
|
// play position is inside this buffer TimeRange, retrieve end of buffer position and buffer length
|
122
143
|
bufferStart = start;
|
123
144
|
bufferEnd = end;
|
124
145
|
bufferLen = bufferEnd - pos;
|
125
146
|
} else if (pos + maxHoleDuration < start) {
|
126
|
-
|
147
|
+
nextStart = start;
|
127
148
|
break;
|
128
149
|
}
|
129
150
|
}
|
@@ -131,8 +152,9 @@ export class BufferHelper {
|
|
131
152
|
len: bufferLen,
|
132
153
|
start: bufferStart || 0,
|
133
154
|
end: bufferEnd || 0,
|
134
|
-
nextStart
|
155
|
+
nextStart,
|
135
156
|
buffered,
|
157
|
+
bufferedIndex,
|
136
158
|
};
|
137
159
|
}
|
138
160
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
export function addEventListener(
|
2
|
+
el: HTMLElement,
|
3
|
+
type: string,
|
4
|
+
listener: EventListenerOrEventListenerObject,
|
5
|
+
) {
|
6
|
+
removeEventListener(el, type, listener);
|
7
|
+
el.addEventListener(type, listener);
|
8
|
+
}
|
9
|
+
|
10
|
+
export function removeEventListener(
|
11
|
+
el: HTMLElement,
|
12
|
+
type: string,
|
13
|
+
listener: EventListenerOrEventListenerObject,
|
14
|
+
) {
|
15
|
+
el.removeEventListener(type, listener);
|
16
|
+
}
|
@@ -502,5 +502,5 @@ export function useAlternateAudio(
|
|
502
502
|
audioTrackUrl: string | undefined,
|
503
503
|
hls: Hls,
|
504
504
|
): boolean {
|
505
|
-
return !!audioTrackUrl && audioTrackUrl !== hls.
|
505
|
+
return !!audioTrackUrl && audioTrackUrl !== hls.loadLevelObj?.uri;
|
506
506
|
}
|