Create media items for session members not joined to LiveKit

This commit is contained in:
Robin
2025-10-03 19:14:48 -04:00
parent 86fb026be8
commit 1820cac3f6
5 changed files with 32 additions and 45 deletions

View File

@@ -304,7 +304,7 @@ class UserMedia {
public readonly presenter$: Behavior<boolean>;
public constructor(
public readonly id: string,
member: RoomMember | undefined,
member: RoomMember,
participant: LocalParticipant | RemoteParticipant | undefined,
encryptionSystem: EncryptionSystem,
livekitRoom: LivekitRoom,
@@ -377,7 +377,7 @@ class ScreenShare {
public constructor(
id: string,
member: RoomMember | undefined,
member: RoomMember,
participant: LocalParticipant | RemoteParticipant,
encryptionSystem: EncryptionSystem,
livekitRoom: LivekitRoom,
@@ -799,7 +799,8 @@ export class CallViewModel extends ViewModel {
livekitRoom: LivekitRoom;
url: string;
participants: {
participant: LocalParticipant | RemoteParticipant;
id: string;
participant: LocalParticipant | RemoteParticipant | undefined;
member: RoomMember;
}[];
}[]
@@ -814,6 +815,7 @@ export class CallViewModel extends ViewModel {
throw new Error("No room member for call membership");
};
const localParticipant = {
id: "local",
participant: localConnection.livekitRoom.localParticipant,
member:
this.matrixRoom.getMember(this.userId ?? "") ?? memberError(),
@@ -826,9 +828,14 @@ export class CallViewModel extends ViewModel {
c.publishingParticipants$.pipe(
map((ps) => {
const participants: {
participant: LocalParticipant | RemoteParticipant;
id: string;
participant:
| LocalParticipant
| RemoteParticipant
| undefined;
member: RoomMember;
}[] = ps.map(({ participant, membership }) => ({
id: `${membership.sender}:${membership.deviceId}`,
participant,
member:
getRoomMemberFromRtcMember(
@@ -929,26 +936,12 @@ export class CallViewModel extends ViewModel {
const newItems: Map<string, UserMedia | ScreenShare> = new Map(
function* (this: CallViewModel): Iterable<[string, MediaItem]> {
for (const { livekitRoom, participants } of participantsByRoom) {
for (const { participant, member } of participants) {
const matrixId = participant.isLocal
? "local"
: participant.identity;
for (const { id, participant, member } of participants) {
for (let i = 0; i < 1 + duplicateTiles; i++) {
const mediaId = `${matrixId}:${i}`;
let prevMedia = prevItems.get(mediaId);
if (prevMedia && prevMedia instanceof UserMedia) {
const mediaId = `${id}:${i}`;
const prevMedia = prevItems.get(mediaId);
if (prevMedia instanceof UserMedia)
prevMedia.updateParticipant(participant);
if (prevMedia.vm.member === undefined) {
// TODO-MULTI-SFU: This is outdated.
// We have a previous media created because of the `debugShowNonMember` flag.
// In this case we actually replace the media item.
// This "hack" never occurs if we do not use the `debugShowNonMember` debugging
// option and if we always find a room member for each rtc member (which also
// only fails if we have a fundamental problem)
prevMedia = undefined;
}
}
yield [
mediaId,
@@ -965,14 +958,10 @@ export class CallViewModel extends ViewModel {
this.mediaDevices,
this.pretendToBeDisconnected$,
this.memberDisplaynames$.pipe(
map((m) => m.get(matrixId) ?? "[👻]"),
),
this.handsRaised$.pipe(
map((v) => v[matrixId]?.time ?? null),
),
this.reactions$.pipe(
map((v) => v[matrixId] ?? undefined),
map((m) => m.get(id) ?? "[👻]"),
),
this.handsRaised$.pipe(map((v) => v[id]?.time ?? null)),
this.reactions$.pipe(map((v) => v[id] ?? undefined)),
),
];
@@ -989,7 +978,7 @@ export class CallViewModel extends ViewModel {
livekitRoom,
this.pretendToBeDisconnected$,
this.memberDisplaynames$.pipe(
map((m) => m.get(matrixId) ?? "[👻]"),
map((m) => m.get(id) ?? "[👻]"),
),
),
];

View File

@@ -66,7 +66,7 @@ export class Connection {
this.livekitAlias,
);
public readonly participantsIncludingSubscribers$;
private readonly participantsIncludingSubscribers$;
public readonly publishingParticipants$;
public readonly livekitRoom: LivekitRoom;
@@ -105,13 +105,11 @@ export class Connection {
? [membership]
: [],
)
// Find all associated publishing livekit participant objects
.flatMap((membership) => {
const participant = participants.find(
(p) =>
p.identity === `${membership.sender}:${membership.deviceId}`,
);
return participant ? [{ participant, membership }] : [];
// Pair with their associated LiveKit participant (if any)
.map((membership) => {
const id = `${membership.sender}:${membership.deviceId}`;
const participant = participants.find((p) => p.identity === id);
return { participant, membership };
}),
),
[],

View File

@@ -255,7 +255,7 @@ abstract class BaseMediaViewModel extends ViewModel {
*/
// TODO: Fully separate the data layer from the UI layer by keeping the
// member object internal
public readonly member: RoomMember | undefined,
public readonly member: RoomMember,
// We don't necessarily have a participant if a user connects via MatrixRTC but not (yet) through
// livekit.
protected readonly participant$: Observable<
@@ -403,7 +403,7 @@ abstract class BaseUserMediaViewModel extends BaseMediaViewModel {
public constructor(
id: string,
member: RoomMember | undefined,
member: RoomMember,
participant$: Observable<LocalParticipant | RemoteParticipant | undefined>,
encryptionSystem: EncryptionSystem,
livekitRoom: LivekitRoom,
@@ -535,7 +535,7 @@ export class LocalUserMediaViewModel extends BaseUserMediaViewModel {
public constructor(
id: string,
member: RoomMember | undefined,
member: RoomMember,
participant$: Behavior<LocalParticipant | undefined>,
encryptionSystem: EncryptionSystem,
livekitRoom: LivekitRoom,
@@ -641,7 +641,7 @@ export class RemoteUserMediaViewModel extends BaseUserMediaViewModel {
public constructor(
id: string,
member: RoomMember | undefined,
member: RoomMember,
participant$: Observable<RemoteParticipant | undefined>,
encryptionSystem: EncryptionSystem,
livekitRoom: LivekitRoom,
@@ -736,7 +736,7 @@ export class ScreenShareViewModel extends BaseMediaViewModel {
public constructor(
id: string,
member: RoomMember | undefined,
member: RoomMember,
participant$: Observable<LocalParticipant | RemoteParticipant>,
encryptionSystem: EncryptionSystem,
livekitRoom: LivekitRoom,

View File

@@ -32,7 +32,7 @@ interface Props extends ComponentProps<typeof animated.div> {
video: TrackReferenceOrPlaceholder | undefined;
videoFit: "cover" | "contain";
mirror: boolean;
member: RoomMember | undefined;
member: RoomMember;
videoEnabled: boolean;
unencryptedWarning: boolean;
encryptionStatus: EncryptionStatus;

View File

@@ -55,7 +55,7 @@ interface SpotlightItemBaseProps {
targetHeight: number;
video: TrackReferenceOrPlaceholder | undefined;
videoEnabled: boolean;
member: RoomMember | undefined;
member: RoomMember;
unencryptedWarning: boolean;
encryptionStatus: EncryptionStatus;
displayName: string;