theNizo / linux_rocksmith

Guides to get Rocksmith 2014 running on Linux
https://thenizo.github.io/linux_rocksmith/
GNU General Public License v3.0
111 stars 10 forks source link

Steam Flatpak Support #31

Closed Siarkowy closed 1 year ago

Siarkowy commented 1 year ago

(Opening as separate issue as it is more specific than https://github.com/theNizo/linux_rocksmith/issues/30.)

Coming from Fedora, I was trying to run Rocksmith 2014 in com.valvesoftware.Steam Flatpak.

I managed to build wineasio extension, using com.valvesoftware.Steam as runtime, which inherits the org.freedesktop.Platform runtime itself. (This essentially mimics how other Steam compatibility tools like com.valvesoftware.Steam.CompatibilityTool.Proton are packaged with Flatpak.)

Above solves the problem of building & packaging but doesn't automatically configure any installations of Proton to actually use wineasio.dll. (This is because all extensions are just layers over base Steam app.)

So I manually copied the files into target Proton library & prefix dirs, and registered. (I installed GE-Proton7-55 using https://davidotek.github.io/protonup-qt/ for this specific proof of concept.)

# install 32-bit wineasio files in Proton
cp /app/share/steam/compatibilitytools.d/WineASIO/lib32/wine/i386-windows/wineasio.dll /var/data/Steam/compatibilitytools.d/GE-Proton7-55/files/lib/wine/i386-windows/
cp /app/share/steam/compatibilitytools.d/WineASIO/lib32/wine/i386-unix/wineasio.dll.so /var/data/Steam/compatibilitytools.d/GE-Proton7-55/files/lib/wine/i386-unix/

# install 64-bit wineasio files in Proton
cp /app/share/steam/compatibilitytools.d/WineASIO/lib/wine/x86_64-windows/wineasio.dll /var/data/Steam/compatibilitytools.d/GE-Proton7-55/files/lib64/wine/x86_64-windows/
cp /app/share/steam/compatibilitytools.d/WineASIO/lib/wine/x86_64-unix/wineasio.dll.so /var/data/Steam/compatibilitytools.d/GE-Proton7-55/files/lib64/wine/x86_64-unix/

# make wineasio DLLs loadable in game(s) from Proton prefix
cp /app/share/steam/compatibilitytools.d/WineASIO/lib32/wine/i386-windows/wineasio.dll /mnt/funky/SteamLibrary/steamapps/compatdata/221680/pfx/drive_c/windows/syswow64/
cp /app/share/steam/compatibilitytools.d/WineASIO/lib/wine/x86_64-windows/wineasio.dll /mnt/funky/SteamLibrary/steamapps/compatdata/221680/pfx/drive_c/windows/system32/

# register wineasio as available DLL in Proton (wondering, is this necessary anymore?)
WINEPREFIX=/mnt/funky/SteamLibrary/steamapps/compatdata/221680/pfx /var/data/Steam/compatibilitytools.d/GE-Proton7-55/files/bin/wine   regsvr32 wineasio.dll
WINEPREFIX=/mnt/funky/SteamLibrary/steamapps/compatdata/221680/pfx /var/data/Steam/compatibilitytools.d/GE-Proton7-55/files/bin/wine64 regsvr32 wineasio.dll

Starting the game with PROTON_LOG=1 leads to the familiar error about missing jack socket.

55639.287:0114:0118:trace:loaddll:build_module Loaded L"Z:\\var\\mnt\\funky\\SteamLibrary\\steamapps\\common\\Rocksmith2014\\RS_ASIO.dll" at 1D9F0000: native
55639.419:0114:0118:trace:loaddll:build_module Loaded L"C:\\windows\\system32\\wineasio.dll" at D53B0000: builtin
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
Unable to open a JACK client as: Rocksmith2014

For Flatpak, it seems necessary to add additional permissions which Steam Flatpak misses by default. (Those can be added from Flatseal or the command line.)

--filesystem=xdg-run/pipewire-0  # pipewire socket
--socket=system-bus  # not sure about this one, might be necessary for realtime mode?

This still didn't fix the jack socket error, however the cleanup section from the linked issue is interesting. It basically says, remove any default (non-pipewire?) jack libs from org.freedesktop.Platform runtime, which Steam Flatpak doesn't do. (Cleaning this up would make sense, as we are trying to avoid the original jack library, and use pipewire-jack instead.)

cleanup:
  - /bin/jack*
  - /lib/libjack*

This got me thinking, can we LD_PRELOAD proper jack implementation here? I wanted to preload the correct .so but interestingly, org.freedesktop.Platform does not provide pipewire-jack.

Also, jack (pipewire?) versions differ from host to container, and that can possibly be a problem according to https://github.com/ValveSoftware/steam-runtime/issues/307#issuecomment-743175065 and https://github.com/ValveSoftware/steam-runtime/issues/438#issuecomment-890885632. Yet, we cannot just ditch jack here and switch to pulseaudio, for obvious reasons.

# fedora 37 host
% find /usr -name '*libjack.so.0*' -o -name '*libpipewire-0.3.so.0*' 2>&-
/usr/lib64/libpipewire-0.3.so.0
/usr/lib64/libpipewire-0.3.so.0.370.0
/usr/lib64/pipewire-0.3/jack/libjack.so.0
/usr/lib64/pipewire-0.3/jack/libjack.so.0.370.0

# flatpak container
[📦 com.valvesoftware.Steam ~]$ find /usr -name '*libjack.so.0*' -o -name '*libpipewire-0.3.so.0*' 2>&-
/usr/lib/i386-linux-gnu/libjack.so.0
/usr/lib/i386-linux-gnu/libjack.so.0.369.0
/usr/lib/i386-linux-gnu/libpipewire-0.3.so.0
/usr/lib/i386-linux-gnu/libpipewire-0.3.so.0.369.0
/usr/lib/x86_64-linux-gnu/libjack.so.0
/usr/lib/x86_64-linux-gnu/libjack.so.0.369.0
/usr/lib/x86_64-linux-gnu/libpipewire-0.3.so.0
/usr/lib/x86_64-linux-gnu/libpipewire-0.3.so.0.369.0

This seems to be a general blocker at this point. I didn't try the "generate proton script and run as non-steam game" workaround yet, maybe that gives some more insight into what's going on here.

Siarkowy commented 1 year ago

Managed to produce some pipewire log output by providing PIPEWIRE_DEBUG=3 and redirecting to a file.

Attempting to load original DLL from: C:\windows\system32\avrt.dll
Load OK; fetching procedure addresses...
[I][23082.528824] pw.context   | [      pipewire.c:  647 pw_init()] version 0.3.69
[I][23082.529125] jack         | [ pipewire-jack.c: 3284 jack_client_open()] 0xf11de270: open 'Rocksmith2014' options:1
[I][23082.529237] pw.conf      | [          conf.c:  403 conf_load()] 0xdece36b0: loaded config '/usr/share/pipewire/jack.conf' with 5 items
[I][23082.529257] pw.conf      | [          conf.c:  950 pw_context_conf_section_for_each()] handle config '/usr/share/pipewire/jack.conf' section 'context.properties'
[I][23082.529266] pw.context   | [       context.c:  241 pw_context_new()] 0xdece3370: parsed 1 context.properties items
[I][23082.529874] pw.conf      | [          conf.c:  950 pw_context_conf_section_for_each()] handle config '/usr/share/pipewire/jack.conf' section 'context.spa-libs'
[I][23082.529894] pw.context   | [       context.c:  342 pw_context_new()] 0xdece3370: parsed 1 context.spa-libs items
[I][23082.529903] pw.conf      | [          conf.c:  950 pw_context_conf_section_for_each()] handle config '/usr/share/pipewire/jack.conf' section 'context.modules'
[I][23082.529912] pw.module    | [   impl-module.c:  162 pw_context_load_module()] 0xdece3370: name:libpipewire-module-rt args:{
            #rt.prio      = 88
            #rt.time.soft = -1
            #rt.time.hard = -1
        }
[I][23082.530175] mod.rt       | [     module-rt.c:  581 check_realtime_privileges()] Clamp rtprio 88 to 0
[I][23082.530187] mod.rt       | [     module-rt.c:  589 check_realtime_privileges()] Priority max (0) must be at least 11
[I][23082.531657] pw.conf      | [          conf.c:  582 load_module()] 0xdece3370: loaded module libpipewire-module-rt
[I][23082.531672] pw.module    | [   impl-module.c:  162 pw_context_load_module()] 0xdece3370: name:libpipewire-module-protocol-native args:(null)
[I][23082.532445] pw.conf      | [          conf.c:  582 load_module()] 0xdece3370: loaded module libpipewire-module-protocol-native
[I][23082.532460] pw.module    | [   impl-module.c:  162 pw_context_load_module()] 0xdece3370: name:libpipewire-module-client-node args:(null)
[I][23082.533225] pw.conf      | [          conf.c:  582 load_module()] 0xdece3370: loaded module libpipewire-module-client-node
[I][23082.533239] pw.module    | [   impl-module.c:  162 pw_context_load_module()] 0xdece3370: name:libpipewire-module-metadata args:(null)
[I][23082.533650] pw.conf      | [          conf.c:  582 load_module()] 0xdece3370: loaded module libpipewire-module-metadata
[I][23082.533662] pw.context   | [       context.c:  346 pw_context_new()] 0xdece3370: parsed 4 context.modules items
[I][23082.533669] pw.context   | [       context.c:  351 pw_context_new()] 0xdece3370: parsed 0 context.objects items
[I][23082.533675] pw.context   | [       context.c:  354 pw_context_new()] 0xdece3370: parsed 0 context.exec items
[E][23082.533683] pw.data-loop | [     data-loop.c:  190 pw_data_loop_start()] 0xdece54c0: can't create thread: Resource temporarily unavailable
[I][23082.533998] jack         | [ pipewire-jack.c: 3562 jack_client_close()] 0xf11de270: close
[I][23082.534015] jack         | [ pipewire-jack.c: 3800 jack_deactivate()] 0xf11de270: active:0
Unable to open a JACK client as: Rocksmith2014
[I][23082.534957] pw.context   | [      pipewire.c:  647 pw_init()] version 0.3.69
[I][23082.535186] jack         | [ pipewire-jack.c: 3284 jack_client_open()] 0xdece7e50: open 'Rocksmith2014' options:1
[I][23082.535254] pw.conf      | [          conf.c:  403 conf_load()] 0xdd30f680: loaded config '/usr/share/pipewire/jack.conf' with 5 items
[I][23082.535271] pw.conf      | [          conf.c:  950 pw_context_conf_section_for_each()] handle config '/usr/share/pipewire/jack.conf' section 'context.properties'
[I][23082.535279] pw.context   | [       context.c:  241 pw_context_new()] 0xdd30f340: parsed 1 context.properties items
[I][23082.535621] pw.conf      | [          conf.c:  950 pw_context_conf_section_for_each()] handle config '/usr/share/pipewire/jack.conf' section 'context.spa-libs'
[I][23082.535637] pw.context   | [       context.c:  342 pw_context_new()] 0xdd30f340: parsed 1 context.spa-libs items
[I][23082.535645] pw.conf      | [          conf.c:  950 pw_context_conf_section_for_each()] handle config '/usr/share/pipewire/jack.conf' section 'context.modules'
[I][23082.535653] pw.module    | [   impl-module.c:  162 pw_context_load_module()] 0xdd30f340: name:libpipewire-module-rt args:{
            #rt.prio      = 88
            #rt.time.soft = -1
            #rt.time.hard = -1
        }
[I][23082.535789] mod.rt       | [     module-rt.c:  581 check_realtime_privileges()] Clamp rtprio 88 to 0
[I][23082.535801] mod.rt       | [     module-rt.c:  589 check_realtime_privileges()] Priority max (0) must be at least 11
[I][23082.536941] pw.conf      | [          conf.c:  582 load_module()] 0xdd30f340: loaded module libpipewire-module-rt
[I][23082.536958] pw.module    | [   impl-module.c:  162 pw_context_load_module()] 0xdd30f340: name:libpipewire-module-protocol-native args:(null)
[I][23082.537115] pw.conf      | [          conf.c:  582 load_module()] 0xdd30f340: loaded module libpipewire-module-protocol-native
[I][23082.537128] pw.module    | [   impl-module.c:  162 pw_context_load_module()] 0xdd30f340: name:libpipewire-module-client-node args:(null)
[I][23082.537280] pw.conf      | [          conf.c:  582 load_module()] 0xdd30f340: loaded module libpipewire-module-client-node
[I][23082.537291] pw.module    | [   impl-module.c:  162 pw_context_load_module()] 0xdd30f340: name:libpipewire-module-metadata args:(null)
[I][23082.537380] pw.conf      | [          conf.c:  582 load_module()] 0xdd30f340: loaded module libpipewire-module-metadata
[I][23082.537391] pw.context   | [       context.c:  346 pw_context_new()] 0xdd30f340: parsed 4 context.modules items
[I][23082.537398] pw.context   | [       context.c:  351 pw_context_new()] 0xdd30f340: parsed 0 context.objects items
[I][23082.537405] pw.context   | [       context.c:  354 pw_context_new()] 0xdd30f340: parsed 0 context.exec items
[E][23082.537412] pw.data-loop | [     data-loop.c:  190 pw_data_loop_start()] 0xdd3103c0: can't create thread: Resource temporarily unavailable
[I][23082.537638] jack         | [ pipewire-jack.c: 3562 jack_client_close()] 0xdece7e50: close
[I][23082.537656] jack         | [ pipewire-jack.c: 3800 jack_deactivate()] 0xdece7e50: active:0
Unable to open a JACK client as: Rocksmith2014
Unloading original DLL

There seems to be some threading related culprit.

[E][23082.537412] pw.data-loop | [     data-loop.c:  190 pw_data_loop_start()] 0xdd3103c0: can't create thread: Resource temporarily unavailable

Looking into several places currently, most promising leads so far:

Siarkowy commented 1 year ago

For anyone wanting to reproduce this locally, check out my Steam WineASIO Flatpak repository below.

https://github.com/Siarkowy/com.valvesoftware.Steam.CompatibilityTool.WineASIO

theNizo commented 1 year ago

Note that I have pretty limited knowledge about Flatpak, so consider this to be possible hints.


# register wineasio as available DLL in Proton (wondering, is this necessary anymore?)

Good point


Since you mentioned the file structure of the Steam Flatpak, I would be interested how that compares to other software. There's Flatpak versions of Guitarix or Ardour.

"generate proton script and run as non-steam game" workaround

This is why I mentioned the 3rd step.Cut out complexity and unnecessary issues with wineasio that appear even when knowing the whole setup process well.

Siarkowy commented 1 year ago

I was able to solve all issues when running Rocksmith 2014 from Steam Flatpak.

The setup at https://github.com/Siarkowy/com.valvesoftware.Steam.CompatibilityTool.WineASIO already provides a stable gaming experience, as tested with both audio interface & RTC cable, with several hours of play. Please feel free to try it out!