Diagnose and fix audio device detection and routing on NixOS xRDP remote desktop sessions. Handles PulseAudio hardware detection, xRDP audio redirection, and USB audio devices.
Install
npx skillscat add yousufjoyian/claude-skills/remote-desktop-audio-config Install via the SkillsCat registry.
Remote Desktop Audio Configuration
Diagnose and resolve audio issues when connecting to a NixOS workstation via xRDP (Windows Remote Desktop).
When to Use This Skill
- Audio devices not showing up in remote desktop session
- No sound through RDP audio redirection
- USB audio devices (headphones, DACs) not detected
- Need to switch between local hardware output and RDP audio passthrough
- PulseAudio only shows xrdp virtual devices, no hardware
Architecture Overview
Audio Flow (RDP passthrough):
App on workstation → PulseAudio → xrdp-sink → RDP channel → Client laptop → Headphones/Speakers
Audio Flow (direct hardware):
App on workstation → PulseAudio → ALSA card → Physical speakers/headphones on workstationKey Components
| Component | Role |
|---|---|
| PulseAudio | Audio server managing sinks/sources |
| module-udev-detect | Auto-detects hardware audio cards |
| module-xrdp-sink | Virtual sink that sends audio over RDP |
| module-xrdp-source | Virtual source for RDP microphone input |
| xrdp-chansrv | Channel server handling rdpsnd protocol |
| ALSA | Kernel-level audio driver layer |
Common Problem: Hardware Audio Not Detected
Root Cause
xRDP uses its own minimal PulseAudio config at /etc/xrdp/pulse/default.pa that only loads xrdp virtual devices. It does not load module-udev-detect, so hardware ALSA cards are invisible to PulseAudio.
The NixOS system config (/etc/pulse/default.pa) may have hardware detection configured, but xRDP bypasses it entirely by using /etc/xrdp/pulse/default.pa.
Diagnosis
# Step 1: Check what PulseAudio sees
pactl list sinks short
pactl list sources short
pactl list cards short
# If only xrdp-sink and xrdp-source appear, hardware detection is missing
# Step 2: Check what ALSA sees (kernel level)
cat /proc/asound/cards
cat /proc/asound/pcm
# Step 3: Check loaded PulseAudio modules
pactl list modules short
# If module-udev-detect is NOT listed, that's the problem
# Step 4: Check which default.pa is being used
cat /etc/xrdp/pulse/default.pa
cat /etc/pulse/default.paQuick Fix (Runtime)
# Load hardware detection module manually (survives until PA restart)
pactl load-module module-udev-detect
# Verify hardware appeared
pactl list sinks short
pactl list cards shortPermanent Fix (NixOS)
Add module-udev-detect to the xRDP PulseAudio config. Edit /etc/xrdp/pulse/default.pa:
.nofail
.fail
load-module module-augment-properties
load-module module-always-sink
# Hardware audio detection (THIS IS THE KEY LINE)
load-module module-udev-detect
.ifexists module-xrdp-sink.so
load-module module-xrdp-sink
.endif
.ifexists module-xrdp-source.so
load-module module-xrdp-source
.endif
load-module module-native-protocol-unixAlso fix whisper-dictation.nix or equivalent NixOS audio config:
- Remove
load-module module-alsa-card-detect(does not exist as a PA module) - Remove duplicate
load-module module-udev-detect(already loaded by included stock config) - The stock PulseAudio
default.paalready loadsmodule-udev-detectvia.include
Common Problem: RDP Audio Not Working
Symptoms
xrdp-sinkis default but no sound reaches the client- PulseAudio logs show
data_send: send failed
Diagnosis
# Check PA logs for send failures
journalctl --user -u pulseaudio --since "5 minutes ago"
# Check chansrv log for audio format negotiation
# Find the current display number
echo $DISPLAY
# Read the matching chansrv log
cat ~/.local/share/xrdp/xrdp-chansrv.${DISPLAY#:}.log | tail -40
# Look for: sound_process_output_format entries
# If MISSING after a reconnect, rdpsnd channel didn't re-initializeWhat to Look For in chansrv Log
Working connection has these entries after socket accepted:
sound_process_output_format: (format negotiation)
sound_process_training: (latency test)Broken connection only has:
num_silent_frames_aac: 4
Detected remote smartcard
Detected remote printer(No sound_process_output_format = rdpsnd channel not active)
Fixes
Full disconnect and reconnect (not just close window):
- On Windows: Start → Disconnect, then reconnect
- This forces rdpsnd channel renegotiation
Restart PulseAudio (if disconnect doesn't help):
systemctl --user restart pulseaudioThen disconnect and reconnect RDP.
Restart chansrv (nuclear option):
# Find and kill chansrv (xrdp will restart it on next connect) pkill xrdp-chansrvThen reconnect RDP.
Test Audio
# Generate and play a test tone through xrdp-sink
python3 -c "
import struct, math, sys
sample_rate = 44100
for i in range(sample_rate * 2):
sample = int(32767 * 0.5 * math.sin(2 * math.pi * 440 * i / sample_rate))
sys.stdout.buffer.write(struct.pack('<hh', sample, sample))
" | paplay --device=xrdp-sink --format=s16le --channels=2 --rate=44100 --raw
# Check if it sent without errors
journalctl --user -u pulseaudio --since "30 seconds ago"
# Good: RUNNING → IDLE → close_send (no "send failed")
# Bad: RUNNING → "data_send: send failed" → close_sendCommon Problem: USB Audio Not Detected
Diagnosis
# List all USB devices
for dev in /sys/bus/usb/devices/*/; do
if [ -f "$dev/product" ]; then
echo "$(cat $dev/product) - $(cat $dev/idVendor 2>/dev/null):$(cat $dev/idProduct 2>/dev/null) - $(cat $dev/manufacturer 2>/dev/null)"
fi
done
# Check kernel log for USB events
journalctl -k --since "5 minutes ago" | grep -i -E "usb|audio|sound"
# Check if new ALSA card appeared
cat /proc/asound/cardsUSB Switcher Notes
If headphones are connected via a USB switcher (e.g., UGreen):
- The switcher must be actively routed to the workstation (press the switch button)
- If headphones are routed to a laptop instead, use RDP audio passthrough:
- Set workstation default sink to
xrdp-sink - Set laptop audio output to the USB headphones
- Audio flow: workstation → RDP → laptop → headphones
- Set workstation default sink to
Quick Reference: Switching Audio Output
# Route audio through RDP to client (laptop headphones)
pactl set-default-sink xrdp-sink
# Route audio to workstation's physical speakers (use name from 'pactl list sinks short')
pactl set-default-sink <alsa_output_sink_name>
# List available sinks to find the right name
pactl list sinks short
# Check current default
pactl get-default-sinkFull Diagnostic Script
#!/usr/bin/env bash
echo "=== Audio Diagnostic ==="
echo ""
echo "--- PulseAudio Server ---"
pactl info 2>&1 | grep -E "Server|Default Sink|Default Source"
echo ""
echo "--- Loaded Modules ---"
pactl list modules short
echo ""
echo "--- Sinks (Outputs) ---"
pactl list sinks short
echo ""
echo "--- Sources (Inputs) ---"
pactl list sources short
echo ""
echo "--- Cards ---"
pactl list cards short
echo ""
echo "--- ALSA Cards (Kernel) ---"
cat /proc/asound/cards
echo ""
echo "--- ALSA PCM Devices ---"
cat /proc/asound/pcm
echo ""
echo "--- USB Audio Devices ---"
for dev in /sys/bus/usb/devices/*/; do
if [ -f "$dev/product" ]; then
product=$(cat "$dev/product")
vid=$(cat "$dev/idVendor" 2>/dev/null)
pid=$(cat "$dev/idProduct" 2>/dev/null)
echo "$product ($vid:$pid)"
fi
done
echo ""
echo "--- xRDP PulseAudio Config ---"
cat /etc/xrdp/pulse/default.pa 2>/dev/null || echo "Not found"
echo ""
echo "--- xRDP chansrv Log (last 20 lines) ---"
DISPLAY_NUM="${DISPLAY#:}"
DISPLAY_NUM="${DISPLAY_NUM%%.*}"
cat ~/.local/share/xrdp/xrdp-chansrv.${DISPLAY_NUM}.log 2>/dev/null | tail -20
echo ""
echo "--- Recent PulseAudio Errors ---"
journalctl --user -u pulseaudio --since "10 minutes ago" 2>&1 | grep -i -E "fail|error|warn" | tail -10
echo ""
echo "--- module-udev-detect Status ---"
if pactl list modules short | grep -q module-udev-detect; then
echo "LOADED (hardware detection active)"
else
echo "NOT LOADED (hardware will be invisible!)"
echo "Fix: pactl load-module module-udev-detect"
fiTrigger Words
| Phrase | Action |
|---|---|
| "fix audio", "no sound" | Run full diagnostic |
| "detect audio devices", "show audio" | Check sinks/sources/cards |
| "audio not working rdp" | Diagnose RDP audio chain |
| "switch audio output" | Change default sink |
| "test audio", "play test tone" | Generate and play test tone |
Windows RDP Client Checklist
When RDP audio isn't working, verify on the Windows client side:
- Connection settings → Local Resources → Remote audio → "Play on this computer"
- Volume not muted on the client machine
- Audio output on client set to correct device (e.g., USB headphones)
- Full disconnect (not just close window) and reconnect if audio channel is stale