Galène videoconferencing server discussion list archives
 help / color / mirror / Atom feed
* [Galene] ANNOUNCE: pw-whip, PipeWire-WHIP bridge
@ 2026-06-25 22:34 Juliusz Chroboczek
  0 siblings, 0 replies; only message in thread
From: Juliusz Chroboczek @ 2026-06-25 22:34 UTC (permalink / raw)
  To: galene

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

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-06-25 22:34 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-25 22:34 [Galene] ANNOUNCE: pw-whip, PipeWire-WHIP bridge Juliusz Chroboczek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox