Skip to content

goncaloalves/KSound-Monitor

Repository files navigation

KSound-Monitor

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.

Screenshots

Tray menu

Configure dialog

Icon picker

Features

  • 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

Status

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.

Requirements

  • Python 3.11+
  • KDE Plasma 6.x (Wayland or X11)
  • PipeWire or PulseAudio audio server
  • pactl (from pulseaudio-utils or pipewire-pulse)
  • PySide6 (Qt6 Python bindings)

Installing Dependencies

Arch Linux:

sudo pacman -S python-pyside6 pipewire-pulse

Fedora:

sudo dnf install python3-pyside6 pipewire-pulseaudio

Debian/Ubuntu:

sudo apt install python3-pyside6 pipewire-pulse

Installation

From Source (Recommended)

# 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 .

Standard Install

pip install .

Development Mode

pip install -e .

This installs the package in editable mode, so changes to the source code take effect immediately.

Usage

Running

ksound-monitor

The 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.sh

The 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.

Stopping

Right-click the tray icon and select Quit, or press Ctrl+C in the terminal.

Autostart

Option 1: Desktop File (Recommended for Plasma)

cp data/ksound-monitor.desktop ~/.config/autostart/

The app also manages this automatically by default. You can toggle KDE autostart from the Configure... dialog.

Option 2: Systemd User Service

# 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 -f

The provided service uses ksound-monitor from your PATH and explicitly allows writing the app config under ~/.config/ksound-monitor.

Configuration

Configuration is stored in ~/.config/ksound-monitor/config.toml. A default configuration file is created automatically on first run.

Example Configuration

[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 = true

Exact 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.

Finding Sink Descriptions

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.

Available Icons

KSound-Monitor uses icons from your system's icon theme (typically Breeze on KDE). Common audio-related icons:

  • audio-headphones - Headphones
  • audio-headset - Headset with microphone
  • audio-speakers - Speakers
  • audio-card - Generic audio device
  • video-display - Display/monitor (for HDMI audio)
  • bluetooth-active - Bluetooth device
  • audio-volume-high / audio-volume-medium / audio-volume-low - Volume levels

To browse all available icons, use a tool like:

# KDE icon viewer
kiconexplorer

Development

Run Tests

python -m unittest discover -s tests -v

CI

GitHub Actions runs the test suite on Python 3.11, 3.12, and 3.13 using .github/workflows/ci.yml.

Packaging

Executable Builds

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-pyinstaller

Output goes to dist/ksound-monitor/. Run it directly:

./dist/ksound-monitor/ksound-monitor

The build script works both in an AUR chroot and in a local checkout (auto-creates a venv if PySide6 is not available system-wide).

Arch / AUR

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:

  1. Tag the release on GitHub and create the source tarball
  2. Update pkgver and sha256sums in PKGBUILD
  3. Regenerate .SRCINFO with makepkg --printsrcinfo > .SRCINFO
  4. Push to the AUR repository

Project Structure

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

Troubleshooting

Tray icon not appearing

  1. Ensure your Plasma system tray is configured to show the icon (right-click system tray → Configure)
  2. Check if other tray applications work
  3. Try running from terminal to see error messages

Icon not changing

  1. Check your config file patterns match your device descriptions
  2. Run pactl list sinks to verify device names
  3. Ensure the icon names exist in your icon theme
  4. If you use exact per-device overrides, open Configure... and confirm the assigned icon still exists in your current theme

pactl not found

Install PulseAudio utilities:

# Arch
sudo pacman -S libpulse

# Fedora
sudo dnf install pulseaudio-utils

# Debian/Ubuntu
sudo apt install pulseaudio-utils

Application crashes on PipeWire restart

The application will automatically attempt to reconnect to the audio server. If it fails after 3 attempts, it falls back to polling mode.

Existing audio does not move after switching

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.

Public Repo Notes

  • 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.

License

MIT License - see LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit issues and pull requests.

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors