KDE 下区分多个 Electron 音频流:用 PipeWire 规则修正 Chromium 元数据
在 KDE Plasma 的音量控制里,多个 Electron 应用常常会被折叠成同一个 Chromium:明明是 Bilibili 和 YesPlayMusic 在同时播放,界面里却只有两个难以分辨的 Chromium 流。问题不在 KDE 没有拿到流,而是 Electron/Chromium 向 PipeWire-Pulse 提交的应用名过于通用。下面记录一次从属性排查、错误方案验证,到做成用户级服务的完整处理过程。
问题不是没有流,而是显示字段选错了
先不要猜测应用名,直接读取当前播放流:
pactl list sink-inputs
wpctl status
wpctl inspect <PipeWire-node-id>一条 Bilibili 音频流的关键属性如下:
重点是 application.process.binary。在这台 Arch Linux + KDE Plasma + PipeWire 1.6.8 的环境中,Bilibili、YesPlayMusic、QQ、微信等 Chromium/Electron 程序的 application.name 可以完全相同,但 application.process.binary 分别是 bilibili、yesplaymusic、qq、wechat。这正是可以交给规则匹配的字段。
先验证一个看似合理、实际上走不通的方向
最开始的想法是:监听到 sink input 后,直接把它改名。这个思路很自然,但本机 pactl 并没有修改已有 sink-input 属性的命令:
pactl update-sink-input-proplist 608 application.name=bilibili
# No valid command specified.随后也验证了 pw-cli set-param <node-id> Props ...。命令能够返回 Props 对象,但 PipeWire-Pulse 创建的流不会因此改写 application.name。这说明不能依赖“流已经出现后再从外部改属性”:KDE 要显示的名字应该在 PulseAudio 兼容层创建流时就设置好。
利用 pipewire-pulse 的 pulse.rules 在创建阶段改名
PipeWire 自带的 /usr/share/pipewire/pipewire-pulse.conf 已经定义了 pulse.rules。规则可以按客户端 / 流属性匹配,并通过 update-props 覆盖属性。用户级配置放在:
~/.config/pipewire/pipewire-pulse.conf.d/90-kde-electron-audio-renamer.conf例如对 Bilibili 的最小规则:
pulse.rules = [
{
matches = [
{ application.name = "Chromium" application.process.binary = "bilibili" }
]
actions = {
update-props = {
application.name = "bilibili"
node.name = "bilibili"
}
}
}
]规则的两个匹配条件必须同时成立。只按 application.process.binary 匹配会影响不应处理的音频客户端;只按 application.name = Chromium 则仍然无法区分不同 Electron 程序。规则生效后,再次检查即可看到:
pactl list sink-inputs | rg 'application.name|application.process.binary|node.name'
# application.name = "bilibili"
# application.process.binary = "bilibili"
# node.name = "bilibili"把发现和规则维护做成用户级服务
手工为每一个程序写规则不难,但新增 Electron 应用后又会回到 Chromium。最终实现选择了一个用户级 systemd 服务,它由两部分组成:
用
pactl subscribe监听 sink-input 事件,并在启动时先扫描一次现有流。只取
application.name = Chromium的流,再从application.process.binary中提取安全的二进制名;electron、chromium、chrome、空值等通用名称会被忽略。把第一次遇到的二进制名写入状态文件,重新生成
pulse.rules配置。
服务安装位置与启动命令如下:
install -Dm755 kde-electron-audio-renamer.sh \
"$HOME/.local/bin/kde-electron-audio-renamer"
install -Dm644 kde-electron-audio-renamer.service \
"$HOME/.config/systemd/user/kde-electron-audio-renamer.service"
systemctl --user daemon-reload
systemctl --user enable --now kde-electron-audio-renamer.service服务本身不需要 root 权限。规则保存在 ~/.config/pipewire/pipewire-pulse.conf.d/,已识别的程序名保存在 ~/.local/state/kde-electron-audio-renamer/binaries。因此登录后服务会自动启动,已有规则也会继续保留。
为什么首次识别新应用仍然需要一次短暂中断
这里有一个不能回避的边界:pulse.rules 是创建流时读取的,PipeWire-Pulse 不会可靠地热加载这条规则并改写已经存在的客户端流。服务发现一个从未见过的二进制名后,会执行一次:
systemctl --user restart pipewire-pulse.service当前音频会短暂中断,客户端随后重新连接,并带着新的 application.name 出现在 KDE 音量控制中。这个重启只发生在某个新二进制名第一次被发现时;例如 bilibili 和 yesplaymusic 已经写入规则后,之后启动它们不会再触发重启。
如果完全不能接受这一次中断,唯一可靠的替代方式是在启动应用之前就注入属性,例如用包装启动器设置 PULSE_PROP_OVERRIDE,或者提前手工写好静态 pulse.rules。对任意已运行、且此前未知的 Electron 流做“无中断即时改名”,在现有 PipeWire-Pulse/PulseAudio 工具链中并没有稳定接口。
验证和排错
systemctl --user status kde-electron-audio-renamer.service
journalctl --user -u kde-electron-audio-renamer.service -f
pactl list sink-inputs
wpctl status日志出现 discovered Chromium stream binary: yesplaymusic 说明服务已捕获到新程序。随后再次查看 pactl list sink-inputs,应确认 application.name、application.process.binary 和 node.name 都是同一个实际程序名。这样 KDE 的每个音频滑块才会真正对应到具体应用,而不是一排无法分辨的 Chromium。
完整脚本、systemd 服务和规则模板已整理在 LuorixDev/kde-electron-audio-renamer。这套方案的核心不是再去猜 PipeWire 的临时 ID,而是利用已经存在但默认未被 KDE 展示的 application.process.binary,在流的创建阶段建立稳定的显示身份。