diff --git a/js/hang/src/publish/source/device.ts b/js/hang/src/publish/source/device.ts index acc607e35..0ce9a35d2 100644 --- a/js/hang/src/publish/source/device.ts +++ b/js/hang/src/publish/source/device.ts @@ -123,10 +123,19 @@ export class Device { // Manually request permission for the device, ignoring the result. requestPermission() { + if (this.permission.peek()) return; + navigator.mediaDevices .getUserMedia({ [this.kind]: true }) .then((stream) => { this.permission.set(true); + + // If the user selected a device during the dialog prompt, save it as the preferred device. + const deviceId = stream.getTracks().at(0)?.getSettings().deviceId; + if (deviceId) { + this.preferred.set(deviceId); + } + stream.getTracks().forEach((track) => { track.stop(); }); diff --git a/js/hang/src/publish/source/microphone.ts b/js/hang/src/publish/source/microphone.ts index 0ed7cd9e4..dc8d06ac4 100644 --- a/js/hang/src/publish/source/microphone.ts +++ b/js/hang/src/publish/source/microphone.ts @@ -36,7 +36,7 @@ export class Microphone { const constraints = effect.get(this.constraints) ?? {}; const finalConstraints: MediaTrackConstraints = { ...constraints, - deviceId: device ? { exact: device } : undefined, + deviceId: device !== undefined ? { exact: device } : undefined, }; effect.spawn(async (cancel) => { @@ -62,6 +62,11 @@ export class Microphone { const settings = track.getSettings(); + if (device === undefined) { + // Save the device that the user selected during the dialog prompt. + this.device.preferred.set(settings.deviceId); + } + effect.set(this.device.active, settings.deviceId); effect.set(this.stream, track); });