hls.js 1.5.17 → 1.5.19
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 +342 -268
- package/dist/hls.js.d.ts +10 -6
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +112 -91
- 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 +111 -90
- 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 +292 -222
- 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/audio-stream-controller.ts +4 -2
- package/src/controller/base-stream-controller.ts +9 -0
- package/src/controller/buffer-controller.ts +1 -0
- package/src/controller/eme-controller.ts +184 -124
- package/src/controller/stream-controller.ts +4 -1
- package/src/hls.ts +24 -17
- package/src/loader/key-loader.ts +6 -1
- package/src/loader/level-key.ts +6 -30
- package/src/remux/mp4-remuxer.ts +11 -7
- package/src/types/component-api.ts +2 -0
- package/src/utils/level-helper.ts +37 -38
- package/src/utils/mediakeys-helper.ts +34 -1
- package/src/utils/xhr-loader.ts +52 -49
package/dist/hls.light.mjs
CHANGED
@@ -411,7 +411,7 @@ function enableLogs(debugConfig, id) {
|
|
411
411
|
// Some browsers don't allow to use bind on console object anyway
|
412
412
|
// fallback to default if needed
|
413
413
|
try {
|
414
|
-
exportedLogger.log(`Debug logs enabled for "${id}" in hls.js version ${"1.5.
|
414
|
+
exportedLogger.log(`Debug logs enabled for "${id}" in hls.js version ${"1.5.19"}`);
|
415
415
|
} catch (e) {
|
416
416
|
exportedLogger = fakeLogger;
|
417
417
|
}
|
@@ -4730,15 +4730,16 @@ function mergeDetails(oldDetails, newDetails) {
|
|
4730
4730
|
delete oldDetails.fragmentHint.endPTS;
|
4731
4731
|
}
|
4732
4732
|
// check if old/new playlists have fragments in common
|
4733
|
-
// loop through overlapping SN and update startPTS
|
4734
|
-
let ccOffset = 0;
|
4733
|
+
// loop through overlapping SN and update startPTS, cc, and duration if any found
|
4735
4734
|
let PTSFrag;
|
4736
|
-
mapFragmentIntersection(oldDetails, newDetails, (oldFrag, newFrag) => {
|
4737
|
-
if (
|
4738
|
-
|
4739
|
-
|
4740
|
-
|
4741
|
-
|
4735
|
+
mapFragmentIntersection(oldDetails, newDetails, (oldFrag, newFrag, newFragIndex, newFragments) => {
|
4736
|
+
if (newDetails.skippedSegments) {
|
4737
|
+
if (newFrag.cc !== oldFrag.cc) {
|
4738
|
+
const ccOffset = oldFrag.cc - newFrag.cc;
|
4739
|
+
for (let i = newFragIndex; i < newFragments.length; i++) {
|
4740
|
+
newFragments[i].cc += ccOffset;
|
4741
|
+
}
|
4742
|
+
}
|
4742
4743
|
}
|
4743
4744
|
if (isFiniteNumber(oldFrag.startPTS) && isFiniteNumber(oldFrag.endPTS)) {
|
4744
4745
|
newFrag.start = newFrag.startPTS = oldFrag.startPTS;
|
@@ -4763,8 +4764,9 @@ function mergeDetails(oldDetails, newDetails) {
|
|
4763
4764
|
currentInitSegment = oldFrag.initSegment;
|
4764
4765
|
}
|
4765
4766
|
});
|
4767
|
+
const newFragments = newDetails.fragments;
|
4766
4768
|
if (currentInitSegment) {
|
4767
|
-
const fragmentsToCheck = newDetails.fragmentHint ?
|
4769
|
+
const fragmentsToCheck = newDetails.fragmentHint ? newFragments.concat(newDetails.fragmentHint) : newFragments;
|
4768
4770
|
fragmentsToCheck.forEach(frag => {
|
4769
4771
|
var _currentInitSegment;
|
4770
4772
|
if (frag && (!frag.initSegment || frag.initSegment.relurl === ((_currentInitSegment = currentInitSegment) == null ? void 0 : _currentInitSegment.relurl))) {
|
@@ -4773,27 +4775,20 @@ function mergeDetails(oldDetails, newDetails) {
|
|
4773
4775
|
});
|
4774
4776
|
}
|
4775
4777
|
if (newDetails.skippedSegments) {
|
4776
|
-
newDetails.deltaUpdateFailed =
|
4778
|
+
newDetails.deltaUpdateFailed = newFragments.some(frag => !frag);
|
4777
4779
|
if (newDetails.deltaUpdateFailed) {
|
4778
4780
|
logger.warn('[level-helper] Previous playlist missing segments skipped in delta playlist');
|
4779
4781
|
for (let i = newDetails.skippedSegments; i--;) {
|
4780
|
-
|
4782
|
+
newFragments.shift();
|
4783
|
+
}
|
4784
|
+
newDetails.startSN = newFragments[0].sn;
|
4785
|
+
} else {
|
4786
|
+
if (newDetails.canSkipDateRanges) {
|
4787
|
+
newDetails.dateRanges = mergeDateRanges(oldDetails.dateRanges, newDetails.dateRanges, newDetails.recentlyRemovedDateranges);
|
4781
4788
|
}
|
4782
|
-
newDetails.startSN = newDetails.fragments[0].sn;
|
4783
|
-
newDetails.startCC = newDetails.fragments[0].cc;
|
4784
|
-
} else if (newDetails.canSkipDateRanges) {
|
4785
|
-
newDetails.dateRanges = mergeDateRanges(oldDetails.dateRanges, newDetails.dateRanges, newDetails.recentlyRemovedDateranges);
|
4786
|
-
}
|
4787
|
-
}
|
4788
|
-
const newFragments = newDetails.fragments;
|
4789
|
-
if (ccOffset) {
|
4790
|
-
logger.warn('discontinuity sliding from playlist, take drift into account');
|
4791
|
-
for (let i = 0; i < newFragments.length; i++) {
|
4792
|
-
newFragments[i].cc += ccOffset;
|
4793
4789
|
}
|
4794
|
-
}
|
4795
|
-
if (newDetails.skippedSegments) {
|
4796
4790
|
newDetails.startCC = newDetails.fragments[0].cc;
|
4791
|
+
newDetails.endCC = newFragments[newFragments.length - 1].cc;
|
4797
4792
|
}
|
4798
4793
|
|
4799
4794
|
// Merge parts
|
@@ -4877,7 +4872,7 @@ function mapFragmentIntersection(oldDetails, newDetails, intersectionFn) {
|
|
4877
4872
|
newFrag = newDetails.fragments[i] = oldFrag;
|
4878
4873
|
}
|
4879
4874
|
if (oldFrag && newFrag) {
|
4880
|
-
intersectionFn(oldFrag, newFrag);
|
4875
|
+
intersectionFn(oldFrag, newFrag, i, newFrags);
|
4881
4876
|
}
|
4882
4877
|
}
|
4883
4878
|
}
|
@@ -7220,6 +7215,7 @@ class BufferController {
|
|
7220
7215
|
this.resetBuffer(type);
|
7221
7216
|
});
|
7222
7217
|
this._initSourceBuffer();
|
7218
|
+
this.hls.resumeBuffering();
|
7223
7219
|
}
|
7224
7220
|
resetBuffer(type) {
|
7225
7221
|
const sb = this.sourceBuffer[type];
|
@@ -8857,47 +8853,51 @@ class XhrLoader {
|
|
8857
8853
|
xhr.onprogress = null;
|
8858
8854
|
const status = xhr.status;
|
8859
8855
|
// http status between 200 to 299 are all successful
|
8860
|
-
const
|
8861
|
-
if (status >= 200 && status < 300
|
8862
|
-
|
8863
|
-
|
8864
|
-
|
8865
|
-
|
8866
|
-
|
8867
|
-
|
8868
|
-
|
8869
|
-
|
8870
|
-
|
8871
|
-
|
8872
|
-
onProgress
|
8873
|
-
|
8874
|
-
|
8856
|
+
const useResponseText = xhr.responseType === 'text' ? xhr.responseText : null;
|
8857
|
+
if (status >= 200 && status < 300) {
|
8858
|
+
const data = useResponseText != null ? useResponseText : xhr.response;
|
8859
|
+
if (data != null) {
|
8860
|
+
stats.loading.end = Math.max(self.performance.now(), stats.loading.first);
|
8861
|
+
const len = xhr.responseType === 'arraybuffer' ? data.byteLength : data.length;
|
8862
|
+
stats.loaded = stats.total = len;
|
8863
|
+
stats.bwEstimate = stats.total * 8000 / (stats.loading.end - stats.loading.first);
|
8864
|
+
if (!this.callbacks) {
|
8865
|
+
return;
|
8866
|
+
}
|
8867
|
+
const onProgress = this.callbacks.onProgress;
|
8868
|
+
if (onProgress) {
|
8869
|
+
onProgress(stats, context, data, xhr);
|
8870
|
+
}
|
8871
|
+
if (!this.callbacks) {
|
8872
|
+
return;
|
8873
|
+
}
|
8874
|
+
const _response = {
|
8875
|
+
url: xhr.responseURL,
|
8876
|
+
data: data,
|
8877
|
+
code: status
|
8878
|
+
};
|
8879
|
+
this.callbacks.onSuccess(_response, stats, context, xhr);
|
8875
8880
|
return;
|
8876
8881
|
}
|
8877
|
-
|
8878
|
-
|
8879
|
-
|
8880
|
-
|
8881
|
-
|
8882
|
-
|
8882
|
+
}
|
8883
|
+
|
8884
|
+
// Handle bad status or nullish response
|
8885
|
+
const retryConfig = config.loadPolicy.errorRetry;
|
8886
|
+
const retryCount = stats.retry;
|
8887
|
+
// if max nb of retries reached or if http status between 400 and 499 (such error cannot be recovered, retrying is useless), return error
|
8888
|
+
const response = {
|
8889
|
+
url: context.url,
|
8890
|
+
data: undefined,
|
8891
|
+
code: status
|
8892
|
+
};
|
8893
|
+
if (shouldRetry(retryConfig, retryCount, false, response)) {
|
8894
|
+
this.retry(retryConfig);
|
8883
8895
|
} else {
|
8884
|
-
|
8885
|
-
|
8886
|
-
|
8887
|
-
|
8888
|
-
|
8889
|
-
data: undefined,
|
8890
|
-
code: status
|
8891
|
-
};
|
8892
|
-
if (shouldRetry(retryConfig, retryCount, false, response)) {
|
8893
|
-
this.retry(retryConfig);
|
8894
|
-
} else {
|
8895
|
-
logger.error(`${status} while loading ${context.url}`);
|
8896
|
-
this.callbacks.onError({
|
8897
|
-
code: status,
|
8898
|
-
text: xhr.statusText
|
8899
|
-
}, context, xhr, stats);
|
8900
|
-
}
|
8896
|
+
logger.error(`${status} while loading ${context.url}`);
|
8897
|
+
this.callbacks.onError({
|
8898
|
+
code: status,
|
8899
|
+
text: xhr.statusText
|
8900
|
+
}, context, xhr, stats);
|
8901
8901
|
}
|
8902
8902
|
}
|
8903
8903
|
}
|
@@ -10939,7 +10939,7 @@ class KeyLoader {
|
|
10939
10939
|
}
|
10940
10940
|
}
|
10941
10941
|
load(frag) {
|
10942
|
-
if (!frag.decryptdata && frag.encrypted && this.emeController) {
|
10942
|
+
if (!frag.decryptdata && frag.encrypted && this.emeController && this.config.emeEnabled) {
|
10943
10943
|
// Multiple keys, but none selected, resolve in eme-controller
|
10944
10944
|
return this.emeController.selectKeySystemFormat(frag).then(keySystemFormat => {
|
10945
10945
|
return this.loadInternal(frag, keySystemFormat);
|
@@ -11899,6 +11899,7 @@ class BaseStreamController extends TaskLoop {
|
|
11899
11899
|
this.startFragRequested = false;
|
11900
11900
|
this.decrypter = void 0;
|
11901
11901
|
this.initPTS = [];
|
11902
|
+
this.buffering = true;
|
11902
11903
|
this.onvseeking = null;
|
11903
11904
|
this.onvended = null;
|
11904
11905
|
this.logPrefix = '';
|
@@ -11938,6 +11939,12 @@ class BaseStreamController extends TaskLoop {
|
|
11938
11939
|
this.clearNextTick();
|
11939
11940
|
this.state = State.STOPPED;
|
11940
11941
|
}
|
11942
|
+
pauseBuffering() {
|
11943
|
+
this.buffering = false;
|
11944
|
+
}
|
11945
|
+
resumeBuffering() {
|
11946
|
+
this.buffering = true;
|
11947
|
+
}
|
11941
11948
|
_streamEnded(bufferInfo, levelDetails) {
|
11942
11949
|
// If playlist is live, there is another buffered range after the current range, nothing buffered, media is detached,
|
11943
11950
|
// of nothing loading/loaded return false
|
@@ -16187,19 +16194,23 @@ class MP4Remuxer {
|
|
16187
16194
|
this.videoTrackConfig = undefined;
|
16188
16195
|
}
|
16189
16196
|
getVideoStartPts(videoSamples) {
|
16197
|
+
// Get the minimum PTS value relative to the first sample's PTS, normalized for 33-bit wrapping
|
16190
16198
|
let rolloverDetected = false;
|
16199
|
+
const firstPts = videoSamples[0].pts;
|
16191
16200
|
const startPTS = videoSamples.reduce((minPTS, sample) => {
|
16192
|
-
|
16201
|
+
let pts = sample.pts;
|
16202
|
+
let delta = pts - minPTS;
|
16193
16203
|
if (delta < -4294967296) {
|
16194
16204
|
// 2^32, see PTSNormalize for reasoning, but we're hitting a rollover here, and we don't want that to impact the timeOffset calculation
|
16195
16205
|
rolloverDetected = true;
|
16196
|
-
|
16197
|
-
|
16206
|
+
pts = normalizePts(pts, firstPts);
|
16207
|
+
delta = pts - minPTS;
|
16208
|
+
}
|
16209
|
+
if (delta > 0) {
|
16198
16210
|
return minPTS;
|
16199
|
-
} else {
|
16200
|
-
return sample.pts;
|
16201
16211
|
}
|
16202
|
-
|
16212
|
+
return pts;
|
16213
|
+
}, firstPts);
|
16203
16214
|
if (rolloverDetected) {
|
16204
16215
|
logger.debug('PTS rollover detected');
|
16205
16216
|
}
|
@@ -18745,7 +18756,7 @@ class StreamController extends BaseStreamController {
|
|
18745
18756
|
if (this.altAudio && this.audioOnly) {
|
18746
18757
|
return;
|
18747
18758
|
}
|
18748
|
-
const level = hls.nextLoadLevel;
|
18759
|
+
const level = this.buffering ? hls.nextLoadLevel : hls.loadLevel;
|
18749
18760
|
if (!(levels != null && levels[level])) {
|
18750
18761
|
return;
|
18751
18762
|
}
|
@@ -18767,6 +18778,9 @@ class StreamController extends BaseStreamController {
|
|
18767
18778
|
this.state = State.ENDED;
|
18768
18779
|
return;
|
18769
18780
|
}
|
18781
|
+
if (!this.buffering) {
|
18782
|
+
return;
|
18783
|
+
}
|
18770
18784
|
|
18771
18785
|
// set next load level : this will trigger a playlist load if needed
|
18772
18786
|
if (hls.loadLevel !== level && hls.manualLevel === -1) {
|
@@ -19729,7 +19743,7 @@ class Hls {
|
|
19729
19743
|
* Get the video-dev/hls.js package version.
|
19730
19744
|
*/
|
19731
19745
|
static get version() {
|
19732
|
-
return "1.5.
|
19746
|
+
return "1.5.19";
|
19733
19747
|
}
|
19734
19748
|
|
19735
19749
|
/**
|
@@ -20010,9 +20024,13 @@ class Hls {
|
|
20010
20024
|
startLoad(startPosition = -1) {
|
20011
20025
|
logger.log(`startLoad(${startPosition})`);
|
20012
20026
|
this.started = true;
|
20013
|
-
this.
|
20014
|
-
|
20015
|
-
|
20027
|
+
this.resumeBuffering();
|
20028
|
+
for (let i = 0; i < this.networkControllers.length; i++) {
|
20029
|
+
this.networkControllers[i].startLoad(startPosition);
|
20030
|
+
if (!this.started || !this.networkControllers) {
|
20031
|
+
break;
|
20032
|
+
}
|
20033
|
+
}
|
20016
20034
|
}
|
20017
20035
|
|
20018
20036
|
/**
|
@@ -20021,32 +20039,35 @@ class Hls {
|
|
20021
20039
|
stopLoad() {
|
20022
20040
|
logger.log('stopLoad');
|
20023
20041
|
this.started = false;
|
20024
|
-
this.networkControllers.
|
20025
|
-
|
20026
|
-
|
20042
|
+
for (let i = 0; i < this.networkControllers.length; i++) {
|
20043
|
+
this.networkControllers[i].stopLoad();
|
20044
|
+
if (this.started || !this.networkControllers) {
|
20045
|
+
break;
|
20046
|
+
}
|
20047
|
+
}
|
20027
20048
|
}
|
20028
20049
|
|
20029
20050
|
/**
|
20030
|
-
* Resumes stream controller segment loading
|
20051
|
+
* Resumes stream controller segment loading after `pauseBuffering` has been called.
|
20031
20052
|
*/
|
20032
20053
|
resumeBuffering() {
|
20033
|
-
|
20034
|
-
|
20035
|
-
|
20036
|
-
|
20037
|
-
|
20038
|
-
|
20039
|
-
}
|
20054
|
+
logger.log(`resume buffering`);
|
20055
|
+
this.networkControllers.forEach(controller => {
|
20056
|
+
if (controller.resumeBuffering) {
|
20057
|
+
controller.resumeBuffering();
|
20058
|
+
}
|
20059
|
+
});
|
20040
20060
|
}
|
20041
20061
|
|
20042
20062
|
/**
|
20043
|
-
*
|
20063
|
+
* Prevents stream controller from loading new segments until `resumeBuffering` is called.
|
20044
20064
|
* This allows for media buffering to be paused without interupting playlist loading.
|
20045
20065
|
*/
|
20046
20066
|
pauseBuffering() {
|
20067
|
+
logger.log(`pause buffering`);
|
20047
20068
|
this.networkControllers.forEach(controller => {
|
20048
|
-
if (
|
20049
|
-
controller.
|
20069
|
+
if (controller.pauseBuffering) {
|
20070
|
+
controller.pauseBuffering();
|
20050
20071
|
}
|
20051
20072
|
});
|
20052
20073
|
}
|