diff --git a/src/state/CallViewModel/CallViewModel.ts b/src/state/CallViewModel/CallViewModel.ts index 0f212101..bf3e9521 100644 --- a/src/state/CallViewModel/CallViewModel.ts +++ b/src/state/CallViewModel/CallViewModel.ts @@ -124,9 +124,9 @@ import { } from "./remoteMembers/ConnectionManager.ts"; import { createMatrixLivekitMembers$, - type TaggedParticipant, type LocalMatrixLivekitMember, type RemoteMatrixLivekitMember, + type MatrixLivekitMember, } from "./remoteMembers/MatrixLivekitMembers.ts"; import { type AutoLeaveReason, @@ -717,65 +717,38 @@ export function createCallViewModel$( matrixLivekitMembers, duplicateTiles, ]) { - let localUserMediaId: string | undefined = undefined; - // add local member if available - if (localMatrixLivekitMember) { + const computeMediaId = (m: MatrixLivekitMember): string => + `${m.userId}:${m.membership$.value.deviceId}`; + + const localUserMediaId = localMatrixLivekitMember + ? 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$ } = - localMatrixLivekitMember; - - localUserMediaId = `${userId}:${membership$.value.deviceId}`; - const rtcBackendIdentity = membership$.value.rtcBackendIdentity; + matrixLivekitMember; + const rtcId = membership$.value.rtcBackendIdentity; // rtcBackendIdentity + const mediaId = computeMediaId(matrixLivekitMember); for (let dup = 0; dup < 1 + duplicateTiles; dup++) { yield { - keys: [ - dup, - localUserMediaId, - userId, - participant satisfies TaggedParticipant as TaggedParticipant, // Widen the type safely - connection$, - rtcBackendIdentity, - ], - data: undefined, - }; - } - } - // add remote members that are available - for (const { - userId, - participant, - connection$, - membership$, - } of matrixLivekitMembers.value) { - const userMediaId = `${userId}:${membership$.value.deviceId}`; - const rtcBackendIdentity = membership$.value.rtcBackendIdentity; - // skip local user as we added them manually before - if (userMediaId === localUserMediaId) continue; - - for (let dup = 0; dup < 1 + duplicateTiles; dup++) { - yield { - keys: [ - dup, - userMediaId, - userId, - participant, - connection$, - rtcBackendIdentity, - ], + keys: [dup, mediaId, userId, participant, connection$, rtcId], data: undefined, }; } } }, - ( - scope, - _data$, - dup, - userMediaId, - userId, - participant, - connection$, - rtcBackendIdentity, - ) => { + (scope, _, dup, mediaId, userId, participant, connection$, rtcId) => { const livekitRoom$ = scope.behavior( connection$.pipe(map((c) => c?.livekitRoom)), ); @@ -790,9 +763,9 @@ export function createCallViewModel$( return new UserMedia( scope, - `${userMediaId}:${dup}`, + `${mediaId}:${dup}`, userId, - rtcBackendIdentity, + rtcId, participant, options.encryptionSystem, livekitRoom$, @@ -801,8 +774,8 @@ export function createCallViewModel$( localMembership.reconnecting$, displayName$, matrixMemberMetadataStore.createAvatarUrlBehavior$(userId), - handsRaised$.pipe(map((v) => v[userMediaId]?.time ?? null)), - reactions$.pipe(map((v) => v[userMediaId] ?? undefined)), + handsRaised$.pipe(map((v) => v[mediaId]?.time ?? null)), + reactions$.pipe(map((v) => v[mediaId] ?? undefined)), ); }, ), diff --git a/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.ts b/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.ts index 10a3e2cb..db52ce2e 100644 --- a/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.ts +++ b/src/state/CallViewModel/remoteMembers/MatrixLivekitMembers.ts @@ -33,7 +33,7 @@ export type TaggedParticipant = | LocalTaggedParticipant | RemoteTaggedParticipant; -interface MatrixLivekitMember { +export interface MatrixLivekitMember { membership$: Behavior; connection$: Behavior; // participantId: string; We do not want a participantId here since it will be generated by the jwt