Files
m20_gamepad/TODO.md
T
hexone2086 d3b2ef1102 docs: 记录 RTSP 低延迟调研结论与 rtsp-client-android 集成决策
- AGENTS.md: RTSP 视频流章节重写——现状(ExoPlayer)、延迟根因分析、
  决策(弃用 ExoPlayer 视频渲染,集成 rtsp-client-android v5.6.5)、
  库的关键技术要点(零缓冲架构/仅TCP/H.265 FU/内置延迟统计/已知坑)
- TODO.md: 视频低延迟改造拆解为 7 个可执行任务
2026-08-13 08:55:01 +08:00

9.0 KiB
Raw Blame History

TODO

待办

视频低延迟改造(进行中,分支 feature/rtsp-low-latency

  • 集成 rtsp-client-android:将 /tmp/rtsp-client-android/library-client-rtsp 拷贝为本地模块(如 rtspclientlibrary/),替换 ExoPlayer 视频渲染
  • Compose 封装:RtspSurfaceViewAndroidView,替换 video/RtspVideoPlayer.ktPlayerView;保留现有 VideoCodec 枚举映射到 DecoderType.HARDWARE/SOFTWARE,设置界面 video_codec 选项复用
  • 保留 RTSP 自动重连:rtsp-client-android 无内置重连,移植现有指数退避逻辑(1s→30s,URL/codec 变化重置)
  • 接入延迟统计:RtspSurfaceView.statisticsvideoDecoderLatencyMsec/networkLatencyMsec 显示到状态栏或日志,验证延迟改善
  • 起播黑屏排查:若 H.265 起播黑屏,检查 RtspProcessor CSD 拼装顺序(sps+pps+vps,应为 VPS→SPS→PPS
  • 可选:FrameQueue(60) 改小(10~20)进一步压缓冲;剔除 media3/camera 依赖(仅需 jcodec
  • 删除 ExoPlayer RTSP 依赖与 RtspVideoPlayer.kt 旧实现(保留 VideoCodec/VideoResizeMode 枚举迁移)

其他

  • 视频进一步延迟优化:探索更激进的低延迟策略(跳过 Media3 ExoPlayer,直接使用 MediaCodec + SurfaceView)——已由上方 rtsp-client-android 集成方案承接

已完成

  • Gradle 配置:版本目录、摇杆本地模块、全部依赖
  • 协议层:Header.kt(16 字节小端编解码)
  • 协议层:ApduMessage.ktHeader + ASDU 封装)
  • 协议层:ControlCommands.kt(全部指令构建函数 + 常量)
  • 协议层:StatusReports.kt(全部状态上报数据类 + JSON 解析器)
  • 协议层:PacketEncoder.ktMsgId 管理 + APDU 编码)
  • 协议层:PacketDecoder.ktAPDU 解码 + 缓冲区搜索)
  • 网络层:ProtocolClient.ktUDP socket、心跳 1Hz、指令发送通道、接收循环、断线检测 3s、订阅触发)
  • 摇杆映射:JoystickController.ktangle/power -> X/Y/Yaw
  • 状态管理:MainViewModel.ktProtocolClient 生命周期、20Hz 轴指令循环、状态收集)
  • 视频播放:RtspVideoPlayer.ktMedia3 ExoPlayer RTSPComposable 包装)
  • 主界面:MainScreen.kt(视频背景 + 双摇杆 + 状态栏 + 控制按钮)
  • 入口:MainActivity.kt + INTERNET 权限
  • 持久化层:AppSettings.kt(配置数据类 + 默认值 + 校验)、SettingsRepository.ktDataStore Preferences 封装,settings: Flow<AppSettings> + 单项 setter + setAll())、M20App.ktApplication 子类,进程级 settingsRepository 单例)
  • 设置界面 UISettingsScreen.kt(主机/端口/RTSP 输入 + 编码器 ExposedDropdownMenu,保存按钮调用 setAll 后回调 onSaved
  • 导航框架:NavRoutes.ktMAIN/SETTINGS 路由常量)、MainActivity.kt 改写为 AppNavGraph()NavHoststartDestination=MAIN,主界面齿轮按钮跳转设置,返回/保存后 popBackStack 到 MAIN
  • 连接参数从设置读取:MainViewModel 构造注入 SettingsRepositorysettings: StateFlow<AppSettings>stateIn(Eagerly)),connect() 读取 settings.value 的 host/portinit {} 监听 host/port 变化(distinctUntilChanged)后断开当前连接,下次连接使用新参数(符合"修改设置后断开当前连接"约束)。移除 DEFAULT_HOST/DEFAULT_PORT/DEFAULT_RTSP_URL 硬编码
  • 连接状态机:RobotConnection.kt(连接状态流转校验 isValidConnectionTransition,运动状态机 requestMotionTransition 按 proto.md 2.3 正向流程 空闲->站立->RL控制 校验;canSwitchGait/canSendAxisCommand 仅 RL 控制下放行;MotionTransitionResult 枚举反馈)。MainViewModel 经状态机校验后下发指令,轴指令循环非 RL 控制时发零速度
  • 状态上报 UI 展示:StatusPanel.kt(异常列表+错误码映射 ErrorCodes.kt、运控状态 Roll/Pitch/Yaw/速度/高度、设备温度电机/驱动器最高温、电池左右电压/电量/温度),顶部状态栏 Info 按钮触发底部弹出面板;指令失败/状态机拒绝通过 Snackbar 反馈
  • 更多控制按钮:Mode(常规/导航/辅助)、步态(基础/楼梯/平地敏捷/楼梯敏捷)、照明(前/后灯开/关)、充电(开始/结束)、休眠(休眠/唤醒)。底部控制区可纵向滚动,点击"更多"展开全部控制选项
  • RTSP 解码器策略实现:VideoCodec 枚举含 AUTO/FORCE_HW/FORCE_SW_H264/FORCE_SW_H265toMediaCodecSelector() 映射到对应 MediaCodecSelectorDefaultLoadControl 最小缓冲(100ms起播,总缓冲<500ms,无回退缓存,时间优先于大小阈值);FORCE_HW 模式对所有 MIME 仅保留硬件加速解码器
  • 摇杆尺寸增大:左右摇杆从 140dp 增大到 180dp,提升操控精度
  • 视频缩放模式:VideoResizeMode 枚举(FIT/ZOOM/FILL),设置界面新增"视频缩放模式"下拉选项,持久化保存,实时生效
  • 状态机修复:趴下状态下允许切换站立状态(机器人站立后自动进入 RL 控制,无需 App 下发)
  • UI 布局:增加 bg1.png 作为底图,无视频流时显示(视频流播放时覆盖底图)
  • UI 布局:开关灯合并为前灯/后灯两个按键,通过颜色(琥珀色=开/暗色=关)表示置位状态,配合机器人回报状态同步
  • 状态栏:ICMP 延迟测量 + WiFi 信号强度图标显示,放置于连接状态文字右侧,延迟独立于连接生命周期
  • UI 布局:StatusBar 背景延伸到屏幕顶端,视觉吸附优化(Box + Row 双层结构,背景填满状态栏区域)
  • UI 布局:连接按钮合并到顶部 StatusBar 的 ConnectionIndicator,删除底部独立连接按钮
  • UI 布局:ConnectionIndicator 改为按钮形态(Surface + 圆角边框),仅指示器区域可点击切换连接
  • UI 布局:隐藏系统状态栏(WindowInsetsControllerCompat),压缩自定义 StatusBar 高度,扩展可视区域
  • UI 布局:功能按钮均布在四周——左上角模式选择+步态切换+起立/趴下,右上角灯光+休眠+充电,充分利用屏幕空间,优化单手操作体验
  • UI 布局:起立/趴下合并为切换按钮(琥珀色=站立时显示"趴下",暗色=非站立时显示"起立"),移至左上角 StatusBar 下方
  • UI 布局:模式选择器(常规/导航/辅助,3个互斥按钮,无缝隙,底色显示当前模式)移至左上角,位于起立/趴上方
  • UI 布局:步态切换(基础/楼梯/平地敏捷/楼梯敏捷,4个互斥按钮,无缝隙)移至模式选择器下方,始终显示,仅普通模式+RL控制时可点击
  • UI 布局:照明/休眠/充电移至右上角,紧凑排列(前灯后灯无缝隙一行,休眠/唤醒切换,充电/充电中切换)
  • UI 布局:底部控制区移除"更多"展开区域,仅保留左右摇杆
  • UI 布局:所有功能按钮统一使用平行四边形形状(左侧按钮斜边左下→右上,右侧按钮斜边左上→右下)
  • UI 布局:所有控制按钮在未连接时灰色不可点击
  • 连接状态准确性修复:ProtocolClient 收到首个有效数据包后才标记 CONNECTED,不再 socket 创建后立即标记;CONNECTING 状态 5 秒无响应自动超时回退 TIMEOUT
  • 连接按钮交互优化:CONNECTING 状态下点击连接按钮仅断开回到 DISCONNECTED,不再自动重连,由用户手动再次点击发起重试
  • 状态机补充:RobotConnection 允许 CONNECTING → TIMEOUT 合法转换
  • 心跳启动时机修复:ProtocolClient.connect() 立即启动心跳线程,不再等待首次收到数据包后才启动;心跳在 CONNECTINGCONNECTED 状态下均正常运行
  • 软急停滑块:右上角新增平行四边形水平滑块,滑到右侧触发软急停(MOTION_DAMPING),跟随机器人状态上报自动归位
  • 状态上报闪烁修复:_latestStatus 改用合并策略(prev.copy),保留上次报告的非 null 字段,避免 4 个独立订阅交替覆盖导致状态栏/步态按钮闪烁
  • 电量显示稳定性优化:StatusBar 电量改用独立 batteryStatus StateFlow,不依赖 status?.batteryStatus
  • 休眠按钮状态约束:仅非站立状态(空闲/趴下/阻尼等)可切换休眠,站立/RL 控制时禁用
  • RTSP 自动重连:RtspVideoPlayer 播放失败后自动重试,指数退避(初始 1s,最大 30s,倍率 2),URL/解码器变化时重置退避状态;覆盖层显示重试次数和倒计时
  • 订阅请求清理:删除 ProtocolClient.sendSubscriptionRequests() 方法及 connect() 中的注释调用;同步删除 ControlCommands.subscribeStatus()SUB_* 常量,彻底清除死代码
  • 摇杆手型支持:HandStyle 枚举(标准/单摇杆左/单摇杆右/坦克式),映射到 JoystickController.dualStickToAxisCommand(),设置界面持久化存储,实时生效