From 099e9c747868933e5e7675916d50fc6c39635ebd Mon Sep 17 00:00:00 2001 From: Ryan Gaus Date: Fri, 17 Apr 2026 13:32:21 -0400 Subject: [PATCH 1/4] fix: avoid attaching a new Closing event listener for each waitForBufferStatusLow call This can very quickly start to log lots of warnings. --- src/room/RTCEngine.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/room/RTCEngine.ts b/src/room/RTCEngine.ts index 4bf7cb1cd4..045f22f1e3 100644 --- a/src/room/RTCEngine.ts +++ b/src/room/RTCEngine.ts @@ -86,6 +86,7 @@ import type { TrackPublishOptions, VideoCodec } from './track/options'; import { getTrackPublicationInfo } from './track/utils'; import type { LoggerOptions } from './types'; import { + Future, isCompressionStreamSupported, isVideoCodec, isVideoTrack, @@ -249,6 +250,8 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit /** used to indicate whether the browser is currently waiting to reconnect */ private isWaitingForNetworkReconnect: boolean = false; + private bufferStatusLowClosingFuture = new Future(); + constructor(private options: InternalRoomOptions) { super(); this.log = getLogger(options.loggerName ?? LoggerNames.Engine); @@ -282,6 +285,13 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit this.client.onParticipantUpdate = (updates) => this.emit(EngineEvent.ParticipantUpdate, updates); this.client.onJoined = (joinResponse) => this.emit(EngineEvent.Joined, joinResponse); + + this.on(EngineEvent.Closing, () => { + this.bufferStatusLowClosingFuture.reject?.(new UnexpectedConnectionState('engine closed')); + }); + // Swallow the rejection at the source so it doesn't surface as an unhandled promise rejection + // when no waitForBufferStatusLow callers are attached. + this.bufferStatusLowClosingFuture.promise.catch(() => {}); } /** @internal */ @@ -1578,19 +1588,15 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit if (this.isBufferStatusLow(kind)) { resolve(); } else { - const onClosing = () => reject(new UnexpectedConnectionState('engine closed')); - this.once(EngineEvent.Closing, onClosing); const dc = this.dataChannelForKind(kind); if (!dc) { reject(new UnexpectedConnectionState(`DataChannel not found, kind: ${kind}`)); return; } + this.bufferStatusLowClosingFuture.promise.catch((e) => reject(e)); dc.addEventListener( 'bufferedamountlow', - () => { - this.off(EngineEvent.Closing, onClosing); - resolve(); - }, + () => resolve(), { once: true, }, From ae278bb5b36087304ba72e4304408449c7851189 Mon Sep 17 00:00:00 2001 From: Ryan Gaus Date: Fri, 17 Apr 2026 13:40:47 -0400 Subject: [PATCH 2/4] fix: add missing changeset --- .changeset/modern-birds-lose.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/modern-birds-lose.md diff --git a/.changeset/modern-birds-lose.md b/.changeset/modern-birds-lose.md new file mode 100644 index 0000000000..2f955bafb6 --- /dev/null +++ b/.changeset/modern-birds-lose.md @@ -0,0 +1,5 @@ +--- +'livekit-client': patch +--- + +Avoid attaching a new Closing event listener for each waitForBufferStatusLow call From f89dca8c8c9e7b92939bb9a2482abf1653f7149a Mon Sep 17 00:00:00 2001 From: Ryan Gaus Date: Fri, 17 Apr 2026 13:41:13 -0400 Subject: [PATCH 3/4] fix: run npm run format --- src/room/RTCEngine.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/room/RTCEngine.ts b/src/room/RTCEngine.ts index 045f22f1e3..e07b3c7c42 100644 --- a/src/room/RTCEngine.ts +++ b/src/room/RTCEngine.ts @@ -1594,13 +1594,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit return; } this.bufferStatusLowClosingFuture.promise.catch((e) => reject(e)); - dc.addEventListener( - 'bufferedamountlow', - () => resolve(), - { - once: true, - }, - ); + dc.addEventListener('bufferedamountlow', () => resolve(), { + once: true, + }); } }); } From 1e97f7cb1dfd8e10e3eb24a4fbc40709662d1064 Mon Sep 17 00:00:00 2001 From: Ryan Gaus Date: Mon, 20 Apr 2026 12:48:51 -0400 Subject: [PATCH 4/4] fix: swap void -> never --- src/room/RTCEngine.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/room/RTCEngine.ts b/src/room/RTCEngine.ts index e07b3c7c42..e95a77742c 100644 --- a/src/room/RTCEngine.ts +++ b/src/room/RTCEngine.ts @@ -250,7 +250,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit /** used to indicate whether the browser is currently waiting to reconnect */ private isWaitingForNetworkReconnect: boolean = false; - private bufferStatusLowClosingFuture = new Future(); + private bufferStatusLowClosingFuture = new Future(); constructor(private options: InternalRoomOptions) { super();