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