日期:2026-09-07
环境:Arch Linux + niri (Wayland/scrollable-tiling) + AMD Ellesmere 双屏
软件:wemeet-bin 3.26.10.401-1 + xdg-desktop-portal 1.22.1 (main) + xdg-desktop-portal-wlr 0.8.2


1. 问题现象

在 niri Wayland 环境下,腾讯会议无法正常共享屏幕:

  • GNOME portal 路径niri-portals.conf 指向 gnome 后端):共享后黑屏(无视频流)
  • wlr portal 路径(指向 xdg-desktop-portal-wlr):点击共享后弹出显示器选区后无反应,6 秒后自动重试

2. 根因分析

2.1 直接根因:wemeet 客户端 D-Bus 竞态 bug

wemeet 的定制模块 libscreen_share_module.so 存在异步调用链缺陷:

1
2
3
4
规范要求的正确顺序:                                              wemeet 实际执行:
CreateSession ──────────────┐ CreateSession ────┐
SelectSources ─────────────┼── (等待 Response) ──► SelectSources ────┼── (不等待!) ──► Start ✗
Start ─────────────────────┘ Start ─────────────┘

Start 的调用被直接放在 SelectSources 发出之后,没有等待其 Response 信号;只有更后面的 OpenPipeWireRemote 正确地放在了 onStartResponse 回调中。这是一个依赖竞态条件的未定义行为

2.2 为什么 GNOME 能用而 wlr 不能用

Portal 后端 SelectSources 行为 结果
gnome 立即返回,在 Start 中才弹窗等待用户选显示器 掩盖了 wemeet 的竞态缺陷 → 流程跑通(但 AMD 下黑屏另有颜色格式问题)
wlr 同步阻塞调用 slurp 等待用户选显示器 Start 提前到达时 SelectSources 尚未完成 → 必然失败

2.3 证据链

  • 后端三层验证全部通过:直连 XDPW impl(node 86)、主 portal 路由(node 75)、wemeet 精确参数复现 persist_mode=1, app_id=''(node 75)——排除 portal 后端问题
  • wemeet 14:04:03 发起 CreateSession(1_1822/wemeet1) + SelectSources,14:04:05 SelectSources 成功(选定 HDMI-A-2),但 XDPW 从未收到 start method invoked,14:04:11(恰 6 秒后)会话关闭并重试——对应客户端超时逻辑
  • dbus-monitor(Request 接口)+ journalctl -v 建立的 4 通道监控确认:问题在 wemeet 客户端侧,非路由层

3. 修复方案

采用社区逆向补丁 Matheritasiv/wemeet-screenshare-patch,该补丁精确针对 wemeet v3.26.10.401(与本地 wemeet-bin 3.26.10.401-1 完全匹配)。

3.1 应用补丁(仅 Hunk 0,修复 Start 竞态)

补丁含三个 Hunk:

  • Hunk 0(必需):将 dbusStart()dbusSelectSources() 中移到 onSelectSourcesResponse() 回调 → 修复异步链
  • Hunk 1a/1b(颜色格式 hook,AMD + force_mod_linear 场景不需要):当前系统已用 force_mod_linear=1 解决颜色问题,按补丁作者说明跳过(否则需要额外 LD_PRELOAD hook 且可能颜色错误)
1
2
3
4
5
6
7
8
9
# 1. 下载补丁:https://raw.githubusercontent.com/Matheritasiv/wemeet-screenshare-patch/main/patch.py
# 2. 生成只含 Hunk 0 的版本(或手动注释掉 PATCHES 中的 Hunk 1a/1b 与 libxcast.so 条目)
# 3. 备份原库
sudo cp /opt/wemeet/bin/modules/screen_share/libscreen_share_module.so \
/opt/wemeet/bin/modules/screen_share/libscreen_share_module.so.bak.20260907
# 4. 先 dry-run 验证字节精确匹配(实测 5 处 offset 全部 [OK])
python3 wemeet-patch-hunk0.py /opt/wemeet --dry-run
# 5. 应用
sudo python3 wemeet-patch-hunk0.py /opt/wemeet

应用结果:

1
2
3
4
5
6
[PATCH]    0x0043d2fa: 00 => 5d
[PATCH] 0x0043d331: 88f7 => 60fb
[PATCH] 0x0043d336: 83c718488b8588f7ffff48 => 89fe4883c618e910000000
[PATCH] 0x0043d357: 0000 => e208
[PATCH] 0x0043dc38: e8c305d9 => e9ecf6ff
→ Hunk #0 applied (20 byte(s))

3.2 恢复 wlr 显示器选择界面

调试期间为绕过竞态,曾将 wlr 配置改为 chooser_type=none + output_name=HDMI-A-2(固定输出、跳过 slurp)。补丁生效后需移除这两行以恢复选区界面:

1
2
3
4
5
# ~/.config/xdg-desktop-portal-wlr/config
[screencast]
force_mod_linear=1 # 保留:AMD Ellesmere 线性缓冲,解决颜色问题
# chooser_type=none # 已删除(恢复 slurp 选择)
# output_name=HDMI-A-2 # 已删除
1
systemctl --user restart xdg-desktop-portal-wlr

3.3 重启 wemeet

必须完全退出 wemeet 进程再重新启动(运行中的进程仍持有旧库的内存映射,补丁只对磁盘文件生效)。


4. 修复后行为

  • 点击”共享屏幕” → 弹出 slurp 显示器选择界面
  • 选定显示器 → 正常出画面
  • 双屏(HDMI-A-1 / HDMI-A-2)均可选 ✓

5. 回滚方法

1
2
sudo cp /opt/wemeet/bin/modules/screen_share/libscreen_share_module.so.bak.20260907 \
/opt/wemeet/bin/modules/screen_share/libscreen_share_module.so

6. 注意事项

  1. 包升级后需重新打补丁wemeet-bin 更新后库文件被覆盖,需重新执行第 3 节步骤(先 dry-run 确认新版本字节仍匹配;若补丁作者未跟进新版本,需等待其更新)
  2. 只打 Hunk 0 无需 LD_PRELOAD hook:补丁 README 明确说明,仅当需要颜色转换(Hunk 1a/1b)时才需 export LD_PRELOAD=.../libhook.so
  3. 快捷操作:完整打补丁命令(含下载)
1
2
3
export https_proxy=http://10.255.254.153:7890   # 若需代理
curl -sL -o /tmp/patch.py https://raw.githubusercontent.com/Matheritasiv/wemeet-screenshare-patch/main/patch.py
python3 /tmp/patch.py /opt/wemeet --dry-run && sudo python3 /tmp/patch.py /opt/wemeet

参考

2026-09-07

⬆︎TOP