@@ -18,7 +18,7 @@ import { useTracks } from "@livekit/components-react";
|
|||||||
|
|
||||||
import { testAudioContext } from "../useAudioContext.test";
|
import { testAudioContext } from "../useAudioContext.test";
|
||||||
import * as MediaDevicesContext from "../MediaDevicesContext";
|
import * as MediaDevicesContext from "../MediaDevicesContext";
|
||||||
import { MatrixAudioRenderer } from "./MatrixAudioRenderer";
|
import { LivekitRoomAudioRenderer } from "./MatrixAudioRenderer";
|
||||||
import { mockMediaDevices, mockTrack } from "../utils/test";
|
import { mockMediaDevices, mockTrack } from "../utils/test";
|
||||||
|
|
||||||
export const TestAudioContextConstructor = vi.fn(() => testAudioContext);
|
export const TestAudioContextConstructor = vi.fn(() => testAudioContext);
|
||||||
@@ -54,7 +54,7 @@ vi.mocked(useTracks).mockReturnValue(tracks);
|
|||||||
it("should render for member", () => {
|
it("should render for member", () => {
|
||||||
const { container, queryAllByTestId } = render(
|
const { container, queryAllByTestId } = render(
|
||||||
<MediaDevicesProvider value={mockMediaDevices({})}>
|
<MediaDevicesProvider value={mockMediaDevices({})}>
|
||||||
<MatrixAudioRenderer
|
<LivekitRoomAudioRenderer
|
||||||
members={[{ sender: "test", deviceId: "123" }] as CallMembership[]}
|
members={[{ sender: "test", deviceId: "123" }] as CallMembership[]}
|
||||||
/>
|
/>
|
||||||
</MediaDevicesProvider>,
|
</MediaDevicesProvider>,
|
||||||
@@ -69,7 +69,7 @@ it("should not render without member", () => {
|
|||||||
] as CallMembership[];
|
] as CallMembership[];
|
||||||
const { container, queryAllByTestId } = render(
|
const { container, queryAllByTestId } = render(
|
||||||
<MediaDevicesProvider value={mockMediaDevices({})}>
|
<MediaDevicesProvider value={mockMediaDevices({})}>
|
||||||
<MatrixAudioRenderer members={memberships} />
|
<LivekitRoomAudioRenderer members={memberships} />
|
||||||
</MediaDevicesProvider>,
|
</MediaDevicesProvider>,
|
||||||
);
|
);
|
||||||
expect(container).toBeTruthy();
|
expect(container).toBeTruthy();
|
||||||
@@ -79,7 +79,7 @@ it("should not render without member", () => {
|
|||||||
it("should not setup audioContext gain and pan if there is no need to.", () => {
|
it("should not setup audioContext gain and pan if there is no need to.", () => {
|
||||||
render(
|
render(
|
||||||
<MediaDevicesProvider value={mockMediaDevices({})}>
|
<MediaDevicesProvider value={mockMediaDevices({})}>
|
||||||
<MatrixAudioRenderer
|
<LivekitRoomAudioRenderer
|
||||||
members={[{ sender: "test", deviceId: "123" }] as CallMembership[]}
|
members={[{ sender: "test", deviceId: "123" }] as CallMembership[]}
|
||||||
/>
|
/>
|
||||||
</MediaDevicesProvider>,
|
</MediaDevicesProvider>,
|
||||||
@@ -102,7 +102,7 @@ it("should setup audioContext gain and pan", () => {
|
|||||||
});
|
});
|
||||||
render(
|
render(
|
||||||
<MediaDevicesProvider value={mockMediaDevices({})}>
|
<MediaDevicesProvider value={mockMediaDevices({})}>
|
||||||
<MatrixAudioRenderer
|
<LivekitRoomAudioRenderer
|
||||||
members={[{ sender: "test", deviceId: "123" }] as CallMembership[]}
|
members={[{ sender: "test", deviceId: "123" }] as CallMembership[]}
|
||||||
/>
|
/>
|
||||||
</MediaDevicesProvider>,
|
</MediaDevicesProvider>,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ Please see LICENSE in the repository root for full details.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { getTrackReferenceId } from "@livekit/components-core";
|
import { getTrackReferenceId } from "@livekit/components-core";
|
||||||
|
import { type Room as LivekitRoom } from "livekit-client";
|
||||||
import { type RemoteAudioTrack, Track } from "livekit-client";
|
import { type RemoteAudioTrack, Track } from "livekit-client";
|
||||||
import { useEffect, useMemo, useRef, useState, type ReactNode } from "react";
|
import { useEffect, useMemo, useRef, useState, type ReactNode } from "react";
|
||||||
import {
|
import {
|
||||||
@@ -19,7 +20,7 @@ import { logger } from "matrix-js-sdk/lib/logger";
|
|||||||
import { useEarpieceAudioConfig } from "../MediaDevicesContext";
|
import { useEarpieceAudioConfig } from "../MediaDevicesContext";
|
||||||
import { useReactiveState } from "../useReactiveState";
|
import { useReactiveState } from "../useReactiveState";
|
||||||
import * as controls from "../controls";
|
import * as controls from "../controls";
|
||||||
|
import {} from "@livekit/components-core";
|
||||||
export interface MatrixAudioRendererProps {
|
export interface MatrixAudioRendererProps {
|
||||||
/**
|
/**
|
||||||
* The list of participants to render audio for.
|
* The list of participants to render audio for.
|
||||||
@@ -27,6 +28,7 @@ export interface MatrixAudioRendererProps {
|
|||||||
* that are not expected to be in the rtc session.
|
* that are not expected to be in the rtc session.
|
||||||
*/
|
*/
|
||||||
members: CallMembership[];
|
members: CallMembership[];
|
||||||
|
livekitRoom: LivekitRoom;
|
||||||
/**
|
/**
|
||||||
* If set to `true`, mutes all audio tracks rendered by the component.
|
* If set to `true`, mutes all audio tracks rendered by the component.
|
||||||
* @remarks
|
* @remarks
|
||||||
@@ -49,9 +51,10 @@ export interface MatrixAudioRendererProps {
|
|||||||
* ```
|
* ```
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export function MatrixAudioRenderer({
|
export function LivekitRoomAudioRenderer({
|
||||||
members,
|
members,
|
||||||
muted,
|
muted,
|
||||||
|
livekitRoom,
|
||||||
}: MatrixAudioRendererProps): ReactNode {
|
}: MatrixAudioRendererProps): ReactNode {
|
||||||
const validIdentities = useMemo(
|
const validIdentities = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@@ -89,6 +92,7 @@ export function MatrixAudioRenderer({
|
|||||||
{
|
{
|
||||||
updateOnlyOn: [],
|
updateOnlyOn: [],
|
||||||
onlySubscribed: true,
|
onlySubscribed: true,
|
||||||
|
room: livekitRoom,
|
||||||
},
|
},
|
||||||
).filter((ref) => {
|
).filter((ref) => {
|
||||||
const isValid = validIdentities?.has(ref.participant.identity);
|
const isValid = validIdentities?.has(ref.participant.identity);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import {
|
|||||||
} from "../settings/settings";
|
} from "../settings/settings";
|
||||||
import { ReactionsSenderProvider } from "../reactions/useReactionsSender";
|
import { ReactionsSenderProvider } from "../reactions/useReactionsSender";
|
||||||
import { useRoomEncryptionSystem } from "../e2ee/sharedKeyManagement";
|
import { useRoomEncryptionSystem } from "../e2ee/sharedKeyManagement";
|
||||||
import { MatrixAudioRenderer } from "../livekit/MatrixAudioRenderer";
|
import { LivekitRoomAudioRenderer } from "../livekit/MatrixAudioRenderer";
|
||||||
import { MediaDevicesContext } from "../MediaDevicesContext";
|
import { MediaDevicesContext } from "../MediaDevicesContext";
|
||||||
import { HeaderStyle } from "../UrlParams";
|
import { HeaderStyle } from "../UrlParams";
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ beforeEach(() => {
|
|||||||
|
|
||||||
// MatrixAudioRenderer is tested separately.
|
// MatrixAudioRenderer is tested separately.
|
||||||
(
|
(
|
||||||
MatrixAudioRenderer as MockedFunction<typeof MatrixAudioRenderer>
|
LivekitRoomAudioRenderer as MockedFunction<typeof LivekitRoomAudioRenderer>
|
||||||
).mockImplementation((_props) => {
|
).mockImplementation((_props) => {
|
||||||
return <div>mocked: MatrixAudioRenderer</div>;
|
return <div>mocked: MatrixAudioRenderer</div>;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ import {
|
|||||||
} from "../settings/settings";
|
} from "../settings/settings";
|
||||||
import { ReactionsReader } from "../reactions/ReactionsReader";
|
import { ReactionsReader } from "../reactions/ReactionsReader";
|
||||||
import { useTypedEventEmitter } from "../useEvents.ts";
|
import { useTypedEventEmitter } from "../useEvents.ts";
|
||||||
|
import { LivekitRoomAudioRenderer } from "../livekit/MatrixAudioRenderer.tsx";
|
||||||
import { muteAllAudio$ } from "../state/MuteAllAudioModel.ts";
|
import { muteAllAudio$ } from "../state/MuteAllAudioModel.ts";
|
||||||
import { useMediaDevices } from "../MediaDevicesContext.ts";
|
import { useMediaDevices } from "../MediaDevicesContext.ts";
|
||||||
import { EarpieceOverlay } from "./EarpieceOverlay.tsx";
|
import { EarpieceOverlay } from "./EarpieceOverlay.tsx";
|
||||||
@@ -151,7 +152,6 @@ export const ActiveCall: FC<ActiveCallProps> = (props) => {
|
|||||||
},
|
},
|
||||||
reactionsReader.raisedHands$,
|
reactionsReader.raisedHands$,
|
||||||
reactionsReader.reactions$,
|
reactionsReader.reactions$,
|
||||||
props.e2eeSystem,
|
|
||||||
);
|
);
|
||||||
setVm(vm);
|
setVm(vm);
|
||||||
return (): void => {
|
return (): void => {
|
||||||
@@ -746,6 +746,8 @@ export const InCallView: FC<InCallViewProps> = ({
|
|||||||
matrixRoom.roomId,
|
matrixRoom.roomId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const allLivekitRooms = useBehavior(vm.allLivekitRooms$);
|
||||||
|
const memberships = useBehavior(vm.memberships$);
|
||||||
const toggleScreensharing = useCallback(() => {
|
const toggleScreensharing = useCallback(() => {
|
||||||
throw new Error("TODO-MULTI-SFU");
|
throw new Error("TODO-MULTI-SFU");
|
||||||
// localParticipant
|
// localParticipant
|
||||||
@@ -878,7 +880,14 @@ export const InCallView: FC<InCallViewProps> = ({
|
|||||||
</Text>
|
</Text>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{/* TODO-MULTI-SFU: <MatrixAudioRenderer members={memberships} muted={muteAllAudio} /> */}
|
{allLivekitRooms.map((roomItem) => (
|
||||||
|
<LivekitRoomAudioRenderer
|
||||||
|
key={roomItem.url}
|
||||||
|
livekitRoom={roomItem.room}
|
||||||
|
members={memberships}
|
||||||
|
muted={muteAllAudio}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
{renderContent()}
|
{renderContent()}
|
||||||
<CallEventAudioRenderer vm={vm} muted={muteAllAudio} />
|
<CallEventAudioRenderer vm={vm} muted={muteAllAudio} />
|
||||||
<ReactionsAudioRenderer vm={vm} muted={muteAllAudio} />
|
<ReactionsAudioRenderer vm={vm} muted={muteAllAudio} />
|
||||||
|
|||||||
@@ -116,7 +116,6 @@ import { type Behavior } from "./Behavior";
|
|||||||
import {
|
import {
|
||||||
enterRTCSession,
|
enterRTCSession,
|
||||||
getLivekitAlias,
|
getLivekitAlias,
|
||||||
leaveRTCSession,
|
|
||||||
makeFocus,
|
makeFocus,
|
||||||
} from "../rtcSessionHelpers";
|
} from "../rtcSessionHelpers";
|
||||||
import { E2eeType } from "../e2ee/e2eeType";
|
import { E2eeType } from "../e2ee/e2eeType";
|
||||||
@@ -462,7 +461,10 @@ export class CallViewModel extends ViewModel {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
private readonly memberships$ = this.scope.behavior(
|
// TODO-MULTI-SFU make sure that we consider the room memberships here as well (so that here we only have valid memberships)
|
||||||
|
// this also makes it possible to use this memberships$ list in all observables based on it.
|
||||||
|
// there should be no other call to: this.matrixRTCSession.memberships!
|
||||||
|
public readonly memberships$ = this.scope.behavior(
|
||||||
fromEvent(
|
fromEvent(
|
||||||
this.matrixRTCSession,
|
this.matrixRTCSession,
|
||||||
MatrixRTCSessionEvent.MembershipsChanged,
|
MatrixRTCSessionEvent.MembershipsChanged,
|
||||||
@@ -567,6 +569,26 @@ export class CallViewModel extends ViewModel {
|
|||||||
concatMap(({ stop }) => stop),
|
concatMap(({ stop }) => stop),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public readonly allLivekitRooms$ = this.scope.behavior(
|
||||||
|
combineLatest([
|
||||||
|
this.remoteConnections$,
|
||||||
|
this.localConnection,
|
||||||
|
this.localFocus,
|
||||||
|
]).pipe(
|
||||||
|
map(([remoteConnections, localConnection, localFocus]) =>
|
||||||
|
Array.from(remoteConnections.entries())
|
||||||
|
.map(([index, c]) => ({ room: c.livekitRoom, url: index }))
|
||||||
|
.concat([
|
||||||
|
{
|
||||||
|
room: localConnection.livekitRoom,
|
||||||
|
url: localFocus.livekit_service_url,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
startWith([]),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
private readonly userId = this.matrixRoom.client.getUserId();
|
private readonly userId = this.matrixRoom.client.getUserId();
|
||||||
|
|
||||||
private readonly matrixConnected$ = this.scope.behavior(
|
private readonly matrixConnected$ = this.scope.behavior(
|
||||||
|
|||||||
Reference in New Issue
Block a user