wemeet: fix camera crash on Wayland (#522135)

This commit is contained in:
Aleksana
2026-06-18 02:57:33 +00:00
committed by GitHub
2 changed files with 194 additions and 1 deletions
+40 -1
View File
@@ -20,6 +20,7 @@
systemd,
udev,
libGL,
libglvnd,
fontconfig,
freetype,
openssl,
@@ -173,6 +174,44 @@ let
};
};
wemeet-camera-fix = stdenv.mkDerivation {
pname = "wemeet-camera-fix";
version = "0-unstable-2026-05-20";
src = ./wemeet-camera-fix.c;
dontUnpack = true;
dontWrapQtApps = true;
buildInputs = [
libglvnd
libx11
];
buildPhase = ''
runHook preBuild
$CC $CFLAGS -Wall -Wextra -fPIC -shared \
-o libwemeet-camera-fix.so $src \
-ldl -lEGL -lX11
runHook postBuild
'';
installPhase = ''
runHook preInstall
install -Dm755 ./libwemeet-camera-fix.so $out/lib/libwemeet-camera-fix.so
runHook postInstall
'';
meta = {
description = "Fix for WeMeet Wayland camera preview rendering";
license = lib.licenses.mit;
};
};
selectSystem =
attrs:
attrs.${stdenv.hostPlatform.system}
@@ -284,7 +323,7 @@ stdenv.mkDerivation {
"--prefix QT_PLUGIN_PATH : $out/app/wemeet/plugins"
];
commonWrapperArgs = baseWrapperArgs ++ [
"--prefix LD_PRELOAD : ${libwemeetwrap}/lib/libwemeetwrap.so:${wemeet-x11-fix}/lib/libwemeet-x11-fix.so"
"--prefix LD_PRELOAD : ${libwemeetwrap}/lib/libwemeetwrap.so:${wemeet-x11-fix}/lib/libwemeet-x11-fix.so:${wemeet-camera-fix}/lib/libwemeet-camera-fix.so"
"--run 'if [[ $XDG_SESSION_TYPE == \"wayland\" ]]; then export LD_PRELOAD=${wemeet-wayland-screenshare}/lib/wemeet/libhook.so\${LD_PRELOAD:+:$LD_PRELOAD}; fi'"
];
xwaylandWrapperArgs = baseWrapperArgs ++ [
+154
View File
@@ -0,0 +1,154 @@
/*
* LD_PRELOAD shim for WeMeet's camera preview on Wayland.
*
* WeMeet's libxcast.so uses EGL to render the local camera preview. It links
* against libEGL and libX11, and later passes X11 native windows to EGL. In a
* Wayland session, Mesa can choose the Wayland EGL platform for
* eglGetDisplay(NULL), which makes libxcast.so hand an X11 XID to the Wayland
* platform path when creating its window surface. The camera still opens and
* remote participants can see it, but the local preview fails to render or may
* crash.
*
* Only for calls originating in libxcast.so, force EGL display creation through
* the X11 platform. Qt/QtWebEngine and other callers continue to use their
* normal EGL path.
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <X11/Xlib.h>
#ifndef EGL_PLATFORM_X11_KHR
#define EGL_PLATFORM_X11_KHR 0x31D5
#endif
typedef EGLDisplay (*pfn_eglGetDisplay)(EGLNativeDisplayType);
typedef EGLDisplay (*pfn_eglGetPlatformDisplay)(EGLenum, void *, const EGLAttrib *);
typedef EGLDisplay (*pfn_eglGetPlatformDisplayEXT)(EGLenum, void *, const EGLint *);
static pfn_eglGetDisplay real_eglGetDisplay;
static pfn_eglGetPlatformDisplay real_eglGetPlatformDisplay;
static pfn_eglGetPlatformDisplayEXT real_eglGetPlatformDisplayEXT;
static EGLDisplay x11_egl_display = EGL_NO_DISPLAY;
static Display *x_display;
static pthread_once_t once_resolve = PTHREAD_ONCE_INIT;
static pthread_once_t once_x11 = PTHREAD_ONCE_INIT;
static int debug_enabled(void)
{
static int value = -1;
if (value < 0) {
value = getenv("WEMEET_CAMERA_FIX_DEBUG") != NULL;
}
return value;
}
#define LOG(...) \
do { \
if (debug_enabled()) { \
fprintf(stderr, "[wemeet-camera-fix] " __VA_ARGS__); \
} \
} while (0)
static void resolve_real_symbols(void)
{
real_eglGetDisplay = (pfn_eglGetDisplay)dlsym(RTLD_NEXT, "eglGetDisplay");
real_eglGetPlatformDisplay =
(pfn_eglGetPlatformDisplay)dlsym(RTLD_NEXT, "eglGetPlatformDisplay");
real_eglGetPlatformDisplayEXT =
(pfn_eglGetPlatformDisplayEXT)dlsym(RTLD_NEXT, "eglGetPlatformDisplayEXT");
}
static void init_x11_egl_display(void)
{
pthread_once(&once_resolve, resolve_real_symbols);
x_display = XOpenDisplay(NULL);
if (!x_display) {
fprintf(stderr, "[wemeet-camera-fix] XOpenDisplay(NULL) failed; DISPLAY=%s\n",
getenv("DISPLAY") ? getenv("DISPLAY") : "(unset)");
return;
}
if (real_eglGetPlatformDisplay) {
x11_egl_display =
real_eglGetPlatformDisplay(EGL_PLATFORM_X11_KHR, x_display, NULL);
} else if (real_eglGetPlatformDisplayEXT) {
x11_egl_display =
real_eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_KHR, x_display, NULL);
} else if (real_eglGetDisplay) {
x11_egl_display = real_eglGetDisplay((EGLNativeDisplayType)x_display);
}
LOG("initialized X11 EGLDisplay=%p for X Display*=%p\n",
(void *)x11_egl_display, (void *)x_display);
}
static int caller_is_xcast(void *caller)
{
Dl_info info;
if (!caller) {
return 0;
}
memset(&info, 0, sizeof(info));
if (!dladdr(caller, &info) || !info.dli_fname) {
return 0;
}
return strstr(info.dli_fname, "libxcast.so") != NULL;
}
EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id)
{
pthread_once(&once_resolve, resolve_real_symbols);
if (caller_is_xcast(__builtin_return_address(0))) {
pthread_once(&once_x11, init_x11_egl_display);
LOG("eglGetDisplay from libxcast.so -> %p\n", (void *)x11_egl_display);
return x11_egl_display;
}
return real_eglGetDisplay ? real_eglGetDisplay(display_id) : EGL_NO_DISPLAY;
}
EGLDisplay eglGetPlatformDisplay(EGLenum platform, void *native_display,
const EGLAttrib *attrib_list)
{
pthread_once(&once_resolve, resolve_real_symbols);
if (caller_is_xcast(__builtin_return_address(0))) {
pthread_once(&once_x11, init_x11_egl_display);
LOG("eglGetPlatformDisplay from libxcast.so -> %p\n",
(void *)x11_egl_display);
return x11_egl_display;
}
return real_eglGetPlatformDisplay
? real_eglGetPlatformDisplay(platform, native_display, attrib_list)
: EGL_NO_DISPLAY;
}
EGLDisplay eglGetPlatformDisplayEXT(EGLenum platform, void *native_display,
const EGLint *attrib_list)
{
pthread_once(&once_resolve, resolve_real_symbols);
if (caller_is_xcast(__builtin_return_address(0))) {
pthread_once(&once_x11, init_x11_egl_display);
LOG("eglGetPlatformDisplayEXT from libxcast.so -> %p\n",
(void *)x11_egl_display);
return x11_egl_display;
}
return real_eglGetPlatformDisplayEXT
? real_eglGetPlatformDisplayEXT(platform, native_display, attrib_list)
: EGL_NO_DISPLAY;
}