From 1a3c23512a9c364bbbfe62038de01c6cae12a093 Mon Sep 17 00:00:00 2001 From: Rob Walch Date: Mon, 1 Jul 2024 10:37:22 -0700 Subject: [PATCH] Reduce max buffer length in response to buffer full errors (#6530) Fixes #6529 --- api-extractor/report/hls.js.api.md | 2 +- src/controller/base-stream-controller.ts | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/api-extractor/report/hls.js.api.md b/api-extractor/report/hls.js.api.md index 6bb626a06b5..b46222f9e3b 100644 --- a/api-extractor/report/hls.js.api.md +++ b/api-extractor/report/hls.js.api.md @@ -453,7 +453,7 @@ export class BaseStreamController extends TaskLoop implements NetworkComponentAP // (undocumented) protected reduceLengthAndFlushBuffer(data: ErrorData): boolean; // (undocumented) - protected reduceMaxBufferLength(threshold: number): boolean; + protected reduceMaxBufferLength(threshold: number, fragDuration: number): boolean; // (undocumented) protected registerListeners(): void; // (undocumented) diff --git a/src/controller/base-stream-controller.ts b/src/controller/base-stream-controller.ts index d6413cfb6ab..78f707fbdc6 100644 --- a/src/controller/base-stream-controller.ts +++ b/src/controller/base-stream-controller.ts @@ -476,7 +476,7 @@ export default class BaseStreamController : 0; if ( backtracked === 1 || - this.reduceMaxBufferLength(minForwardBufferLength) + this.reduceMaxBufferLength(minForwardBufferLength, frag.duration) ) { fragmentTracker.removeFragment(frag); } @@ -1152,10 +1152,16 @@ export default class BaseStreamController return Math.min(maxBufLen, config.maxMaxBufferLength); } - protected reduceMaxBufferLength(threshold: number) { + protected reduceMaxBufferLength(threshold: number, fragDuration: number) { const config = this.config; - const minLength = threshold || config.maxBufferLength; - const reducedLength = config.maxMaxBufferLength / 2; + const minLength = Math.max( + Math.min(threshold, config.maxBufferLength), + fragDuration, + ); + const reducedLength = Math.max( + threshold - fragDuration * 3, + config.maxMaxBufferLength / 2, + ); if (reducedLength >= minLength) { // reduce max buffer length as it might be too high. we do this to avoid loop flushing ... config.maxMaxBufferLength = reducedLength; @@ -1712,6 +1718,7 @@ export default class BaseStreamController protected reduceLengthAndFlushBuffer(data: ErrorData): boolean { // if in appending state if (this.state === State.PARSING || this.state === State.PARSED) { + const frag = data.frag; const playlistType = data.parent as PlaylistLevelType; const bufferedInfo = this.getFwdBufferInfo( this.mediaBuffer, @@ -1721,7 +1728,7 @@ export default class BaseStreamController // reduce max buf len if current position is buffered const buffered = bufferedInfo && bufferedInfo.len > 0.5; if (buffered) { - this.reduceMaxBufferLength(bufferedInfo.len); + this.reduceMaxBufferLength(bufferedInfo.len, frag?.duration || 10); } const flushBuffer = !buffered; if (flushBuffer) { @@ -1732,9 +1739,9 @@ export default class BaseStreamController `Buffer full error while media.currentTime is not buffered, flush ${playlistType} buffer`, ); } - if (data.frag) { - this.fragmentTracker.removeFragment(data.frag); - this.nextLoadPosition = data.frag.start; + if (frag) { + this.fragmentTracker.removeFragment(frag); + this.nextLoadPosition = frag.start; } this.resetLoadingState(); return flushBuffer;