Files
simba-rmic-2026/docs/testing/realtime.md
T
sloray 6a0eb14b28
构建客户端 / 检查(类型 + 单元测试) (push) Waiting to run
构建客户端 / Linux x64(deb + AppImage) (push) Blocked by required conditions
构建客户端 / Windows x64(NSIS 安装包) (push) Blocked by required conditions
构建客户端 / macOS 通用(.app + .dmg) (push) Blocked by required conditions
docs: 整理项目文档并统一界面表述
将项目说明按主题集中到 docs,补齐根目录 README 和 AGENTS,移除弃用方案并保留有效测试记录与未实现提案。同步文档索引、引用及改动日志生成路径,README 增加 GitHub Markdown 导航和 Mermaid 图。

- fix(client): 统一状态与操作文案,录制和截图成功后再显示完成提示
- test(client): 按文件名核对媒体类型,避免依赖时间戳排序

验证:23 份项目文档、144 处本地引用、27 条外链、2 张 Mermaid 图;前端构建和 12 项测试;截图与录制的 4 条异步反馈路径;Windows Rust 编译检查和后端测试。后端 40 项返回成功,其中 3 项 ffmpeg 集成用例因本机缺少工具而未实际执行。
2026-10-19 11:26:26 +08:00

7.1 KiB
Raw Blame History

阻塞恢复与最新帧处理(2026-10-18)

当前交付

当前 15 dBm 交付 App SHA-256:a6092e4b0cf42819c04424e066651f285b8961312a73822d667532f800e46767,应用分区 0x70000。COM8 烧录与三段独立校验通过;355.1 秒串口的 71 次功率回读均为 15.00 dBm。五分钟观察:原生完整接收 29.68 fps,丢帧 1.045%,本地 JPEG 通道 28.23 fps,31 张抽帧全部完整解码为 640×480 RGB,无无效 JPEG、设备离线、通道断开、复位或采集错误;仍有最长 1.646 秒的到帧间隔,不能称为无卡顿。距离与拥塞分析、测试边界见 功率与拥塞记录 和制品 POWER-RESULT.json。

沿用已确认可用的三块 PSRAM 采集缓冲、OV5640 VGA 彩色、约 30 fps PLL 时钟、AE 目标 45/55、约 20 ms 曝光上限及自动增益;Wi-Fi 自动重连和 TUN 兼容订阅保持不变。没有增加待发送 JPEG FIFO,也没有为了消除队列改成单块 DMA 缓冲。

发送程序只持有当前一张完整 JPEG;阻塞恢复后通过有限次数的零等待取帧选择最新有效帧,旧帧立即归还驱动。三块采集内存用于捕获余量,与必须按序播放的三帧队列不同。已有相机队列仍然有限,应用交接会跳过其旧帧。

完整 JPEG 取得后按 1400 字节载荷分片立即提交,复用一个数据报缓冲,直接读取 PSRAM。当前传感器驱动在 JPEG 结束后交出完整帧,本次没有改成在 DMA 尚未完成时就读取其内容;不完整 JPEG 由接收端整帧丢弃,不进入绘制。

阻塞处理

阶段 处理方式
采集交接 首帧最多等待 100 ms,其后零等待、有限次数取更新的有效帧;归还被替代的旧缓冲
发送帧龄 用板内同一单调时钟检查从首个 DMA 缓冲开始的年龄,期限 100 ms
当前帧发送 绝对检查期限 25 ms,成功发送分片不会续期,所有订阅者共享
拥塞重试 默认每帧最多 8 ms 让出调度重试;预算用尽或过期后放弃该目标剩余分片,转向新帧
原生本地通道 每路保留最新帧;不重放超过 100 ms 的缓存,写入超过 100 ms 时断开慢端以便重连
WebView / 解码 原生端在 JPEG 前发送 frameTiming;JS 在解码前后拒绝本机滞留超过 100 ms 的帧并释放旧结果
CAM_FB_COUNT=3
CAM_AE_LEVEL=-1
CAM_EXPOSURE_EV=0
CAM_EXPOSURE_MAX_LINES=592
UDP_PACKET_GAP_US=0
UDP_RETRY_BUDGET_US=8000
WIFI_TX_POWER_DBM=15

当前交付根据用户反馈回退到 15 dBm。启动和重连应用同一功率上限,拥塞和温控逻辑不自动降功率;此前 17 dBm 的数据作为历史记录保留,见 功率与拥塞记录。

若要在发送回压时立即放弃本帧,可将 UDP_RETRY_BUDGET_US=0 后重编烧录。该模式仍保留三块采集内存和完整 JPEG 校验;这里的“零”指不让出调度重试,不是删除驱动和路由器中的所有缓冲。零重试策略已经主机测试,本次五分钟实机使用默认 8000 μs。

分片间隔也计入 25 ms 检查期限,不再额外延长帧的发送寿命;设置过大的间隔可能使整帧无法在期限内提交。分片在 SDK socket 中已经接受后无法由本策略撤回,底层调度和网络排队也无法由应用层强制抢占。以上为应用层新鲜度策略,不能保证每帧、无线链路或物理屏幕具有硬实时上限。

本地 JPEG 二进制头继续为 16 字节,旧消费者可忽略新增文本消息。新前端连接旧后端时仍可用,但没有原生发布时间,只能按 JS 收到时刻判断本地队列年龄。两端本机发布时间使用同机系统时间;这不是 ESP 与电脑的时钟同步,也不能据此计算无线单向延迟。JS 内部排队同时使用单调时钟检查。

此前 14 dBm 版本的实机五分钟检查

该次测试使用 14 dBm,App SHA-256:9a7decd59572c3f280e7fd4c0a291645011b779025e56e99ea50087e92b5fa77,应用分区 0x60000。以下五分钟数据属于该历史镜像,不是提高功率后的重测结果。该镜像曾经 COM8 烧录并独立三段校验,三段镜像必须成套使用。运行保留 TUN、只有一个 UDP 订阅者;串口和本地视频观察器不会产生额外 UDP 推流。

指标 本次结果
本地 JPEG 通道观察时长 300.005 s
原生接收计数有效区间 180.937 s
完整接收 / 丢帧 5390 / 26(仅有效区间)
完整接收帧率 / 帧损失率 29.79 fps / 0.480%(仅有效区间)
本地 JPEG 通道 29.69 fps
本地 JPEG 通道到达间隔 P95 / 最大值 47.648 / 323.146 ms
主动跳过旧采集帧 0
发送前过期帧 / 发送期限目标丢弃 0 / 0
提交时采集帧龄最大观测值 74.13 ms
发送持有时间最大观测值 11.23 ms
复位 / 采集错误 0 / 0

观察途中界面切到队伍端,按设计隐藏诊断计数,所以原生完整帧率和损失率只报告隐藏前的有效区间,不提供完整五分钟的原生丢帧率;本地 JPEG 通道则完整观察五分钟。保留用户当前界面选择,没有强制切回裁判端。两个最大值是板端自启动起的观测值,包含预热;帧龄从驱动的首个 DMA 缓冲时间戳开始,不是光子进入传感器到屏幕的时间。主动跳过的采集帧尚未分配网络帧号,不计入接收端丢帧率;两种计数不能混为一谈。另抽取 61 张 JPEG,均完整解码为 640×480 RGB。

部署前的 30 秒基线仅用于检查连通性,画面内容和无线状态有变化,不能据此证明本策略使丢帧率或光学延迟降低。本次未重新测量物理端到端延迟,也未证明所有长程拥塞峰值均已解决。较早的标记回显测量保留在 延迟测量。

阻塞恢复验证

真实原生视频通道上的辅助接收端主动阻塞事件循环 350 ms,生产 StreamClient 恢复后拒绝 8 张过期帧,帧号从 1886 前进至 1918。该测试没有新增 UDP 订阅者;JPEG 解码在此辅助测试中使用替身,验证的是本地积压年龄和恢复逻辑,实际 JPEG 完整解码另行检查。

  • 12 项 Rust 调度策略测试:绝对帧期限、旧采集帧寿命、共享重试预算、零重试及原有调度策略。
  • 4 项 C 驱动交接情景:有限次数追赶、旧缓冲仅归还一次、无有效新帧时保留已有帧、首次超时及单缓冲边界。
  • 8 项前端测试:慢解码保留最新待处理帧、500 ms 本机积压拒绝、阻塞解码结果释放、待解码帧超期和原有关闭/重启处理。
  • 10 项原生视频通道测试:时间标记先于对应 JPEG、重连不重放过期缓存及原有协议与通道行为。

使用 python scripts/test-latest-frame.py 运行驱动交接测试;desktop/ 中运行 pnpm test:stream。实时通道故障测试为 node desktop/scripts/test-live-freshness.mjs <本机私有调试日志> <结果JSON>,日志内的通道令牌仅在程序内部读取,不应发布。完整测量与边界见制品 REALTIME-RESULT.json,不包含私有日志、用户配置或相机抽帧。