Ubuntu ARM / Rockchip 音频输出设备固定与故障排查笔记
适用场景:Ubuntu ARM / Rockchip 设备,使用 PipeWire + WirePlumber,存在多个 ALSA 音频输出(ES8388、HDMI 等),希望默认使用
combined / Simultaneous output,并解决重启后默认设备变化、偶发只剩Dummy Output、pactl list short sinks为空等问题。本文整理自一次实际排障过程,重点记录容易踩坑的地方。
1. 先明确 Ubuntu 的音频架构
现代 Ubuntu 常见的音频链路是:
应用程序 / pactl
↓
pipewire-pulse
↓
PipeWire
↓
WirePlumber
↓
ALSA
↓
Rockchip 音频硬件
其中:
-
ALSA:内核层音频接口,负责实际声卡。
-
PipeWire:音频服务器。
-
pipewire-pulse:提供 PulseAudio 兼容接口,因此
pactl仍然可以使用。 -
WirePlumber:PipeWire 的 session/policy manager,负责发现、管理和选择音频设备。
-
pactl:控制 PulseAudio/pipewire-pulse 的命令行工具。
-
wpctl:WirePlumber/PipeWire 的命令行控制工具。
重要结论
如果:
pactl info
显示类似:
Server Name: PulseAudio (on PipeWire ...)
那么实际运行的是 PipeWire,不应该再尝试用:
pulseaudio --start
去启动传统 PulseAudio。
正确的服务操作方式是:
systemctl --user restart pipewire pipewire-pulse wireplumber
2. 查看音频输出设备
2.1 查看 PipeWire/PulseAudio 输出设备
pactl list short sinks
这是最实用的命令之一。
例如:
0 alsa_output.xxx-rockchip-p0...
1 alsa_output.xxx-rockchip-p1...
2 alsa_output.xxx-rockchip-es8388...
3 alsa_output.xxx-rockchip-hdmi0...
4 alsa_output.xxx-rockchip-hdmi1...
5 combined
其中 sink 就是输出设备。
查看当前默认输出:
pactl get-default-sink
2.2 使用 PipeWire/WirePlumber 查看
wpctl status -n
查看某个节点详细信息:
wpctl inspect <ID>
例如:
wpctl inspect 42
可以重点寻找:
node.name
node.description
priority.session
priority.driver
注意
设备的数字 ID 不一定在重启后保持不变。
因此:
wpctl set-default 42
适合临时操作,不适合作为长期固定配置的唯一依据。
更稳定的是使用:
node.name
或设备的稳定属性。
3. 查看 ALSA 底层设备
这是排查音频问题最重要的一层。
aplay -l
也可以:
cat /proc/asound/cards
查看 ALSA PCM 名称:
aplay -L
4. 最重要的故障判断方法
遇到:
pactl list short sinks
为空,或者桌面只显示:
Dummy Output
不要第一时间折腾 pactl。
先执行:
aplay -l
情况 A:aplay -l 也没有设备
例如:
no soundcards found
说明:
内核 / 设备树 / ALSA / Rockchip ASoC / Codec
这一层就没有正常识别声卡。
这不是 pactl 或默认 sink 配置的问题。
进一步检查:
dmesg | grep -Ei "sound|audio|alsa|asoc|es8388|hdmi|i2s|rockchip"
以及:
lsmod | grep -Ei "snd|rockchip|es8388|hdmi|i2s"
重点关注:
-
Rockchip ASoC
-
I2S
-
HDMI audio
-
ES8388 codec
-
device tree
-
codec probe
-
sound card registration
情况 B:aplay -l 有设备,但 pactl list short sinks 为空
例如:
aplay -l
能看到:
rockchip-p0
rockchip-p1
rockchip-es8388
rockchip-hdmi0
rockchip-hdmi1
但:
pactl list short sinks
没有任何输出。
那么:
ALSA 正常
↓
PipeWire / WirePlumber 没有成功创建 sink
重点检查:
systemctl --user status pipewire pipewire-pulse wireplumber
以及:
journalctl --user -u wireplumber -b --no-pager | tail -n 100
journalctl --user -u pipewire -b --no-pager | tail -n 100
可以尝试:
systemctl --user restart wireplumber
sleep 2
pactl list short sinks
如果仍然没有:
systemctl --user restart pipewire pipewire-pulse wireplumber
sleep 2
pactl list short sinks
5. Dummy Output 是什么?
如果桌面声音设置里只剩:
Dummy Output
通常意味着当前 PulseAudio/PipeWire 兼容层没有可用的真实输出 sink。
它不是实体声卡。
典型链路是:
ALSA 没注册
↓
或者 PipeWire 没发现 ALSA
↓
没有真实 sink
↓
桌面显示 Dummy Output
所以看到 Dummy Output 时,第一反应应该是:
aplay -l
而不是尝试反复修改默认输出。
6. Simultaneous output to ... / combined 是什么?
如果声音设置里看到:
Simultaneous output to rockchip-p0,
rockchip-p1,
rockchip-es8388,
rockchip-hdmi0,
rockchip-hdmi1...
它通常是一个虚拟组合输出 sink。
作用是:
应用程序
↓
combined / Simultaneous output
├──→ rockchip-p0
├──→ rockchip-p1
├──→ rockchip-es8388
├──→ rockchip-hdmi0
└──→ rockchip-hdmi1
它不是"模拟声卡",也不是一个实体硬件。
如果目标只是"只要能正常播放声音",并且希望多个输出同时工作,那么可以把它作为默认 sink。
7. 临时把 combined 设置成默认输出
先找名字:
pactl list short sinks | grep -Ei "combined|combine"
例如:
5 combined
然后:
pactl set-default-sink combined
检查:
pactl get-default-sink
8. 为什么不要依赖数字 ID?
例如:
wpctl set-default 42
或者:
pactl list short sinks
中的:
0
1
2
3
这些数字可能因为设备初始化顺序改变而变化。
重启后可能变成:
0 hdmi
1 es8388
2 combined
因此长期配置应该:
-
根据稳定的
node.name -
或根据稳定的 sink 名称
-
或启动后动态搜索
combined
不要硬编码:
42
5
9. WirePlumber 优先级固定设备
如果希望某个真实设备成为默认输出,可以使用 WirePlumber 提高:
priority.session
priority.driver
例如 WirePlumber 0.5+ 的配置思路:
monitor.alsa.rules = [
{
matches = [
{
node.name = "alsa_output.xxx"
}
]
actions = {
update-props = {
priority.session = 20000
priority.driver = 20000
}
}
}
]
用户配置目录:
~/.config/wireplumber/wireplumber.conf.d/
例如:
mkdir -p ~/.config/wireplumber/wireplumber.conf.d
nano ~/.config/wireplumber/wireplumber.conf.d/51-fixed-audio-sink.conf
WirePlumber 版本差异
WirePlumber 0.4 和 0.5 的配置方式不同。
先检查:
wireplumber --version
不要在不知道版本的情况下直接套用另一版本的配置。
10. Ubuntu 22.04 包名踩坑
本次环境是:
Ubuntu 22.04 Jammy
ARM64
曾经尝试:
sudo apt install --reinstall pipewire pipewire-pulse wireplumber libspa-0.2-alsa alsa-utils
结果:
E: 无法按照 glob 'libspa-0.2-alsa' 找到任何软件包
原因是 Ubuntu 22.04 中相关包名不是:
libspa-0.2-alsa
而是:
libspa-0.2-modules
因此可以使用:
sudo apt update
sudo apt install --reinstall pipewire pipewire-pulse wireplumber libspa-0.2-modules alsa-utils
如果系统仓库提供,也可以安装:
sudo apt install pipewire-alsa
11. 修复 PipeWire/WirePlumber
如果怀疑 PipeWire/WirePlumber 安装不完整:
sudo apt update
sudo apt install --reinstall pipewire pipewire-pulse wireplumber libspa-0.2-modules alsa-utils
然后:
systemctl --user daemon-reload
systemctl --user restart pipewire pipewire-pulse wireplumber
检查:
pactl list short sinks
12. 不要混用传统 PulseAudio
如果:
pactl info
显示:
Server Name: PulseAudio (on PipeWire ...)
不要使用:
pulseaudio --start
这是传统 PulseAudio 的启动命令。
PipeWire 环境应该使用:
systemctl --user restart pipewire pipewire-pulse wireplumber
13. 为什么 systemd 自动固定默认输出可能不生效?
如果创建:
~/.config/systemd/user/fix-audio-combined.service
它可能启动得太早。
典型时序:
systemd user service
↓
脚本执行
↓
combined 尚未创建
↓
脚本找不到 combined
↓
脚本退出
之后:
PipeWire 启动
↓
WirePlumber 扫描 ALSA
↓
combined 才出现
因此:
systemctl --user enable --now fix-audio-combined.service
并不能保证它执行时 combined 已经存在。
14. 更适合桌面环境:登录后自启动
如果系统有桌面环境,可以使用:
~/.config/autostart/
创建:
mkdir -p ~/.config/autostart
nano ~/.config/autostart/fix-audio-combined.desktop
内容:
[Desktop Entry]
Type=Application
Name=Fix Audio Combined
Comment=Set default audio output to combined sink after login
Exec=/bin/bash -lc "$HOME/.local/bin/fix-audio-combined-login.sh"
Terminal=false
X-GNOME-Autostart-enabled=true
可以故意延迟:
Exec=/bin/bash -lc "sleep 10; $HOME/.local/bin/fix-audio-combined-login.sh"
如果 Rockchip 声卡初始化较慢,可以:
Exec=/bin/bash -lc "sleep 20; $HOME/.local/bin/fix-audio-combined-login.sh"
15. 推荐的登录后修复脚本
创建:
mkdir -p ~/.local/bin ~/.cache
nano ~/.local/bin/fix-audio-combined-login.sh
内容:
#!/usr/bin/env bash
LOG="$HOME/.cache/fix-audio-combined.log"
exec >> "$LOG" 2>&1
echo "========== $(date) =========="
# 等待 pactl 可用
for i in {1..60}; do
if pactl info >/dev/null 2>&1; then
echo "pactl ready"
break
fi
sleep 1
done
# 等待 sink 出现
for i in {1..60}; do
SINKS="$(pactl list short sinks 2>/dev/null || true)"
if [ -n "$SINKS" ]; then
echo "sinks found:"
echo "$SINKS"
break
fi
sleep 1
done
SINKS="$(pactl list short sinks 2>/dev/null || true)"
# 没有 sink 时先重启 WirePlumber
if [ -z "$SINKS" ]; then
echo "no sinks, restart wireplumber"
systemctl --user restart wireplumber
sleep 3
fi
SINKS="$(pactl list short sinks 2>/dev/null || true)"
# 仍然没有时重启整个 PipeWire 音频栈
if [ -z "$SINKS" ]; then
echo "still no sinks, restart pipewire stack"
systemctl --user restart pipewire pipewire-pulse wireplumber
sleep 5
fi
echo "current sinks:"
pactl list short sinks || true
# 查找 combined
TARGET="$(pactl list short sinks | awk '$2 ~ /combined|combine/ {print $2; exit}')"
# combined 不存在时尝试创建
if [ -z "$TARGET" ]; then
echo "combined sink not found, try create"
pactl load-module module-combine-sink \
sink_name=combined \
sink_properties=device.description=Combined_Output
sleep 2
TARGET="$(pactl list short sinks | awk '$2 ~ /combined|combine/ {print $2; exit}')"
fi
# 最终兜底:选择第一个非 dummy sink
if [ -z "$TARGET" ]; then
echo "combined still not found, fallback"
TARGET="$(pactl list short sinks | awk '$2 !~ /auto_null|dummy/ {print $2; exit}')"
fi
if [ -z "$TARGET" ]; then
echo "no usable sink found"
exit 1
fi
echo "set default sink: $TARGET"
pactl set-default-sink "$TARGET"
# 将当前已有播放流迁移到目标 sink
pactl list short sink-inputs | awk '{print $1}' | while read -r INPUT; do
pactl move-sink-input "$INPUT" "$TARGET" 2>/dev/null || true
done
echo "final default sink:"
pactl get-default-sink || true
授权:
chmod +x ~/.local/bin/fix-audio-combined-login.sh
16. 如果希望调试,保留日志
脚本使用:
~/.cache/fix-audio-combined.log
查看:
cat ~/.cache/fix-audio-combined.log
或者:
tail -f ~/.cache/fix-audio-combined.log
这对于判断:
启动太早
combined 尚未出现
WirePlumber 没启动
PipeWire 没启动
ALSA 没声卡
非常有用。
17. 偶发 pactl list short sinks 完全为空
这是本次最值得关注的问题。
如果重启后偶尔出现:
pactl list short sinks
完全没有输出,并且桌面显示:
Dummy Output
首先不要纠结默认设备。
执行:
aplay -l
然后分情况:
ALSA 也没设备
aplay -l
→ no soundcards found
重点调查:
dmesg | grep -Ei "sound|audio|alsa|asoc|es8388|hdmi|i2s|rockchip"
这属于内核/设备树/驱动初始化问题。
ALSA 有设备
aplay -l
→ 有 rockchip/es8388/hdmi
但:
pactl list short sinks
→ 空
则重点调查:
systemctl --user status pipewire pipewire-pulse wireplumber
以及:
journalctl --user -u wireplumber -b --no-pager | tail -n 100
journalctl --user -u pipewire -b --no-pager | tail -n 100
这种情况很可能与 WirePlumber/设备枚举时序有关。
18. 可以清理 WirePlumber 用户状态
如果怀疑 WirePlumber 用户状态损坏,可以:
systemctl --user stop wireplumber pipewire pipewire-pulse
然后:
rm -rf ~/.local/state/wireplumber
rm -rf ~/.cache/wireplumber
重新启动:
systemctl --user start pipewire pipewire-pulse wireplumber
然后:
pactl list short sinks
注意:清理状态会丢失部分 WirePlumber 用户级状态/选择,因此只在需要时操作。
19. 配置文件位置速查
PipeWire
用户:
~/.config/pipewire/
系统:
/etc/pipewire/
默认参考:
/usr/share/pipewire/
WirePlumber 0.4
常见用户配置:
~/.config/wireplumber/main.lua.d/
WirePlumber 0.5+
常见用户配置:
~/.config/wireplumber/wireplumber.conf.d/
PulseAudio
如果系统确实使用传统 PulseAudio:
~/.config/pulse/default.pa
/etc/pulse/default.pa
但 PipeWire 环境下不要优先修改这里。
20. 关于 module-combine-sink
如果想检查系统是否加载了组合输出模块:
pactl list short modules | grep -i combine
可能出现:
23 module-combine-sink
可以临时卸载:
pactl unload-module 23
其中 23 要替换成实际 module ID。
然后:
pactl list short sinks
如果 Simultaneous output... 消失,就证明它确实来自 combine sink。
21. 查找是谁自动创建了 combine sink
可以搜索:
grep -R "module-combine-sink\|combine-sink" \
~/.config/pulse \
/etc/pulse \
/usr/share/pipewire \
/usr/share/wireplumber \
2>/dev/null
如果找到:
load-module module-combine-sink
就可以进一步判断是谁在启动时创建它。
不要直接修改 /usr/share 下的文件。
优先使用用户配置:
~/.config/...
22. systemd 用户服务与系统服务的区别
如果服务文件在:
~/.config/systemd/user/
那么必须使用:
systemctl --user status xxx.service
而不是:
systemctl status xxx.service
例如:
systemctl --user status fix-audio-combined.service
启动:
systemctl --user start fix-audio-combined.service
启用:
systemctl --user enable fix-audio-combined.service
23. 如果需要登录前/无桌面环境运行
可以考虑:
loginctl enable-linger $USER
检查:
loginctl show-user $USER | grep Linger
如果:
Linger=yes
用户 systemd manager 可以在没有图形登录会话时持续存在。
但是对于本次"登录桌面后固定音频输出"的需求,~/.config/autostart/ 往往更简单。
24. 最终推荐方案
对于当前这台 Rockchip Ubuntu ARM 机器,推荐把问题分成两层:
第一层:确保真实音频设备稳定出现
每次出现问题先:
aplay -l
如果没有声卡:
优先查内核 / 设备树 / ASoC / Codec / HDMI 初始化
如果有声卡但没有 sink:
systemctl --user restart pipewire pipewire-pulse wireplumber
然后:
pactl list short sinks
第二层:默认输出固定为 combined
登录后:
pactl list short sinks
动态寻找:
combined
然后:
pactl set-default-sink combined
不要依赖固定数字 ID。
25. 一套最常用的排障命令
以后遇到声音没了,直接复制这一组:
echo "===== ALSA ====="
aplay -l
echo "===== ASOUND ====="
cat /proc/asound/cards
echo "===== PIPEWIRE ====="
pactl info
echo "===== SINKS ====="
pactl list short sinks
echo "===== DEFAULT ====="
pactl get-default-sink
echo "===== SERVICES ====="
systemctl --user --no-pager status pipewire pipewire-pulse wireplumber
echo "===== WIREPLUMBER LOG ====="
journalctl --user -u wireplumber -b --no-pager | tail -n 100
echo "===== PIPEWIRE LOG ====="
journalctl --user -u pipewire -b --no-pager | tail -n 100
这套信息基本足够判断音频到底死在哪一层。
26. 最容易踩的坑总结
| 现象 | 优先检查 |
|---|---|
Dummy Output |
aplay -l |
pactl list short sinks 为空 |
aplay -l + WirePlumber |
aplay -l 无声卡 |
内核/设备树/驱动/ASoC |
aplay -l 有声卡,pactl 无 sink |
PipeWire/WirePlumber |
pulseaudio --start 失败 |
先确认是不是 PipeWire |
wpctl ID 重启后变化 |
不要硬编码数字 ID |
| 默认输出重启后变化 | 使用稳定 sink/node 名称或登录后脚本 |
combined 没出现 |
检查 module-combine-sink / 创建时机 |
| systemd 服务不生效 | 检查启动时机,必要时改用桌面登录自启动 |
libspa-0.2-alsa 找不到 |
Ubuntu 22.04 使用 libspa-0.2-modules |
| WirePlumber 状态异常 | 必要时清理 ~/.local/state/wireplumber |
| 只在重启后偶发失效 | 高度关注设备初始化/启动时序 |
27. 当前问题的核心结论
本次问题实际上涉及两个不同层次:
问题 1:
默认输出设备会变化
↓
可以用 combined + 登录后脚本解决
问题 2:
重启后偶尔所有 sink 都消失
↓
不能单纯靠 set-default-sink 解决
↓
必须确认 ALSA 是否仍存在
↓
再判断 PipeWire/WirePlumber 是否成功枚举
因此以后看到:
Dummy Output
或者:
pactl list short sinks
没有输出时,第一条命令应该是:
aplay -l
这一步可以直接把问题分成"内核/驱动层"与"PipeWire/WirePlumber 层"。
快速恢复命令
如果只是 PipeWire/WirePlumber 临时异常:
systemctl --user restart pipewire pipewire-pulse wireplumber
sleep 3
pactl list short sinks
如果 combined 已经出现:
pactl list short sinks | grep -Ei "combined|combine"
pactl set-default-sink combined
如果没有任何 sink:
aplay -l
然后根据第 4 节继续判断。