mirror of
https://github.com/vector-im/element-call.git
synced 2026-02-08 04:19:11 +00:00
Remove the option to show non-member ("ghost") participants
As we'd like to get the multi-SFU feature branch shipped, this is not the most important debugging tool to expend effort on at the moment.
This commit is contained in:
@@ -13,7 +13,6 @@ import {
|
||||
useSetting,
|
||||
duplicateTiles as duplicateTilesSetting,
|
||||
debugTileLayout as debugTileLayoutSetting,
|
||||
showNonMemberTiles as showNonMemberTilesSetting,
|
||||
showConnectionStats as showConnectionStatsSetting,
|
||||
useNewMembershipManager as useNewMembershipManagerSetting,
|
||||
useExperimentalToDeviceTransport as useExperimentalToDeviceTransportSetting,
|
||||
@@ -35,9 +34,6 @@ export const DeveloperSettingsTab: FC<Props> = ({ client, livekitRooms }) => {
|
||||
const [debugTileLayout, setDebugTileLayout] = useSetting(
|
||||
debugTileLayoutSetting,
|
||||
);
|
||||
const [showNonMemberTiles, setShowNonMemberTiles] = useSetting(
|
||||
showNonMemberTilesSetting,
|
||||
);
|
||||
|
||||
const [showConnectionStats, setShowConnectionStats] = useSetting(
|
||||
showConnectionStatsSetting,
|
||||
@@ -128,20 +124,6 @@ export const DeveloperSettingsTab: FC<Props> = ({ client, livekitRooms }) => {
|
||||
}
|
||||
/>
|
||||
</FieldRow>
|
||||
<FieldRow>
|
||||
<InputField
|
||||
id="showNonMemberTiles"
|
||||
type="checkbox"
|
||||
label={t("developer_mode.show_non_member_tiles")}
|
||||
checked={!!showNonMemberTiles}
|
||||
onChange={useCallback(
|
||||
(event: ChangeEvent<HTMLInputElement>): void => {
|
||||
setShowNonMemberTiles(event.target.checked);
|
||||
},
|
||||
[setShowNonMemberTiles],
|
||||
)}
|
||||
/>
|
||||
</FieldRow>
|
||||
<FieldRow>
|
||||
<InputField
|
||||
id="showConnectionStats"
|
||||
|
||||
@@ -76,10 +76,6 @@ export const developerMode = new Setting("developer-settings-tab", false);
|
||||
|
||||
export const duplicateTiles = new Setting("duplicate-tiles", 0);
|
||||
|
||||
export const showNonMemberTiles = new Setting<boolean>(
|
||||
"show-non-member-tiles",
|
||||
false,
|
||||
);
|
||||
export const debugTileLayout = new Setting("debug-tile-layout", false);
|
||||
|
||||
export const showConnectionStats = new Setting<boolean>(
|
||||
|
||||
@@ -69,7 +69,6 @@ import {
|
||||
} from "../livekit/useECConnectionState";
|
||||
import { E2eeType } from "../e2ee/e2eeType";
|
||||
import type { RaisedHandInfo } from "../reactions";
|
||||
import { showNonMemberTiles } from "../settings/settings";
|
||||
import {
|
||||
alice,
|
||||
aliceDoppelganger,
|
||||
@@ -824,53 +823,6 @@ test("participants must have a MatrixRTCSession to be visible", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("shows participants without MatrixRTCSession when enabled in settings", () => {
|
||||
try {
|
||||
// enable the setting:
|
||||
showNonMemberTiles.setValue(true);
|
||||
withTestScheduler(({ behavior, expectObservable }) => {
|
||||
const scenarioInputMarbles = " abc";
|
||||
const expectedLayoutMarbles = "abc";
|
||||
|
||||
withCallViewModel(
|
||||
{
|
||||
remoteParticipants$: behavior(scenarioInputMarbles, {
|
||||
a: [],
|
||||
b: [aliceParticipant],
|
||||
c: [aliceParticipant, bobParticipant],
|
||||
}),
|
||||
rtcMembers$: constant([localRtcMember]), // No one else joins the MatrixRTC session
|
||||
},
|
||||
(vm) => {
|
||||
vm.setGridMode("grid");
|
||||
expectObservable(summarizeLayout$(vm.layout$)).toBe(
|
||||
expectedLayoutMarbles,
|
||||
{
|
||||
a: {
|
||||
type: "grid",
|
||||
spotlight: undefined,
|
||||
grid: ["local:0"],
|
||||
},
|
||||
b: {
|
||||
type: "one-on-one",
|
||||
local: "local:0",
|
||||
remote: `${aliceId}:0`,
|
||||
},
|
||||
c: {
|
||||
type: "grid",
|
||||
spotlight: undefined,
|
||||
grid: ["local:0", `${aliceId}:0`, `${bobId}:0`],
|
||||
},
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
} finally {
|
||||
showNonMemberTiles.setValue(showNonMemberTiles.defaultValue);
|
||||
}
|
||||
});
|
||||
|
||||
it("should show at least one tile per MatrixRTCSession", () => {
|
||||
withTestScheduler(({ behavior, expectObservable }) => {
|
||||
// iterate through some combinations of MatrixRTC memberships
|
||||
|
||||
@@ -92,7 +92,6 @@ import {
|
||||
duplicateTiles,
|
||||
playReactionsSound,
|
||||
showReactions,
|
||||
showNonMemberTiles,
|
||||
} from "../settings/settings";
|
||||
import { isFirefox } from "../Platform";
|
||||
import { setPipEnabled$ } from "../controls";
|
||||
@@ -812,152 +811,84 @@ export class CallViewModel extends ViewModel {
|
||||
this.participantsByRoom$,
|
||||
duplicateTiles.value$,
|
||||
this.memberships$,
|
||||
showNonMemberTiles.value$,
|
||||
]).pipe(
|
||||
scan(
|
||||
(
|
||||
prevItems,
|
||||
[participantsByRoom, duplicateTiles, memberships, showNonMemberTiles],
|
||||
) => {
|
||||
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;
|
||||
scan((prevItems, [participantsByRoom, duplicateTiles, memberships]) => {
|
||||
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 (let i = 0; i < 1 + duplicateTiles; i++) {
|
||||
const mediaId = `${matrixId}:${i}`;
|
||||
let prevMedia = prevItems.get(mediaId);
|
||||
if (prevMedia && prevMedia instanceof UserMedia) {
|
||||
prevMedia.updateParticipant(participant);
|
||||
if (prevMedia.vm.member === undefined) {
|
||||
// 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;
|
||||
}
|
||||
for (let i = 0; i < 1 + duplicateTiles; i++) {
|
||||
const mediaId = `${matrixId}:${i}`;
|
||||
let prevMedia = prevItems.get(mediaId);
|
||||
if (prevMedia && prevMedia instanceof UserMedia) {
|
||||
prevMedia.updateParticipant(participant);
|
||||
if (prevMedia.vm.member === undefined) {
|
||||
// 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,
|
||||
// We create UserMedia with or without a participant.
|
||||
// This will be the initial value of a BehaviourSubject.
|
||||
// Once a participant appears we will update the BehaviourSubject. (see above)
|
||||
prevMedia ??
|
||||
new UserMedia(
|
||||
mediaId,
|
||||
member,
|
||||
participant,
|
||||
this.options.encryptionSystem,
|
||||
livekitRoom,
|
||||
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),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
if (participant?.isScreenShareEnabled) {
|
||||
const screenShareId = `${mediaId}:screen-share`;
|
||||
yield [
|
||||
mediaId,
|
||||
// We create UserMedia with or without a participant.
|
||||
// This will be the initial value of a BehaviourSubject.
|
||||
// Once a participant appears we will update the BehaviourSubject. (see above)
|
||||
prevMedia ??
|
||||
new UserMedia(
|
||||
mediaId,
|
||||
screenShareId,
|
||||
prevItems.get(screenShareId) ??
|
||||
new ScreenShare(
|
||||
screenShareId,
|
||||
member,
|
||||
participant,
|
||||
this.options.encryptionSystem,
|
||||
livekitRoom,
|
||||
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),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
if (participant?.isScreenShareEnabled) {
|
||||
const screenShareId = `${mediaId}:screen-share`;
|
||||
yield [
|
||||
screenShareId,
|
||||
prevItems.get(screenShareId) ??
|
||||
new ScreenShare(
|
||||
screenShareId,
|
||||
member,
|
||||
participant,
|
||||
this.options.encryptionSystem,
|
||||
livekitRoom,
|
||||
this.pretendToBeDisconnected$,
|
||||
this.memberDisplaynames$.pipe(
|
||||
map((m) => m.get(matrixId) ?? "[👻]"),
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.bind(this)(),
|
||||
);
|
||||
}
|
||||
}.bind(this)(),
|
||||
);
|
||||
|
||||
// Generate non member items (items without a corresponding MatrixRTC member)
|
||||
// Those items should not be rendered, they are participants in LiveKit that do not have a corresponding
|
||||
// MatrixRTC members. This cannot be any good:
|
||||
// - A malicious user impersonates someone
|
||||
// - Someone injects abusive content
|
||||
// - The user cannot have encryption keys so it makes no sense to participate
|
||||
// We can only trust users that have a MatrixRTC member event.
|
||||
//
|
||||
// This is still available as a debug option. This can be useful
|
||||
// - If one wants to test scalability using the LiveKit CLI.
|
||||
// - If an experimental project does not yet do the MatrixRTC bits.
|
||||
// - If someone wants to debug if the LiveKit connection works but MatrixRTC room state failed to arrive.
|
||||
// TODO-MULTI-SFU
|
||||
// const newNonMemberItems = showNonMemberTiles
|
||||
// ? new Map(
|
||||
// function* (
|
||||
// this: CallViewModel,
|
||||
// ): Iterable<[string, MediaItem]> {
|
||||
// for (const participant of remoteParticipants) {
|
||||
// for (let i = 0; i < 1 + duplicateTiles; i++) {
|
||||
// const maybeNonMemberParticipantId =
|
||||
// participant.identity + ":" + i;
|
||||
// if (!newItems.has(maybeNonMemberParticipantId)) {
|
||||
// const nonMemberId = maybeNonMemberParticipantId;
|
||||
// yield [
|
||||
// nonMemberId,
|
||||
// prevItems.get(nonMemberId) ??
|
||||
// new UserMedia(
|
||||
// nonMemberId,
|
||||
// undefined,
|
||||
// participant,
|
||||
// this.options.encryptionSystem,
|
||||
// localConnection.livekitRoom,
|
||||
// this.mediaDevices,
|
||||
// this.pretendToBeDisconnected$,
|
||||
// this.memberDisplaynames$.pipe(
|
||||
// map(
|
||||
// (m) =>
|
||||
// m.get(participant.identity) ?? "[👻]",
|
||||
// ),
|
||||
// ),
|
||||
// of(null),
|
||||
// of(null),
|
||||
// ),
|
||||
// ];
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }.bind(this)(),
|
||||
// )
|
||||
// : new Map();
|
||||
// if (newNonMemberItems.size > 0) {
|
||||
// logger.debug("Added NonMember items: ", newNonMemberItems);
|
||||
// }
|
||||
|
||||
const combinedNew = new Map([
|
||||
// ...newNonMemberItems.entries(),
|
||||
...newItems.entries(),
|
||||
]);
|
||||
|
||||
for (const [id, t] of prevItems)
|
||||
if (!combinedNew.has(id)) t.destroy();
|
||||
return combinedNew;
|
||||
},
|
||||
new Map<string, MediaItem>(),
|
||||
),
|
||||
for (const [id, t] of prevItems) if (!newItems.has(id)) t.destroy();
|
||||
return newItems;
|
||||
}, new Map<string, MediaItem>()),
|
||||
map((mediaItems) => [...mediaItems.values()]),
|
||||
finalizeValue((ts) => {
|
||||
for (const t of ts) t.destroy();
|
||||
|
||||
Reference in New Issue
Block a user