hls.js 1.6.0-beta.4.0.canary.11033 → 1.6.0-beta.4.0.canary.11034

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.mjs CHANGED
@@ -402,7 +402,7 @@ function enableLogs(debugConfig, context, id) {
402
402
  // Some browsers don't allow to use bind on console object anyway
403
403
  // fallback to default if needed
404
404
  try {
405
- newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.0-beta.4.0.canary.11033"}`);
405
+ newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.0-beta.4.0.canary.11034"}`);
406
406
  } catch (e) {
407
407
  /* log fn threw an exception. All logger methods are no-ops. */
408
408
  return createLogger();
@@ -3226,8 +3226,8 @@ class AbrController extends Logger {
3226
3226
  This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
3227
3227
  quickly enough to prevent underbuffering
3228
3228
  */
3229
- this._abandonRulesCheck = () => {
3230
- var _this$hls$latestLevel;
3229
+ this._abandonRulesCheck = levelLoaded => {
3230
+ var _ref;
3231
3231
  const {
3232
3232
  fragCurrent: frag,
3233
3233
  partCurrent: part,
@@ -3245,20 +3245,29 @@ class AbrController extends Logger {
3245
3245
  const duration = part ? part.duration : frag.duration;
3246
3246
  const timeLoading = now - stats.loading.start;
3247
3247
  const minAutoLevel = hls.minAutoLevel;
3248
+ const loadingFragForLevel = frag.level;
3249
+ const currentAutoLevel = this._nextAutoLevel;
3248
3250
  // If frag loading is aborted, complete, or from lowest level, stop timer and return
3249
- if (stats.aborted || stats.loaded && stats.loaded === stats.total || frag.level <= minAutoLevel) {
3251
+ if (stats.aborted || stats.loaded && stats.loaded === stats.total || loadingFragForLevel <= minAutoLevel) {
3250
3252
  this.clearTimer();
3251
3253
  // reset forced auto level value so that next level will be selected
3252
3254
  this._nextAutoLevel = -1;
3253
3255
  return;
3254
3256
  }
3255
3257
 
3256
- // This check only runs if we're in ABR mode and actually playing
3257
- if (!autoLevelEnabled || media.paused || !media.playbackRate || !media.readyState) {
3258
+ // This check only runs if we're in ABR mode
3259
+ if (!autoLevelEnabled) {
3260
+ return;
3261
+ }
3262
+
3263
+ // Must be loading/loaded a new level or be in a playing state
3264
+ const fragBlockingSwitch = currentAutoLevel > -1 && currentAutoLevel !== loadingFragForLevel;
3265
+ const levelChange = !!levelLoaded || fragBlockingSwitch;
3266
+ if (!levelChange && (media.paused || !media.playbackRate || !media.readyState)) {
3258
3267
  return;
3259
3268
  }
3260
3269
  const bufferInfo = hls.mainForwardBufferInfo;
3261
- if (bufferInfo === null) {
3270
+ if (!levelChange && bufferInfo === null) {
3262
3271
  return;
3263
3272
  }
3264
3273
  const ttfbEstimate = this.bwEstimator.getEstimateTTFB();
@@ -3269,12 +3278,12 @@ class AbrController extends Logger {
3269
3278
  }
3270
3279
 
3271
3280
  // bufferStarvationDelay is an estimate of the amount time (in seconds) it will take to exhaust the buffer
3272
- const bufferStarvationDelay = bufferInfo.len / playbackRate;
3281
+ const bufferStarvationDelay = bufferInfo ? bufferInfo.len / playbackRate : 0;
3273
3282
  const ttfb = stats.loading.first ? stats.loading.first - stats.loading.start : -1;
3274
3283
  const loadedFirstByte = stats.loaded && ttfb > -1;
3275
3284
  const bwEstimate = this.getBwEstimate();
3276
3285
  const levels = hls.levels;
3277
- const level = levels[frag.level];
3286
+ const level = levels[loadingFragForLevel];
3278
3287
  const expectedLen = Math.max(stats.loaded, Math.round(duration * (frag.bitrate || level.averageBitrate) / 8));
3279
3288
  let timeStreaming = loadedFirstByte ? timeLoading - ttfb : timeLoading;
3280
3289
  if (timeStreaming < 1 && loadedFirstByte) {
@@ -3289,12 +3298,12 @@ class AbrController extends Logger {
3289
3298
  return;
3290
3299
  }
3291
3300
  const bwe = loadRate ? loadRate * 8 : bwEstimate;
3292
- const live = ((_this$hls$latestLevel = this.hls.latestLevelDetails) == null ? void 0 : _this$hls$latestLevel.live) === true;
3301
+ const live = ((_ref = (levelLoaded == null ? void 0 : levelLoaded.details) || this.hls.latestLevelDetails) == null ? void 0 : _ref.live) === true;
3293
3302
  const abrBandWidthUpFactor = this.hls.config.abrBandWidthUpFactor;
3294
3303
  let fragLevelNextLoadedDelay = Number.POSITIVE_INFINITY;
3295
3304
  let nextLoadLevel;
3296
3305
  // Iterate through lower level and try to find the largest one that avoids rebuffering
3297
- for (nextLoadLevel = frag.level - 1; nextLoadLevel > minAutoLevel; nextLoadLevel--) {
3306
+ for (nextLoadLevel = loadingFragForLevel - 1; nextLoadLevel > minAutoLevel; nextLoadLevel--) {
3298
3307
  // compute time to load next fragment at lower level
3299
3308
  // 8 = bits per byte (bps/Bps)
3300
3309
  const levelNextBitrate = levels[nextLoadLevel].maxBitrate;
@@ -3329,7 +3338,7 @@ class AbrController extends Logger {
3329
3338
  if (bestSwitchLevel > -1) {
3330
3339
  nextLoadLevel = bestSwitchLevel;
3331
3340
  }
3332
- this.warn(`Fragment ${frag.sn}${part ? ' part ' + part.index : ''} of level ${frag.level} is loading too slowly;
3341
+ this.warn(`Fragment ${frag.sn}${part ? ' part ' + part.index : ''} of level ${loadingFragForLevel} is loading too slowly;
3333
3342
  Fragment duration: ${frag.duration.toFixed(3)}
3334
3343
  Time to underbuffer: ${bufferStarvationDelay.toFixed(3)} s
3335
3344
  Estimated load time for current fragment: ${fragLoadedDelay.toFixed(3)} s
@@ -3340,7 +3349,7 @@ class AbrController extends Logger {
3340
3349
  Switching to level ${nextLoadLevel} @ ${nextLoadLevelBitrate | 0} bps`);
3341
3350
  hls.nextLoadLevel = hls.nextAutoLevel = nextLoadLevel;
3342
3351
  this.clearTimer();
3343
- this.timer = self.setInterval(() => {
3352
+ const abortAndSwitch = () => {
3344
3353
  // Are nextLoadLevel details available or is stream-controller still in "WAITING_LEVEL" state?
3345
3354
  this.clearTimer();
3346
3355
  if (this.fragCurrent === frag && this.hls.loadLevel === nextLoadLevel && nextLoadLevel > 0) {
@@ -3359,7 +3368,12 @@ class AbrController extends Logger {
3359
3368
  this.resetEstimator(this.hls.levels[lowestSwitchLevel].bitrate);
3360
3369
  }
3361
3370
  }
3362
- }, fragLevelNextLoadedDelay * 1000);
3371
+ };
3372
+ if (fragBlockingSwitch || fragLoadedDelay > fragLevelNextLoadedDelay * 2) {
3373
+ abortAndSwitch();
3374
+ } else {
3375
+ this.timer = self.setInterval(abortAndSwitch, fragLevelNextLoadedDelay * 1000);
3376
+ }
3363
3377
  hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
3364
3378
  frag,
3365
3379
  part,
@@ -3494,7 +3508,7 @@ class AbrController extends Logger {
3494
3508
  }
3495
3509
  getTimeToLoadFrag(timeToFirstByteSec, bandwidth, fragSizeBits, isSwitch) {
3496
3510
  const fragLoadSec = timeToFirstByteSec + fragSizeBits / bandwidth;
3497
- const playlistLoadSec = isSwitch ? this.lastLevelLoadSec : 0;
3511
+ const playlistLoadSec = isSwitch ? timeToFirstByteSec + this.lastLevelLoadSec : 0;
3498
3512
  return fragLoadSec + playlistLoadSec;
3499
3513
  }
3500
3514
  onLevelLoaded(event, data) {
@@ -3502,7 +3516,7 @@ class AbrController extends Logger {
3502
3516
  const {
3503
3517
  loading
3504
3518
  } = data.stats;
3505
- const timeLoadingMs = loading.end - loading.start;
3519
+ const timeLoadingMs = loading.end - loading.first;
3506
3520
  if (isFiniteNumber(timeLoadingMs)) {
3507
3521
  this.lastLevelLoadSec = timeLoadingMs / 1000;
3508
3522
  }
@@ -3511,6 +3525,9 @@ class AbrController extends Logger {
3511
3525
  } else {
3512
3526
  this.bwEstimator.update(config.abrEwmaSlowVoD, config.abrEwmaFastVoD);
3513
3527
  }
3528
+ if (this.timer > -1) {
3529
+ this._abandonRulesCheck(data.levelInfo);
3530
+ }
3514
3531
  }
3515
3532
  onFragLoaded(event, {
3516
3533
  frag,
@@ -3720,7 +3737,7 @@ class AbrController extends Logger {
3720
3737
  return this.bwEstimator.canEstimate() ? this.bwEstimator.getEstimate() : this.hls.config.abrEwmaDefaultEstimate;
3721
3738
  }
3722
3739
  findBestLevel(currentBw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor) {
3723
- var _this$hls$latestLevel2;
3740
+ var _this$hls$latestLevel;
3724
3741
  const maxFetchDuration = bufferStarvationDelay + maxStarvationDelay;
3725
3742
  const lastLoadedFragLevel = this.lastLoadedFragLevel;
3726
3743
  const selectionBaseLevel = lastLoadedFragLevel === -1 ? this.hls.firstLevel : lastLoadedFragLevel;
@@ -3738,7 +3755,7 @@ class AbrController extends Logger {
3738
3755
  return 0;
3739
3756
  }
3740
3757
  const level = levels[selectionBaseLevel];
3741
- const live = !!((_this$hls$latestLevel2 = this.hls.latestLevelDetails) != null && _this$hls$latestLevel2.live);
3758
+ const live = !!((_this$hls$latestLevel = this.hls.latestLevelDetails) != null && _this$hls$latestLevel.live);
3742
3759
  const firstSelection = loadLevel === -1 || lastLoadedFragLevel === -1;
3743
3760
  let currentCodecSet;
3744
3761
  let currentVideoRange = 'SDR';
@@ -4919,7 +4936,6 @@ class FragmentTracker {
4919
4936
  }
4920
4937
  removeFragment(fragment) {
4921
4938
  const fragKey = getFragmentKey(fragment);
4922
- fragment.stats.loaded = 0;
4923
4939
  fragment.clearElementaryStreamInfo();
4924
4940
  const activeParts = this.activePartLists[fragment.type];
4925
4941
  if (activeParts) {
@@ -9048,7 +9064,7 @@ class BaseStreamController extends TaskLoop {
9048
9064
  const mainStart = this.hls.startPosition;
9049
9065
  const liveSyncPosition = this.hls.liveSyncPosition;
9050
9066
  const startPosition = frag ? (mainStart !== -1 && mainStart >= start ? mainStart : liveSyncPosition) || frag.start : pos;
9051
- this.log(`Setting startPosition to ${startPosition} to match initial live edge. mainStart: ${mainStart} liveSyncPosition: ${liveSyncPosition} frag.start: ${(_frag = frag) == null ? void 0 : _frag.start}`);
9067
+ this.log(`Setting startPosition to ${startPosition} to match start frag at live edge. mainStart: ${mainStart} liveSyncPosition: ${liveSyncPosition} frag.start: ${(_frag = frag) == null ? void 0 : _frag.start}`);
9052
9068
  this.startPosition = this.nextLoadPosition = startPosition;
9053
9069
  }
9054
9070
  } else if (pos <= start) {
@@ -9274,6 +9290,7 @@ class BaseStreamController extends TaskLoop {
9274
9290
  // Leave this.startPosition at -1, so that we can use `getInitialLiveFragment` logic when startPosition has
9275
9291
  // not been specified via the config or an as an argument to startLoad (#3736).
9276
9292
  startPosition = this.hls.liveSyncPosition || sliding;
9293
+ this.log(`Setting startPosition to -1 to start at live edge ${startPosition}`);
9277
9294
  this.startPosition = -1;
9278
9295
  } else {
9279
9296
  this.log(`setting startPosition to 0 by default`);
@@ -9951,7 +9968,7 @@ function requireEventemitter3 () {
9951
9968
  var eventemitter3Exports = requireEventemitter3();
9952
9969
  var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
9953
9970
 
9954
- const version = "1.6.0-beta.4.0.canary.11033";
9971
+ const version = "1.6.0-beta.4.0.canary.11034";
9955
9972
 
9956
9973
  // ensure the worker ends up in the bundle
9957
9974
  // If the worker should not be included this gets aliased to empty.js
@@ -24868,8 +24885,9 @@ MediaSource ${stringify(attachMediaSourceData)} from ${logFromSource}`);
24868
24885
  }
24869
24886
  }
24870
24887
  startLoadingPrimaryAt(timelinePos, skipSeekToStartPosition) {
24888
+ var _hls$mainForwardBuffe;
24871
24889
  const hls = this.hls;
24872
- if (!hls.loadingEnabled || !hls.media || Math.abs(hls.media.currentTime - timelinePos) > 0.5) {
24890
+ if (!hls.loadingEnabled || !hls.media || Math.abs((((_hls$mainForwardBuffe = hls.mainForwardBufferInfo) == null ? void 0 : _hls$mainForwardBuffe.start) || hls.media.currentTime) - timelinePos) > 0.5) {
24873
24891
  hls.startLoad(timelinePos, skipSeekToStartPosition);
24874
24892
  } else if (!hls.bufferingEnabled) {
24875
24893
  hls.resumeBuffering();
@@ -25072,11 +25090,11 @@ MediaSource ${stringify(attachMediaSourceData)} from ${logFromSource}`);
25072
25090
  }
25073
25091
  const isInterstitial = this.isInterstitial(item);
25074
25092
  const bufferingPlayer = this.getBufferingPlayer();
25075
- const timeRemaining = bufferingPlayer ? bufferingPlayer.remaining : bufferingLast ? bufferingLast.end - this.timelinePos : 0;
25076
- this.log(`buffered to boundary ${segmentToString(item)}` + (bufferingLast ? ` (${timeRemaining.toFixed(2)} remaining)` : ''));
25077
25093
  this.bufferingItem = item;
25078
25094
  this.bufferedPos = Math.max(item.start, Math.min(item.end, this.timelinePos));
25079
25095
  if (!this.playbackDisabled) {
25096
+ const timeRemaining = bufferingPlayer ? bufferingPlayer.remaining : bufferingLast ? bufferingLast.end - this.timelinePos : 0;
25097
+ this.log(`buffered to boundary ${segmentToString(item)}` + (bufferingLast ? ` (${timeRemaining.toFixed(2)} remaining)` : ''));
25080
25098
  if (isInterstitial) {
25081
25099
  // primary fragment loading will exit early in base-stream-controller while `bufferingItem` is set to an Interstitial block
25082
25100
  item.event.assetList.forEach(asset => {
@@ -32211,8 +32229,7 @@ class StreamController extends BaseStreamController {
32211
32229
  return;
32212
32230
  }
32213
32231
  const liveSyncPosition = this.hls.liveSyncPosition;
32214
- const mediaCurrentTime = media.currentTime;
32215
- const currentTime = this.hasEnoughToStart || mediaCurrentTime > 0 ? mediaCurrentTime : this.startPosition;
32232
+ const currentTime = this.getLoadPosition();
32216
32233
  const start = levelDetails.fragmentStart;
32217
32234
  const end = levelDetails.edge;
32218
32235
  const withinSlidingWindow = currentTime >= start - config.maxFragLookUpTolerance && currentTime <= end;