Skip to content

Instantly share code, notes, and snippets.

@nikes
Forked from robertkirkman/README.md
Created October 13, 2023 17:20
Show Gist options
  • Save nikes/9cffbf86452ad366a96d5349bbeb3e94 to your computer and use it in GitHub Desktop.
Save nikes/9cffbf86452ad366a96d5349bbeb3e94 to your computer and use it in GitHub Desktop.
How to record or stream SteamOS 3.5 Gaming Mode

How to record or stream SteamOS 3.5 in gamescope (Gaming Mode)

Here is another method that uses Flatpak and obs-vkcapture, which don't meet my personal needs but are very likely to be useful for you. In the comments there there is also an obs-gstreamer method.

Here is another method for recording that has its own GUI for Gaming Mode built with Decky Loader.

Prerequisites for all methods shown here

  1. Set a password (if you haven't already) and disable read-only rootfs (yes this means after updating SteamOS [not Steam Client] this will all be deleted and you will have to do all this again if you want to stream again)
passwd
sudo steamos-readonly disable
  1. (OPTIONAL) The on-Steam Deck OBS guide is written in a way that shouldn't require a separate device to actually execute any commands (the Sunshine guide requires a separate device for Moonlight), but for much less awkward and more efficient CLI activity, especially if you don't have a physical keyboard that's compatible with your Steam Deck, you can enable the SSH server to allow remotely connecting using your preferred keyboard-endowed device
sudo systemctl enable --now sshd
  1. Set up pacman

WARNING: If you have a different version of SteamOS from me, this can mess up your rootfs, but luckily there is a backup rootfs in every OFW Steam Deck that you can access with the ・・・ + ⏻ button combination at boot, from which you can recover if that happens. Sometimes the contents of pacman.conf may be edited by SteamOS or become outdated. This pacman.conf is what's currently working correctly for me. SigLevel = Never is set because sometimes, Valve doesn't have their packages signed correctly, making it sometimes impossible to get the correct signatures. What you hope to see after sudo pacman -Syyu is "there is nothing to do", or at least very few upgrades available. That means you have found Valve repositories for your pacman.conf that contain packages very close to the rootfs image that rauc last installed, and the fewer packages that differ from your rootfs' preinstalled packages you have to install, the less likely it is you will encounter severe issues.

curl https://gist.githubusercontent.com/robertkirkman/753922262259486ec417e5ff8b5b924b/raw/2921bcd9d842a2ee8ad32d71e7c8367d7f941d5c/pacman.conf | sudo tee /etc/pacman.conf
sudo pacman-key --init
sudo pacman-key --populate
sudo pacman -Syyu
  1. Reinstall all corrupted packages that once contained header files before Valve deleted /usr/include

You might see a huge number of errors generated by dracut during the post-transaction hooks phase. These are spurious and can be safely ignored.

sudo pacman -S $(pacman -Ql | grep include | cut -d' ' -f1 | awk '!a[$0]++')
  1. Install toolchain packages
sudo pacman --overwrite=/etc/ld.so.conf.d/fakeroot.conf -S base-devel meson cmake
  1. Install your preferred terminal emulator (unless you prefer konsole which is preinstalled), Launch KDE Plasma Xorg (Desktop Mode), open Steam LIBRARY tab, and add it as a non-Steam game; here kitty is used as an example. At this time, I would also suggest you add a large number of dummy/duplicate non-Steam game entries for future use, because if you wish to remain in Gaming Mode, you will be able to change preexisting non-Steam game entries to add new shortcuts, which is otherwise impossible without switching to Desktop Mode.
paru -S kitty
  • Suggested kitty Launch Options in non-Steam game properties:
LD_PRELOAD= %command% --start-as=fullscreen

Sunshine

  1. Fetch dependencies, build and install sunshine using paru
paru -S sunshine
  1. Enable DRM capture mode in sunshine

WARNING: setcap is a security risk and after running it, all users and software with executable permission for the affected binary can be considered effectively root-equivalent (in this context, they would definitely be able to see your screen for example). To remove setcap permissions from any binaries granted this, use sudo setcap -r /path/to/file.

sudo setcap cap_sys_admin+p $(readlink -f $(which sunshine))
  1. Create symlink to stub xrandr to work around Error: [xrandr --output HDMI-1 --mode 1920x1080] failed with code [1], then run sunshine:
ln -s /bin/true xrandr
export PATH=$(pwd):$PATH
sunshine &
  1. Make sure the Steam Deck is connected to Wi-Fi or Ethernet, and identify its local IP address for use in the following steps
ip a
  1. Now move to the LAN device you would like to connect to the Steam Deck's Sunshine from and install Moonlight and a browser capable of accessing Sunshine's PIN entry box, for example epiphany or ungoogled-chromium; example command for an Arch Linux device with yay

Unfortunately, OBS cannot record the moonlight-qt window in gamescope without adding the additional overhead of the OBS section below this section, and epiphany is bugged and does not work in gamescope, so both of these softwares can only be effectively used to connect to Steam Deck Gaming Mode Sunshine from a separate device.

yay -S moonlight-qt epiphany
  1. Launch your browser, connect to the Sunshine web server on the Steam Deck where you replace 192.168.12.146 with your Steam Deck's local IP address, accept all warnings (which occur on every default copy of Sunshine) and create a username and password for administration of Sunshine, re-enter the new credentials to log in, then navigate to the "PIN Pairing" entry box
epiphany https://192.168.12.146:47990
  1. Launch Moonlight and add the Steam Deck's IP address as a new device, then type the PIN provided by Moonlight into the PIN box in the browser window

Sometimes Moonlight will fail to authenticate the first time even if the PIN is correct, just keep trying until you can click on the Steam Deck's entry and see the "Desktop" button.

moonlight
  1. Click the Steam Deck's entry in Moonlight and the "Desktop" button, you can now see the entire Steam Deck screen and almost every menu and game, with a few exceptions - sometimes the onscreen keyboard and Quick Settings menu are invisible in Moonlight, but overall, Sunshine configured this way is capable of capturing much more, more reliably, than any other software. You can also capture the moonlight-qt window using OBS, which works better than the OBS guide below as long as you have this other system to run Moonlight on. Sometimes, sunshine might crash or Moonlight might spontaneously disconnect; if that happens, just restart both and everything will start working again.

If you use Sunshine+Moonlight for streaming-based netplay (someone playing on Steam Deck while someone else plays on another device), you might want to configure advanced audio settings (such as making sure the person using Moonlight can hear the game audio, but not themselves through your VOIP software like Discord). Steam Deck contains two distinct digital sound controllers that behave almost the exact same way their desktop PC counterparts do, which makes such advanced audio settings both possible and nearly identical to how they would be on a desktop Arch Linux PC. Therefore, for now I consider such settings outside the scope of this guide, but if you struggle with audio settings, let me know and I will consider expanding this to cover that common audio use case.

OBS

  1. Install OBS
paru -S obs-studio
  1. If you do not have any unused dummy shortcuts to populate with OBS, launch KDE Plasma Xorg (Desktop Mode), open Steam and add OBS to Library as a non-Steam game, then right click on it, click Properties, and place the following text exactly as shown in the Launch Options box:
LD_PRELOAD= QT_QPA_PLATFORM=xcb %command%
  • There are three possible capture sources for OBS that currently work in gamescope. obs-kmsgrab used to work, and does still work in Xorg as a test, but I think it would need more updates to work with present-day gamescope:

OBS with FFmpeg

Unfortunately, this is a very messy method that encodes twice, stutters a lot, and sometimes looks green.

  1. Install FFmpeg

WARNING: setcap is a security risk and after running it, all users and software with executable permission for the affected binary can be considered effectively root-equivalent (in this context, they would definitely be able to see your screen for example). To remove setcap permissions from any binaries granted this, use sudo setcap -r /path/to/file.

yay -S ffmpeg
sudo setcap cap_sys_admin+ep $(readlink -f $(which ffmpeg))
  1. First create a new Scene in OBS, then add a new Media Source to the Scene and uncheck Local File. Then add the following and click OK
  • Input: udp://localhost:4444

  • Input Format: udp

  1. Switch to gamescope, navigate to Library and launch your terminal emulator, then execute this command; ffmpeg will crash anytime you leave the Steam client window by selecting a game or non-Steam app, and this should automatically restart it
while true; do ffmpeg -thread_queue_size 512 -framerate 60 -device /dev/dri/card0 \
     -f kmsgrab -i - -vaapi_device /dev/dri/renderD128 \
     -vf 'hwmap=derive_device=vaapi,scale_vaapi=format=nv12' \
     -c:v h264_vaapi -bf 1 -f mpegts udp://localhost:4444; done
  • You will also need to bind Ctrl+C to actually be able stop this capture with the least difficulty; navigate to "Controller settings" for your terminal emulator's non-Steam game entry and bind buttons to these keys, as pictured below. It is very possible that there is a better way of controlling ffmpeg without an external keyboard than this, but unfortunately I haven't found that way yet.

image

  1. Navigate to Library, launch OBS and start your stream or recording now. ffmpeg will often crash when you switch windows, but wait for a few seconds each time you do. The loop will automatically reset ffmpeg, and anything you can look at should be captured. When you are done, navigate to OBS and stop your stream or recording, then navigate to your terminal emulator and hold down your Ctrl+C keybind for a few seconds to kill the ffmpeg loop

Sometimes, ffmpeg will only record a small rectangular portion of the screen and the rest will be black. I don't know exactly why this happens and I haven't found any way to consistently prevent it, but it doesn't happen every single time, so if the source looks incomplete in OBS, kill the loop and try running it again until it looks acceptable.

Special thanks to people who helped me with various parts of this guide: scaled#4479 logan2611#2351 kamae#7499 2zd9R#9421 and to the developers of all the software involved

#
# /etc/pacman.conf
#
# See the pacman.conf(5) manpage for option and repository directives
#
# GENERAL OPTIONS
#
[options]
# The following paths are commented out with their default values listed.
# If you wish to use different paths, uncomment and update the paths.
#RootDir = /
DBPath = /usr/lib/holo/pacmandb/
#CacheDir = /var/cache/pacman/pkg/
#LogFile = /var/log/pacman.log
#GPGDir = /etc/pacman.d/gnupg/
#HookDir = /etc/pacman.d/hooks/
HoldPkg = pacman glibc
#XferCommand = /usr/bin/curl -L -C - -f -o %o %u
#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u
#CleanMethod = KeepInstalled
Architecture = auto
# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup
#IgnorePkg =
#IgnoreGroup =
#NoUpgrade =
#NoExtract =
# Misc options
#UseSyslog
Color
#TotalDownload
# We cannot check disk space from within a chroot environment
CheckSpace
#VerbosePkgLists
ParallelDownloads = 10
# By default, pacman accepts packages signed by keys that its local keyring
# trusts (see pacman-key and its man page), as well as unsigned packages.
SigLevel = Required DatabaseOptional
LocalFileSigLevel = Optional
#RemoteFileSigLevel = Required
# NOTE: You must run `pacman-key --init` before first using pacman; the local
# keyring can then be populated with the keys of all official Arch Linux
# packagers with `pacman-key --populate archlinux`.
#
# REPOSITORIES
# - can be defined here or included from another file
# - pacman will search repositories in the order defined here
# - local/custom mirrors can be added here or in separate files
# - repositories listed first will take precedence when packages
# have identical names, regardless of version number
# - URLs will have $repo replaced by the name of the current repo
# - URLs will have $arch replaced by the name of the architecture
#
# Repository entries are of the format:
# [repo-name]
# Server = ServerName
# Include = IncludePath
#
# The header [repo-name] is crucial - it must be present and
# uncommented to enable the repo.
#
# The testing repositories are disabled by default. To enable, uncomment the
# repo name header and Include lines. You can add preferred servers immediately
# after the header, and they will be used before the default mirrors.
#[testing]
#Include = /etc/pacman.d/mirrorlist
[jupiter-3.5]
SigLevel = Never
Include = /etc/pacman.d/mirrorlist
[holo-3.5]
SigLevel = Never
Include = /etc/pacman.d/mirrorlist
[core-3.5]
SigLevel = Never
Include = /etc/pacman.d/mirrorlist
[extra-3.5]
SigLevel = Never
Include = /etc/pacman.d/mirrorlist
#[community-testing]
#Include = /etc/pacman.d/mirrorlist
[community-3.5]
SigLevel = Never
Include = /etc/pacman.d/mirrorlist
[multilib-3.5]
SigLevel = Never
Include = /etc/pacman.d/mirrorlist
# An example of a custom package repository. See the pacman manpage for
# tips on creating your own repositories.
#[custom]
#SigLevel = Optional TrustAll
#Server = file:///home/custompkgs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment