Skip to content

Commit

Permalink
Check-in on abandon rules check and switch to lowest when stuck on in…
Browse files Browse the repository at this point in the history
…-flight frag

Resolves #6689
  • Loading branch information
robwalch committed Oct 9, 2024
1 parent c8ee777 commit e629ade
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 12 deletions.
70 changes: 61 additions & 9 deletions src/controller/abr-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ class AbrController extends Logger implements AbrComponentAPI {
}

const bwe = loadRate ? loadRate * 8 : bwEstimate;
const live = this.hls.latestLevelDetails?.live === true;
const abrBandWidthUpFactor = this.hls.config.abrBandWidthUpFactor;
let fragLevelNextLoadedDelay: number = Number.POSITIVE_INFINITY;
let nextLoadLevel: number;
// Iterate through lower level and try to find the largest one that avoids rebuffering
Expand All @@ -316,13 +318,17 @@ class AbrController extends Logger implements AbrComponentAPI {
// compute time to load next fragment at lower level
// 8 = bits per byte (bps/Bps)
const levelNextBitrate = levels[nextLoadLevel].maxBitrate;
const requiresLevelLoad = !levels[nextLoadLevel].details || live;
fragLevelNextLoadedDelay = this.getTimeToLoadFrag(
ttfbEstimate / 1000,
bwe,
duration * levelNextBitrate,
!levels[nextLoadLevel].details,
requiresLevelLoad,
);
if (fragLevelNextLoadedDelay < bufferStarvationDelay) {
if (
fragLevelNextLoadedDelay <
Math.min(bufferStarvationDelay, duration / abrBandWidthUpFactor)
) {
break;
}
}
Expand All @@ -336,7 +342,6 @@ class AbrController extends Logger implements AbrComponentAPI {
if (fragLevelNextLoadedDelay > duration * 10) {
return;
}
hls.nextLoadLevel = hls.nextAutoLevel = nextLoadLevel;
if (loadedFirstByte) {
// If there has been loading progress, sample bandwidth using loading time offset by minimum TTFB time
this.bwEstimator.sample(
Expand All @@ -348,17 +353,26 @@ class AbrController extends Logger implements AbrComponentAPI {
this.bwEstimator.sampleTTFB(timeLoading);
}
const nextLoadLevelBitrate = levels[nextLoadLevel].maxBitrate;
if (
this.getBwEstimate() * this.hls.config.abrBandWidthUpFactor >
nextLoadLevelBitrate
) {
if (this.getBwEstimate() * abrBandWidthUpFactor > nextLoadLevelBitrate) {
this.resetEstimator(nextLoadLevelBitrate);
}
const bestSwitchLevel = this.findBestLevel(
nextLoadLevelBitrate,
minAutoLevel,
nextLoadLevel,
0,
bufferStarvationDelay,
1,
1,
);
if (bestSwitchLevel > -1) {
nextLoadLevel = bestSwitchLevel;
}

this.clearTimer();
this.warn(`Fragment ${frag.sn}${
part ? ' part ' + part.index : ''
} of level ${frag.level} is loading too slowly;
Fragment duration: ${frag.duration.toFixed(3)}
Time to underbuffer: ${bufferStarvationDelay.toFixed(3)} s
Estimated load time for current fragment: ${fragLoadedDelay.toFixed(3)} s
Estimated load time for down switch fragment: ${fragLevelNextLoadedDelay.toFixed(
Expand All @@ -370,6 +384,44 @@ class AbrController extends Logger implements AbrComponentAPI {
} bps
New BW estimate: ${this.getBwEstimate() | 0} bps
Switching to level ${nextLoadLevel} @ ${nextLoadLevelBitrate | 0} bps`);

hls.nextLoadLevel = hls.nextAutoLevel = nextLoadLevel;

this.clearTimer();
this.timer = self.setInterval(() => {
// Are nextLoadLevel details available or is stream-controller still in "WAITING_LEVEL" state?
this.clearTimer();
if (
this.fragCurrent === frag &&
this.hls.loadLevel === nextLoadLevel &&
nextLoadLevel > 0
) {
const bufferStarvationDelay = this.getStarvationDelay();
this
.warn(`Aborting inflight request ${nextLoadLevel > 0 ? 'and switching down' : ''}
Fragment duration: ${frag.duration.toFixed(3)} s
Time to underbuffer: ${bufferStarvationDelay.toFixed(3)} s`);
frag.abortRequests();
this.fragCurrent = this.partCurrent = null;
if (nextLoadLevel > minAutoLevel) {
let lowestSwitchLevel = this.findBestLevel(
this.hls.levels[minAutoLevel].bitrate,
minAutoLevel,
nextLoadLevel,
0,
bufferStarvationDelay,
1,
1,
);
if (lowestSwitchLevel === -1) {
lowestSwitchLevel = minAutoLevel;
}
this.hls.nextLoadLevel = this.hls.nextAutoLevel = lowestSwitchLevel;
this.resetEstimator(this.hls.levels[lowestSwitchLevel].bitrate);
}
}
}, fragLevelNextLoadedDelay * 1000);

hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, { frag, part, stats });
};

Expand Down Expand Up @@ -665,7 +717,7 @@ class AbrController extends Logger implements AbrComponentAPI {
return 0;
}
const level: Level | undefined = levels[selectionBaseLevel];
const live = !!level?.details?.live;
const live = !!this.hls.latestLevelDetails?.live;
const firstSelection = loadLevel === -1 || lastLoadedFragLevel === -1;
let currentCodecSet: string | undefined;
let currentVideoRange: VideoRange | undefined = 'SDR';
Expand Down
10 changes: 7 additions & 3 deletions src/controller/level-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,11 +439,12 @@ export default class LevelController extends BasePlaylistController {

if (
lastLevelIndex === newLevel &&
level.details &&
lastLevel &&
lastPathwayId === pathwayId
) {
return;
if (level.details || this.requestScheduled !== -1) {
return;
}
}

this.log(
Expand Down Expand Up @@ -571,7 +572,10 @@ export default class LevelController extends BasePlaylistController {
data.context.type === PlaylistContextType.LEVEL &&
data.context.level === this.level
) {
this.checkRetry(data);
const retry = this.checkRetry(data);
if (!retry) {
this.requestScheduled = -1;
}
}
}

Expand Down

0 comments on commit e629ade

Please sign in to comment.