hls.js 1.5.9 → 1.5.10-0.canary.10320
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/README.md +4 -3
- package/dist/hls-demo.js +41 -38
- package/dist/hls-demo.js.map +1 -1
- package/dist/hls.js +3477 -2194
- package/dist/hls.js.d.ts +108 -85
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +2401 -1754
- 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 +1989 -1315
- 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 +2863 -1557
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/dist/hls.worker.js.map +1 -1
- package/package.json +35 -35
- package/src/config.ts +3 -2
- package/src/controller/abr-controller.ts +24 -20
- package/src/controller/audio-stream-controller.ts +68 -74
- package/src/controller/audio-track-controller.ts +1 -1
- package/src/controller/base-playlist-controller.ts +27 -10
- package/src/controller/base-stream-controller.ts +160 -38
- package/src/controller/buffer-controller.ts +230 -92
- package/src/controller/buffer-operation-queue.ts +16 -19
- package/src/controller/cap-level-controller.ts +3 -2
- package/src/controller/cmcd-controller.ts +51 -14
- package/src/controller/content-steering-controller.ts +29 -15
- package/src/controller/eme-controller.ts +10 -23
- package/src/controller/error-controller.ts +6 -8
- package/src/controller/fps-controller.ts +8 -3
- package/src/controller/fragment-tracker.ts +15 -11
- package/src/controller/gap-controller.ts +43 -16
- package/src/controller/id3-track-controller.ts +7 -7
- package/src/controller/latency-controller.ts +9 -11
- package/src/controller/level-controller.ts +37 -19
- package/src/controller/stream-controller.ts +37 -32
- package/src/controller/subtitle-stream-controller.ts +28 -40
- package/src/controller/subtitle-track-controller.ts +5 -3
- package/src/controller/timeline-controller.ts +19 -21
- package/src/crypt/aes-crypto.ts +21 -2
- package/src/crypt/decrypter-aes-mode.ts +4 -0
- package/src/crypt/decrypter.ts +32 -16
- package/src/crypt/fast-aes-key.ts +28 -5
- package/src/demux/audio/aacdemuxer.ts +2 -2
- package/src/demux/audio/ac3-demuxer.ts +4 -3
- package/src/demux/audio/adts.ts +9 -4
- package/src/demux/audio/base-audio-demuxer.ts +16 -14
- package/src/demux/audio/mp3demuxer.ts +4 -3
- package/src/demux/audio/mpegaudio.ts +1 -1
- package/src/demux/mp4demuxer.ts +7 -7
- package/src/demux/sample-aes.ts +2 -0
- package/src/demux/transmuxer-interface.ts +4 -12
- package/src/demux/transmuxer-worker.ts +4 -4
- package/src/demux/transmuxer.ts +16 -3
- package/src/demux/tsdemuxer.ts +71 -37
- package/src/demux/video/avc-video-parser.ts +208 -119
- package/src/demux/video/base-video-parser.ts +147 -18
- package/src/demux/video/exp-golomb.ts +0 -208
- package/src/demux/video/hevc-video-parser.ts +749 -0
- package/src/empty-es.js +5 -0
- package/src/events.ts +8 -1
- package/src/exports-named.ts +1 -1
- package/src/hls.ts +61 -38
- package/src/loader/fragment-loader.ts +10 -3
- package/src/loader/key-loader.ts +3 -1
- package/src/loader/level-key.ts +10 -9
- package/src/loader/playlist-loader.ts +4 -5
- package/src/remux/mp4-generator.ts +196 -1
- package/src/remux/mp4-remuxer.ts +24 -8
- package/src/task-loop.ts +5 -2
- package/src/types/component-api.ts +3 -1
- package/src/types/demuxer.ts +4 -0
- package/src/types/events.ts +4 -0
- package/src/types/remuxer.ts +1 -1
- package/src/utils/buffer-helper.ts +12 -31
- package/src/utils/cea-608-parser.ts +1 -3
- package/src/utils/codecs.ts +34 -5
- package/src/utils/encryption-methods-util.ts +21 -0
- package/src/utils/fetch-loader.ts +1 -1
- package/src/utils/imsc1-ttml-parser.ts +1 -1
- package/src/utils/keysystem-util.ts +1 -6
- package/src/utils/logger.ts +58 -23
- package/src/utils/mp4-tools.ts +5 -3
- package/src/utils/utf8-utils.ts +18 -0
- package/src/utils/webvtt-parser.ts +1 -1
- package/src/demux/id3.ts +0 -411
@@ -1,12 +1,15 @@
|
|
1
1
|
import TaskLoop from '../task-loop';
|
2
2
|
import { FragmentState } from './fragment-tracker';
|
3
3
|
import { Bufferable, BufferHelper, BufferInfo } from '../utils/buffer-helper';
|
4
|
-
import { logger } from '../utils/logger';
|
5
4
|
import { Events } from '../events';
|
6
5
|
import { ErrorDetails, ErrorTypes } from '../errors';
|
7
6
|
import { ChunkMetadata } from '../types/transmuxer';
|
8
7
|
import { appendUint8Array } from '../utils/mp4-tools';
|
9
8
|
import { alignStream } from '../utils/discontinuities';
|
9
|
+
import {
|
10
|
+
isFullSegmentEncryption,
|
11
|
+
getAesModeFromFullSegmentMethod,
|
12
|
+
} from '../utils/encryption-methods-util';
|
10
13
|
import {
|
11
14
|
findFragmentByPDT,
|
12
15
|
findFragmentByPTS,
|
@@ -97,12 +100,8 @@ export default class BaseStreamController
|
|
97
100
|
protected startFragRequested: boolean = false;
|
98
101
|
protected decrypter: Decrypter;
|
99
102
|
protected initPTS: RationalTimestamp[] = [];
|
100
|
-
protected
|
101
|
-
|
102
|
-
|
103
|
-
private readonly logPrefix: string = '';
|
104
|
-
protected log: (msg: any) => void;
|
105
|
-
protected warn: (msg: any) => void;
|
103
|
+
protected buffering: boolean = true;
|
104
|
+
private loadingParts: boolean = false;
|
106
105
|
|
107
106
|
constructor(
|
108
107
|
hls: Hls,
|
@@ -111,18 +110,32 @@ export default class BaseStreamController
|
|
111
110
|
logPrefix: string,
|
112
111
|
playlistType: PlaylistLevelType,
|
113
112
|
) {
|
114
|
-
super();
|
113
|
+
super(logPrefix, hls.logger);
|
115
114
|
this.playlistType = playlistType;
|
116
|
-
this.logPrefix = logPrefix;
|
117
|
-
this.log = logger.log.bind(logger, `${logPrefix}:`);
|
118
|
-
this.warn = logger.warn.bind(logger, `${logPrefix}:`);
|
119
115
|
this.hls = hls;
|
120
116
|
this.fragmentLoader = new FragmentLoader(hls.config);
|
121
117
|
this.keyLoader = keyLoader;
|
122
118
|
this.fragmentTracker = fragmentTracker;
|
123
119
|
this.config = hls.config;
|
124
120
|
this.decrypter = new Decrypter(hls.config);
|
121
|
+
}
|
122
|
+
|
123
|
+
protected registerListeners() {
|
124
|
+
const { hls } = this;
|
125
|
+
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
126
|
+
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
127
|
+
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
125
128
|
hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
129
|
+
hls.on(Events.ERROR, this.onError, this);
|
130
|
+
}
|
131
|
+
|
132
|
+
protected unregisterListeners() {
|
133
|
+
const { hls } = this;
|
134
|
+
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
135
|
+
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
136
|
+
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
137
|
+
hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
138
|
+
hls.off(Events.ERROR, this.onError, this);
|
126
139
|
}
|
127
140
|
|
128
141
|
protected doTick() {
|
@@ -150,6 +163,14 @@ export default class BaseStreamController
|
|
150
163
|
this.state = State.STOPPED;
|
151
164
|
}
|
152
165
|
|
166
|
+
public pauseBuffering() {
|
167
|
+
this.buffering = false;
|
168
|
+
}
|
169
|
+
|
170
|
+
public resumeBuffering() {
|
171
|
+
this.buffering = true;
|
172
|
+
}
|
173
|
+
|
153
174
|
protected _streamEnded(
|
154
175
|
bufferInfo: BufferInfo,
|
155
176
|
levelDetails: LevelDetails,
|
@@ -197,10 +218,8 @@ export default class BaseStreamController
|
|
197
218
|
data: MediaAttachedData,
|
198
219
|
) {
|
199
220
|
const media = (this.media = this.mediaBuffer = data.media);
|
200
|
-
|
201
|
-
|
202
|
-
media.addEventListener('seeking', this.onvseeking);
|
203
|
-
media.addEventListener('ended', this.onvended);
|
221
|
+
media.addEventListener('seeking', this.onMediaSeeking);
|
222
|
+
media.addEventListener('ended', this.onMediaEnded);
|
204
223
|
const config = this.config;
|
205
224
|
if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
|
206
225
|
this.startLoad(config.startPosition);
|
@@ -215,10 +234,9 @@ export default class BaseStreamController
|
|
215
234
|
}
|
216
235
|
|
217
236
|
// remove video listeners
|
218
|
-
if (media
|
219
|
-
media.removeEventListener('seeking', this.
|
220
|
-
media.removeEventListener('ended', this.
|
221
|
-
this.onvseeking = this.onvended = null;
|
237
|
+
if (media) {
|
238
|
+
media.removeEventListener('seeking', this.onMediaSeeking);
|
239
|
+
media.removeEventListener('ended', this.onMediaEnded);
|
222
240
|
}
|
223
241
|
if (this.keyLoader) {
|
224
242
|
this.keyLoader.detach();
|
@@ -229,7 +247,11 @@ export default class BaseStreamController
|
|
229
247
|
this.stopLoad();
|
230
248
|
}
|
231
249
|
|
232
|
-
protected
|
250
|
+
protected onManifestLoading() {}
|
251
|
+
|
252
|
+
protected onError(event: Events.ERROR, data: ErrorData) {}
|
253
|
+
|
254
|
+
protected onMediaSeeking = () => {
|
233
255
|
const { config, fragCurrent, media, mediaBuffer, state } = this;
|
234
256
|
const currentTime: number = media ? media.currentTime : 0;
|
235
257
|
const bufferInfo = BufferHelper.bufferInfo(
|
@@ -283,6 +305,21 @@ export default class BaseStreamController
|
|
283
305
|
);
|
284
306
|
|
285
307
|
this.lastCurrentTime = currentTime;
|
308
|
+
if (!this.loadingParts) {
|
309
|
+
const bufferEnd = Math.max(bufferInfo.end, currentTime);
|
310
|
+
const shouldLoadParts = this.shouldLoadParts(
|
311
|
+
this.getLevelDetails(),
|
312
|
+
bufferEnd,
|
313
|
+
);
|
314
|
+
if (shouldLoadParts) {
|
315
|
+
this.log(
|
316
|
+
`LL-Part loading ON after seeking to ${currentTime.toFixed(
|
317
|
+
2,
|
318
|
+
)} with buffer @${bufferEnd.toFixed(2)}`,
|
319
|
+
);
|
320
|
+
this.loadingParts = shouldLoadParts;
|
321
|
+
}
|
322
|
+
}
|
286
323
|
}
|
287
324
|
|
288
325
|
// in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
|
@@ -292,12 +329,17 @@ export default class BaseStreamController
|
|
292
329
|
|
293
330
|
// Async tick to speed up processing
|
294
331
|
this.tickImmediate();
|
295
|
-
}
|
332
|
+
};
|
296
333
|
|
297
|
-
protected onMediaEnded() {
|
334
|
+
protected onMediaEnded = () => {
|
298
335
|
// reset startPosition and lastCurrentTime to restart playback @ stream beginning
|
299
336
|
this.startPosition = this.lastCurrentTime = 0;
|
300
|
-
|
337
|
+
if (this.playlistType === PlaylistLevelType.MAIN) {
|
338
|
+
this.hls.trigger(Events.MEDIA_ENDED, {
|
339
|
+
stalled: false,
|
340
|
+
});
|
341
|
+
}
|
342
|
+
};
|
301
343
|
|
302
344
|
protected onManifestLoaded(
|
303
345
|
event: Events.MANIFEST_LOADED,
|
@@ -308,11 +350,10 @@ export default class BaseStreamController
|
|
308
350
|
}
|
309
351
|
|
310
352
|
protected onHandlerDestroying() {
|
311
|
-
this.hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
312
353
|
this.stopLoad();
|
313
354
|
super.onHandlerDestroying();
|
314
355
|
// @ts-ignore
|
315
|
-
this.hls = null;
|
356
|
+
this.hls = this.onMediaSeeking = this.onMediaEnded = null;
|
316
357
|
}
|
317
358
|
|
318
359
|
protected onHandlerDestroyed() {
|
@@ -496,7 +537,7 @@ export default class BaseStreamController
|
|
496
537
|
payload.byteLength > 0 &&
|
497
538
|
decryptData?.key &&
|
498
539
|
decryptData.iv &&
|
499
|
-
decryptData.method
|
540
|
+
isFullSegmentEncryption(decryptData.method)
|
500
541
|
) {
|
501
542
|
const startTime = self.performance.now();
|
502
543
|
// decrypt init segment data
|
@@ -505,6 +546,7 @@ export default class BaseStreamController
|
|
505
546
|
new Uint8Array(payload),
|
506
547
|
decryptData.key.buffer,
|
507
548
|
decryptData.iv.buffer,
|
549
|
+
getAesModeFromFullSegmentMethod(decryptData.method),
|
508
550
|
)
|
509
551
|
.catch((err) => {
|
510
552
|
hls.trigger(Events.ERROR, {
|
@@ -548,7 +590,9 @@ export default class BaseStreamController
|
|
548
590
|
throw new Error('init load aborted, missing levels');
|
549
591
|
}
|
550
592
|
const stats = data.frag.stats;
|
551
|
-
this.state
|
593
|
+
if (this.state !== State.STOPPED) {
|
594
|
+
this.state = State.IDLE;
|
595
|
+
}
|
552
596
|
data.frag.data = new Uint8Array(data.payload);
|
553
597
|
stats.parsing.start = stats.buffering.start = self.performance.now();
|
554
598
|
stats.parsing.end = stats.buffering.end = self.performance.now();
|
@@ -659,7 +703,7 @@ export default class BaseStreamController
|
|
659
703
|
if (frag.encrypted && !frag.decryptdata?.key) {
|
660
704
|
this.log(
|
661
705
|
`Loading key for ${frag.sn} of [${details.startSN}-${details.endSN}], ${
|
662
|
-
this.
|
706
|
+
this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track'
|
663
707
|
} ${frag.level}`,
|
664
708
|
);
|
665
709
|
this.state = State.KEY_LOADING;
|
@@ -683,8 +727,23 @@ export default class BaseStreamController
|
|
683
727
|
this.keyLoader.loadClear(frag, details.encryptedFragments);
|
684
728
|
}
|
685
729
|
|
730
|
+
const fragPrevious = this.fragPrevious;
|
731
|
+
if (
|
732
|
+
frag.sn !== 'initSegment' &&
|
733
|
+
(!fragPrevious || frag.sn !== fragPrevious.sn)
|
734
|
+
) {
|
735
|
+
const shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
|
736
|
+
if (shouldLoadParts !== this.loadingParts) {
|
737
|
+
this.log(
|
738
|
+
`LL-Part loading ${
|
739
|
+
shouldLoadParts ? 'ON' : 'OFF'
|
740
|
+
} loading sn ${fragPrevious?.sn}->${frag.sn}`,
|
741
|
+
);
|
742
|
+
this.loadingParts = shouldLoadParts;
|
743
|
+
}
|
744
|
+
}
|
686
745
|
targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
|
687
|
-
if (this.
|
746
|
+
if (this.loadingParts && frag.sn !== 'initSegment') {
|
688
747
|
const partList = details.partList;
|
689
748
|
if (partList && progressCallback) {
|
690
749
|
if (targetBufferTime > frag.end && details.fragmentHint) {
|
@@ -699,7 +758,7 @@ export default class BaseStreamController
|
|
699
758
|
} of playlist [${details.startSN}-${
|
700
759
|
details.endSN
|
701
760
|
}] parts [0-${partIndex}-${partList.length - 1}] ${
|
702
|
-
this.
|
761
|
+
this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track'
|
703
762
|
}: ${frag.level}, target: ${parseFloat(
|
704
763
|
targetBufferTime.toFixed(3),
|
705
764
|
)}`,
|
@@ -755,10 +814,22 @@ export default class BaseStreamController
|
|
755
814
|
}
|
756
815
|
}
|
757
816
|
|
817
|
+
if (frag.sn !== 'initSegment' && this.loadingParts) {
|
818
|
+
this.log(
|
819
|
+
`LL-Part loading OFF after next part miss @${targetBufferTime.toFixed(
|
820
|
+
2,
|
821
|
+
)}`,
|
822
|
+
);
|
823
|
+
this.loadingParts = false;
|
824
|
+
} else if (!frag.url) {
|
825
|
+
// Selected fragment hint for part but not loading parts
|
826
|
+
return Promise.resolve(null);
|
827
|
+
}
|
828
|
+
|
758
829
|
this.log(
|
759
830
|
`Loading fragment ${frag.sn} cc: ${frag.cc} ${
|
760
831
|
details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : ''
|
761
|
-
}${this.
|
832
|
+
}${this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track'}: ${
|
762
833
|
frag.level
|
763
834
|
}, target: ${parseFloat(targetBufferTime.toFixed(3))}`,
|
764
835
|
);
|
@@ -882,9 +953,50 @@ export default class BaseStreamController
|
|
882
953
|
if (part) {
|
883
954
|
part.stats.parsing.end = now;
|
884
955
|
}
|
956
|
+
// See if part loading should be disabled/enabled based on buffer and playback position.
|
957
|
+
if (frag.sn !== 'initSegment') {
|
958
|
+
const levelDetails = this.getLevelDetails();
|
959
|
+
const loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
|
960
|
+
const shouldLoadParts =
|
961
|
+
loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
|
962
|
+
if (shouldLoadParts !== this.loadingParts) {
|
963
|
+
this.log(
|
964
|
+
`LL-Part loading ${
|
965
|
+
shouldLoadParts ? 'ON' : 'OFF'
|
966
|
+
} after parsing segment ending @${frag.end.toFixed(2)}`,
|
967
|
+
);
|
968
|
+
this.loadingParts = shouldLoadParts;
|
969
|
+
}
|
970
|
+
}
|
971
|
+
|
885
972
|
this.updateLevelTiming(frag, part, level, chunkMeta.partial);
|
886
973
|
}
|
887
974
|
|
975
|
+
private shouldLoadParts(
|
976
|
+
details: LevelDetails | undefined,
|
977
|
+
bufferEnd: number,
|
978
|
+
): boolean {
|
979
|
+
if (this.config.lowLatencyMode) {
|
980
|
+
if (!details) {
|
981
|
+
return this.loadingParts;
|
982
|
+
}
|
983
|
+
if (details?.partList) {
|
984
|
+
// Buffer must be ahead of first part + duration of parts after last segment
|
985
|
+
// and playback must be at or past segment adjacent to part list
|
986
|
+
const firstPart = details.partList[0];
|
987
|
+
const safePartStart =
|
988
|
+
firstPart.end + (details.fragmentHint?.duration || 0);
|
989
|
+
if (
|
990
|
+
bufferEnd >= safePartStart &&
|
991
|
+
this.lastCurrentTime > firstPart.start - firstPart.fragment.duration
|
992
|
+
) {
|
993
|
+
return true;
|
994
|
+
}
|
995
|
+
}
|
996
|
+
}
|
997
|
+
return false;
|
998
|
+
}
|
999
|
+
|
888
1000
|
protected getCurrentContext(
|
889
1001
|
chunkMeta: ChunkMetadata,
|
890
1002
|
): { frag: Fragment; part: Part | null; level: Level } | null {
|
@@ -1001,7 +1113,10 @@ export default class BaseStreamController
|
|
1001
1113
|
// Workaround flaw in getting forward buffer when maxBufferHole is smaller than gap at current pos
|
1002
1114
|
if (bufferInfo.len === 0 && bufferInfo.nextStart !== undefined) {
|
1003
1115
|
const bufferedFragAtPos = this.fragmentTracker.getBufferedFrag(pos, type);
|
1004
|
-
if (
|
1116
|
+
if (
|
1117
|
+
bufferedFragAtPos &&
|
1118
|
+
(bufferInfo.nextStart <= bufferedFragAtPos.end || bufferedFragAtPos.gap)
|
1119
|
+
) {
|
1005
1120
|
return BufferHelper.bufferInfo(
|
1006
1121
|
bufferable,
|
1007
1122
|
pos,
|
@@ -1014,7 +1129,7 @@ export default class BaseStreamController
|
|
1014
1129
|
|
1015
1130
|
protected getMaxBufferLength(levelBitrate?: number): number {
|
1016
1131
|
const { config } = this;
|
1017
|
-
let maxBufLen;
|
1132
|
+
let maxBufLen: number;
|
1018
1133
|
if (levelBitrate) {
|
1019
1134
|
maxBufLen = Math.max(
|
1020
1135
|
(8 * config.maxBufferSize) / levelBitrate,
|
@@ -1067,7 +1182,8 @@ export default class BaseStreamController
|
|
1067
1182
|
// find fragment index, contiguous with end of buffer position
|
1068
1183
|
const { config } = this;
|
1069
1184
|
const start = fragments[0].start;
|
1070
|
-
|
1185
|
+
const canLoadParts = config.lowLatencyMode && !!levelDetails.partList;
|
1186
|
+
let frag: Fragment | null = null;
|
1071
1187
|
|
1072
1188
|
if (levelDetails.live) {
|
1073
1189
|
const initialLiveManifestSize = config.initialLiveManifestSize;
|
@@ -1087,6 +1203,10 @@ export default class BaseStreamController
|
|
1087
1203
|
this.startPosition === -1) ||
|
1088
1204
|
pos < start
|
1089
1205
|
) {
|
1206
|
+
if (canLoadParts && !this.loadingParts) {
|
1207
|
+
this.log(`LL-Part loading ON for initial live fragment`);
|
1208
|
+
this.loadingParts = true;
|
1209
|
+
}
|
1090
1210
|
frag = this.getInitialLiveFragment(levelDetails, fragments);
|
1091
1211
|
this.startPosition = this.nextLoadPosition = frag
|
1092
1212
|
? this.hls.liveSyncPosition || frag.start
|
@@ -1099,7 +1219,7 @@ export default class BaseStreamController
|
|
1099
1219
|
|
1100
1220
|
// If we haven't run into any special cases already, just load the fragment most closely matching the requested position
|
1101
1221
|
if (!frag) {
|
1102
|
-
const end =
|
1222
|
+
const end = this.loadingParts
|
1103
1223
|
? levelDetails.partEnd
|
1104
1224
|
: levelDetails.fragmentEnd;
|
1105
1225
|
frag = this.getFragmentAtPosition(pos, end, levelDetails);
|
@@ -1282,7 +1402,7 @@ export default class BaseStreamController
|
|
1282
1402
|
const partList = levelDetails.partList;
|
1283
1403
|
|
1284
1404
|
const loadingParts = !!(
|
1285
|
-
|
1405
|
+
this.loadingParts &&
|
1286
1406
|
partList?.length &&
|
1287
1407
|
fragmentHint
|
1288
1408
|
);
|
@@ -1561,7 +1681,7 @@ export default class BaseStreamController
|
|
1561
1681
|
errorAction.resolved = true;
|
1562
1682
|
}
|
1563
1683
|
} else {
|
1564
|
-
|
1684
|
+
this.warn(
|
1565
1685
|
`${data.details} reached or exceeded max retry (${retryCount})`,
|
1566
1686
|
);
|
1567
1687
|
return;
|
@@ -1650,7 +1770,9 @@ export default class BaseStreamController
|
|
1650
1770
|
this.log('Reset loading state');
|
1651
1771
|
this.fragCurrent = null;
|
1652
1772
|
this.fragPrevious = null;
|
1653
|
-
this.state
|
1773
|
+
if (this.state !== State.STOPPED) {
|
1774
|
+
this.state = State.IDLE;
|
1775
|
+
}
|
1654
1776
|
}
|
1655
1777
|
|
1656
1778
|
protected resetStartWhenNotLoaded(level: Level | null): void {
|