vdi-cloud/docs/moonlight-kiosk-20261028.md
宋一鸣 85f64df1a5 功能:支持设备身份自动登录并直达桌面列表
变更详情:开机直进桌面列表——设备身份自动登录,移除登录页与退出登录入口

- 构造时以设备 SN 走演示认证,kConfig->kAuthenticating->kDesktopList 同步完成,开机不再显示登录页
- 列表页移除"退出登录"按钮(无登录概念无去向);管理菜单"退出终端"保留
- 登录页与认证代码保留,接平台正式认证后由 DesktopService 驱动恢复登录流程
- 已部署盒子并抓屏验证;文档与 MEMORY 同步
2026-10-30 09:19:17 +08:00

267 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Moonlight 云桌面开机直达落地记录(2026-10-28)
## 起因
上一个对话在做完 RDP/Moonlight 实测对比(见 `rdp-vs-moonlight-comparison-20261028.md`)后,
提出把 Moonlight 产品化为开机直连云桌面,但只列了 5 条待办就中断了。
现场表现:登录盒子后看到的是 MATE 的绿色桌面,不是云桌面。
## 根因
盒子自启项 `~/.config/autostart/vdi-kiosk.desktop` 仍然拉起的是 RDP 版 `kiosk-shell`,
而 Moonlight 从来没有进入过开机自启链;同时命令行直连串流还存在两处硬伤:
1. **应用 id 失效**:Moonlight 图形界面里配对的记录里,`Desktop` 的 app id 是 `881448767`,
但 Sunshine 重装/升级后服务端的应用 id 已经变了,用旧 id 启动直接报
`Qt Critical: 找不到应用程序 881448767`,串流根本起不来。
改用应用**名称** `Desktop` 启动即可,服务端当前返回的应用列表是
`Desktop` / `Steam Big Picture`。
2. **硬解路径不可用**:`moonlight-qt` 的 `--video-decoder auto` 会优先尝试
`h264_v4l2m2m`,在 RK3528 上报 `Could not find a valid device`
(尽管存在 `/dev/mpp_service`、`/dev/rga`、`/dev/dri/renderD128`)。
显式指定 `--video-decoder software` 后串流稳定。
另外两个在联调中发现并修掉的问题:
3. **Monitor 只杀直接子进程**:`vdi-kiosk-monitor` 通过 `sh -c` 启动主进程,
杀掉它只会结束 `sh -c` 包装进程,真正的启动器变成孤儿并继续拉起第二条串流,
两条流同时抢显示设备。已改为子进程独立进程组、按组结束整棵进程树。
4. **主机可达性判断用错了协议**:Windows 防火墙屏蔽 ICMP,盒子 ping 不到 `192.168.1.70`,
但 TCP/UDP 正常。可达性判断改成 TCP 连接探测(`bash /dev/tcp`)。
## 已交付
仓库内新增(`terminal/kiosk-shell/`):
```text
scripts/vdi-moonlight # 云桌面串流启动器(POSIX sh)
etc/moonlight.conf # 串流参数模板
vdi-moonlight.desktop # 开机自启条目(Monitor + 启动器)
```
修改:`src/monitor.cpp`(进程组管理)、`src/monitor_main.cpp` 无改动。
盒子上的部署位置:
```text
~/vdi-terminal/bin/vdi-moonlight # 启动器
~/vdi-terminal/bin/vdi-kiosk-monitor # 看门狗(已按本次修改重新编译)
~/.config/vdi-terminal/moonlight.conf # 串流参数
~/.config/autostart/vdi-moonlight.desktop # 开机自启(已启用)
~/.config/autostart/vdi-kiosk.desktop # RDP 旧路径(已禁用,保留作回退)
```
启动链:
```text
systemd/user autostart
-> vdi-kiosk-monitor --heartbeat-file /tmp/vdi-moonlight.heartbeat --max-restart 200
-- /home/armbian/vdi-terminal/bin/vdi-moonlight
-> moonlight-qt stream 192.168.1.70 Desktop ... (fullscreen)
```
启动器职责:读本地配置 → 等云桌面主机就绪(TCP 探测)→ 全屏串流 →
每 5 秒写心跳 → 检测串流假死(CPU 与网络均无流量超过 `hang-timeout`)→ 失败重试。
## 实测结果
全部在 RK3528 盒子(192.168.1.188)上实测:
| 项目 | 结果 |
|---|---|
| 开机/手动拉起后屏幕内容 | 满屏 Windows 10 云桌面,1920x1080 与屏幕 1:1 无缩放 |
| 杀掉 moonlight-qt 客户端 | 启动器 5 秒内重连成功 |
| 杀掉启动器 | 看门狗 3 秒后重启启动器,重新串流 |
| 心跳文件 | `/tmp/vdi-moonlight.heartbeat` 每 5 秒刷新 |
| 串流进程数 | 始终 1 条,无孤儿进程 |
`moonlight-qt --performance-overlay` 实测(1080p60 / H.264 / 软解):
```text
Video stream: 1920x1080 21.59 FPS (Codec: H.264)
Incoming frame rate from network: 21.59 FPS
Decoding frame rate: 21.59 FPS
Rendering frame rate: 18.15 FPS
Frames dropped by your network connection: 0.00%
Frames dropped due to network jitter: 13.64%
Average network latency: 3 ms (variance: 1 ms)
Average decoding time: 15.04 ms
Average frame queue delay: 47.50 ms
Average rendering time (including monitor V-sync latency): 51.09 ms
```
结论:链路健康,网络丢包 0%,延迟 3 ms;21.6 FPS 的上限来自**服务端**,
VM 100 内 Sunshine 走 libx264 软件编码(无 GPU 直通),抖动丢帧 13.64% 同源。
## 仍未验证 / 下一步
1. **服务端 GPU 直通**:宿主机 `starhe` 有 GTX 965M(`0000:01:00.0`,IOMMU Group 2 独占),
主机同时有 Intel 核显 `0000:00:02.0` 可继续驱动本机显示,具备直通条件。
直通后 Sunshine 可用 NVENC 硬编码,是把帧率提到 60 FPS、改善鼠标拖尾/卡顿的前提。
2. **鼠标卡顿**:性能叠图实测渲染帧率仅 18.15 FPS、帧队列延迟 47.50 ms、
渲染/VSync 51.09 ms,再叠加服务端 libx264 软编码,视频链路本身已累计约 100 ms。
`--absolute-mouse` 已启用,输入模式没有配置错误;体感滞后来自低帧率和视频队列,
根治仍是 Sunshine NVENC。短期可降为 1080p30、使用 `--no-vsync --no-frame-pacing`
做 A/B 测试,但可能增加撕裂,不能替代服务端硬编码。
3. **RK3528 硬解**:`h264_v4l2m2m` / `hevc_v4l2m2m` 缺少可用设备,需要 Rockchip MPP 的
FFmpeg 补丁或 V4L2 request 驱动。当前 1080p 软解可用,4K 需要硬解。
4. **2K 分辨率**:盒子当前屏幕是 1920x1080@60Hz,Sunshine 侧虚拟显示器也是 1920x1080@60Hz。
若产品要求 2K,需要同时调整虚拟显示器分辨率和盒子端显示模式。
5. **音频**:`--audio-on-host` 已开启,但终端出音未经现场耳朵确认。
6. **产品登录流程**:当前开机直连 Moonlight 只是串流技术验证,不是最终产品形态。
最终应由 `kiosk-shell` 显示首配/登录/桌面列表,用户选择后再获取短期连接票据并启动会话;
管理员 Web 控制台是独立的 `console/`,方案见 `docs/web-console-mvp-plan-20261028.md`。
7. **与 RDP 的关系**:RDP 路径代码保留在 `src/rdp_session.*`,自启项已禁用,可随时切回。
正式协议选型仍需按实测数据与产品方案确认,不能仅凭本记录定版。
8. **管理平台 API**:Moonlight 路径目前是本地配置文件驱动,接入自研管理平台后
应由 API 下发主机/分辨率/帧率等参数,替换 `etc/moonlight.conf` 的静态配置。
9. **重启验收异常**:2026-10-28 15:54 执行真实重启后,盒子在 3 分钟内未恢复
`192.168.1.188` 的网络/SSH,局域网扫描也未发现其 SSH 地址。重启前已确认
NetworkManager 连接 `YXTech` 的 `autoconnect=yes`,但真实重启后的开机自启验收因此未完成;
需要现场查看盒子 HDMI 画面/电源状态,并通过串口或本地键盘确认启动与 WiFi 情况。
## 附:常用运维命令
```bash
# 查看状态
/home/armbian/vdi-terminal/bin/vdi-moonlight status
# 查看日志
tail -f ~/vdi-terminal/logs/moonlight-$(date +%Y%m%d).log
tail -f /tmp/vdi-monitor.log
# 手动重启串流
pkill -f '^moonlight-qt stream' # 启动器会自动重连
# 切回 RDP 路径
sed -i 's/^X-GNOME-Autostart-enabled=false/X-GNOME-Autostart-enabled=true/' \
~/.config/autostart/vdi-kiosk.desktop
sed -i 's/^X-GNOME-Autostart-enabled=true/X-GNOME-Autostart-enabled=false/' \
~/.config/autostart/vdi-moonlight.desktop
```
---
# 2026-10-29 追加:登录/桌面列表产品流程落地与网络根因修复
## 新增验证结论(全部实测)
1. **产品流程全面跑通**:开机 → 登录页(本地演示认证)→ 桌面列表
(Windows 可连接 / Ubuntu、麒麟待分配)→ 点击连接 → Moonlight 全屏串流
Windows 10 桌面 → 串流结束自动回桌面列表。
2. **重启验收通过**:真实重启后固定 IP `192.168.1.188` 自动恢复,
唯一自启链 `vdi-kiosk-monitor -> kiosk-shell` 生效,开机只进登录页,
不再出现"先 RDP 后 Moonlight"双链竞争。
3. **Monitor 崩溃恢复**:kill -9 kiosk-shell 后 4 秒内自动重启,心跳正常。
## 昨晚两次串流失败的根因(重要)
用户给盒子配静态 IP `192.168.1.188` 时,是在 DHCP 连接上"添加地址",
导致 wlan0 同时持有 `.185`(DHCP)和 `.188`(静态)两个地址。
双地址引发 ARP 混乱,实测:
```text
盒子 -> 网关 ping 丢包 66%~85%(间歇)
PC -> 盒子 ping 丢包 33%
UDP 双向近乎全丢(Moonlight 的视频/控制都是 UDP)
TCP/SSH 基本正常
```
Moonlight 两次失败(38 秒断流、第二次连不上)均为该丢包所致,
与 Moonlight 参数、Sunshine 无关。WiFi 信号本身满格(-38dBm)。
修复:`nmcli` 将 YXTech 连接改为 `ipv4.method=manual` 纯静态,
只保留 `.188` 一个地址。修复后网关 ping 0% 丢包(60/60),
串流稳定运行 7 分钟以上直至手动结束。
**教训:给无线终端配静态 IP 必须用 `ipv4.method=manual` 整体替换,
不能在 DHCP 连接上叠加第二个地址。**
## 鼠标延迟 A/B 实测(1080p60,服务端 libx264)
| 指标 | 基线 vsync+frame-pacing | no-vsync + no-frame-pacing |
|---|---|---|
| 串流帧率 | 21.64 FPS | 21.60 FPS |
| 渲染帧率 | 18.20 FPS | 18.16 FPS |
| 网络丢帧 | 0.00% | 0.00% |
| 抖动丢帧 | 15.91% | 13.64% |
| 帧队列延迟 | 44.13 ms | 47.21 ms |
| 渲染/VSync | 48.79 ms | 49.49 ms |
结论:关闭 vsync/frame-pacing **无改善**(队列延迟反而略升)。
~45ms 队列延迟 ≈ 一个帧间隔(21.6FPS → 46ms/帧),
瓶颈是服务端软编码帧率,不是客户端参数。
决定:保持 vsync + frame-pacing 开启(C++ 默认),
`etc/moonlight.conf` 默认值已同步改回 `1`。
鼠标卡顿的根治手段仍是服务端 GPU 直通 + NVENC。
---
# 2026-10-29 下午追加:四件事落地(删 RDP / 退出设计 / 过场层 / ultrafast 实测)
## 已交付(全部编译部署到盒子并实测)
1. **删 RDP**:`rdp_session.*`、FreeRDP 渲染管线、CMake 构建依赖全部移除,
协议概念(`Protocol` 枚举)从代码删除,Moonlight 是唯一会话通道;
RDP 代码只存在于 git 历史(网关备用)。部署后 `ldd kiosk-shell` 无任何 freerdp 依赖。
2. **退出设计三层**:
- 会话内 `Ctrl+Alt+Shift+Q` 退出串流回桌面列表——moonlight-qt 自带快捷键为主路径,
kiosk 侧保留同一快捷键兜底(串流未建立/焦点仍在 kiosk 时生效);
- 桌面列表右上角"退出登录"→ 登录页(已有);
- 登录页删除"退出"按钮(退出终端是维护功能,只留在管理菜单 Ctrl+Alt+Shift+M)。
3. **加载过场层**:新增 `src/transition_overlay.*`,点连接后全屏置顶黑层
("正在进入云桌面…"动态省略号 + 旋轮),盖住 moonlight-qt 启动期左上角小窗闪烁;
首帧检测用 moonlight 进程 CPU 时间近似(软解 CPU 远高于握手期,阈值 120 tick / 15s 兜底),
检测到后 1 秒淡出。活动期间吞键盘鼠标、周期 raise 保持置顶。
4. **Sunshine x264 预设 ultrafast**:VM 100 的 `C:\Program Files\Sunshine\config\sunshine.conf`
写入 `sw_preset = ultrafast`(该版本支持 `sw_preset`/`sw_tune` 键),服务已重启生效。
## 关键实测结论:21.6 FPS 帽子不在 x264,旧根因判定被推翻
ultrafast 前后对照(1080p60 / H.264 / 盒子软解,同参数同网络):
| 指标 | medium(基线 10-28) | ultrafast(本次) |
|---|---|---|
| Video stream FPS | 21.59~21.64 | 21.57~21.61 |
| 抖动丢帧 | 13.64%~15.91% | 13.64%(分毫不差) |
| 客户端解码 | 15.04 ms | 10.51~11.14 ms |
决定性证据:
- 串流进行中 VM 内 `Processor(_Total)` CPU 仅 0.2%~0.5%,
sunshine 进程自服务重启起累计 CPU 时间仅 14 秒(含三次共约 3 分钟会话);
- 用 xdotool 持续晃鼠标制造画面运动,帧率与 CPU 都不变;
- libx264 只有 `MMX2 SSE2Fast SSSE3 SSE4.2`——VM CPU 型号是
`QEMU Virtual CPU version 2.5+`(kvm64 类),宿主指令集(含 AVX2)没有透传。
结论:**21.6 FPS 的上限来自虚拟显示/捕获节奏(IddSampleDriver/MttVDD 呈现与
Desktop Duplication 的脏帧节奏,叠加 QEMU 显示栈),不是编码器算力**——
编码器近乎空转,预设怎么调都不会变。ultrafast 保留(无害,客户端解码也略降)。
根治路径按优先级:GPU 直通(NVENC + 真实显示栈)> 换 VM 显示方案
(VirtIO-GPU / cpu=host 先排除 QEMU 显示栈因素)> 都不是调 Sunshine 参数能解决的。
## 运维新装 Linux 云桌面 VM(2026-10-29 接入信息)
| VM | Proxmox | 地址 | 账号 | 实测 |
|---|---|---|---|---|
| kylin-test | 101 | 192.168.1.71 | test1 / yx66668888 | SSH 可登,银河麒麟 V10 SP1 桌面版,UKUI + Xorg,图形会话运行中 |
| ubuntu-test | 102 | 192.168.1.72 | test2 / yx66668888 | SSH 可登,Ubuntu 24.04.4 LTS,GNOME + Xorg,图形会话运行中(4 核 / 5.8GiB) |
两台均未装 Sunshine(47989 等端口关闭),还不能被 Moonlight 连接。
接入桌面列表的步骤:装 Sunshine(Linux 版)→ 配对 → 在盒子"桌面连接设置"里
把 Ubuntu/麒麟卡片的地址填上即可(kiosk 代码已支持,无需改代码)。
---
# 2026-10-30 追加:开机直进桌面列表
按产品决定,盒子开机不再显示 kiosk 登录页,直接进入"选择云桌面"列表页:
- 构造时以设备身份(SN)自动走 DesktopService 演示认证(SN 即当前用户展示),
状态链 `kConfig -> kAuthenticating -> kDesktopList` 同步完成,无登录页闪烁;
- 列表页右上角"退出登录"按钮移除(无登录概念后无去向),管理菜单"退出终端"保留;
- **登录页与 DesktopService 认证代码全部保留**:接入管理平台正式认证
(/api/v1/terminal/session/login)后,由 DesktopService 决定是否回到登录流程,
页面代码无需重写;git 历史含完整"登录页 -> 桌面列表"产品流程版本。
- 已编译部署盒子并抓屏验证:开机落在桌面列表,Windows 可连接、Ubuntu/麒麟待分配。