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