From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mail.toke.dk; spf=pass smtp.mailfrom=irif.fr; dkim=pass header.d=irif.fr; arc=none (Message is not ARC signed); dmarc=none Received: from korolev.univ-paris7.fr (korolev.univ-paris7.fr [IPv6:2001:660:3301:8000::1:2]) by mail.toke.dk (Postfix) with ESMTPS id BA4BA126FE6F for ; Fri, 26 Jun 2026 00:34:31 +0200 (CEST) Received: from potemkin.univ-paris7.fr (potemkin.univ-paris7.fr [IPv6:2001:660:3301:8000::1:1]) by korolev.univ-paris7.fr (8.14.4/8.14.4/relay1/82085) with ESMTP id 65PMYPWV003507 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Fri, 26 Jun 2026 00:34:25 +0200 Received: from mailhub.math.univ-paris-diderot.fr (mailhub.math.univ-paris-diderot.fr [81.194.30.253]) by potemkin.univ-paris7.fr (8.14.4/8.14.4/relay2/82085) with ESMTP id 65PMYP6w019825 for ; Fri, 26 Jun 2026 00:34:25 +0200 Received: from mailhub.math.univ-paris-diderot.fr (localhost [127.0.0.1]) by mailhub.math.univ-paris-diderot.fr (Postfix) with ESMTP id 989213AA8B for ; Fri, 26 Jun 2026 00:34:25 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=irif.fr; h= content-type:content-type:mime-version:user-agent:subject :subject:from:from:message-id:date:date:received:received; s= dkim-irif; t=1782426864; x=1783290865; bh=zG0d8jx3sLYCH7aQNcGl79 0LGS99F7QuCQRXEVGe+1g=; b=HhB6XuPfoKq9H14sJmhn1/Nkhcyf17zxNbj9vw i+O/4zcfkTwqBrAgb+5c2ORvCmgwWFzdNtXkwFl+Na0iR9jifKqtECHVwt0SOfRD OPgzFnMPB6/FoPmwqD7okAXXskRX5F/RT96/qIpV+UJ6lmtf60IuVZm3OATKnjbg 2oIY6R1dXJA4jjedAOOPQfXHIYEV/fNFCXLv3ktsRbaNlmQyEcDnxaQJgDuqIvOq mCeVYdaQX/aAx2FHk4mv0s9BZF6oPffUZvUsXMPr+AKuTTVyJBehn50zf0gu8gwP VXBRjpKxS3qjibKQOQs6/vWdkxyE/GDo/dTk4NKWsBem/kGQ== X-Virus-Scanned: amavisd-new at math.univ-paris-diderot.fr Received: from mailhub.math.univ-paris-diderot.fr ([127.0.0.1]) by mailhub.math.univ-paris-diderot.fr (mailhub.math.univ-paris-diderot.fr [127.0.0.1]) (amavisd-new, port 10023) with ESMTP id vP9xYWc2Txyy for ; Fri, 26 Jun 2026 00:34:24 +0200 (CEST) Received: from trurl.irif.fr (82-64-191-149.subs.proxad.net [82.64.191.149]) (Authenticated sender: jch) by mailhub.math.univ-paris-diderot.fr (Postfix) with ESMTPSA id 1897B3AA08 for ; Fri, 26 Jun 2026 00:34:24 +0200 (CEST) Date: Fri, 26 Jun 2026 00:34:23 +0200 Message-ID: <871pdutfkg.wl-jch@irif.fr> From: Juliusz Chroboczek To: galene@lists.galene.org User-Agent: Wanderlust/2.15.9 (Almost Unreal) Emacs/30.2 Mule/6.0 MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") Content-Type: text/plain; charset=US-ASCII X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.2.7 (korolev.univ-paris7.fr [IPv6:2001:660:3301:8000::1:2]); Fri, 26 Jun 2026 00:34:25 +0200 (CEST) X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.2.7 (potemkin.univ-paris7.fr [194.254.61.141]); Fri, 26 Jun 2026 00:34:25 +0200 (CEST) X-Miltered: at korolev with ID 6A3DACF1.000 by Joe's j-chkmail (http : // j-chkmail dot ensmp dot fr)! X-Miltered: at potemkin with ID 6A3DACF1.000 by Joe's j-chkmail (http : // j-chkmail dot ensmp dot fr)! X-j-chkmail-Enveloppe: 6A3DACF1.000 from potemkin.univ-paris7.fr/potemkin.univ-paris7.fr/null/potemkin.univ-paris7.fr/ X-j-chkmail-Enveloppe: 6A3DACF1.000 from mailhub.math.univ-paris-diderot.fr/mailhub.math.univ-paris-diderot.fr/null/mailhub.math.univ-paris-diderot.fr/ X-j-chkmail-Score: MSGID : 6A3DACF1.000 on korolev.univ-paris7.fr : j-chkmail score : . : R=. U=. O=. B=0.000 -> S=0.000 X-j-chkmail-Score: MSGID : 6A3DACF1.000 on potemkin.univ-paris7.fr : j-chkmail score : . : R=. U=. O=. B=0.000 -> S=0.000 X-j-chkmail-Status: Ham X-j-chkmail-Status: Ham Message-ID-Hash: TJCNZTHECFRQ57IIKBHYX6FUCK6PUODE X-Message-ID-Hash: TJCNZTHECFRQ57IIKBHYX6FUCK6PUODE X-MailFrom: jch@irif.fr X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list Subject: [Galene] ANNOUNCE: pw-whip, PipeWire-WHIP bridge List-Id: =?utf-8?q?Gal=C3=A8ne_videoconferencing_server_discussion_list?= Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Hello, PipeWire is a multimedia (audio and video) framework for Linux. WHIP (RFC 9725) is a standardised protocol for streaming audio and video to network servers. Galene can accept WHIP input. Pw-whip is a bridge between PipeWire and WHIP. https://github.com/jech/pw-whip It can be used to stream the audio of any Linux application to Galene: pw-whip -C mpv https://galene.org:8443/group/public/pw-whip/.whip This is currently audio-only, I'll extend it to do video if there's demand. While pw-whip is a useful utility, this was mainly a learning exercice for me: I've been wanting to play with libdatachannel, the incredible WebRTC stack written in C++ by a single person (Paul-Louis Ageneau), and since PipeWire is a hard requirement on modern Linux laptops, I thought it would be a good idea to learn more about it. Here's what I've learnt. # libdatachannel is lovely I was initially planning to write the whole thing in C. However, I soon found out that libdatachannel's C binding is incomplete, and so I switched to C++ for the WHIP part of the program. It turns out that libdatachannel is a pleasure to work with. The data structures are well designed, the API is natural enough, and at times it almost felt that RAII makes sense. (I've recovered since.) There are some missing features, but they should be easy to add. Highly recommended, will use again. # libpipewire is a mess I haven't looked at the sources of the PipeWire deamon, so the following only applies to the libpipewire client library. Which demonstrates that a competent programmer can achieve C++-like levels of obfuscation in C. Instead of providing a set of sane abstractions, libpipewire exposes the PipeWire protocol, but attempts to hide it behind a set of macros that confuse both the programmer and the programmer's editor. Here's how I request that the PipeWire server send me audio in a given format: uint8_t buffer[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); const struct spa_pod *params[1]; params[0] = spa_format_audio_raw_build( &b, SPA_PARAM_EnumFormat, &SPA_AUDIO_INFO_RAW_INIT( .format = SPA_AUDIO_FORMAT_F32, .rate = 48000)); What is a builder, and why do I need one in order to build the data structure that describes 48000-Hz audio? Why am I being asked to put struct initialisers inside a macro inside a function call? Only RedHat minds can tell. The documentation is incomplete; for example, I never found out how to make pw-whip appear as a default sink in pavucontrol. Fortunately, there's an extensive set of examples, which are an excellent source of copy-paste. Oh, and I couldn't include the libpipewire headers in C++ code, which is why the PipeWire part of the code is plain C. But let's not blame the victim, that's Bjarne's fault. Please let me know if you find this useful, so I know whether to add the missing features. -- Juliusz