Peng's Blog

Peng's Blog

马上订阅 Peng's Blog RSS 更新: https://pengs.top/atom.xml

解决linux系统下pipewire作为音频服务器持续播放声音中断问题

2025年8月18日 08:57

本文接上篇在ThinkBook 16+ 2025上安装archlinux驯服记录【基本信息与触摸板修复】。按理说,本文标题本应是《在ThinkBook 16+ 2025上安装archlinux驯服记录【音频修复】》的,考虑到此问题可能影响到较多机型,故修改为更通用的标题。

闲话少说,开始解决问题。

问题背景

我有时候会用电脑播放音乐,这些音乐都是无损flac格式的盗版音乐。在我的上一台电脑上,一切正常。在这台新款的ThinkBook 16+ 2025上,问题表现为:

播放音乐的时候,能放一会儿(约30秒),然后就没有声音了,插电也是这样
声音中断后KDE设置显示“已失去与声音服务器的连接”,VLC启动时加载时间比正常情况久很多,音量被自动设置到0,且进度条不开始。

这种情况令我糟心,为了立刻重新听上音乐,我通过systemctl重启了pipewire与wireplumber服务,重新打开vlc,播放了2~3分钟后,同样的声音中断发生了。

作为archlinux用户,我的软件包都是滚动更新的最新版本,所以显然上游还没有修复这个问题,只能自己动手了。

调试过程

我查看了与声卡有关的日志,如下:

屏幕截图_20250817_143513

从日志上看,驱动能够正常识别与处理设备,而在播放过程中,pipewire或其下的某个组件崩溃了,造成了broken pipe

考虑到linux音频系统的混乱与复杂(如下图),我没有能力深度调试,决定先进行“猜测”。

linux混乱的音频系统

我首先怀疑是省电配置导致的,因为我希望延长续航时间,所以安装了tlp并且手动配置了许多省电选项。

所以我直接修改了/etc/tlp.conf,找到了与声卡节能有关的配置并修改为以下内容:

1
2
SOUND_POWER_SAVE_ON_BAT=0
SOUND_POWER_SAVE_ON_AC=0

这意味着在交流供电与电源供电时都不会尝试让声卡通过挂起等方式节能。根据我的经验与直觉,linux下硬件不能正常工作,常常是和suspend(挂起)与recover(恢复)有关的。所以我满心期待以为问题解决了。

然后我跟着音乐哼着哼着,音乐停了。

我寻思是不是有内核参数在作祟,于是又折腾了好久。可是并没有用。

就在这个时候我注意到一个此前忽略的细节:虽然连续播放的音乐会中断,但是如果不播放音乐,系统的提示音效在开机后多久,甚至睡眠又唤醒后都是正常的。

也就是说长音频不行而短音频没有影响。

诡异吧?

缓冲区玄学

这个玄学问题,最终还要归结于“缓冲区”。

什么是缓冲区?

想象一下你在搬砖,有一个小推车(缓冲区)。CPU负责往小推车里放砖(音频数据),声卡负责从车里取砖去砌墙(播放声音)。为了让声卡能源源不断地拿到砖,小推车里必须一直有存货。

什么是欠载?

如果CPU因为某些原因(比如在忙别的事情)没来得及往车里放砖,导致小推车空了,声卡过来取砖时发现没东西可取,这就叫“欠载”。
欠载后会发生什么? 通常情况下,ALSA驱动会检测到这个问题,并尝试快速“恢复”现场,比如重置指针、清空缓冲区等,这可能会导致你听到一声非常短暂的“咔哒”声,但播放会继续。

实际情况(猜测)

我的硬件驱动/固件(SOF)非常新,它的“欠载恢复”机制可能有Bug。当欠载发生时,驱动尝试恢复,但操作失败了,把自己搞“死机”了。这就解释了最初日志里的那句 snd_pcm_avail after recover: 断开的管道 (Broken pipe) —— “恢复后管道断开”,意思就是恢复失败了!

刑,既然咱猜是缓存区害得,那把缓存区调大不就好了!

问题解决

我们即将创建一个配置文件覆盖原有默认设置:

1
2
sudo mkdir -p /etc/pipewire/pipewire.conf.d/
sudo nano /etc/pipewire/pipewire.conf.d/99-custom-buffer.conf

数字-XXX是linux下约定俗成的配置文件(主要是在XXconf..d下的)的命名方式,前面的数字表示加载的先后顺序,数字越大越晚被加载,而后加载的配置会覆盖先加载的,所以99(几乎肯定)能覆盖默认配置。

写入以下内容:

1
2
3
4
context.properties = {
default.clock.quantum = 2048,
default.clock.min-quantum = 2048
}

这是把缓冲区大小设置为了2048,对于咱们32GB RAM的高端机器来说不值得一提😎

但是如果你想显得自己很阔气把这个值调的极大呢?

哈哈,我已经帮你试过了。

不会再有什么正面影响了,同时,音频的延迟性会上升,打游戏估计不爽,但对我没影响。实际播放其实影响也不大,因为pipewire似乎会选择一个较为合适的quantum.


更新:与sof-firmware交流,有以下新消息:

#5284中有人提出了类似的问题,他们修改了一个与alsa有关的参数,经过我的测试,可以奏效,方法如下:

新建文件~/.config/wireplumber/wireplumber.conf.d/50-alsa-config.conf,内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
monitor.alsa.rules = [
{
# Matches all SOF alsa sinks
matches = [
{
api.alsa.card.name = "~sof-*"
},
{
node.name = "~alsa_output.*"
}
]
actions = {
update-props = {
api.alsa.headroom = 1024
}
}
}
]

关于为什么要这么修改,我咨询了开发人员,感谢@kv2019i的耐心解答。

原文:

In short, headroom controls how close to the hardware read pointer Pipewire stays. In systems without audio DSPs, the data is consumed at a steady pace, so Pipewire can keep only very little...

剩余内容已隐藏

查看完整文章以阅读更多