Search existing issues
Describe the bug
On macOS, the microphone selected inside OpenScreen has no effect on the recording — the app always captures whatever the OS default input device is.
What makes this confusing is that everything in the UI looks correct: the device picker shows my selection, and the level meter next to it reacts to my voice on the selected device. Only the finished recording reveals the problem.
I hit this with my MacBook closed (clamshell, external display). The OS default input is "MacBook Pro Microphone", which produces nothing while the lid is shut. So when I select my external microphone in OpenScreen and record, the resulting file has no audible audio at all — and with system audio turned off, no audio track whatsoever.
The counter-test confirms it: if I change the OS default input to another device, that device is what ends up in the recording, regardless of what I picked in OpenScreen.
Nothing in the app indicates that the selection was ignored. No warning, no toast, no log entry.
Expected behavior
The microphone selected in OpenScreen is the microphone that gets recorded.
If the app cannot honour that selection for any reason and falls back to the system default input, it should say so instead of failing silently — the current behaviour is indistinguishable from "the recording is just broken".
To Reproduce
- Connect an external microphone (I used a USB headset; any second input device works).
- In macOS System Settings > Sound > Input, set the default input to "MacBook Pro Microphone".
- Close the MacBook lid and work on an external display, so the built-in microphone picks up nothing.
- In OpenScreen, enable the microphone and select the external microphone in the device picker.
- Confirm the level meter next to the picker reacts to your voice — it does, on the correct device.
- Record a few seconds while speaking, then stop.
- Play the recording back: there is no audible audio. With system audio disabled, the file has no audio track at all.
Screenshots
No response
OS
macOS
OS Version
26.5.2 (25F84)
Other OS
No response
Browser
No response
Browser Version
No response
Other Browser
No response
Device Type
Laptop
Other Device
No response
Additional context
The root cause is in the macOS ScreenCaptureKit helper, in resolveMicrophoneCaptureDeviceID() (electron/native/screencapturekit/.../ScreenCaptureRecorder.swift).
It tries to resolve the requested device two ways, and both fail:
- It compares Chromium's MediaDeviceInfo.deviceId against AVCaptureDevice.uniqueID. Chromium's deviceId is an opaque per-origin HMAC, so this comparison can never match — it is effectively dead code.
- It compares the device name using strict string equality against AVCaptureDevice.localizedName. But the name usually never reaches the helper: RecordingPrefs (electron/ipc/handlers.ts) carries only micDeviceId and no micDeviceName, and those prefs are the only channel between the editor's Rec stage and the recorder HUD, which are separate renderer windows.
When both branches fail the function returns nil, the caller simply leaves microphoneCaptureDeviceID unset, and ScreenCaptureKit silently records the system default input. There is no warning event on this path.
That also explains why the level meter looks fine: on macOS the preview and the recording share no code. useAudioLevelMeter opens its own Chromium getUserMedia stream with deviceId: { exact: ... } and hits the right device; the recording goes entirely through the Swift helper.
Two secondary issues in the same area: AVCaptureDevice.devices(for: .audio) is deprecated and does not report aggregate/virtual/external devices, so some devices can never be resolved even by name; and helper "warning" events are never forwarded to the renderer (dispatchNativeMacHelperEvent only emits them internally, and the only consumers handle recording-started / recording-stopped / error), which is why the fallback is completely invisible.
For reference, the equivalent bug was already fixed on the other platforms: Linux matches on the label via resolve_microphone_node (fuzzy, with tests) in the PipeWire helper, and Windows has scoreNativeDeviceName(). macOS is the only platform still using strict equality.
Search existing issues
Describe the bug
On macOS, the microphone selected inside OpenScreen has no effect on the recording — the app always captures whatever the OS default input device is.
What makes this confusing is that everything in the UI looks correct: the device picker shows my selection, and the level meter next to it reacts to my voice on the selected device. Only the finished recording reveals the problem.
I hit this with my MacBook closed (clamshell, external display). The OS default input is "MacBook Pro Microphone", which produces nothing while the lid is shut. So when I select my external microphone in OpenScreen and record, the resulting file has no audible audio at all — and with system audio turned off, no audio track whatsoever.
The counter-test confirms it: if I change the OS default input to another device, that device is what ends up in the recording, regardless of what I picked in OpenScreen.
Nothing in the app indicates that the selection was ignored. No warning, no toast, no log entry.
Expected behavior
The microphone selected in OpenScreen is the microphone that gets recorded.
If the app cannot honour that selection for any reason and falls back to the system default input, it should say so instead of failing silently — the current behaviour is indistinguishable from "the recording is just broken".
To Reproduce
Screenshots
No response
OS
macOS
OS Version
26.5.2 (25F84)
Other OS
No response
Browser
No response
Browser Version
No response
Other Browser
No response
Device Type
Laptop
Other Device
No response
Additional context
The root cause is in the macOS ScreenCaptureKit helper, in resolveMicrophoneCaptureDeviceID() (electron/native/screencapturekit/.../ScreenCaptureRecorder.swift).
It tries to resolve the requested device two ways, and both fail:
When both branches fail the function returns nil, the caller simply leaves microphoneCaptureDeviceID unset, and ScreenCaptureKit silently records the system default input. There is no warning event on this path.
That also explains why the level meter looks fine: on macOS the preview and the recording share no code. useAudioLevelMeter opens its own Chromium getUserMedia stream with deviceId: { exact: ... } and hits the right device; the recording goes entirely through the Swift helper.
Two secondary issues in the same area: AVCaptureDevice.devices(for: .audio) is deprecated and does not report aggregate/virtual/external devices, so some devices can never be resolved even by name; and helper "warning" events are never forwarded to the renderer (dispatchNativeMacHelperEvent only emits them internally, and the only consumers handle recording-started / recording-stopped / error), which is why the fallback is completely invisible.
For reference, the equivalent bug was already fixed on the other platforms: Linux matches on the label via resolve_microphone_node (fuzzy, with tests) in the PipeWire helper, and Windows has scoreNativeDeviceName(). macOS is the only platform still using strict equality.