跳到主要内容

第 1 章 项目总览与文件分级总览表

本章解决两个问题:① 这份代码是个什么东西、整体怎么跑起来;② 哪些文件是核心、哪些是辅助、哪些一辈子都不用看。后面所有章节都会基于这张总览表展开。


1.1 项目是什么

xiaozhi-esp32-main 是开源项目「小智 AI 聊天机器人」的 v2 版本固件源码(仓库 78/xiaozhi-esp32)。代码角色:

角色说明
麦克风用 I²S 采集 16 kHz PCM
唤醒词识别板载 ESP-SR("你好小智"等),整段离线运行
编解码Opus(窄带语音压缩),上行下行都是 Opus 帧
通信选 WebSocket 或 MQTT+UDP 之一,向云端发音频 + 收音频/文本
云端语音处理ASR(语音转文字)→ LLM(Qwen/DeepSeek 等)→ TTS(合成语音),全部在服务器
表情/状态显示OLED / LCD / AMOLED / e-Paper 均可,UI 走 LVGL
设备控制通过 MCP 协议(一种基于 JSON-RPC 2.0 的工具调用协议)暴露音量、灯光、电机、GPIO 等给云端大模型

一句话:麦克风 + 网络 + 喇叭 + 一个能被 LLM 调用 GPIO 的协议 = 一个会对话能控制硬件的小盒子。

支持的芯片:ESP32 / ESP32-C3 / ESP32-S3 / ESP32-C5 / ESP32-C6 / ESP32-P4。开发板(boards/)有 110 块。

1.2 顶层目录速览

xiaozhi-esp32-main/
├── CMakeLists.txt # 顶层 CMake,引 ESP-IDF
├── sdkconfig.defaults* # 各芯片默认 menuconfig 配置
├── README*.md # 项目自述(中英日三份)
├── LICENSE # 开源协议
├── main/ # 应用代码(本项目的全部业务逻辑)
├── partitions/ # 分区表 v1 / v2
├── scripts/ # Python 辅助脚本:资源打包、发布、音频调试
├── docs/ # 协议文档(MCP、WebSocket、MQTT+UDP、自定义板子)
└── .github/ # GitHub Actions CI 配置(每个板子自动构建)

只有 main/ 是业务代码。其它都是构建胶水、文档、CI——读不读完全不影响理解。

main/ 下进一步拆:

main/
├── CMakeLists.txt # 列出所有源文件 + 110 个板子的条件分支选择
├── Kconfig.projbuild # 项目级 menuconfig 选项(板子型号、AEC 模式、唤醒词等)
├── idf_component.yml # ESP-IDF 组件依赖清单(esp-sr、opus、lvgl 等)
├── main.cc # app_main(),30 行
├── application.{cc,h} # ★ 全局单例 Application,主事件循环(1055 行)
├── device_state.h # 11 个状态枚举
├── device_state_machine.{cc,h} # ★ 状态机 + 回调观察者
├── ota.{cc,h} # ★ 服务器握手 / 激活 / 固件升级
├── settings.{cc,h} # NVS 键值对封装
├── system_info.{cc,h} # 芯片型号 / MAC / 堆内存信息
├── mcp_server.{cc,h} # ★ 设备端 MCP 工具调用服务器
├── assets.{cc,h} # ★ assets 分区(字体/表情/唤醒词模型)管理

├── audio/ # ★ 音频子系统
├── protocols/ # ★ WebSocket / MQTT+UDP 双协议
├── display/ # 显示子系统(LCD / OLED / e-Paper / 表情)
├── led/ # 状态指示灯
├── assets/ # 多语言文字 + 提示音 OGG 文件
└── boards/ # 110 个开发板的硬件适配
├── common/ # ★ 板级共用基类(Board / WifiBoard / Ml307Board / blufi 等)
└── <某板子>/ # 各板子具体的 GPIO 引脚、屏幕驱动、按键映射

带 ★ 的就是后面会逐文件逐函数讲的核心模块。

1.3 全局架构与启动流程

1.3.1 一张图看懂启动顺序

ESP-IDF 启动


app_main() ── main.cc 初始化 NVS 闪存


Application::GetInstance() ① 单例 → 创建事件组 + 时钟 timer


Application::Initialize() ② 一系列同步初始化(在 app_main 上下文)
│ ├─ Board::GetInstance() └─ 板级单例 (board.cc 里 create_board())
│ ├─ display = board.GetDisplay() └─ 拿屏(每个板子构造时已创建)
│ ├─ audio_service_.Initialize(codec) └─ 装好编解码器、起 audio 任务
│ ├─ audio_service_.Start()
│ ├─ audio_service_.SetCallbacks(...) └─ 把"有 Opus 包可发"等回调挂到 event group
│ ├─ state_machine_.AddStateChangeListener(...) └─ 状态变 → 触发 event group
│ ├─ esp_timer_start_periodic(1s) └─ 心跳 timer
│ ├─ McpServer::GetInstance().AddCommonTools() └─ 注册 self.audio_speaker.set_volume 等通用工具
│ ├─ board.SetNetworkEventCallback(...) └─ 网络连/断/扫描等 UI 反馈
│ └─ board.StartNetwork() └─ 异步启动 WiFi / 4G


Application::Run() ③ 永不返回的主事件循环

│ while (true) {
│ xEventGroupWaitBits(...); ← 13 种事件位
│ 处理:状态变 / 网络变 / 唤醒词 / VAD / 心跳 / 主线程任务 / ...
│ }

└── 与此并行运行的后台任务:
├─ ActivationTask(一次性):拉服务器配置、CheckNewVersion、激活、初始化协议
├─ audio_input_task / audio_output_task / opus_codec_task
├─ LVGL 任务(在 display.cc / LvglDisplay 里起)
├─ 网络栈本身的 RTOS 任务(WiFi/MQTT/WS/UDP)
└─ 各板子的辅助任务(按键防抖、电池监控、屏幕背光定时器 等)

1.3.2 谁负责什么——一句话总结

模块责任
main.cc上电跳板,30 行
Application大调度器,所有事件汇总在它的 event_group_ 上,谁也别绕开
Board板子抽象,每块板子各自实现 audio_codec / display / network 等接口的具体硬件
AudioService三个 RTOS 任务管全部音频读写、Opus 编解码、唤醒词馈喂、AFE 处理
Protocol(基类)+ WebsocketProtocol / MqttProtocol收发两边的 JSON 控制信令 + 二进制 Opus 帧
McpServer把"音量""灯光""GPIO"等本地能力注册成 MCP 工具,给云端 LLM 调用
Ota启动后向 xiaozhi.me 发 POST 拿配置(含 MQTT/WS 端点),处理激活码与固件升级
Assets管理 SPI Flash 上一个名为 assets 的分区(字体、表情、唤醒词模型按文件名 mmap)
DisplayUI 抽象。LcdDisplay / OledDisplay / EmoteDisplay 各自实现
Led状态指示灯(单 LED 闪烁、WS2812 灯环、RGB)
Settings对 ESP-IDF NVS 的轻量封装,读写小配置

1.3.3 数据流速览

上行:你说话 → 服务器

MIC (I²S)

▼ AudioCodec::InputData → vector<int16_t>
audio_input_task

├─ 喂 → WakeWord::Feed (若处于 idle、需要监听唤醒词)
├─ 喂 → AudioProcessor::Feed (若 listening 状态,AFE 做降噪/VAD/AEC)
└─ 否则丢弃

AudioProcessor 输出

▼ PushTaskToEncodeQueue(kEncodeToSendQueue)
opus_codec_task

▼ Opus 编码
audio_send_queue_ ──→ MAIN_EVENT_SEND_AUDIO

▼ Application::Run() 取包
protocol_->SendAudio(...)


WebSocket 二进制帧 / UDP+AES 加密 → 服务端 ASR+LLM+TTS

下行:服务器 → 喇叭

WebSocket/UDP 收到二进制 Opus

▼ protocol_ on_incoming_audio 回调
audio_service_.PushPacketToDecodeQueue(...)

opus_codec_task

▼ Opus 解码
audio_playback_queue_


audio_output_task

▼ AudioCodec::OutputData → I²S → 喇叭

控制信令(JSON)走另一条路:

WebSocket/MQTT JSON 文本

▼ protocol_ on_incoming_json
Application::InitializeProtocol 中注册的大 switch(按 type 分发)
├─ "tts" / "stt" / "llm" → 改设备状态 + UI
├─ "mcp" → McpServer::ParseMessage(工具调用)
├─ "alert" → 弹提示
└─ "system" → reboot 等

1.4 全文件分级总览表(这是本章最值钱的一张表)

分级说明:

  • ★★★ 核心:业务主干,必须逐文件读懂,关键函数要逐段注释
  • ★★ 重要:模块的稳定基础,要懂作用 + 主要类/函数 + 关键技术点
  • ★ 辅助:偶尔读一眼即可,会按用途归类讲,但不展开
  • ○ 板级硬件:110 块板子里挑代表讲,其余看名字知道是什么
  • — 构建/资源:CMake / Kconfig / 资源文件 / CI / 文档,不是 C++ 业务代码

1.4.1 main/ 根目录(11 个文件)

文件行数分级一句话作用主要技术
main.cc30★★★入口;NVS 初始化 + Application 单例 + Run()ESP-IDF app_main
application.h186★★★Application 类定义 + 13 种事件位宏 + AEC 模式枚举事件组、单例
application.cc1055★★★大调度器:初始化、主循环、所有协议回调、激活、升级、状态切换FreeRTOS EventGroup、esp_timer、lambda、Schedule(任务)、互斥锁、unique_ptr
device_state.h17★★★11 个状态枚举(idle/listening/speaking 等)enum
device_state_machine.h83★★★状态机 + 观察者回调std::atomic<>、互斥锁
device_state_machine.cc161★★★状态转换合法性表 + 通知监听者状态机、switch case 转换表、观察者模式
ota.h58★★OTA 类接口(CheckVersion / Activate / Upgrade)
ota.cc473★★xiaozhi.me 握手取配置、激活码循环、esp_https_ota 升级HTTP POST + JSON、HMAC-SHA256、esp_https_ota
assets.h52★★Assets 单例接口
assets.cc532★★管理 SPI Flash 上一个 assets 分区:下载、校验、mmap、按文件名取数据esp_partition_*mmap、流式 CRC、HTTP 下载
mcp_server.h344★★★Property / PropertyList / McpTool / McpServer 完整类型定义 + base64 编码std::variantstd::optional、模板、JSON-RPC 2.0
mcp_server.cc563★★★MCP 协议解析 + initialize / tools/list / tools/call 三大方法实现 + 内置工具注册JSON-RPC、cJSON、线程池跑工具
settings.h28Settings 类接口
settings.cc108NVS 命名空间封装nvs_flash
system_info.h22静态方法集合
system_info.cc151取 MAC / 芯片型号 / 堆内存 / 任务表esp_chip_infouxTaskGetSystemState

1.4.2 main/audio/ —— 音频子系统(19 个文件)

文件行数分级一句话作用主要技术
audio_codec.h61★★★AudioCodec 抽象基类:双工标志、I²S 句柄、Read/Write 纯虚I²S、抽象基类
audio_codec.cc77★★基类默认实现:音量、增益、Start默认行为
audio_service.h160★★★AudioService 接口 + 队列上限宏 + 事件位宏 + AudioServiceCallbacks任务/队列设计
audio_service.cc686★★★三任务(input/output/codec)+ 5 个队列 + 唤醒词/AFE 切换 + 节流 + Opus 重采样FreeRTOS Task、条件变量、deque 队列、std::chrono 节流、Opus 编解码、采样率重采样
audio_processor.h26★★AudioProcessor 抽象基类(前端处理)抽象
wake_word.h26★★WakeWord 抽象基类抽象
processors/afe_audio_processor.{cc,h}187+★★ESP-SR AFE 实现:VAD + AEC + 降噪ESP-SR AFE API
processors/no_audio_processor.{cc,h}59+兜底无处理实现(小芯片用)直通
processors/audio_debugger.{cc,h}67+录音转发到本机 Python 脚本听效果UDP 流
wake_words/afe_wake_word.{cc,h}208+★★用 ESP-SR AFE 内置唤醒词wakenet 模型
wake_words/custom_wake_word.{cc,h}254+★★自定义 MFCC + 简单分类器信号处理
wake_words/esp_wake_word.{cc,h}87+★★兼容小芯片(C3)的轻量唤醒wakenet9
codecs/no_audio_codec.{cc,h}359+★★软件 I²S codec(无外置芯片,靠 MCU 自驱 PDM/麦克风)I²S std、PDM
codecs/es8311_audio_codec.{cc,h}196+ES8311 I²S codec 芯片驱动(最常见)I²C 配置寄存器
codecs/es8374_audio_codec.{cc,h}197+ES8374 codec同上
codecs/es8388_audio_codec.{cc,h}221+ES8388 codec(lyrat/某些 box)同上
codecs/es8389_audio_codec.{cc,h}203+ES8389 codec同上
codecs/box_audio_codec.{cc,h}244+乐鑫 ESP-BOX 自家组合方案双芯片协作
codecs/dummy_audio_codec.{cc,h}20+无音频硬件占位(编译过)假实现
README.md几行模块说明

1.4.3 main/protocols/ —— 通信协议(6 个文件)

文件行数分级一句话作用主要技术
protocol.h98★★★Protocol 基类 + AudioStreamPacket + 两版二进制帧头 + 几个 enum抽象基类、PoD struct + __attribute__((packed))
protocol.cc90★★★公共回调注册 + 发送 abort/listen/mcp 控制 JSON + 超时判断JSON 字符串拼接
websocket_protocol.h34★★★WebsocketProtocol 类声明
websocket_protocol.cc253★★★单条 WSS 连接同时传 JSON 文本 + Opus 二进制帧esp_websocket_client、HTTP hello 握手
mqtt_protocol.h65★★★MqttProtocol 类声明
mqtt_protocol.cc382★★★MQTT 走控制信令;UDP+AES-128-CTR 走 Opus 媒体流;hello/goodbye 协调MQTT 客户端、UDP socket、mbedtls AES-CTR、随机 nonce

1.4.4 main/display/ —— 显示子系统(13 个文件)

文件行数分级一句话作用主要技术
display.h81★★Display 基类接口 + DisplayLockGuard RAII + NoDisplay 占位抽象、RAII
display.cc56基类默认实现(多数为空、被子类覆盖)
oled_display.{cc,h}396+★★SSD1306/SSD1315 OLED LVGL 适配LVGL、I²C 屏
lcd_display.{cc,h}1196+★★LCD(ST7789、ILI9341、AMOLED、e-Paper)LVGL 适配,含状态栏/聊天气泡布局LVGL widget、字体、按需重绘
emote_display.{cc,h}657+表情专用显示风格(动画化、整屏铺满)LVGL Animation
lvgl_display/lvgl_display.{cc,h}258+★★LVGL 启动、tick 任务、主题切换LVGL Port
lvgl_display/lvgl_theme.{cc,h}30+主题(深/浅色)
lvgl_display/lvgl_font.{cc,h}12+字体注册(普惠/font_awesome)
lvgl_display/lvgl_image.{cc,h}63+图片资源解码
lvgl_display/emoji_collection.{cc,h}123+表情包查表(twemoji 32/64)
lvgl_display/gif/{gifdec.c, lvgl_gif.cc}GIF 解码(emote_display 用)
lvgl_display/jpg/{image_to_jpeg.cpp, jpeg_to_image.c}JPEG 编解码(带相机的板子用)

1.4.5 main/led/ —— LED 状态指示(4 个文件)

文件行数分级一句话作用主要技术
led.h17Led 基类 + NoLed 占位抽象
single_led.{cc,h}单 LED(GPIO 闪烁)esp_timer 定时切换
gpio_led.{cc,h}多色 LED(多 GPIO 组合)
circular_strip.{cc,h}WS2812 RGB 灯环(state→颜色映射)RMT 驱动

1.4.6 main/boards/common/ —— 板级共用基类(22 个文件)

文件行数分级一句话作用主要技术
board.h93★★★Board 基类 + DECLARE_BOARD 宏 + NetworkEvent enum + PowerSaveLevel抽象基类、虚函数、DECLARE_BOARD 单例宏
board.cc178★★公共方法默认实现(GenerateUuid、GetSystemInfoJson、GetLed/Display 默认占位)UUID 生成
wifi_board.{cc,h}359+★★★所有 WiFi 板子的基类:连 WiFi、配网(SmartConfig/AP/BluFi)、事件分发esp_wifi、esp_netif、事件
ml307_board.{cc,h}274+★★4G 模组(中移 ML307)板子的基类UART + AT 指令
dual_network_board.{cc,h}同板支持 WiFi+4G 切换双栈共存
button.{cc,h}★★按键防抖、长短按区分iot_button 组件
knob.{cc,h}旋钮(编码器)iot_knob
backlight.{cc,h}LCD 背光 PWMledc
power_save_timer.{cc,h}空闲计时降功耗esp_timer
sleep_timer.{cc,h}深度睡眠倒计时esp_sleep
system_reset.{cc,h}长按硬件复位、出厂nvs erase + reset
i2c_device.{cc,h}I²C 设备父类(codec/PMIC 复用)i2c_master
adc_battery_monitor.{cc,h}ADC 读电压估电量adc_oneshot
axp2101.{cc,h}AXP2101 电源管理 IC 驱动I²C
sy6970.{cc,h}SY6970 充电 ICI²C
camera.h + esp32_camera.{cc,h}DVP/MIPI 摄像头驱动(带摄像头的板子用)esp32-camera 组件
lamp_controller.h灯具控制接口
afsk_demod.{cc,h}AFSK 声波配网解调(手机用 web 发 wifi 配置)DSP
blufi.{cpp,h}777蓝牙 BLE 配网(BluFi 协议)nimble BLE
press_to_talk_mcp_tool.{cc,h}把"按住说话"模式注册成 MCP 工具MCP tool 复用模板

1.4.7 main/boards/<各板子>/ —— 110 块开发板

每块板子目录下基本只有 3 类文件:

<board-name>/
├── config.h 硬件 GPIO 引脚号宏定义
├── config.json 给 CI 用的"这个板子叫什么、追加哪些 sdkconfig"
├── <board>_board.cc 继承 WifiBoard / Ml307Board,实现 GetAudioCodec / GetDisplay 等
└── README.md / 图片 可选

本文档不会把 110 块全部拆开讲——里面 95% 是引脚号差异。后面第 9 章会挑 3 个代表(bread-compact-wifi 面包板、esp-box-3 乐鑫官方开发板、xmini-c3-4g 带 4G 的硬件)讲清楚"如何看懂一个板子目录"。其余板子你看到目录名 xxx-s3-touch-amoled-1.8 这种就能猜出大概,遇到具体硬件 GPIO 才去对应目录翻 config.h

1.4.8 main/assets/ —— 资源文件(非代码)

子目录内容分级
common/5 个通用 OGG 提示音(success / exclamation / vibration / popup / low_battery)
locales/<lang>/36 种语言的 language.json(文本翻译表)+ 部分语言独有的 OGG 数字播报音(活码激活时)
lang_config.hCMake 阶段由 scripts/gen_lang.py 自动从对应 locale 的 JSON 生成的 C++ 头

讲解时这里只需要知道:"文本翻译表 + 提示音 ogg 文件,编译期被嵌进固件二进制"。

1.4.9 顶层辅助资源

路径分级用途
partitions/v1/partitions/v2/不同 Flash 容量、不同芯片的分区表 CSV
scripts/gen_lang.py从 locales/*/language.json 生成 C++ 头
scripts/build_default_assets.py把字体+表情+唤醒词模型打成一个 assets.bin
scripts/release.pyscripts/versions.py发版构建脚本
scripts/audio_debug_server.py配合 audio_debugger.cc 监听设备的 UDP 流听音质
scripts/ogg_converter/scripts/mp3_to_ogg.sh提示音转码工具
scripts/Image_Converter/LVGL 图片资源转换
scripts/spiffs_assets/scripts/p3_tools/scripts/acoustic_check/资源/声学测试小工具
scripts/sonic_wifi_config.htmlAFSK 声波配网用的浏览器页面
docs/mcp-protocol.mdMCP 协议官方说明
docs/mcp-usage.mdMCP 用法教程
docs/websocket.mdWebSocket 通信细节
docs/mqtt-udp.mdMQTT + UDP 媒体流细节
docs/custom-board.md怎么添加自己的板子
docs/blufi.mdBluFi 蓝牙配网说明
docs/v0/docs/v1/旧版资料
.github/workflows/每块板子的 CI 构建工作流

1.5 本项目核心技术与方法清单

后面章节会随用随讲,这里先列一份"看这份代码会学到什么"的索引:

1.5.1 FreeRTOS / 嵌入式并发原语

技术在哪里用到干什么
EventGroup(事件组)application.ccevent_group_audio_service.ccevent_group_不同 task 之间用 1 bit 1 个事件来"提醒"主循环干活
xTaskCreateaudio_service.cc(input/output/codec 三个任务)、application.cc 的激活任务、各板子的按键任务创建独立 RTOS 任务
esp_timer 周期定时application.cc 的 clock_timer(1 秒滴答更新状态栏)、led/single_led.cc 的闪烁软定时器在 timer 任务上下文回调
std::mutex / std::lock_guardapplication.cc 的 main_tasks_ 队列、device_state_machine.cc 的 listeners_、audio_service.cc 的 audio_queue_mutex_跨任务共享数据保护
std::condition_variableaudio_service.cc 的 audio_queue_cv_队列空/满时阻塞/唤醒 codec 任务
std::atomicdevice_state_machine.cc 的 current_state_状态字段无锁读写
vTaskDelete激活任务做完后自杀一次性任务清理
uxTaskPriorityGet/Set + RAII(TaskPriorityResetapplication.h 末尾那个 helper 类临时提权再恢复,常见于关键短任务

1.5.2 状态机 + 观察者

  • 11 个状态(device_state.h);
  • 一张合法转换表(device_state_machine.cc::IsValidTransition)——非法转换直接拒绝并 ESP_LOGW
  • 观察者:AddStateChangeListener 注册回调,转换成功后挨个调;
  • Application 把"状态变了"翻译成 MAIN_EVENT_STATE_CHANGED 事件位,再在主循环里执行真正的副作用(点灯/切音频任务/UI),保证副作用都跑在主任务上下文

1.5.3 单例模式 + DECLARE_BOARD 宏

  • Application::GetInstance()McpServer::GetInstance()Assets::GetInstance()Board::GetInstance() 都用 C++11 magic static(线程安全的局部静态变量);
  • 但是 Board 比较特别:用宏 DECLARE_BOARD(BoardClass) 由具体板子定义 create_board()Board::GetInstance() 内部调用 static_cast<Board*>(create_board()) 完成多态实例化。整个项目只有一处板级实例化,靠 CMake 选板子的源文件来决定 create_board() 到底返回哪个子类。这就是"110 个板子怎么共用同一份 Application 代码"的关键。

1.5.4 工厂 + 抽象基类

每个子系统都搭一对"抽象基类 + 多个实现 + 工厂选择":

基类多个实现工厂决定点
BoardWifiBoard / Ml307Board / DualNetworkBoard / 110 个具体板子DECLARE_BOARD 宏(CMake 选板子)
AudioCodecNoAudioCodec / Es8311AudioCodec / Box* / ...各板子的 GetAudioCodec()
DisplayOledDisplay / LcdDisplay / EmoteDisplay / NoDisplay各板子的构造函数里 new
WakeWordAfeWakeWord / CustomWakeWord / EspWakeWordaudio_service.cc::Initialize + Kconfig
AudioProcessorAfeAudioProcessor / NoAudioProcessoraudio_service.cc::Initialize + Kconfig
ProtocolWebsocketProtocol / MqttProtocolapplication.cc::InitializeProtocol + 服务器下发的配置
LedSingleLed / GpioLed / CircularStrip / NoLed各板子的 GetLed()

1.5.5 回调式编程(避免上层关心下层细节)

  • Protocol::OnIncomingJson(...)Application 决定 JSON 来了怎么处理;
  • AudioServiceCallbacksApplication 决定唤醒/VAD/可发包了怎么响应;
  • Board::SetNetworkEventCallback(...)Application 在网络变化时改 UI 和状态;
  • McpToolstd::function<ReturnValue(const PropertyList&)> 让每个工具的具体实现可以是 lambda、可以是成员函数;
  • Ota::Upgrade(...) 接受进度回调,把"进度怎么显示"和"OTA 怎么下载"解耦。

1.5.6 JSON-RPC 2.0(MCP 协议)

  • mcp_server.cc 解析 method 字段,分发到 initialize / notifications/initialized / tools/list / tools/call
  • 工具描述(input schema)按 JSON Schema 规范写:type=object, properties={}, required=[…];
  • 调用结果统一封装成 {"content":[{"type":"text","text":"..."}],"isError":false}
  • 大模型那边可以理解"这台设备暴露了 set_volume / set_brightness / press_to_talk 等工具,调用它们"。

1.5.7 二进制流协议(音频帧)

  • WebSocket:帧头 BinaryProtocol2(16 字节)+ Opus payload;
  • MQTT+UDP:UDP 帧头 BinaryProtocol3(4 字节)+ AES-128-CTR(nonce, opus_payload);
  • 时间戳字段用于服务端 AEC(回声消除):服务器知道刚才发的是哪一段 TTS,就能在你这一段输入里减掉它。

1.5.8 资源管理与 Flash 分区

  • 分区表(partitions/v2/*.csv)划出 assets 分区;
  • assets.bin 的格式:固定头 + 文件索引表 + 各文件原始数据;
  • 运行期:esp_partition_mmap() 把分区直接映射进 CPU 地址空间,然后按 Asset { offset, size } 表去拿数据——字体直接 mmap 给 LVGL、模型直接 mmap 给 ESP-SR、不占内存
  • 升级:HTTP 下载新的 assets.bin → 写入分区 → 校验 CRC → 重 mmap → 应用。

1.5.9 ESP-IDF 特定 API 速览

  • nvs_flash_init():键值存储初始化;
  • esp_event_loop_create_default()(在 wifi_board 里):默认事件循环;
  • esp_https_ota_*:固件 OTA;
  • esp_partition_*esp_partition_mmap():分区表读写、mmap;
  • esp_timer_*:高精度软定时器;
  • esp_chip_info() / esp_efuse_* / esp_mac_addr_*:硬件信息;
  • esp_wifi_* / esp_netif_*:网络栈;
  • i2s_std_* / i2s_pdm_*:音频外设;
  • mbedtls_*:base64 / SHA / AES。

1.5.10 第三方库

  • cJSON:所有 JSON 解析/序列化;
  • Opus(含 encoder/decoder/resampler 三个包装类,来自管理组件):语音编解码;
  • ESP-SR:唤醒词模型 (wakenet) + AFE 前端处理;
  • LVGL:UI 框架;
  • esp-websocket-client:WebSocket;
  • esp-mqtt:MQTT 客户端;
  • iot_buttoniot_knob:按键/旋钮;
  • mbedtls:加解密;
  • 4G 模组用 ML307 SDK(espressif/atomic_*)。

1.6 看完本章你应该掌握的

  • 知道 main/ 是业务代码,其它目录只是构建/资源
  • 知道一次开机会经过 app_main → Application::Initialize → board.StartNetwork → 等网通了 → ActivationTask → 拉服务器配置 → 选 WS/MQTT → 进 idle 等唤醒
  • 能看着分级表估算优先级:核心 7-8 个文件读懂就能讲清整个项目
  • 知道这份代码用到的核心技术清单,遇到具体代码段能猜到属于哪个技术

下一章开始进入 main.cc + application.cc/h——主调度器逐段讲解。


参考资料:

  • 项目自带 README_zh.md 已实现功能列表
  • docs/mcp-protocol.md MCP 协议
  • docs/websocket.md WebSocket 帧格式
  • docs/mqtt-udp.md MQTT + UDP 媒体流
  • docs/custom-board.md 添加自定义板子