hls.js 1.5.7-0.canary.10015 → 1.5.7-0.canary.10016
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.js +276 -161
- package/dist/hls.js.d.ts +13 -6
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +259 -128
- 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 +200 -71
- 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 +217 -104
- 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 +1 -1
- package/src/controller/abr-controller.ts +3 -0
- package/src/controller/audio-stream-controller.ts +26 -38
- package/src/controller/base-stream-controller.ts +5 -2
- package/src/controller/buffer-controller.ts +192 -56
- package/src/controller/buffer-operation-queue.ts +16 -19
- package/src/controller/fragment-tracker.ts +15 -11
- package/src/controller/stream-controller.ts +9 -0
- package/src/controller/subtitle-stream-controller.ts +1 -15
- package/src/hls.ts +7 -3
- package/src/utils/codecs.ts +1 -1
package/dist/hls.light.mjs
CHANGED
@@ -512,7 +512,7 @@ function enableLogs(debugConfig, context, id) {
|
|
512
512
|
// Some browsers don't allow to use bind on console object anyway
|
513
513
|
// fallback to default if needed
|
514
514
|
try {
|
515
|
-
newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.5.7-0.canary.
|
515
|
+
newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.5.7-0.canary.10016"}`);
|
516
516
|
} catch (e) {
|
517
517
|
/* log fn threw an exception. All logger methods are no-ops. */
|
518
518
|
return createLogger();
|
@@ -6595,6 +6595,9 @@ class AbrController extends Logger {
|
|
6595
6595
|
partCurrent,
|
6596
6596
|
hls
|
6597
6597
|
} = this;
|
6598
|
+
if (hls.levels.length <= 1) {
|
6599
|
+
return hls.loadLevel;
|
6600
|
+
}
|
6598
6601
|
const {
|
6599
6602
|
maxAutoLevel,
|
6600
6603
|
config,
|
@@ -6949,24 +6952,22 @@ class BufferOperationQueue {
|
|
6949
6952
|
this.executeNext(type);
|
6950
6953
|
}
|
6951
6954
|
}
|
6952
|
-
insertAbort(operation, type) {
|
6953
|
-
const queue = this.queues[type];
|
6954
|
-
queue.unshift(operation);
|
6955
|
-
this.executeNext(type);
|
6956
|
-
}
|
6957
6955
|
appendBlocker(type) {
|
6958
|
-
|
6959
|
-
|
6960
|
-
|
6956
|
+
return new Promise(resolve => {
|
6957
|
+
const operation = {
|
6958
|
+
execute: resolve,
|
6959
|
+
onStart: () => {},
|
6960
|
+
onComplete: () => {},
|
6961
|
+
onError: () => {}
|
6962
|
+
};
|
6963
|
+
this.append(operation, type);
|
6961
6964
|
});
|
6962
|
-
|
6963
|
-
|
6964
|
-
|
6965
|
-
|
6966
|
-
|
6967
|
-
}
|
6968
|
-
this.append(operation, type);
|
6969
|
-
return promise;
|
6965
|
+
}
|
6966
|
+
unblockAudio(op) {
|
6967
|
+
const queue = this.queues.audio;
|
6968
|
+
if (queue[0] === op) {
|
6969
|
+
this.shiftAndExecuteNext('audio');
|
6970
|
+
}
|
6970
6971
|
}
|
6971
6972
|
executeNext(type) {
|
6972
6973
|
const queue = this.queues[type];
|
@@ -6999,7 +7000,7 @@ class BufferOperationQueue {
|
|
6999
7000
|
|
7000
7001
|
const VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
|
7001
7002
|
class BufferController extends Logger {
|
7002
|
-
constructor(hls) {
|
7003
|
+
constructor(hls, fragmentTracker) {
|
7003
7004
|
super('buffer-controller', hls.logger);
|
7004
7005
|
// The level details used to determine duration, target-duration and live
|
7005
7006
|
this.details = null;
|
@@ -7010,6 +7011,7 @@ class BufferController extends Logger {
|
|
7010
7011
|
// References to event listeners for each SourceBuffer, so that they can be referenced for event removal
|
7011
7012
|
this.listeners = void 0;
|
7012
7013
|
this.hls = void 0;
|
7014
|
+
this.fragmentTracker = void 0;
|
7013
7015
|
// The number of BUFFER_CODEC events received before any sourceBuffers are created
|
7014
7016
|
this.bufferCodecEventsExpected = 0;
|
7015
7017
|
// The total number of BUFFER_CODEC events received
|
@@ -7020,6 +7022,10 @@ class BufferController extends Logger {
|
|
7020
7022
|
this.mediaSource = null;
|
7021
7023
|
// Last MP3 audio chunk appended
|
7022
7024
|
this.lastMpegAudioChunk = null;
|
7025
|
+
// Audio fragment blocked from appending until corresponding video appends or context changes
|
7026
|
+
this.blockedAudioAppend = null;
|
7027
|
+
// Keep track of video append position for unblocking audio
|
7028
|
+
this.lastVideoAppendEnd = 0;
|
7023
7029
|
this.appendSource = void 0;
|
7024
7030
|
// counters
|
7025
7031
|
this.appendErrors = {
|
@@ -7051,7 +7057,10 @@ class BufferController extends Logger {
|
|
7051
7057
|
this.log('Media source opened');
|
7052
7058
|
if (media) {
|
7053
7059
|
media.removeEventListener('emptied', this._onMediaEmptied);
|
7054
|
-
this.
|
7060
|
+
const durationAndRange = this.getDurationAndRange();
|
7061
|
+
if (durationAndRange) {
|
7062
|
+
this.updateMediaSource(durationAndRange);
|
7063
|
+
}
|
7055
7064
|
this.hls.trigger(Events.MEDIA_ATTACHED, {
|
7056
7065
|
media,
|
7057
7066
|
mediaSource: mediaSource
|
@@ -7079,6 +7088,7 @@ class BufferController extends Logger {
|
|
7079
7088
|
}
|
7080
7089
|
};
|
7081
7090
|
this.hls = hls;
|
7091
|
+
this.fragmentTracker = fragmentTracker;
|
7082
7092
|
this.appendSource = hls.config.preferManagedMediaSource;
|
7083
7093
|
this._initSourceBuffer();
|
7084
7094
|
this.registerListeners();
|
@@ -7091,7 +7101,7 @@ class BufferController extends Logger {
|
|
7091
7101
|
this.details = null;
|
7092
7102
|
this.lastMpegAudioChunk = null;
|
7093
7103
|
// @ts-ignore
|
7094
|
-
this.hls = null;
|
7104
|
+
this.hls = this.fragmentTracker = null;
|
7095
7105
|
// @ts-ignore
|
7096
7106
|
this._onMediaSourceOpen = this._onMediaSourceClose = null;
|
7097
7107
|
// @ts-ignore
|
@@ -7147,6 +7157,8 @@ class BufferController extends Logger {
|
|
7147
7157
|
audiovideo: 0
|
7148
7158
|
};
|
7149
7159
|
this.lastMpegAudioChunk = null;
|
7160
|
+
this.blockedAudioAppend = null;
|
7161
|
+
this.lastVideoAppendEnd = 0;
|
7150
7162
|
}
|
7151
7163
|
onManifestLoading() {
|
7152
7164
|
this.bufferCodecEventsExpected = this._bufferCodecEventsTotal = 0;
|
@@ -7284,9 +7296,10 @@ class BufferController extends Logger {
|
|
7284
7296
|
const trackNames = Object.keys(data);
|
7285
7297
|
trackNames.forEach(trackName => {
|
7286
7298
|
if (sourceBufferCount) {
|
7299
|
+
var _track$buffer;
|
7287
7300
|
// check if SourceBuffer codec needs to change
|
7288
7301
|
const track = this.tracks[trackName];
|
7289
|
-
if (track && typeof track.buffer.changeType === 'function') {
|
7302
|
+
if (track && typeof ((_track$buffer = track.buffer) == null ? void 0 : _track$buffer.changeType) === 'function') {
|
7290
7303
|
var _trackCodec;
|
7291
7304
|
const {
|
7292
7305
|
id,
|
@@ -7356,20 +7369,54 @@ class BufferController extends Logger {
|
|
7356
7369
|
};
|
7357
7370
|
operationQueue.append(operation, type, !!this.pendingTracks[type]);
|
7358
7371
|
}
|
7372
|
+
blockAudio(partOrFrag) {
|
7373
|
+
var _this$fragmentTracker;
|
7374
|
+
const pStart = partOrFrag.start;
|
7375
|
+
const pTime = pStart + partOrFrag.duration * 0.05;
|
7376
|
+
const atGap = ((_this$fragmentTracker = this.fragmentTracker.getAppendedFrag(pStart, PlaylistLevelType.MAIN)) == null ? void 0 : _this$fragmentTracker.gap) === true;
|
7377
|
+
if (atGap) {
|
7378
|
+
return;
|
7379
|
+
}
|
7380
|
+
const op = {
|
7381
|
+
execute: () => {
|
7382
|
+
var _this$fragmentTracker2;
|
7383
|
+
if (this.lastVideoAppendEnd > pTime || this.sourceBuffer.video && BufferHelper.isBuffered(this.sourceBuffer.video, pTime) || ((_this$fragmentTracker2 = this.fragmentTracker.getAppendedFrag(pTime, PlaylistLevelType.MAIN)) == null ? void 0 : _this$fragmentTracker2.gap) === true) {
|
7384
|
+
this.blockedAudioAppend = null;
|
7385
|
+
this.operationQueue.shiftAndExecuteNext('audio');
|
7386
|
+
}
|
7387
|
+
},
|
7388
|
+
onStart: () => {},
|
7389
|
+
onComplete: () => {},
|
7390
|
+
onError: () => {}
|
7391
|
+
};
|
7392
|
+
this.blockedAudioAppend = {
|
7393
|
+
op,
|
7394
|
+
frag: partOrFrag
|
7395
|
+
};
|
7396
|
+
this.operationQueue.append(op, 'audio', true);
|
7397
|
+
}
|
7398
|
+
unblockAudio() {
|
7399
|
+
const blockedAudioAppend = this.blockedAudioAppend;
|
7400
|
+
if (blockedAudioAppend) {
|
7401
|
+
this.blockedAudioAppend = null;
|
7402
|
+
this.operationQueue.unblockAudio(blockedAudioAppend.op);
|
7403
|
+
}
|
7404
|
+
}
|
7359
7405
|
onBufferAppending(event, eventData) {
|
7360
7406
|
const {
|
7361
|
-
hls,
|
7362
7407
|
operationQueue,
|
7363
7408
|
tracks
|
7364
7409
|
} = this;
|
7365
7410
|
const {
|
7366
7411
|
data,
|
7367
7412
|
type,
|
7413
|
+
parent,
|
7368
7414
|
frag,
|
7369
7415
|
part,
|
7370
7416
|
chunkMeta
|
7371
7417
|
} = eventData;
|
7372
7418
|
const chunkStats = chunkMeta.buffering[type];
|
7419
|
+
const sn = frag.sn;
|
7373
7420
|
const bufferAppendingStart = self.performance.now();
|
7374
7421
|
chunkStats.start = bufferAppendingStart;
|
7375
7422
|
const fragBuffering = frag.stats.buffering;
|
@@ -7392,7 +7439,36 @@ class BufferController extends Logger {
|
|
7392
7439
|
checkTimestampOffset = !this.lastMpegAudioChunk || chunkMeta.id === 1 || this.lastMpegAudioChunk.sn !== chunkMeta.sn;
|
7393
7440
|
this.lastMpegAudioChunk = chunkMeta;
|
7394
7441
|
}
|
7395
|
-
|
7442
|
+
|
7443
|
+
// Block audio append until overlapping video append
|
7444
|
+
const videoSb = this.sourceBuffer.video;
|
7445
|
+
if (videoSb && sn !== 'initSegment') {
|
7446
|
+
const partOrFrag = part || frag;
|
7447
|
+
const blockedAudioAppend = this.blockedAudioAppend;
|
7448
|
+
if (type === 'audio' && parent !== 'main' && !this.blockedAudioAppend) {
|
7449
|
+
const pStart = partOrFrag.start;
|
7450
|
+
const pTime = pStart + partOrFrag.duration * 0.05;
|
7451
|
+
const vbuffered = videoSb.buffered;
|
7452
|
+
const vappending = this.operationQueue.current('video');
|
7453
|
+
if (!vbuffered.length && !vappending) {
|
7454
|
+
// wait for video before appending audio
|
7455
|
+
this.blockAudio(partOrFrag);
|
7456
|
+
} else if (!vappending && !BufferHelper.isBuffered(videoSb, pTime) && this.lastVideoAppendEnd < pTime) {
|
7457
|
+
// audio is ahead of video
|
7458
|
+
this.blockAudio(partOrFrag);
|
7459
|
+
}
|
7460
|
+
} else if (type === 'video') {
|
7461
|
+
const videoAppendEnd = partOrFrag.end;
|
7462
|
+
if (blockedAudioAppend) {
|
7463
|
+
const audioStart = blockedAudioAppend.frag.start;
|
7464
|
+
if (videoAppendEnd > audioStart || videoAppendEnd < this.lastVideoAppendEnd || BufferHelper.isBuffered(videoSb, audioStart)) {
|
7465
|
+
this.unblockAudio();
|
7466
|
+
}
|
7467
|
+
}
|
7468
|
+
this.lastVideoAppendEnd = videoAppendEnd;
|
7469
|
+
}
|
7470
|
+
}
|
7471
|
+
const fragStart = (part || frag).start;
|
7396
7472
|
const operation = {
|
7397
7473
|
execute: () => {
|
7398
7474
|
chunkStats.executeStart = self.performance.now();
|
@@ -7401,7 +7477,7 @@ class BufferController extends Logger {
|
|
7401
7477
|
if (sb) {
|
7402
7478
|
const delta = fragStart - sb.timestampOffset;
|
7403
7479
|
if (Math.abs(delta) >= 0.1) {
|
7404
|
-
this.log(`Updating audio SourceBuffer timestampOffset to ${fragStart} (delta: ${delta}) sn: ${
|
7480
|
+
this.log(`Updating audio SourceBuffer timestampOffset to ${fragStart} (delta: ${delta}) sn: ${sn})`);
|
7405
7481
|
sb.timestampOffset = fragStart;
|
7406
7482
|
}
|
7407
7483
|
}
|
@@ -7468,22 +7544,21 @@ class BufferController extends Logger {
|
|
7468
7544
|
/* with UHD content, we could get loop of quota exceeded error until
|
7469
7545
|
browser is able to evict some data from sourcebuffer. Retrying can help recover.
|
7470
7546
|
*/
|
7471
|
-
this.warn(`Failed ${appendErrorCount}/${hls.config.appendErrorMaxRetry} times to append segment in "${type}" sourceBuffer`);
|
7472
|
-
if (appendErrorCount >= hls.config.appendErrorMaxRetry) {
|
7547
|
+
this.warn(`Failed ${appendErrorCount}/${this.hls.config.appendErrorMaxRetry} times to append segment in "${type}" sourceBuffer`);
|
7548
|
+
if (appendErrorCount >= this.hls.config.appendErrorMaxRetry) {
|
7473
7549
|
event.fatal = true;
|
7474
7550
|
}
|
7475
7551
|
}
|
7476
|
-
hls.trigger(Events.ERROR, event);
|
7552
|
+
this.hls.trigger(Events.ERROR, event);
|
7477
7553
|
}
|
7478
7554
|
};
|
7479
7555
|
operationQueue.append(operation, type, !!this.pendingTracks[type]);
|
7480
7556
|
}
|
7481
|
-
|
7482
|
-
|
7483
|
-
|
7484
|
-
|
7485
|
-
|
7486
|
-
execute: this.removeExecutor.bind(this, type, data.startOffset, data.endOffset),
|
7557
|
+
getFlushOp(type, start, end) {
|
7558
|
+
return {
|
7559
|
+
execute: () => {
|
7560
|
+
this.removeExecutor(type, start, end);
|
7561
|
+
},
|
7487
7562
|
onStart: () => {
|
7488
7563
|
// logger.debug(`[buffer-controller]: Started flushing ${data.startOffset} -> ${data.endOffset} for ${type} Source Buffer`);
|
7489
7564
|
},
|
@@ -7496,12 +7571,22 @@ class BufferController extends Logger {
|
|
7496
7571
|
onError: error => {
|
7497
7572
|
this.warn(`Failed to remove from ${type} SourceBuffer`, error);
|
7498
7573
|
}
|
7499
|
-
}
|
7500
|
-
|
7501
|
-
|
7574
|
+
};
|
7575
|
+
}
|
7576
|
+
onBufferFlushing(event, data) {
|
7577
|
+
const {
|
7578
|
+
operationQueue
|
7579
|
+
} = this;
|
7580
|
+
const {
|
7581
|
+
type,
|
7582
|
+
startOffset,
|
7583
|
+
endOffset
|
7584
|
+
} = data;
|
7585
|
+
if (type) {
|
7586
|
+
operationQueue.append(this.getFlushOp(type, startOffset, endOffset), type);
|
7502
7587
|
} else {
|
7503
|
-
this.getSourceBufferTypes().forEach(
|
7504
|
-
operationQueue.append(
|
7588
|
+
this.getSourceBufferTypes().forEach(sbType => {
|
7589
|
+
operationQueue.append(this.getFlushOp(sbType, startOffset, endOffset), sbType);
|
7505
7590
|
});
|
7506
7591
|
}
|
7507
7592
|
}
|
@@ -7548,6 +7633,9 @@ class BufferController extends Logger {
|
|
7548
7633
|
// on BUFFER_EOS mark matching sourcebuffer(s) as ended and trigger checkEos()
|
7549
7634
|
// an undefined data.type will mark all buffers as EOS.
|
7550
7635
|
onBufferEos(event, data) {
|
7636
|
+
if (data.type === 'video') {
|
7637
|
+
this.unblockAudio();
|
7638
|
+
}
|
7551
7639
|
const ended = this.getSourceBufferTypes().reduce((acc, type) => {
|
7552
7640
|
const sb = this.sourceBuffer[type];
|
7553
7641
|
if (sb && (!data.type || data.type === type)) {
|
@@ -7590,10 +7678,14 @@ class BufferController extends Logger {
|
|
7590
7678
|
return;
|
7591
7679
|
}
|
7592
7680
|
this.details = details;
|
7681
|
+
const durationAndRange = this.getDurationAndRange();
|
7682
|
+
if (!durationAndRange) {
|
7683
|
+
return;
|
7684
|
+
}
|
7593
7685
|
if (this.getSourceBufferTypes().length) {
|
7594
|
-
this.blockBuffers(this.
|
7686
|
+
this.blockBuffers(() => this.updateMediaSource(durationAndRange));
|
7595
7687
|
} else {
|
7596
|
-
this.
|
7688
|
+
this.updateMediaSource(durationAndRange);
|
7597
7689
|
}
|
7598
7690
|
}
|
7599
7691
|
trimBuffers() {
|
@@ -7698,9 +7790,9 @@ class BufferController extends Logger {
|
|
7698
7790
|
* 'liveDurationInfinity` is set to `true`
|
7699
7791
|
* More details: https://github.com/video-dev/hls.js/issues/355
|
7700
7792
|
*/
|
7701
|
-
|
7793
|
+
getDurationAndRange() {
|
7702
7794
|
if (!this.details || !this.media || !this.mediaSource || this.mediaSource.readyState !== 'open') {
|
7703
|
-
return;
|
7795
|
+
return null;
|
7704
7796
|
}
|
7705
7797
|
const {
|
7706
7798
|
details,
|
@@ -7714,25 +7806,41 @@ class BufferController extends Logger {
|
|
7714
7806
|
if (details.live && hls.config.liveDurationInfinity) {
|
7715
7807
|
// Override duration to Infinity
|
7716
7808
|
mediaSource.duration = Infinity;
|
7717
|
-
|
7809
|
+
const len = details.fragments.length;
|
7810
|
+
if (len && details.live && !!mediaSource.setLiveSeekableRange) {
|
7811
|
+
const start = Math.max(0, details.fragments[0].start);
|
7812
|
+
const end = Math.max(start, start + details.totalduration);
|
7813
|
+
return {
|
7814
|
+
duration: Infinity,
|
7815
|
+
start,
|
7816
|
+
end
|
7817
|
+
};
|
7818
|
+
}
|
7819
|
+
return {
|
7820
|
+
duration: Infinity
|
7821
|
+
};
|
7718
7822
|
} else if (levelDuration > msDuration && levelDuration > mediaDuration || !isFiniteNumber(mediaDuration)) {
|
7719
|
-
|
7720
|
-
|
7721
|
-
|
7722
|
-
// flushing already buffered portion when switching between quality level
|
7723
|
-
this.log(`Updating Media Source duration to ${levelDuration.toFixed(3)}`);
|
7724
|
-
mediaSource.duration = levelDuration;
|
7823
|
+
return {
|
7824
|
+
duration: levelDuration
|
7825
|
+
};
|
7725
7826
|
}
|
7827
|
+
return null;
|
7726
7828
|
}
|
7727
|
-
|
7728
|
-
|
7729
|
-
|
7730
|
-
|
7731
|
-
|
7732
|
-
|
7733
|
-
|
7734
|
-
|
7735
|
-
|
7829
|
+
updateMediaSource({
|
7830
|
+
duration,
|
7831
|
+
start,
|
7832
|
+
end
|
7833
|
+
}) {
|
7834
|
+
if (!this.media || !this.mediaSource || this.mediaSource.readyState !== 'open') {
|
7835
|
+
return;
|
7836
|
+
}
|
7837
|
+
if (isFiniteNumber(duration)) {
|
7838
|
+
this.log(`Updating Media Source duration to ${duration.toFixed(3)}`);
|
7839
|
+
}
|
7840
|
+
this.mediaSource.duration = duration;
|
7841
|
+
if (start !== undefined && end !== undefined) {
|
7842
|
+
this.log(`Media Source duration is set to ${this.mediaSource.duration}. Setting seekable range to ${start}-${end}.`);
|
7843
|
+
this.mediaSource.setLiveSeekableRange(start, end);
|
7736
7844
|
}
|
7737
7845
|
}
|
7738
7846
|
checkPendingTracks() {
|
@@ -7915,6 +8023,7 @@ class BufferController extends Logger {
|
|
7915
8023
|
}
|
7916
8024
|
return;
|
7917
8025
|
}
|
8026
|
+
sb.ending = false;
|
7918
8027
|
sb.ended = false;
|
7919
8028
|
sb.appendBuffer(data);
|
7920
8029
|
}
|
@@ -7934,10 +8043,14 @@ class BufferController extends Logger {
|
|
7934
8043
|
|
7935
8044
|
// logger.debug(`[buffer-controller]: Blocking ${buffers} SourceBuffer`);
|
7936
8045
|
const blockingOperations = buffers.map(type => operationQueue.appendBlocker(type));
|
7937
|
-
|
8046
|
+
const audioBlocked = buffers.length > 1 && !!this.blockedAudioAppend;
|
8047
|
+
if (audioBlocked) {
|
8048
|
+
this.unblockAudio();
|
8049
|
+
}
|
8050
|
+
Promise.all(blockingOperations).then(result => {
|
7938
8051
|
// logger.debug(`[buffer-controller]: Blocking operation resolved; unblocking ${buffers} SourceBuffer`);
|
7939
8052
|
onUnblocked();
|
7940
|
-
buffers.forEach(type => {
|
8053
|
+
buffers.forEach((type, i) => {
|
7941
8054
|
const sb = this.sourceBuffer[type];
|
7942
8055
|
// Only cycle the queue if the SB is not updating. There's a bug in Chrome which sets the SB updating flag to
|
7943
8056
|
// true when changing the MediaSource duration (https://bugs.chromium.org/p/chromium/issues/detail?id=959359&can=2&q=mediasource%20duration)
|
@@ -10256,13 +10369,16 @@ class FragmentTracker {
|
|
10256
10369
|
* If not found any Fragment, return null
|
10257
10370
|
*/
|
10258
10371
|
getBufferedFrag(position, levelType) {
|
10372
|
+
return this.getFragAtPos(position, levelType, true);
|
10373
|
+
}
|
10374
|
+
getFragAtPos(position, levelType, buffered) {
|
10259
10375
|
const {
|
10260
10376
|
fragments
|
10261
10377
|
} = this;
|
10262
10378
|
const keys = Object.keys(fragments);
|
10263
10379
|
for (let i = keys.length; i--;) {
|
10264
10380
|
const fragmentEntity = fragments[keys[i]];
|
10265
|
-
if ((fragmentEntity == null ? void 0 : fragmentEntity.body.type) === levelType && fragmentEntity.buffered) {
|
10381
|
+
if ((fragmentEntity == null ? void 0 : fragmentEntity.body.type) === levelType && (!buffered || fragmentEntity.buffered)) {
|
10266
10382
|
const frag = fragmentEntity.body;
|
10267
10383
|
if (frag.start <= position && position <= frag.end) {
|
10268
10384
|
return frag;
|
@@ -10517,7 +10633,8 @@ class FragmentTracker {
|
|
10517
10633
|
const {
|
10518
10634
|
frag,
|
10519
10635
|
part,
|
10520
|
-
timeRanges
|
10636
|
+
timeRanges,
|
10637
|
+
type
|
10521
10638
|
} = data;
|
10522
10639
|
if (frag.sn === 'initSegment') {
|
10523
10640
|
return;
|
@@ -10532,10 +10649,8 @@ class FragmentTracker {
|
|
10532
10649
|
}
|
10533
10650
|
// Store the latest timeRanges loaded in the buffer
|
10534
10651
|
this.timeRanges = timeRanges;
|
10535
|
-
|
10536
|
-
|
10537
|
-
this.detectEvictedFragments(elementaryStream, timeRange, playlistType, part);
|
10538
|
-
});
|
10652
|
+
const timeRange = timeRanges[type];
|
10653
|
+
this.detectEvictedFragments(type, timeRange, playlistType, part);
|
10539
10654
|
}
|
10540
10655
|
onFragBuffered(event, data) {
|
10541
10656
|
this.detectPartialFragments(data);
|
@@ -12712,7 +12827,7 @@ class BaseStreamController extends TaskLoop {
|
|
12712
12827
|
// Workaround flaw in getting forward buffer when maxBufferHole is smaller than gap at current pos
|
12713
12828
|
if (bufferInfo.len === 0 && bufferInfo.nextStart !== undefined) {
|
12714
12829
|
const bufferedFragAtPos = this.fragmentTracker.getBufferedFrag(pos, type);
|
12715
|
-
if (bufferedFragAtPos && bufferInfo.nextStart
|
12830
|
+
if (bufferedFragAtPos && (bufferInfo.nextStart <= bufferedFragAtPos.end || bufferedFragAtPos.gap)) {
|
12716
12831
|
return BufferHelper.bufferInfo(bufferable, pos, Math.max(bufferInfo.nextStart, maxBufferHole));
|
12717
12832
|
}
|
12718
12833
|
}
|
@@ -19892,6 +20007,17 @@ class StreamController extends BaseStreamController {
|
|
19892
20007
|
getMainFwdBufferInfo() {
|
19893
20008
|
return this.getFwdBufferInfo(this.mediaBuffer ? this.mediaBuffer : this.media, PlaylistLevelType.MAIN);
|
19894
20009
|
}
|
20010
|
+
get maxBufferLength() {
|
20011
|
+
const {
|
20012
|
+
levels,
|
20013
|
+
level
|
20014
|
+
} = this;
|
20015
|
+
const levelInfo = levels == null ? void 0 : levels[level];
|
20016
|
+
if (!levelInfo) {
|
20017
|
+
return this.config.maxBufferLength;
|
20018
|
+
}
|
20019
|
+
return this.getMaxBufferLength(levelInfo.maxBitrate);
|
20020
|
+
}
|
19895
20021
|
backtrack(frag) {
|
19896
20022
|
this.couldBacktrack = true;
|
19897
20023
|
// Causes findFragments to backtrack through fragments to find the keyframe
|
@@ -19997,7 +20123,7 @@ class Hls {
|
|
19997
20123
|
* Get the video-dev/hls.js package version.
|
19998
20124
|
*/
|
19999
20125
|
static get version() {
|
20000
|
-
return "1.5.7-0.canary.
|
20126
|
+
return "1.5.7-0.canary.10016";
|
20001
20127
|
}
|
20002
20128
|
|
20003
20129
|
/**
|
@@ -20099,7 +20225,9 @@ class Hls {
|
|
20099
20225
|
} = config;
|
20100
20226
|
const errorController = new ConfigErrorController(this);
|
20101
20227
|
const abrController = this.abrController = new ConfigAbrController(this);
|
20102
|
-
|
20228
|
+
// FragmentTracker must be defined before StreamController because the order of event handling is important
|
20229
|
+
const fragmentTracker = new FragmentTracker(this);
|
20230
|
+
const bufferController = this.bufferController = new ConfigBufferController(this, fragmentTracker);
|
20103
20231
|
const capLevelController = this.capLevelController = new ConfigCapLevelController(this);
|
20104
20232
|
const fpsController = new ConfigFpsController(this);
|
20105
20233
|
const playListLoader = new PlaylistLoader(this);
|
@@ -20108,8 +20236,6 @@ class Hls {
|
|
20108
20236
|
// ConentSteeringController is defined before LevelController to receive Multivariant Playlist events first
|
20109
20237
|
const contentSteering = ConfigContentSteeringController ? new ConfigContentSteeringController(this) : null;
|
20110
20238
|
const levelController = this.levelController = new LevelController(this, contentSteering);
|
20111
|
-
// FragmentTracker must be defined before StreamController because the order of event handling is important
|
20112
|
-
const fragmentTracker = new FragmentTracker(this);
|
20113
20239
|
const keyLoader = new KeyLoader(this.config);
|
20114
20240
|
const streamController = this.streamController = new StreamController(this, fragmentTracker, keyLoader);
|
20115
20241
|
|
@@ -20637,6 +20763,9 @@ class Hls {
|
|
20637
20763
|
get mainForwardBufferInfo() {
|
20638
20764
|
return this.streamController.getMainFwdBufferInfo();
|
20639
20765
|
}
|
20766
|
+
get maxBufferLength() {
|
20767
|
+
return this.streamController.maxBufferLength;
|
20768
|
+
}
|
20640
20769
|
|
20641
20770
|
/**
|
20642
20771
|
* Find and select the best matching audio track, making a level switch when a Group change is necessary.
|