make ring$ a behavior and add code comments to justify/explain the change.

Signed-off-by: Timo K <toger5@hotmail.de>
This commit is contained in:
Timo K
2025-09-19 14:11:22 +02:00
parent 0774d18f92
commit 5dfad5ec1e

View File

@@ -880,23 +880,28 @@ export class CallViewModel extends ViewModel {
? this.allOthersLeft$ ? this.allOthersLeft$
: NEVER; : NEVER;
/** private readonly didSendCallNotification$ = fromEvent(
* Whenever the RTC session tells us that it intends to ring the remote
* participant's devices, this emits an Observable tracking the current state of
* that ringing process.
*/
private readonly ring$: Observable<
Observable<"ringing" | "timeout" | "decline">
> = (
fromEvent(
this.matrixRTCSession, this.matrixRTCSession,
MatrixRTCSessionEvent.DidSendCallNotification, MatrixRTCSessionEvent.DidSendCallNotification,
) as Observable< ) as Observable<
Parameters< Parameters<
MatrixRTCSessionEventHandlerMap[MatrixRTCSessionEvent.DidSendCallNotification] MatrixRTCSessionEventHandlerMap[MatrixRTCSessionEvent.DidSendCallNotification]
> >
> >;
).pipe( /**
* Whenever the RTC session tells us that it intends to ring the remote
* participant's devices, this emits an Observable tracking the current state of
* that ringing process.
*/
// This is a behavior since we need to store the latest state for when we subscribe to this after `didSendCallNotification$`
// has already emitted but we still need the latest observable with a timeout timer that only gets created on after receiving `notificationEvent`.
// A behavior will emit the latest observable with the running timer to new subscribers.
// see also: callPickupState$ and in particular the line: `return this.ring$.pipe(mergeAll());` here we otherwise might get an EMPTY observable if
// `ring$` would not be a behavior.
private readonly ring$: Behavior<
Observable<"ringing" | "timeout" | "decline"> | Observable<never>
> = this.scope.behavior(
this.didSendCallNotification$.pipe(
filter( filter(
([notificationEvent]) => notificationEvent.notification_type === "ring", ([notificationEvent]) => notificationEvent.notification_type === "ring",
), ),
@@ -926,7 +931,8 @@ export class CallViewModel extends ViewModel {
([event]) => ([event]) =>
event.getType() === EventType.RTCDecline && event.getType() === EventType.RTCDecline &&
event.getRelation()?.rel_type === "m.reference" && event.getRelation()?.rel_type === "m.reference" &&
event.getRelation()?.event_id === notificationEvent.event_id && event.getRelation()?.event_id ===
notificationEvent.event_id &&
event.getSender() !== this.userId, event.getSender() !== this.userId,
), ),
), ),
@@ -934,6 +940,8 @@ export class CallViewModel extends ViewModel {
endWith("decline" as const), endWith("decline" as const),
); );
}), }),
),
EMPTY,
); );
/** /**
@@ -972,6 +980,8 @@ export class CallViewModel extends ViewModel {
return of("success" as const); return of("success" as const);
} }
// Show the ringing state of the most recent ringing attempt. // Show the ringing state of the most recent ringing attempt.
// ring$ is a behavior so it will emit the latest observable which very well might already have a running timer.
// this is important in case livekitConnectionState$ and someoneElseJoined$ emit after didSendCallNotification$ has already emitted.
return this.ring$.pipe(switchAll()); return this.ring$.pipe(switchAll());
}), }),
// The state starts as 'unknown' because we don't know if the RTC // The state starts as 'unknown' because we don't know if the RTC