AI-powered per-application noise suppression for PipeWire on Linux.
Broadcast routes your audio streams through DeepFilterNet to remove typing, keyboard, and background noise — with per-app control over which streams get filtered.
Think of it as NVIDIA Broadcast for Linux, but open source and running on any hardware.
- Per-app routing — choose which apps get noise filtering (e.g., filter browser audio but leave Spotify clean)
- Mic input filtering — remove typing/background noise from your microphone
- Output filtering — remove noise from audio you're listening to (YouTube, calls)
- CLI tool (
broadcast-ctl) — toggle, status, per-app routing from the terminal - GTK4 GUI (
broadcast-gui) — visual per-app toggle switches with live stream list - PipeWire native — uses filter chains, no JACK bridge needed
- Configurable — node names are user-configurable for custom filter chain setups
Coming soon
- PipeWire (with
pactl/ PulseAudio compatibility) - DeepFilterNet LADSPA plugin — provides the AI noise suppression
- Arch/CachyOS:
paru -S libdeep_filter_ladspa-git
- Arch/CachyOS:
- GTK4 + Libadwaita (for the GUI)
- gtk4-layer-shell (for the
--menupopup mode — already present on any system running Ironbar) - PipeWire filter chain configs (see examples/)
paru -S broadcast-bin # pre-built binaries
# or
paru -S broadcast-git # build from sourceDownload the .deb from the latest release:
# Install both packages
sudo dpkg -i broadcast-ctl_*.deb broadcast-gui_*.deb
sudo apt-get install -f # resolve any missing dependenciesDownload the .rpm from the latest release:
sudo rpm -i broadcast-ctl-*.rpm broadcast-gui-*.rpmgh release download --repo londospark/broadcast -p 'broadcast-ctl' -p 'broadcast-gui' --dir ~/.local/bin/
chmod +x ~/.local/bin/broadcast-ctl ~/.local/bin/broadcast-guigit clone https://github.com/londospark/broadcast.git
cd broadcast
cargo build --release
cp target/release/broadcast-ctl target/release/broadcast-gui ~/.local/bin/# Arch/CachyOS
paru -S libdeep_filter_ladspa-git ladspaCopy the example configs to your PipeWire config directory:
mkdir -p ~/.config/pipewire/pipewire.conf.d/
cp examples/50-deepfilter-input.conf ~/.config/pipewire/pipewire.conf.d/
cp examples/50-deepfilter-output.conf ~/.config/pipewire/pipewire.conf.d/
systemctl --user restart pipewirebroadcast-ctl status
# Should show: Filters: loadedbroadcast-ctl toggle # Toggle noise suppression on/off
broadcast-ctl on # Enable filtering
broadcast-ctl off # Disable filtering (passthrough)
broadcast-ctl status # Show current state
broadcast-ctl status --ironbar # Compact status for bar widgets
broadcast-ctl status --json # JSON output
broadcast-ctl apps # List running audio streams
broadcast-ctl route brave filtered # Route Brave through the filter
broadcast-ctl route spotify direct # Keep Spotify unfiltered
broadcast-ctl apply # Re-apply saved routing preferences
broadcast-ctl devices # List available audio devices
broadcast-ctl set-device output <name> # Set preferred output device
broadcast-ctl set-device input <name> # Set preferred input device
broadcast-ctl --version # Show versionbroadcast-gui # normal application window
broadcast-gui --menu # popup/flyout (no decorations, closes on focus loss)
broadcast-gui --menu --margin-top 48 --margin-right 10 # custom popup positionOn Omarchy, Broadcast ships as a native bar-widget plugin
(omarchy-plugin/io.github.londospark.broadcast/) instead of a floating popup —
a mic icon in the bar (green/red for filter health) opens a panel with the
master on/off switch, backend selector (DeepFilterNet/Maxine), GPU intensity
slider, health status with a one-click "Fix routing", output/input device
pickers, and per-app filtered/direct toggles.
bash scripts/install-omarchy-plugin.sh --enable --putRe-run that script after pulling changes to sync omarchy-plugin/ into
~/.config/omarchy/plugins/ (Omarchy's validator rejects symlinks inside a
plugin folder, so it's a real copy, not a live link).
Broadcast works well with Wayland status bars. The --menu flag opens the GUI as
an undecorated popup that closes automatically when it loses focus, giving a
flyout-style experience from the bar. You can tune its position with
--margin-top and --margin-right (defaults: 48 and 10).
[[end]]
type = "script"
name = "broadcast"
mode = "poll"
cmd = "broadcast-ctl status --ironbar"
interval = 2000
on_click_left = "broadcast-ctl toggle"
on_click_right = "broadcast-gui --menu --margin-top 48 --margin-right 10"Add "custom/broadcast" to your modules-right (or whichever side you prefer).
- script:
path: /bin/sh
args:
- -c
- broadcast-ctl status --ironbar
poll-interval: 2000
content:
string:
text: "{broadcast-ctl status --ironbar}"
on-click:
left: broadcast-ctl toggle
right: broadcast-gui --menu --margin-top 38 --margin-right 10Both AGS and Eww can poll broadcast-ctl status --json for structured data and
broadcast-ctl toggle for click actions. Example Eww widget:
(deflisten broadcast-status :initial "{}"
`watch -n2 -t broadcast-ctl status --json`)
(defwidget broadcast []
(button :onclick "broadcast-ctl toggle"
:onrightclick "broadcast-gui --menu"
(label :text {broadcast-status.active ? "" : ""})))
Any bar that can poll a command and trigger click actions works. You need:
| Function | Command |
|---|---|
| Status text | broadcast-ctl status --ironbar |
| JSON status | broadcast-ctl status --json |
| Toggle | broadcast-ctl toggle |
| Popup GUI | broadcast-gui --menu |
State is persisted at ~/.local/state/broadcast/config.json. You can configure:
active— global enable/disable for all filteringdefault_route—"filtered"or"direct"for new audio streamsapp_routes— per-app routing preferences (persisted across restarts)nodes— PipeWire node names for your filter chains:{ "nodes": { "input_capture": "capture.deepfilter_mic", "output_sink": "broadcast_filter_sink" } }preferred_output_sink/preferred_input_source— preferred device by PipeWire node name (null= auto-detect)
- PipeWire filter chains load the DeepFilterNet LADSPA plugin
- A virtual "Clean Mic" source captures from your real mic through DeepFilterNet
- A virtual "Broadcast Filter" sink processes output audio through DeepFilterNet
broadcast-ctl/broadcast-guimove app audio streams between the filter sink and real speakers usingpactl
Mic Input: Real Mic → DeepFilterNet (mono) → "Clean Mic" virtual source
App Output: App → "Broadcast Filter" sink → DeepFilterNet (stereo) → Speakers
GPL-3.0-or-later — see LICENSE.