I am trying to set up sunshine to capture using the wlr method and do it headlessly. no dummy plug, no monitor. Supposedly this is possible, but I’m having trouble.

first I create the user in fedora and give them the permissions needed. I set up setd and create the service file for systemd to fire a sway instance. I edit sway config for that user to include the virtual display output by including this line:

output HEADLESS-1 { pos 0,0 mode 3840x2160@60hz }

That should make a virtual monitor that wayland can render to and sunshine can capture the framebuffer from sway with.

Sway launches fine, sunshine see the wayland instance, but it sees no monitor attached so it has nothing in it can capture from.

I cannot use swaymsg from SSH since its not part of that wayland session so it cant access it and pass commands to it. it just complains about socket errors. So I dont know what I’m supposed to do to make this headlessly run.

  • muusemuuse@sh.itjust.worksOP
    link
    fedilink
    English
    arrow-up
    1
    ·
    edit-2
    2 days ago

    Okay here’s what I stumbled through.

    This is on a fedora server machine with an intel ARC B580. I intentionally chose fedora because my fedora skills are ass and I wanted to improve them so…

    1. enable rpmfusion repos - go here (https://docs.fedoraproject.org/en-US/quick-docs/rpmfusion-setup/) make sure to include nonfree. we need the intel-media-driver from there. The one included in the fedora repos is incomplete and generally wont be enough for what we want.
    2. enable the copr repo for sunshine - at this time, there isnt anything in stable for fedora 43, so we enable the beta repo with “sudo dnf copr enable lizardbyte/beta”
    3. install the packages - run “sudo dnf install intel-media-driver sway seatd nano pipewire wireplumber Sunshine”
    4. open ports on the fedora firewall - I’m a hack and used cockpit for this. log into the cockpit UI and got to Networking->edit rules and zones->add services. add TCP 47990, 47984, 47989, 48010 and UDP 47998-48000
    5. add a sunshine user on the machine - run “sudo adduser sunshine -m”
    6. set a password for the sunshine user - run “sudo passwd sunshine”
    7. add sunshine user to the required groups - run “sudo usermod -aG video,render,seat,input sunshine”
    8. enable seatd at boot so the sunshine user can create a headless wayland session in the background without having to be logged in - run “sudo systemctl enable --now seatd”
    9. enable linger so things can run by themselves as that user - run “sudo loginctl enable-linger sunshine”
    10. create config directories - log in as the sunshine user we created. run “mkdir -p ~/.config/sway ~/.config/sunshine ~/.config/systemd/user”
    11. create sway config - run “nano ~/.config/sway/config” and ensure the following is included in the file:
    output HEADLESS-1 {
    pos 0,0
    mode 3840x2160@60hz
    }
    exec swaymsg create_output HEADLESS-1
    
    default_border none
    default_floating_border none
    
    1. create the initial sunshine config - run “nano ~/.config/sunshine/sunshine.config” and ensure the following is included in the file:
    capture = wlr
    encoder = vaapi
    
    1. config systemd to launch sway at boot - run “nano ~/.config/systemd/user/sway.service” and make the file look like this:
    [Unit]
    Description=Sway Wayland compositor
    Documentation=man:sway(5)
    After=pipewire.socket wireplumber.service
    Wants=pipewire.socket wireplumber.service
    
    [Service]
    ExecStart=/usr/bin/sway
    Restart=on-failure
    RestartSec=2
    Environment=XDG_SESSION_TYPE=wayland
    Environment=LIBSEAT_BACKEND=seatd
    Environment=XDG_CURRENT_DESKTOP=sway
    
    [Install]
    WantedBy=default.target
    
    1. config systemd to launch sunshine at boot (the way we want it to) - run “EDITOR=nano systemctl --user edit sunshine” and put the following in the area that will apply the override:
    [Unit]
    After=sway.service
    Requires=sway.service
    
    [Service]
    Environment=WAYLAND_DISPLAY=wayland-1
    Environment=XDG_SESSION_TYPE=wayland
    
    [Install]
    WantedBy=default.target
    
    1. enable the systemd services - run “systemctl --user daemon-reload” then run “systemctl --user enable --now sway” and “systemctl --user enable --now sunshine”
    2. configure sway to change resolution to whatever the moonlight client asks for - access the sunshine webUI by pointing a web browser to https://(your server IP):47990/ and go to the applications tab. in each entry you want to assign this ability to, hit edit and add the following DO command sh -c "swaymsg output HEADLESS-1 pos 0 0 res \"${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT}@${SUNSHINE_CLIENT_FPS}Hz\"" and if you want an undo command set it to "sh -c swaymsg output HEADLESS-1 pos 0 0 res 3840x2160@60Hz"

    There, you now have a headless, resolution-matching, zero-copy, lightweight sunshine install and you didn’t need any dummy plugs, connected monitors, EDID injection, etc.

    There are likely things I missed but this is what I’ve got so far.

    • muusemuuse@sh.itjust.worksOP
      link
      fedilink
      English
      arrow-up
      1
      ·
      5 days ago

      Also, if you are using an intel ARC GPU, you might want to run through fwupd as there are issues with these cards that the windows installer resolves during driver install that we cant run on linux that way, so we can tell linux to do that step for us with fwupd.

  • themoken@startrek.website
    link
    fedilink
    English
    arrow-up
    10
    ·
    edit-2
    8 days ago

    I have this setup with Plasma, and it is probably easier to do this at the Linux level. I added this to my kernel command line: drm.edid_firmware=DP-1:edid/lg-ultra.bin video=DP-1:3840x2160@60e

    Where that EDID file I dumped from a spare monitor using a method I got here.

    Anyway, it can be tricky to pick the right device, but I can confirm Sunshine sees it and works properly, and it can be managed like a normal monitor.

    • muusemuuse@sh.itjust.worksOP
      link
      fedilink
      English
      arrow-up
      2
      ·
      edit-2
      5 days ago

      I think I actually figured it out without the EDID injection, I forgot a line in the sway config. I’ll test it after work today and report back what I have if it works as this method is a cleaner way of getting headless zero copy.

      EDIT: okay, posted. feel free to suggest corrections as I’m still learning.