Fix #32727: Ensure VoiceRecording uses the selected microphone (#32887)

Voice messages were being recorded using the system default microphone
instead of the device selected in Element settings.

This was fixed by ensuring the preferred deviceId is correctly passed
to the MediaStream constraints in VoiceRecording.ts.

Added unit tests in VoiceRecording-test.ts to verify that the
application correctly requests the user-selected device.

Co-authored-by: Will Hunt <2072976+Half-Shot@users.noreply.github.com>
This commit is contained in:
Joao Pedro Antunes Borie 2026-04-09 12:07:32 +01:00 committed by GitHub
parent 52061d624b
commit 5ba09a5f90
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 28 additions and 1 deletions

View File

@ -103,10 +103,14 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
private async makeRecorder(): Promise<void> {
try {
const requestedDeviceId = MediaDeviceHandler.getAudioInput();
const deviceIdConstraint =
requestedDeviceId && requestedDeviceId !== "default" ? { deviceId: { exact: requestedDeviceId } } : {};
this.recorderStream = await navigator.mediaDevices.getUserMedia({
audio: {
channelCount: CHANNELS,
deviceId: MediaDeviceHandler.getAudioInput(),
...deviceIdConstraint,
autoGainControl: { ideal: MediaDeviceHandler.getAudioAutoGainControl() },
echoCancellation: { ideal: MediaDeviceHandler.getAudioEchoCancellation() },
noiseSuppression: { ideal: MediaDeviceHandler.getAudioNoiseSuppression() },

View File

@ -120,6 +120,29 @@ describe("VoiceRecording", () => {
}),
);
});
it("should request the selected microphone as an exact device constraint", async () => {
MediaDeviceHandlerMock.getAudioInput.mockReturnValue("selected-mic");
await recording.start();
expect(navigator.mediaDevices.getUserMedia).toHaveBeenCalledWith(
expect.objectContaining({
audio: expect.objectContaining({ deviceId: { exact: "selected-mic" } }),
}),
);
});
it("should not force an exact microphone when default device is selected", async () => {
MediaDeviceHandlerMock.getAudioInput.mockReturnValue("default");
await recording.start();
const constraints = mocked(navigator.mediaDevices.getUserMedia).mock.calls[0][0] as MediaStreamConstraints;
expect(constraints.audio).toEqual(
expect.not.objectContaining({
deviceId: expect.anything(),
}),
);
});
});
describe("when recording", () => {