这次折腾的目标不是单纯让 Sunshine 在 KDE 桌面里能用,而是把串流入口前移到 SDDM:机器刚开机、还没有登录 Plasma 时,手机就能看到登录界面;完成登录后,再切换回用户级 Sunshine。同时,这台机器有两块分辨率和缩放不同的显示器,桌面串流还要保留原来的显示器切换与触控坐标适配。

实际踩坑点主要集中在三处:SDDM 和 Plasma 使用的捕获后端不同;Sunshine 的 output_name 不是 DRM connector ID;root 版 Sunshine 如果直接复用用户的 apps.json,会在 SDDM 阶段错误执行 kscreen-doctor。本文把最终可用的配置和每一步判断完整记录下来。

0. 实机环境和最终分工

项目

实际值

用途

系统

Arch Linux

systemd + SDDM

桌面

KDE Plasma Wayland

登录后的用户会话

Sunshine

2026.516.143833-4

用户服务与 SDDM 服务共用程序

显卡

NVIDIA,/dev/dri/card2

NVENC 与 KMS

Wayland 输出 0

HDMI-A-3,1440×900,偏移 0×410

副屏

Wayland 输出 1

DP-3,2560×1440,偏移 1440×0

目标串流屏

SDDM X11 输出

HDMI-0 / DP-0

登录界面的 XRandR 名称

最终分工是: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 running

root 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-setting

SDDM 的 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.target

Restart=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-31 = DP-3;SDDM X11 中则是 0 = HDMI-01 = 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.service

SDDM 阶段

systemctl status sunshine-sddm.service
tail -100 /run/sunshine-sddm.log

日志应出现 capture = x11Screencasting 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 与显示器切换。这样既能在登录前串流,也不会牺牲登录后的多显示器和触控适配。