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}