Almost running
- NEVER use undefined as the default for behaviors (FOOTGUN)
This commit is contained in:
@@ -146,7 +146,7 @@ export function createCallNotificationLifecycle$({
|
||||
newAndLegacyEvents?.[0].notification_type === "ring",
|
||||
),
|
||||
map((e) => e as CallNotificationWrapper),
|
||||
switchMap(([notificastionEvent]) => {
|
||||
switchMap(([notificationEvent]) => {
|
||||
const lifetimeMs = notificationEvent?.lifetime ?? 0;
|
||||
return concat(
|
||||
lifetimeMs === 0
|
||||
|
||||
@@ -109,6 +109,7 @@ import {
|
||||
createReceivedDecline$,
|
||||
createSentCallNotification$,
|
||||
} from "./CallNotificationLifecycle.ts";
|
||||
import { createRoomMembers$ } from "./remoteMembers/displayname.ts";
|
||||
|
||||
const logger = rootLogger.getChild("[CallViewModel]");
|
||||
//TODO
|
||||
@@ -266,6 +267,7 @@ export class CallViewModel {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// CallNotificationLifecycle
|
||||
// consider inlining these!!!
|
||||
private sentCallNotification$ = createSentCallNotification$(
|
||||
this.scope,
|
||||
this.matrixRTCSession,
|
||||
@@ -281,6 +283,9 @@ export class CallViewModel {
|
||||
localUser: { userId: this.userId, deviceId: this.deviceId },
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// ROOM MEMBER tracking TODO
|
||||
private roomMembers$ = createRoomMembers$(this.scope, this.matrixRoom);
|
||||
/**
|
||||
* If there is a configuration error with the call (e.g. misconfigured E2EE).
|
||||
* This is a fatal error that prevents the call from being created/joined.
|
||||
@@ -440,6 +445,7 @@ export class CallViewModel {
|
||||
mediaItems.filter((m): m is UserMedia => m instanceof UserMedia),
|
||||
),
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
public readonly joinSoundEffect$ = this.userMedia$.pipe(
|
||||
@@ -465,6 +471,9 @@ export class CallViewModel {
|
||||
this.memberships$.pipe(map((ms) => ms.value.length)),
|
||||
);
|
||||
|
||||
// only public to expose to the view.
|
||||
public readonly callPickupState$ = this.callLifecycle.callPickupState$;
|
||||
|
||||
public readonly leaveSoundEffect$ = combineLatest([
|
||||
this.callLifecycle.callPickupState$,
|
||||
this.userMedia$,
|
||||
@@ -645,7 +654,6 @@ export class CallViewModel {
|
||||
|
||||
private readonly naturalWindowMode$ = this.scope.behavior<WindowMode>(
|
||||
fromEvent(window, "resize").pipe(
|
||||
startWith(null),
|
||||
map(() => {
|
||||
const height = window.innerHeight;
|
||||
const width = window.innerWidth;
|
||||
@@ -658,6 +666,7 @@ export class CallViewModel {
|
||||
return "normal";
|
||||
}),
|
||||
),
|
||||
"normal",
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -687,7 +696,6 @@ export class CallViewModel {
|
||||
// automatically switch to spotlight mode and reset when screen sharing ends
|
||||
this.scope.behavior<GridMode>(
|
||||
this.gridModeUserSelection$.pipe(
|
||||
startWith(null),
|
||||
switchMap((userSelection) =>
|
||||
(userSelection === "spotlight"
|
||||
? EMPTY
|
||||
@@ -706,6 +714,7 @@ export class CallViewModel {
|
||||
).pipe(startWith(userSelection ?? "grid")),
|
||||
),
|
||||
),
|
||||
"grid",
|
||||
);
|
||||
|
||||
public setGridMode(value: GridMode): void {
|
||||
|
||||
@@ -288,7 +288,7 @@ export const createLocalMembership$ = ({
|
||||
};
|
||||
|
||||
const requestConnect = (): LocalMemberConnectionState => {
|
||||
if (state.livekit$.value === null) {
|
||||
if (state.livekit$.value.state === LivekitState.Uninitialized) {
|
||||
startTracks();
|
||||
state.livekit$.next({ state: LivekitState.Connecting });
|
||||
combineLatest([publisher$, tracks$], (publisher, tracks) => {
|
||||
@@ -302,7 +302,7 @@ export const createLocalMembership$ = ({
|
||||
});
|
||||
});
|
||||
}
|
||||
if (state.matrix$.value.state !== MatrixState.Disconnected) {
|
||||
if (state.matrix$.value.state === MatrixState.Disconnected) {
|
||||
state.matrix$.next({ state: MatrixState.Connecting });
|
||||
localTransport$.pipe(
|
||||
tap((transport) => {
|
||||
@@ -438,6 +438,7 @@ export const createLocalMembership$ = ({
|
||||
return of(false);
|
||||
}),
|
||||
),
|
||||
null,
|
||||
);
|
||||
|
||||
const toggleScreenSharing =
|
||||
|
||||
@@ -67,18 +67,22 @@ export const createLocalTransport$ = ({
|
||||
*/
|
||||
const oldestMemberTransport$ = scope.behavior(
|
||||
memberships$.pipe(
|
||||
mapEpoch((memberships) => memberships[0].getTransport(memberships[0])),
|
||||
first((t) => t != undefined && isLivekitTransport(t)),
|
||||
mapEpoch(
|
||||
(memberships) => memberships[0]?.getTransport(memberships[0]) ?? null,
|
||||
),
|
||||
first((t) => t != null && isLivekitTransport(t)),
|
||||
),
|
||||
undefined,
|
||||
null,
|
||||
);
|
||||
|
||||
/**
|
||||
* The transport that we would personally prefer to publish on (if not for the
|
||||
* transport preferences of others, perhaps).
|
||||
*/
|
||||
const preferredTransport$: Behavior<LivekitTransport | undefined> =
|
||||
scope.behavior(from(makeTransport(client, roomId)), undefined);
|
||||
const preferredTransport$: Behavior<LivekitTransport | null> = scope.behavior(
|
||||
from(makeTransport(client, roomId)),
|
||||
null,
|
||||
);
|
||||
|
||||
/**
|
||||
* The transport we should advertise in our MatrixRTC membership.
|
||||
@@ -89,7 +93,6 @@ export const createLocalTransport$ = ({
|
||||
(useOldestMember, oldestMemberTransport, preferredTransport) =>
|
||||
useOldestMember ? oldestMemberTransport : preferredTransport,
|
||||
).pipe<LivekitTransport>(distinctUntilChanged(deepCompare)),
|
||||
undefined,
|
||||
);
|
||||
return advertisedTransport$;
|
||||
};
|
||||
@@ -103,7 +106,6 @@ async function makeTransportInternal(
|
||||
logger.log("Searching for a preferred transport");
|
||||
//TODO refactor this to use the jwt service returned alias.
|
||||
const livekitAlias = roomId;
|
||||
|
||||
// TODO-MULTI-SFU: Either remove this dev tool or make it more official
|
||||
const urlFromStorage =
|
||||
localStorage.getItem("robin-matrixrtc-auth") ??
|
||||
|
||||
@@ -307,6 +307,7 @@ export class Publisher {
|
||||
return track instanceof LocalVideoTrack ? track : null;
|
||||
}),
|
||||
),
|
||||
null,
|
||||
);
|
||||
trackProcessorSync(track$, trackerProcessorState$);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
type LivekitTransport,
|
||||
type ParticipantId,
|
||||
} from "matrix-js-sdk/lib/matrixrtc";
|
||||
import { BehaviorSubject, combineLatest, map, switchMap } from "rxjs";
|
||||
import { BehaviorSubject, combineLatest, map, of, switchMap } from "rxjs";
|
||||
import { logger as rootLogger } from "matrix-js-sdk/lib/logger";
|
||||
import { type LocalParticipant, type RemoteParticipant } from "livekit-client";
|
||||
|
||||
@@ -191,6 +191,11 @@ export function createConnectionManager$({
|
||||
);
|
||||
});
|
||||
|
||||
// probably not required
|
||||
if (listOfConnectionsWithPublishingParticipants.length === 0) {
|
||||
return of(new Epoch(new ConnectionManagerData(), epoch));
|
||||
}
|
||||
|
||||
// combineLatest the several streams into a single stream with the ConnectionManagerData
|
||||
return combineLatest(listOfConnectionsWithPublishingParticipants).pipe(
|
||||
map(
|
||||
@@ -206,6 +211,7 @@ export function createConnectionManager$({
|
||||
);
|
||||
}),
|
||||
),
|
||||
new Epoch(new ConnectionManagerData()),
|
||||
);
|
||||
|
||||
return { transports$, connectionManagerData$, connections$ };
|
||||
|
||||
@@ -17,7 +17,6 @@ import { combineLatest, filter, map } from "rxjs";
|
||||
// eslint-disable-next-line rxjs/no-internal
|
||||
import { type NodeStyleEventEmitter } from "rxjs/internal/observable/fromEvent";
|
||||
import { type Room as MatrixRoom, type RoomMember } from "matrix-js-sdk";
|
||||
import { logger } from "matrix-js-sdk/lib/logger";
|
||||
|
||||
import { type Behavior } from "../../Behavior";
|
||||
import { type IConnectionManager } from "./ConnectionManager";
|
||||
@@ -56,6 +55,7 @@ interface Props {
|
||||
// => Extract an AvatarService instead?
|
||||
// Better with just `getMember`
|
||||
matrixRoom: Pick<MatrixRoom, "getMember"> & NodeStyleEventEmitter;
|
||||
roomMember$: Behavior<Pick<RoomMember, "userId" | "getMxcAvatarUrl">>;
|
||||
}
|
||||
// Alternative structure idea:
|
||||
// const livekitMatrixMember$ = (callMemberships$,connectionManager,scope): Observable<MatrixLivekitMember[]> => {
|
||||
|
||||
@@ -26,6 +26,17 @@ import {
|
||||
} from "../../../utils/displayname";
|
||||
import { type Behavior } from "../../Behavior";
|
||||
|
||||
export function createRoomMembers$(
|
||||
scope: ObservableScope,
|
||||
matrixRoom: MatrixRoom,
|
||||
): Behavior<Pick<RoomMember, "userId" | "getMxcAvatarUrl">[]> {
|
||||
return scope.behavior(
|
||||
fromEvent(matrixRoom, RoomStateEvent.Members).pipe(
|
||||
map(() => matrixRoom.getMembers()),
|
||||
),
|
||||
[],
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Displayname for each member of the call. This will disambiguate
|
||||
* any displayname that clashes with another member. Only members
|
||||
@@ -37,6 +48,7 @@ import { type Behavior } from "../../Behavior";
|
||||
export const memberDisplaynames$ = (
|
||||
scope: ObservableScope,
|
||||
matrixRoom: Pick<MatrixRoom, "getMember"> & NodeStyleEventEmitter,
|
||||
// roomMember$: Behavior<Pick<RoomMember, "userId" | "getMxcAvatarUrl">>;
|
||||
memberships$: Observable<Epoch<CallMembership[]>>,
|
||||
): Behavior<Epoch<Map<string, string>>> =>
|
||||
scope.behavior(
|
||||
|
||||
Reference in New Issue
Block a user