hls.js 1.6.0-beta.2.0.canary.10882 → 1.6.0-beta.2.0.canary.10883
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 -0
- package/dist/hls.d.ts +21 -0
- package/dist/hls.js +109 -64
- package/dist/hls.js.d.ts +21 -0
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +109 -64
- 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 +106 -63
- 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 +106 -63
- 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/types/events.ts +3 -0
- package/src/utils/buffer-helper.ts +5 -8
package/dist/hls.light.mjs
CHANGED
@@ -77,6 +77,7 @@ let Events = /*#__PURE__*/function (Events) {
|
|
77
77
|
Events["MEDIA_DETACHING"] = "hlsMediaDetaching";
|
78
78
|
Events["MEDIA_DETACHED"] = "hlsMediaDetached";
|
79
79
|
Events["MEDIA_ENDED"] = "hlsMediaEnded";
|
80
|
+
Events["STALL_RESOLVED"] = "hlsStallResolved";
|
80
81
|
Events["BUFFER_RESET"] = "hlsBufferReset";
|
81
82
|
Events["BUFFER_CODECS"] = "hlsBufferCodecs";
|
82
83
|
Events["BUFFER_CREATED"] = "hlsBufferCreated";
|
@@ -401,7 +402,7 @@ function enableLogs(debugConfig, context, id) {
|
|
401
402
|
// Some browsers don't allow to use bind on console object anyway
|
402
403
|
// fallback to default if needed
|
403
404
|
try {
|
404
|
-
newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.0-beta.2.0.canary.
|
405
|
+
newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.0-beta.2.0.canary.10883"}`);
|
405
406
|
} catch (e) {
|
406
407
|
/* log fn threw an exception. All logger methods are no-ops. */
|
407
408
|
return createLogger();
|
@@ -7283,8 +7284,7 @@ class BufferHelper {
|
|
7283
7284
|
return {
|
7284
7285
|
len: 0,
|
7285
7286
|
start: pos,
|
7286
|
-
end: pos
|
7287
|
-
nextStart: undefined
|
7287
|
+
end: pos
|
7288
7288
|
};
|
7289
7289
|
}
|
7290
7290
|
static bufferedInfo(buffered, pos, maxHoleDuration) {
|
@@ -7347,7 +7347,8 @@ class BufferHelper {
|
|
7347
7347
|
len: bufferLen,
|
7348
7348
|
start: bufferStart || 0,
|
7349
7349
|
end: bufferEnd || 0,
|
7350
|
-
nextStart: bufferStartNext
|
7350
|
+
nextStart: bufferStartNext,
|
7351
|
+
buffered
|
7351
7352
|
};
|
7352
7353
|
}
|
7353
7354
|
|
@@ -17283,6 +17284,7 @@ const hlsDefaultConfig = _objectSpread2(_objectSpread2({
|
|
17283
17284
|
progressive: false,
|
17284
17285
|
lowLatencyMode: true,
|
17285
17286
|
cmcd: undefined,
|
17287
|
+
detectStallWithCurrentTimeMs: 1250,
|
17286
17288
|
enableDateRangeMetadataCues: true,
|
17287
17289
|
enableEmsgMetadataCues: true,
|
17288
17290
|
enableEmsgKLVMetadata: false,
|
@@ -18768,32 +18770,28 @@ function assignTrackIdsByGroup(tracks) {
|
|
18768
18770
|
});
|
18769
18771
|
}
|
18770
18772
|
|
18771
|
-
const STALL_MINIMUM_DURATION_MS = 250;
|
18772
18773
|
const MAX_START_GAP_JUMP = 2.0;
|
18773
18774
|
const SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
|
18774
18775
|
const SKIP_BUFFER_RANGE_START = 0.05;
|
18775
18776
|
class GapController extends Logger {
|
18776
|
-
constructor(
|
18777
|
+
constructor(media, fragmentTracker, hls) {
|
18777
18778
|
super('gap-controller', hls.logger);
|
18778
|
-
this.config = undefined;
|
18779
18779
|
this.media = null;
|
18780
|
-
this.fragmentTracker =
|
18781
|
-
this.hls =
|
18780
|
+
this.fragmentTracker = null;
|
18781
|
+
this.hls = null;
|
18782
18782
|
this.nudgeRetry = 0;
|
18783
18783
|
this.stallReported = false;
|
18784
18784
|
this.stalled = null;
|
18785
18785
|
this.moved = false;
|
18786
18786
|
this.seeking = false;
|
18787
18787
|
this.ended = 0;
|
18788
|
-
this.
|
18788
|
+
this.waiting = 0;
|
18789
18789
|
this.media = media;
|
18790
18790
|
this.fragmentTracker = fragmentTracker;
|
18791
18791
|
this.hls = hls;
|
18792
18792
|
}
|
18793
18793
|
destroy() {
|
18794
|
-
this.media = null;
|
18795
|
-
// @ts-ignore
|
18796
|
-
this.hls = this.fragmentTracker = null;
|
18794
|
+
this.media = this.hls = this.fragmentTracker = null;
|
18797
18795
|
}
|
18798
18796
|
|
18799
18797
|
/**
|
@@ -18803,12 +18801,12 @@ class GapController extends Logger {
|
|
18803
18801
|
* @param lastCurrentTime - Previously read playhead position
|
18804
18802
|
*/
|
18805
18803
|
poll(lastCurrentTime, activeFrag, levelDetails, state) {
|
18804
|
+
var _this$hls;
|
18806
18805
|
const {
|
18807
|
-
config,
|
18808
18806
|
media,
|
18809
18807
|
stalled
|
18810
18808
|
} = this;
|
18811
|
-
if (media
|
18809
|
+
if (!media) {
|
18812
18810
|
return;
|
18813
18811
|
}
|
18814
18812
|
const {
|
@@ -18828,43 +18826,45 @@ class GapController extends Logger {
|
|
18828
18826
|
if (!seeking) {
|
18829
18827
|
this.nudgeRetry = 0;
|
18830
18828
|
}
|
18831
|
-
if (
|
18832
|
-
|
18833
|
-
if (this.stallReported) {
|
18834
|
-
const _stalledDuration = self.performance.now() - stalled;
|
18835
|
-
this.warn(`playback not stuck anymore @${currentTime}, after ${Math.round(_stalledDuration)}ms`);
|
18836
|
-
this.stallReported = false;
|
18837
|
-
}
|
18838
|
-
this.stalled = null;
|
18829
|
+
if (this.waiting === 0) {
|
18830
|
+
this.stallResolved(currentTime);
|
18839
18831
|
}
|
18840
18832
|
return;
|
18841
18833
|
}
|
18842
18834
|
|
18843
18835
|
// Clear stalled state when beginning or finishing seeking so that we don't report stalls coming out of a seek
|
18844
18836
|
if (beginSeek || seeked) {
|
18845
|
-
|
18837
|
+
if (seeked) {
|
18838
|
+
this.stallResolved(currentTime);
|
18839
|
+
}
|
18846
18840
|
return;
|
18847
18841
|
}
|
18848
18842
|
|
18849
18843
|
// The playhead should not be moving
|
18850
|
-
if (media.paused && !seeking || media.ended || media.playbackRate === 0
|
18844
|
+
if (media.paused && !seeking || media.ended || media.playbackRate === 0) {
|
18845
|
+
this.nudgeRetry = 0;
|
18846
|
+
this.stallResolved(currentTime);
|
18851
18847
|
// Fire MEDIA_ENDED to workaround event not being dispatched by browser
|
18852
|
-
if (!this.ended && media.ended) {
|
18848
|
+
if (!this.ended && media.ended && this.hls) {
|
18853
18849
|
this.ended = currentTime || 1;
|
18854
18850
|
this.hls.trigger(Events.MEDIA_ENDED, {
|
18855
18851
|
stalled: false
|
18856
18852
|
});
|
18857
18853
|
}
|
18854
|
+
return;
|
18855
|
+
}
|
18856
|
+
if (!BufferHelper.getBuffered(media).length) {
|
18858
18857
|
this.nudgeRetry = 0;
|
18859
18858
|
return;
|
18860
18859
|
}
|
18861
18860
|
const bufferInfo = BufferHelper.bufferInfo(media, currentTime, 0);
|
18862
18861
|
const nextStart = bufferInfo.nextStart || 0;
|
18863
|
-
|
18862
|
+
const fragmentTracker = this.fragmentTracker;
|
18863
|
+
if (seeking && fragmentTracker) {
|
18864
18864
|
// Waiting for seeking in a buffered range to complete
|
18865
18865
|
const hasEnoughBuffer = bufferInfo.len > MAX_START_GAP_JUMP;
|
18866
18866
|
// Next buffered range is too far ahead to jump to while still seeking
|
18867
|
-
const noBufferGap = !nextStart || activeFrag && activeFrag.start <= currentTime || nextStart - currentTime > MAX_START_GAP_JUMP && !
|
18867
|
+
const noBufferGap = !nextStart || activeFrag && activeFrag.start <= currentTime || nextStart - currentTime > MAX_START_GAP_JUMP && !fragmentTracker.getPartialFragment(currentTime);
|
18868
18868
|
if (hasEnoughBuffer || noBufferGap) {
|
18869
18869
|
return;
|
18870
18870
|
}
|
@@ -18874,7 +18874,7 @@ class GapController extends Logger {
|
|
18874
18874
|
|
18875
18875
|
// Skip start gaps if we haven't played, but the last poll detected the start of a stall
|
18876
18876
|
// The addition poll gives the browser a chance to jump the gap for us
|
18877
|
-
if (!this.moved && this.stalled !== null) {
|
18877
|
+
if (!this.moved && this.stalled !== null && fragmentTracker) {
|
18878
18878
|
// There is no playable buffer (seeked, waiting for buffer)
|
18879
18879
|
const isBuffered = bufferInfo.len > 0;
|
18880
18880
|
if (!isBuffered && !nextStart) {
|
@@ -18888,7 +18888,7 @@ class GapController extends Logger {
|
|
18888
18888
|
// that begins over 1 target duration after the video start position.
|
18889
18889
|
const isLive = !!(levelDetails != null && levelDetails.live);
|
18890
18890
|
const maxStartGapJump = isLive ? levelDetails.targetduration * 2 : MAX_START_GAP_JUMP;
|
18891
|
-
const partialOrGap =
|
18891
|
+
const partialOrGap = fragmentTracker.getPartialFragment(currentTime);
|
18892
18892
|
if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
|
18893
18893
|
if (!media.paused) {
|
18894
18894
|
this._trySkipBufferHole(partialOrGap);
|
@@ -18898,16 +18898,27 @@ class GapController extends Logger {
|
|
18898
18898
|
}
|
18899
18899
|
|
18900
18900
|
// Start tracking stall time
|
18901
|
+
const config = (_this$hls = this.hls) == null ? undefined : _this$hls.config;
|
18902
|
+
if (!config) {
|
18903
|
+
return;
|
18904
|
+
}
|
18905
|
+
const detectStallWithCurrentTimeMs = config.detectStallWithCurrentTimeMs;
|
18901
18906
|
const tnow = self.performance.now();
|
18907
|
+
const tWaiting = this.waiting;
|
18902
18908
|
if (stalled === null) {
|
18903
|
-
|
18909
|
+
// Use time of recent "waiting" event
|
18910
|
+
if (tWaiting > 0 && tnow - tWaiting < detectStallWithCurrentTimeMs) {
|
18911
|
+
this.stalled = tWaiting;
|
18912
|
+
} else {
|
18913
|
+
this.stalled = tnow;
|
18914
|
+
}
|
18904
18915
|
return;
|
18905
18916
|
}
|
18906
18917
|
const stalledDuration = tnow - stalled;
|
18907
|
-
if (!seeking && stalledDuration >=
|
18918
|
+
if (!seeking && (stalledDuration >= detectStallWithCurrentTimeMs || tWaiting) && this.hls) {
|
18908
18919
|
// Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
|
18909
18920
|
if (state === State.ENDED && !(levelDetails != null && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? undefined : levelDetails.edge) || 0)) < 1) {
|
18910
|
-
if (
|
18921
|
+
if (this.ended) {
|
18911
18922
|
return;
|
18912
18923
|
}
|
18913
18924
|
this.ended = currentTime || 1;
|
@@ -18918,13 +18929,27 @@ class GapController extends Logger {
|
|
18918
18929
|
}
|
18919
18930
|
// Report stalling after trying to fix
|
18920
18931
|
this._reportStall(bufferInfo);
|
18921
|
-
if (!this.media) {
|
18932
|
+
if (!this.media || !this.hls) {
|
18922
18933
|
return;
|
18923
18934
|
}
|
18924
18935
|
}
|
18925
18936
|
const bufferedWithHoles = BufferHelper.bufferInfo(media, currentTime, config.maxBufferHole);
|
18926
18937
|
this._tryFixBufferStall(bufferedWithHoles, stalledDuration);
|
18927
18938
|
}
|
18939
|
+
stallResolved(currentTime) {
|
18940
|
+
const stalled = this.stalled;
|
18941
|
+
if (stalled && this.hls) {
|
18942
|
+
this.stalled = null;
|
18943
|
+
// The playhead is now moving, but was previously stalled
|
18944
|
+
if (this.stallReported) {
|
18945
|
+
const stalledDuration = self.performance.now() - stalled;
|
18946
|
+
this.warn(`playback not stuck anymore @${currentTime}, after ${Math.round(stalledDuration)}ms`);
|
18947
|
+
this.stallReported = false;
|
18948
|
+
this.waiting = 0;
|
18949
|
+
this.hls.trigger(Events.STALL_RESOLVED, {});
|
18950
|
+
}
|
18951
|
+
}
|
18952
|
+
}
|
18928
18953
|
|
18929
18954
|
/**
|
18930
18955
|
* Detects and attempts to fix known buffer stalling issues.
|
@@ -18933,12 +18958,13 @@ class GapController extends Logger {
|
|
18933
18958
|
* @private
|
18934
18959
|
*/
|
18935
18960
|
_tryFixBufferStall(bufferInfo, stalledDurationMs) {
|
18961
|
+
var _this$hls2;
|
18936
18962
|
const {
|
18937
|
-
config,
|
18938
18963
|
fragmentTracker,
|
18939
18964
|
media
|
18940
18965
|
} = this;
|
18941
|
-
|
18966
|
+
const config = (_this$hls2 = this.hls) == null ? undefined : _this$hls2.config;
|
18967
|
+
if (!media || !fragmentTracker || !config) {
|
18942
18968
|
return;
|
18943
18969
|
}
|
18944
18970
|
const currentTime = media.currentTime;
|
@@ -18958,13 +18984,12 @@ class GapController extends Logger {
|
|
18958
18984
|
// we may just have to "nudge" the playlist as the browser decoding/rendering engine
|
18959
18985
|
// needs to cross some sort of threshold covering all source-buffers content
|
18960
18986
|
// to start playing properly.
|
18961
|
-
|
18987
|
+
const bufferedRanges = bufferInfo.buffered;
|
18988
|
+
if ((bufferedRanges && bufferedRanges.length > 1 && bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
|
18962
18989
|
this.warn('Trying to nudge playhead over buffer-hole');
|
18963
18990
|
// Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
|
18964
18991
|
// We only try to jump the hole if it's under the configured size
|
18965
|
-
|
18966
|
-
this.stalled = null;
|
18967
|
-
this._tryNudgeBuffer();
|
18992
|
+
this._tryNudgeBuffer(bufferInfo);
|
18968
18993
|
}
|
18969
18994
|
}
|
18970
18995
|
|
@@ -18977,9 +19002,10 @@ class GapController extends Logger {
|
|
18977
19002
|
const {
|
18978
19003
|
hls,
|
18979
19004
|
media,
|
18980
|
-
stallReported
|
19005
|
+
stallReported,
|
19006
|
+
stalled
|
18981
19007
|
} = this;
|
18982
|
-
if (!stallReported && media) {
|
19008
|
+
if (!stallReported && stalled !== null && media && hls) {
|
18983
19009
|
// Report stalled error once
|
18984
19010
|
this.stallReported = true;
|
18985
19011
|
const error = new Error(`Playback stalling at @${media.currentTime} due to low buffer (${JSON.stringify(bufferInfo)})`);
|
@@ -18989,7 +19015,11 @@ class GapController extends Logger {
|
|
18989
19015
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
18990
19016
|
fatal: false,
|
18991
19017
|
error,
|
18992
|
-
buffer: bufferInfo.len
|
19018
|
+
buffer: bufferInfo.len,
|
19019
|
+
bufferInfo,
|
19020
|
+
stalled: {
|
19021
|
+
start: stalled
|
19022
|
+
}
|
18993
19023
|
});
|
18994
19024
|
}
|
18995
19025
|
}
|
@@ -19000,12 +19030,13 @@ class GapController extends Logger {
|
|
19000
19030
|
* @private
|
19001
19031
|
*/
|
19002
19032
|
_trySkipBufferHole(partial) {
|
19033
|
+
var _this$hls3;
|
19003
19034
|
const {
|
19004
|
-
|
19005
|
-
hls,
|
19035
|
+
fragmentTracker,
|
19006
19036
|
media
|
19007
19037
|
} = this;
|
19008
|
-
|
19038
|
+
const config = (_this$hls3 = this.hls) == null ? undefined : _this$hls3.config;
|
19039
|
+
if (!media || !fragmentTracker || !config) {
|
19009
19040
|
return 0;
|
19010
19041
|
}
|
19011
19042
|
|
@@ -19020,9 +19051,6 @@ class GapController extends Logger {
|
|
19020
19051
|
if (gapLength > 0 && (bufferStarved || waiting)) {
|
19021
19052
|
// Only allow large gaps to be skipped if it is a start gap, or all fragments in skip range are partial
|
19022
19053
|
if (gapLength > config.maxBufferHole) {
|
19023
|
-
const {
|
19024
|
-
fragmentTracker
|
19025
|
-
} = this;
|
19026
19054
|
let startGap = false;
|
19027
19055
|
if (currentTime === 0) {
|
19028
19056
|
const startFrag = fragmentTracker.getAppendedFrag(0, PlaylistLevelType.MAIN);
|
@@ -19053,17 +19081,18 @@ class GapController extends Logger {
|
|
19053
19081
|
const targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
|
19054
19082
|
this.warn(`skipping hole, adjusting currentTime from ${currentTime} to ${targetTime}`);
|
19055
19083
|
this.moved = true;
|
19056
|
-
this.stalled = null;
|
19057
19084
|
media.currentTime = targetTime;
|
19058
|
-
if (partial && !partial.gap) {
|
19085
|
+
if (partial && !partial.gap && this.hls) {
|
19059
19086
|
const error = new Error(`fragment loaded with buffer holes, seeking from ${currentTime} to ${targetTime}`);
|
19060
|
-
hls.trigger(Events.ERROR, {
|
19087
|
+
this.hls.trigger(Events.ERROR, {
|
19061
19088
|
type: ErrorTypes.MEDIA_ERROR,
|
19062
19089
|
details: ErrorDetails.BUFFER_SEEK_OVER_HOLE,
|
19063
19090
|
fatal: false,
|
19064
19091
|
error,
|
19065
19092
|
reason: error.message,
|
19066
|
-
frag: partial
|
19093
|
+
frag: partial,
|
19094
|
+
buffer: bufferInfo.len,
|
19095
|
+
bufferInfo
|
19067
19096
|
});
|
19068
19097
|
}
|
19069
19098
|
return targetTime;
|
@@ -19076,15 +19105,15 @@ class GapController extends Logger {
|
|
19076
19105
|
* Attempts to fix buffer stalls by advancing the mediaElement's current time by a small amount.
|
19077
19106
|
* @private
|
19078
19107
|
*/
|
19079
|
-
_tryNudgeBuffer() {
|
19108
|
+
_tryNudgeBuffer(bufferInfo) {
|
19080
19109
|
const {
|
19081
|
-
config,
|
19082
19110
|
hls,
|
19083
19111
|
media,
|
19084
19112
|
nudgeRetry
|
19085
19113
|
} = this;
|
19086
|
-
|
19087
|
-
|
19114
|
+
const config = hls == null ? undefined : hls.config;
|
19115
|
+
if (!media || !config) {
|
19116
|
+
return 0;
|
19088
19117
|
}
|
19089
19118
|
const currentTime = media.currentTime;
|
19090
19119
|
this.nudgeRetry++;
|
@@ -19098,7 +19127,9 @@ class GapController extends Logger {
|
|
19098
19127
|
type: ErrorTypes.MEDIA_ERROR,
|
19099
19128
|
details: ErrorDetails.BUFFER_NUDGE_ON_STALL,
|
19100
19129
|
error,
|
19101
|
-
fatal: false
|
19130
|
+
fatal: false,
|
19131
|
+
buffer: bufferInfo.len,
|
19132
|
+
bufferInfo
|
19102
19133
|
});
|
19103
19134
|
} else {
|
19104
19135
|
const error = new Error(`Playhead still not moving while enough data buffered @${currentTime} after ${config.nudgeMaxRetry} nudges`);
|
@@ -19107,13 +19138,15 @@ class GapController extends Logger {
|
|
19107
19138
|
type: ErrorTypes.MEDIA_ERROR,
|
19108
19139
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
19109
19140
|
error,
|
19110
|
-
fatal: true
|
19141
|
+
fatal: true,
|
19142
|
+
buffer: bufferInfo.len,
|
19143
|
+
bufferInfo
|
19111
19144
|
});
|
19112
19145
|
}
|
19113
19146
|
}
|
19114
19147
|
}
|
19115
19148
|
|
19116
|
-
const version = "1.6.0-beta.2.0.canary.
|
19149
|
+
const version = "1.6.0-beta.2.0.canary.10883";
|
19117
19150
|
|
19118
19151
|
// ensure the worker ends up in the bundle
|
19119
19152
|
// If the worker should not be included this gets aliased to empty.js
|
@@ -19540,11 +19573,18 @@ class StreamController extends BaseStreamController {
|
|
19540
19573
|
this.backtrackFragment = null;
|
19541
19574
|
this.audioCodecSwitch = false;
|
19542
19575
|
this.videoBuffer = null;
|
19576
|
+
this.onMediaWaiting = () => {
|
19577
|
+
const gapController = this.gapController;
|
19578
|
+
if (gapController) {
|
19579
|
+
gapController.waiting = self.performance.now();
|
19580
|
+
}
|
19581
|
+
};
|
19543
19582
|
this.onMediaPlaying = () => {
|
19544
19583
|
// tick to speed up FRAG_CHANGED triggering
|
19545
19584
|
const gapController = this.gapController;
|
19546
19585
|
if (gapController) {
|
19547
19586
|
gapController.ended = 0;
|
19587
|
+
gapController.waiting = 0;
|
19548
19588
|
}
|
19549
19589
|
this.tick();
|
19550
19590
|
};
|
@@ -19600,7 +19640,7 @@ class StreamController extends BaseStreamController {
|
|
19600
19640
|
}
|
19601
19641
|
onHandlerDestroying() {
|
19602
19642
|
// @ts-ignore
|
19603
|
-
this.onMediaPlaying = this.onMediaSeeked = null;
|
19643
|
+
this.onMediaPlaying = this.onMediaSeeked = this.onMediaWaiting = null;
|
19604
19644
|
this.unregisterListeners();
|
19605
19645
|
super.onHandlerDestroying();
|
19606
19646
|
}
|
@@ -19931,9 +19971,11 @@ class StreamController extends BaseStreamController {
|
|
19931
19971
|
const media = data.media;
|
19932
19972
|
media.removeEventListener('playing', this.onMediaPlaying);
|
19933
19973
|
media.removeEventListener('seeked', this.onMediaSeeked);
|
19974
|
+
media.removeEventListener('waiting', this.onMediaWaiting);
|
19934
19975
|
media.addEventListener('playing', this.onMediaPlaying);
|
19935
19976
|
media.addEventListener('seeked', this.onMediaSeeked);
|
19936
|
-
|
19977
|
+
media.addEventListener('waiting', this.onMediaWaiting);
|
19978
|
+
this.gapController = new GapController(media, this.fragmentTracker, this.hls);
|
19937
19979
|
}
|
19938
19980
|
onMediaDetaching(event, data) {
|
19939
19981
|
const {
|
@@ -19942,6 +19984,7 @@ class StreamController extends BaseStreamController {
|
|
19942
19984
|
if (media) {
|
19943
19985
|
media.removeEventListener('playing', this.onMediaPlaying);
|
19944
19986
|
media.removeEventListener('seeked', this.onMediaSeeked);
|
19987
|
+
media.removeEventListener('waiting', this.onMediaWaiting);
|
19945
19988
|
}
|
19946
19989
|
this.videoBuffer = null;
|
19947
19990
|
this.fragPlaying = null;
|
@@ -20369,7 +20412,7 @@ class StreamController extends BaseStreamController {
|
|
20369
20412
|
let startPosition = this.startPosition;
|
20370
20413
|
// only adjust currentTime if different from startPosition or if startPosition not buffered
|
20371
20414
|
// at that stage, there should be only one buffered range, as we reach that code after first fragment has been buffered
|
20372
|
-
if (startPosition >= 0) {
|
20415
|
+
if (startPosition >= 0 && currentTime < startPosition) {
|
20373
20416
|
if (media.seeking) {
|
20374
20417
|
this.log(`could not seek to ${startPosition}, already seeking at ${currentTime}`);
|
20375
20418
|
return;
|