diff --git a/src/state/CallViewModel/localMember/LocalMember.test.ts b/src/state/CallViewModel/localMember/LocalMember.test.ts index e7c5b1e45..2fc59c48f 100644 --- a/src/state/CallViewModel/localMember/LocalMember.test.ts +++ b/src/state/CallViewModel/localMember/LocalMember.test.ts @@ -930,6 +930,55 @@ describe("LocalMembership", () => { scope.end(); }); + it("ignores signal-only reconnects", async () => { + const scope = new ObservableScope(); + const trackSpy = vi.spyOn( + PosthogAnalytics.instance.eventCallReconnecting, + "track", + ); + + const connectionState$ = new BehaviorSubject( + ConnectionState.LivekitConnected, + ); + const mutableConnection = { + ...connectionTransportAConnected, + state$: connectionState$, + } as unknown as Connection; + + const connectionManagerData = new ConnectionManagerData(); + connectionManagerData.add(mutableConnection, []); + + const localMembership = createLocalMembership$({ + scope, + ...defaultCreateLocalMemberValues, + homeserverConnected: { + combined$: constant<[boolean, HomeserverDisconnectReason | null]>([ + true, + null, + ]), + rtsSession$: constant(RTCMemberStatus.Connected), + }, + connectionManager: { + connectionManagerData$: constant(new Epoch(connectionManagerData)), + }, + localTransport: { + advertised$: constant(aTransport), + active$: constant(aTransportWithSFUConfig), + }, + }); + + await flushPromises(); + + connectionState$.next(ConnectionState.LivekitSignalReconnecting); + expect(localMembership.reconnecting$.value).toBe(false); + expect(localMembership.connected$.value).toBe(true); + connectionState$.next(ConnectionState.LivekitConnected); + + expect(trackSpy).not.toHaveBeenCalled(); + + scope.end(); + }); + it("fires one event per completed reconnection cycle", async () => { const scope = new ObservableScope(); const trackSpy = vi.spyOn( diff --git a/src/state/CallViewModel/localMember/LocalMember.ts b/src/state/CallViewModel/localMember/LocalMember.ts index 7805805b8..d150ab151 100644 --- a/src/state/CallViewModel/localMember/LocalMember.ts +++ b/src/state/CallViewModel/localMember/LocalMember.ts @@ -582,7 +582,13 @@ export const createLocalMembership$ = ({ combineLatest([ homeserverConnected.combined$, localConnectionState$.pipe( - map((state) => state === ConnectionState.LivekitConnected), + // A signal-only reconnect keeps the peer connection (and so the + // media) up, so we don't tell the user we're reconnecting for it. + map( + (state) => + state === ConnectionState.LivekitConnected || + state === ConnectionState.LivekitSignalReconnecting, + ), ), ]).pipe( map(([[hsConnected, hsReason], livekitConnected]) => {