Avoid updating membership during focus switch

This commit is contained in:
Robin
2025-10-14 09:16:46 -04:00
parent de5f5198dd
commit a18700cbcd

View File

@@ -507,11 +507,17 @@ export class CallViewModel extends ViewModel {
/** /**
* Lists the transports used by ourselves, plus all other MatrixRTC session * Lists the transports used by ourselves, plus all other MatrixRTC session
* members. * members. For completeness this also lists the preferred transport and
* whether we are in multi-SFU mode (because advertisedTransport$ wants to
* read them at the same time, and bundling data together when it might change
* together is what you have to do in RxJS to avoid reading inconsistent state
* or observing too many changes.)
*/ */
private readonly transports$: Behavior<{ private readonly transports$: Behavior<{
local: Async<LivekitTransport>; local: Async<LivekitTransport>;
remote: { membership: CallMembership; transport: LivekitTransport }[]; remote: { membership: CallMembership; transport: LivekitTransport }[];
preferred: Async<LivekitTransport>;
multiSfu: boolean;
} | null> = this.scope.behavior( } | null> = this.scope.behavior(
this.joined$.pipe( this.joined$.pipe(
switchMap((joined) => switchMap((joined) =>
@@ -541,7 +547,7 @@ export class CallViewModel extends ViewModel {
if (isLivekitTransport(selection)) local = ready(selection); if (isLivekitTransport(selection)) local = ready(selection);
} }
} }
return { local, remote }; return { local, remote, preferred, multiSfu };
}, },
) )
: of(null), : of(null),
@@ -568,6 +574,35 @@ export class CallViewModel extends ViewModel {
), ),
); );
/**
* The transport we should advertise in our MatrixRTC membership (plus whether
* it is a multi-SFU transport).
*/
private readonly advertisedTransport$: Behavior<{
multiSfu: boolean;
transport: LivekitTransport;
} | null> = this.scope.behavior(
this.transports$.pipe(
map((transports) =>
transports?.local.state === "ready" &&
transports.preferred.state === "ready"
? {
multiSfu: transports.multiSfu,
// In non-multi-SFU mode we should always advertise the preferred
// SFU to minimize the number of membership updates
transport: transports.multiSfu
? transports.local.value
: transports.preferred.value,
}
: null,
),
distinctUntilChanged<{
multiSfu: boolean;
transport: LivekitTransport;
} | null>(deepCompare),
),
);
private readonly localConnectionAndTransport$ = this.scope.behavior( private readonly localConnectionAndTransport$ = this.scope.behavior(
this.localTransport$.pipe( this.localTransport$.pipe(
map( map(
@@ -1959,16 +1994,16 @@ export class CallViewModel extends ViewModel {
}); });
// Start and stop session membership as needed // Start and stop session membership as needed
this.scope.reconcile(this.localTransport$, async (localTransport) => { this.scope.reconcile(this.advertisedTransport$, async (advertised) => {
if (localTransport?.state === "ready") { if (advertised !== null) {
try { try {
await enterRTCSession( await enterRTCSession(
this.matrixRTCSession, this.matrixRTCSession,
localTransport.value, advertised.transport,
this.options.encryptionSystem.kind !== E2eeType.NONE, this.options.encryptionSystem.kind !== E2eeType.NONE,
true, true,
true, true,
multiSfu.value$.value, advertised.multiSfu,
); );
} catch (e) { } catch (e) {
logger.error("Error entering RTC session", e); logger.error("Error entering RTC session", e);