Arch Linux 下让 Sunshine 接管 SDDM:X11 捕获、服务交接与多显示器触控适配
这次折腾的目标不是单纯让 Sunshine 在 KDE 桌面里能用,而是把串流入口前移到 SDDM:机器刚开机、还没有登录 Plasma 时,手机就能看到登录界面;完成登录后,再切换回用户级 Sunshine。同时,这台机器有两块分辨率和缩放不同的显示器,桌面串流还要保留原来的显示器切换与触控坐标适配。
实际踩坑点主要集中在三处:SDDM 和 Plasma 使用的捕获后端不同;Sunshine 的 output_name 不是 DRM connector ID;root 版 Sunshine 如果直接复用用户的 apps.json,会在 SDDM 阶段错误执行 kscreen-doctor。本文把最终可用的配置和每一步判断完整记录下来。
0. 实机环境和最终分工
最终分工是:SDDM 阶段由 system 级 root Sunshine 使用 X11 捕获;登录 Plasma 后,root 服务停止,用户级 Sunshine 使用原有 Wayland/KMS 路径。两者共享证书、配对信息和基础配置,但不共享应用列表。
1. 503 的含义:端口活着不等于视频服务可用
最开始手机能发现主机,但启动 Desktop 返回 503。Sunshine 的 Web UI 甚至还能显示在 https://localhost:47990,真正有用的是 /run/sunshine-sddm.log:
Error: [wayland] Environment variable WAYLAND_DISPLAY has not been defined
Warning: [portalgrab] Failed to connect to dbus. Cannot enumerate displays
Error: Unable to initialize capture method
Error: Platform failed to initialize
Fatal: Unable to find display or encoder during startup.
Error: Failed to create client: Daemon not runningroot system service 不属于桌面用户的 Wayland 会话,没有 WAYLAND_DISPLAY,也没有用户 DBus 和 portal。Sunshine 仍能开放管理端口,但视频 daemon 没有初始化,因此 Moonlight 启动应用时只能得到 503。
2. 为什么强制 capture=kms 仍然不稳定
第一版修复是在 root 服务后追加 capture=kms output_name=0。手动启动时它确实成功过:
Screencasting with KMS
/dev/dri/card2 -> nvidia-drm
Found monitor for DRM screencasting
Found connector ID [1211]
Found cursor plane [194]但重启后仍会失败。继续查看 SDDM 日志才发现,这台机器的 greeter 运行在 X11:
Running: /usr/bin/X -nolisten tcp -background none -seat seat0 vt2 ...
Starting X11 session: /usr/bin/sddm-greeter-qt6 ...Sunshine 二进制里还有一条直接的判断:
Avoiding KMS capture under X11 due to lack of atomic mode-settingSDDM 的 Xorg 正持有显示设备时,继续把 KMS 当作唯一方案并不可靠。正确做法是连接 SDDM 已经存在的 X11 display,并使用它动态生成的 Xauthority。
3. DISPLAY 固定,Xauthority 不能写死
本机 SDDM 的 socket 是 /tmp/.X11-unix/X0,所以 DISPLAY=:0。认证文件则类似 /run/sddm/xauth_SlcbgF,随机后缀每次启动都可能变化。
服务启动前应同时等待三件事:/run/sddm/xauth_* 已生成、/tmp/.X11-unix/X0 是 socket、sddm-greeter 进程确实存在。最后一个条件很重要,因为用户登录 Plasma 后,X0 socket 仍可能残留,只检查 socket 会把 root Sunshine 错误启动到桌面阶段。
4. 最终的 sunshine-sddm.service
[Unit]
Description=Sunshine for the display manager session
Requires=sddm.service
After=sddm.service
PartOf=sddm.service
[Service]
Type=simple
User=root
Group=root
Environment=HOME=/home/luorix
Environment=XDG_CONFIG_HOME=/home/luorix/.config
ExecStartPre=/bin/sleep 5
ExecStartPre=/bin/sh -c 'for i in $(seq 1 30); do set -- /run/sddm/xauth_*; if [ -f "$1" ] && [ -S /tmp/.X11-unix/X0 ] && /usr/bin/pgrep -f sddm-greeter >/dev/null; then exit 0; fi; sleep 1; done; exit 1'
Environment=DISPLAY=:0
ExecStart=/bin/sh -c 'set -- /run/sddm/xauth_*; export XAUTHORITY="$1"; exec /usr/bin/sunshine /home/luorix/.config/sunshine/sunshine.conf file_apps=/home/luorix/.config/sunshine/apps-sddm.json log_path=/run/sunshine-sddm.log system_tray=disabled capture=x11 output_name=0'
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.targetRestart=always 是因为 Sunshine 在部分捕获初始化失败场景会以 0 退出,Restart=on-failure 不会重试。启动前循环最多等待 30 秒,用来覆盖 greeter 初始化时序。
5. root 服务必须使用独立 apps-sddm.json
切换到 X11 后,SDDM 画面已经可以检测和编码,但手机启动 Desktop 仍一直没有画面。日志给出了新的原因:
Screencasting with X11
Streaming display: HDMI-0 with res 1440x900 offset by 2560x0
Executing Do Cmd: [kscreen-doctor output.HDMI-A-3.disable]
Error: [kscreen-doctor output.HDMI-A-3.disable] exited with code [15]root Sunshine 读取了用户的 apps.json,继承了 Desktop 的 Wayland 多显示器命令。但 SDDM 是 X11 greeter,没有用户 Plasma DBus,输出名称也不同,此时执行 kscreen-doctor output.HDMI-A-3.disable 必然失败。
SDDM 应使用一个最小的独立应用列表:
{
"env": { "PATH": "$(PATH):$(HOME)/.local/bin" },
"apps": [
{ "name": "Desktop", "image-path": "desktop.png" }
]
}root unit 通过 file_apps=/home/luorix/.config/sunshine/apps-sddm.json 使用它。这样手机点击 Desktop 时只开始捕获,不再执行 KDE 命令。
6. 登录前后如何交接两个 Sunshine 服务
用户级服务名是 app-dev.lizardbyte.app.Sunshine.service。给它添加 drop-in:
[Service]
ExecStartPre=
ExecStartPre=/usr/bin/systemctl stop sunshine-sddm.service
ExecStartPre=/bin/sleep 5
ExecStopPost=/usr/bin/systemctl --no-block start sunshine-sddm.service登录 Plasma 时,用户 Sunshine 启动前先停 root 服务,等待端口和 NVIDIA 编码资源释放;退出桌面会话时,再异步排队启动 root 服务。这里必须有 --no-block,否则用户服务停止过程会同步等待 SDDM greeter,而 greeter 又要等当前会话退出,容易形成看起来像“注销卡住”的等待链。
普通用户还需要有权启停这一项 system service,对应 polkit 规则:
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "sunshine-sddm.service" &&
subject.user == "luorix") {
return polkit.Result.YES;
}
});规则只放行这一个 unit,没有把任意 systemd 管理权限交给桌面用户。
7. 多显示器下 output_name 和触控坐标为什么会错位
output_name 在不同捕获后端下使用不同的枚举:Plasma Wayland 中 0 = HDMI-A-3、1 = DP-3;SDDM X11 中则是 0 = HDMI-0、1 = DP-0。KMS 日志中的 1211/1214 是 DRM connector ID,不是 Sunshine 输出编号。
曾经把 1214 填进配置,结果是:
Couldn't find monitor [1214]画面和触控还有另一个层次的问题。两块屏幕同时启用时,绝对触控坐标按整个桌面布局换算;即使视频抓的是 DP-3,触摸也可能落到 HDMI-A-3 所在的逻辑区域。把 output_name 从 0 改成 1,只改变捕获目标,不会自动改变系统的绝对坐标空间。
用户级 Desktop 因此继续保留原来的准备命令:
{
"name": "Desktop",
"image-path": "desktop.png",
"prep-cmd": [
{
"do": "kscreen-doctor output.HDMI-A-3.disable",
"undo": "kscreen-doctor output.HDMI-A-3.enable"
}
]
}串流开始时暂时禁用 HDMI-A-3,DP-3 成为唯一输出并重新编号为 0。此时视频捕获、绝对触控坐标和 native_pen_touch = enabled 都落在同一块屏幕上;结束串流后再恢复 HDMI-A-3。这套适配只属于 Plasma 用户会话,不能放进 SDDM 的应用列表。
8. 安装与验证顺序
安装 unit、polkit 规则、用户 drop-in 和独立应用列表后执行:
sudo systemctl daemon-reload
sudo systemctl enable sunshine-sddm.service
systemctl --user daemon-reload
systemctl --user enable app-dev.lizardbyte.app.Sunshine.service
sudo systemctl restart polkit.serviceSDDM 阶段
systemctl status sunshine-sddm.service
tail -100 /run/sunshine-sddm.log日志应出现 capture = x11、Screencasting with X11、检测到 HDMI-0/DP-0 和可用 NVENC 编码器。手机启动 Desktop 后,不应再出现任何 kscreen-doctor。
登录 Plasma 后
systemctl status sunshine-sddm.service
systemctl --user status app-dev.lizardbyte.app.Sunshine.service
journalctl --user -u app-dev.lizardbyte.app.Sunshine.service -n 100此时 root 服务应为 inactive,用户服务应为 active。用户日志可以继续走 KMS/Wayland,并保留 Desktop 的显示器禁用与恢复命令。
最终检查清单
开机停在 SDDM 时,Moonlight 能发现主机并打开 Desktop;
SDDM 画面连续显示,不再返回 503;
登录 Plasma 后串流连接可以重新建立;
用户 Desktop 开始时 HDMI-A-3 被禁用,结束后恢复;
增强多点触控开启后,触摸位置与 DP-3 画面一致;
root 日志不执行用户的
kscreen-doctor;桌面阶段不会同时存在 root 和用户两个 Sunshine 进程。
9. 最终需要分离的三种状态
这次问题表面上是 503 和触控错位,实际是把三组本应分开的状态混在了一起:SDDM X11 与 Plasma Wayland 的捕获环境、DRM connector 与 Sunshine 输出索引、登录界面应用列表与桌面多显示器准备命令。
最终方案没有强行让一个配置覆盖所有阶段,而是共享配对和基础 Sunshine 配置,同时分离捕获参数与 apps.json。SDDM 使用 X11 + 动态 Xauthority,Plasma 保留原来的 KMS/Wayland 与显示器切换。这样既能在登录前串流,也不会牺牲登录后的多显示器和触控适配。