Disable device switching when in controlled audio devices mode (#3290)
* Disable device switching when in controlled audio devices mode * Temporarily switch matrix-js-sdk to robin/embedded-no-update-state To allow us to test this change on Element X, which does not yet support the update_state action. * Also add a check for controlled audio devices in useAudioContext * use develop branch * fix tests --------- Co-authored-by: Robin <robin@robin.town>
This commit is contained in:
@@ -42,6 +42,7 @@ import {
|
|||||||
} from "./TrackProcessorContext";
|
} from "./TrackProcessorContext";
|
||||||
import { useInitial } from "../useInitial";
|
import { useInitial } from "../useInitial";
|
||||||
import { observeTrackReference$ } from "../state/MediaViewModel";
|
import { observeTrackReference$ } from "../state/MediaViewModel";
|
||||||
|
import { useUrlParams } from "../UrlParams";
|
||||||
|
|
||||||
interface UseLivekitResult {
|
interface UseLivekitResult {
|
||||||
livekitRoom?: Room;
|
livekitRoom?: Room;
|
||||||
@@ -54,6 +55,8 @@ export function useLivekit(
|
|||||||
sfuConfig: SFUConfig | undefined,
|
sfuConfig: SFUConfig | undefined,
|
||||||
e2eeSystem: EncryptionSystem,
|
e2eeSystem: EncryptionSystem,
|
||||||
): UseLivekitResult {
|
): UseLivekitResult {
|
||||||
|
const { controlledAudioDevices } = useUrlParams();
|
||||||
|
|
||||||
const e2eeOptions = useMemo((): E2EEManagerOptions | undefined => {
|
const e2eeOptions = useMemo((): E2EEManagerOptions | undefined => {
|
||||||
if (e2eeSystem.kind === E2eeType.NONE) return undefined;
|
if (e2eeSystem.kind === E2eeType.NONE) return undefined;
|
||||||
|
|
||||||
@@ -303,7 +306,11 @@ export function useLivekit(
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Sync the requested devices with LiveKit's devices
|
// Sync the requested devices with LiveKit's devices
|
||||||
if (room !== undefined && connectionState === ConnectionState.Connected) {
|
if (
|
||||||
|
room !== undefined &&
|
||||||
|
connectionState === ConnectionState.Connected &&
|
||||||
|
!controlledAudioDevices
|
||||||
|
) {
|
||||||
const syncDevice = (
|
const syncDevice = (
|
||||||
kind: MediaDeviceKind,
|
kind: MediaDeviceKind,
|
||||||
device: MediaDeviceHandle,
|
device: MediaDeviceHandle,
|
||||||
@@ -363,7 +370,7 @@ export function useLivekit(
|
|||||||
syncDevice("audiooutput", devices.audioOutput);
|
syncDevice("audiooutput", devices.audioOutput);
|
||||||
syncDevice("videoinput", devices.videoInput);
|
syncDevice("videoinput", devices.videoInput);
|
||||||
}
|
}
|
||||||
}, [room, devices, connectionState]);
|
}, [room, devices, connectionState, controlledAudioDevices]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
connState: connectionState,
|
connState: connectionState,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { expect, vi, afterEach, beforeEach, test } from "vitest";
|
|||||||
import { type FC } from "react";
|
import { type FC } from "react";
|
||||||
import { render } from "@testing-library/react";
|
import { render } from "@testing-library/react";
|
||||||
import userEvent, { type UserEvent } from "@testing-library/user-event";
|
import userEvent, { type UserEvent } from "@testing-library/user-event";
|
||||||
|
import { BrowserRouter } from "react-router-dom";
|
||||||
|
|
||||||
import { deviceStub, MediaDevicesContext } from "./livekit/MediaDevicesContext";
|
import { deviceStub, MediaDevicesContext } from "./livekit/MediaDevicesContext";
|
||||||
import { useAudioContext } from "./useAudioContext";
|
import { useAudioContext } from "./useAudioContext";
|
||||||
@@ -38,6 +39,13 @@ const TestComponent: FC = () => {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
const TestComponentWrapper: FC = () => {
|
||||||
|
return (
|
||||||
|
<BrowserRouter>
|
||||||
|
<TestComponent />
|
||||||
|
</BrowserRouter>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const gainNode = vi.mocked(
|
const gainNode = vi.mocked(
|
||||||
{
|
{
|
||||||
@@ -94,13 +102,13 @@ afterEach(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("can play a single sound", async () => {
|
test("can play a single sound", async () => {
|
||||||
const { findByText } = render(<TestComponent />);
|
const { findByText } = render(<TestComponentWrapper />);
|
||||||
await user.click(await findByText("Valid sound"));
|
await user.click(await findByText("Valid sound"));
|
||||||
expect(testAudioContext.createBufferSource).toHaveBeenCalledOnce();
|
expect(testAudioContext.createBufferSource).toHaveBeenCalledOnce();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("will ignore sounds that are not registered", async () => {
|
test("will ignore sounds that are not registered", async () => {
|
||||||
const { findByText } = render(<TestComponent />);
|
const { findByText } = render(<TestComponentWrapper />);
|
||||||
await user.click(await findByText("Invalid sound"));
|
await user.click(await findByText("Invalid sound"));
|
||||||
expect(testAudioContext.createBufferSource).not.toHaveBeenCalled();
|
expect(testAudioContext.createBufferSource).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
@@ -122,7 +130,7 @@ test("will use the correct device", () => {
|
|||||||
stopUsingDeviceNames: () => {},
|
stopUsingDeviceNames: () => {},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TestComponent />
|
<TestComponentWrapper />
|
||||||
</MediaDevicesContext.Provider>,
|
</MediaDevicesContext.Provider>,
|
||||||
);
|
);
|
||||||
expect(testAudioContext.createBufferSource).not.toHaveBeenCalled();
|
expect(testAudioContext.createBufferSource).not.toHaveBeenCalled();
|
||||||
@@ -131,7 +139,7 @@ test("will use the correct device", () => {
|
|||||||
|
|
||||||
test("will use the correct volume level", async () => {
|
test("will use the correct volume level", async () => {
|
||||||
soundEffectVolumeSetting.setValue(0.33);
|
soundEffectVolumeSetting.setValue(0.33);
|
||||||
const { findByText } = render(<TestComponent />);
|
const { findByText } = render(<TestComponentWrapper />);
|
||||||
await user.click(await findByText("Valid sound"));
|
await user.click(await findByText("Valid sound"));
|
||||||
expect(testAudioContext.gain.gain.setValueAtTime).toHaveBeenCalledWith(
|
expect(testAudioContext.gain.gain.setValueAtTime).toHaveBeenCalledWith(
|
||||||
0.33,
|
0.33,
|
||||||
@@ -157,7 +165,7 @@ test("will use the pan if earpiece is selected", async () => {
|
|||||||
stopUsingDeviceNames: () => {},
|
stopUsingDeviceNames: () => {},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TestComponent />
|
<TestComponentWrapper />
|
||||||
</MediaDevicesContext.Provider>,
|
</MediaDevicesContext.Provider>,
|
||||||
);
|
);
|
||||||
await user.click(await findByText("Valid sound"));
|
await user.click(await findByText("Valid sound"));
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
useMediaDevices,
|
useMediaDevices,
|
||||||
} from "./livekit/MediaDevicesContext";
|
} from "./livekit/MediaDevicesContext";
|
||||||
import { type PrefetchedSounds } from "./soundUtils";
|
import { type PrefetchedSounds } from "./soundUtils";
|
||||||
|
import { useUrlParams } from "./UrlParams";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Play a sound though a given AudioContext. Will take
|
* Play a sound though a given AudioContext. Will take
|
||||||
@@ -71,7 +72,7 @@ export function useAudioContext<S extends string>(
|
|||||||
): UseAudioContext<S> | null {
|
): UseAudioContext<S> | null {
|
||||||
const [soundEffectVolume] = useSetting(soundEffectVolumeSetting);
|
const [soundEffectVolume] = useSetting(soundEffectVolumeSetting);
|
||||||
const { audioOutput } = useMediaDevices();
|
const { audioOutput } = useMediaDevices();
|
||||||
|
const { controlledAudioDevices } = useUrlParams();
|
||||||
const [audioContext, setAudioContext] = useState<AudioContext>();
|
const [audioContext, setAudioContext] = useState<AudioContext>();
|
||||||
const [audioBuffers, setAudioBuffers] = useState<Record<S, AudioBuffer>>();
|
const [audioBuffers, setAudioBuffers] = useState<Record<S, AudioBuffer>>();
|
||||||
|
|
||||||
@@ -110,14 +111,18 @@ export function useAudioContext<S extends string>(
|
|||||||
|
|
||||||
// Update the sink ID whenever we change devices.
|
// Update the sink ID whenever we change devices.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (audioContext && "setSinkId" in audioContext) {
|
if (
|
||||||
|
audioContext &&
|
||||||
|
"setSinkId" in audioContext &&
|
||||||
|
!controlledAudioDevices
|
||||||
|
) {
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/setSinkId
|
// https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/setSinkId
|
||||||
// @ts-expect-error - setSinkId doesn't exist yet in types, maybe because it's not supported everywhere.
|
// @ts-expect-error - setSinkId doesn't exist yet in types, maybe because it's not supported everywhere.
|
||||||
audioContext.setSinkId(audioOutput.selectedId).catch((ex) => {
|
audioContext.setSinkId(audioOutput.selectedId).catch((ex) => {
|
||||||
logger.warn("Unable to change sink for audio context", ex);
|
logger.warn("Unable to change sink for audio context", ex);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [audioContext, audioOutput.selectedId]);
|
}, [audioContext, audioOutput.selectedId, controlledAudioDevices]);
|
||||||
const { pan: earpiecePan, volume: earpieceVolume } = useEarpieceAudioConfig();
|
const { pan: earpiecePan, volume: earpieceVolume } = useEarpieceAudioConfig();
|
||||||
|
|
||||||
// Don't return a function until we're ready.
|
// Don't return a function until we're ready.
|
||||||
|
|||||||
@@ -9612,7 +9612,7 @@ __metadata:
|
|||||||
|
|
||||||
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#head=develop":
|
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#head=develop":
|
||||||
version: 37.6.0
|
version: 37.6.0
|
||||||
resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=93982716951ce2583904bfc26b27d6a86ba17a87"
|
resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=bf6dc16ad32d47f2c6e167236f4c853ceef01d4f"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime": "npm:^7.12.5"
|
"@babel/runtime": "npm:^7.12.5"
|
||||||
"@matrix-org/matrix-sdk-crypto-wasm": "npm:^14.2.0"
|
"@matrix-org/matrix-sdk-crypto-wasm": "npm:^14.2.0"
|
||||||
@@ -9629,7 +9629,7 @@ __metadata:
|
|||||||
sdp-transform: "npm:^2.14.1"
|
sdp-transform: "npm:^2.14.1"
|
||||||
unhomoglyph: "npm:^1.0.6"
|
unhomoglyph: "npm:^1.0.6"
|
||||||
uuid: "npm:11"
|
uuid: "npm:11"
|
||||||
checksum: 10c0/22a28099d2deaf0ca7f609a5859fe00fbd20c314d3b607a95b4a623a8aa159e428310b1849c77ab7b9875a29fc2d924cddbb6fc83dc4e42a74c4713401dcb0be
|
checksum: 10c0/2877e7c5b2779200b48f3152bb7b510e58899b1e779e7e6d2bc1a236ed178fa8858f0547b644a2029f48f55dc7cc3954f48e2598c8963d45293c8280ccc23039
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user