Serialize updates to the call intent

So that the value advertised in your membership can't desync from the actual value if you toggle video too fast.
This commit is contained in:
Robin
2025-10-14 15:19:40 -04:00
parent b0eb566a4f
commit 102e581c41
2 changed files with 10 additions and 8 deletions

View File

@@ -140,6 +140,7 @@ import {
type SpotlightPortraitLayoutMedia,
} from "./layout-types.ts";
import { ElementCallError, UnknownCallError } from "../utils/errors.ts";
import { ObservableScope } from "./ObservableScope.ts";
export interface CallViewModelOptions {
encryptionSystem: EncryptionSystem;
@@ -1805,18 +1806,19 @@ export class CallViewModel extends ViewModel {
} catch (e) {
logger.error("Error entering RTC session", e);
}
// Update our member event when our mute state changes.
const muteSubscription = this.muteStates.video.enabled$.subscribe(
(videoEnabled) =>
// TODO: Ensure that these calls are serialized in case of
// fast video toggling
void this.matrixRTCSession.updateCallIntent(
const intentScope = new ObservableScope();
intentScope.reconcile(
this.muteStates.video.enabled$,
async (videoEnabled) =>
this.matrixRTCSession.updateCallIntent(
videoEnabled ? "video" : "audio",
),
);
return async (): Promise<void> => {
muteSubscription.unsubscribe();
intentScope.end();
// Only sends Matrix leave event. The LiveKit session will disconnect
// as soon as either the stopConnection$ handler above gets to it or
// the view model is destroyed.

View File

@@ -114,11 +114,11 @@ export class ObservableScope {
*/
public reconcile<T>(
value$: Behavior<T>,
callback: (value: T) => Promise<(() => Promise<void>) | undefined>,
callback: (value: T) => Promise<(() => Promise<void>) | void>,
): void {
let latestValue: T | typeof nothing = nothing;
let reconciledValue: T | typeof nothing = nothing;
let cleanUp: (() => Promise<void>) | undefined = undefined;
let cleanUp: (() => Promise<void>) | void = undefined;
value$
.pipe(
catchError(() => EMPTY), // Ignore errors