






























本文接上篇在ThinkBook 16+ 2025上安装archlinux驯服记录【基本信息与触摸板修复】。按理说,本文标题本应是《在ThinkBook 16+ 2025上安装archlinux驯服记录【音频修复】》的,考虑到此问题可能影响到较多机型,故修改为更通用的标题。
闲话少说,开始解决问题。
我有时候会用电脑播放音乐,这些音乐都是无损flac格式的盗版音乐。在我的上一台电脑上,一切正常。在这台新款的ThinkBook 16+ 2025上,问题表现为:
播放音乐的时候,能放一会儿(约30秒),然后就没有声音了,插电也是这样
声音中断后KDE设置显示“已失去与声音服务器的连接”,VLC启动时加载时间比正常情况久很多,音量被自动设置到0,且进度条不开始。
这种情况令我糟心,为了立刻重新听上音乐,我通过systemctl重启了pipewire与wireplumber服务,重新打开vlc,播放了2~3分钟后,同样的声音中断发生了。
作为archlinux用户,我的软件包都是滚动更新的最新版本,所以显然上游还没有修复这个问题,只能自己动手了。
我查看了与声卡有关的日志,如下:

从日志上看,驱动能够正常识别与处理设备,而在播放过程中,pipewire或其下的某个组件崩溃了,造成了broken pipe
考虑到linux音频系统的混乱与复杂(如下图),我没有能力深度调试,决定先进行“猜测”。

我首先怀疑是省电配置导致的,因为我希望延长续航时间,所以安装了tlp并且手动配置了许多省电选项。
所以我直接修改了/etc/tlp.conf,找到了与声卡节能有关的配置并修改为以下内容:
1 | SOUND_POWER_SAVE_ON_BAT=0 |
这意味着在交流供电与电源供电时都不会尝试让声卡通过挂起等方式节能。根据我的经验与直觉,linux下硬件不能正常工作,常常是和suspend(挂起)与recover(恢复)有关的。所以我满心期待以为问题解决了。
然后我跟着音乐哼着哼着,音乐停了。
我寻思是不是有内核参数在作祟,于是又折腾了好久。可是并没有用。
就在这个时候我注意到一个此前忽略的细节:虽然连续播放的音乐会中断,但是如果不播放音乐,系统的提示音效在开机后多久,甚至睡眠又唤醒后都是正常的。
也就是说长音频不行而短音频没有影响。
诡异吧?
这个玄学问题,最终还要归结于“缓冲区”。
想象一下你在搬砖,有一个小推车(缓冲区)。CPU负责往小推车里放砖(音频数据),声卡负责从车里取砖去砌墙(播放声音)。为了让声卡能源源不断地拿到砖,小推车里必须一直有存货。
如果CPU因为某些原因(比如在忙别的事情)没来得及往车里放砖,导致小推车空了,声卡过来取砖时发现没东西可取,这就叫“欠载”。
欠载后会发生什么? 通常情况下,ALSA驱动会检测到这个问题,并尝试快速“恢复”现场,比如重置指针、清空缓冲区等,这可能会导致你听到一声非常短暂的“咔哒”声,但播放会继续。
我的硬件驱动/固件(SOF)非常新,它的“欠载恢复”机制可能有Bug。当欠载发生时,驱动尝试恢复,但操作失败了,把自己搞“死机”了。这就解释了最初日志里的那句 snd_pcm_avail after recover: 断开的管道 (Broken pipe) —— “恢复后管道断开”,意思就是恢复失败了!
刑,既然咱猜是缓存区害得,那把缓存区调大不就好了!
我们即将创建一个配置文件覆盖原有默认设置:
1 | sudo mkdir -p /etc/pipewire/pipewire.conf.d/ |
数字-XXX是linux下约定俗成的配置文件(主要是在XXconf..d下的)的命名方式,前面的数字表示加载的先后顺序,数字越大越晚被加载,而后加载的配置会覆盖先加载的,所以99(几乎肯定)能覆盖默认配置。
写入以下内容:
1 | context.properties = { |
这是把缓冲区大小设置为了2048,对于咱们32GB RAM的高端机器来说不值得一提😎
但是如果你想显得自己很阔气把这个值调的极大呢?
哈哈,我已经帮你试过了。
不会再有什么正面影响了,同时,音频的延迟性会上升,打游戏估计不爽,但对我没影响。实际播放其实影响也不大,因为pipewire似乎会选择一个较为合适的quantum.
更新:与sof-firmware交流,有以下新消息:
在#5284中有人提出了类似的问题,他们修改了一个与alsa有关的参数,经过我的测试,可以奏效,方法如下:
新建文件~/.config/wireplumber/wireplumber.conf.d/50-alsa-config.conf,内容如下
1 | monitor.alsa.rules = [ |
关于为什么要这么修改,我咨询了开发人员,感谢@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 data in the buffer (to minimize latency). When you have a DSP, power can be saved by not transferring data all the time, but moving data in bigger chunks. What happens in your case, that Pipewire keeps too little data in the audio buffer and a single DSP transfer (from main memory to DSP memory) can dry out the buffer and cause an xrun (there is nothing to play).
We are not talking about large buffers here. With regular PCMs, typical DSP configuration will be a 4ms buffer, so small addition to headroom will be enough to avoid xruns.
Pipewire is doing this to minimize latency, but in this case, it is too aggressive by default and ends up causing continuous xruns.
We do have a separate question how to solve this better in the longer term, but currently we don't have means in ALSA interface to describe (to apps like Pipewire) what is the maximum DMA burst size.
中文:
简而言之,headroom 控制着 Pipewire 与硬件读取指针的距离。在没有音频 DSP 的系统中,数据以稳定的速度被消耗,因此 Pipewire 只需在缓冲区中保留极少的数据(以最小化延迟)。当系统配备 DSP 时,可以通过不持续传输数据,而是以更大的块为单位传输数据来节省电量。在你的情况下,问题在于 Pipewire 在音频缓冲区中保留的数据太少,一次 DSP 传输(从主内存到 DSP 内存)就可能耗尽缓冲区,从而导致 xrun(没有可播放的内容)。
这里我们说的并不是大型缓冲区。对于常规的 PCM,典型的 DSP 配置会采用 4 毫秒的缓冲区,因此稍微增加一点 headroom 就足以避免 xrun。
Pipewire 这样做是为了最小化延迟,但在这种情况下,其默认设置过于激进,最终导致了持续的 xrun。
我们另外有一个问题,即如何在长期内更好地解决这个问题,但目前我们在 ALSA 接口中还没有办法向 Pipewire 这类应用程序描述最大 DMA 突发大小。
也就是说问题是出在alsa与pipewire的协商。而sof-firmware本身并没有问题。让我们等待上游修复吧
最后重启电脑,或者重启服务都可以
1 | systemctl --user restart pipewire.service |
以上内容算是一个对我可用的workaround,我不知道别人有没有遇到过这样的问题,也不知道这样能不能奏效。
如果你也遇到了这样的问题,希望你在评论区告诉我这样的方案能不能奏效。
同时为了帮助到更多人,我在sof的github仓库上打开了一个issue,不知道上游会怎么说。
就到这里吧。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。