RustDesk + HDMI 诱骗器:远程听不到本机声音的修复记录
环境:Win11 控制端 → Ubuntu 22.04 被控端,被控为 X11,本机插 HDMI 诱骗器(虚拟显示器),音频走 PipeWire(界面显示为 PulseAudio on PipeWire)。
现象:远程连接后,本机明明在放视频/音乐,对端却听不到;或曾经修好过,重启后又没声;或安装 Wine / Win32 播放器后,远端再次听不到本机声音。
根因(本次已核实)
- RustDesk 采的是「某个声卡输出的 Monitor」,不是「物理麦克风」。若采到 板载 analog 输出的 monitor,而实际播放却在 HDMI 诱骗器,对端就会静音(或只有环境噪声)。
- WirePlumber / stream-restore 会按应用名记住 RustDesk 上次用的采集端,容易一直钉在
analog-stereo上;仅改「默认信源」有时不会自动改掉已建立的 RustDesk 录音流。 - 播放器输出也必须走同一条 HDMI sink。安装 Wine 后,新出现的 Wine / PotPlayer / Win32 应用播放流可能被旧路由记忆影响,跑到 analog 或其它输出;此时 RustDesk 即使已经采 HDMI monitor,也会因为 HDMI monitor 没有实际音频样本而静音。
- 当时若没有应用在出声,monitor 上也没有波形,听起来也像「没声音」——需本机有播放器在播,且采集端对准正在出声的那条 HDMI。
现场诊断命令(建议保留)
# 默认 sink / source、设备是否在跑
pactl info | head -20
pactl list short sinks
pactl list short sources
# 谁在「播放」(应看到浏览器 / PotPlayer / Wine 应用,Sink 应对应 HDMI)
pactl list sink-inputs
# 谁在「录音」(应出现 application.name = RustDesk)
pactl list source-outputs
# PipeWire 视角看路由:播放器 output 应到 HDMI playback,RustDesk input 应来自 HDMI monitor
wpctl status
# 看 RustDesk 绑定的信源索引:信源一行应对应 hdmi 的 .monitor
LANG=C pactl list source-outputs | grep -E '^(Source Output|Source:|application.name)'判读要点:
pactl list short sources里 HDMI 诱骗器一般是带hdmi且以.monitor结尾的条目(例如alsa_output....hdmi-stereo.monitor)。pactl list sink-inputs里播放器 / Wine 应用的Sink:应指向 HDMI sink;若播放流去了 analog,HDMI monitor 仍然可能是全 0。- 在
source-outputs里若看到 RustDesk 的Source:指向 analog 的 monitor,而本机声音实际从 HDMI 出来,就需要把该录音流 挪到 HDMI 的 monitor。 - 若 RustDesk 已指向 HDMI monitor 但远端仍无声,应先用测试音确认 HDMI monitor 是否真的有波形;若测试音有波形,重点检查控制端 RustDesk 的音频开关/播放设备。
一次性手工修复(当场救急)
把 <HDMI_MONITOR> 换成你机器上 pactl list short sources 里那条 hdmi 的 .monitor 名称,把 <HDMI_SINK> 换成 pactl list short sinks 里那条 hdmi 输出名称。
# 先设默认播放为 HDMI,默认采集为 HDMI monitor
pactl set-default-sink '<HDMI_SINK>'
pactl set-default-source '<HDMI_MONITOR>'
# 若播放器 / Wine 应用已经在播,查 sink-inputs 里的「Sink Input #数字」并挪到 HDMI
pactl move-sink-input <SINK_INPUT_ID> '<HDMI_SINK>'
# 若 RustDesk 已在采,查 source-outputs 里的「Source Output #数字」并挪到 HDMI monitor
pactl move-source-output <SOURCE_OUTPUT_ID> '<HDMI_MONITOR>'改完后:控制端断开再连一次,并在本机播放一段有声音的内容验证。
持久化(本机已部署)
架构总览
应用播放 ─▶ rustdesk_capture (虚拟 sink, 受系统音量控制)
│
├─▶ monitor ─▶ RustDesk 采集 ─▶ [软件音量镜像] ─▶ 远端
│
└─▶ loopback (固定 100%, 低延迟) ─▶ HDMI 诱骗器之所以走虚拟 sink 而不是直接采 HDMI monitor:HDMI sink 的 monitor 抓取点位于硬件音量节点之前,系统音量条对远端音频完全无效(远端听到的永远是满音量)。
但 PipeWire 的 monitor port 始终位于 sink 音量节点之前,单纯改虚拟 sink 音量也无法衰减 monitor 输出。所以本方案在 keep 脚本里把虚拟 sink 当前音量实时镜像到 RustDesk 自身 source-output 的软件音量——RustDesk 采集流末端的软件衰减直接作用于发送给远端的 PCM 数据,调节系统音量条因此可以真正控制远端音量。
层 1:PipeWire 虚拟 sink(loopback 模块)
文件 ~/.config/pipewire/pipewire.conf.d/99-rustdesk-capture-sink.conf:
context.modules = [
{ name = libpipewire-module-loopback
args = {
node.description = "RustDesk Capture Sink"
capture.props = {
node.name = "rustdesk_capture"
node.nick = "RustDesk Capture"
media.class = "Audio/Sink"
audio.position = [ FL FR ]
priority.session = 3000
priority.driver = 3000
node.latency = "256/48000"
}
playback.props = {
node.name = "rustdesk_capture_loopback"
media.name = "RustDesk Capture → HDMI"
node.passive = true
target.object = "alsa_output.pci-0000_08_00.1.hdmi-stereo"
stream.dont-remix = true
node.latency = "256/48000"
}
}
}
]要点:
priority.session = 3000保证它优先于 HDMI(2000)和 analog,被自动选为默认 sink/source。node.latency = "256/48000"≈ 5.3 ms,loopback 两端总延迟约 10 ms,听感上无明显延迟。如仍觉得延迟,可降到128/48000(约 2.7 ms,CPU 占用略升)。target.object写死了 HDMI 节点名;换显卡时需更新此处。
修改后 systemctl --user restart pipewire pipewire-pulse 立即生效。
层 2:WirePlumber 优先级规则(备份兜底)
~/.config/wireplumber/main.lua.d/51-hdmi-priority.lua:把 HDMI 节点 priority.session 抬高到 2000。即使虚拟 sink 没起来(pipewire conf 出错时),HDMI 仍是次优默认设备,远端不会因为默认设备掉到 analog 而完全失声。
alsa_monitor.rules = alsa_monitor.rules or {}
table.insert(alsa_monitor.rules, {
matches = {
{ { "node.name", "matches", "alsa_output.*hdmi*" } },
{ { "node.name", "matches", "alsa_input.*hdmi*" } },
},
apply_properties = {
["priority.session"] = 2000,
["priority.driver"] = 2000,
},
})修改后 systemctl --user restart wireplumber 生效。
层 3:systemd keep 服务(路由 + 音量镜像)
~/.local/bin/rustdesk-hdmi-audio-keep.sh 由 ~/.config/systemd/user/rustdesk-hdmi-audio.service 拉起,每 2 秒:
- 将默认 sink/source 设为虚拟
rustdesk_capture/rustdesk_capture.monitor; - 取消 monitor 静音;强制 HDMI sink 音量 100%、不静音(避免双重衰减);
- 把所有普通 sink-input 挪到
rustdesk_capture(loopback 自身被识别后跳过,避免环路); - 把
application.name = "RustDesk"的 source-output 挪到rustdesk_capture.monitor,并将虚拟 sink 当前音量值/静音状态镜像到该 source-output 的软件音量上——这是远端音量真正受控的关键。
| 项目 | 路径 |
|---|---|
| 虚拟 sink 配置 | ~/.config/pipewire/pipewire.conf.d/99-rustdesk-capture-sink.conf |
| WirePlumber 规则 | ~/.config/wireplumber/main.lua.d/51-hdmi-priority.lua |
| keep 脚本 | ~/.local/bin/rustdesk-hdmi-audio-keep.sh |
| systemd unit | ~/.config/systemd/user/rustdesk-hdmi-audio.service |
常用命令:
systemctl --user daemon-reload
systemctl --user enable --now rustdesk-hdmi-audio.service
systemctl --user status rustdesk-hdmi-audio.service --no-pager
journalctl --user -u rustdesk-hdmi-audio.service -f停用:systemctl --user disable --now rustdesk-hdmi-audio.service
换硬件注意:更换主板/显卡后,99-rustdesk-capture-sink.conf 里的 target.object 需更新为新的 HDMI 节点名(pactl list short sinks 第 2 列);其他配置使用 hdmi 通配符匹配,无需修改。
使用侧注意
- 远程要听到本机系统声,本机需有应用正在向 HDMI(或当前默认输出)播放;仅「连着没播」时 monitor 上也是空的。
- 安装 Wine / Win32 播放器后,优先检查播放流是否真的去了 HDMI:
pactl list sink-inputs或wpctl status。 - 控制端可在 RustDesk 工具栏检查 音频相关选项(版本不同菜单位置可能不同);根本对齐仍是被控端 PipeWire 上「播放流进 HDMI、RustDesk 采 HDMI monitor」。
记录日期以本机整理为准;修改服务后记得 daemon-reload 再 enable --now。


评论 (0)