Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/state/CallViewModel/CallViewModel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ import {
import { MediaDevices } from "../MediaDevices.ts";
import { getValue } from "../../utils/observable.ts";
import { type Behavior, constant } from "../Behavior.ts";
import { withCallViewModel } from "./CallViewModelTestUtils.ts";
import { withCallViewModel as withCallViewModelInMode } from "./CallViewModelTestUtils.ts";
import { MatrixRTCMode } from "../../settings/settings.ts";

vi.mock("rxjs", async (importOriginal) => ({
...(await importOriginal()),
Expand Down Expand Up @@ -229,7 +230,13 @@ function mockRingEvent(
// need a value to fill in for them when emitting notifications
const mockLegacyRingEvent = {} as { event_id: string } & ICallNotifyContent;

describe("CallViewModel", () => {
describe.each([
[MatrixRTCMode.Legacy],
[MatrixRTCMode.Compatibil],
[MatrixRTCMode.Matrix_2_0],
])("CallViewModel (%s mode)", (mode) => {
const withCallViewModel = withCallViewModelInMode(mode);

test("participants are retained during a focus switch", () => {
withTestScheduler(({ behavior, expectObservable }) => {
// Participants disappear on frame 2 and come back on frame 3
Expand Down
58 changes: 34 additions & 24 deletions src/state/CallViewModel/CallViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import { accumulate, generateItems, pauseWhen } from "../../utils/observable";
import {
duplicateTiles,
MatrixRTCMode,
matrixRTCMode,
matrixRTCMode as matrixRTCModeSetting,
playReactionsSound,
showReactions,
} from "../../settings/settings";
Expand Down Expand Up @@ -110,6 +110,7 @@ import { ECConnectionFactory } from "./remoteMembers/ConnectionFactory.ts";
import { createConnectionManager$ } from "./remoteMembers/ConnectionManager.ts";
import {
createMatrixLivekitMembers$,
type TaggedParticipant,
type MatrixLivekitMember,
} from "./remoteMembers/MatrixLivekitMembers.ts";
import {
Expand Down Expand Up @@ -149,6 +150,8 @@ export interface CallViewModelOptions {
connectionState$?: Behavior<ConnectionState>;
/** Optional behavior overriding the computed window size, mainly for testing purposes. */
windowSize$?: Behavior<{ width: number; height: number }>;
/** Optional behavior overriding the MatrixRTC mode, mainly for testing purposes. */
matrixRTCMode$?: Behavior<MatrixRTCMode>;
}

// Do not play any sounds if the participant count has exceeded this
Expand Down Expand Up @@ -399,13 +402,15 @@ export function createCallViewModel$(
memberships$,
);

const matrixRTCMode$ = options.matrixRTCMode$ ?? matrixRTCModeSetting.value$;

const localTransport$ = createLocalTransport$({
scope: scope,
memberships$: memberships$,
client,
roomId: matrixRoom.roomId,
useOldestMember$: scope.behavior(
matrixRTCMode.value$.pipe(map((v) => v === MatrixRTCMode.Legacy)),
matrixRTCMode$.pipe(map((v) => v === MatrixRTCMode.Legacy)),
),
});

Expand Down Expand Up @@ -446,7 +451,7 @@ export function createCallViewModel$(
});

const connectOptions$ = scope.behavior(
matrixRTCMode.value$.pipe(
matrixRTCMode$.pipe(
map((mode) => ({
encryptMedia: livekitKeyProvider !== undefined,
// TODO. This might need to get called again on each change of matrixRTCMode...
Expand Down Expand Up @@ -500,23 +505,26 @@ export function createCallViewModel$(
),
);

const localMatrixLivekitMemberUninitialized = {
membership$: localRtcMembership$,
participant$: localMembership.participant$,
connection$: localMembership.connection$,
userId: userId,
};

const localMatrixLivekitMember$: Behavior<MatrixLivekitMember | null> =
scope.behavior(
const localMatrixLivekitMember$ =
scope.behavior<MatrixLivekitMember<"local"> | null>(
localRtcMembership$.pipe(
switchMap((membership) => {
if (!membership) return of(null);
return of(
// casting is save here since we know that localRtcMembership$ is !== null since we reached this case.
localMatrixLivekitMemberUninitialized as MatrixLivekitMember,
);
}),
generateItems(
// Generate a local member when membership is non-null
function* (membership) {
if (membership !== null)
yield { keys: ["local"], data: membership };
},
(_scope, membership$) => ({
membership$,
participant: {
type: "local" as const,
value$: localMembership.participant$,
},
connection$: localMembership.connection$,
userId,
}),
),
map(([localMember]) => localMember ?? null),
),
);

Expand Down Expand Up @@ -595,7 +603,7 @@ export function createCallViewModel$(
const members = membersWithEpoch.value;
const a$ = combineLatest(
members.map((member) =>
combineLatest([member.connection$, member.participant$]).pipe(
combineLatest([member.connection$, member.participant.value$]).pipe(
map(([connection, participant]) => {
// do not render audio for local participant
if (!connection || !participant || participant.isLocal)
Expand Down Expand Up @@ -673,8 +681,10 @@ export function createCallViewModel$(
let localParticipantId: string | undefined = undefined;
// add local member if available
if (localMatrixLivekitMember) {
const { userId, participant$, connection$, membership$ } =
const { userId, connection$, membership$ } =
localMatrixLivekitMember;
const participant: TaggedParticipant =
localMatrixLivekitMember.participant; // Widen the type
localParticipantId = `${userId}:${membership$.value.deviceId}`; // should be membership$.value.membershipID which is not optional
// const participantId = membership$.value.membershipID;
if (localParticipantId) {
Expand All @@ -684,7 +694,7 @@ export function createCallViewModel$(
dup,
localParticipantId,
userId,
participant$,
participant,
connection$,
],
data: undefined,
Expand All @@ -695,7 +705,7 @@ export function createCallViewModel$(
// add remote members that are available
for (const {
userId,
participant$,
participant,
connection$,
membership$,
} of matrixLivekitMembers) {
Expand All @@ -704,7 +714,7 @@ export function createCallViewModel$(
// const participantId = membership$.value?.identity;
for (let dup = 0; dup < 1 + duplicateTiles; dup++) {
yield {
keys: [dup, participantId, userId, participant$, connection$],
keys: [dup, participantId, userId, participant, connection$],
data: undefined,
};
}
Expand Down
Loading
Loading