SerLiunx

Ubuntu ARM / Rockchip 音频输出设备固定与故障排查笔记

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 节继续判断。