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}