Unixlib support for non-Wine binaries? (Or: would upstream Wine take a Spout2 to PipeWire bridge?)
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
Hi Lina, I don't have an answer for your question (sorry), but also need to use a Linux library in a Windows app that will run under Wine. In my case I want to use Linux JACK in a Windows/Wine application. I'm glad to hear that unixlib is working for you. I'd heard about it, sounds like it will do the trick, but don't know how to use it. Have you come across any examples or docs for how to work with it? We could DM this side conversation if that makes more sense: imichaelost@gmail.com. Thanks!
On 2026-01-19 19:18, Michael Ost via Wine-devel wrote:
Hi Lina,
I don't have an answer for your question (sorry), but also need to use a Linux library in a Windows app that will run under Wine. In my case I want to use Linux JACK in a Windows/Wine application. I'm glad to hear that unixlib is working for you. I'd heard about it, sounds like it will do the trick, but don't know how to use it. Have you come across any examples or docs for how to work with it?
We could DM this side conversation if that makes more sense: imichaelost@gmail.com.
Thanks!
Hi Michael, A few years ago I worked on a PipeWire driver for Wine, but never found the time to complete it after refactoring mmdevapi and friends. The idea is that Windows-side you shouldn't need anything other than WASAPI, because: - IAudioClient3 allows to open low-latency streams in shared mode and we now support it. - All streams that are opened by the application show up Linux-side, allowing you to route them as you like. Feel free to contact me in private. On 2026-01-17 10:35, Hoshino Lina via Wine-devel wrote:
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.
Hi Lina, Let's also link the OBS plugin discussion, for reference: https://github.com/Off-World-Live/obs-spout2-plugin/issues/83 In my opinion we should support bridging shared memory areas between Windows and UNIX. This would also allow games to interact with tools running outside of Wine, such as Mumble's Link plugin. For Spout2 it would be "just" a matter of reading the shared memory area on UNIX and sending the video into PipeWire. What do you think?
~~ Lina On 1/21/26 7:52 PM, Davide Beatrici via Wine-devel wrote:
On 2026-01-19 19:18, Michael Ost via Wine-devel wrote:
Hi Lina,
I don't have an answer for your question (sorry), but also need to use a Linux library in a Windows app that will run under Wine. In my case I want to use Linux JACK in a Windows/Wine application. I'm glad to hear that unixlib is working for you. I'd heard about it, sounds like it will do the trick, but don't know how to use it. Have you come across any examples or docs for how to work with it?
We could DM this side conversation if that makes more sense: imichaelost@gmail.com.
Thanks!
Hi Michael,
A few years ago I worked on a PipeWire driver for Wine, but never found the time to complete it after refactoring mmdevapi and friends.
The idea is that Windows-side you shouldn't need anything other than WASAPI, because:
- IAudioClient3 allows to open low-latency streams in shared mode and we now support it. - All streams that are opened by the application show up Linux-side, allowing you to route them as you like.
Feel free to contact me in private.
It's been a long time, but last time I poked around low-latency audio in wine, I used this: https://github.com/wineasio/wineasio It's similar to spout2pw in that it also uses the companion .so library (and needs to be installed into the wine prefix), though it doesn't use the unixlib.h mechanism but rather I think it builds all the actual code using the unix compiler and just creates a fake module for the dll (?) (I'm still a bit confused as to how wine/unix interop works myself at the binary/ABI level, to be honest).
On 2026-01-17 10:35, Hoshino Lina via Wine-devel wrote:
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.
Hi Lina,
Let's also link the OBS plugin discussion, for reference: https://github.com/Off-World-Live/obs-spout2-plugin/issues/83
In my opinion we should support bridging shared memory areas between Windows and UNIX. This would also allow games to interact with tools running outside of Wine, such as Mumble's Link plugin.
For Spout2 it would be "just" a matter of reading the shared memory area on UNIX and sending the video into PipeWire.
What do you think?
This is already how the bridge works, except it cannot be shared memory because GPU textures are not shared (CPU) memory, they are dma-bufs. The way it works is it opens the shared GPU texture handle wine-side, pokes at wine/proton internals to get the corresponding UNIX file descriptor for it, and then uses it on the UNIX side. I recently published the bridge here: https://github.com/hoshinolina/spout2pw And the corresponding OBS plugin (which is generic and not specific to anything wine/spout2) here: https://github.com/hoshinolina/obs-pwvideo (Note that this is all very rough around the edges)
Hi Lina, On 1/17/26 10:35, Hoshino Lina via Wine-devel wrote:
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?
Regarding supporting unixlibs for non-builtin modules, it's probably a up to Alexandre whether he thinks it's future proof and stable enough. I believe we are now distributing wine/unixlib.h as part of public Wine headers, so it seems to me that this is indeed the directions we are taking. It's perhaps then just a matter of time before it's officially supported, or just a matter of someone proposing the changes to make it work.
- 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.
Please note that the Proton shared memory resource implementation (\??\SharedGpuResource) is now deprecated, it will be removed in future Proton releases and replaced with Wine upstream implementation through the D3DKMT API, which DXVK also supports now.
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).
Fwiw, we can consider preserving the variable if set externally, it's not really intentionally overwritten. Feel free to open a Proton MR. Cheers, -- Rémi Bernon <rbernon@codeweavers.com>
On 1/21/26 6:02 PM, Rémi Bernon via Wine-devel wrote:
Hi Lina,
On 1/17/26 10:35, Hoshino Lina via Wine-devel wrote:
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?
Regarding supporting unixlibs for non-builtin modules, it's probably a up to Alexandre whether he thinks it's future proof and stable enough.
I believe we are now distributing wine/unixlib.h as part of public Wine headers, so it seems to me that this is indeed the directions we are taking.
It's perhaps then just a matter of time before it's officially supported, or just a matter of someone proposing the changes to make it work.
Oh, I'd totally missed that! I just checked and indeed in the Wine 11 packages, unixlib.h is there so I don't have to ship it myself any more. I think at that point it just becomes a matter of changing the search path for .so files a bit, so WINEDLLPATH is not necessary.
- 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.
Please note that the Proton shared memory resource implementation (\?? \SharedGpuResource) is now deprecated, it will be removed in future Proton releases and replaced with Wine upstream implementation through the D3DKMT API, which DXVK also supports now.
Yeah, someone else also pointed this out to me the other day. I'll take a look and make sure I support both mechanisms.
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).
Fwiw, we can consider preserving the variable if set externally, it's not really intentionally overwritten. Feel free to open a Proton MR.
Thanks! I've opened a PR here: https://github.com/ValveSoftware/Proton/pull/9420 ~~ Lina
participants (4)
-
Davide Beatrici -
Hoshino Lina -
imichaelost@gmail.com -
Rémi Bernon