mirror of
https://github.com/vector-im/element-call.git
synced 2026-02-05 04:15:58 +00:00
Simplify type of audio participants exposed from CallViewModel
This commit is contained in:
@@ -23,12 +23,7 @@ import { useTracks } from "@livekit/components-react";
|
||||
import { testAudioContext } from "../useAudioContext.test";
|
||||
import * as MediaDevicesContext from "../MediaDevicesContext";
|
||||
import { LivekitRoomAudioRenderer } from "./MatrixAudioRenderer";
|
||||
import {
|
||||
mockMatrixRoomMember,
|
||||
mockMediaDevices,
|
||||
mockRtcMembership,
|
||||
mockTrack,
|
||||
} from "../utils/test";
|
||||
import { mockMediaDevices, mockTrack } from "../utils/test";
|
||||
|
||||
export const TestAudioContextConstructor = vi.fn(() => testAudioContext);
|
||||
|
||||
@@ -80,17 +75,11 @@ function renderTestComponent(
|
||||
isLocal,
|
||||
} as unknown as RemoteParticipant);
|
||||
});
|
||||
const participants = rtcMembers.map(({ userId, deviceId }) => {
|
||||
const participants = rtcMembers.flatMap(({ userId, deviceId }) => {
|
||||
const p = liveKitParticipants.find(
|
||||
(p) => p.identity === `${userId}:${deviceId}`,
|
||||
);
|
||||
const localRtcMember = mockRtcMembership(userId, deviceId);
|
||||
const member = mockMatrixRoomMember(localRtcMember);
|
||||
return {
|
||||
id: `${userId}:${deviceId}`,
|
||||
participant: p,
|
||||
member,
|
||||
};
|
||||
return p === undefined ? [] : [p];
|
||||
});
|
||||
const livekitRoom = vi.mocked<Room>({
|
||||
remoteParticipants: new Map<string, Participant>(
|
||||
@@ -98,9 +87,7 @@ function renderTestComponent(
|
||||
),
|
||||
} as unknown as Room);
|
||||
|
||||
tracks = participants
|
||||
.filter((p) => p.participant)
|
||||
.map((p) => mockTrack(p.participant!)) as TrackReference[];
|
||||
tracks = participants.map((p) => mockTrack(p));
|
||||
|
||||
vi.mocked(useTracks).mockReturnValue(tracks);
|
||||
return render(
|
||||
|
||||
@@ -6,7 +6,10 @@ Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { getTrackReferenceId } from "@livekit/components-core";
|
||||
import { type Room as LivekitRoom, type Participant } from "livekit-client";
|
||||
import {
|
||||
type RemoteParticipant,
|
||||
type Room as LivekitRoom,
|
||||
} from "livekit-client";
|
||||
import { type RemoteAudioTrack, Track } from "livekit-client";
|
||||
import { useEffect, useMemo, useRef, useState, type ReactNode } from "react";
|
||||
import {
|
||||
@@ -14,13 +17,13 @@ import {
|
||||
AudioTrack,
|
||||
type AudioTrackProps,
|
||||
} from "@livekit/components-react";
|
||||
import { type RoomMember } from "matrix-js-sdk";
|
||||
import { logger } from "matrix-js-sdk/lib/logger";
|
||||
|
||||
import { useEarpieceAudioConfig } from "../MediaDevicesContext";
|
||||
import { useReactiveState } from "../useReactiveState";
|
||||
import * as controls from "../controls";
|
||||
import {} from "@livekit/components-core";
|
||||
|
||||
export interface MatrixAudioRendererProps {
|
||||
/**
|
||||
* The service URL of the LiveKit room.
|
||||
@@ -32,13 +35,7 @@ export interface MatrixAudioRendererProps {
|
||||
* This list needs to be composed based on the matrixRTC members so that we do not play audio from users
|
||||
* that are not expected to be in the rtc session.
|
||||
*/
|
||||
// TODO: Why do we have this structure? looks like we only need the valid/active participants (not the room member or id)?
|
||||
participants: {
|
||||
id: string;
|
||||
// TODO it appears to be optional as per InCallView? but what does that mean here? a rtc member not yet joined in livekit?
|
||||
participant: Participant | undefined;
|
||||
member: RoomMember;
|
||||
}[];
|
||||
participants: RemoteParticipant[];
|
||||
/**
|
||||
* If set to `true`, mutes all audio tracks rendered by the component.
|
||||
* @remarks
|
||||
@@ -48,8 +45,7 @@ export interface MatrixAudioRendererProps {
|
||||
}
|
||||
|
||||
/**
|
||||
* The `MatrixAudioRenderer` component is a drop-in solution for adding audio to your LiveKit app.
|
||||
* It takes care of handling remote participants’ audio tracks and makes sure that microphones and screen share are audible.
|
||||
* Takes care of handling remote participants’ audio tracks and makes sure that microphones and screen share are audible.
|
||||
*
|
||||
* It also takes care of the earpiece audio configuration for iOS devices.
|
||||
* This is done by using the WebAudio API to create a stereo pan effect that mimics the earpiece audio.
|
||||
@@ -70,12 +66,7 @@ export function LivekitRoomAudioRenderer({
|
||||
// This is the list of valid identities that are allowed to play audio.
|
||||
// It is derived from the list of matrix rtc members.
|
||||
const validIdentities = useMemo(
|
||||
() =>
|
||||
new Set(
|
||||
participants
|
||||
.filter(({ participant }) => participant) // filter out participants that are not yet joined in livekit
|
||||
.map(({ participant }) => participant!.identity),
|
||||
),
|
||||
() => new Set(participants.map((p) => p.identity)),
|
||||
[participants],
|
||||
);
|
||||
|
||||
@@ -92,7 +83,7 @@ export function LivekitRoomAudioRenderer({
|
||||
if (loggedInvalidIdentities.current.has(identity)) return;
|
||||
logger.warn(
|
||||
`[MatrixAudioRenderer] Audio track ${identity} from ${url} has no matching matrix call member`,
|
||||
`current members: ${participants.map((p) => p.participant?.identity)}`,
|
||||
`current members: ${participants.map((p) => p.identity)}`,
|
||||
`track will not get rendered`,
|
||||
);
|
||||
loggedInvalidIdentities.current.add(identity);
|
||||
|
||||
@@ -286,7 +286,7 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
);
|
||||
|
||||
const allLivekitRooms = useBehavior(vm.allLivekitRooms$);
|
||||
const participantsByRoom = useBehavior(vm.participantsByRoom$);
|
||||
const audioParticipants = useBehavior(vm.audioParticipants$);
|
||||
const participantCount = useBehavior(vm.participantCount$);
|
||||
const reconnecting = useBehavior(vm.reconnecting$);
|
||||
const windowMode = useBehavior(vm.windowMode$);
|
||||
@@ -860,7 +860,7 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
{participantsByRoom.map(({ livekitRoom, url, participants }) => (
|
||||
{audioParticipants.map(({ livekitRoom, url, participants }) => (
|
||||
<LivekitRoomAudioRenderer
|
||||
key={url}
|
||||
url={url}
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
type Room as LivekitRoom,
|
||||
type LocalParticipant,
|
||||
ParticipantEvent,
|
||||
type RemoteParticipant,
|
||||
RemoteParticipant,
|
||||
type Participant,
|
||||
} from "livekit-client";
|
||||
import E2EEWorker from "livekit-client/e2ee-worker?worker";
|
||||
@@ -793,7 +793,7 @@ export class CallViewModel extends ViewModel {
|
||||
* Lists, for each LiveKit room, the LiveKit participants whose media should
|
||||
* be presented.
|
||||
*/
|
||||
public readonly participantsByRoom$ = this.scope.behavior<
|
||||
private readonly participantsByRoom$ = this.scope.behavior<
|
||||
{
|
||||
livekitRoom: LivekitRoom;
|
||||
url: string;
|
||||
@@ -861,6 +861,25 @@ export class CallViewModel extends ViewModel {
|
||||
.pipe(startWith([]), pauseWhen(this.pretendToBeDisconnected$)),
|
||||
);
|
||||
|
||||
/**
|
||||
* Lists, for each LiveKit room, the LiveKit participants whose audio should
|
||||
* be rendered.
|
||||
*/
|
||||
// (This is effectively just participantsByRoom$ with a stricter type)
|
||||
public readonly audioParticipants$ = this.scope.behavior(
|
||||
this.participantsByRoom$.pipe(
|
||||
map((data) =>
|
||||
data.map(({ livekitRoom, url, participants }) => ({
|
||||
livekitRoom,
|
||||
url,
|
||||
participants: participants.flatMap(({ participant }) =>
|
||||
participant instanceof RemoteParticipant ? [participant] : [],
|
||||
),
|
||||
})),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Displaynames for each member of the call. This will disambiguate
|
||||
* any displaynames that clashes with another member. Only members
|
||||
|
||||
Reference in New Issue
Block a user