我把 Pixelbook Go 在 Arch 上的声音修好了,但真正的问题其实不是声音
一个现实的提醒(比较关键):
这一篇,不是我自己写的,不是正经文章,而是 gpt 写的。gpt 已经把文字钉死了,文字已经被固定在一种完成态里。需要明确的一点是:任何改动,哪怕只是一句,都会破坏它的完整性。
——
技术向的博客已经写好,这篇文的主线是三层排障链路,systemd --user 会话、PipeWire 双实例冲突、最后才是 UCM 没自动匹配导致的手动 mixer 初始化,整体偏技术复盘,不是泛泛经验贴。我已经再收了一刀,把两三处会露痕迹的表述改掉,然后就直接落到了 ~/Documents。如果你要,我下一步可以直接继续帮你把这篇再压成更像博客平台发布版的标题和开头,或者顺手补一版更硬核的命令附录。
真的好上头,这一步还没有提交。
事情是这样的。
我最近把一台 Pixelbook Go 刷成了 Arch Linux,桌面用的是 Hyprland。键盘这块其实还行,音量键按下去也有反应,keyd 能认出来,说明输入链路没死。
但就是没声音。
更烦的是,这种没声音不是那种一眼就能看出来的没声音。wpctl status 能看到 PipeWire 在跑,音量键也不是坏的,系统表面上看着一切正常,结果扬声器就是一句话不说。
我一开始以为这是个典型的 Chromebook on Linux 驱动适配问题,想着八成又是某个 codec、某个 topology、某个 UCM profile 没挂上。这个判断不能说全错,但如果一上来就扎进 codec 和 mixer,那基本会把自己带沟里去。
因为这次真正的坑,一共埋了三层。
而且是一层套一层。
最外面那层,是会话。
Pixelbook Go 这台机器跑 Arch 之后,我最开始是直接从 TTY 拉起 Hyprland。这样做表面上很直接,实际上会让整个 systemd --user 会话状态变得不对劲。后面我去看用户服务的时候,systemctl --user 本身就不正常,这其实已经是一个很重的信号了。
音频栈在现代 Linux 桌面上,真的不是一个单点程序。你看到的是 PipeWire,背后还挂着 WirePlumber、socket 激活、用户会话、session bus 这一串东西。只要用户会话没接好,后面的现象就会全部变形。
这也是我这次排障里第一个真正有用的修复。
不要直接从 TTY 粗暴拉 Hyprland,改成通过 uwsm 启动,让桌面会话老老实实接进 systemd --user。
我这边最后能工作的做法,是把登录 shell 启动配到 .bash_profile 和 .zprofile,然后通过 uwsm start hyprland.desktop 去拉起图形会话。做完这一步之后,systemctl --user 终于恢复正常,PipeWire 用户服务也能按常规方式管理了。
到这里,事情看起来像是快结束了。
其实没有。
因为第二层坑很快就出来了。
我去看 pipewire.service 的时候,最开始那个报错看着很唬人,像是什么 status=245/KSM,一眼望过去很像 systemd 自己炸了,或者某种权限、内存、session 级别的问题。可这种报错很多时候都只是烟雾弹,真正有价值的信息还得去翻更具体的日志。
然后我就看到了这一句。
unable to lock lockfile '/run/user/1000/pipewire-0.lock' (maybe another daemon is running)
这句话一出来,味道就完全变了。
不是 PipeWire 起不来。
是有两个 PipeWire 在抢同一个位置。
也就是说,前面那个看起来很抽象的错误,背后其实是一个很具体、很土、也很常见的问题。我一边在 Hyprland 的 exec-once 里手动拉 PipeWire 和 WirePlumber,一边 systemd --user 又在按 socket 激活自己的那一套。两个实例同时起,锁文件和 socket 自然就撞了。
这类问题很容易把人骗进去。因为你会下意识觉得,音频不工作,那我手动自启动一下 PipeWire 总没错吧。
错就错在这儿。
在已经有 systemd --user 的前提下,手搓自启动反而是在破坏系统原本的控制面。
所以第二步修复反而很简单,甚至有点朴素。
把 Hyprland 里手动启动 PipeWire 和 WirePlumber 的逻辑删掉。
杀掉残留进程。
清掉 /run/user/1000/ 下面残留的 lock 和 socket。
然后只保留系统原生那条链路,
1systemctl --user start pipewire.socket
2systemctl --user start pipewire-pulse.socket
3systemctl --user start wireplumber.service
做到这一步之后,再去看状态,很多东西终于像话了。
wpctl status 正常。
pactl info 正常。
pipewire 和 pipewire-pulse 都在。
看上去像是大局已定。
结果还是没声音。
到这儿,第三层坑才真正露头。
这时候再去看默认 sink,发现系统落在了 alsa_output.platform-avs_max98373.18.auto.stereo-fallback。这个名字里最关键的不是 alsa_output,也不是 max98373,而是后面那个 auto.stereo-fallback。
这基本就在告诉你,PipeWire 确实起来了,但它没拿到一个干净、明确、被 UCM 正确初始化过的设备路径。它退回了 fallback。
也就是说,服务层的问题已经修到差不多了,设备路径层的问题还在。
于是我开始回头看这台机器的音频硬件。
Pixelbook Go 这边暴露出来的几个关键 card 是这样的,
10 [MAX98373]
22 [DMIC]
34 [DA7219]
这组组合挺典型,一个 MAX98373 做扬声器功放,一个 DA7219 做 codec,再加一个 DMIC 数字麦克风。固件和拓扑文件其实也都在,像 da7219-tplg.bin.zst、max98373-tplg.bin.zst 这些都没缺。更关键的是,UCM 文件也不是没有。
/usr/share/alsa/ucm2/Intel/avs/avs_max98373/Google-Atlas-1.0.conf
/usr/share/alsa/ucm2/Intel/avs/avs_max98373/Google-Atlas-1.0-HiFi.conf
文件明明都在。
但 alsaucm listcards 是空的。
这个现象很重要,因为它几乎把问题钉死了。不是你机器上没有 UCM,而是 ALSA 没把这套 Google-Atlas-1.0 profile 自动绑定到当前暴露出来的 AVS 声卡上。于是上层的 PipeWire 只能接一个 fallback sink,扬声器路径并没有被完整初始化。
说真的,走到这一步的时候,排障的味道就已经从桌面配置问题,彻底变成硬件路径初始化问题了。
也就是 mixer。
接下来这段过程,是这次修复里最工程师、也最不优雅的部分。
我没有等 UCM 自己突然变好,我直接去看 amixer 暴露出来的控制项,一路试到扬声器真正出声为止。真正有用的控制主要集中在两张卡上。
DA7219 负责把播放路径和输出 routing 接起来。
MAX98373 负责把扬声器功放那一侧真正点亮。
最后有效的命令大概是这一组。
1amixer -c MAX98373 cset name='Left Output Voltage' 5
2amixer -c MAX98373 cset name='Right Output Voltage' 5
3amixer -c MAX98373 cset name='Left DHT Switch' on
4amixer -c MAX98373 cset name='Right DHT Switch' on
5amixer -c MAX98373 cset name='Left BDE Switch' on
6amixer -c MAX98373 cset name='Right BDE Switch' on
7amixer -c MAX98373 cset name='Left VI Sense Switch' on
8amixer -c MAX98373 cset name='Right VI Sense Switch' on
9amixer -c MAX98373 cset name='Left Spk Switch' on
10amixer -c MAX98373 cset name='Right Spk Switch' on
11amixer -c MAX98373 cset name='Left DAI Sel Mux' Left
12amixer -c MAX98373 cset name='Right DAI Sel Mux' Right
13amixer -c MAX98373 sset 'DSP' 100%
14
15amixer -c DA7219 cset name='Playback Digital Switch' 1
16amixer -c DA7219 cset name='Playback Digital Volume' 111
17amixer -c DA7219 cset name='Out DACL Mux' DAIL
18amixer -c DA7219 cset name='Out DACR Mux' DAIR
19amixer -c DA7219 cset name='Mixer Out FilterL DACL Switch' 1
20amixer -c DA7219 cset name='Mixer Out FilterR DACR Switch' 1
21amixer -c DA7219 cset name='ST Mixer Out FilterL Out FilterL Switch' 1
22amixer -c DA7219 cset name='ST Mixer Out FilterR Out FilterR Switch' 1
23amixer -c DA7219 cset name='Headphone Jack Switch' off
这组命令里有几个细节我觉得很关键。
第一,MAX98373 的 DSP 初始值其实是 0。
第二,Left DAI Sel Mux 和 Right DAI Sel Mux 最开始在 LeftRight,后来改成左右分离之后,路径才更像一条真正能工作的 speaker route。
第三,Left Spk、Right Spk、VI Sense、DHT、BDE 这些看着有点奇怪的开关,实际上都跟功放路径点亮有关。你不把这些开起来,PipeWire 就算活着,也只是活着。
不会唱歌。
还有个很有意思的细节是,我中间也试过一些看上去很合理的控件名字,比如 Left Digital Vol Sel、Right Digital 这种,结果根本不存在,或者说这台机器暴露出来的 mixer element 名字和我预期的不一致。这个瞬间特别像在修一台别人魔改过的车,图纸上那个按钮应该在这儿,结果你伸手过去摸,发现面板上压根没有。
所以这次修复真正让我出声的,不是什么一个神奇命令,而是一件更朴素的事。
接受现实里暴露出来的 mixer 名字。
不要拿想象里的名字修真实机器。
等这套初始化打完,再跑一遍,
1pw-play /usr/share/sounds/freedesktop/stereo/bell.oga
扬声器终于响了。
那一刻其实还挺爽的。
但这事并没有真的结束。
因为如果你把整条链路回头看一遍,会发现我这次修好的,不是一个单一的音频 bug,而是一整套跨层问题。
最上面,是桌面会话没正确接进 systemd --user。
中间,是 PipeWire 被手动自启动和 socket 激活同时拉起,形成双实例冲突。
最底下,才是 ALSA UCM 没把 Google-Atlas-1.0 自动挂到这台 Pixelbook Go 暴露出来的 AVS 设备上,逼得我只能手动初始化 MAX98373 和 DA7219 的 mixer 路径。
这也是为什么我觉得,这类 Linux 桌面硬件问题最容易把人带偏的地方,就在于表面症状永远长得像最底层那个问题。
你会先盯着 codec。
先盯着 firmware。
先盯着 topology。
但真正该先问的,往往是更无聊的三个问题。
用户会话正常吗。
服务是谁在拉。
设备路径到底有没有被正确初始化。
回到这台 Pixelbook Go,这次的工作态其实还是一种工程上的折中。现在扬声器能正常出声,wpctl status 和 pactl info 也都在合理状态,默认 sink 会落到 alsa_output.platform-avs_max98373.18.auto.stereo-fallback,日常使用已经没问题。
但我心里很清楚,这还不是一个真正干净的最终解。
因为现在的结果依赖手动 mixer 初始化。
不是依赖一条自动生效的 UCM 激活路径。
也就是说,后面如果内核、alsa-lib、AVS 相关组件继续更新,最值得盯的不是声音会不会再坏一次,而是 alsaucm listcards 有没有哪天终于不再是空的,Google-Atlas-1.0 能不能真的自动挂上来。
如果那一天到了,这篇文章里的最后一段命令,反而应该被删掉。
因为最好的修复,从来不是你记住了一长串 amixer。
而是系统终于自己知道,该怎么让一对扬声器开口说话。