mirror of
https://github.com/vector-im/element-call.git
synced 2026-07-09 18:29:21 +00:00
Clarify which Matrix-LiveKit members are remote
It was rather confusing that matrixLivekitMembers$ gives you objects of type RemoteMatrixLivekitMembers and yet the *local* member would often be among these. I've attempted to clear this up. To my knowledge this wasn't creating any bugs.
This commit is contained in:
10
sdk/main.ts
10
sdk/main.ts
@@ -76,9 +76,9 @@ interface MatrixRTCSdk {
|
|||||||
stop: () => void;
|
stop: () => void;
|
||||||
data$: Observable<{ rtcBackendIdentity: string; data: string }>;
|
data$: Observable<{ rtcBackendIdentity: string; data: string }>;
|
||||||
/**
|
/**
|
||||||
* flattened list of members
|
* flattened list of remote members
|
||||||
*/
|
*/
|
||||||
members$: Behavior<
|
remoteMembers$: Behavior<
|
||||||
{
|
{
|
||||||
connection: Connection | null;
|
connection: Connection | null;
|
||||||
membership: CallMembership;
|
membership: CallMembership;
|
||||||
@@ -86,7 +86,7 @@ interface MatrixRTCSdk {
|
|||||||
}[]
|
}[]
|
||||||
>;
|
>;
|
||||||
/**
|
/**
|
||||||
* flattened local members
|
* flattened local member
|
||||||
*/
|
*/
|
||||||
localMember$: Behavior<{
|
localMember$: Behavior<{
|
||||||
connection: Connection | null;
|
connection: Connection | null;
|
||||||
@@ -338,8 +338,8 @@ export async function createMatrixRTCSdk(
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
connected$: callViewModel.connected$,
|
connected$: callViewModel.connected$,
|
||||||
members$: scope.behavior(
|
remoteMembers$: scope.behavior(
|
||||||
callViewModel.matrixLivekitMembers$.pipe(
|
callViewModel.remoteMatrixLivekitMembers$.pipe(
|
||||||
switchMap((members) => {
|
switchMap((members) => {
|
||||||
const listOfMemberObservables = members.map((member) =>
|
const listOfMemberObservables = members.map((member) =>
|
||||||
combineLatest([
|
combineLatest([
|
||||||
|
|||||||
@@ -127,10 +127,9 @@ import {
|
|||||||
createConnectionManager$,
|
createConnectionManager$,
|
||||||
} from "./remoteMembers/ConnectionManager.ts";
|
} from "./remoteMembers/ConnectionManager.ts";
|
||||||
import {
|
import {
|
||||||
createMatrixLivekitMembers$,
|
createRemoteMatrixLivekitMembers$,
|
||||||
type LocalMatrixLivekitMember,
|
type LocalMatrixLivekitMember,
|
||||||
type RemoteMatrixLivekitMember,
|
type RemoteMatrixLivekitMember,
|
||||||
type MatrixLivekitMember,
|
|
||||||
} from "./remoteMembers/MatrixLivekitMembers.ts";
|
} from "./remoteMembers/MatrixLivekitMembers.ts";
|
||||||
import {
|
import {
|
||||||
type AutoLeaveReason,
|
type AutoLeaveReason,
|
||||||
@@ -302,7 +301,7 @@ export interface CallViewModel {
|
|||||||
/** Participants sorted by livekit room so they can be used in the audio rendering */
|
/** Participants sorted by livekit room so they can be used in the audio rendering */
|
||||||
livekitRoomItems$: Behavior<LivekitRoomItem[]>;
|
livekitRoomItems$: Behavior<LivekitRoomItem[]>;
|
||||||
/** use the layout instead, this is just for the sdk export. */
|
/** use the layout instead, this is just for the sdk export. */
|
||||||
matrixLivekitMembers$: Behavior<RemoteMatrixLivekitMember[]>;
|
remoteMatrixLivekitMembers$: Behavior<RemoteMatrixLivekitMember[]>;
|
||||||
localMatrixLivekitMember$: Behavior<LocalMatrixLivekitMember | null>;
|
localMatrixLivekitMember$: Behavior<LocalMatrixLivekitMember | null>;
|
||||||
/** List of participants raising their hand */
|
/** List of participants raising their hand */
|
||||||
handsRaised$: Behavior<Record<string, RaisedHandInfo>>;
|
handsRaised$: Behavior<Record<string, RaisedHandInfo>>;
|
||||||
@@ -529,13 +528,15 @@ export function createCallViewModel$(
|
|||||||
ownMembershipIdentity,
|
ownMembershipIdentity,
|
||||||
});
|
});
|
||||||
|
|
||||||
const matrixLivekitMembers$: Behavior<Epoch<RemoteMatrixLivekitMember[]>> =
|
const remoteMatrixLivekitMembers$: Behavior<
|
||||||
createMatrixLivekitMembers$({
|
Epoch<RemoteMatrixLivekitMember[]>
|
||||||
scope: scope,
|
> = createRemoteMatrixLivekitMembers$({
|
||||||
membershipsWithTransport$:
|
scope: scope,
|
||||||
membershipsAndTransports.membershipsWithTransport$,
|
membershipsWithTransport$:
|
||||||
connectionManager: connectionManager,
|
membershipsAndTransports.membershipsWithTransport$,
|
||||||
});
|
connectionManager: connectionManager,
|
||||||
|
localUser: { userId, deviceId },
|
||||||
|
});
|
||||||
|
|
||||||
const connectOptions$ = scope.behavior(
|
const connectOptions$ = scope.behavior(
|
||||||
matrixRTCMode$.pipe(
|
matrixRTCMode$.pipe(
|
||||||
@@ -612,6 +613,13 @@ export function createCallViewModel$(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const matrixLivekitMembers$ = scope.behavior(
|
||||||
|
combineLatest(
|
||||||
|
[localMatrixLivekitMember$, remoteMatrixLivekitMembers$],
|
||||||
|
(local, remote) => [...(local === null ? [] : [local]), ...remote.value],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// matrixMemberMetadataStore
|
// matrixMemberMetadataStore
|
||||||
|
|
||||||
@@ -641,7 +649,7 @@ export function createCallViewModel$(
|
|||||||
connectionManager.connectionManagerData$.pipe(map((d) => d.value)),
|
connectionManager.connectionManagerData$.pipe(map((d) => d.value)),
|
||||||
);
|
);
|
||||||
const livekitRoomItems$ = scope.behavior(
|
const livekitRoomItems$ = scope.behavior(
|
||||||
matrixLivekitMembers$.pipe(
|
remoteMatrixLivekitMembers$.pipe(
|
||||||
switchMap((members) => {
|
switchMap((members) => {
|
||||||
const a$ = combineLatest(
|
const a$ = combineLatest(
|
||||||
members.value.map((member) =>
|
members.value.map((member) =>
|
||||||
@@ -707,43 +715,20 @@ export function createCallViewModel$(
|
|||||||
* List of user media (camera feeds) that we want tiles for.
|
* List of user media (camera feeds) that we want tiles for.
|
||||||
*/
|
*/
|
||||||
const userMedia$ = scope.behavior<WrappedUserMediaViewModel[]>(
|
const userMedia$ = scope.behavior<WrappedUserMediaViewModel[]>(
|
||||||
combineLatest([
|
combineLatest([matrixLivekitMembers$, duplicateTiles.value$]).pipe(
|
||||||
localMatrixLivekitMember$,
|
|
||||||
matrixLivekitMembers$,
|
|
||||||
duplicateTiles.value$,
|
|
||||||
]).pipe(
|
|
||||||
// Generate a collection of user media from the list of expected (whether
|
// Generate a collection of user media from the list of expected (whether
|
||||||
// present or missing) LiveKit participants.
|
// present or missing) LiveKit participants.
|
||||||
generateItems(
|
generateItems(
|
||||||
"CallViewModel userMedia$",
|
"CallViewModel userMedia$",
|
||||||
function* ([
|
function* ([members, duplicateTiles]) {
|
||||||
localMatrixLivekitMember,
|
for (const {
|
||||||
matrixLivekitMembers,
|
userId,
|
||||||
duplicateTiles,
|
participant,
|
||||||
]) {
|
connection$,
|
||||||
const computeMediaId = (m: MatrixLivekitMember): string =>
|
membership$,
|
||||||
`${m.userId}:${m.membership$.value.deviceId}`;
|
} of members) {
|
||||||
|
const rtcId = membership$.value.rtcBackendIdentity;
|
||||||
const localUserMediaId = localMatrixLivekitMember
|
const mediaId = `${userId}:${membership$.value.deviceId}`;
|
||||||
? computeMediaId(localMatrixLivekitMember)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const localAsArray = localMatrixLivekitMember
|
|
||||||
? [localMatrixLivekitMember]
|
|
||||||
: [];
|
|
||||||
const remoteWithoutLocal = matrixLivekitMembers.value.filter(
|
|
||||||
(m) => computeMediaId(m) !== localUserMediaId,
|
|
||||||
);
|
|
||||||
const allMatrixLivekitMembers = [
|
|
||||||
...localAsArray,
|
|
||||||
...remoteWithoutLocal,
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const matrixLivekitMember of allMatrixLivekitMembers) {
|
|
||||||
const { userId, participant, connection$, membership$ } =
|
|
||||||
matrixLivekitMember;
|
|
||||||
const rtcId = membership$.value.rtcBackendIdentity; // rtcBackendIdentity
|
|
||||||
const mediaId = computeMediaId(matrixLivekitMember);
|
|
||||||
for (let dup = 0; dup < 1 + duplicateTiles; dup++) {
|
for (let dup = 0; dup < 1 + duplicateTiles; dup++) {
|
||||||
yield {
|
yield {
|
||||||
keys: [dup, mediaId, userId, participant, connection$, rtcId],
|
keys: [dup, mediaId, userId, participant, connection$, rtcId],
|
||||||
@@ -861,7 +846,7 @@ export function createCallViewModel$(
|
|||||||
* multiple devices.
|
* multiple devices.
|
||||||
*/
|
*/
|
||||||
const participantCount$ = scope.behavior(
|
const participantCount$ = scope.behavior(
|
||||||
matrixLivekitMembers$.pipe(map((ms) => ms.value.length)),
|
matrixLivekitMembers$.pipe(map((ms) => ms.length)),
|
||||||
);
|
);
|
||||||
|
|
||||||
const leaveSoundEffect$ = userMedia$.pipe(
|
const leaveSoundEffect$ = userMedia$.pipe(
|
||||||
@@ -1770,8 +1755,8 @@ export function createCallViewModel$(
|
|||||||
setGridMode: setGridMode,
|
setGridMode: setGridMode,
|
||||||
layout$: layout$,
|
layout$: layout$,
|
||||||
localMatrixLivekitMember$,
|
localMatrixLivekitMember$,
|
||||||
matrixLivekitMembers$: scope.behavior(
|
remoteMatrixLivekitMembers$: scope.behavior(
|
||||||
matrixLivekitMembers$.pipe(
|
remoteMatrixLivekitMembers$.pipe(
|
||||||
map((members) => members.value),
|
map((members) => members.value),
|
||||||
tap((v) => {
|
tap((v) => {
|
||||||
const listForLogs = v
|
const listForLogs = v
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { BehaviorSubject, combineLatest, map, type Observable } from "rxjs";
|
|||||||
import { type IConnectionManager } from "./ConnectionManager.ts";
|
import { type IConnectionManager } from "./ConnectionManager.ts";
|
||||||
import {
|
import {
|
||||||
type RemoteMatrixLivekitMember,
|
type RemoteMatrixLivekitMember,
|
||||||
createMatrixLivekitMembers$,
|
createRemoteMatrixLivekitMembers$,
|
||||||
} from "./MatrixLivekitMembers.ts";
|
} from "./MatrixLivekitMembers.ts";
|
||||||
import {
|
import {
|
||||||
Epoch,
|
Epoch,
|
||||||
@@ -31,6 +31,7 @@ import {
|
|||||||
} from "../../../utils/test.ts";
|
} from "../../../utils/test.ts";
|
||||||
import { type Connection } from "./Connection.ts";
|
import { type Connection } from "./Connection.ts";
|
||||||
import { constant } from "../../Behavior.ts";
|
import { constant } from "../../Behavior.ts";
|
||||||
|
import { localRtcMember } from "../../../utils/test-fixtures.ts";
|
||||||
|
|
||||||
let testScope: ObservableScope;
|
let testScope: ObservableScope;
|
||||||
|
|
||||||
@@ -88,12 +89,13 @@ test("should signal participant not yet connected to livekit", async () => {
|
|||||||
mockConnectionManagerData$,
|
mockConnectionManagerData$,
|
||||||
);
|
);
|
||||||
|
|
||||||
const matrixLivekitMember$ = createMatrixLivekitMembers$({
|
const matrixLivekitMember$ = createRemoteMatrixLivekitMembers$({
|
||||||
scope: testScope,
|
scope: testScope,
|
||||||
membershipsWithTransport$: testScope.behavior(membershipsWithTransport$),
|
membershipsWithTransport$: testScope.behavior(membershipsWithTransport$),
|
||||||
connectionManager: {
|
connectionManager: {
|
||||||
connectionManagerData$: connectionManagerData$,
|
connectionManagerData$: connectionManagerData$,
|
||||||
} as unknown as IConnectionManager,
|
} as unknown as IConnectionManager,
|
||||||
|
localUser: localRtcMember,
|
||||||
});
|
});
|
||||||
|
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
@@ -157,12 +159,13 @@ test("should signal participant on a connection that is publishing", async () =>
|
|||||||
constant(dataWithPublisher),
|
constant(dataWithPublisher),
|
||||||
);
|
);
|
||||||
|
|
||||||
const matrixLivekitMember$ = createMatrixLivekitMembers$({
|
const matrixLivekitMember$ = createRemoteMatrixLivekitMembers$({
|
||||||
scope: testScope,
|
scope: testScope,
|
||||||
membershipsWithTransport$: testScope.behavior(membershipsWithTransport$),
|
membershipsWithTransport$: testScope.behavior(membershipsWithTransport$),
|
||||||
connectionManager: {
|
connectionManager: {
|
||||||
connectionManagerData$: connectionManagerData$,
|
connectionManagerData$: connectionManagerData$,
|
||||||
} as unknown as IConnectionManager,
|
} as unknown as IConnectionManager,
|
||||||
|
localUser: localRtcMember,
|
||||||
});
|
});
|
||||||
|
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
@@ -197,12 +200,13 @@ test("should signal participant on a connection that is not publishing", async (
|
|||||||
constant(dataWithPublisher),
|
constant(dataWithPublisher),
|
||||||
);
|
);
|
||||||
|
|
||||||
const matrixLivekitMember$ = createMatrixLivekitMembers$({
|
const matrixLivekitMember$ = createRemoteMatrixLivekitMembers$({
|
||||||
scope: testScope,
|
scope: testScope,
|
||||||
membershipsWithTransport$: testScope.behavior(membershipsWithTransport$),
|
membershipsWithTransport$: testScope.behavior(membershipsWithTransport$),
|
||||||
connectionManager: {
|
connectionManager: {
|
||||||
connectionManagerData$: connectionManagerData$,
|
connectionManagerData$: connectionManagerData$,
|
||||||
} as unknown as IConnectionManager,
|
} as unknown as IConnectionManager,
|
||||||
|
localUser: localRtcMember,
|
||||||
});
|
});
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
expect(matrixLivekitMember$.value.value).toSatisfy(
|
expect(matrixLivekitMember$.value.value).toSatisfy(
|
||||||
@@ -245,12 +249,13 @@ describe("Publication edge case", () => {
|
|||||||
constant(connectionWithPublisher),
|
constant(connectionWithPublisher),
|
||||||
);
|
);
|
||||||
|
|
||||||
const matrixLivekitMembers$ = createMatrixLivekitMembers$({
|
const matrixLivekitMembers$ = createRemoteMatrixLivekitMembers$({
|
||||||
scope: testScope,
|
scope: testScope,
|
||||||
membershipsWithTransport$: testScope.behavior(membershipsWithTransport$),
|
membershipsWithTransport$: testScope.behavior(membershipsWithTransport$),
|
||||||
connectionManager: {
|
connectionManager: {
|
||||||
connectionManagerData$: connectionManagerData$,
|
connectionManagerData$: connectionManagerData$,
|
||||||
} as unknown as IConnectionManager,
|
} as unknown as IConnectionManager,
|
||||||
|
localUser: localRtcMember,
|
||||||
});
|
});
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
expect(matrixLivekitMembers$.value.value).toSatisfy(
|
expect(matrixLivekitMembers$.value.value).toSatisfy(
|
||||||
@@ -303,12 +308,13 @@ test("bob is publishing in the wrong connection", async () => {
|
|||||||
connectionsWithPublisher$,
|
connectionsWithPublisher$,
|
||||||
);
|
);
|
||||||
|
|
||||||
const matrixLivekitMember$ = createMatrixLivekitMembers$({
|
const matrixLivekitMember$ = createRemoteMatrixLivekitMembers$({
|
||||||
scope: testScope,
|
scope: testScope,
|
||||||
membershipsWithTransport$: testScope.behavior(membershipsWithTransport$),
|
membershipsWithTransport$: testScope.behavior(membershipsWithTransport$),
|
||||||
connectionManager: {
|
connectionManager: {
|
||||||
connectionManagerData$: connectionManagerData$,
|
connectionManagerData$: connectionManagerData$,
|
||||||
} as unknown as IConnectionManager,
|
} as unknown as IConnectionManager,
|
||||||
|
localUser: localRtcMember,
|
||||||
});
|
});
|
||||||
|
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
|
|||||||
@@ -62,7 +62,9 @@ interface Props {
|
|||||||
Epoch<{ membership: CallMembership; transport?: LivekitTransportConfig }[]>
|
Epoch<{ membership: CallMembership; transport?: LivekitTransportConfig }[]>
|
||||||
>;
|
>;
|
||||||
connectionManager: IConnectionManager;
|
connectionManager: IConnectionManager;
|
||||||
|
localUser: { deviceId: string; userId: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combines MatrixRTC and Livekit worlds.
|
* Combines MatrixRTC and Livekit worlds.
|
||||||
*
|
*
|
||||||
@@ -73,13 +75,14 @@ interface Props {
|
|||||||
* - out (via public Observable):
|
* - out (via public Observable):
|
||||||
* - `remoteMatrixLivekitMember` an observable of MatrixLivekitMember[] to track the remote members and associated livekit data.
|
* - `remoteMatrixLivekitMember` an observable of MatrixLivekitMember[] to track the remote members and associated livekit data.
|
||||||
*/
|
*/
|
||||||
export function createMatrixLivekitMembers$({
|
export function createRemoteMatrixLivekitMembers$({
|
||||||
scope,
|
scope,
|
||||||
membershipsWithTransport$,
|
membershipsWithTransport$,
|
||||||
connectionManager,
|
connectionManager,
|
||||||
|
localUser,
|
||||||
}: Props): Behavior<Epoch<RemoteMatrixLivekitMember[]>> {
|
}: Props): Behavior<Epoch<RemoteMatrixLivekitMember[]>> {
|
||||||
/**
|
/**
|
||||||
* Stream of all the call members and their associated livekit data (if available).
|
* Behavior of all the remote call members and their associated livekit data (if available).
|
||||||
*/
|
*/
|
||||||
return scope.behavior(
|
return scope.behavior(
|
||||||
combineLatest([
|
combineLatest([
|
||||||
@@ -91,12 +94,19 @@ export function createMatrixLivekitMembers$({
|
|||||||
),
|
),
|
||||||
map(([ms, data]) => new Epoch([ms.value, data.value] as const, ms.epoch)),
|
map(([ms, data]) => new Epoch([ms.value, data.value] as const, ms.epoch)),
|
||||||
generateItemsWithEpoch(
|
generateItemsWithEpoch(
|
||||||
"MatrixLivekitMembers",
|
"RemoteMatrixLivekitMembers",
|
||||||
// Generator function.
|
// Generator function.
|
||||||
// creates an array of `{key, data}[]`
|
// creates an array of `{key, data}[]`
|
||||||
// Each change in the keys (new key) will result in a call to the factory function.
|
// Each change in the keys (new key) will result in a call to the factory function.
|
||||||
function* ([membershipsWithTransport, managerData]) {
|
function* ([membershipsWithTransport, managerData]) {
|
||||||
for (const { membership, transport } of membershipsWithTransport) {
|
for (const { membership, transport } of membershipsWithTransport) {
|
||||||
|
// Exclude the local membership
|
||||||
|
if (
|
||||||
|
membership.userId === localUser.userId &&
|
||||||
|
membership.deviceId === localUser.deviceId
|
||||||
|
)
|
||||||
|
continue;
|
||||||
|
|
||||||
const participants = transport
|
const participants = transport
|
||||||
? managerData.getParticipantsForTransport(transport)
|
? managerData.getParticipantsForTransport(transport)
|
||||||
: [];
|
: [];
|
||||||
|
|||||||
@@ -29,13 +29,13 @@ import {
|
|||||||
import { type ProcessorState } from "../../../livekit/TrackProcessorContext.tsx";
|
import { type ProcessorState } from "../../../livekit/TrackProcessorContext.tsx";
|
||||||
import {
|
import {
|
||||||
areLivekitTransportsEqual,
|
areLivekitTransportsEqual,
|
||||||
createMatrixLivekitMembers$,
|
createRemoteMatrixLivekitMembers$,
|
||||||
type RemoteMatrixLivekitMember,
|
type RemoteMatrixLivekitMember,
|
||||||
} from "./MatrixLivekitMembers.ts";
|
} from "./MatrixLivekitMembers.ts";
|
||||||
import { createConnectionManager$ } from "./ConnectionManager.ts";
|
import { createConnectionManager$ } from "./ConnectionManager.ts";
|
||||||
import { membershipsAndTransports$ } from "../../SessionBehaviors.ts";
|
import { membershipsAndTransports$ } from "../../SessionBehaviors.ts";
|
||||||
import { constant } from "../../Behavior.ts";
|
import { constant } from "../../Behavior.ts";
|
||||||
import { testJWTToken } from "../../../utils/test-fixtures.ts";
|
import { localRtcMember, testJWTToken } from "../../../utils/test-fixtures.ts";
|
||||||
|
|
||||||
// Test the integration of ConnectionManager and MatrixLivekitMerger
|
// Test the integration of ConnectionManager and MatrixLivekitMerger
|
||||||
|
|
||||||
@@ -130,11 +130,12 @@ test("bob, carl, then bob joining no tracks yet", () => {
|
|||||||
ownMembershipIdentity: ownMemberMock,
|
ownMembershipIdentity: ownMemberMock,
|
||||||
});
|
});
|
||||||
|
|
||||||
const matrixLivekitMembers$ = createMatrixLivekitMembers$({
|
const matrixLivekitMembers$ = createRemoteMatrixLivekitMembers$({
|
||||||
scope: testScope,
|
scope: testScope,
|
||||||
membershipsWithTransport$:
|
membershipsWithTransport$:
|
||||||
membershipsAndTransports.membershipsWithTransport$,
|
membershipsAndTransports.membershipsWithTransport$,
|
||||||
connectionManager,
|
connectionManager,
|
||||||
|
localUser: localRtcMember,
|
||||||
});
|
});
|
||||||
|
|
||||||
expectObservable(matrixLivekitMembers$).toBe(vMarble, {
|
expectObservable(matrixLivekitMembers$).toBe(vMarble, {
|
||||||
|
|||||||
Reference in New Issue
Block a user