65 lines
8.6 KiB
Markdown
65 lines
8.6 KiB
Markdown
# 对话无回复诊断日志
|
||
|
||
设备端新增四类日志,按 `round`、`session`、单调运行时间关联。诊断不调整对话协议、VAD 阈值或回复等待时限。
|
||
|
||
| 标记 | 内容 | 可以缩小的范围 |
|
||
| --- | --- | --- |
|
||
| `MIC-DIAG` | 录音打开结果及句柄、读取返回值/字节数、全零帧、峰值/平均绝对幅值、录音事件、PCM 缓冲写入丢失 | 区分未取得 PCM、全零输入、已有音频但没有通过 VAD、音频交给编码器前丢失 |
|
||
| `VOICE-TX` | 认证消息入队结果;START/END 的序号、类型、字节数、返回值和入队耗时;音频入队失败 | 区分请求未入队、内存分配失败、正常提交发送队列 |
|
||
| `WSS-IO` | 实际 TLS 写入结果、累计写入次数和字节;TLS 错误码、部分写入进度和重试;实际接收字节;关闭时的累计收发及未消费接收字节 | 区分入队后未完成写入、对端关闭、收到字节但应用层未获得完整消息 |
|
||
| `VOICE-RX` | 接收文本长度、前 192 字节、当前会话、是否通过会话准入检查;二进制消息计数 | 显示 START_ACK/END_ACK、未知回复、被准入检查丢弃的消息。二进制消息仍沿用原有忽略行为 |
|
||
| `VOICE-DIAG` | START/END 入队后的摘要、超时断开前和断开回调时的摘要 | 汇总入队成功/失败数、音频载荷字节、文本/二进制消息数、ACK 次数、末次收包距今时长和回复等待时长 |
|
||
|
||
拾音统计按一次录音累计,每秒及停止时输出。`peak`/`mean_abs` 是 16 位有符号 PCM 的绝对幅值,不是分贝;`zero` 统计有效读取长度内全部为零的帧。`short` 包括零长度以及所有非 640 字节的读取。PCM 写入不足或失败计入 `ring_drops`,同时记录丢失字节数。录音 tick 回调不打印,其他重复事件限频。
|
||
|
||
`VOICE-TX ret=0` 只代表入队成功。`queue_bytes` 只计成功入队的音频载荷,不含自定义包头、WebSocket 帧头、认证和控制消息。`WSS-IO tx_bytes` 是传给传输层并成功返回的明文字节数,含握手/帧头,不能与 `queue_bytes` 直接比较;TLS 失败时已写出的部分字节由 `tls_write_failed`/`tls_write_timeout` 的 `sent` 单独报告。正常写入首条和每 50 次打印一次,实际接收前 20 次及每 50 次打印,断开时输出累计值。`tick`/`elapsed_ticks` 使用 RTOS tick,其他带 `ms` 的字段使用单调毫秒。
|
||
|
||
`start_ack`/`end_ack` 按收到的文本子串统计,包含被准入检查拒绝的消息;它们不是对当前 session 的服务端确认保证。应结合 `VOICE-RX` 原文中的会话标识判断归属。若服务端协议不发送 ACK,ACK 为零本身不代表失败。`accepted=1` 表示通过外层会话准入检查,后续仍可能因 OTA、打断状态、URL 或 session 校验而未播放。文本仅保留前 192 字节,原有错误消息完整分块日志继续保留。
|
||
|
||
复现时保留开机到失败后第二次对话结束的完整串口日志。推荐按以下顺序判断:
|
||
|
||
1. `MIC-DIAG` 检查读取长度、返回值和电平,结合既有 FVAD 语音确认日志判断拾音与 VAD。
|
||
2. `VOICE-TX` 检查 START、音频、END 入队;`queue_fail` 和 `ring_drops` 应为零。
|
||
3. `WSS-IO` 检查实际写入是否失败,关闭时是否有接收字节和残留未消费数据。
|
||
4. `VOICE-RX` 检查 ACK、未知错误文本、被拒绝的回复或二进制数据。
|
||
5. `timeout-before-disconnect` 检查 `wait_ms`。`wait=2` 是等待回复,`wait=1` 是无语音,`wait=3` 是 END 入队失败。`response` 表示现有业务逻辑已接收可用音频 URL,不等同于收到任意文本或 TTS_START。
|
||
|
||
即使 TLS 写入成功,也不能证明服务器应用收到完整录音。若已经看到归属正确的 END_ACK,却没有后续 TTS,优先按 session 查服务端识别和生成链路;若没有 ACK,也需要结合服务端接收记录判断。设备单侧日志不能完全区分服务端未处理、网络中断和回复延迟。
|
||
|
||
本机验证:`python3 tools/test_voice_diag.py`、`python3 tools/test_conversation_timeout.py`、`python3 tools/test_wss_io.py`、`python3 tools/test_wss_receive.py`。诊断测试直接编译实际函数并注入录音、缓冲区、队列及收包结果;不替代目标固件构建及设备实测。
|
||
|
||
## GNSS 日志开关
|
||
|
||
`inc/app_gnss_log.h` 中的 `APP_GNSS_LOG_ENABLED` 默认是 `0`,关闭应用侧全部 GNSS/NMEA 原始输出、解析失败、模式切换、卫星搜索、坐标打印和 GPS 查询提示。需要恢复时可在编译参数中设置 `-DAPP_GNSS_LOG_ENABLED=1`。语音与 NITZ 时间校准诊断继续输出。
|
||
|
||
GNSS 数据解析、定位上报和硬件开关流程继续运行。原先放在打印参数内的四处 `ql_gnss_close()` 已分离为独立操作,避免禁用日志时跳过关闭定位。`python3 tools/test_gnss_logging.py` 在日志开启和关闭两种配置下验证真实解析代码、无卫星退出、卫星不足退出、搜索超时退出及 FAST 切换 SLOW 的关闭路径。
|
||
|
||
## 连接失败与提示音诊断
|
||
|
||
`WSS-DIAG` 使用 `stage` 区分 TLS 握手、TLS 读取、WebSocket 升级。日志记录阶段、实际耗时、超时配置、错误码和收包情况,不输出原始响应头、Cookie 或音频内容。TLS 握手仍是 20 秒总窗口,WebSocket 升级仍是 10 秒窗口,HTTP select 等待仍是 2 秒。
|
||
|
||
| 日志字段 | 含义和排查方向 |
|
||
| --- | --- |
|
||
| `stage=tls_handshake result=timeout phase=server hello` | TLS 等待服务器 Hello 超时,不能据此判断证书错误。结合 `last_step`、`want_read`/`want_write`、`phase_ms`、`calls_ms` 判断等待和本地计算耗时 |
|
||
| `stage=tls_connect failed_at=… verify_flags=…` | 记录 TLS 初始化/建连的失败步骤和证书校验标志;校验标志仅在已进行证书校验时有解释意义 |
|
||
| `stage=tls_read reason=peer_close_notify` | 对端发送 TLS 关闭通知;仅证明关闭由对端通知,不证明为何关闭 |
|
||
| `stage=tls_read reason=tls_eof/tls_read_timeout/tls_read_error` | 分别表示读取返回 0、TLS 读取超时、其他读取错误;保留原始十进制和十六进制返回值 |
|
||
| `stage=ws_upgrade reason=no_response_timeout` | 升级等待超时,缓冲中没有响应数据;对照 `rx_bytes=0`,服务端需核查请求是否到达及是否返回 101 |
|
||
| `stage=ws_upgrade reason=incomplete_headers_timeout` | 收到部分数据,但在窗口内未收到完整 HTTP 响应头 |
|
||
| `stage=ws_upgrade reason=http_rejected http=…` | 收到了完整响应头及非 101 状态;按实际 HTTP 状态检查代理或后端 |
|
||
| `stage=ws_upgrade reason=invalid_upgrade_response` | 收到非法或不符合 WebSocket 校验的响应;例如 101 响应的 Accept/Upgrade/Connection 不符合要求,或响应格式错误;当前不进一步细分具体头字段 |
|
||
| `stage=ws_upgrade reason=transport_error` | 等待升级期间底层连接出错,结合紧邻的 `tls_read` 日志及断开回调的具体错误描述 |
|
||
| `HTTP-DIAG stage=tcp_connect/response_header/response_body` | HTTP 在建连、响应头或响应体等待期间失败;`timeout` 表示 select 返回 0,`select_error` 表示负值,并记录立即保存的 errno;超时的 errno 字段为 0,不能用历史 errno 推断原因 |
|
||
| `NET-GATE leave recording=… pending=… mqtt=… action=…` | 记录留言键为什么被拦截,区分正在录音、等待留言请求回复和 MQTT 离线。忙碌分支当前仍播放原有网络提示并清除 pending,此次仅增加诊断 |
|
||
| `NET-GATE tip=network_ok reason=mqtt_connected voice_service=not_checked` | “已连上网络”仅由 MQTT 连通触发,不表示 TLS/WebSocket/语音业务已验证 |
|
||
|
||
例如此次无响应升级会输出类似以下摘要(示例,并非当前固件已有的历史日志):
|
||
|
||
```text
|
||
[WSS-DIAG] stage=ws_upgrade result=failed reason=no_response_timeout http=0 elapsed_ms=10000 timeout_ms=10000 rx_bytes=0 buffered=0 header_bytes=0 parser=0 polls=...
|
||
```
|
||
|
||
`http=0` 表示尚未解析到有效状态码,不是服务器返回的 HTTP 状态码。成功 TLS 写入只证明本地传输层接受了数据,设备端仍不能独自证明请求到达服务器或定位中间链路丢包。诊断不会改变现有提示音、重试或业务状态机。
|
||
|
||
验证:`python3 tools/test_wss_receive.py` 覆盖完整/分段 101、零响应超时、部分响应头超时、503 拒绝、非法 Accept、对端关闭、TLS 读取超时等分支;`python3 tools/test_wss_handshake.py` 验证真实握手函数的超时/失败摘要及原有时限、重试和 tick 回绕。以上为主机侧函数测试,需重新构建并烧录目标固件后采集新日志。
|