Unixlib support for non-Wine binaries? (Or: would upstream Wine take a Spout2 to PipeWire bridge?)

Hoshino Lina via Wine-devel <[email protected]> Sat, 17 Jan 2026 18:35:00 +0900
Newsgroups gmane.comp.emulators.wine.devel
Message-ID <[email protected]>
Hi!

I'm working on a tool to bridge Spout2 [1][2] to PipeWire. Spout2 is a 
windows-only frame-sharing technology widely used for video-streaming 
and mixing apps. It allows one app to send video to another, much like 
JACK does for audio on Linux (and now PipeWire for both A/V). For 
example, the majority of the VTubing/streaming world relies on Spout2 to 
stream avatars and graphics on screen.

To make this work, the bridge needs to use unixlib to do the bridging 
between the Windows and Linux worlds. I got it to build outside the Wine 
source tree by using just a few headers outside the public wine headers 
(unixlib.h, server.h, server_protocol.h). Originally I intended to 
distribute it as a simple installable that users could throw into their 
WINEPREFIX, but it turned out that for unixlib to work, the exe needs to 
be marked as builtin and distributed as a Wine builtin exe in 
wine/x86_64-windows with the .so file in the companion x86_64-unix 
directory.

- Would it make sense for Wine to change its unixlib loading code to 
work with non-builtin binaries, such as looking for the .so in the same 
directory as the .dll/.exe?
- Otherwise, would upstream Wine be interested in merging this feature? 
The main dependencies are PipeWire and libfunnel [3].

The app does rely on some Wine/DXVK internals (unixlib, 
KeUserDispatchCallback, \??\SharedGpuResource, 
ProcessWineMakeProcessSystem) but it's not strictly necessary for those 
to remain stable across all future Wine releases, as making updates to 
stay compatible is not a major issue.

At this time I plan to distribute it as a "patch" that can be applied to 
Proton installations (which just drops in the exe/so and adds it to 
wine.ini). Another option is using WINEDLLPATH, which should work for 
regular Wine (this one is problematic on Proton since the Proton 
launcher unconditionally clobbers that environment variable).

One potential issue is that due to the less than ideal design of Spout2, 
there is no way to know when apps start using Spout2 other than polling 
for the existence of a named shared memory segment. So if this is merged 
unconditionally, the service would have to always run even if not 
needed, unless some kind of hack is added to `CreateFileMappingA` to 
watch for the "SpoutSenderNames" mapping and launch the service on 
demand when it is created. On top of that, once PipeWire -> Spout2 
support is added, it would mean the daemon is bridging every possible 
PipeWire stream to Spout2 as soon as any Spout2 app runs regardless of 
whether any Spout2 consumer exists for it. The only way I can think of 
avoiding this (other than manual config) is, again, some kind of Wine 
hook that only triggers the bridge for a stream when some Spout2 
consumer app has the specific stream shared memory and/or mutex opened 
to a handle... it really isn't a well designed protocol, unfortunately, 
but it is what is in use on Windows.

[1] https://spout.zeal.co/
[2] https://github.com/leadedge/Spout2
[3] https://github.com/hoshinolina/libfunnel

~~ Lina