1. 背景:
使用GoldenDict-ng的过程中,遇到词典内的音频播放时与默认输出设备不一致的问题,之前凑合着用一直没解决,今天有空就做一下排查。
| 名称 | 版本 |
|---|---|
| 系统内核 | 6.17.0-23-generic |
| 发行版 | Ubuntu26.04 |
| GoldenDict-ng | 26.1.1 |
2. 排查流程
2.1 先确认系统默认输出设备
pactl是PulseAudio控制工具。当前系统实际运行PipeWire,但通过pipewire-pulse提供PulseAudio兼容层,所以pactl仍可查看默认sink、播放流sink-input等信息。
sink原意是水槽,在音频系统里表示音频流的接收端,也就是输出设备。耳机、扬声器、HDMI输出都可以是sink。播放程序产生stream,stream连接到sink。
pactl get-default-sink输出为:
bluez_output.44:FB:76:27:4D:D7说明系统默认输出是蓝牙耳机。
2.2 再看 PipeWire/WirePlumber视角的设备与流
wpctl是WirePlumber/PipeWire控制工具。
WirePlumber是PipeWire的会话和策略管理器,负责默认设备、流连接、设备切换后的跟随策略等。
wpctl status得到如下输出:
......Default Configured Devices: Audio/Sink bluez_output.44:FB:76:27:4D:D7......Streams: GoldenDict-ng output_AUX0 > HDMI 0:playback_FL系统默认是耳机,但 GoldenDict-ng 的实际流走到了 HDMI。
2.3 查看 GoldenDict-ng 播放流的具体属性
pactl list sink-inputs查看有用的部分:
media.name = "GoldenDict-ng"node.target = "131"node.dont-reconnect = "true"module-stream-restore.id = "sink-input-by-media-role:music"node.target = "131" 表示该stream明确指定了输出设备为HDMI。
node.dont-reconnect = "true" 表示它不希望会话管理器自动重连到别的设备。
2.4 确认 131 是哪个设备
其实上面已经说明是哪个设备了,不过可以再查一下。
wpctl inspect 131截取有用的输出部分:
node.description = "AD107 High Definition Audio Controller Digital Stereo (HDMI)"node.name = "alsa_output.pci-0000_01_00.1.hdmi-stereo"node.nick = "HDMI 0"所以 GoldenDict-ng 的流实际绑定到了 HDMI。
2.5 查看 WirePlumber 的状态
排除系统记住了 GoldenDict-ng 走 HDMI 的默认行为。
rg -i "goldendict" ~/.local/state/wireplumber/这些文件用于保存默认节点、流音量/静音/声道等持久状态。
检查目的不是修复,而是确认是否存在 GoldenDict-ng 专门的路由记录。
结果没有看到 GoldenDict-ng 被绑定到 HDMI 的应用规则。
2.6 用普通 PipeWire 播放流做对照实验。
pw-play是PipeWire自带的播放测试工具,属于pw-cat工具组。它可以直接通过PipeWire创建播放流,适合做路由对照实验。
先生成静音音频:
ffmpeg -hide_banner -loglevel error -f lavfi -i "anullsrc=r=48000:cl=stereo" -t 20 -y "/tmp/gd-route-silence.wav"再播放:
pw-play "/tmp/gd-route-silence.wav"同时查看:
wpctl status对照输出显示:
pw-play output_FL > vivo TWS Air3 Pro:playback_FL output_FR > vivo TWS Air3 Pro:playback_FR这说明普通 PipeWire native 播放流会正确走耳机。
GoldenDict-ng 同时仍显示走 HDMI,问题不在 PipeWire 全局默认路由,而是 GoldenDict-ng/Qt 内部播放器路径。
3. 结论
通过查阅以下文档:
确认GoldenDict-ng 使用内部 FFmpeg 播放器时,音频解码本身并不是引发问题的原因。
问题出在内部播放器创建音频输出流时,Qt/PipeWire 路径把流固定到了 HDMI 输出,而不是当前系统默认耳机。
这通常是因为 Qt6 的多媒体后端在枚举音频设备时存在 bug,或者在与 PipeWire/ALSA 兼容层交互时获取了错误的默认设备 ID,导致其触发了 node.dont-reconnect = "true"
当前的方案是把 GoldenDict-ng 的音频播放器改为外部播放器:
mpv --no-video --no-audio-displaympv 一样用 FFmpeg/Libav 做解码,只不过 mpv 会自己创建 PipeWire/PulseAudio 音频流,所以走的输出设备跟当前系统的默认输出设备一致。
对于我自己做的配置维护脚本,针对
GoldenDict-ng,目前的设置为:只在检测到配置仍是
内部播放器 + FFmpeg时,设置播放源切换到外部mpv。如果已经改成
VLC、ffplay、其他外部播放器或其他内部后端,脚本不会做出更改,避免不正确的覆盖行为。