From 5151924dce497ffbfb6aa581ae2b1be6b4157f31 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Tue, 28 Apr 2026 14:13:43 +0200 Subject: [PATCH 1/3] consistent connection state handling --- packages/livekit-rtc/src/room.ts | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/livekit-rtc/src/room.ts b/packages/livekit-rtc/src/room.ts index e71f509e..87e0e5ba 100644 --- a/packages/livekit-rtc/src/room.ts +++ b/packages/livekit-rtc/src/room.ts @@ -109,7 +109,7 @@ export class Room extends (EventEmitter as new () => TypedEmitter private _serverUrl?: string; e2eeManager?: E2EEManager; - connectionState: ConnectionState = ConnectionState.CONN_DISCONNECTED; + _connectionState: ConnectionState = ConnectionState.CONN_DISCONNECTED; remoteParticipants: Map = new Map(); localParticipant?: LocalParticipant; @@ -118,6 +118,10 @@ export class Room extends (EventEmitter as new () => TypedEmitter super(); } + get connectionState() { + return this._connectionState; + } + get name(): string | undefined { return this.info?.name; } @@ -262,7 +266,6 @@ export class Room extends (EventEmitter as new () => TypedEmitter this._token = token; this._serverUrl = url; this.info = cb.message.value.room!.info; - this.connectionState = ConnectionState.CONN_CONNECTED; // Reset the abort controller for this connection session so that // a previous disconnect doesn't immediately cancel new operations. this.disconnectController = new AbortController(); @@ -281,6 +284,7 @@ export class Room extends (EventEmitter as new () => TypedEmitter rp.trackPublications.set(publication.sid!, publication); } } + this.updateConnectionState(ConnectionState.CONN_CONNECTED); break; case 'error': default: @@ -321,6 +325,14 @@ export class Room extends (EventEmitter as new () => TypedEmitter this.removeAllListeners(); } + private updateConnectionState(newState: ConnectionState) { + if (this._connectionState === newState) { + return; + } + this._connectionState = newState; + this.emit(RoomEvent.ConnectionStateChanged, this._connectionState); + } + // Runs at most once per connection session. The FFI layer and explicit // disconnect() both race to get here — whichever wins emits the events, // the other is a no-op. A reconnect via connect() clears hasCleanedUp. @@ -359,12 +371,7 @@ export class Room extends (EventEmitter as new () => TypedEmitter // to reject and clean up their event listeners. this.disconnectController.abort(); - // Only emit ConnectionStateChanged if the FFI 'connectionStateChanged' - // path didn't already flip us to DISCONNECTED. - if (this.connectionState !== ConnectionState.CONN_DISCONNECTED) { - this.connectionState = ConnectionState.CONN_DISCONNECTED; - this.emit(RoomEvent.ConnectionStateChanged, this.connectionState); - } + this.updateConnectionState(ConnectionState.CONN_DISCONNECTED); this.emit(RoomEvent.Disconnected, reason); } @@ -678,14 +685,7 @@ export class Room extends (EventEmitter as new () => TypedEmitter this.emit(RoomEvent.EncryptionError, new Error('internal server error')); } } else if (ev.case == 'connectionStateChanged') { - const newState = ev.value.state!; - // Skip redundant transitions — cleanupOnDisconnect may have already - // flipped us to DISCONNECTED, and we don't want to emit the event twice. - if (this.connectionState === newState) { - return; - } - this.connectionState = newState; - this.emit(RoomEvent.ConnectionStateChanged, this.connectionState); + this.updateConnectionState(ev.value.state!); /*} else if (ev.case == 'connected') { this.emit(RoomEvent.Connected);*/ } else if (ev.case == 'disconnected') { From b5ea27d3079d310a0b700a4e97017acd94aa155e Mon Sep 17 00:00:00 2001 From: lukasIO Date: Tue, 28 Apr 2026 14:15:07 +0200 Subject: [PATCH 2/3] Add changeset for consistent connection state handling --- .changeset/empty-bugs-pull.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/empty-bugs-pull.md diff --git a/.changeset/empty-bugs-pull.md b/.changeset/empty-bugs-pull.md new file mode 100644 index 00000000..4bf90596 --- /dev/null +++ b/.changeset/empty-bugs-pull.md @@ -0,0 +1,5 @@ +--- +"@livekit/rtc-node": patch +--- + +fix(rtc): consistent connection state handling From 2537d5e17f2eea31932cb2035bc99ff29d8f50c9 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Tue, 28 Apr 2026 14:36:21 +0200 Subject: [PATCH 3/3] private modifier --- packages/livekit-rtc/src/room.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/livekit-rtc/src/room.ts b/packages/livekit-rtc/src/room.ts index 87e0e5ba..db80fe22 100644 --- a/packages/livekit-rtc/src/room.ts +++ b/packages/livekit-rtc/src/room.ts @@ -107,9 +107,9 @@ export class Room extends (EventEmitter as new () => TypedEmitter private _token?: string; private _serverUrl?: string; + private _connectionState: ConnectionState = ConnectionState.CONN_DISCONNECTED; e2eeManager?: E2EEManager; - _connectionState: ConnectionState = ConnectionState.CONN_DISCONNECTED; remoteParticipants: Map = new Map(); localParticipant?: LocalParticipant;