hls.js 1.6.0-beta.2.0.canary.10882 → 1.6.0-beta.2.0.canary.10884
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 +21 -1
- package/dist/hls.d.ts +21 -1
- package/dist/hls.js +130 -98
- package/dist/hls.js.d.ts +21 -1
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +130 -98
- 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 +123 -93
- 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 +123 -93
- 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/config.ts +2 -0
- package/src/controller/gap-controller.ts +92 -58
- package/src/controller/stream-controller.ts +13 -3
- package/src/events.ts +3 -0
- package/src/hls.ts +2 -1
- package/src/loader/level-details.ts +0 -2
- package/src/loader/m3u8-parser.ts +1 -1
- package/src/types/events.ts +3 -0
- package/src/utils/buffer-helper.ts +5 -8
- package/src/utils/level-helper.ts +29 -35
package/dist/hls.light.js
CHANGED
@@ -756,6 +756,7 @@
|
|
756
756
|
Events["MEDIA_DETACHING"] = "hlsMediaDetaching";
|
757
757
|
Events["MEDIA_DETACHED"] = "hlsMediaDetached";
|
758
758
|
Events["MEDIA_ENDED"] = "hlsMediaEnded";
|
759
|
+
Events["STALL_RESOLVED"] = "hlsStallResolved";
|
759
760
|
Events["BUFFER_RESET"] = "hlsBufferReset";
|
760
761
|
Events["BUFFER_CODECS"] = "hlsBufferCodecs";
|
761
762
|
Events["BUFFER_CREATED"] = "hlsBufferCreated";
|
@@ -1029,7 +1030,7 @@
|
|
1029
1030
|
// Some browsers don't allow to use bind on console object anyway
|
1030
1031
|
// fallback to default if needed
|
1031
1032
|
try {
|
1032
|
-
newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.6.0-beta.2.0.canary.
|
1033
|
+
newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.6.0-beta.2.0.canary.10884");
|
1033
1034
|
} catch (e) {
|
1034
1035
|
/* log fn threw an exception. All logger methods are no-ops. */
|
1035
1036
|
return createLogger();
|
@@ -3621,8 +3622,7 @@
|
|
3621
3622
|
return {
|
3622
3623
|
len: 0,
|
3623
3624
|
start: pos,
|
3624
|
-
end: pos
|
3625
|
-
nextStart: undefined
|
3625
|
+
end: pos
|
3626
3626
|
};
|
3627
3627
|
};
|
3628
3628
|
BufferHelper.bufferedInfo = function bufferedInfo(buffered, pos, maxHoleDuration) {
|
@@ -3687,7 +3687,8 @@
|
|
3687
3687
|
len: bufferLen,
|
3688
3688
|
start: bufferStart || 0,
|
3689
3689
|
end: bufferEnd || 0,
|
3690
|
-
nextStart: bufferStartNext
|
3690
|
+
nextStart: bufferStartNext,
|
3691
|
+
buffered: buffered
|
3691
3692
|
};
|
3692
3693
|
}
|
3693
3694
|
|
@@ -5792,8 +5793,6 @@
|
|
5792
5793
|
this.advancedDateTime = undefined;
|
5793
5794
|
this.updated = true;
|
5794
5795
|
this.advanced = true;
|
5795
|
-
this.availabilityDelay = undefined;
|
5796
|
-
// Manifest reload synchronization
|
5797
5796
|
this.misses = 0;
|
5798
5797
|
this.startCC = 0;
|
5799
5798
|
this.startSN = 0;
|
@@ -5846,7 +5845,6 @@
|
|
5846
5845
|
} else {
|
5847
5846
|
this.misses = previous.misses + 1;
|
5848
5847
|
}
|
5849
|
-
this.availabilityDelay = previous.availabilityDelay;
|
5850
5848
|
};
|
5851
5849
|
return _createClass(LevelDetails, [{
|
5852
5850
|
key: "hasProgramDateTime",
|
@@ -7729,7 +7727,7 @@
|
|
7729
7727
|
if (!level.live) {
|
7730
7728
|
lastFragment.endList = true;
|
7731
7729
|
}
|
7732
|
-
if (firstFragment &&
|
7730
|
+
if (firstFragment && level.startCC === undefined) {
|
7733
7731
|
level.startCC = firstFragment.cc;
|
7734
7732
|
}
|
7735
7733
|
/**
|
@@ -8019,15 +8017,16 @@
|
|
8019
8017
|
delete oldDetails.fragmentHint.endPTS;
|
8020
8018
|
}
|
8021
8019
|
// check if old/new playlists have fragments in common
|
8022
|
-
// loop through overlapping SN and update startPTS
|
8023
|
-
var ccOffset = 0;
|
8020
|
+
// loop through overlapping SN and update startPTS, cc, and duration if any found
|
8024
8021
|
var PTSFrag;
|
8025
|
-
mapFragmentIntersection(oldDetails, newDetails, function (oldFrag, newFrag) {
|
8026
|
-
if (
|
8027
|
-
|
8028
|
-
|
8029
|
-
|
8030
|
-
|
8022
|
+
mapFragmentIntersection(oldDetails, newDetails, function (oldFrag, newFrag, newFragIndex, newFragments) {
|
8023
|
+
if (newDetails.skippedSegments) {
|
8024
|
+
if (newFrag.cc !== oldFrag.cc) {
|
8025
|
+
var ccOffset = oldFrag.cc - newFrag.cc;
|
8026
|
+
for (var _i = newFragIndex; _i < newFragments.length; _i++) {
|
8027
|
+
newFragments[_i].cc += ccOffset;
|
8028
|
+
}
|
8029
|
+
}
|
8031
8030
|
}
|
8032
8031
|
if (isFiniteNumber(oldFrag.startPTS) && isFiniteNumber(oldFrag.endPTS)) {
|
8033
8032
|
newFrag.setStart(newFrag.startPTS = oldFrag.startPTS);
|
@@ -8056,7 +8055,8 @@
|
|
8056
8055
|
currentInitSegment = oldFrag.initSegment;
|
8057
8056
|
}
|
8058
8057
|
});
|
8059
|
-
var
|
8058
|
+
var newFragments = newDetails.fragments;
|
8059
|
+
var fragmentsToCheck = newDetails.fragmentHint ? newFragments.concat(newDetails.fragmentHint) : newFragments;
|
8060
8060
|
if (currentInitSegment) {
|
8061
8061
|
fragmentsToCheck.forEach(function (frag) {
|
8062
8062
|
var _currentInitSegment;
|
@@ -8066,19 +8066,17 @@
|
|
8066
8066
|
});
|
8067
8067
|
}
|
8068
8068
|
if (newDetails.skippedSegments) {
|
8069
|
-
newDetails.deltaUpdateFailed =
|
8069
|
+
newDetails.deltaUpdateFailed = newFragments.some(function (frag) {
|
8070
8070
|
return !frag;
|
8071
8071
|
});
|
8072
8072
|
if (newDetails.deltaUpdateFailed) {
|
8073
8073
|
logger.warn('[level-helper] Previous playlist missing segments skipped in delta playlist');
|
8074
|
-
for (var
|
8075
|
-
|
8076
|
-
}
|
8077
|
-
newDetails.startSN = newDetails.fragments[0].sn;
|
8078
|
-
if (!newDetails.startCC) {
|
8079
|
-
newDetails.startCC = newDetails.fragments[0].cc;
|
8074
|
+
for (var _i2 = newDetails.skippedSegments; _i2--;) {
|
8075
|
+
newFragments.shift();
|
8080
8076
|
}
|
8077
|
+
newDetails.startSN = newFragments[0].sn;
|
8081
8078
|
} else {
|
8079
|
+
newDetails.endCC = newFragments[newFragments.length - 1].cc;
|
8082
8080
|
if (newDetails.canSkipDateRanges) {
|
8083
8081
|
newDetails.dateRanges = mergeDateRanges(oldDetails.dateRanges, newDetails);
|
8084
8082
|
}
|
@@ -8086,25 +8084,15 @@
|
|
8086
8084
|
return frag.rawProgramDateTime;
|
8087
8085
|
});
|
8088
8086
|
if (oldDetails.hasProgramDateTime && !newDetails.hasProgramDateTime) {
|
8089
|
-
for (var
|
8090
|
-
if (fragmentsToCheck[
|
8091
|
-
assignProgramDateTime(fragmentsToCheck[
|
8087
|
+
for (var _i3 = 1; _i3 < fragmentsToCheck.length; _i3++) {
|
8088
|
+
if (fragmentsToCheck[_i3].programDateTime === null) {
|
8089
|
+
assignProgramDateTime(fragmentsToCheck[_i3], fragmentsToCheck[_i3 - 1], programDateTimes);
|
8092
8090
|
}
|
8093
8091
|
}
|
8094
8092
|
}
|
8095
8093
|
mapDateRanges(programDateTimes, newDetails);
|
8096
8094
|
}
|
8097
8095
|
}
|
8098
|
-
var newFragments = newDetails.fragments;
|
8099
|
-
if (ccOffset) {
|
8100
|
-
logger.warn('discontinuity sliding from playlist, take drift into account');
|
8101
|
-
for (var _i3 = 0; _i3 < newFragments.length; _i3++) {
|
8102
|
-
newFragments[_i3].cc += ccOffset;
|
8103
|
-
}
|
8104
|
-
}
|
8105
|
-
if (newDetails.skippedSegments) {
|
8106
|
-
newDetails.startCC = newDetails.fragments[0].cc;
|
8107
|
-
}
|
8108
8096
|
|
8109
8097
|
// Merge parts
|
8110
8098
|
mapPartIntersection(oldDetails.partList, newDetails.partList, function (oldPart, newPart) {
|
@@ -8200,7 +8188,7 @@
|
|
8200
8188
|
_newFrag = newDetails.fragments[i] = _oldFrag;
|
8201
8189
|
}
|
8202
8190
|
if (_oldFrag && _newFrag) {
|
8203
|
-
intersectionFn(_oldFrag, _newFrag);
|
8191
|
+
intersectionFn(_oldFrag, _newFrag, i, newFrags);
|
8204
8192
|
}
|
8205
8193
|
}
|
8206
8194
|
}
|
@@ -14972,6 +14960,7 @@
|
|
14972
14960
|
progressive: false,
|
14973
14961
|
lowLatencyMode: true,
|
14974
14962
|
cmcd: undefined,
|
14963
|
+
detectStallWithCurrentTimeMs: 1250,
|
14975
14964
|
enableDateRangeMetadataCues: true,
|
14976
14965
|
enableEmsgMetadataCues: true,
|
14977
14966
|
enableEmsgKLVMetadata: false,
|
@@ -19236,25 +19225,23 @@
|
|
19236
19225
|
}]);
|
19237
19226
|
}(TaskLoop);
|
19238
19227
|
|
19239
|
-
var STALL_MINIMUM_DURATION_MS = 250;
|
19240
19228
|
var MAX_START_GAP_JUMP = 2.0;
|
19241
19229
|
var SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
|
19242
19230
|
var SKIP_BUFFER_RANGE_START = 0.05;
|
19243
19231
|
var GapController = /*#__PURE__*/function (_Logger) {
|
19244
|
-
function GapController(
|
19232
|
+
function GapController(media, fragmentTracker, hls) {
|
19245
19233
|
var _this;
|
19246
19234
|
_this = _Logger.call(this, 'gap-controller', hls.logger) || this;
|
19247
|
-
_this.config = undefined;
|
19248
19235
|
_this.media = null;
|
19249
|
-
_this.fragmentTracker =
|
19250
|
-
_this.hls =
|
19236
|
+
_this.fragmentTracker = null;
|
19237
|
+
_this.hls = null;
|
19251
19238
|
_this.nudgeRetry = 0;
|
19252
19239
|
_this.stallReported = false;
|
19253
19240
|
_this.stalled = null;
|
19254
19241
|
_this.moved = false;
|
19255
19242
|
_this.seeking = false;
|
19256
19243
|
_this.ended = 0;
|
19257
|
-
_this.
|
19244
|
+
_this.waiting = 0;
|
19258
19245
|
_this.media = media;
|
19259
19246
|
_this.fragmentTracker = fragmentTracker;
|
19260
19247
|
_this.hls = hls;
|
@@ -19263,9 +19250,7 @@
|
|
19263
19250
|
_inheritsLoose(GapController, _Logger);
|
19264
19251
|
var _proto = GapController.prototype;
|
19265
19252
|
_proto.destroy = function destroy() {
|
19266
|
-
this.media = null;
|
19267
|
-
// @ts-ignore
|
19268
|
-
this.hls = this.fragmentTracker = null;
|
19253
|
+
this.media = this.hls = this.fragmentTracker = null;
|
19269
19254
|
}
|
19270
19255
|
|
19271
19256
|
/**
|
@@ -19275,10 +19260,10 @@
|
|
19275
19260
|
* @param lastCurrentTime - Previously read playhead position
|
19276
19261
|
*/;
|
19277
19262
|
_proto.poll = function poll(lastCurrentTime, activeFrag, levelDetails, state) {
|
19278
|
-
var
|
19279
|
-
|
19263
|
+
var _this$hls;
|
19264
|
+
var media = this.media,
|
19280
19265
|
stalled = this.stalled;
|
19281
|
-
if (media
|
19266
|
+
if (!media) {
|
19282
19267
|
return;
|
19283
19268
|
}
|
19284
19269
|
var currentTime = media.currentTime,
|
@@ -19296,43 +19281,45 @@
|
|
19296
19281
|
if (!seeking) {
|
19297
19282
|
this.nudgeRetry = 0;
|
19298
19283
|
}
|
19299
|
-
if (
|
19300
|
-
|
19301
|
-
if (this.stallReported) {
|
19302
|
-
var _stalledDuration = self.performance.now() - stalled;
|
19303
|
-
this.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
|
19304
|
-
this.stallReported = false;
|
19305
|
-
}
|
19306
|
-
this.stalled = null;
|
19284
|
+
if (this.waiting === 0) {
|
19285
|
+
this.stallResolved(currentTime);
|
19307
19286
|
}
|
19308
19287
|
return;
|
19309
19288
|
}
|
19310
19289
|
|
19311
19290
|
// Clear stalled state when beginning or finishing seeking so that we don't report stalls coming out of a seek
|
19312
19291
|
if (beginSeek || seeked) {
|
19313
|
-
|
19292
|
+
if (seeked) {
|
19293
|
+
this.stallResolved(currentTime);
|
19294
|
+
}
|
19314
19295
|
return;
|
19315
19296
|
}
|
19316
19297
|
|
19317
19298
|
// The playhead should not be moving
|
19318
|
-
if (media.paused && !seeking || media.ended || media.playbackRate === 0
|
19299
|
+
if (media.paused && !seeking || media.ended || media.playbackRate === 0) {
|
19300
|
+
this.nudgeRetry = 0;
|
19301
|
+
this.stallResolved(currentTime);
|
19319
19302
|
// Fire MEDIA_ENDED to workaround event not being dispatched by browser
|
19320
|
-
if (!this.ended && media.ended) {
|
19303
|
+
if (!this.ended && media.ended && this.hls) {
|
19321
19304
|
this.ended = currentTime || 1;
|
19322
19305
|
this.hls.trigger(Events.MEDIA_ENDED, {
|
19323
19306
|
stalled: false
|
19324
19307
|
});
|
19325
19308
|
}
|
19309
|
+
return;
|
19310
|
+
}
|
19311
|
+
if (!BufferHelper.getBuffered(media).length) {
|
19326
19312
|
this.nudgeRetry = 0;
|
19327
19313
|
return;
|
19328
19314
|
}
|
19329
19315
|
var bufferInfo = BufferHelper.bufferInfo(media, currentTime, 0);
|
19330
19316
|
var nextStart = bufferInfo.nextStart || 0;
|
19331
|
-
|
19317
|
+
var fragmentTracker = this.fragmentTracker;
|
19318
|
+
if (seeking && fragmentTracker) {
|
19332
19319
|
// Waiting for seeking in a buffered range to complete
|
19333
19320
|
var hasEnoughBuffer = bufferInfo.len > MAX_START_GAP_JUMP;
|
19334
19321
|
// Next buffered range is too far ahead to jump to while still seeking
|
19335
|
-
var noBufferGap = !nextStart || activeFrag && activeFrag.start <= currentTime || nextStart - currentTime > MAX_START_GAP_JUMP && !
|
19322
|
+
var noBufferGap = !nextStart || activeFrag && activeFrag.start <= currentTime || nextStart - currentTime > MAX_START_GAP_JUMP && !fragmentTracker.getPartialFragment(currentTime);
|
19336
19323
|
if (hasEnoughBuffer || noBufferGap) {
|
19337
19324
|
return;
|
19338
19325
|
}
|
@@ -19342,7 +19329,7 @@
|
|
19342
19329
|
|
19343
19330
|
// Skip start gaps if we haven't played, but the last poll detected the start of a stall
|
19344
19331
|
// The addition poll gives the browser a chance to jump the gap for us
|
19345
|
-
if (!this.moved && this.stalled !== null) {
|
19332
|
+
if (!this.moved && this.stalled !== null && fragmentTracker) {
|
19346
19333
|
// There is no playable buffer (seeked, waiting for buffer)
|
19347
19334
|
var isBuffered = bufferInfo.len > 0;
|
19348
19335
|
if (!isBuffered && !nextStart) {
|
@@ -19356,7 +19343,7 @@
|
|
19356
19343
|
// that begins over 1 target duration after the video start position.
|
19357
19344
|
var isLive = !!(levelDetails != null && levelDetails.live);
|
19358
19345
|
var maxStartGapJump = isLive ? levelDetails.targetduration * 2 : MAX_START_GAP_JUMP;
|
19359
|
-
var partialOrGap =
|
19346
|
+
var partialOrGap = fragmentTracker.getPartialFragment(currentTime);
|
19360
19347
|
if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
|
19361
19348
|
if (!media.paused) {
|
19362
19349
|
this._trySkipBufferHole(partialOrGap);
|
@@ -19366,16 +19353,27 @@
|
|
19366
19353
|
}
|
19367
19354
|
|
19368
19355
|
// Start tracking stall time
|
19356
|
+
var config = (_this$hls = this.hls) == null ? undefined : _this$hls.config;
|
19357
|
+
if (!config) {
|
19358
|
+
return;
|
19359
|
+
}
|
19360
|
+
var detectStallWithCurrentTimeMs = config.detectStallWithCurrentTimeMs;
|
19369
19361
|
var tnow = self.performance.now();
|
19362
|
+
var tWaiting = this.waiting;
|
19370
19363
|
if (stalled === null) {
|
19371
|
-
|
19364
|
+
// Use time of recent "waiting" event
|
19365
|
+
if (tWaiting > 0 && tnow - tWaiting < detectStallWithCurrentTimeMs) {
|
19366
|
+
this.stalled = tWaiting;
|
19367
|
+
} else {
|
19368
|
+
this.stalled = tnow;
|
19369
|
+
}
|
19372
19370
|
return;
|
19373
19371
|
}
|
19374
19372
|
var stalledDuration = tnow - stalled;
|
19375
|
-
if (!seeking && stalledDuration >=
|
19373
|
+
if (!seeking && (stalledDuration >= detectStallWithCurrentTimeMs || tWaiting) && this.hls) {
|
19376
19374
|
// Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
|
19377
19375
|
if (state === State.ENDED && !(levelDetails != null && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? undefined : levelDetails.edge) || 0)) < 1) {
|
19378
|
-
if (
|
19376
|
+
if (this.ended) {
|
19379
19377
|
return;
|
19380
19378
|
}
|
19381
19379
|
this.ended = currentTime || 1;
|
@@ -19386,12 +19384,26 @@
|
|
19386
19384
|
}
|
19387
19385
|
// Report stalling after trying to fix
|
19388
19386
|
this._reportStall(bufferInfo);
|
19389
|
-
if (!this.media) {
|
19387
|
+
if (!this.media || !this.hls) {
|
19390
19388
|
return;
|
19391
19389
|
}
|
19392
19390
|
}
|
19393
19391
|
var bufferedWithHoles = BufferHelper.bufferInfo(media, currentTime, config.maxBufferHole);
|
19394
19392
|
this._tryFixBufferStall(bufferedWithHoles, stalledDuration);
|
19393
|
+
};
|
19394
|
+
_proto.stallResolved = function stallResolved(currentTime) {
|
19395
|
+
var stalled = this.stalled;
|
19396
|
+
if (stalled && this.hls) {
|
19397
|
+
this.stalled = null;
|
19398
|
+
// The playhead is now moving, but was previously stalled
|
19399
|
+
if (this.stallReported) {
|
19400
|
+
var stalledDuration = self.performance.now() - stalled;
|
19401
|
+
this.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(stalledDuration) + "ms");
|
19402
|
+
this.stallReported = false;
|
19403
|
+
this.waiting = 0;
|
19404
|
+
this.hls.trigger(Events.STALL_RESOLVED, {});
|
19405
|
+
}
|
19406
|
+
}
|
19395
19407
|
}
|
19396
19408
|
|
19397
19409
|
/**
|
@@ -19401,10 +19413,11 @@
|
|
19401
19413
|
* @private
|
19402
19414
|
*/;
|
19403
19415
|
_proto._tryFixBufferStall = function _tryFixBufferStall(bufferInfo, stalledDurationMs) {
|
19404
|
-
var
|
19405
|
-
|
19416
|
+
var _this$hls2;
|
19417
|
+
var fragmentTracker = this.fragmentTracker,
|
19406
19418
|
media = this.media;
|
19407
|
-
|
19419
|
+
var config = (_this$hls2 = this.hls) == null ? undefined : _this$hls2.config;
|
19420
|
+
if (!media || !fragmentTracker || !config) {
|
19408
19421
|
return;
|
19409
19422
|
}
|
19410
19423
|
var currentTime = media.currentTime;
|
@@ -19424,13 +19437,12 @@
|
|
19424
19437
|
// we may just have to "nudge" the playlist as the browser decoding/rendering engine
|
19425
19438
|
// needs to cross some sort of threshold covering all source-buffers content
|
19426
19439
|
// to start playing properly.
|
19427
|
-
|
19440
|
+
var bufferedRanges = bufferInfo.buffered;
|
19441
|
+
if ((bufferedRanges && bufferedRanges.length > 1 && bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
|
19428
19442
|
this.warn('Trying to nudge playhead over buffer-hole');
|
19429
19443
|
// Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
|
19430
19444
|
// We only try to jump the hole if it's under the configured size
|
19431
|
-
|
19432
|
-
this.stalled = null;
|
19433
|
-
this._tryNudgeBuffer();
|
19445
|
+
this._tryNudgeBuffer(bufferInfo);
|
19434
19446
|
}
|
19435
19447
|
}
|
19436
19448
|
|
@@ -19442,8 +19454,9 @@
|
|
19442
19454
|
_proto._reportStall = function _reportStall(bufferInfo) {
|
19443
19455
|
var hls = this.hls,
|
19444
19456
|
media = this.media,
|
19445
|
-
stallReported = this.stallReported
|
19446
|
-
|
19457
|
+
stallReported = this.stallReported,
|
19458
|
+
stalled = this.stalled;
|
19459
|
+
if (!stallReported && stalled !== null && media && hls) {
|
19447
19460
|
// Report stalled error once
|
19448
19461
|
this.stallReported = true;
|
19449
19462
|
var error = new Error("Playback stalling at @" + media.currentTime + " due to low buffer (" + JSON.stringify(bufferInfo) + ")");
|
@@ -19453,7 +19466,11 @@
|
|
19453
19466
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
19454
19467
|
fatal: false,
|
19455
19468
|
error: error,
|
19456
|
-
buffer: bufferInfo.len
|
19469
|
+
buffer: bufferInfo.len,
|
19470
|
+
bufferInfo: bufferInfo,
|
19471
|
+
stalled: {
|
19472
|
+
start: stalled
|
19473
|
+
}
|
19457
19474
|
});
|
19458
19475
|
}
|
19459
19476
|
}
|
@@ -19464,10 +19481,11 @@
|
|
19464
19481
|
* @private
|
19465
19482
|
*/;
|
19466
19483
|
_proto._trySkipBufferHole = function _trySkipBufferHole(partial) {
|
19467
|
-
var
|
19468
|
-
|
19484
|
+
var _this$hls3;
|
19485
|
+
var fragmentTracker = this.fragmentTracker,
|
19469
19486
|
media = this.media;
|
19470
|
-
|
19487
|
+
var config = (_this$hls3 = this.hls) == null ? undefined : _this$hls3.config;
|
19488
|
+
if (!media || !fragmentTracker || !config) {
|
19471
19489
|
return 0;
|
19472
19490
|
}
|
19473
19491
|
|
@@ -19482,7 +19500,6 @@
|
|
19482
19500
|
if (gapLength > 0 && (bufferStarved || waiting)) {
|
19483
19501
|
// Only allow large gaps to be skipped if it is a start gap, or all fragments in skip range are partial
|
19484
19502
|
if (gapLength > config.maxBufferHole) {
|
19485
|
-
var fragmentTracker = this.fragmentTracker;
|
19486
19503
|
var startGap = false;
|
19487
19504
|
if (currentTime === 0) {
|
19488
19505
|
var startFrag = fragmentTracker.getAppendedFrag(0, PlaylistLevelType.MAIN);
|
@@ -19513,17 +19530,18 @@
|
|
19513
19530
|
var targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
|
19514
19531
|
this.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
|
19515
19532
|
this.moved = true;
|
19516
|
-
this.stalled = null;
|
19517
19533
|
media.currentTime = targetTime;
|
19518
|
-
if (partial && !partial.gap) {
|
19534
|
+
if (partial && !partial.gap && this.hls) {
|
19519
19535
|
var error = new Error("fragment loaded with buffer holes, seeking from " + currentTime + " to " + targetTime);
|
19520
|
-
hls.trigger(Events.ERROR, {
|
19536
|
+
this.hls.trigger(Events.ERROR, {
|
19521
19537
|
type: ErrorTypes.MEDIA_ERROR,
|
19522
19538
|
details: ErrorDetails.BUFFER_SEEK_OVER_HOLE,
|
19523
19539
|
fatal: false,
|
19524
19540
|
error: error,
|
19525
19541
|
reason: error.message,
|
19526
|
-
frag: partial
|
19542
|
+
frag: partial,
|
19543
|
+
buffer: bufferInfo.len,
|
19544
|
+
bufferInfo: bufferInfo
|
19527
19545
|
});
|
19528
19546
|
}
|
19529
19547
|
return targetTime;
|
@@ -19536,13 +19554,13 @@
|
|
19536
19554
|
* Attempts to fix buffer stalls by advancing the mediaElement's current time by a small amount.
|
19537
19555
|
* @private
|
19538
19556
|
*/;
|
19539
|
-
_proto._tryNudgeBuffer = function _tryNudgeBuffer() {
|
19540
|
-
var
|
19541
|
-
hls = this.hls,
|
19557
|
+
_proto._tryNudgeBuffer = function _tryNudgeBuffer(bufferInfo) {
|
19558
|
+
var hls = this.hls,
|
19542
19559
|
media = this.media,
|
19543
19560
|
nudgeRetry = this.nudgeRetry;
|
19544
|
-
|
19545
|
-
|
19561
|
+
var config = hls == null ? undefined : hls.config;
|
19562
|
+
if (!media || !config) {
|
19563
|
+
return 0;
|
19546
19564
|
}
|
19547
19565
|
var currentTime = media.currentTime;
|
19548
19566
|
this.nudgeRetry++;
|
@@ -19556,7 +19574,9 @@
|
|
19556
19574
|
type: ErrorTypes.MEDIA_ERROR,
|
19557
19575
|
details: ErrorDetails.BUFFER_NUDGE_ON_STALL,
|
19558
19576
|
error: error,
|
19559
|
-
fatal: false
|
19577
|
+
fatal: false,
|
19578
|
+
buffer: bufferInfo.len,
|
19579
|
+
bufferInfo: bufferInfo
|
19560
19580
|
});
|
19561
19581
|
} else {
|
19562
19582
|
var _error = new Error("Playhead still not moving while enough data buffered @" + currentTime + " after " + config.nudgeMaxRetry + " nudges");
|
@@ -19565,7 +19585,9 @@
|
|
19565
19585
|
type: ErrorTypes.MEDIA_ERROR,
|
19566
19586
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
19567
19587
|
error: _error,
|
19568
|
-
fatal: true
|
19588
|
+
fatal: true,
|
19589
|
+
buffer: bufferInfo.len,
|
19590
|
+
bufferInfo: bufferInfo
|
19569
19591
|
});
|
19570
19592
|
}
|
19571
19593
|
};
|
@@ -19735,7 +19757,7 @@
|
|
19735
19757
|
return !remuxResult.audio && !remuxResult.video && !remuxResult.text && !remuxResult.id3 && !remuxResult.initSegment;
|
19736
19758
|
}
|
19737
19759
|
|
19738
|
-
var version = "1.6.0-beta.2.0.canary.
|
19760
|
+
var version = "1.6.0-beta.2.0.canary.10884";
|
19739
19761
|
|
19740
19762
|
// ensure the worker ends up in the bundle
|
19741
19763
|
// If the worker should not be included this gets aliased to empty.js
|
@@ -20155,11 +20177,18 @@
|
|
20155
20177
|
_this.backtrackFragment = null;
|
20156
20178
|
_this.audioCodecSwitch = false;
|
20157
20179
|
_this.videoBuffer = null;
|
20180
|
+
_this.onMediaWaiting = function () {
|
20181
|
+
var gapController = _this.gapController;
|
20182
|
+
if (gapController) {
|
20183
|
+
gapController.waiting = self.performance.now();
|
20184
|
+
}
|
20185
|
+
};
|
20158
20186
|
_this.onMediaPlaying = function () {
|
20159
20187
|
// tick to speed up FRAG_CHANGED triggering
|
20160
20188
|
var gapController = _this.gapController;
|
20161
20189
|
if (gapController) {
|
20162
20190
|
gapController.ended = 0;
|
20191
|
+
gapController.waiting = 0;
|
20163
20192
|
}
|
20164
20193
|
_this.tick();
|
20165
20194
|
};
|
@@ -20214,7 +20243,7 @@
|
|
20214
20243
|
};
|
20215
20244
|
_proto.onHandlerDestroying = function onHandlerDestroying() {
|
20216
20245
|
// @ts-ignore
|
20217
|
-
this.onMediaPlaying = this.onMediaSeeked = null;
|
20246
|
+
this.onMediaPlaying = this.onMediaSeeked = this.onMediaWaiting = null;
|
20218
20247
|
this.unregisterListeners();
|
20219
20248
|
_BaseStreamController.prototype.onHandlerDestroying.call(this);
|
20220
20249
|
};
|
@@ -20535,15 +20564,18 @@
|
|
20535
20564
|
var media = data.media;
|
20536
20565
|
media.removeEventListener('playing', this.onMediaPlaying);
|
20537
20566
|
media.removeEventListener('seeked', this.onMediaSeeked);
|
20567
|
+
media.removeEventListener('waiting', this.onMediaWaiting);
|
20538
20568
|
media.addEventListener('playing', this.onMediaPlaying);
|
20539
20569
|
media.addEventListener('seeked', this.onMediaSeeked);
|
20540
|
-
|
20570
|
+
media.addEventListener('waiting', this.onMediaWaiting);
|
20571
|
+
this.gapController = new GapController(media, this.fragmentTracker, this.hls);
|
20541
20572
|
};
|
20542
20573
|
_proto.onMediaDetaching = function onMediaDetaching(event, data) {
|
20543
20574
|
var media = this.media;
|
20544
20575
|
if (media) {
|
20545
20576
|
media.removeEventListener('playing', this.onMediaPlaying);
|
20546
20577
|
media.removeEventListener('seeked', this.onMediaSeeked);
|
20578
|
+
media.removeEventListener('waiting', this.onMediaWaiting);
|
20547
20579
|
}
|
20548
20580
|
this.videoBuffer = null;
|
20549
20581
|
this.fragPlaying = null;
|
@@ -20953,7 +20985,7 @@
|
|
20953
20985
|
var startPosition = this.startPosition;
|
20954
20986
|
// only adjust currentTime if different from startPosition or if startPosition not buffered
|
20955
20987
|
// at that stage, there should be only one buffered range, as we reach that code after first fragment has been buffered
|
20956
|
-
if (startPosition >= 0) {
|
20988
|
+
if (startPosition >= 0 && currentTime < startPosition) {
|
20957
20989
|
if (media.seeking) {
|
20958
20990
|
this.log("could not seek to " + startPosition + ", already seeking at " + currentTime);
|
20959
20991
|
return;
|