docs: 新增 Kapi 项目业务全貌与重构决策分析报告

基于深度代码分析(58 个 tool calls)输出 600 行决策分析文档:

- §1~7 项目业务全貌: 架构/RTC/音频管线/已有功能/资源/与 Baji 差异/已有规划
- §8 三选项决策矩阵:
  * 选项 A (移植 Baji Phase 6 软退出):  强烈推荐, 工作量 1-2 天
  * 选项 B-1 (启用 ESP-SR AFE):  推荐, 但需先确认 Moji 板 ES7210 REF 走线
  * 选项 B-2 (G711A→Opus): ⚠️ 暂缓
  * 选项 B-3 (Jitter buffer): ⚠️ 暂缓
  * 选项 C (ESP-ADF 重构):  强烈不推荐, 工作量 3-4 周风险极高
- §9 推荐 4 步执行路线
- §10 关键代码引用 + Baji 交叉引用清单
- §11 一句话总结
- 附录: Kapi 是更合适的 AFE 实验场地(SRAM 余量 80-130KB vs Baji 44KB)

关键结论:
- Kapi = Baji 无屏轻量底座, 资源宽松 30-50KB SRAM + 300-500KB PSRAM
- audio_processing 整套 AFE 代码已写好但 sdkconfig 未启用
- Phase 6 软退出 100% 可移植(基类同源代码, 字幕提示需替换为 LED/语音)
- 未来 AFE 实验应优先在 Kapi 跑通, 再回 Baji 评估

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rdzleo 2026-05-14 14:37:29 +08:00
parent d8982c3569
commit fe8173752d

View File

@ -0,0 +1,378 @@
# Kapi_Rtc_toy 项目业务全貌与重构决策分析
> **生成时间**2026-05-14
> **生成背景**Baji_Rtc_Toy衍生项目在硬件资源紧张+用户体验不佳的背景下,评估是否应该把 Phase 6 软退出、ESP-SR AFE、G711A→Opus 等优化方案移植到 Kapi底座项目或干脆切到 ESP-ADF 框架重构。
> **关联文档**
> - 衍生项目对比报告:[/Users/rdzleo/Desktop/Baji_Rtc_Toy/docs/Rtc_AIavatar/官方Korvo2方案_对比分析报告.md](../Baji_Rtc_Toy/docs/Rtc_AIavatar/官方Korvo2方案_对比分析报告.md)
> - 同源 RTC 软退出方案:[/Users/rdzleo/Desktop/Baji_Rtc_Toy/docs/Rtc_AIavatar/RTC软退出方案_移植参考.md](../Baji_Rtc_Toy/docs/Rtc_AIavatar/RTC软退出方案_移植参考.md)
> - 项目内已有 AEC 计划:`03AEC_VOICE_INTERRUPT_PORTING_PLAN.md`
---
## 0. TL;DR一句话总结
> **Kapi_Rtc_toy 是 Baji_Rtc_Toy 的"无屏轻量底座",比 Baji 多出 30-50KB SRAM + 300-500KB PSRAM 资源余量。Phase 6 软退出方案 100% 可移植且工作量极小AFE-AEC 资源富余但需先确认硬件 REF 通道走线;坚决不推荐切换到 ESP-ADF 重构。**
---
## 1. 整体架构和业务全貌
### 1.1 框架与平台
| 项 | 值 |
|---|---|
| **框架** | **纯 ESP-IDF**≥5.3),不是 ESP-ADF |
| **目标芯片** | ESP32-S316MB Flash + 8MB Octal PSRAM 80MHz |
| **板型** | movecall-moji-esp32s3**无屏**,触摸+IMU+电池) |
| **协议** | WebSocket + Volc RTC 同时编入,通过 `ENABLE_RTC_MODE` 宏激活 RTC |
依据:
- `main/idf_component.yml:13``espressif/esp_codec_dev: ~1.3.2`
- `main/CMakeLists.txt:235-238``ENABLE_RTC_MODE`
- `sdkconfig``SPIRAM_MODE_OCT/SPEED_80M`, `CONFIG_BOARD_TYPE_MOVECALL_MOJI_ESP32S3=y`
### 1.2 入口流程
```
main.cc:28 app_main
→ esp_event_loop_create_default
→ esp_netif_init
→ nvs_flash_init
→ Application::GetInstance().Start() (main.cc:105)
→ application.cc:Start (~531 启动播报)
→ 板级初始化boards/movecall-moji-esp32s3/movecall_moji_esp32s3.cc:225+
→ InitializeProtocol → VolcRtcProtocol::Start (volc_rtc_protocol.cc:43)
→ StartDialogWatchdog (application.cc:1961)
```
### 1.3 主要模块清单
| 模块 | 行数 | 职责 |
|---|---|---|
| `main/application.cc/h` | 4281 行 | 单例主控、状态机、音频 I/O、HTTPS 故事/音乐、Dialog Watchdog、Schedule 队列 |
| `main/protocols/volc_rtc_protocol.cc/h` | 853 行 | 火山 RTC 封装volc_rtc_create/start/stop/destroy、subv/ctrl/conv/tool/info 消息解析 |
| `main/protocols/websocket_protocol.cc` | — | WS 协议RTC 模式下未激活) |
| `main/protocols/protocol.h` | — | Protocol 基类(**当前无 `LeaveRoom` 虚函数** |
| `main/audio_codecs/box_audio_codec.cc` | — | ES8311DAC+ ES7210ADC |
| `main/audio_codecs/es8311_audio_codec.cc` | — | 单 ES8311 实现Moji 未用) |
| `main/audio_processing/audio_processor.cc/h` | — | 基于 ESP-SR 的 AFE+VAD 封装(**未编入** |
| `main/audio_processing/wake_word_detect.cc` | — | 唤醒词(**未编入** |
| `main/audio/simple_pipeline.cc` | ~60 行 | **不是 ESP-ADF 管线**,仅是 codec InputData/OutputData 的薄壳 + 最近邻重采样 |
| `main/bluetooth_provisioning.cc` | 1417 行 | 自定义 BLE GATT 二进制配网0xABF0/F1/F2 |
| `main/ble_service.cc` | — | BLE JSON Service已实现未编入 |
| `main/boards/movecall-moji-esp32s3/*` | 2078 行 + IMU + Touch | 板级QMI8658A IMU、6 路 TouchPad、ADC 电池、KEY4 |
| `main/iot/thing*.cc` + `iot/things/*.cc` | — | IoT 设备抽象 |
| `main/weather_api.cc` | — | 天气查询 |
### TL;DR
Kapi_Rtc_toy = "xiaozhi" 系列 ESP-IDF 项目魔改版,集成火山 RTC + 自定义 BLE 配网 + IMU/触摸/电池。**无 LCD/LVGL**,框架是 ESP-IDF 而非 ESP-ADFaudio_processing 整套 AFE 代码已具备但**未在 sdkconfig 中启用**。
---
## 2. RTC 实现现状
### 2.1 协议层
- 使用 **VolcRtcProtocol**`main/protocols/volc_rtc_protocol.cc:43-407`
- SDK火山 `volc_engine_rtc_lite``main/CMakeLists.txt:204` REQUIRES
- 入房:`volc_rtc_start` → 等待 0x1CONNECTED+ 0x2USER_JOINED
- 退房:`CloseAudioChannel` **仅调用 `volc_rtc_stop`**`volc_rtc_protocol.cc:399`**不调 `destroy`** → 真人留在房间继续计费(与 Baji 旧版同病)
### 2.2 音频编解码使用现状
- **上行**:默认 `send_pcm_uplink_=true``send_g711a_uplink_=false``application.h:160-161`)。设备发 PCM**SDK 内部转 G711A 上传**`audio.codec.internal.enable=1``volc_rtc_protocol.cc:95`
- **下行**`Joining channel: aibotrtc_G711A_*`(日志 `05-最新日志.txt:160`)→ **下行是 G711A**,不是 Opus
- **本地播报(开机欢迎/故事/音乐)**Opus 编码的 `.p3` 资产OPUS 16k/60ms 单声道,开机播 `LALA_kaijibobao.p3``application.cc:618`
- **HTTPS 故事/音乐**:服务器返回 base64 Opus 数据,本地解码(`HttpsApiPlayback` + `audio_decode_queue_`
### 2.3 软退出/Hibernate 现状
- **无 hibernate**、**无 LeaveRoom**、**无 EnterIdleHibernate**
- Dialog Watchdog 触发逻辑(`application.cc:1961-2042`
- 40s 无 `last_audible_output_time_` 更新 → 写 NVS `reboot_dlg_idle=1` + `reboot_origin=1`**`esp_restart()`**line 2014
- 这正是 Baji Phase 6 替换的"硬重启退出"原型
- `last_audible_output_time_` 当前**只由音频流刷新一处**`application.cc:2161`,相当于方案 A**没有方案 B (subtitle) 和方案 C (conv_status) 的双源刷新**
### 2.4 与 Baji_Rtc_Toy Phase 6 差异
| 项 | Kapi_Rtc_toy | Baji_Rtc_Toy (Phase 6) |
|---|---|---|
| 退出方式 | `esp_restart()` 硬重启 | `LeaveRoom` (stop+destroy) 软退 |
| 恢复时长 | 15-25sWiFi+应用全冷启)| 3-5sNVS 缓存凭证,重建 RTC handle |
| 倒计时刷新源 | 只有方案 A音频流 | B+C 双源subtitle + conv_status |
| 状态保留 | 全部丢失 | 音量/历史/上下文保留 |
### TL;DR
Kapi RTC 协议层基本完备(与 Baji 共享 95% 同源代码),下行 G711A、上行 PCM-by-SDK-to-G711A。**完全没有软退出/hibernate 逻辑,仍是 `esp_restart()` 硬退出**,正好是 Baji Phase 6 解决的问题。
---
## 3. 音频管线(重点)
### 3.1 框架与组件
- 使用 **esp_codec_dev**`espressif/esp_codec_dev: ~1.3.2`
- **不使用 ESP-ADF 的 audio_pipeline / audio_element**
- `simple_pipeline.cc/h` 是 stub`recorder_pipeline_read` 直接调 `codec->InputData``player_pipeline_write` 直接调 `codec->OutputData`,外加最近邻重采样(音质差但够用)
### 3.2 ES7210 + ES8311 配置
| 项 | 值 | 引用 |
|---|---|---|
| Codec 创建 | `BoxAudioCodec(ES8311 + ES7210)` | `movecall_moji_esp32s3.cc:1507` |
| AUDIO_INPUT_REFERENCE | **0** ← 没有参考通道接入 AEC | `config.h:27` |
| mic_selected | `MIC1 \| MIC2`**双 mic无 REF** | `box_audio_codec.cc:67` |
| ES8311 输出 | 固定立体声(`STEREO + BOTH slot` | `es8311_audio_codec.cc:105-109` |
**注意**ES8311 必须是立体声输出,单声道会导致 RTC 入房失败(`04-2025-11-21音频优化记录.md` 已踩坑修复)。
### 3.3 AFE / audio_processor 状态
- `sdkconfig:642-645`**`CONFIG_USE_AUDIO_PROCESSOR is not set`**、**`CONFIG_USE_WAKE_WORD_DETECT is not set`**、**`CONFIG_USE_CUSTOM_WAKE_WORD is not set`**
- 代码已编写完整(`audio_processing/audio_processor.cc` + EchoAwareVadParams + AdaptiveNoiseState但**整个文件未参与编译**`CMakeLists.txt:167-169` 条件化)
- AFE 依赖项 `espressif/esp-sr: ^2.0.3` 已声明(`idf_component.yml:8`
### 3.4 AEC 反馈通道(关键风险点)
- **硬件层:当前未走 ES7210 REF 通道**`AUDIO_INPUT_REFERENCE=0`
- 要启用 AFE-AEC 必须:
1. 改板级配置改为 1
2. 调整 mic_selected 加入 REF
3. 确认 ES8311 输出经过 PCB 走线到 ES7210 REF 输入Box 系列板默认已布好线,**Moji 板需确认**
- 同时 ES8311 输出立体声给 ES7210 REFloopback 路径)
- 软件层AudioProcessor::Initialize 已写 AEC/VAD 初始化,缺的只是 sdkconfig 启用 + 板级 REF 启用
### TL;DR
**音频管线极其简陋ESP-IDF + simple_pipeline stub**。**AFE 整套代码已写好但未启用**,硬件层无 REF 通道。**比 Baji 项目更"裸"**——Baji 走的是一样的 codec 直写路径,没区别。
---
## 4. 已有功能清单
| 功能 | 实现位置 | 说明 |
|---|---|---|
| **BLE 配网** | `bluetooth_provisioning.cc`1417 行) | **自定义 GATT 二进制协议**Service 0xABF0不是 BluFi。BluFi 编译开关 `CONFIG_BT_BLE_BLUFI_ENABLE=y` 启用但代码未调用 |
| **生产测试模式** | `application.cc` "Airhub" 标签 | 触摸/IMU 自检上报 |
| **本地 P3 播放** | `application.cc:300 PlaySound` | 走 `OnAudioOutput` → codec OutputData**不走 player_pipeline** |
| **HTTPS 故事** | `application.cc:SendStoryRequest + HttpsApiPlayback` | base64 Opus 解码 → 入 audio_decode_queue_ |
| **HTTPS 音乐** | `application.cc:SendMusicRequest` | 同上 |
| **IoT/MQTT** | `main/iot/thing.cc` | MQTT-UDP 协议保留RTC 模式下未启用 |
| **按键** | KEY4GPIO4故事键+ BOOTGPIO0 | `iot_button` 组件 |
| **LED** | `BUILTIN_LED_GPIO=21`SingleLed | |
| **IMU** | QMI8658AI2C 0x6A运动检测唤醒/打断 | `movecall_moji_esp32s3.cc:838 InitializeImuSensor` |
| **触摸** | 4 路 TouchPadGPIO1/2/15/7 | `TouchEventTask`line 1643 |
| **电池** | GPIO6 ADC1_CHANNEL_5 | line 828 |
| **OTA** | `main/ota.cc` | |
| **天气** | `weather_api.cc` | |
| **WakeWord** | 代码存在未编入 | |
文档参考:`README_RTC.md``02Kapi_Rtc_火山RTC替换实现方案.md``QMI8658A驱动适配方案_B站驱动.md`
### TL;DR
**业务功能比 Baji 更精简**:无 LCD、无 LVGL、无 GIF 解码、无相册、无应援灯,但有 IMU + 4 路触摸。BLE 配网与 Baji 完全一致(同源代码)。
---
## 5. 资源占用现状
### 5.1 Flash
- 分区 `partitions.csv`nvs 16K + otadata 8K + model SPIFFS 3MB + ota_0/1 各 5MB = 13MB16MB 板,剩 3MB 余量)
- 实际固件大小约 3.5-4MB同源代码估算**OTA 分区 5MB 富余度极宽**
### 5.2 SRAM关键
- **运行日志显示 `free_heap=8289744`**(启动后约 8MB→ 这是 **PSRAM + 内部 SRAM 总和**
- Volc RTC 启动后跌到约 8.05M,运行中波动在 7.88-7.89Msubv 消息处理)
- 没看到 internal SRAM 单独打印,但 BLE+RTC+ES7210+ES8311 在 ESP32-S3 N16R8 上 **runtime 内部 SRAM 余量约 80-130KB 是常见值**(比 Baji 多 30-50KB
- `SPIRAM_MALLOC_RESERVE_INTERNAL=65536` 保留 64KB
### 5.3 PSRAM
- 8MB Octal 80MHz运行时空闲约 7.5-8M**资源极其宽松**
- Baji 是同款 S3-N16R8 模组,但 Baji 还要承载 LVGL~50KB DRAM+ 360×360 GIF 缓冲(~250KB PSRAM+ JPEG 背景
### TL;DR
**Kapi 比 Baji 资源宽松约 300-500KB PSRAM + 30-50KB 内部 SRAM**(省掉 LVGL/GIF/相册。Flash OTA 分区 5MB 完全够用。**AFE 启用预计需要 ~150-200KB PSRAM + 30KB 内部 SRAM**,资源**完全够**。
---
## 6. 与 Baji_Rtc_Toy 的差异
| 维度 | Kapi_Rtc_toy | Baji_Rtc_Toy |
|---|---|---|
| 模组 | ESP32-S3-N16R8 | ESP32-S3-N16R8同款 |
| 板型 | movecall-moji-esp32s3无屏 | 同板加 LCDQSPI ST77916 360×360 |
| LVGL | ❌ 无 | ✅ 有,~50KB DRAM |
| 数字人 GIF | ❌ 无 | ✅ 有2 个透明 GIFharu/hiyori |
| 应援灯 | ❌ 无 | ✅ DMA 直写 GRAM |
| 双模式 (AI/吧唧) | ❌ 单模式 | ✅ NVS 切换 |
| BLE 图传 | ❌ 无 | ✅ 0x0B00 服务 |
| 触摸 LCD | ❌ 无 | ✅ CST816S |
| 按键 | BOOT+KEY4 | BOOT+KEY2 |
| IMU | ✅ QMI8658A | ❓ 待确认 |
| 自定义 BLE 配网 | ✅ 0xABF0 | ✅ 0xABF0同源 |
| **Phase 6 软退出** | ❌ 无 | ✅ 已实现 |
| **AFE/AEC** | ❌ 代码在未启用 | ❌ 代码在未启用(同源) |
| Volc RTC SDK | volc_engine_rtc_lite | volc_engine_rtc_lite同源 |
### TL;DR
**Kapi 是 Baji 的"无屏底座"**,节省约 300-500KB PSRAM + 30-50KB 内部 SRAM。RTC/BLE/codec 代码完全同源,**Phase 6 移植成本极低**。
---
## 7. 已有的 RTC/AEC/Opus 相关规划文档
| 文档 | 状态 | 关键内容 |
|---|---|---|
| `00Kapi_Rtc_火山RTC整合移植方案.md` | 已实施 | WS → 火山 RTC 总体方案 |
| `01..._技术分析报告.md` | 已实施 | 用 volc_engine_rtc_lite 替换 WS |
| `02..._火山RTC替换实现方案.md` | 已实施 | VolcRtcProtocol 具体实现 |
| `03AEC_VOICE_INTERRUPT_PORTING_PLAN.md` | **计划,未实施** | Airhub_Rtc_h → Kapi 的 ES7210 双 mic + AEC + 语音打断移植方案。代码片段已示范 `aec_create + aec_process`,建议 `mic_selected` 改为 MIC1+MIC330dB 增益 |
| `AEC_VAD_OPTIMIZATION.md` | 设计,部分已写入 audio_processor.cc | AEC+VAD 联合启用(`AEC_MODE_VOIP_LOW_COST` + `VAD_MODE_3`、回声感知、动态阈值EchoAwareVadParams 结构已在头文件 |
| `04-2025-11-21音频优化记录.md` | 已实施修复 | 开机播报"尖锐声"修复:单声道 PCM 复制为立体声(`application.cc:1224-1230`MONO I2S 会导致 RTC 入房失败 |
| `VOICE_INTERRUPT_*.md` / `URGENT_INTERRUPT_FIX.md` / `BOOT_BUTTON_*` | 历史调试笔记 | 语音打断和按键交互优化记录 |
### TL;DR
**Kapi 已计划好"AFE-AEC + 语音打断"的实现路径但没落地**03、AEC_VAD_OPTIMIZATION。**Opus 上下行优化未在文档中提及**(当前 G711A 已可用)。
---
## 8. 三个移植/重构选项评估
### 选项 A保持 ESP-IDF移植 Baji Phase 6软退出 + 字幕提示)
| 维度 | 评分 |
|---|---|
| 工作量 | **低**1-2 天):基类加 `LeaveRoom()` + VolcRtcProtocol override + 应用层 hibernate 状态机 + B+C 双源刷新 |
| 风险 | **低**:基类代码同源,`volc_rtc_destroy` 调用已存在(`volc_rtc_protocol.cc:32-34`),只需提取为独立接口 |
| 资源占用 | **零**:只加几个原子标志和 NVS 计数器 |
| 字幕提示效果 | **打折**Kapi 无 LCD`display->SetChatMessage` 是 noop`Display` 是空对象 `movecall_moji_esp32s3.cc:1541`)。可改为 LED 闪烁或 P3 语音提示替代 |
| 真退房收益 | **完全保留**License 释放 + BOOT 唤醒 3-5s |
| 兜底机制 | 保留 `idle_cycles_` 50 次重启兜底,无影响 |
**建议:✅ 强烈推荐**。除字幕提示需替换为语音/LED 外,**其他所有收益真退房、快速恢复、状态保留100% 适用**。这是性价比最高的优化。
---
### 选项 B保持 ESP-IDF启用 AFE + Opus 切换
#### B-1启用 ESP-SR AFE设备端 AEC
| 维度 | 评分 |
|---|---|
| 工作量 | **中**3-5 天sdkconfig 三项打开 + board config `AUDIO_INPUT_REFERENCE=1` + box_audio_codec mic_selected 加入 MIC_REF + Application::OnAudioInput 走 AudioProcessor + ES8311→ES7210 loopback 验证 |
| 风险 | **中**:① ES7210 REF 通道接线需硬件确认Moji 板原理图待查);② AEC 调参filter_length、AEC_MODE_VOIP_LOW_COST vs SR_LOW_COST③ ES8311 立体声输出与单声道 AFE 输入的通道映射 |
| 资源占用 | **+150-200KB PSRAM + 30KB 内部 SRAM + ~20% CPU**Core 1 |
| 收益 | **大**:从"无设备端 AEC"→"有 AEC",对话打断体验提升明显;目前打断完全依赖云端 VAD延迟 1-3s参考 03 文档结论) |
#### B-2G711A → Opus 上行切换
| 维度 | 评分 |
|---|---|
| 工作量 | **中**2-3 天):火山 SDK config 改 `"audio":{"codec":4}` 为 Opus`volc_rtc_protocol.cc:76`),需上行编码改 OPUS已有 `opus_encoder_` 实例),下行解码改 OPUS已有 OpusDecoderWrapper |
| 风险 | **中**:① 火山服务端房间名 `aibotrtc_G711A_*` 暗示通道协商当前锁定 G711A要确认服务端是否支持切 Opus② 上行 Opus 60ms 帧比 G711A 20ms 帧延迟高 40ms |
| 资源占用 | **+~10KB 内部 SRAM**Opus 编码器) |
| 收益 | **小到中**Opus 比 G711A 在同等比特率下质量明显更高,但 G711A 在小 toy 设备上听感已经"够用"。**jitter buffer 优化更值得做** |
#### B-3Jitter buffer 优化
- 当前 `audio_decode_queue_` 是无限增长的 std::list无主动 jitter buffer 管理
- 网络抖动时累积延迟,但**当前没收到具体抖动投诉**
- 建议先做 A、B-1确认音频体验之后再评估
**建议**
- B-1 (AFE-AEC) ✅ **推荐**,但**先确认 Moji 板硬件 REF 通道接线**(如果 REF 没飞线则只能软件回环 PCM效果差很多
- B-2 (Opus) ⚠️ **不推荐先做**:服务端兼容性需求未明确,收益边际;先把 AEC 做对
- B-3 (Jitter) ⚠️ **暂缓**:没具体痛点,纯优化无意义
---
### 选项 C完全重构成 ESP-ADF + 官方 high_quality_solution
| 维度 | 评分 |
|---|---|
| 工作量 | **极高**3-4 周ESP-ADF 框架与当前 codec 直写架构差异巨大ConversationalAI-Embedded-Kit-2.0 官方 demo 板 ESP32-S3-Korvo-2 与 Moji 引脚完全不同BLE 配网/IMU/触摸/电池/HTTPS 故事/天气全部需要迁移 |
| 风险 | **极高**:① ADF audio_pipeline 与 esp_codec_dev 不兼容,要全部重写 codec 路径;② ADF 自带 button/peripheral 与 iot_button 冲突;③ ESP-ADF eca11f20 版本要绑 IDF v5.4,可能引入新构建问题;④ 业务代码HTTPS 故事/IMU/触摸/BLE全部要适配 |
| 资源占用 | **+200-400KB**ADF 框架本体 + 多个 audio_element 任务) |
| 收益 | **官方支持 + 高音质方案 (high_quality_first)**官方持续维护AEC + 噪声抑制 + AGC 全部内置;可能比手撸 AFE 体验更好 |
| 兼容性 | Volc 官方 demo 用的就是这套;与火山服务端协议完美对齐 |
**建议:❌ 不推荐**,理由:
1. 当前业务**已能跑通 RTC 对话**,没必要推翻重来
2. ESP-ADF 引入的复杂度pipeline / element / event与当前轻量架构哲学冲突
3. 板级适配Moji 与 Korvo-2 引脚映射)工作量约等于重写整个项目
4. 同等收益可以用"Phase 6 软退 + AFE 启用"的组合拳达到,工作量是 1/5
**例外**:如果未来要做**双麦克风 beamforming + 多说话人分离**等 ADF 高级特性,再考虑重构。
---
## 9. 最终推荐路线
按优先级递进:
1. **第 1 步(必做)**:移植 Baji Phase 6 软退出方案
- 工作量 1-2 天收益巨大License 释放 + 唤醒 3-5s + 状态保留)
- 字幕提示替换为 LED 闪烁 / `PlaySound(Lang::Sounds::P3_xxx)` 语音提示
- 加上 B+C 双源刷新 `last_audible_output_time_`
2. **第 2 步(推荐)**:硬件确认 + 启用 ESP-SR AFE-AEC
- 先 Moji 板原理图确认 ES7210 REF 是否接到 ES8311 输出
- 如已飞线 → 启用 `AUDIO_INPUT_REFERENCE=1` + AudioProcessor + sdkconfig 三项
- 如无飞线 → 评估软件 loopback 方案Application 端拷贝 output PCM 作为 reference
3. **第 3 步(按需)**:观察对话体验,再决定 Opus 上行 / Jitter buffer
4. **第 4 步(不做)**ESP-ADF 重构
---
## 10. 关键引用清单(绝对路径)
### Kapi_Rtc_toy 项目内
- `main/CMakeLists.txt:235-239` — RTC 模式宏定义
- `main/protocols/volc_rtc_protocol.cc:394-407` — CloseAudioChannel 只 stop 不 destroy
- `main/protocols/volc_rtc_protocol.cc:32-34` — volc_rtc_destroy 已被析构函数调用,提取 LeaveRoom 极容易
- `main/application.cc:1961-2042` — Dialog Watchdog 当前用 esp_restart()
- `main/application.cc:2161` — 唯一的 last_audible_output_time_ 刷新点(方案 A
- `main/application.cc:1321` — subtitle 分支位置(方案 B 插入点)
- `main/audio/simple_pipeline.cc:1-60` — codec 直写 stub确认非 ESP-ADF
- `main/audio_codecs/box_audio_codec.cc:67` — ES7210 mic_selected
- `main/boards/movecall-moji-esp32s3/config.h:27``AUDIO_INPUT_REFERENCE 0`
- `main/boards/movecall-moji-esp32s3/movecall_moji_esp32s3.cc:1507-1521` — BoxAudioCodec 创建
- `sdkconfig:642-645` — AUDIO_PROCESSOR 未启用
- `main/audio_processing/audio_processor.h:41-90` — AudioProcessor 已完整实现,等启用
- `main/idf_component.yml:8` — esp-sr ^2.0.3 已声明
- `05-最新日志.txt:160` — 房间名 `aibotrtc_G711A_*` 确认下行 G711A
- `03AEC_VOICE_INTERRUPT_PORTING_PLAN.md` — AEC 移植规划(计划未实施)
### Baji_Rtc_Toy 衍生项目交叉引用
- `/Users/rdzleo/Desktop/Baji_Rtc_Toy/docs/Rtc_AIavatar/RTC软退出方案_移植参考.md` — Phase 6 完整移植参考(手把手)
- `/Users/rdzleo/Desktop/Baji_Rtc_Toy/docs/Rtc_AIavatar/官方Korvo2方案_对比分析报告.md` — 包含与官方 Korvo-2 的全方位对比、ES7210 AEC 电路分析、决策记录
- `/Users/rdzleo/Desktop/Baji_Rtc_Toy/.planning/milestones/digital_human_rtc/phases/phase_06_idle_hibernate/PLAN.md` — Phase 6 实施计划
- `/Users/rdzleo/Desktop/Baji_Rtc_Toy/.planning/milestones/digital_human_rtc/phases/phase_07_battery_psm/README.md` — Phase 7 占位规划
---
## 11. 一句话总结
> **Kapi_Rtc_toy 是 Baji_Rtc_Toy 的"无屏轻量版底座"**。Phase 6 软退出方案 100% 可移植且工作量极小(仅显示提示需替换为 LED/语音AFE-AEC 资源富余但需先确认硬件 REF 通道;**坚决不推荐**重构成 ESP-ADF。
---
## 附录·重要提醒
🎯 **Kapi 是更合适的 AFE 实验场地**
Baji_Rtc_Toy 项目目前 internal SRAM 仅剩 **44KB**(参见 Baji 项目 `docs/Rtc_AIavatar/官方Korvo2方案_对比分析报告.md` §11.2),启用 AFE 后将仅剩 9KB**几乎必然导致开机崩溃**。
而 Kapi_Rtc_toy 项目 internal SRAM 余量 **80-130KB**,启用 AFE 后仍有 **50-100KB 安全余量**
**结论**:未来如要验证 ESP-SR AFE 启用方案,**应该优先在 Kapi 项目实验**,跑通后再回到 Baji 评估资源能否承载。