A lightweight system tray application for KDE Plasma that monitors the active audio output device, updates its tray icon to match the current sink, and provides quick switching between available outputs.
- Dynamic tray icon - Changes based on the active audio output (headphones, speakers, HDMI, Bluetooth, etc.)
- Quick device switching - Right-click menu to switch between available audio sinks
- Visual device configuration - Assign exact icons per output from a built-in Configure dialog
- Automatic updates - Icon updates instantly when devices are plugged in, unplugged, or switched
- Native KDE integration - Uses StatusNotifierItem protocol and respects Plasma's icon themes
- Configurable mappings - Customize which icons are used for your devices
- Low resource usage - Event-driven monitoring via
pactl subscribe, no polling
KSound-Monitor is functional, but still early-stage software. The current implementation uses pactl subscribe for event-driven updates and QSystemTrayIcon for tray integration.
The tray menu now includes a Configure... action for exact per-device icon assignments, with a curated visual picker for the most common icon-theme choices.
- Python 3.11+
- KDE Plasma 6.x (Wayland or X11)
- PipeWire or PulseAudio audio server
- pactl (from
pulseaudio-utilsorpipewire-pulse) - PySide6 (Qt6 Python bindings)
Arch Linux:
sudo pacman -S python-pyside6 pipewire-pulseFedora:
sudo dnf install python3-pyside6 pipewire-pulseaudioDebian/Ubuntu:
sudo apt install python3-pyside6 pipewire-pulse# Clone the repository
git clone https://github.com/ksound-monitor/ksound-monitor.git
cd ksound-monitor
# Install in a virtual environment
python -m venv .venv
source .venv/bin/activate
pip install -e .pip install .pip install -e .This installs the package in editable mode, so changes to the source code take effect immediately.
ksound-monitorThe application will appear in your system tray. Right-click the icon to see available audio outputs and switch between them.
If you do not want to activate the virtual environment manually, you can also run:
./run.shThe script reuses .venv or venv when present, or creates .venv automatically on first run.
When you switch sinks from the menu, KSound-Monitor also attempts to move active playback streams to the newly selected default sink.
Use Configure... from the tray menu to assign exact icons to each detected audio output and choose whether the app should auto-start with KDE.
Right-click the tray icon and select Quit, or press Ctrl+C in the terminal.
cp data/ksound-monitor.desktop ~/.config/autostart/The app also manages this automatically by default. You can toggle KDE autostart from the Configure... dialog.
# Copy the service file
cp data/ksound-monitor.service ~/.config/systemd/user/
# Enable and start the service
systemctl --user enable --now ksound-monitor
# Check status
systemctl --user status ksound-monitor
# View logs
journalctl --user -u ksound-monitor -fThe provided service uses ksound-monitor from your PATH and explicitly allows writing the app config under ~/.config/ksound-monitor.
Configuration is stored in ~/.config/ksound-monitor/config.toml. A default configuration file is created automatically on first run.
[device_icons]
# Exact sink name = "icon-name"
# Exact matches win over regex mappings below
"alsa_output.usb-Logitech_USB_Headset-00.analog-stereo" = "audio-headphones"
[mappings]
# Pattern (regex) = "icon-name"
# Patterns are matched case-insensitively against sink descriptions
".*headphone.*" = "audio-headphones"
".*headset.*" = "audio-headset"
".*speaker.*" = "audio-speakers"
".*hdmi.*" = "video-display"
".*displayport.*" = "video-display"
".*bluetooth.*" = "bluetooth-active"
".*usb.*" = "audio-card"
[settings]
# Default icon when no pattern matches
default_icon = "audio-volume-medium"
# Fallback polling interval (seconds) if pactl subscribe fails
poll_interval_seconds = 5
# Create or remove the KDE autostart entry automatically
autostart_enabled = trueExact per-device assignments are the recommended way to configure icons because they survive similar device descriptions and let you choose icons visually from the app.
To see your audio devices and their descriptions:
pactl -f json list sinks | jq '.[].description'Or for a simpler view:
pactl list sinks | grep -E "Name:|Description:"Use these descriptions to create regex patterns in your config file.
KSound-Monitor uses icons from your system's icon theme (typically Breeze on KDE). Common audio-related icons:
audio-headphones- Headphonesaudio-headset- Headset with microphoneaudio-speakers- Speakersaudio-card- Generic audio devicevideo-display- Display/monitor (for HDMI audio)bluetooth-active- Bluetooth deviceaudio-volume-high/audio-volume-medium/audio-volume-low- Volume levels
To browse all available icons, use a tool like:
# KDE icon viewer
kiconexplorerpython -m unittest discover -s tests -vGitHub Actions runs the test suite on Python 3.11, 3.12, and 3.13 using .github/workflows/ci.yml.
PyInstaller is used to produce a standalone, self-contained executable (bundles Python + PySide6 + Qt plugins).
# Build with the convenience script
./packaging/pyinstaller/build.sh
# Or use the Makefile target
make build-pyinstallerOutput goes to dist/ksound-monitor/. Run it directly:
./dist/ksound-monitor/ksound-monitorThe build script works both in an AUR chroot and in a local checkout (auto-creates a venv if PySide6 is not available system-wide).
The packaging/aur/ directory contains the AUR PKGBUILD, which builds the standalone executable via PyInstaller (rather than installing as a Python package). The resulting package bundles all Python + Qt dependencies, with only libpulse required at runtime.
To publish a new release:
- Tag the release on GitHub and create the source tarball
- Update
pkgverandsha256sumsinPKGBUILD - Regenerate
.SRCINFOwithmakepkg --printsrcinfo > .SRCINFO - Push to the AUR repository
ksound-monitor/
├── src/ksound_monitor/
│ ├── __init__.py # Package metadata
│ ├── __main__.py # Entry point
│ ├── app.py # Main application wiring
│ ├── config.py # Configuration loading
│ ├── monitor.py # Audio event monitoring (pactl subscribe)
│ ├── switcher.py # Audio sink listing/switching (pactl)
│ └── tray.py # System tray icon and menu
├── data/
│ ├── ksound-monitor.desktop # Autostart desktop entry
│ ├── ksound-monitor.service # Systemd user service
│ └── icons/ # Application icons
├── config/
│ └── ksound-monitor.toml.example
├── pyproject.toml
└── README.md
- Ensure your Plasma system tray is configured to show the icon (right-click system tray → Configure)
- Check if other tray applications work
- Try running from terminal to see error messages
- Check your config file patterns match your device descriptions
- Run
pactl list sinksto verify device names - Ensure the icon names exist in your icon theme
- If you use exact per-device overrides, open
Configure...and confirm the assigned icon still exists in your current theme
Install PulseAudio utilities:
# Arch
sudo pacman -S libpulse
# Fedora
sudo dnf install pulseaudio-utils
# Debian/Ubuntu
sudo apt install pulseaudio-utilsThe application will automatically attempt to reconnect to the audio server. If it fails after 3 attempts, it falls back to polling mode.
KSound-Monitor attempts to move active playback streams after changing the default sink. If some applications stay on the old sink, restart playback in that application and verify pactl can see the stream.
- This repository is intended to be publishable as-is: generated files should stay ignored, tests should pass locally, and no secrets or personal data should be required to run it.
- The original product brief lives in
docs/PRD.md; it is intentionally kept as a historical planning document even where the implementation took a simpler route.
MIT License - see LICENSE file for details.
Contributions are welcome! Please feel free to submit issues and pull requests.

