From 4cd93e039b1d587736af87bda292614e37445159 Mon Sep 17 00:00:00 2001 From: Rob Walch Date: Tue, 28 Mar 2023 17:25:25 -0700 Subject: [PATCH] Remove fragment from fragment tracker on BUFFER_FULL error and when in appending state and trying to reload on IDLE (#5354) Resolves #5328 Related to #5349 / Follow up to #5350 --- api-extractor/report/hls.js.api.md | 2 ++ src/controller/audio-stream-controller.ts | 2 ++ src/controller/base-stream-controller.ts | 23 +++++++++++++++++++++++ src/controller/buffer-controller.ts | 3 +++ src/controller/stream-controller.ts | 10 ++-------- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/api-extractor/report/hls.js.api.md b/api-extractor/report/hls.js.api.md index 8d013786f1c..6d061b90196 100644 --- a/api-extractor/report/hls.js.api.md +++ b/api-extractor/report/hls.js.api.md @@ -290,6 +290,8 @@ export class BaseStreamController extends TaskLoop implements NetworkComponentAP // (undocumented) protected bufferFragmentData(data: RemuxedTrack, frag: Fragment, part: Part | null, chunkMeta: ChunkMetadata): void; // (undocumented) + protected clearTrackerIfNeeded(frag: Fragment): void; + // (undocumented) protected config: HlsConfig; // Warning: (ae-forgotten-export) The symbol "Decrypter" needs to be exported by the entry point hls.d.ts // diff --git a/src/controller/audio-stream-controller.ts b/src/controller/audio-stream-controller.ts index 2cdc82c39e0..55b28f31633 100644 --- a/src/controller/audio-stream-controller.ts +++ b/src/controller/audio-stream-controller.ts @@ -873,6 +873,8 @@ class AudioStreamController this.startFragRequested = true; super.loadFragment(frag, track, targetBufferTime); } + } else { + this.clearTrackerIfNeeded(frag); } } diff --git a/src/controller/base-stream-controller.ts b/src/controller/base-stream-controller.ts index 184b95fc583..2204df477e9 100644 --- a/src/controller/base-stream-controller.ts +++ b/src/controller/base-stream-controller.ts @@ -386,6 +386,28 @@ export default class BaseStreamController }); } + protected clearTrackerIfNeeded(frag: Fragment) { + const fragState = this.fragmentTracker.getState(frag); + if (fragState === FragmentState.APPENDING) { + // Lower the buffer size and try again + const playlistType = frag.type as PlaylistLevelType; + const bufferedInfo = this.getFwdBufferInfo( + this.mediaBuffer, + playlistType + ); + const minForwardBufferLength = Math.max( + frag.duration, + bufferedInfo ? bufferedInfo.len : this.config.maxBufferLength + ); + if (this.reduceMaxBufferLength(minForwardBufferLength)) { + this.fragmentTracker.removeFragment(frag); + } + } else if (this.mediaBuffer?.buffered.length === 0) { + // Stop gap for bad tracker / buffer flush behavior + this.fragmentTracker.removeAllFragments(); + } + } + protected flushMainBuffer( startOffset: number, endOffset: number, @@ -1495,6 +1517,7 @@ export default class BaseStreamController ); } if (data.frag) { + this.fragmentTracker.removeFragment(data.frag); this.nextLoadPosition = data.frag.start; } this.resetLoadingState(); diff --git a/src/controller/buffer-controller.ts b/src/controller/buffer-controller.ts index 146c1ed3ed4..372b5277d06 100644 --- a/src/controller/buffer-controller.ts +++ b/src/controller/buffer-controller.ts @@ -414,6 +414,9 @@ export default class BufferController implements ComponentAPI { type: ErrorTypes.MEDIA_ERROR, parent: frag.type, details: ErrorDetails.BUFFER_APPEND_ERROR, + frag, + part, + chunkMeta, error: err, err, fatal: false, diff --git a/src/controller/stream-controller.ts b/src/controller/stream-controller.ts index 49534c7c6a6..9c611351996 100644 --- a/src/controller/stream-controller.ts +++ b/src/controller/stream-controller.ts @@ -357,14 +357,8 @@ export default class StreamController this.startFragRequested = true; super.loadFragment(frag, level, targetBufferTime); } - } else if (fragState === FragmentState.APPENDING) { - // Lower the buffer size and try again - if (this.reduceMaxBufferLength(frag.duration)) { - this.fragmentTracker.removeFragment(frag); - } - } else if (this.media?.buffered.length === 0) { - // Stop gap for bad tracker / buffer flush behavior - this.fragmentTracker.removeAllFragments(); + } else { + this.clearTrackerIfNeeded(frag); } }