Skip to content

Commit 5374342

Browse files
toger5robintown
andauthored
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>
1 parent 0971a15 commit 5374342

File tree

4 files changed

+32
-12
lines changed

4 files changed

+32
-12
lines changed

src/livekit/useLivekit.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
} from "./TrackProcessorContext";
4343
import { useInitial } from "../useInitial";
4444
import { observeTrackReference$ } from "../state/MediaViewModel";
45+
import { useUrlParams } from "../UrlParams";
4546

4647
interface UseLivekitResult {
4748
livekitRoom?: Room;
@@ -54,6 +55,8 @@ export function useLivekit(
5455
sfuConfig: SFUConfig | undefined,
5556
e2eeSystem: EncryptionSystem,
5657
): UseLivekitResult {
58+
const { controlledAudioDevices } = useUrlParams();
59+
5760
const e2eeOptions = useMemo((): E2EEManagerOptions | undefined => {
5861
if (e2eeSystem.kind === E2eeType.NONE) return undefined;
5962

@@ -303,7 +306,11 @@ export function useLivekit(
303306

304307
useEffect(() => {
305308
// Sync the requested devices with LiveKit's devices
306-
if (room !== undefined && connectionState === ConnectionState.Connected) {
309+
if (
310+
room !== undefined &&
311+
connectionState === ConnectionState.Connected &&
312+
!controlledAudioDevices
313+
) {
307314
const syncDevice = (
308315
kind: MediaDeviceKind,
309316
device: MediaDeviceHandle,
@@ -363,7 +370,7 @@ export function useLivekit(
363370
syncDevice("audiooutput", devices.audioOutput);
364371
syncDevice("videoinput", devices.videoInput);
365372
}
366-
}, [room, devices, connectionState]);
373+
}, [room, devices, connectionState, controlledAudioDevices]);
367374

368375
return {
369376
connState: connectionState,

src/useAudioContext.test.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { expect, vi, afterEach, beforeEach, test } from "vitest";
99
import { type FC } from "react";
1010
import { render } from "@testing-library/react";
1111
import userEvent, { type UserEvent } from "@testing-library/user-event";
12+
import { BrowserRouter } from "react-router-dom";
1213

1314
import { deviceStub, MediaDevicesContext } from "./livekit/MediaDevicesContext";
1415
import { useAudioContext } from "./useAudioContext";
@@ -38,6 +39,13 @@ const TestComponent: FC = () => {
3839
</>
3940
);
4041
};
42+
const TestComponentWrapper: FC = () => {
43+
return (
44+
<BrowserRouter>
45+
<TestComponent />
46+
</BrowserRouter>
47+
);
48+
};
4149

4250
const gainNode = vi.mocked(
4351
{
@@ -94,13 +102,13 @@ afterEach(() => {
94102
});
95103

96104
test("can play a single sound", async () => {
97-
const { findByText } = render(<TestComponent />);
105+
const { findByText } = render(<TestComponentWrapper />);
98106
await user.click(await findByText("Valid sound"));
99107
expect(testAudioContext.createBufferSource).toHaveBeenCalledOnce();
100108
});
101109

102110
test("will ignore sounds that are not registered", async () => {
103-
const { findByText } = render(<TestComponent />);
111+
const { findByText } = render(<TestComponentWrapper />);
104112
await user.click(await findByText("Invalid sound"));
105113
expect(testAudioContext.createBufferSource).not.toHaveBeenCalled();
106114
});
@@ -122,7 +130,7 @@ test("will use the correct device", () => {
122130
stopUsingDeviceNames: () => {},
123131
}}
124132
>
125-
<TestComponent />
133+
<TestComponentWrapper />
126134
</MediaDevicesContext.Provider>,
127135
);
128136
expect(testAudioContext.createBufferSource).not.toHaveBeenCalled();
@@ -131,7 +139,7 @@ test("will use the correct device", () => {
131139

132140
test("will use the correct volume level", async () => {
133141
soundEffectVolumeSetting.setValue(0.33);
134-
const { findByText } = render(<TestComponent />);
142+
const { findByText } = render(<TestComponentWrapper />);
135143
await user.click(await findByText("Valid sound"));
136144
expect(testAudioContext.gain.gain.setValueAtTime).toHaveBeenCalledWith(
137145
0.33,
@@ -157,7 +165,7 @@ test("will use the pan if earpiece is selected", async () => {
157165
stopUsingDeviceNames: () => {},
158166
}}
159167
>
160-
<TestComponent />
168+
<TestComponentWrapper />
161169
</MediaDevicesContext.Provider>,
162170
);
163171
await user.click(await findByText("Valid sound"));

src/useAudioContext.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
useMediaDevices,
1818
} from "./livekit/MediaDevicesContext";
1919
import { type PrefetchedSounds } from "./soundUtils";
20+
import { useUrlParams } from "./UrlParams";
2021

2122
/**
2223
* Play a sound though a given AudioContext. Will take
@@ -71,7 +72,7 @@ export function useAudioContext<S extends string>(
7172
): UseAudioContext<S> | null {
7273
const [soundEffectVolume] = useSetting(soundEffectVolumeSetting);
7374
const { audioOutput } = useMediaDevices();
74-
75+
const { controlledAudioDevices } = useUrlParams();
7576
const [audioContext, setAudioContext] = useState<AudioContext>();
7677
const [audioBuffers, setAudioBuffers] = useState<Record<S, AudioBuffer>>();
7778

@@ -110,14 +111,18 @@ export function useAudioContext<S extends string>(
110111

111112
// Update the sink ID whenever we change devices.
112113
useEffect(() => {
113-
if (audioContext && "setSinkId" in audioContext) {
114+
if (
115+
audioContext &&
116+
"setSinkId" in audioContext &&
117+
!controlledAudioDevices
118+
) {
114119
// https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/setSinkId
115120
// @ts-expect-error - setSinkId doesn't exist yet in types, maybe because it's not supported everywhere.
116121
audioContext.setSinkId(audioOutput.selectedId).catch((ex) => {
117122
logger.warn("Unable to change sink for audio context", ex);
118123
});
119124
}
120-
}, [audioContext, audioOutput.selectedId]);
125+
}, [audioContext, audioOutput.selectedId, controlledAudioDevices]);
121126
const { pan: earpiecePan, volume: earpieceVolume } = useEarpieceAudioConfig();
122127

123128
// Don't return a function until we're ready.

yarn.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9612,7 +9612,7 @@ __metadata:
96129612

96139613
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#head=develop":
96149614
version: 37.6.0
9615-
resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=93982716951ce2583904bfc26b27d6a86ba17a87"
9615+
resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=bf6dc16ad32d47f2c6e167236f4c853ceef01d4f"
96169616
dependencies:
96179617
"@babel/runtime": "npm:^7.12.5"
96189618
"@matrix-org/matrix-sdk-crypto-wasm": "npm:^14.2.0"
@@ -9629,7 +9629,7 @@ __metadata:
96299629
sdp-transform: "npm:^2.14.1"
96309630
unhomoglyph: "npm:^1.0.6"
96319631
uuid: "npm:11"
9632-
checksum: 10c0/22a28099d2deaf0ca7f609a5859fe00fbd20c314d3b607a95b4a623a8aa159e428310b1849c77ab7b9875a29fc2d924cddbb6fc83dc4e42a74c4713401dcb0be
9632+
checksum: 10c0/2877e7c5b2779200b48f3152bb7b510e58899b1e779e7e6d2bc1a236ed178fa8858f0547b644a2029f48f55dc7cc3954f48e2598c8963d45293c8280ccc23039
96339633
languageName: node
96349634
linkType: hard
96359635

0 commit comments

Comments
 (0)