@@ -107,9 +107,9 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
107107
108108 private _token ?: string ;
109109 private _serverUrl ?: string ;
110+ private _connectionState : ConnectionState = ConnectionState . CONN_DISCONNECTED ;
110111
111112 e2eeManager ?: E2EEManager ;
112- connectionState : ConnectionState = ConnectionState . CONN_DISCONNECTED ;
113113
114114 remoteParticipants : Map < string , RemoteParticipant > = new Map ( ) ;
115115 localParticipant ?: LocalParticipant ;
@@ -118,6 +118,10 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
118118 super ( ) ;
119119 }
120120
121+ get connectionState ( ) {
122+ return this . _connectionState ;
123+ }
124+
121125 get name ( ) : string | undefined {
122126 return this . info ?. name ;
123127 }
@@ -262,7 +266,6 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
262266 this . _token = token ;
263267 this . _serverUrl = url ;
264268 this . info = cb . message . value . room ! . info ;
265- this . connectionState = ConnectionState . CONN_CONNECTED ;
266269 // Reset the abort controller for this connection session so that
267270 // a previous disconnect doesn't immediately cancel new operations.
268271 this . disconnectController = new AbortController ( ) ;
@@ -281,6 +284,7 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
281284 rp . trackPublications . set ( publication . sid ! , publication ) ;
282285 }
283286 }
287+ this . updateConnectionState ( ConnectionState . CONN_CONNECTED ) ;
284288 break ;
285289 case 'error' :
286290 default :
@@ -321,6 +325,14 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
321325 this . removeAllListeners ( ) ;
322326 }
323327
328+ private updateConnectionState ( newState : ConnectionState ) {
329+ if ( this . _connectionState === newState ) {
330+ return ;
331+ }
332+ this . _connectionState = newState ;
333+ this . emit ( RoomEvent . ConnectionStateChanged , this . _connectionState ) ;
334+ }
335+
324336 // Runs at most once per connection session. The FFI layer and explicit
325337 // disconnect() both race to get here — whichever wins emits the events,
326338 // the other is a no-op. A reconnect via connect() clears hasCleanedUp.
@@ -359,12 +371,7 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
359371 // to reject and clean up their event listeners.
360372 this . disconnectController . abort ( ) ;
361373
362- // Only emit ConnectionStateChanged if the FFI 'connectionStateChanged'
363- // path didn't already flip us to DISCONNECTED.
364- if ( this . connectionState !== ConnectionState . CONN_DISCONNECTED ) {
365- this . connectionState = ConnectionState . CONN_DISCONNECTED ;
366- this . emit ( RoomEvent . ConnectionStateChanged , this . connectionState ) ;
367- }
374+ this . updateConnectionState ( ConnectionState . CONN_DISCONNECTED ) ;
368375 this . emit ( RoomEvent . Disconnected , reason ) ;
369376 }
370377
@@ -678,14 +685,7 @@ export class Room extends (EventEmitter as new () => TypedEmitter<RoomCallbacks>
678685 this . emit ( RoomEvent . EncryptionError , new Error ( 'internal server error' ) ) ;
679686 }
680687 } else if ( ev . case == 'connectionStateChanged' ) {
681- const newState = ev . value . state ! ;
682- // Skip redundant transitions — cleanupOnDisconnect may have already
683- // flipped us to DISCONNECTED, and we don't want to emit the event twice.
684- if ( this . connectionState === newState ) {
685- return ;
686- }
687- this . connectionState = newState ;
688- this . emit ( RoomEvent . ConnectionStateChanged , this . connectionState ) ;
688+ this . updateConnectionState ( ev . value . state ! ) ;
689689 /*} else if (ev.case == 'connected') {
690690 this.emit(RoomEvent.Connected);*/
691691 } else if ( ev . case == 'disconnected' ) {
0 commit comments