3.3 KiB
Context
The recording pipeline already depends on IMeetingAudioSource and composes independent microphone and system streams through CompositeMeetingAudioSource. Windows supplies those streams with NAudio behind the WINDOWS compilation boundary. The portable target currently supplies an unavailable source on every non-Windows host.
.NET does not ship ScreenCaptureKit or AVFoundation bindings. A small native process is therefore the narrowest reliable adapter between Apple's capture frameworks and the existing managed PCM stream contract.
Goals / Non-Goals
Goals:
- Capture the default macOS microphone and computer output without a virtual audio device.
- Emit the configured sample rate/channel count as signed 16-bit PCM.
- Reuse the existing managed alignment, AEC, gain, mixing, WAV, and transcription path.
- Keep Windows source files, registrations, packages, and runtime behavior unchanged.
- Fail with actionable privacy-permission or helper-packaging diagnostics.
Non-Goals:
- Add a macOS tray icon, global hotkeys, Outlook metadata, notifications, or screenshots.
- Add runtime macOS microphone selection in this change.
- Replace or refactor the Windows NAudio implementation.
- Commit long-lived user meeting audio; the proof WAV is a short implementation artifact only.
Decisions
Reuse the existing composite source
macOS registers separate microphone and system IMeetingAudioSource adapters and feeds them to CompositeMeetingAudioSource. This preserves the established audio semantics and keeps platform code limited to capture and PCM conversion.
Use one native helper with two modes
The bundled Swift helper accepts microphone or system, plus sample rate and channel count, and writes headerless signed 16-bit PCM to standard output. AVFoundation supplies microphone buffers. ScreenCaptureKit supplies system-audio buffers. AVAudioConverter normalizes both sources before managed code reads them.
The managed adapter owns process lifetime, reads PCM chunks asynchronously, terminates the helper when capture is cancelled, and surfaces native diagnostics when the helper exits unexpectedly.
Build the helper only on macOS
The Swift source is portable content, but compilation is conditioned on the build host being macOS. macOS build and publish output receives the executable under Native. Windows compilation remains within its existing WINDOWS branch and does not compile or invoke Swift code.
Keep unsupported-host behavior
The portable target chooses macOS capture with a runtime OS check. Linux and other hosts continue resolving UnavailableMeetingAudioSource with an updated host-neutral error.
Risks / Trade-offs
- [macOS privacy controls can initially deny or pause capture] → Request microphone authorization and report explicit Screen Recording/System Audio or Microphone guidance on stderr.
- [A helper process adds a packaging boundary] → Make the build fail on macOS if Swift compilation fails and verify the helper exists in build and publish output.
- [Native audio buffer formats vary] → Convert the CoreMedia/AVFoundation buffers with
AVAudioConverterto the exact requested PCM format before writing. - [Windows regressions from shared startup edits] → Leave the
#if WINDOWSbranch intact and build the Windows target in addition to portable tests.