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