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.
sudo apt update
sudo apt install -y pipewire pipewire-pulse wireplumber pipewire-bin pulseaudio-utils rtkit dbus-user-session libasound2-plugins
libasound2-plugins
is required so ALSA apps can see/use pcm.pulse
→ PipeWire.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.service
Verify:
ls -ld /run/user/1000 # expect: drwx------ dietpi audio
ls -l /run/user/1000/bus # should be a socket
dietpi
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
EOF
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
EOF
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
EOF
Enable them:
sudo systemctl daemon-reload
sudo systemctl enable --now pipewire-dietpi wireplumber-dietpi pipewire-pulse-dietpi
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-fallback
Note: Using
PULSE_SERVER
is recommended.PULSE_SOURCE
can be used to select a specific input if needed, but may be less robust if device names change.
pipewire
ALSA deviceTo 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"
}
EOF
Now apps that enumerate ALSA devices will show pipewire
as an option.
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/bus
Load them immediately:
source ~/.profile
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-fallback
Set HiFiBerry as default:
pactl set-default-source alsa_input.platform-soc_107c000000_sound.stereo-fallback
Test recording:
parecord /tmp/test.wav # Ctrl+C after a few seconds
aplay /tmp/test.wav
Create config override:
mkdir -p ~/.config/pipewire/pipewire.conf.d
nano ~/.config/pipewire/pipewire.conf.d/10-lowlatency.conf
Contents:
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-dietpi
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 privileges
This 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.
sudo apt update
sudo apt install -y dbus rtkit
sudo systemctl enable --now dbus
Verify the socket:
ls -l /run/dbus/system_bus_socket
Restart PipeWire services:
sudo systemctl restart dietpi-user-runtime pipewire-dietpi wireplumber-dietpi pipewire-pulse-dietpi
After this, the “system bus” and “realtime scheduling disabled” warnings should disappear, and PipeWire can make use of RTKit for low-latency scheduling.
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-dietpi
Check 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.conf
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/pipewire
Also inspect logs:
sudo journalctl -u pipewire-dietpi -u wireplumber-dietpi -u pipewire-pulse-dietpi -n 120 --no-pager
pactl
says “Connection refused”pipewire-pulse-dietpi
is active:systemctl --no-pager -l status pipewire-pulse-dietpi
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
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
dpkg -l | grep libasound2-plugins
/etc/asound.conf
defines pcm.pipewire
and ctl.pipewire
as shown above.Follow everything at once:
sudo journalctl -u dietpi-user-runtime -u pipewire-dietpi -u wireplumber-dietpi -u pipewire-pulse-dietpi -f
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.
pactl list short sources
Example output:
alsa_input.platform-soc_107c000000_sound.stereo-fallback
alsa_input.usb-Generic_AB13X_USB_Audio_20210926172016-00.mono-fallback
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-app
This launches my-app
using the USB mic while the system keeps HiFiBerry as default.
parecord
parecord --device=alsa_input.usb-Generic_AB13X_USB_Audio_20210926172016-00.mono-fallback /tmp/usb-test.wav
aplay /tmp/usb-test.wav
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)"
}
EOF
Now the USB mic will appear in ALSA device lists as:
usbmic USB Microphone (via PipeWire)
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/dsp
These messages appear because:
dsnoop
warnings → the ALSA dsnoop
plugin 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 install pipewire-jack
, but otherwise these warnings can be ignored./dev/dsp
OSS 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.
If you want to prevent JACK errors from appearing in logs, set this environment variable in your session:
export JACK_NO_START_SERVER=1
To make it persistent for the dietpi
user, add it to ~/.profile
:
echo 'export JACK_NO_START_SERVER=1' >> ~/.profile
Then reload:
source ~/.profile
This tells libraries that probe JACK not to try auto-starting a JACK server, removing the “jack server is not running” spam.
We respect your privacy. We respect your privacy.
TLDR: We use cookies for language selection, theme, and analytics. Learn more. TLDR: We use cookies for language selection, theme, and analytics. Learn more