nix: Hide pipewire lazy trampolines in libwebrtc when linking as SO (#50743)

Jakub Konka created

This would cause a null pointer dereference when trying to open an audio
device in Zed. More context:
https://github.com/NixOS/nixpkgs/pull/478907/changes#r2885943326

cc @cameron1024 

Release Notes:

- Fixed crash when trying to join a channel/test audio on Nix-built Zed
on Linux.

Change summary

nix/livekit-libwebrtc/0001-shared-libraries.patch | 10 +++++--
nix/livekit-libwebrtc/libwebrtc.version           | 22 +++++++++++++++++
nix/livekit-libwebrtc/package.nix                 |  5 +++
3 files changed, 33 insertions(+), 4 deletions(-)

Detailed changes

nix/livekit-libwebrtc/0001-shared-libraries.patch 🔗

@@ -1,6 +1,6 @@
---- a/BUILD.gn	2026-01-10 19:22:47.201811909 -0500
-+++ b/BUILD.gn	2026-01-10 19:24:36.440918317 -0500
-@@ -143,8 +143,8 @@
+--- a/BUILD.gn
++++ b/BUILD.gn
+@@ -143,8 +143,12 @@
  # target_defaults and direct_dependent_settings.
  config("common_inherited_config") {
    defines = [ "PROTOBUF_ENABLE_DEBUG_LOGGING_MAY_LEAK_PII=0" ]
@@ -8,6 +8,10 @@
 -  ldflags = []
 +  cflags = [ "-fvisibility=default" ]
 +  ldflags = [ "-lavutil", "-lavformat", "-lavcodec" ]
++
++  if (is_linux) {
++    ldflags += [ "-Wl,--version-script=" + rebase_path("//libwebrtc.version", root_build_dir) ]
++  }
 
    if (rtc_objc_prefix != "") {
      defines += [ "RTC_OBJC_TYPE_PREFIX=${rtc_objc_prefix}" ]

nix/livekit-libwebrtc/libwebrtc.version 🔗

@@ -0,0 +1,22 @@
+/* Linker version script for libwebrtc.so (Linux only).
+ *
+ * When libwebrtc.so is built with rtc_use_pipewire=true and
+ * -fvisibility=default, PipeWire lazy-load trampoline stubs (pw_*, spa_*)
+ * are exported as weak symbols. If the PipeWire ALSA plugin
+ * (libasound_module_pcm_pipewire.so) is later dlopen'd by libasound,
+ * the dynamic linker may resolve the plugin's pw_* references through
+ * libwebrtc.so's broken trampolines instead of the real libpipewire.so,
+ * causing a SIGSEGV (NULL function pointer dereference).
+ *
+ * This script hides only those third-party symbol namespaces while
+ * keeping every WebRTC / BoringSSL / internal symbol exported (which
+ * the Rust webrtc-sys bindings require).
+ */
+{
+  global:
+    *;
+
+  local:
+    pw_*;
+    spa_*;
+};

nix/livekit-libwebrtc/package.nix 🔗

@@ -114,7 +114,9 @@ stdenv.mkDerivation {
       stripLen = 1;
       extraPrefix = "third_party/";
     })
-    # Required for dynamically linking to ffmpeg libraries and exposing symbols
+    # Required for dynamically linking to ffmpeg libraries, exposing symbols,
+    # and hiding PipeWire symbols via version script (Linux only) to prevent
+    # SIGSEGV when ALSA's PipeWire plugin is loaded.
     ./0001-shared-libraries.patch
     # Borrow a patch from chromium to prevent a build failure due to missing libclang libraries
     ./chromium-129-rust.patch
@@ -161,6 +163,7 @@ stdenv.mkDerivation {
   + lib.optionalString stdenv.hostPlatform.isLinux ''
     mkdir -p buildtools/linux64
     ln -sf ${lib.getExe gn} buildtools/linux64/gn
+    cp ${./libwebrtc.version} libwebrtc.version
     substituteInPlace build/toolchain/linux/BUILD.gn \
       --replace 'toolprefix = "aarch64-linux-gnu-"' 'toolprefix = ""'
   ''