This guide sets up PipeWire as system services tied to the dietpi user, allowing multiple applications (e.g. InterScribe agent + monitoring tools) to access HiFiBerry ADC simultaneously with low latency.
HiFiBerry ADC devices, when accessed directly through ALSA, can sometimes exhibit quirks or limited compatibility—especially with applications like the InterScribe Agent that expect multi-client audio access. ALSA by itself does not natively allow multiple programs to capture from the same device at once, and some applications may not work reliably with certain ALSA plugins. PipeWire acts as a unified sound server that greatly improves compatibility: it enables simultaneous access from multiple apps, provides a modern replacement for both PulseAudio and JACK, and avoids many of the limitations and device-specific issues found with direct ALSA access.
By default, DietPi doesn’t run systemd --user sessions, so we run PipeWire as system services for the dietpi user.
1. Install required packages
sudo apt update
sudo apt install -y pipewire pipewire-pulse wireplumber pipewire-bin pulseaudio-utils rtkit dbus-user-session libasound2-pluginslibasound2-pluginsis required so ALSA apps can see/usepcm.pulse→ PipeWire.
2. Create runtime + DBus session service
PipeWire expects /run/user/<UID> with correct ownership and permissions.
We create a helper service to provide this for dietpi.
sudo tee /etc/systemd/system/dietpi-user-runtime.service >/dev/null <<'EOF'
[Unit]
Description=Create /run/user and session bus for dietpi
After=systemd-logind.service
Wants=systemd-logind.service
[Service]
Type=simple
User=dietpi
Group=audio
PermissionsStartOnly=yes
ExecStartPre=/bin/mkdir -p /run/user/1000
ExecStartPre=/bin/chown dietpi:audio /run/user/1000
ExecStartPre=/bin/chmod 700 /run/user/1000
Environment=XDG_RUNTIME_DIR=/run/user/1000
ExecStart=/usr/bin/dbus-daemon --session --address=unix:path=/run/user/1000/bus --nofork
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now dietpi-user-runtime.serviceVerify:
ls -ld /run/user/1000 # expect: drwx------ dietpi audio
ls -l /run/user/1000/bus # should be a socket3. Create PipeWire services for dietpi
PipeWire
sudo tee /etc/systemd/system/pipewire-dietpi.service >/dev/null <<'EOF'
[Unit]
Description=PipeWire for dietpi (headless)
After=dietpi-user-runtime.service
Requires=dietpi-user-runtime.service
[Service]
Type=simple
User=dietpi
Group=audio
Environment=HOME=/home/dietpi
Environment=TMPDIR=/tmp
Environment=XDG_RUNTIME_DIR=/run/user/1000
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
ExecStartPre=-/bin/rm -f /run/user/1000/pipewire-0 /run/user/1000/pipewire-0.lock
ExecStart=/usr/bin/pipewire
Restart=always
RestartSec=2
LimitRTPRIO=95
LimitMEMLOCK=infinity
[Install]
WantedBy=multi-user.target
EOFWirePlumber
sudo tee /etc/systemd/system/wireplumber-dietpi.service >/dev/null <<'EOF'
[Unit]
Description=WirePlumber (session manager) for dietpi
After=pipewire-dietpi.service
Requires=pipewire-dietpi.service
[Service]
Type=simple
User=dietpi
Group=audio
Environment=HOME=/home/dietpi
Environment=TMPDIR=/tmp
Environment=XDG_RUNTIME_DIR=/run/user/1000
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
ExecStart=/usr/bin/wireplumber
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.target
EOFPulseAudio shim
sudo tee /etc/systemd/system/pipewire-pulse-dietpi.service >/dev/null <<'EOF'
[Unit]
Description=PipeWire PulseAudio compatibility for dietpi
After=pipewire-dietpi.service
Requires=pipewire-dietpi.service
[Service]
Type=simple
User=dietpi
Group=audio
Environment=HOME=/home/dietpi
Environment=TMPDIR=/tmp
Environment=XDG_RUNTIME_DIR=/run/user/1000
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
ExecStartPre=-/bin/rm -f /run/user/1000/pulse/native
ExecStart=/usr/bin/pipewire-pulse
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.target
EOFEnable them:
sudo systemctl daemon-reload
sudo systemctl enable --now pipewire-dietpi wireplumber-dietpi pipewire-pulse-dietpi4. Configure InterScribe Agent audio settings
To ensure the InterScribe Agent uses the correct audio server, you must configure /etc/default/interscribe-agent.
Preferred method: Set the PULSE_SERVER environment variable. This makes the agent independent of the system's default source and more robust, as it connects directly to the PulseAudio (PipeWire) server socket.
Example /etc/default/interscribe-agent:
# Recommended: Point directly to the PulseAudio (PipeWire) server socket
PULSE_SERVER=unix:/run/user/1000/pulse/native
# Alternative (not recommended): Use PULSE_SOURCE to select a specific input device by name
# PULSE_SOURCE=alsa_input.platform-soc_107c000000_sound.stereo-fallbackNote: Using
PULSE_SERVERis recommended.PULSE_SOURCEcan be used to select a specific input if needed, but may be less robust if device names change.
5. Expose a pipewire ALSA device
To make pipewire appear in ALSA device lists:
sudo tee /etc/asound.conf >/dev/null <<'EOF'
pcm.pipewire {
type pulse
hint.description "PipeWire Sound Server"
}
ctl.pipewire {
type pulse
}
pcm.!default {
type pulse
fallback "hw:CARD=sndrpihifiberry,DEV=0"
hint.description "PipeWire (Default)"
}
ctl.!default {
type pulse
fallback "hw:CARD=sndrpihifiberry,DEV=0"
}
EOFNow apps that enumerate ALSA devices will show pipewire as an option.
6. Export environment in your shell
PipeWire needs these environment variables in your dietpi session. Add them to ~/.profile so they persist:
export XDG_RUNTIME_DIR=/run/user/1000
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/busLoad them immediately:
source ~/.profile7. Verify PipeWire
Check the PulseAudio shim is active:
pactl info | grep "Server Name"
# Expect: Server Name: PulseAudio (on PipeWire 0.3.x)List inputs:
pactl list short sources
# You should see your HiFiBerry ADC as alsa_input.platform-soc_107c000000_sound.stereo-fallbackSet HiFiBerry as default:
pactl set-default-source alsa_input.platform-soc_107c000000_sound.stereo-fallbackTest recording:
parecord /tmp/test.wav # Ctrl+C after a few seconds
aplay /tmp/test.wav8. Low-latency tuning (optional)
Create config override:
mkdir -p ~/.config/pipewire/pipewire.conf.d
nano ~/.config/pipewire/pipewire.conf.d/10-lowlatency.confContents:
context.properties = {
default.clock.rate = 48000
default.clock.quantum = 128
default.clock.min-quantum = 32
default.clock.max-quantum = 2048
}Restart services:
sudo systemctl restart pipewire-dietpi wireplumber-dietpi pipewire-pulse-dietpi12. [Optional] Enable System D-Bus + RTKit (Cleaner Logs + Realtime Scheduling)
On DietPi, PipeWire and WirePlumber may log warnings like:
Failed to connect to system bus: No such file or directory
Realtime scheduling disabled: insufficient realtime privilegesThis happens because DietPi doesn’t run the system D-Bus or RTKit by default. Audio still works, but logs may look noisy and realtime scheduling isn’t used.
✅ Enable system D-Bus and RTKit
sudo apt update
sudo apt install -y dbus rtkit
sudo systemctl enable --now dbusVerify the socket:
ls -l /run/dbus/system_bus_socketRestart PipeWire services:
sudo systemctl restart dietpi-user-runtime pipewire-dietpi wireplumber-dietpi pipewire-pulse-dietpiAfter this, the “system bus” and “realtime scheduling disabled” warnings should disappear, and PipeWire can make use of RTKit for low-latency scheduling.
10. Troubleshooting
🧪 Quick health check (copy/paste)
Run these as the dietpi user (not root):
# Ensure your shell points to the correct runtime/bus
export XDG_RUNTIME_DIR=/run/user/1000
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
echo "== runtime =="
ls -ld /run/user/1000 || echo "MISSING: /run/user/1000"
ls -l /run/user/1000/bus || echo "MISSING: bus socket"
ls -l /run/user/1000/pulse/native || echo "MISSING: pulse/native"
echo "== services =="
systemctl --no-pager -l status dietpi-user-runtime pipewire-dietpi wireplumber-dietpi pipewire-pulse-dietpi || true
echo "== pactl =="
pactl --server="$XDG_RUNTIME_DIR/pulse/native" info || echo "pactl failed"If /run/user/1000 is missing or the bus/pulse/native sockets are missing, see the items below.
/run/user/1000 missing (or wrong owner/permissions)
/run is a tmpfs and resets on boot. Recreate and restart in order:
# replace 1000 with your actual UID if different
id -u dietpi
sudo systemctl stop pipewire-dietpi pipewire-pulse-dietpi wireplumber-dietpi || true
sudo mkdir -p /run/user/1000
sudo chown dietpi:audio /run/user/1000
sudo chmod 700 /run/user/1000
sudo systemctl restart dietpi-user-runtime
sudo systemctl start pipewire-dietpi wireplumber-dietpi pipewire-pulse-dietpiCheck why the shim didn’t create it:
sudo journalctl -u dietpi-user-runtime -n 80 --no-pager(Optional hardening) Create a tmpfiles rule so the directory exists early at boot:
echo "d /run/user/1000 0700 dietpi audio -" | sudo tee /etc/tmpfiles.d/dietpi-user.conf
sudo systemd-tmpfiles --create /etc/tmpfiles.d/dietpi-user.confPipeWire won’t start (status=245/254) or WirePlumber exits (status=69)
Common causes & fixes:
# 1) Ownership/permissions on the runtime dir
ls -ld /run/user/1000
sudo chown dietpi:audio /run/user/1000
sudo chmod 700 /run/user/1000
# 2) Stale lock/socket files
sudo rm -f /run/user/1000/pipewire-0 /run/user/1000/pipewire-0.lock /run/user/1000/pulse/native
# 3) Ensure a machine-id exists for D-Bus
[ -s /etc/machine-id ] || sudo systemd-machine-id-setup
# 4) Kill legacy pulseaudio if it’s running (rare on DietPi)
pgrep -a pulseaudio || true
sudo killall pulseaudio 2>/dev/null || true
# 5) Restart in order
sudo systemctl restart dietpi-user-runtime
sudo systemctl restart pipewire-dietpi wireplumber-dietpi pipewire-pulse-dietpi
# 6) Foreground debug (shows the exact error)
sudo -u dietpi \
XDG_RUNTIME_DIR=/run/user/1000 \
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
PIPEWIRE_DEBUG=4 \
/usr/bin/pipewireAlso inspect logs:
sudo journalctl -u pipewire-dietpi -u wireplumber-dietpi -u pipewire-pulse-dietpi -n 120 --no-pagerpactl says “Connection refused”
- Make sure
pipewire-pulse-dietpiis active:systemctl --no-pager -l status pipewire-pulse-dietpi - Ensure your shell has the right env set:
export XDG_RUNTIME_DIR=/run/user/1000 export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus pactl --server="$XDG_RUNTIME_DIR/pulse/native" info - If you must run with
sudo, target the dietpi runtime:sudo -u dietpi XDG_RUNTIME_DIR=/run/user/1000 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus pactl info
PipeWire not listed in ALSA apps
- Confirm the plugin package is installed:
dpkg -l | grep libasound2-plugins - Ensure
/etc/asound.confdefinespcm.pipewireandctl.pipewireas shown above. - Restart apps (some cache ALSA device lists).
View live logs
Follow everything at once:
sudo journalctl -u dietpi-user-runtime -u pipewire-dietpi -u wireplumber-dietpi -u pipewire-pulse-dietpi -f11. [Optional] Using Multiple Input Devices (Without Changing Default)
By default, PipeWire will expose all connected capture devices (HiFiBerry, USB mics, webcams, etc.). Only one device is set as the default input, but you can still access others explicitly without changing defaults.
🔹 1. List available input devices
pactl list short sourcesExample output:
alsa_input.platform-soc_107c000000_sound.stereo-fallback
alsa_input.usb-Generic_AB13X_USB_Audio_20210926172016-00.mono-fallback- The first is the HiFiBerry Studio ADC (default).
- The second is a USB microphone.
🔹 2. Use another device temporarily
Instead of changing the default, run your app with the desired source:
PULSE_SOURCE=alsa_input.usb-Generic_AB13X_USB_Audio_20210926172016-00.mono-fallback my-appThis launches my-app using the USB mic while the system keeps HiFiBerry as default.
🔹 3. Test with parecord
parecord --device=alsa_input.usb-Generic_AB13X_USB_Audio_20210926172016-00.mono-fallback /tmp/usb-test.wav
aplay /tmp/usb-test.wav🔹 4. Make a friendly ALSA alias (optional)
If your app only enumerates ALSA devices and doesn’t understand PipeWire names, you can define an alias:
sudo tee -a /etc/asound.conf >/dev/null <<'EOF'
pcm.usbmic {
type pulse
device "alsa_input.usb-Generic_AB13X_USB_Audio_20210926172016-00.mono-fallback"
hint.description "USB Microphone (via PipeWire)"
}
EOFNow the USB mic will appear in ALSA device lists as:
usbmic USB Microphone (via PipeWire)12. Common Log Messages (Safe to Ignore)
When using ALSA and PipeWire together, you may occasionally see warnings like:
ALSA lib pcm_dsnoop.c:566:(snd_pcm_dsnoop_open) unable to open slave
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
ALSA lib pcm_oss.c:397:(_snd_pcm_oss_open) Cannot open device /dev/dspThese messages appear because:
dsnoopwarnings → the ALSAdsnoopplugin only supports capture. Apps probing playback may trigger these harmless errors.jack server is not running→ some apps probe JACK even if you don’t use it. PipeWire can handle JACK apps if you installpipewire-jack, but otherwise these warnings can be ignored./dev/dspOSS errors → legacy OSS interface is not available on modern systems, so apps that still try will log a failure, but ALSA/PipeWire continues working fine.
✅ None of these indicate a problem with PipeWire or HiFiBerry. Your audio will still flow normally — you can safely ignore these logs.
🔇 Silencing JACK Warnings
If you want to prevent JACK errors from appearing in logs, set this environment variable in your session:
export JACK_NO_START_SERVER=1To make it persistent for the dietpi user, add it to ~/.profile:
echo 'export JACK_NO_START_SERVER=1' >> ~/.profileThen reload:
source ~/.profileThis tells libraries that probe JACK not to try auto-starting a JACK server, removing the “jack server is not running” spam.
