Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save GithubUser5462/ed2cbb93b5b47ab0eb20d734664ce7ac to your computer and use it in GitHub Desktop.

Select an option

Save GithubUser5462/ed2cbb93b5b47ab0eb20d734664ce7ac to your computer and use it in GitHub Desktop.
Fixing "no sound" over a USB / USB-C dock or DAC on Linux (PipeWire)

Fixing "no sound" over a USB / USB-C dock or DAC on Linux (PipeWire)

You plugged headphones/speakers into a USB-C dock (or a USB DAC), the device shows up in your sound settings, volume is up... and there's still silence.

This guide walks the full decision tree. The gotcha most guides miss is the last step: a USB DAC can have its own hardware mute switch at the raw ALSA level that your desktop's volume slider never touches.

Tested on Arch/CachyOS with PipeWire + WirePlumber, but the ALSA/PipeWire commands apply to any modern distro (Fedora, Ubuntu 22.10+, etc.).


TL;DR

# 1. Is the device even seen by ALSA? (find its card number)
cat /proc/asound/cards

# 2. Route audio to it and unmute at the PipeWire level
wpctl status                         # find the sink id / name
wpctl set-default <SINK_ID>
wpctl set-mute   <SINK_ID> 0
wpctl set-volume <SINK_ID> 0.8

# 3. THE ONE PEOPLE MISS: unmute the raw hardware switches on the DAC
amixer -c <CARD_NUMBER>              # list controls; look for any "[off]"
amixer -c <CARD_NUMBER> sset 'Headphones' unmute
amixer -c <CARD_NUMBER> sset 'Speaker'    unmute   # names vary by device

# 4. Make it stick across reboots
sudo alsactl store

If you only remember one thing: amixer -c N and look for [off].


Step 0 — Confirm the device is detected

Being detected rules out cable/driver/hardware faults early.

lsusb | grep -i audio          # USB descriptor sees an audio endpoint?
cat /proc/asound/cards         # ALSA registered a card for it?
aplay -l                       # playback devices per card

You should see your dock/DAC listed with a card number (e.g. card 2). Note that number — you'll need it for amixer -c N.

⚠️ Gotcha: the card number from aplay -l / /proc/asound/cards can differ from the index amixer uses. If amixer -c 2 shows nothing useful, try amixer -c 0, -c 1, etc., or run aplay -L and match by name.

If the device is not listed at all: try another cable/port, check dmesg | tail -30 right after plugging it in, and confirm the dock itself is powered. That's a different (hardware/enumeration) problem, out of scope here.


Step 1 — Is it just routed to the wrong output?

By far the most common cause. Your apps are happily playing to the laptop speakers because the dock was never selected as the default.

wpctl status

Look under Sinks for a * marking the default. If the * is on your internal speakers and your dock sink has no star, that's your problem.

# Set the dock as default (use the id number shown in wpctl status)
wpctl set-default 60

# Move already-playing apps onto it (PulseAudio-compat command)
pactl list short sink-inputs | cut -f1 \
  | xargs -r -I{} pactl move-sink-input {} <DOCK_SINK_NAME>

Prefer the sink name (e.g. alsa_output.usb-..._analog-stereo) over the numeric id in scripts — names are stable across reboots, ids are not.

Play something. Fixed? Great. Still silent? Continue.


Step 2 — Prove audio is actually reaching the device

Before blaming the DAC, confirm the OS is really delivering samples to it. Play a test tone directly to the sink and watch the sink change state.

# Generate a 3s 440 Hz stereo tone (needs `sox`)
sox -n -r 48000 -c 2 /tmp/tone.wav synth 3 sine 440 gain -3

# Play it straight to the dock sink (needs pipewire/pulse utils)
paplay --device=<DOCK_SINK_NAME> /tmp/tone.wav

In another terminal, while it's playing:

pactl list short sinks | grep <your-dock-name>
  • If the sink shows RUNNING during playback (then IDLE/SUSPENDED after) → the software path works end to end. The fault is downstream, in the DAC hardware controls. Go to Step 3. This is the important clue.
  • If it never leaves SUSPENDED / errors out → routing or profile problem; revisit Step 1 and check the card profile (see Step 4).

Step 3 — Unmute the DAC's own hardware switches ← the usual culprit

USB DACs frequently expose their own mixer switches (Headphones, Speaker, PCM, Master, Extension Unit, ...). PipeWire's volume/mute does not always map to these. One can sit at [off] while your desktop shows 80%, and the DAC silently drops the audio.

amixer -c <CARD_NUMBER>

Scan the output for any playback control showing [off], e.g.:

Simple mixer control 'Headphones',0
  Front Left:  Playback 175 [100%] [0.00dB] [off]   <-- muted at the hardware!
  Front Right: Playback 175 [100%] [0.00dB] [off]

Unmute each one (names vary — use what amixer printed):

amixer -c <CARD_NUMBER> sset 'Headphones' unmute
amixer -c <CARD_NUMBER> sset 'Speaker'    unmute
amixer -c <CARD_NUMBER> sset 'PCM'    100% unmute

Replay the tone from Step 2. This is very often the fix.

Some devices have a phantom control (in my case an Extension Unit switch) that reads [off] and toggles itself back immediately but does not block audio. Don't chase it — if sound works with the main switch on, ignore the rest. Test by ear rather than trusting the reported state.

Prefer a GUI? Install alsamixer, press F6 to pick the card, and use M to toggle mute on each channel — same thing, visual.


Step 4 — (If still stuck) check the card profile & port

If Step 2 showed the sink never runs, the card may be on the wrong profile (e.g. an S/PDIF/digital profile instead of analog) or the wrong output port.

pactl list cards | less     # find your card; look at "Active Profile" + "Ports"

Set an analog output profile and port:

pactl set-card-profile <CARD_NAME> output:analog-stereo
pactl set-sink-port <DOCK_SINK_NAME> analog-output

Step 5 — Make the fix persist

ALSA mixer state is restored on boot by alsa-restore.service. Save the current (now-unmuted) state:

sudo alsactl store          # writes /var/lib/alsa/asound.state

Verify it saved:

grep -A1 "Playback Switch" /var/lib/alsa/asound.state | grep -iB1 -A1 value

The PipeWire default-sink choice is remembered by WirePlumber automatically.

If it only breaks after UNPLUGGING/REPLUGGING the dock

alsactl store covers reboots but not necessarily a hot re-plug, which can re-init the DAC with switches muted again. Add a udev rule to auto-unmute on connect. Find the vendor/product id from lsusb (e.g. 03f0:056b), then:

# /etc/udev/rules.d/99-dock-audio-unmute.rules
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="03f0", ATTR{idProduct}=="056b", \
  RUN+="/usr/bin/amixer -c <CARD> sset 'Headphones' unmute"

(Adjust ids/card/control names. Reload with sudo udevadm control --reload.)


Quick reference cheat-sheet

Symptom Command to check Likely fix
Device missing entirely lsusb, cat /proc/asound/cards cable/port/power, dmesg
Device present, wrong output wpctl status (see the *) wpctl set-default N
Sink RUNNING but silent amixer -c N → look for [off] amixer -c N sset '<ctl>' unmute
Only digital/HDMI works pactl list cards → profile set-card-profile ... analog-stereo
Reverts after reboot sudo alsactl store
Reverts after replug lsusb for ids udev auto-unmute rule

Written after debugging an HP USB-C Dock G5 on CachyOS/PipeWire, where the DAC's Headphones switch was muted at the ALSA level despite the desktop showing full volume.

Comments are disabled for this gist.