Skip to content

feat(linux): native PipeWire/PulseAudio system-audio capture - #708

Open
loicfavory wants to merge 2 commits into
Zackriya-Solutions:mainfrom
loicfavory:feat/linux-native-pulse-system-audio
Open

feat(linux): native PipeWire/PulseAudio system-audio capture#708
loicfavory wants to merge 2 commits into
Zackriya-Solutions:mainfrom
loicfavory:feat/linux-native-pulse-system-audio

Conversation

@loicfavory

@loicfavory loicfavory commented Aug 12, 2026

Copy link
Copy Markdown

Description

Replaces the ALSA monitor-hint hack for Linux "System Audio" capture with a native PipeWire/PulseAudio client, and fixes a heap-corruption crash in the ALSA device-enumeration path that this branch still shares with the rest of the app.

Why the hack needed replacing: cpal has no native PulseAudio/PipeWire backend on Linux — only ALSA/JACK. Capturing system audio therefore only worked if a monitor source was hand-registered as a named ALSA pseudo-device in ~/.asoundrc (type pulse, a hint { show on } block, and a device name containing "monitor" since that's what configure_linux_audio() filtered on). On a stock install with no such setup, the System Audio list is simply empty. #701 covers this in detail, and #702 (still open) fixes a related bug in that same ALSA-hack path — this PR bypasses that path entirely for System Audio rather than patching it further.

The crash: list_audio_devices() is polled every 2-5s by the device disconnect/reconnect monitor for the whole duration of a recording, and can also be triggered from the UI or recording_manager at any time. alsa-lib's snd_device_name_hint/snd_config_update_r mutate a process-global config cache and are not safe to call concurrently — an overlapping call from a second Tokio worker thread was corrupting alsa-lib's heap state, which glibc eventually detected and aborted on. This produced SIGABRT crashes ~30-35 minutes into a recording (reproduced with two coredumps, both inside alsa-lib/malloc, both after that consistent delay).

Related Issue

Fixes #701, #273, #383 — all three are the same underlying problem (Linux "System Audio" not capturing anything, via the ALSA monitor-hint hack), reported independently over the past few months:

Also related:

Type of Change

  • Bug fix
  • New feature

Fix

  • New module audio/capture/pulse_linux.rs (#[cfg(target_os = "linux")]), structured as the Linux sibling of the existing macOS capture/core_audio.rs: talks to the PulseAudio client protocol directly via libpulse-binding/libpulse-simple-binding, which PipeWire also implements (pipewire-pulse). Lists real sink names/descriptions and opens a record stream on a sink's monitor source — no ~/.asoundrc needed on either PipeWire or classic PulseAudio.
  • audio/stream.rs: Linux System Audio always routes through this native Pulse backend now, wired in the same way as macOS's Core Audio branch.
  • audio/devices/platform/linux.rs and audio/devices/speakers.rs: System Audio device listing/default resolution now come from the real Pulse sink list instead of the ALSA "monitor" name heuristic.
  • Microphone capture is untouched — still cpal/ALSA, out of scope here.
  • audio/devices/discovery.rs and audio/devices/platform/linux.rs: added a process-wide Mutex (ALSA_ENUM_LOCK) serializing every remaining ALSA-touching enumeration call, to stop the concurrent-access heap corruption described above.

Testing

  • Manual testing performed

  • All tests pass

  • cargo check and cargo build --release succeed (Arch Linux, PipeWire 1.6.8, KDE Plasma / Wayland).

  • Fresh state, zero ~/.asoundrc customization: Settings → System Audio lists real sink names out of the box.

  • Recorded while playing audio; confirmed the output file's system-audio track is non-silent (ffmpeg -i recording.mp4 -af volumedetect -f null -).

  • Switched outputs (different sink) mid-session and saw the new device picked up without an app restart.

  • Ran a recording past the ~30-35 minute mark that reliably triggered the pre-fix SIGABRT — no crash with the ALSA_ENUM_LOCK change.

No automated tests added for pulse_linux.rs beyond two #[ignore]d manual tests (test_list_sinks, test_capture_reads_nonzero_samples) — both require a live PipeWire/PulseAudio server and real audio playback, so they're not meant to run in CI.

Documentation

  • No documentation needed

No user-facing docs affected. Module-level comments in pulse_linux.rs and on ALSA_ENUM_LOCK explain the approach and the concurrency hazard being fixed, respectively.

Checklist

  • Code follows project style (mirrors the existing macOS Core Audio native-capture pattern)
  • Self-reviewed the code
  • Branch is up to date with main
  • No merge conflicts

Additional Notes

Once this lands, the ALSA "monitor"-hint enumeration path for System Audio on Linux is effectively dead code (Microphone capture still needs the rest of configure_linux_audio()). Left it in place — removing it is a separate cleanup, not folded into this PR.

Replace the ALSA monitor-hint hack (manual ~/.asoundrc entry with a
"monitor" substring) with a native libpulse client for system-audio
capture on Linux. System Audio entries now list real PulseAudio/
PipeWire sinks directly, and streaming goes through a dedicated Pulse
backend instead of cpal's ALSA host, which has no native Pulse/PipeWire
support and required per-machine manual setup to work at all.
…tion

alsa-lib's snd_device_name_hint/snd_config_update_r mutate a
process-global config cache and are not safe to call concurrently.
list_audio_devices() is polled every 2-5s by the device disconnect/
reconnect monitor for the whole duration of a recording, and can
also be triggered from the UI or recording_manager at any time; an
overlapping call from a second Tokio worker thread corrupts alsa-lib's
heap state, which glibc eventually detects and aborts on. This is what
produced the SIGABRT crashes ~30-35 minutes into a recording (two
coredumps, both inside alsa-lib/malloc, both after that consistent
delay). A process-wide mutex now serializes every ALSA-touching
enumeration call.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Linux: System Audio device is never resolved at recording start — system audio silently missing

1 participant