diff --git a/src/room/RTCEngine.ts b/src/room/RTCEngine.ts index 5272a5e353..89545267cb 100644 --- a/src/room/RTCEngine.ts +++ b/src/room/RTCEngine.ts @@ -200,13 +200,14 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit this._isClosed = false; this.latestJoinResponse = joinResponse; + this.pcState = PCState.New; this.subscriberPrimary = joinResponse.subscriberPrimary; if (!this.publisher) { this.configure(joinResponse); } // create offer - if (!this.subscriberPrimary) { + if (!this.subscriberPrimary || this.hasPublished) { this.negotiate(); } @@ -241,6 +242,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit this.clearPendingReconnect(); await this.cleanupPeerConnections(); await this.cleanupClient(); + this.pcState = PCState.Closed; } finally { unlock(); } @@ -269,6 +271,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit } this.primaryPC = undefined; + this.pcState = PCState.Closed; const dcCleanup = (dc: RTCDataChannel | undefined) => { if (!dc) return; @@ -415,16 +418,17 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit primaryPC.onconnectionstatechange = async () => { log.debug(`primary PC state changed ${primaryPC.connectionState}`); if (primaryPC.connectionState === 'connected') { - const shouldEmit = this.pcState === PCState.New; - this.pcState = PCState.Connected; - if (shouldEmit) { + const initialFullConnection = + (this.pcState === PCState.New && !this.hasPublished) || + this.publisher?.pc.connectionState === 'connected'; + if (initialFullConnection) { + this.pcState = PCState.Connected; this.emit(EngineEvent.Connected, joinResponse); } } else if (primaryPC.connectionState === 'failed') { // on Safari, PeerConnection will switch to 'disconnected' during renegotiation if (this.pcState === PCState.Connected) { this.pcState = PCState.Disconnected; - this.handleDisconnect( 'primary peerconnection', subscriberPrimary @@ -435,6 +439,14 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit } }; secondaryPC.onconnectionstatechange = async () => { + if (secondaryPC.connectionState === 'connected') { + const initialFullConnection = + this.pcState === PCState.New && primaryPC.connectionState === 'connected'; + if (initialFullConnection) { + this.pcState = PCState.Connected; + this.emit(EngineEvent.Connected, joinResponse); + } + } log.debug(`secondary PC state changed ${secondaryPC.connectionState}`); // also reconnect if secondary peerconnection fails if (secondaryPC.connectionState === 'failed') { @@ -939,6 +951,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit await this.client.sendLeave(); } await this.cleanupPeerConnections(); + this.pcState = PCState.Closed; await this.cleanupClient(); let joinResponse: JoinResponse; @@ -964,7 +977,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit this.client.setReconnected(); this.emit(EngineEvent.SignalRestarted, joinResponse); - await this.waitForPCReconnected(); + await this.waitForPCInitialConnection(); this.regionUrlProvider?.resetAttempts(); // reconnect success this.emit(EngineEvent.Restarted); @@ -1092,11 +1105,10 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit // this means we'd have to check its status manually and update address // manually now - startTime > minReconnectWait && - this.primaryPC?.connectionState === 'connected' + this.primaryPC?.connectionState === 'connected' && + (!this.hasPublished || this.publisher?.pc.connectionState === 'connected') ) { this.pcState = PCState.Connected; - } - if (this.pcState === PCState.Connected) { return; } await sleep(100); diff --git a/src/room/Room.ts b/src/room/Room.ts index a18a329af4..39af375ad2 100644 --- a/src/room/Room.ts +++ b/src/room/Room.ts @@ -1119,9 +1119,12 @@ class Room extends (EventEmitter as new () => TypedEmitter) // reconnection failed, handleDisconnect is being invoked already, just return here return; } - this.setAndEmitConnectionState(ConnectionState.Connected); - this.emit(RoomEvent.Reconnected); - this.registerConnectionReconcile(); + // only set as connected if _only_ the signal connection had been severed + if (this.engine.verifyTransport()) { + this.setAndEmitConnectionState(ConnectionState.Connected); + this.emit(RoomEvent.Reconnected); + this.registerConnectionReconcile(); + } // emit participant connected events after connection has been re-established this.participants.forEach((participant) => {