From 5d539640e96eb6ab795db0caa3b60da301fb91b1 Mon Sep 17 00:00:00 2001 From: Ryan Gaus Date: Thu, 31 Jul 2025 13:04:02 -0400 Subject: [PATCH 1/2] feat: add SupersededBy event so downstream consumers can always have the latest RTCEngine --- src/e2ee/E2eeManager.ts | 4 +++- src/room/RTCEngine.ts | 1 + src/room/Room.ts | 8 ++------ src/room/events.ts | 1 + src/room/participant/LocalParticipant.ts | 9 +++++++-- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/e2ee/E2eeManager.ts b/src/e2ee/E2eeManager.ts index 47a9d42588..2a726f6f74 100644 --- a/src/e2ee/E2eeManager.ts +++ b/src/e2ee/E2eeManager.ts @@ -34,7 +34,6 @@ import { isE2EESupported, isScriptTransformSupported } from './utils'; export interface BaseE2EEManager { setup(room: Room): void; - setupEngine(engine: RTCEngine): void; setParticipantCryptorEnabled(enabled: boolean, participantIdentity: string): void; setSifTrailer(trailer: Uint8Array): void; on(event: E, listener: E2EEManagerCallbacks[E]): this; @@ -174,6 +173,9 @@ export class E2EEManager engine.on(EngineEvent.RTPVideoMapUpdate, (rtpMap) => { this.postRTPMap(rtpMap); }); + engine.on(EngineEvent.SupersededBy, (newEngine) => { + this.setupEngine(newEngine); + }); } private setupEventListeners(room: Room, keyProvider: BaseKeyProvider) { diff --git a/src/room/RTCEngine.ts b/src/room/RTCEngine.ts index fe2eaf8b12..717abe8cdb 100644 --- a/src/room/RTCEngine.ts +++ b/src/room/RTCEngine.ts @@ -1580,6 +1580,7 @@ export type EngineEventCallbacks = { offline: () => void; signalRequestResponse: (response: RequestResponse) => void; signalConnected: (joinResp: JoinResponse) => void; + supersededBy: (newEngine: RTCEngine) => void; }; function supportOptionalDatachannel(protocol: number | undefined): boolean { diff --git a/src/room/Room.ts b/src/room/Room.ts index 979b0a7a4f..671a46f76f 100644 --- a/src/room/Room.ts +++ b/src/room/Room.ts @@ -517,6 +517,7 @@ class Room extends (EventEmitter as new () => TypedEmitter) return; } + const oldEngine = this.engine; this.engine = new RTCEngine(this.options); this.engine @@ -610,12 +611,7 @@ class Room extends (EventEmitter as new () => TypedEmitter) } }); - if (this.localParticipant) { - this.localParticipant.setupEngine(this.engine); - } - if (this.e2eeManager) { - this.e2eeManager.setupEngine(this.engine); - } + oldEngine?.emit(EngineEvent.SupersededBy, this.engine); } /** diff --git a/src/room/events.ts b/src/room/events.ts index 26248686e6..0872397e45 100644 --- a/src/room/events.ts +++ b/src/room/events.ts @@ -606,6 +606,7 @@ export enum EngineEvent { SignalRequestResponse = 'signalRequestResponse', SignalConnected = 'signalConnected', RoomMoved = 'roomMoved', + SupersededBy = 'supersededBy', } export enum TrackEvent { diff --git a/src/room/participant/LocalParticipant.ts b/src/room/participant/LocalParticipant.ts index 63e73a8e38..beb3df7838 100644 --- a/src/room/participant/LocalParticipant.ts +++ b/src/room/participant/LocalParticipant.ts @@ -234,7 +234,7 @@ export default class LocalParticipant extends Participant { /** * @internal */ - setupEngine(engine: RTCEngine) { + private setupEngine(engine: RTCEngine) { this.engine = engine; this.engine.on(EngineEvent.RemoteMute, (trackSid: string, muted: boolean) => { const pub = this.trackPublications.get(trackSid); @@ -263,7 +263,8 @@ export default class LocalParticipant extends Participant { .on(EngineEvent.SubscribedQualityUpdate, this.handleSubscribedQualityUpdate) .on(EngineEvent.Closing, this.handleClosing) .on(EngineEvent.SignalRequestResponse, this.handleSignalRequestResponse) - .on(EngineEvent.DataPacketReceived, this.handleDataPacket); + .on(EngineEvent.DataPacketReceived, this.handleDataPacket) + .on(EngineEvent.SupersededBy, this.handleNewEngine); } private handleReconnecting = () => { @@ -337,6 +338,10 @@ export default class LocalParticipant extends Participant { } }; + private handleNewEngine = (newEngine: RTCEngine) => { + this.setupEngine(newEngine); + }; + /** * Sets and updates the metadata of the local participant. * Note: this requires `canUpdateOwnMetadata` permission. From aab40b10293198948d24db30b3ca66c0791a13c9 Mon Sep 17 00:00:00 2001 From: Ryan Gaus Date: Mon, 4 Aug 2025 12:05:31 -0400 Subject: [PATCH 2/2] fix: address cyclical RTCEngine reference caused by supersededby event --- src/room/RTCEngine.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/room/RTCEngine.ts b/src/room/RTCEngine.ts index 717abe8cdb..68c5c5bd9f 100644 --- a/src/room/RTCEngine.ts +++ b/src/room/RTCEngine.ts @@ -94,8 +94,10 @@ enum PCState { Closed, } +const EngineEventEmitter = EventEmitter as new () => TypedEventEmitter; + /** @internal */ -export default class RTCEngine extends (EventEmitter as new () => TypedEventEmitter) { +export default class RTCEngine extends EngineEventEmitter { client: SignalClient; rtcConfig: RTCConfiguration = {};