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.
@@ -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();
@@ -2852,8 +2852,8 @@ class AbrController extends Logger {
2852
2852
  This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
2853
2853
  quickly enough to prevent underbuffering
2854
2854
  */
2855
- this._abandonRulesCheck = () => {
2856
- var _this$hls$latestLevel;
2855
+ this._abandonRulesCheck = levelLoaded => {
2856
+ var _ref;
2857
2857
  const {
2858
2858
  fragCurrent: frag,
2859
2859
  partCurrent: part,
@@ -2871,20 +2871,29 @@ class AbrController extends Logger {
2871
2871
  const duration = part ? part.duration : frag.duration;
2872
2872
  const timeLoading = now - stats.loading.start;
2873
2873
  const minAutoLevel = hls.minAutoLevel;
2874
+ const loadingFragForLevel = frag.level;
2875
+ const currentAutoLevel = this._nextAutoLevel;
2874
2876
  // If frag loading is aborted, complete, or from lowest level, stop timer and return
2875
- if (stats.aborted || stats.loaded && stats.loaded === stats.total || frag.level <= minAutoLevel) {
2877
+ if (stats.aborted || stats.loaded && stats.loaded === stats.total || loadingFragForLevel <= minAutoLevel) {
2876
2878
  this.clearTimer();
2877
2879
  // reset forced auto level value so that next level will be selected
2878
2880
  this._nextAutoLevel = -1;
2879
2881
  return;
2880
2882
  }
2881
2883
 
2882
- // This check only runs if we're in ABR mode and actually playing
2883
- if (!autoLevelEnabled || media.paused || !media.playbackRate || !media.readyState) {
2884
+ // This check only runs if we're in ABR mode
2885
+ if (!autoLevelEnabled) {
2886
+ return;
2887
+ }
2888
+
2889
+ // Must be loading/loaded a new level or be in a playing state
2890
+ const fragBlockingSwitch = currentAutoLevel > -1 && currentAutoLevel !== loadingFragForLevel;
2891
+ const levelChange = !!levelLoaded || fragBlockingSwitch;
2892
+ if (!levelChange && (media.paused || !media.playbackRate || !media.readyState)) {
2884
2893
  return;
2885
2894
  }
2886
2895
  const bufferInfo = hls.mainForwardBufferInfo;
2887
- if (bufferInfo === null) {
2896
+ if (!levelChange && bufferInfo === null) {
2888
2897
  return;
2889
2898
  }
2890
2899
  const ttfbEstimate = this.bwEstimator.getEstimateTTFB();
@@ -2895,12 +2904,12 @@ class AbrController extends Logger {
2895
2904
  }
2896
2905
 
2897
2906
  // bufferStarvationDelay is an estimate of the amount time (in seconds) it will take to exhaust the buffer
2898
- const bufferStarvationDelay = bufferInfo.len / playbackRate;
2907
+ const bufferStarvationDelay = bufferInfo ? bufferInfo.len / playbackRate : 0;
2899
2908
  const ttfb = stats.loading.first ? stats.loading.first - stats.loading.start : -1;
2900
2909
  const loadedFirstByte = stats.loaded && ttfb > -1;
2901
2910
  const bwEstimate = this.getBwEstimate();
2902
2911
  const levels = hls.levels;
2903
- const level = levels[frag.level];
2912
+ const level = levels[loadingFragForLevel];
2904
2913
  const expectedLen = Math.max(stats.loaded, Math.round(duration * (frag.bitrate || level.averageBitrate) / 8));
2905
2914
  let timeStreaming = loadedFirstByte ? timeLoading - ttfb : timeLoading;
2906
2915
  if (timeStreaming < 1 && loadedFirstByte) {
@@ -2915,12 +2924,12 @@ class AbrController extends Logger {
2915
2924
  return;
2916
2925
  }
2917
2926
  const bwe = loadRate ? loadRate * 8 : bwEstimate;
2918
- const live = ((_this$hls$latestLevel = this.hls.latestLevelDetails) == null ? void 0 : _this$hls$latestLevel.live) === true;
2927
+ const live = ((_ref = (levelLoaded == null ? void 0 : levelLoaded.details) || this.hls.latestLevelDetails) == null ? void 0 : _ref.live) === true;
2919
2928
  const abrBandWidthUpFactor = this.hls.config.abrBandWidthUpFactor;
2920
2929
  let fragLevelNextLoadedDelay = Number.POSITIVE_INFINITY;
2921
2930
  let nextLoadLevel;
2922
2931
  // Iterate through lower level and try to find the largest one that avoids rebuffering
2923
- for (nextLoadLevel = frag.level - 1; nextLoadLevel > minAutoLevel; nextLoadLevel--) {
2932
+ for (nextLoadLevel = loadingFragForLevel - 1; nextLoadLevel > minAutoLevel; nextLoadLevel--) {
2924
2933
  // compute time to load next fragment at lower level
2925
2934
  // 8 = bits per byte (bps/Bps)
2926
2935
  const levelNextBitrate = levels[nextLoadLevel].maxBitrate;
@@ -2955,7 +2964,7 @@ class AbrController extends Logger {
2955
2964
  if (bestSwitchLevel > -1) {
2956
2965
  nextLoadLevel = bestSwitchLevel;
2957
2966
  }
2958
- this.warn(`Fragment ${frag.sn}${part ? ' part ' + part.index : ''} of level ${frag.level} is loading too slowly;
2967
+ this.warn(`Fragment ${frag.sn}${part ? ' part ' + part.index : ''} of level ${loadingFragForLevel} is loading too slowly;
2959
2968
  Fragment duration: ${frag.duration.toFixed(3)}
2960
2969
  Time to underbuffer: ${bufferStarvationDelay.toFixed(3)} s
2961
2970
  Estimated load time for current fragment: ${fragLoadedDelay.toFixed(3)} s
@@ -2966,7 +2975,7 @@ class AbrController extends Logger {
2966
2975
  Switching to level ${nextLoadLevel} @ ${nextLoadLevelBitrate | 0} bps`);
2967
2976
  hls.nextLoadLevel = hls.nextAutoLevel = nextLoadLevel;
2968
2977
  this.clearTimer();
2969
- this.timer = self.setInterval(() => {
2978
+ const abortAndSwitch = () => {
2970
2979
  // Are nextLoadLevel details available or is stream-controller still in "WAITING_LEVEL" state?
2971
2980
  this.clearTimer();
2972
2981
  if (this.fragCurrent === frag && this.hls.loadLevel === nextLoadLevel && nextLoadLevel > 0) {
@@ -2985,7 +2994,12 @@ class AbrController extends Logger {
2985
2994
  this.resetEstimator(this.hls.levels[lowestSwitchLevel].bitrate);
2986
2995
  }
2987
2996
  }
2988
- }, fragLevelNextLoadedDelay * 1000);
2997
+ };
2998
+ if (fragBlockingSwitch || fragLoadedDelay > fragLevelNextLoadedDelay * 2) {
2999
+ abortAndSwitch();
3000
+ } else {
3001
+ this.timer = self.setInterval(abortAndSwitch, fragLevelNextLoadedDelay * 1000);
3002
+ }
2989
3003
  hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
2990
3004
  frag,
2991
3005
  part,
@@ -3120,7 +3134,7 @@ class AbrController extends Logger {
3120
3134
  }
3121
3135
  getTimeToLoadFrag(timeToFirstByteSec, bandwidth, fragSizeBits, isSwitch) {
3122
3136
  const fragLoadSec = timeToFirstByteSec + fragSizeBits / bandwidth;
3123
- const playlistLoadSec = isSwitch ? this.lastLevelLoadSec : 0;
3137
+ const playlistLoadSec = isSwitch ? timeToFirstByteSec + this.lastLevelLoadSec : 0;
3124
3138
  return fragLoadSec + playlistLoadSec;
3125
3139
  }
3126
3140
  onLevelLoaded(event, data) {
@@ -3128,7 +3142,7 @@ class AbrController extends Logger {
3128
3142
  const {
3129
3143
  loading
3130
3144
  } = data.stats;
3131
- const timeLoadingMs = loading.end - loading.start;
3145
+ const timeLoadingMs = loading.end - loading.first;
3132
3146
  if (isFiniteNumber(timeLoadingMs)) {
3133
3147
  this.lastLevelLoadSec = timeLoadingMs / 1000;
3134
3148
  }
@@ -3137,6 +3151,9 @@ class AbrController extends Logger {
3137
3151
  } else {
3138
3152
  this.bwEstimator.update(config.abrEwmaSlowVoD, config.abrEwmaFastVoD);
3139
3153
  }
3154
+ if (this.timer > -1) {
3155
+ this._abandonRulesCheck(data.levelInfo);
3156
+ }
3140
3157
  }
3141
3158
  onFragLoaded(event, {
3142
3159
  frag,
@@ -3346,7 +3363,7 @@ class AbrController extends Logger {
3346
3363
  return this.bwEstimator.canEstimate() ? this.bwEstimator.getEstimate() : this.hls.config.abrEwmaDefaultEstimate;
3347
3364
  }
3348
3365
  findBestLevel(currentBw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor) {
3349
- var _this$hls$latestLevel2;
3366
+ var _this$hls$latestLevel;
3350
3367
  const maxFetchDuration = bufferStarvationDelay + maxStarvationDelay;
3351
3368
  const lastLoadedFragLevel = this.lastLoadedFragLevel;
3352
3369
  const selectionBaseLevel = lastLoadedFragLevel === -1 ? this.hls.firstLevel : lastLoadedFragLevel;
@@ -3364,7 +3381,7 @@ class AbrController extends Logger {
3364
3381
  return 0;
3365
3382
  }
3366
3383
  const level = levels[selectionBaseLevel];
3367
- const live = !!((_this$hls$latestLevel2 = this.hls.latestLevelDetails) != null && _this$hls$latestLevel2.live);
3384
+ const live = !!((_this$hls$latestLevel = this.hls.latestLevelDetails) != null && _this$hls$latestLevel.live);
3368
3385
  const firstSelection = loadLevel === -1 || lastLoadedFragLevel === -1;
3369
3386
  let currentCodecSet;
3370
3387
  let currentVideoRange = 'SDR';
@@ -6327,7 +6344,6 @@ class FragmentTracker {
6327
6344
  }
6328
6345
  removeFragment(fragment) {
6329
6346
  const fragKey = getFragmentKey(fragment);
6330
- fragment.stats.loaded = 0;
6331
6347
  fragment.clearElementaryStreamInfo();
6332
6348
  const activeParts = this.activePartLists[fragment.type];
6333
6349
  if (activeParts) {
@@ -8502,7 +8518,7 @@ class BaseStreamController extends TaskLoop {
8502
8518
  const mainStart = this.hls.startPosition;
8503
8519
  const liveSyncPosition = this.hls.liveSyncPosition;
8504
8520
  const startPosition = frag ? (mainStart !== -1 && mainStart >= start ? mainStart : liveSyncPosition) || frag.start : pos;
8505
- this.log(`Setting startPosition to ${startPosition} to match initial live edge. mainStart: ${mainStart} liveSyncPosition: ${liveSyncPosition} frag.start: ${(_frag = frag) == null ? void 0 : _frag.start}`);
8521
+ 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}`);
8506
8522
  this.startPosition = this.nextLoadPosition = startPosition;
8507
8523
  }
8508
8524
  } else if (pos <= start) {
@@ -8728,6 +8744,7 @@ class BaseStreamController extends TaskLoop {
8728
8744
  // Leave this.startPosition at -1, so that we can use `getInitialLiveFragment` logic when startPosition has
8729
8745
  // not been specified via the config or an as an argument to startLoad (#3736).
8730
8746
  startPosition = this.hls.liveSyncPosition || sliding;
8747
+ this.log(`Setting startPosition to -1 to start at live edge ${startPosition}`);
8731
8748
  this.startPosition = -1;
8732
8749
  } else {
8733
8750
  this.log(`setting startPosition to 0 by default`);
@@ -19450,7 +19467,7 @@ function assignTrackIdsByGroup(tracks) {
19450
19467
  });
19451
19468
  }
19452
19469
 
19453
- const version = "1.6.0-beta.4.0.canary.11033";
19470
+ const version = "1.6.0-beta.4.0.canary.11034";
19454
19471
 
19455
19472
  // ensure the worker ends up in the bundle
19456
19473
  // If the worker should not be included this gets aliased to empty.js
@@ -20394,8 +20411,7 @@ class StreamController extends BaseStreamController {
20394
20411
  return;
20395
20412
  }
20396
20413
  const liveSyncPosition = this.hls.liveSyncPosition;
20397
- const mediaCurrentTime = media.currentTime;
20398
- const currentTime = this.hasEnoughToStart || mediaCurrentTime > 0 ? mediaCurrentTime : this.startPosition;
20414
+ const currentTime = this.getLoadPosition();
20399
20415
  const start = levelDetails.fragmentStart;
20400
20416
  const end = levelDetails.edge;
20401
20417
  const withinSlidingWindow = currentTime >= start - config.maxFragLookUpTolerance && currentTime <= end;