Use USB Speaker as Audio Output
Let HA output audio via USB Speaker
The Problem#
Home Assistant can generate audio (TTS, alerts), but getting it to actually come out of a USB speaker on a Linux box can be weirdly painful—mostly because audio services love fighting over devices and permissions.
In this post, I’ll show how I routed HA audio through a USB speaker using MPD, how to verify the ALSA device, and how to fix the classic “device busy” / “PipeWire connection refused” traps so sound finally plays where it should.
The Solution#
How to Do It#
1. Ensure your speaker is visible by the system#
katrina@homeserver:~$ aplay -l
**** List of PLAYBACK Hardware Devices ****
... # Other devices
card 2: Device [USB Audio Device], device 0: USB Audio [USB Audio] # <== This one
Subdevices: 0/1
Subdevice #0: subdevice #0shIn my case, the USB speaker is the card 2. We can also verify it by cat /proc/asound/cards.
katrina@homeserver:~$ cat /proc/asound/cards
... # Other devices
2 [Device ]: USB-Audio - USB Audio Device # <== This one
GeneralPlus USB Audio Device at usb-0000:00:14.0-1, full speedsh2. Ensure MPD is installed and Verify it’s working#
Check MPD system daemon status by systemctl status mpd
katrina@homeserver:~$ systemctl status mpd
● mpd.service - Music Player Daemon
Loaded: loaded (/lib/systemd/system/mpd.service; enabled; preset: enabled)
Active: active (running) since Fri 2025-08-22 17:27:41 AEST; 14min ago
...shWe can verify that is running as it’s saying Active: active (running). If not, enable and start MPD by
sudo systemctl enable mpd
sudo systemctl start mpdshThen we can check its status using mpc
katrina@homeserver:~$ mpc status
volume:100% repeat: off random: off single: off consume: off
ERROR: Failed to decode http://192.168.0.208:8123/api/tts_proxy/ffxnuIRPgDEXKSy1qKMovg.mp3; CURL failed: The requested URL returned error: 404shUh oh, it’s currently off, and the speaker-test fails as well.
katrina@homeserver:~$ speaker-test -D hw:2,0 -c 2
speaker-test 1.2.8
Playback device is hw:2,0
Stream parameters are 48000Hz, S16_LE, 2 channels
Using 16 octaves of pink noise
Playback open error: -16,Device or resource busyshSince the output indicates Device or resource busy, it maybe occupied by other process.
2.1 Debug - Check Who is Using PulseAudio#
Execute command:
## Check who is using audio devices
sudo fuser -v /dev/snd/*
## Check audio processes
ps aux | grep -E 'pulse|pipewire'
## If above indicates that PulseAudio is occupied, try temporarily stop it
systemctl --user stop pulseaudio.socket
systemctl --user stop pulseaudio.servicesh3. Configure and Test MPD#
Open MPD config file with nano sudo nano /etc/mpd.conf
Edit:
## Ensure MPD listen to localhost
bind_to_address "0.0.0.0"
## Ensure MPD listen port 6600
port "6600"shThen, restart MPD
sudo systemctl restart mpd
## Check status
systemctl status mpd
## Ensure the port is listened
ss -tuln | grep 6600shPlay a sample mp3 to test the MPD
## Clear old playlist
mpc clear
## Play a sample mp3
mpc add https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3
mpc play
## Check status
mpc status
## Check volumn
mpc volume
## List all audio output devices
pactl list short sinksshIn my case, I see this output:
katrina@homeserver:~$ mpc status
https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3
[paused] #1/1 0:00/6:13 (0%)
volume: n/a repeat: off random: off single: off consume: off
ERROR: Failed to enable output "PipeWire Output" (pulse); pa_context_connect() has failed: Connection refused
katrina@homeserver:~$ pactl list short sinks
43 alsa_output.usb-GeneralPlus_USB_Audio_Device-00.analog-stereo PipeWire s16le 2ch 48000Hz RUNNING
...shThe first mpc status gives Connection refused error, while pactl list short sinks indicates that our USB speaker is running as device 43.
3.1 Debug - Speaker is running, but PipeWire Output says “Connection refused”#
Observation: We could list our speaker through pactl list short sinks, which was running with user-level permission; but MPD service could not connect to PipeWire (showed “Connection refused” error).
This might be because MPD service is running as a mpd user, so it can’t connect to the user-level (katrina) PipeWire session.
We can verify this conflicts:
katrina@homeserver:~$ ps aux | grep -E "mpd|pipewire"
katrina 3832551 3.4 0.1 109980 29416 ? Ssl 17:10 6:07 /usr/bin/pipewire # <== PipeWire running with "katrina"
katrina 3832553 2.3 0.5 216200 85196 ? SLsl 17:10 4:14 /usr/bin/pipewire-pulse # An adapter layer
mpd 3923115 0.1 0.4 727684 72492 ? SLsl 18:00 0:11 /usr/bin/mpd --systemd # <== MPD running with "mpd" user
katrina 4060487 0.0 0.0 6336 2064 pts/5 S+ 20:09 0:00 grep -E mpd|pipewire # The grep itselfshThe problem is clear now. MPD running as an “mpd” user, so it doesn’t have permission to access PipeWire’s socket.
Solution: Let’s check MPD config file
- Stop MPD service
shsudo systemctl stop mpd sudo systemctl disable mpd - Open MPD config file, and find this line
plaintext# This setting specifies the user that MPD will run as. MPD should never run as # root and you may use this setting to make MPD change its user ID after # initialization. This setting is disabled by default and MPD is run as the # current user. # user "mpd" - Ah, we can see that user is set to “mpd”. We just need to comment this line to let MPD run as the current user
sh# Comment this line # user "mpd" - Start MPD service
shmpd - Verify permission — All running with current user
shkatrina@homeserver:~$ ps aux | grep -E "mpd|pipewire" katrina 3832551 3.4 0.1 109980 30184 ? Ssl 17:10 7:40 /usr/bin/pipewire katrina 3832553 2.4 0.5 216200 90956 ? SLsl 17:10 5:18 /usr/bin/pipewire-pulse katrina 4122244 1.9 0.3 932160 53944 ? Ssl 20:51 0:00 mpd katrina 4122673 0.0 0.0 6336 2144 pts/5 S+ 20:51 0:00 grep -E mpd|pipewire - If not, try killing mpd process completely then start again
katrina@homeserver:~$ ps aux | grep mpd | grep -v grep # Find the process
katrina 4122244 0.3 0.3 932160 53944 ? Ssl 20:51 0:00 mpd
katrina@homeserver:~$ kill -9 4122244 # The process ID
katrina@homeserver:~$ ps aux | grep mpd | grep -v grep # Verify the process is gone
katrina@homeserver:~$ mpd # Start MPDshThen, repeat the steps to play sample mp3 to test the MPD. The USB speaker should now be able to play some sound.
Summary#
Home Assistant audio now plays through a USB speaker by routing output via MPD and fixing PipeWire/permission conflicts.