package.nix

  1{
  2  stdenv,
  3  clang,
  4  gclient2nix,
  5  lib,
  6  gn,
  7  fetchurl,
  8  fetchpatch,
  9  xcbuild,
 10  python3,
 11  ninja,
 12  git,
 13  cpio,
 14  pkg-config,
 15  glib,
 16  alsa-lib,
 17  pulseaudio,
 18  nasm,
 19  brotli,
 20  fontconfig,
 21  freetype,
 22  harfbuzz,
 23  icu,
 24  jsoncpp,
 25  libpng,
 26  libwebp,
 27  libxml2,
 28  libxslt,
 29  minizip,
 30  ffmpeg_6,
 31  libepoxy,
 32  libgbm,
 33  libGL,
 34  libxcomposite,
 35  libxdamage,
 36  libxext,
 37  libxfixes,
 38  libxrandr,
 39  libxtst,
 40  libx11,
 41  libxi,
 42  pipewire,
 43  xorg,
 44}:
 45let
 46  platformMap = {
 47    "x86_64" = "x64";
 48    "i686" = "x86";
 49    "arm" = "arm";
 50    "aarch64" = "arm64";
 51  };
 52  cpuName = stdenv.hostPlatform.parsed.cpu.name;
 53  gnArch = platformMap."${cpuName}" or (throw "unsupported arch ${cpuName}");
 54  gnOs =
 55    if stdenv.hostPlatform.isLinux then
 56      "linux"
 57    else if stdenv.hostPlatform.isDarwin then
 58      "mac"
 59    else
 60      throw "unknown platform ${stdenv.hostPlatform.config}";
 61  boringSslSymbols = fetchurl {
 62    url = "https://raw.githubusercontent.com/livekit/rust-sdks/refs/tags/webrtc-dac8015-6/webrtc-sys/libwebrtc/boringssl_prefix_symbols.txt";
 63    hash = "sha256-dAweArv8zjsFPENEKi9mNBQkt4y+hh3rCqG6QZjRC20=";
 64  };
 65  gnSystemLibraries = import ./mkSystemLibraries.nix {
 66    inherit
 67      brotli
 68      fontconfig
 69      freetype
 70      harfbuzz
 71      icu
 72      jsoncpp
 73      libpng
 74      libwebp
 75      libxml2
 76      libxslt
 77      minizip
 78      ffmpeg_6
 79      ;
 80  };
 81in
 82stdenv.mkDerivation {
 83  pname = "livekit-libwebrtc";
 84  version = "137-unstable-2025-11-24";
 85
 86  # libwebrtc loads libEGL/libGL at runtime via dlopen() in the Wayland
 87  # screencast path, so they are not visible as ordinary DT_NEEDED edges.
 88  # Keep an explicit rpath so the shared object can resolve them at runtime.
 89  NIX_LDFLAGS = lib.optionalString stdenv.hostPlatform.isLinux
 90    "-rpath ${lib.makeLibraryPath [ libGL ]}";
 91
 92  # Prevent fixup from stripping the rpath above as "unused".
 93  dontPatchELF = stdenv.hostPlatform.isLinux;
 94
 95  gclientDeps = gclient2nix.importGclientDeps ./sources.json;
 96  sourceRoot = "src";
 97
 98  patches = [
 99    # Adds missing dependencies to generated LICENSE
100    (fetchpatch {
101      url = "https://raw.githubusercontent.com/livekit/rust-sdks/a4343fe9d88fcc96f8e88959c90d509abbd0307b/webrtc-sys/libwebrtc/patches/add_licenses.patch";
102      hash = "sha256-9A4KyRW1K3eoQxsTbPX0vOnj66TCs2Fxjpsu5wO8mGI=";
103    })
104    # Fixes the certificate chain, required for Let's Encrypt certs
105    (fetchpatch {
106      url = "https://raw.githubusercontent.com/livekit/rust-sdks/a4343fe9d88fcc96f8e88959c90d509abbd0307b/webrtc-sys/libwebrtc/patches/ssl_verify_callback_with_native_handle.patch";
107      hash = "sha256-RBvRcJzoKItpEbqpe07YZe1D1ZVGS12EnDSISldGy+0=";
108    })
109    # Adds dependencies and features required by livekit
110    (fetchpatch {
111      url = "https://raw.githubusercontent.com/livekit/rust-sdks/a4343fe9d88fcc96f8e88959c90d509abbd0307b/webrtc-sys/libwebrtc/patches/add_deps.patch";
112      hash = "sha256-DwRtGdU5sppmiFsVuyhJoVCQrRl5JFmZJfxgUPhYXBg=";
113    })
114    # Fix gcc-related errors
115    (fetchpatch {
116      url = "https://raw.githubusercontent.com/livekit/rust-sdks/a4343fe9d88fcc96f8e88959c90d509abbd0307b/webrtc-sys/libwebrtc/patches/force_gcc.patch";
117      hash = "sha256-1d73Pi1HkbunjYvp1NskUNE4xXbCmnh++rC6NrCJHbY=";
118      stripLen = 1;
119      extraPrefix = "build/";
120    })
121    # fix a gcc-related dav1d compile option
122    (fetchpatch {
123      url = "https://raw.githubusercontent.com/livekit/rust-sdks/a4343fe9d88fcc96f8e88959c90d509abbd0307b/webrtc-sys/libwebrtc/patches/david_disable_gun_source_macro.patch";
124      hash = "sha256-RCZpeeSQHaxkL3dY2oFFXDjYeU0KHw7idQFONGge8+0=";
125      stripLen = 1;
126      extraPrefix = "third_party/";
127    })
128    # Required for dynamically linking to ffmpeg libraries, exposing symbols,
129    # and hiding PipeWire symbols via version script (Linux only) to prevent
130    # SIGSEGV when ALSA's PipeWire plugin is loaded.
131    ./0001-shared-libraries.patch
132    # Borrow a patch from chromium to prevent a build failure due to missing libclang libraries
133    ./chromium-129-rust.patch
134  ];
135
136  postPatch = ''
137    substituteInPlace .gn \
138      --replace-fail "vpython3" "python3"
139
140    substituteInPlace tools/generate_shim_headers/generate_shim_headers.py \
141      --replace-fail "OFFICIAL_BUILD" "GOOGLE_CHROME_BUILD"
142
143    substituteInPlace BUILD.gn \
144      --replace-fail "rtc_static_library" "rtc_shared_library" \
145      --replace-fail "complete_static_lib = true" ""
146
147    substituteInPlace webrtc.gni \
148      --replace-fail "!build_with_chromium && is_component_build" "false"
149
150    substituteInPlace rtc_tools/BUILD.gn \
151      --replace-fail "\":frame_analyzer\"," ""
152
153    for lib in ${toString (builtins.attrNames gnSystemLibraries)}; do
154      if [ -d "third_party/$lib" ]; then
155        find "third_party/$lib" -type f \
156          \! -path "third_party/$lib/chromium/*" \
157          \! -path "third_party/$lib/google/*" \
158          \! -path "third_party/harfbuzz-ng/utils/hb_scoped.h" \
159          \! -regex '.*\.\(gn\|gni\|isolate\)' \
160          \! -name 'LICENSE*' \
161          \! -name 'COPYING*' \
162          -delete
163      fi
164    done
165
166    # Trick the update_rust.py script into thinking we have *this specific* rust available.
167    # It isn't actually needed for the libwebrtc build, but GN will fail if it isn't there.
168    mkdir -p third_party/rust-toolchain
169    (python3 tools/rust/update_rust.py --print-package-version || true) \
170      | head -n 1 \
171      | sed 's/.* expected Rust version is \([^ ]*\) .*/rustc 1.0 1234 (\1 chromium)/' \
172      > third_party/rust-toolchain/VERSION
173  ''
174  + lib.optionalString stdenv.hostPlatform.isLinux ''
175    mkdir -p buildtools/linux64
176    ln -sf ${lib.getExe gn} buildtools/linux64/gn
177    cp ${./libwebrtc.version} libwebrtc.version
178    substituteInPlace build/toolchain/linux/BUILD.gn \
179      --replace 'toolprefix = "aarch64-linux-gnu-"' 'toolprefix = ""'
180  ''
181  + lib.optionalString stdenv.hostPlatform.isDarwin ''
182    mkdir -p buildtools/mac
183    ln -sf ${lib.getExe gn} buildtools/mac/gn
184    chmod +x build/toolchain/apple/linker_driver.py
185    patchShebangs build/toolchain/apple/linker_driver.py
186    substituteInPlace build/toolchain/apple/toolchain.gni --replace-fail "/bin/cp -Rc" "cp -a"
187  '';
188
189  outputs = [
190    "dev"
191    "out"
192  ];
193
194  nativeBuildInputs =
195    (builtins.concatLists (
196      lib.mapAttrsToList (
197        _: library: if (library.package ? dev) then [ library.package.dev ] else [ ]
198      ) gnSystemLibraries
199    ))
200    ++ [
201      gclient2nix.gclientUnpackHook
202      gn
203      (python3.withPackages (ps: [ ps.setuptools ]))
204      ninja
205      git
206      cpio
207      pkg-config
208    ]
209    ++ lib.optionals stdenv.hostPlatform.isDarwin [ xcbuild ];
210
211  buildInputs = [
212    nasm
213  ]
214  ++ (lib.mapAttrsToList (_: library: library.package) gnSystemLibraries)
215  ++ (lib.optionals stdenv.hostPlatform.isLinux [
216    glib
217    alsa-lib
218    pulseaudio
219    libepoxy
220    libgbm
221    libGL
222    libxcomposite
223    libxdamage
224    libxext
225    libxfixes
226    libxrandr
227    libxtst
228    pipewire
229    libx11
230    libxi
231  ]);
232
233  preConfigure = ''
234    echo "generate_location_tags = true" >> build/config/gclient_args.gni
235    echo "0" > build/util/LASTCHANGE.committime
236
237    python build/linux/unbundle/replace_gn_files.py \
238        --system-libraries ${toString (builtins.attrNames gnSystemLibraries)}
239  '';
240
241  gnFlags = [
242    "is_debug=false"
243    "rtc_include_tests=false"
244    ''target_os="${gnOs}"''
245    ''target_cpu="${gnArch}"''
246    "treat_warnings_as_errors=false"
247    "rtc_enable_protobuf=false"
248    "rtc_include_tests=false"
249    "rtc_build_examples=false"
250    "rtc_build_tools=false"
251    "rtc_libvpx_build_vp9=true"
252    "enable_libaom=true"
253    "use_dummy_lastchange=true"
254    "is_component_build=true"
255    "enable_stripping=true"
256    "rtc_use_h264=true"
257    "rtc_use_h265=true"
258    "use_custom_libcxx=false"
259    "use_rtti=true"
260  ]
261  ++ (lib.optionals stdenv.hostPlatform.isLinux [
262    "rtc_use_pipewire=true"
263    "symbol_level=0"
264    "enable_iterator_debugging=false"
265    "rtc_use_x11=true"
266    "use_sysroot=false"
267    "use_custom_libcxx_for_host=false"
268    "use_libcxx_modules=false"
269    "use_llvm_libatomic=false"
270    "is_clang=false"
271  ])
272  ++ (lib.optionals stdenv.hostPlatform.isDarwin [
273    ''mac_deployment_target="${stdenv.hostPlatform.darwinMinVersion}"''
274    "rtc_enable_symbol_export=true"
275    "rtc_enable_objc_symbol_export=true"
276    "rtc_include_dav1d_in_internal_decoder_factory=true"
277    "clang_use_chrome_plugins=false"
278    "use_lld=false"
279    ''clang_base_path="${clang}"''
280  ]);
281
282  ninjaFlags = [
283    ":default"
284  ]
285  ++ lib.optionals stdenv.hostPlatform.isDarwin [
286    "api/audio_codecs:builtin_audio_decoder_factory"
287    "api/task_queue:default_task_queue_factory"
288    "sdk:native_api"
289    "sdk:default_codec_factory_objc"
290    "pc:peer_connection"
291    "sdk:videocapture_objc"
292    "sdk:mac_framework_objc"
293    "desktop_capture_objc"
294  ];
295
296  postBuild =
297    lib.optionalString stdenv.hostPlatform.isLinux ''
298      objcopy --redefine-syms="${boringSslSymbols}" "libwebrtc.so"
299    ''
300    + ''
301      # Generate licenses
302      python3 "../../tools_webrtc/libs/generate_licenses.py" \
303          --target ${if stdenv.hostPlatform.isDarwin then ":webrtc" else ":default"} $PWD $PWD
304    '';
305
306  installPhase = ''
307    runHook preInstall
308
309    mkdir -p $out/lib
310    mkdir -p $dev/include
311
312    install -m0644 obj/webrtc.ninja obj/modules/desktop_capture/desktop_capture.ninja args.gn LICENSE.md $dev
313
314    pushd ../..
315    find . -name "*.h" -print | cpio -pd $dev/include
316    find . -name "*.inc" -print | cpio -pd $dev/include
317    popd
318  ''
319  + lib.optionalString stdenv.hostPlatform.isLinux ''
320    install -m0644 libwebrtc.so libthird_party_boringssl.so $out/lib
321  ''
322  + lib.optionalString stdenv.hostPlatform.isDarwin ''
323    install -m0644 WebRTC.framework/Versions/A/WebRTC $out/lib/libwebrtc.dylib
324    install -m0644 libthird_party_boringssl.dylib $out/lib
325  ''
326  + ''
327    ln -s $out/lib $dev/lib
328
329    runHook postInstall
330  '';
331
332  postFixup = lib.optionalString stdenv.hostPlatform.isDarwin ''
333    boringssl="$out/lib/libthird_party_boringssl.dylib"
334    webrtc="$out/lib/libwebrtc.dylib"
335
336    install_name_tool -id "$boringssl" "$boringssl"
337    install_name_tool -id "$webrtc" "$webrtc"
338    install_name_tool -change @rpath/libthird_party_boringssl.dylib "$boringssl" "$webrtc"
339  '';
340
341  passthru.updateScript = ./update.sh;
342
343  meta = {
344    description = "WebRTC library used by livekit";
345    homepage = "https://github.com/livekit/rust-sdks/";
346    license = lib.licenses.bsd3;
347    maintainers = with lib.maintainers; [
348      WeetHet
349      niklaskorz
350    ];
351    platforms = lib.platforms.linux ++ lib.platforms.darwin;
352  };
353}