|
|
bffd31645e
|
feat(provisioning): BLE 配网完整修复 (跳过 EAF 资源 + EAF 最小化 + 音效播放)
修复 4 个配网模式核心问题, 让 Rtc_AIavatar 分支 (含火山 RTC SDK + 软件 AEC + 完整业务)
能像 adaptation_dzbjImg_shar 一样正常配网, 同时显示居中提示文字.
============ 问题与修复 ============
### 问题 1: 配网模式 BLE 广播 ADV_DATA malloc 失败 (手机搜不到设备)
日志:
E (3731) BLE_INIT: Malloc failed
E (3731) BT_HCI: CC evt: op=0x2008 (HCI_BLE_WRITE_ADV_DATA), status=0x7
I (3731) BluetoothProvisioning: ✅ 广播启动成功 (假成功, 广播数据空)
根因:
Rtc_AIavatar 比 adaptation_dzbjImg_shar 多 ~50-80 KB DRAM 业务 .bss
(软件 AEC + HTTPS 完整状态机 + dialog watchdog + 完整 RTC 状态),
+ 火山 RTC SDK 静态库 .bss ~30-50 KB (g_cnxMgr 14.6KB, ack$14 12.6KB 等),
配网模式时 BLE Bluedroid stack 抢不到广播数据 malloc 所需的 ~10KB DRAM.
修复 (前次 commit 已做): sdkconfig 关闭 BLE 5.0 6 个特性 (项目实际只用 4.2 legacy),
省 ~15 KB controller DRAM, 广播数据 malloc 成功.
### 问题 2: 配网模式下 LCD 绘制跟 WiFi/BLE 初始化抢 DRAM 导致 reboot
日志:
E (1200) wifi:Expected to init 10 rx buffer, actual is 1
E (1220) BluetoothProvisioning: WiFi初始化失败: ESP_ERR_NO_MEM
assert failed: vQueueDelete queue.c:2355 (pxQueue) ← BLE GATT fixed_queue_new 失败 → 反向清理 NULL 队列
排查路径 (失败方案记录):
- esp_lcd_panel_draw_bitmap 一次画 360x360 (253KB): SPI queue 满, 下半屏未画 + DRAM 抢 WiFi
- 分块画 (60 行/块) + vTaskDelay 块间: SPI driver 内部 queue 持续保留 DRAM, 仍然抢
- 强制 codec output_only=false 完整 duplex: 多 15KB DRAM, BLE BTU_StartUp malloc 失败 reboot
- CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y: 引入 BTU bt_workqueue 分配失败 → vQueueDelete NULL → assert
修复 (本次 commit): EAF 最小化初始化
movecall_moji_esp32s3.cc 配网模式调用新增的 ai_chat_screen_init_provisioning(),
跳过 8 张 EAF 资源加载 (省 4.32 MB PSRAM + ~10KB DRAM), 跳过数字人 anim,
只启用 gfx_emote renderer + 单个 gfx_label, flush buffer 启动时预分配 (~30KB DRAM 一次到位),
跟 BLE 初始化不再有动态分配冲突. 跟 adaptation_dzbjImg_shar 用 LVGL 显示 GIF 同思路,
用 EAF 替代 LVGL 避免引入 50-80KB LVGL .bss.
### 问题 3: 配网模式音效不播放
根因:
ResetWifiConfiguration 由 BOOT 按键 OnClick 调用, 跑在 esp_timer task 上下文,
vTaskDelay(4000ms) 实测只等了 1.1 秒就被唤醒, 音效没播完就 esp_restart.
修复 (前次 commit 已做): 派发到独立 task 跑 PlaySound + vTaskDelay + esp_restart,
独立 task 中 vTaskDelay 正常工作, 等 4 秒确保 解码 + DMA + 功放尾音完整.
### 问题 4: 配网时屏幕黑屏 (UX 不友好)
实施: ai_chat_screen_init_provisioning("请使用APP\n蓝牙配网~")
LCD 黑底白字居中显示提示文字, 用户感知"配网中".
label height=64 (恰好包 2 行 + 余白), GFX_ALIGN_CENTER 上下左右居中.
============ 文件改动 ============
main/application.cc:
Application 构造时显式注释: 不能在配网模式置 background_task_=nullptr
(OnAudioOutput 无判空, 会 std::mutex::lock 异常 abort).
main/boards/common/wifi_board.cc:
ResetWifiConfiguration 派发独立 task 跑 PlaySound + 4s delay + esp_restart,
EnterWifiConfigMode BLE 启动后早 return (StartBleProvisioning 内部已 Alert 音效).
main/boards/movecall-moji-esp32s3/movecall_moji_esp32s3.cc:
AI 对话模式分支: 配网时调 ai_chat_screen_init_provisioning() 显示文字,
正常模式调 ai_chat_screen_init() 显示数字人.
main/dzbj/ai_chat_ui.h:
新增 ai_chat_screen_init_provisioning(const char* hint_text) 声明.
main/dzbj/ai_chat_ui_eaf.c:
新增 ai_chat_screen_init_provisioning() 实现, EAF 最小化路径:
gfx_emote_init + gfx_disp_add + 单 label 显示文字, 跳过 EAF 资源/anim/背景图.
============ 测试结果 (设备实测) ============
- 按 BOOT 触发配网: 听到完整配网音效 (P3_LALA_WIFICONFIG 约 1 秒)
- 设备重启 → 配网模式启动 → LCD 显示"请使用APP\n蓝牙配网~" 居中
- 手机能搜到 Airhub_d0:cf:13:03:bb:f2 → 能连接 → 配网完成
- 配网完成重启 → 正常模式数字人 + RTC 对话功能正常
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-21 14:42:13 +08:00 |
|
|
|
2458c4e8bc
|
fix(ble): 关闭 BLE 5.0 特性释放 controller DRAM, 修复配网广播数据 malloc 失败
问题:
日志:
E (3731) BLE_INIT: Malloc failed
E (3731) BT_HCI: CC evt: op=0x2008 (HCI_BLE_WRITE_ADV_DATA), status=0x7
E (3731) BLE_INIT: Malloc failed
E (3731) BT_HCI: CC evt: op=0x2009 (HCI_BLE_WRITE_SCAN_RSP), status=0x7
I (3731) BluetoothProvisioning: ✅ 广播启动成功
代码层"广播启动成功", 但 HCI 层 ADV_DATA + SCAN_RSP_DATA 都没写入 → 广播空数据 → 手机搜不到设备.
根因:
sdkconfig 同时启用了 BLE 5.0 + 4.2 全套特性, 但项目代码实际只用 4.2 legacy advertising
(esp_ble_adv_params_t / esp_ble_gap_start_advertising). BLE 5.0 6 个特性总和占用 controller DRAM,
让 HCI ADV_DATA / SCAN_RSP_DATA 内存池耗尽.
修复:
sdkconfig 关闭所有 BLE 5.0 特性 (项目实际不用):
# CONFIG_BT_BLE_50_FEATURES_SUPPORTED is not set
# CONFIG_BT_BLE_50_EXTEND_ADV_EN is not set
# CONFIG_BT_BLE_50_PERIODIC_ADV_EN is not set
# CONFIG_BT_BLE_50_EXTEND_SCAN_EN is not set
# CONFIG_BT_BLE_50_EXTEND_SYNC_EN is not set
# CONFIG_BT_BLE_50_DTM_TEST_EN is not set
保留 CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y (legacy advertising 必需).
dzbj_ble.c:458 用了 esp_ble_gap_set_preferred_phy (BLE 5.0 API), 但有
#if (BLE_50_FEATURE_SUPPORT == TRUE) 保护, 关闭后编译自动跳过, 不影响其他功能.
附加: 修复 BOOT 触发配网时音效不响
wifi_board.cc::ResetWifiConfiguration():
- 移除直接 vTaskDelay (iot_button 回调跑在 esp_timer task, 实测 vTaskDelay 4000ms 只等了 1.1s)
- 改用 xTaskCreate("wifi_reset") 独立 task 跑: PlaySound + vTaskDelay(4000) + esp_restart
- 在重启前播完配网音效
wifi_board.cc::EnterWifiConfigMode():
- 移除之前在 BLE 配网成功后重复 PlaySound 的代码 (StartBleProvisioning 内部 Alert 已经调用过)
注: codec output_only 仍保持 NeedsProvisioning() (TX-only + ES8311-only).
强制 duplex 会让 BLE Bluedroid gatt_init malloc failed → assert reboot loop, 已验证.
待解决 (留待 adaptation_dzbjImg_shar 分支对比):
- 关闭 BLE 5.0 后手机可搜到设备, 但点击连接失败
- 配网模式下 P3_LALA_WIFICONFIG 音效仍不响 (StartBleProvisioning 内 Alert 调用但 audio_loop 似乎没消费)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-21 12:02:44 +08:00 |
|
|
|
70f0cdd07a
|
feat(rtc): 偶发连接失败完整修复 (A+B+C 三件套)
实测根因 (DIAG 埋点确认): 火山 RTC SDK 启动时一次性申请大量 lwIP socket fd,
默认 CONFIG_LWIP_MAX_SOCKETS=10 不够 SDK 分配, 触发 SocketConnection-Lite.c:191
bind local ip failed → ICE 协商失败 → wait connect bits=0x0 超时.
实测对比:
修复前: 冷启动 RTC join 30+ 秒超时 × 3 次失败
修复后: 冷启动 RTC join 1.6 秒成功, 软退出 + 唤醒重连 2.3 秒成功 ✅
修复内容:
[A] sdkconfig: CONFIG_LWIP_MAX_SOCKETS=10 → 20
根治 lwIP socket fd 不足. 16 是临界值, 20 留 25% 余量应对 burst 场景
(HTTP 重试 / DNS 查询 / NTP 同步并发). 代价: +6 fd × ~200B = 1.2 KB RAM (忽略).
[B] application.h/cc + volc_rtc_protocol.h/cc: 失败 3 次后销毁 + 重建 engine
新增 VolcRtcProtocol::ForceRebuildEngine() public 方法.
OpenAudioChannel 连续失败 3 次时调用 (application.cc:566-573):
- 销毁 rtc_handle_ + reset SDK 内部状态污染
- 等待 2 秒让 lwIP 释放残留 socket fd (TIME_WAIT)
- 触发 Phase 6 重建路径 (rtc_handle_=nullptr → Start())
应对 A 修复后仍可能出现的 SDK 内部状态错乱 (e.g. ICE Agent 异常).
本次实测未触发 (A 已解决主要问题), 但保留作为兜底防御.
[C] volc_rtc_protocol.cc: DIAG_RTC_BIND_ENABLE 一键开关诊断埋点
在 join_room 前/后 + ForceRebuildEngine 前/后打印:
- lwIP socket fd 使用量 (sockets=N/MAX)
- heap free + psram free
- WiFi rssi
- 失败时的 errno + strerror
验证完成后改 0 关闭, 编译器消除 #if 块, 零运行时开销.
文件改动:
sdkconfig | LWIP_MAX_SOCKETS 10→20
main/application.h | +audio_channel_retry_count_
main/application.cc | +重试计数 + static_cast → ForceRebuildEngine 调用
main/protocols/volc_rtc_protocol.h | +ForceRebuildEngine() 声明
main/protocols/volc_rtc_protocol.cc | +DIAG 埋点 + diag_count_used_sockets() + ForceRebuildEngine()
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-21 10:23:21 +08:00 |
|
|
|
c6ecdb124c
|
feat(audio): 同步 Kapi 软件 AEC + NULL crash fix 到数字人项目
来源: Kapi commit 63b21fd (NULL fix) + a369796 (软件 AEC) 完整移植
改动:
- components/common/src/volc_rtc.c
on_global_error 加 message ? message : "(null)" 防御.
解决: idle ≥10 分钟后服务端 session 超时 / NAT 表过期触发的
printf("%s", NULL) → strlen panic → 设备重启.
- main/CMakeLists.txt
REQUIRES 末尾加 esp-sr (提供 esp_aec.h 同步 API).
- main/application.h
+7 个 AEC 成员 + 5 个函数声明 (recorder/player pipeline 后).
- main/application.cc
+InitAec / DeinitAec / AppendRefSamples / GetDelayedRef / ApplyAEC (~170 行).
OnAudioOutput 三个 codec output 位置都加 AppendRefSamples hook.
ReadAudio 两条路径 (recorder_pipeline + codec 直读) 加 lazy InitAec
+ ApplyAEC + target_samples = max(samples, chunk_size).
PHASE8_DIAG_ENABLE 默认 0 (诊断埋点已完成根因定位, 关闭减少日志噪声).
实测效果 (30 分钟设备验证):
AI 说话: mic=285 ref=8310 clean=31 (消除 89%)
AI 说话: mic=660 ref=7489 clean=57 (消除 91%)
AI 说话: mic=156 ref=2748 clean=0 (消除 100%)
用户说话: mic=224 ref=8 clean=224 (passthrough 正常)
资源占用:
Flash +59 KB (+1.2%)
Internal SRAM +35-50 KB (+10-15%)
PSRAM +10-15 KB (<0.2%)
Core 1 CPU +6-12% @240MHz
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-19 16:54:55 +08:00 |
|
|
|
22b7a70d7d
|
fix: 同步 Kapi 软 RTC 退出五连修到数字人项目(待命音 + 欢迎语杂音)
从 Kapi commit b1577d8 / a3a476f 完整移植 5 个修复,覆盖三类问题:
1. 开机/唤醒后按 BOOT 进 RTC 房间,欢迎语前 1-3 秒杂音
2. 软 RTC 退出(41s 无对话触发 Dialog watchdog)后待命音"卡卡正在待命"无声/杂音/被截
3. 软退出后按 BOOT 唤醒,欢迎语前杂音
【修复 1】OnAudioChannelOpened EnableOutput(true) 后立刻灌 200ms silence
- 防止 I2S DMA 启动后到 RTC 真实 PCM 到达 1-3s 空窗的杂音
【修复 2】LeaveRoom 加 notify_closed 参数(默认 true 不变老路径)
- hibernate 路径传 false 跳过 on_audio_channel_closed_ 回调
- 避免回调链 player_pipeline_close → EnableOutput(false) 误关 codec
导致待命音无声
【修复 3】LeaveRoom 不再 volc_rtc_destroy, 保留 rtc_handle_
- 唤醒时 OpenAudioChannel 直接 volc_rtc_start 复用 handle, 不死循环
- 服务端 AI 任务无需 destroy 也会按 180s 兜底机制清理
【修复 4 - 最隐蔽】LeaveRoom 末尾重置 downlink_is_pcm_ = false
- 火山 RTC 下行是 PCM, DataCallback 设 downlink_is_pcm_=true
- 不重置 → PlaySound 的 Opus 包被 OnAudioOutput 当成 raw PCM 字节流
直接写 codec → 杂音而非待命音
- 唤醒重连后 DataCallback 收下一包会自动重置, 不影响欢迎语
【修复 5】OnAudioInput 入口加 hibernating_ guard
- hibernate 期间禁用输入侧, 防止访问关闭的 codec → std::bad_alloc abort
- 不冻结 OnAudioOutput, 让待命音队列正常被消费
【EnterIdleHibernate 重写】套用 Kapi 新顺序:
Step 0: hibernating_=true + 50ms (让 OnAudioInput guard 生效)
Step 1: LeaveRoom(false) (codec output 保留)
Step 2: background_task->WaitForCompletion
Step 3: 清空 audio_decode_queue_
Step 4: EnableInput(false) + close recorder_pipeline
Step 5: 强制 esp_pm 禁用 Light Sleep
Step 5.5: EnableOutput(false→true) + 200ms silence (清 LeaveRoom 副作用)
Step 6: SetDeviceState(idle) → PlaySound 待命音
Step 7: WaitForAudioPlayback (队列消费完毕)
Step 7.5: background_task->WaitForCompletion + vTaskDelay(1000)
(DMA + ES8311 FIFO + 功放尾音衰减, 防尾音截断)
Step 8: player_pipeline_close
Step 9: NVS idle_cycles_++
Step 10: 显示字幕"已自动退出RTC对话..."(数字人特有, 保留)
【WakeFromHibernate】调整 hibernating_=false 顺序
- 先放下 hibernating_, 让 ToggleChatState 期间 OnAudioInput guard 通过
- 否则 ToggleChatState 期间音频上行迟迟不开
编译: kapi.bin 0x41c000 (4.21MB), 分区 25% 空闲。
实测三项全通: 欢迎语干净 + 待命音清晰完整 + 唤醒欢迎语干净。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-18 10:11:36 +08:00 |
|
|
|
3dc6cadf49
|
diag(rtc-only): Phase 8 - 音频卡顿根因诊断埋点 + 数据采集报告
数字人 RTC 模式音频卡顿根因定位。通过 4 类 ESP_LOGW 埋点采集运行时
数据,对照表格判定根因,输出 Phase 9 实施分支决策。
埋点实现(main/application.cc,PHASE8_DIAG_ENABLE 宏开关,关闭后零开销):
- DIAG-1 queue 深度:3 处(出队 + WebSocket 入队 + RTC 入队),50ms 节流
- DIAG-2 codec->OutputData 写入耗时:>15ms 阈值告警
- DIAG-3 WiFi RSSI:OnClockTimer 1Hz
- DIAG-4 heap 快照 + 碎片率:OnClockTimer 1Hz
实测结论(见 DIAG_REPORT.md):用户感知卡顿 = 两个独立根因
- A. 开机播报阶段 ③' codec init 时序缺陷(ES7210 I2C 失败 +
126 次 write_slow 集中在 2-13s)
- B. RTC 对话阶段 ⑤ Opus/WebSocket 应用层帧到达抖动
(queue 突发堆积 19 + queue=0 出现 58 次,但 codec 写入 0 次 slow)
完全排除:① CPU 争抢、② PSRAM 带宽、④ WiFi 丢包(RSSI -24~-33dBm
极强)、⑥ 内存碎片(heap 全程稳定)
Phase 9 推荐分支 B'(双线修复,原 A/C 的 EAF 方案不适用):
- 9.1 应用层 jitter buffer(fill-threshold + drain)—— 解 B
- 9.2 开机 codec init 时序修复(ES7210 reset + ready 等待)—— 解 A
- 估时 1 天
ROADMAP 同步:Phase 7 矫正为 battery_psm(实际状态)、Phase 8 新增
诊断、Phase 9 占位待 Phase 8 决策、原"集成测试"挪到 Phase 10。
新增 .planning/STATE.md 记录 roadmap evolution。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-15 11:40:42 +08:00 |
|
|
|
4b7b1949d4
|
perf(rtc-only): Phase 6 收尾 - 卡顿优化 + PowerSaveTimer 守卫 + 开机加速
代码改动:
- AudioLoop 加 vTaskDelay(1),让出 Core 1 idle task 防 WiFi/RTC 饥饿
- BackgroundTask 优先级 2 → 5,提升 Opus 解码实时性
- LVGL 刷新 5ms → 16ms (60Hz),CPU 占用降 60%
- GIF 定时器 20ms → 33ms (3 处),PSRAM 流量减半
- AI 字幕推送 100ms 节流,避免 LVGL 锁争抢
- EnterIdleHibernate 清空 audio_decode_queue_,防 standby_sound 残留误触发首帧
- PowerSaveTimer OnEnterSleepMode 加 device_state 守卫,拦截 dialog/connecting
期间关功放(修复欢迎语期间被静音 bug)
- 取消开机 ADC 阻塞采样,开机播报响应从 6 秒缩到 < 3 秒
新增规划:
- Phase 7 占位文档:电量保护 + PowerSaveTimer 重构 + 唤醒杂音根治 + RTC 抖动缓解
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-14 11:38:48 +08:00 |
|
|
|
b8a5fe958f
|
feat(rtc-only): Phase 6 - RTC 空闲软休眠(B+C 双源 + 真退房 + 字幕提示 + 内存兜底)
按 GSD 框架 .planning/milestones/digital_human_rtc/phases/phase_06_idle_hibernate/
规划完成 Phase 6 软退出 RTC 机制。替代旧的"40s 硬重启退出"方案。
## 核心变更
### 1. 倒计时刷新(B+C 双源方案)
| 方案 | 监听源 | 实施位置 | 状态 |
|------|--------|---------|------|
| A 扬声器流 | I2S/PCM 输出 | application.cc audio output 3 处 | **宏关闭**(PHASE6_ENABLE_AUDIO_FALLBACK) |
| **B 字幕监听** | RTC subtitle 消息 | application.cc:1300 subtitle 分支 | **启用** |
| **C 智能体状态** | RTC conv_status 消息 | application.cc:1260 conv_status 分支 | **启用** |
复用现有 DIALOG_IDLE_COUNTDOWN_SECONDS=40 不新增常量。
### 2. 真退出 RTC 房间(释放 License)
- 新增 Protocol 基类虚函数 LeaveRoom(默认回退到 CloseAudioChannel)
- VolcRtcProtocol::LeaveRoom 覆写:volc_rtc_stop + volc_rtc_destroy
- 火山官方文档明确:真退房必须 leaveRoom + destroyRTCEngine
- CloseAudioChannel 只 stop 不够(真人仍在房间继续计费)
- 服务端 AI 任务在 180s 内自动清理(火山平台机制)
### 3. EnterIdleHibernate / WakeFromHibernate
EnterIdleHibernate 流程(严格顺序):
1. protocol_->LeaveRoom() # 真退房
2. codec->EnableInput/Output(false) # 重置 codec 状态机
3. recorder_pipeline_close()
4. hibernating_.store(true) # 关键:先设标志阻止 PowerSaveTimer
5. esp_pm_configure(light_sleep=false) # 双保险禁用 Light Sleep
6. SetDeviceState(kDeviceStateIdle)
7. idle_cycles_++ + NVS 持久化
8. 字幕"已自动退出RTC对话,按BOOT键重新连接RTC"(5 次重试间隔 200ms)
WakeFromHibernate 流程:
1. 检查 idle_cycles_ >= 50 → 硬重启清理碎片(兜底)
2. 清空字幕
3. ToggleChatState → OpenAudioChannel → 自动重建 rtc_handle_
4. RTC 重新加入房间(实测 2-3s 完成)
### 4. CanEnterSleepMode 加 hibernating 检查
防止 hibernate 期间 PowerSaveTimer 触发 esp_pm_configure(light_sleep=true)
导致 I2C 总线进入低功耗 → 唤醒后 ES7210/ES8311 通信失败 abort。
### 5. Dialog Watchdog 触发动作改造
旧:esp_restart() 整机重启(黑屏 15-25s + WiFi 重连)
新:Schedule(EnterIdleHibernate) 软退房(不熄屏 + 字幕提示)
### 6. BOOT 唤醒走 WakeFromHibernate 路径
iot_button 回调中检测 IsHibernating(),派发到独立 task 执行
WakeFromHibernate(避免阻塞 esp_timer 任务,CLAUDE.md 经验)。
### 7. OpenAudioChannel 适配重建
LeaveRoom 销毁 rtc_handle_ 后,OpenAudioChannel 头部检测 NULL
触发 Start() 异步重建,轮询 5s 等待就绪。NVS 缓存 device_secret
所以重建通常 100ms 完成。
## 实测验证(用户协作)
| 阶段 | 时间 |
|------|------|
| 40s 触发软休眠 | ✅ |
| LeaveRoom 真退房 | ✅ "✓ 已真退出 RTC 房间(leaveRoom + destroyRTCEngine)" |
| 屏幕保持 + 字幕显示 | ✅ "已自动退出RTC对话,按BOOT键重新连接RTC" |
| BOOT 按键唤醒 | ✅ |
| RTC 实例重建 | ✅ 100ms |
| RTC 重新加入房间 | ✅ 2-3s |
| 连续 2 次软休眠+唤醒 | ✅ 无 abort/I2C 失败 |
| 时间对比 | 旧硬重启 15-25s → 软休眠 3-5s(省 80%) |
## 6 个关键踩坑修复(详见 HIBERNATE_REPORT.md)
1. codec 状态机未重置 → 唤醒后 I2C abort
2. PowerSaveTimer Light Sleep 干扰 I2C 总线
3. hibernating_ 设置时序错误
4. dynamic_cast 在 -fno-rtti 下编译失败 → 改基类虚函数
5. LeaveRoom 后 OpenAudioChannel 直接失败 → 加重建逻辑
6. 字幕 LVGL 锁竞争 → 推迟到最后 + 5 次重试
## 文档产出(同时提交)
- .planning/.../phase_06_idle_hibernate/PLAN.md(含实施变更记录 V1-V6)
- .planning/.../phase_06_idle_hibernate/HIBERNATE_REPORT.md(验证报告)
- .planning/.../ROADMAP.md(Phase 1-5 ✅ + Phase 6 进行中状态更新)
- docs/Rtc_AIavatar/数字人表情渲染方案_云端预渲染+BLE+OTA.md
新增第 19 章 RTC 空闲倒计时方案选型与软退出(9 小节)
- docs/Rtc_AIavatar/RTC软退出方案_移植参考.md
完整移植参考(10 章 + 3 附录,可移植到其他火山 RTC 项目)
- docs/Rtc_AIavatar/音频卡顿_全局资源分析.md
全局资源分析 + 13 项优化建议(不改代码)
|
2026-05-13 17:28:36 +08:00 |
|
|
|
672506e7c7
|
feat(rtc-only): Phase 1 - 通过 CONFIG_BAJI_BADGE_MODE 屏蔽电子吧唧模式
按 GSD 框架 .planning/milestones/digital_human_rtc/ 规划完成 Phase 1。
源代码全部保留,通过 Kconfig 开关 + CMakeLists 条件编译 + #ifdef 调用点保护
实现"吧唧模式不进固件但代码可恢复"。
## 核心变更
### Kconfig 开关(默认关闭)
- 新增 CONFIG_BAJI_BADGE_MODE(main/Kconfig.projbuild)
- sdkconfig.defaults 默认 =n
- =y 时恢复双模式(电子吧唧 + AI 对话)
- =n 时仅 AI 数字人 RTC 模式
### CMakeLists 剥离(剥离式不重写)
- 9 个 dzbj/ 吧唧专属 + 9 个 ui/screens/ 吧唧 UI 进入 if(CONFIG_BAJI_BADGE_MODE) 条件块
- 公共保留: dzbj/lcd.c, ai_chat_ui.c, sprite_demo.c, dual_gif_demo.c,
bg_gif_demo.c, pages_pwm.c, dzbj_init.c, fatfs.c
- 修正 PLAN 漏判:dzbj_init/fatfs 公共化(AI 模式调用 dzbj_hw_display_init/DecodeImg)
### 调用点 #ifdef 保护
- application.cc: L20 include, L63-66 background_task, L536 device_mode 分支
- movecall_moji_esp32s3.cc: dzbj headers, init_spiffs_image_list extern,
dzbj_boot_click_handler extern, device_mode_is_badge 分支, InitializeBadgeMode,
InitializeBadgeModeButtons, mode_switch_combo 注册, device_mode_in_switch_suppress
- 保留公共 extern: ai_chat_screen_init, ai_chat_resume_animation, pwm_init
### 整体文件级 #ifdef 包裹
- dzbj/dzbj_button.c/h
- dzbj/sleep_mgr.c
- sleep_mgr/include/sleep_mgr.h
### 6 个文件显式 #include "sdkconfig.h"
- ESP-IDF 不会 force-include,必须手动 include 才能拿到 CONFIG_* 宏
## G7 验收双向编译
- =n 模式 build: ✅ EXIT=0(数字人 RTC 单一形态)
- =y 模式 build: ✅ EXIT=0(双模式恢复可用)
## 固件大小变化
| 段 | =n | =y | 节省 |
|----|-----|------|------|
| .text | 2.03 MB | 2.06 MB | 27 KB |
| .rodata | 2.48 MB | 3.87 MB | 1.39 MB |
| Total | 4.63 MB | 6.05 MB | 1.45 MB |
## GSD 文档(同时提交)
- .planning/milestones/digital_human_rtc/MILESTONE.md
- .planning/milestones/digital_human_rtc/ROADMAP.md
- .planning/milestones/digital_human_rtc/INTEL.md
- .planning/milestones/digital_human_rtc/phases/phase_01_kconfig_isolation/PLAN.md
- .planning/milestones/digital_human_rtc/phases/phase_01_kconfig_isolation/SIZE_REPORT.md
- .planning/milestones/digital_human_rtc/phases/phase_01_kconfig_isolation/BADGE_MODE_ISOLATION_MAP.md
- 编译大小原始数据: size_*.txt
## 已知事项
- =n 固件 4.63 MB 仍 > 4 MB 目标,Phase 2 调整分区 + Phase 3 物理移除图片资源解决
- main/dzbj/ 下所有源文件完整保留,无任何物理删除
|
2026-05-13 10:22:48 +08:00 |
|
|
|
919bf8f28f
|
feat: GIF动画表情系统 + 情绪映射增强 + HTTPS音频中止修复
一、新增功能:
1、新增8种GIF动画表情(200x89) + 3种叠加图标(45x45),实现22种情绪标签到GIF的映射表;
2、新增30+组英文近义词情绪fallback映射(如worried→sad),防止AI使用非标准标签时GIF无法切换;
3、新增HTTPS中止后诊断日志,自动追踪前20帧音频处理流程便于定位无声问题;
二、Bug修复:
4、修复HTTPS播放中止后RTC音频解码参数未恢复(16000/60→8000/20),通过background_task_串行化恢复;
5、修复AbortHttpsPlayback解码器竞态崩溃,将重置/恢复/DMA flush全部串行化执行;
6、修复LVGL gifdec不支持无全局颜色表GIF的问题,支持仅使用局部颜色表的压缩GIF;
7、修复GIF透明区域显示黑色方块,canvas初始alpha改为0x00;
8、修复lv_gif定时器gif对象为NULL时的空指针崩溃;
三、优化:
9、情绪标签从等待is_final改为第一条字幕即时触发GIF切换,新增去重和回复结束自动恢复neutral;
10、对话状态表情映射优化:THINKING→thinking、ANSWERING→happy、INTERRUPTED→surprised;
11、CPU核心绑定:LVGL任务Core0,音频循环Core1,避免GIF解码与音频争抢;
12、中文情绪词映射扩展,新增担心/心疼/着急等映射;
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
2026-03-19 15:28:14 +08:00 |
|
|
|
23613e1cd3
|
1、新增obtain_music Function Calling音乐播放功能,4处协议分支均支持URL直播和音乐API两种HTTPS方式;
2、Kconfig新增MUSIC_API_URL音乐播放API地址配置;
3、重构SendStoryRequest和SendMusicRequest为HttpsApiPlayback通用方法,消除故事/音乐播放~440行重复代码;
4、修正4处obtain_story注释和日志:WebSocket描述改为HTTPS API(与实际实现一致);
|
2026-03-05 15:44:47 +08:00 |
|
|
|
ccea0c681c
|
feat: HTTPS故事播放 + RTC/HTTPS双向音频切换状态机 + 协议层优化
1、新增HTTPS故事播放功能:SendStoryRequest通过蓝牙MAC请求故事API,支持intro+body两段式无缝播放,替换原WebSocket故事请求方式;
2、新增HttpsPlaybackFromUrl通用HTTPS音频下载播放方法,支持JSON格式Opus帧流式解码播放;
3、新增RTC↔HTTPS双向音频切换三标志位状态机(opus_playback_active_/https_playback_active_/https_playback_abort_),HTTPS播放期间静默丢弃RTC PCM包,OnAudioOutput捕获is_opus_frame防止残留Opus帧杂音;
4、新增AbortHttpsPlayback中止方法,使用独立高优先级任务(priority=10)执行DMA flush;AbortSpeaking也新增DMA缓冲区flush确保扬声器立即静音;
5、协议层新增OnBotMessage回调,非字幕Bot下行消息立即中止HTTPS播放;volc_rtc_protocol移除is_binary依赖改为直接前缀检测,新增info前缀识别,subv字幕排除on_bot_message_由subtitle handler单独处理;
6、subtitle字幕USER/AI区分从CONFIG_VOLC_DEVICE_NAME比较改为bot_前缀判断,用户说话时立即中止HTTPS播放;
7、Kconfig新增STORY_API_URL故事播放API地址配置;
8、设备注册RTC服务时,设备名称从Wi-Fi MAC地址改为使用蓝牙MAC地址
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
2026-03-05 13:45:52 +08:00 |
|
|
|
1e7ba0763a
|
1、更新了postman参数、约束和语音请求讲故事的Function Call参数;
2、字幕增加了情绪标签,并且emoji表情跟随情绪和设备状态而更新;
|
2026-03-02 17:27:03 +08:00 |
|
|
|
04d26d7cee
|
1、本次新增了Function Calling的讲故事功能,可以语音获取小故事
|
2026-03-02 15:34:41 +08:00 |
|
|
|
98e40ac163
|
feat: 火山RTC字幕文本实时显示 + 字幕日志精简
1. DataCallback 新增 subv(字幕)二进制消息前缀识别,字幕数据正确解析并转发到应用层
2. OnIncomingJson 处理 type:"subtitle",通过 userId 区分用户语音识别(STT)和 AI 回复文本
3. 字幕日志简化:subv 消息仅打印"接收下行二进制消息(字幕)",不展开 JSON 内容
4. 新增postman请求的参数
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
2026-03-02 15:11:34 +08:00 |
|
|
|
58c33e3cb4
|
feat: AI对话模式emoji表情系统 + 中文字体 + 分区优化
1. 新增AI对话LVGL界面(ai_chat_ui),支持emoji图片 + 状态文本 + 聊天消息
2. 新增7个emoji表情资源(64×64 PNG C数组):neutral/happy/sad/angry/crying/funny/laughing
3. 新增阿里巴巴普惠体20px 4bpp中文字体(GB2312字符集)
4. 利用火山RTC会话状态(VOLC_MSG_CONV_STATUS)驱动emoji切换:
- LISTENING→happy, THINKING→neutral, ANSWERING→laughing
- INTERRUPTED→funny, ANSWER_FINISH→happy
5. 设备状态emoji映射:Listening→happy, Speaking→laughing, Dialog→happy
6. 配网模式显示happy emoji
7. 分区优化:model 3MB→64KB,OTA 5MB→6.5MB
8. 编译优化:-Og→-Os,移除SimSun CJK字体
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
2026-02-28 18:14:19 +08:00 |
|
|
|
14776acb0a
|
feat: 完成 AI/吧唧双模式完全隔离重构 + 触摸坐标日志 + SPIFFS 预烧录
## 核心变更
### 1. 双模式完全隔离 (Phase 2+4)
- 拆分 InitializeButtons() 为 InitializeBadgeModeButtons() + InitializeAiModeButtons()
- 构造函数按 device_mode 分支:吧唧模式不创建 PowerSaveTimer/BackgroundTask
- 吧唧模式不注册音量/故事按键回调,避免调用 GetAudioCodec() 崩溃
- GPIO0 由 iot_button 统一处理,dzbj_button 仅注册 KEY2(GPIO4)
- SetDeviceState() 中 background_task_ 空指针保护
### 2. 吧唧模式 BOOT 按键崩溃修复
- 新增 dzbj_boot_click_handler()(C 函数,避免 lvgl.h 与 display.h 冲突)
- 移植 dzbj 的唤醒屏幕/退出手电筒/返回Home 完整逻辑
### 3. esp_timer 阻塞 LVGL 渲染修复
- iot_button 回调在 esp_timer 任务中执行,vTaskDelay 会阻塞 lv_tick_inc
- 改为 xTaskCreate 派发到独立 FreeRTOS 任务,避免冻结 LVGL 渲染
### 4. 触摸坐标日志 + SPIFFS 预烧录
- esp_lvgl_port_touch.c 添加触摸坐标打印
- CMakeLists.txt 添加 spiffs_create_partition_image 自动打包 spiffs_image/
### 5. dzbj 模块文件新增
- device_mode: NVS 设备模式管理 (AI=0/吧唧=1)
- dzbj_button: GPIO4 KEY2 中断 + BOOT 点击处理
- dzbj_ble: BLE GATT 图传服务 (0x0B00)
- dzbj_battery: ADC 电池电压监测
- sleep_mgr: 10s 超时熄屏低功耗管理
- pages: 图片浏览/GIF播放/PWM亮度
- fatfs: SPIFFS 文件管理
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
2026-02-28 10:23:04 +08:00 |
|
|
|
c24a9bc162
|
feat: 集成 dzbj LVGL 显示模块 + 配网模式内存优化
阶段1: 将 dzbj 项目的 LVGL 8.3.11 LCD 显示集成到 AI小智 主项目,
开机显示 ScreenHome 界面,同时优化配网模式下的内存使用,
确保 WiFi+BLE+LVGL 三者共存运行。
## 新增功能
### dzbj 显示模块集成
- 新增 main/dzbj/ 目录,移植 LCD 驱动(ST77916 QSPI)、触摸驱动(CST816S)、
LVGL 初始化和 SquareLine Studio UI 界面
- I2C 总线共享:dzbj 触摸控制器复用主项目的 I2C_NUM_1 总线
- GPIO 冲突解决:LED(GPIO21)、Touch1(GPIO1)、Touch4(GPIO7) 改为 NC,
电池 ADC 从 GPIO6 改为 GPIO3
- 添加 LVGL、esp_lcd_st77916、esp_lcd_touch_cst816s 等组件依赖
- managed_components 纳入版本管理
### 配网模式轻量化启动
- BoxAudioCodec: 新增 output_only 模式,仅创建 I2S TX 通道(省 ~13KB DMA)
跳过 ES7210 ADC 初始化(省 ~2-4KB)
- AudioCodec: 新增 StartOutputOnly() 方法,仅启用扬声器输出
- Application: 配网模式跳过 Opus 编码器、输入重采样器、协议初始化、
天气位置检测等网络业务
- 板级构造函数: 配网模式跳过电池检测、IMU传感器、PowerSaveTimer
### WifiBoard 配网流程修复
- NeedsProvisioning() 静态方法: 读取 NVS force_ap 和 SSID 列表,
用于提前判断配网模式
- force_ap 竞态修复: 构造函数不再清零 force_ap,改在 StartNetwork() 清零,
确保 NeedsProvisioning() 能正确读到 force_ap=1
- Application 缓存 provisioning_mode_ 成员变量,避免重复读 NVS
### BLE 配网重启修复
- 配网成功后用 esp_timer 延迟重启替代 xTaskCreate,
避免内存紧张时任务创建失败导致设备不重启
- 注释掉 WiFi 连接成功后的 MAC 地址发送步骤
### sdkconfig 内存优化
- BT_ALLOCATION_FROM_SPIRAM_FIRST=y (BLE 动态分配优先 PSRAM)
- SPIRAM_MALLOC_RESERVE_INTERNAL=32768
- NVS_ALLOCATE_CACHE_IN_SPIRAM=y
- WiFi 静态缓冲区数量优化 (RX=10, TX=8)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
2026-02-27 17:07:51 +08:00 |
|
|
|
03496efecb
|
1、初始化代码,待适配中....
|
2026-02-24 15:28:34 +08:00 |
|