问题现象

大概一两个月前,在 KDE Plasma Wayland 环境中使用腾讯会议时,突然无法正常查看其他参会者共享的屏幕了,这个情况困扰了我很久,导致经常不得不用手机来参会。今天有空闲时间,上网搜索了一下,终于找到了解决方案。

本机环境大致如下:

  • Arch Linux
  • KDE Plasma Wayland
  • wemeet-bin 3.26.10.401-1
  • Intel 核显 + NVIDIA RTX 4060 Max-Q 混合显卡
  • xdg-desktop-portal-kde、PipeWire、WirePlumber

原因定位

此前腾讯会议也有问题,根据AUR对应包的评论区中的建议,修改方案是添加一个环境变量:

1
__EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/50_mesa.json

这个主要是之前的解决方案,很长一段时间内是管用的。但是最近失灵了。根据Arch Linux CN论坛中网友的说法,是以下两个地方出现问题:

1. Wemeet 的 DBus 调用存在时序问题

屏幕共享请求应该依次完成:

1
CreateSession → SelectSources → Start → OpenPipeWireRemote

但当前版本在 SelectSources 完成前就调用了 Start。某些 portal 后端会容忍这个竞态,另一些后端则会导致共享请求失败或没有视频数据。

2. PipeWire 颜色格式协商不兼容

Wemeet 原本硬编码了 BGRx 等颜色格式,而当前 portal 后端可能协商出 RGBx。格式协商失败时,界面可能已经显示“正在共享”,但实际没有可显示的视频帧,于是看到黑屏或白屏。

具体解释还是要看源仓库中的文档。

解决方法

使用该网友自行逆向后给出的补丁 wemeet-screenshare-patch 修复 Wemeet 的屏幕共享二进制。该补丁包含:

  • Hunk 0:修复 DBus SelectSourcesStart 的异步调用顺序。
  • Hunk 1a/1b:修复 PipeWire 的颜色格式协商,并通过 hook 转换缓冲区颜色格式。

1. 下载补丁并备份原文件

1
2
3
4
5
git clone --depth=1 https://github.com/Matheritasiv/wemeet-screenshare-patch.git /tmp/wemeet-screenshare-patch

mkdir -p ~/.local/state/wemeet-screenshare-patch-backup-3.26.10.401
cp -p /opt/wemeet/bin/modules/screen_share/libscreen_share_module.so ~/.local/state/wemeet-screenshare-patch-backup-3.26.10.401/
cp -p /usr/lib/wemeet/libxcast.so ~/.local/state/wemeet-screenshare-patch-backup-3.26.10.401/

2. 适配 Arch Linux 的文件布局

可以直接按照README说的去做,也可以看下面的解决方案,Codex实际的操作步骤。

补丁仓库默认假设 libxcast.so 位于 /opt/wemeet/lib/,但 Arch 的 wemeet-bin 将它安装在 /usr/lib/wemeet/。因此需要复制一份补丁脚本并调整两个路径:

1
2
3
cd /tmp/wemeet-screenshare-patch
cp patch.py patch-arch.py
sed -i -e 's#"bin/modules/screen_share/libscreen_share_module.so"#"opt/wemeet/bin/modules/screen_share/libscreen_share_module.so"#' -e 's#"lib/libxcast.so"#"usr/lib/wemeet/libxcast.so"#' patch-arch.py

先执行 dry-run,确认当前 Wemeet 版本匹配:

1
python3 patch-arch.py / --dry-run

看到所有 Hunk 都显示 [OK] 后再正式写入:

1
sudo python3 patch-arch.py /

3. 安装 hook 到用户目录

1
2
3
mkdir -p ~/.local/lib/wemeet-screenshare-patch
cp -p /tmp/wemeet-screenshare-patch/libhook.so ~/.local/lib/wemeet-screenshare-patch/libhook.so
chmod 755 ~/.local/lib/wemeet-screenshare-patch/libhook.so

临时测试启动:

1
env __EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/50_mesa.json LD_PRELOAD="$HOME/.local/lib/wemeet-screenshare-patch/libhook.so" wemeet

固定到 KDE 应用启动项

创建用户级桌面文件,避免修改系统包管理的文件:

1
2
mkdir -p ~/.local/share/applications
cp /usr/share/applications/wemeetapp.desktop ~/.local/share/applications/wemeetapp.desktop

将用户级文件中的 Exec 改为:

1
Exec=env __EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/50_mesa.json LD_PRELOAD=/home/ziyu/.local/lib/wemeet-screenshare-patch/libhook.so wemeet %u

如果文件中存在下面这一项,建议设置为 false,避免 KDE 再次强制使用 NVIDIA:

1
PrefersNonDefaultGPU=false

刷新 KDE 应用菜单缓存:

1
kbuildsycoca6 --noincremental

之后从 KDE 应用菜单启动腾讯会议即可。

不要安装旧的 wemeet-wayland-screenshare-git

这个项目已经归档,而且它仍然使用 OpenCV 旧版 C API。当前 Arch 的 OpenCV 5 已经移除了:

1
2
opencv2/core/core_c.h
opencv2/imgproc/imgproc_c.h

因此安装它会在编译阶段失败。这和 Wemeet 本次黑屏问题是两个不同的问题;当前应直接修补 wemeet-bin 自带的屏幕共享模块。

Warning

wemeet-screenshare-patch 直接修改 /opt/wemeet/usr/lib/wemeet 中的二进制文件。以后升级 wemeet-bin 后,补丁可能被覆盖,需要重新备份、dry-run 并应用补丁。不要将 __EGL_VENDOR_LIBRARY_FILENAMES 全局写入系统环境变量,只对腾讯会议设置即可。


参考资料