ESP32 S3-智能语音

AiXiaoZhi 项目结构与关键逻辑分析

生成方式:基于源码阅读整理

平台:ESP32 系列 (ESP32-S3 / ESP32-C3 / ESP32-P4)

框架:ESP-IDF 5.4

当前目标板:HiwonderExploit_S3

顶层版本:PROJECT_VER = 1.8.9

一、项目概述

小智 AI 语音助手,基于 ESP-IDF 5.4 的 ESP32 系列语音对话设备固件。

核心链路:本地唤醒词 → Opus 音频上行 → 云端 ASR/LLM/TTS → 音频下行播放。

支持:

  • 本地唤醒词检测(AFE/ESP/Custom 三种实现)
  • 音频前端处理(降噪 NS、回音消除 AEC、语音活动检测 VAD)
  • 双协议传输:MQTT+UDP(默认,AES-CTR 加密音频)、WebSocket
  • 云端 ASR + LLM + TTS 完整对话流程
  • LVGL 显示系统(LCD/OLED/ESP-Log,多表情)
  • OTA 远程升级 + 设备激活
  • MCP 设备控制协议(JSON-RPC 2.0)
  • 90+ 种开发板适配、多语言支持

二、目录结构(顶层)

复制代码
AiXiaoZhi/
├── main/                  # 全部源码(业务核心)
│   ├── main.cc            # 入口(app_main)
│   ├── application.cc/h   # 应用核心(单例 + 事件循环 + 状态机)
│   ├── ota.cc/h           # OTA 升级 + 服务器配置获取
│   ├── mcp_server.cc/h    # MCP 设备控制协议
│   ├── settings.cc/h      # NVS 键值存储封装
│   ├── system_info.cc/h   # 系统信息(MAC/堆内存等)
│   ├── device_state*.h    # 设备状态机与事件
│   ├── audio/             # 音频子系统(多任务流水线)
│   │   ├── audio_service.cc/h   # 音频服务(3 个 FreeRTOS 任务)
│   │   ├── audio_codec.h        # 编解码抽象
│   │   ├── codecs/              # ES8311/8388/8389/Box 等实现
│   │   ├── processors/          # AFE 降噪/AEC/VAD 处理器
│   │   └── wake_words/          # 唤醒词(AFE/ESP/Custom 三种)
│   ├── protocols/         # MQTT+UDP(默认)与 WebSocket(策略模式)
│   ├── display/           # Display 基类 + LCD(LVGL)/OLED/ESP-Log
│   ├── led/               # 单色 LED / 圆形灯带 / GPIO 状态灯
│   ├── boards/            # 90+ 种开发板 + common 公共基类
│   └── assets/            # 多语言 UI 文本 + OGG 音效
├── partitions/            # 16MB 分区表(v0/v1)
├── docs/                  # 协议文档
├── sdkconfig(.defaults)   # 构建配置
└── CMakeLists.txt         # 顶层构建(PROJECT_VER=1.8.9)

三、分层架构

层 主要内容
应用层 Application(状态机 / 调度 / 业务逻辑)
服务层 AudioService、Protocol(MQTT/WebSocket)、McpServer、Ota
抽象层 Board(板级单例)、AudioCodec、Display、Led 等虚基类
硬件层 ESP-IDF 驱动 + boards/<厂商>/ 具体板实现

四、关键逻辑

1. 入口与启动流程(main/application.cc:329 Start())

app_main 只做事件循环 / NVS 初始化,随后启动 Application 单例。Start() 顺序:

  1. 初始化显示;初始化并启动 AudioService(3 个任务);注册回调事件
  2. board.StartNetwork()(WiFi 连接,失败则进入 WiFi 配置 AP 模式,见 wifi_board.cc:71)
  3. CheckNewVersion(ota) ------ 阻塞直到完成版本检查:失败指数退避重试(最多 10 次);有新版本直接 OTA 升级;否则处理激活码 / 激活挑战(application.cc:70)
  4. 依据 OTA 服务器返回配置选择协议:HasMqttConfig() → MQTT,HasWebsocketConfig() → WebSocket,否则默认 MQTT
  5. protocol_->Start() → 进入 kDeviceStateIdle

2. 状态机(main/application.cc:641 SetDeviceState)

复制代码
Unknown → Starting → WifiConfiguring → Idle
Idle ←→ Listening ←→ Connecting ←(唤醒词/按键) Speaking
               ↘      Upgrading / Activating / AudioTesting / FatalError
  • 状态切换统一驱动:显示状态栏、表情、LED 变化(led->OnStateChanged())
  • 启停唤醒词检测 / 语音处理 :
    • Idle:开启唤醒词、关闭语音处理
    • Listening:打开 AFE 语音处理、关闭唤醒词,发送 start_listening
    • Speaking:视 AEC 模式而定(Realtime 模式保持监听,可被二次唤醒打断)

3. 事件驱动主循环(main/application.cc:547 MainEventLoop)

FreeRTOS EventGroup 驱动,事件位定义(application.h:20):

复制代码
MAIN_EVENT_SCHEDULE              (1<<0)  任务调度
MAIN_EVENT_SEND_AUDIO           (1<<1)  发送音频
MAIN_EVENT_WAKE_WORD_DETECTED   (1<<2)  唤醒词检测到
MAIN_EVENT_VAD_CHANGE           (1<<3)  VAD 状态变化
MAIN_EVENT_ERROR                (1<<4)  错误事件
MAIN_EVENT_CHECK_NEW_VERSION_DONE (1<<5)
  • Schedule() 为线程安全的异步任务入队机制 :回调统一进 main_tasks_ 队列,由主循环串行执行(application.cc:536)。协议 / 音频回调均通过它安全访问 UI 和连接状态。
  • 主循环优先级提到 3,避免被后台任务抢占。

4. 音频流水线(main/audio/audio_service.cc)------ 3 个任务

复制代码
上行: MIC →[AudioInputTask]→ Resampler→16k → AFE处理器(NS/AEC/VAD) → Encode队列
      →[OpusCodecTask → Opus编码(60ms/16k)] → Send队列 →[主循环 SendAudio]→ Server
下行: Server → Decode队列 →[OpusCodecTask 解码] → Playback队列
      →[AudioOutputTask]→ Resampler→codec采样率 → Speaker
  • AudioInputTask(核 1,优先级 8,仅启用 AFE 时):按事件位分支喂给「音频测试 / 唤醒词 / AFE 处理器」
  • AudioOutputTask(优先级 3):PCM 播出,记录时间戳供服务器端 AEC
  • OpusCodecTask(优先级 2):双向编解码,维护 4 个有界队列 + 条件变量
  • 关键参数(audio_service.h):OPUS_FRAME_DURATION_MS=60、上行 16kHz、MAX_DECODE/SEND_PACKETS_IN_QUEUE=40
  • 服务器端 AEC:播出的时间戳与上传数据对齐(PushTaskToEncodeQueue,audio_service.cc:408)
  • 节能:输入 / 输出静默 15s 自动关闭 codec(CheckAndUpdateAudioPowerState)

5. 协议层(策略模式,main/protocols/protocol.h)

抽象基类 Protocol 提供统一接口:

Start / OpenAudioChannel / CloseAudioChannel / SendAudio / SendWakeWordDetected / SendStartListening / SendAbortSpeaking / SendMcpMessage

握手流程:连接后互换 Hello 消息(type:"hello",含 transport、audio_params=16000Hz/1ch/60ms)。

  • MQTT+UDP(默认) :控制消息走 MQTT;服务器 Hello 下发 udp.server/port/key/nonce,音频用 AES-CTR 加密后走 UDP(mqtt_protocol.cc:135)
  • WebSocket :单通道。BinaryProtocol2(带时间戳,用于服务器 AEC)与 BinaryProtocol3 两种帧头;音频二进制帧 + JSON 文本帧复用同一连接

下行 JSON 分发(application.cc:405):

tts(start/stop/sentence_start)、stt、llm(emotion)、mcp、system(reboot)、alert、custom(需 CONFIG_RECEIVE_CUSTOM_MESSAGE)

6. Board 抽象(main/boards/common/board.h)

  • 单例工厂 + 多态:Board::GetInstance() 通过 create_board() 生成当前编译目标的板子(DECLARE_BOARD 宏)
  • 板子选型在 main/CMakeLists.txt 由 CONFIG_BOARD_TYPE_* 决定(当前 HiwonderExploit_S3),并把 boards/<type>/*.cc + boards/common/*.cc 加入编译
  • 基类提供:音频 codec、显示、网络、电池、温湿度 / 光照 / IMU / 超声波 / 点阵屏 / 串口舵机等可选能力(默认返回空实现 / false)

7. OTA(main/ota.cc)与设备激活

  • 启动即请求 CONFIG_OTA_URL(默认 https://api.tenclass.net/xiaozhi/ota/)
  • 服务器返回:MQTT/WebSocket 配置 + 新版本信息 + 激活信息(如有)
  • 有新版本 → esp_ota 下载 → 升级 → 重启;失败则恢复音频服务继续运行
  • 无新版但需激活 → 显示 / 播报激活码,等待用户激活(ShowActivationCode 逐个数字 TTS 播报)
  • PrintOtaConfig():启动时打印完整 OTA 配置(最近新增功能)

8. MCP 设备控制(main/mcp_server.h,单例)

  • 内嵌 JSON-RPC 2.0 风格 MCP Server
  • McpTool + Property(支持 bool/int/string,int 范围校验)+ PropertyList 生成 JSON Schema
  • 支持 tools/list(带 cursor 分页)、tools/call
  • 工具 Call() 在独立线程执行,避免阻塞音频链路
  • AddCommonTools() 注册通用能力;协议收到的 type=mcp 消息交给 ParseMessage

五、数据流小结

  • 音频上行:唤醒词触发 → 开音频通道 → 编码唤醒词并上传 → 进入 Listening → 语音处理(NS/AEC/VAD)→ Opus 编码 → 发送队列 → 协议上传
  • 音频下行:会话(Speaking)状态下接收服务器音频 → 解码队列 → Opus 解码 → 重采样 → 播放队列 → 扬声器
  • 控制命令:服务器 JSON → 协议回调 → Schedule 入队 → 主循环处理(切状态 / 显示 / 播放音效 / 设备控制)

六、构建与配置关键点

  • 顶层 CMakeLists.txt:set(PROJECT_VER "1.8.9"),project(AiXiaoZhi_Hiwonder)
  • sdkconfig.defaults:16MB 自定义分区表(partitions/v1/16m.csv)、LVGL 9.2.2 精简配置、MBEDTLS 动态缓冲等
  • main/Kconfig.projbuild:OTA_URL、LANGUAGE_*(当前 zh-CN)、BOARD_TYPE_*(当前 HiwonderExploit_S3)、USE_AFE_WAKE_WORD=y、USE_AUDIO_PROCESSOR=y、USE_DEVICE_AEC/SERVER_AEC(互斥)
  • 编译:idf.py set-target esp32s3 && idf.py build && idf.py flash && idf.py monitor

七、注意事项 / 观察

  • 项目自带 readme.md 既是使用说明也是架构文档,与源码基本一致
  • Initialize() 中 CONFIG_USE_DEVICE_AEC 与 CONFIG_USE_SERVER_AEC 同时开启会编译报错(#error,application.cc:40)
  • 唤醒词方案三选一:AFE / ESP-SR / Custom(由 Kconfig 决定,audio_service.cc 中按编译开关创建对应实例)
  • 主任务承担网络等待与版本检查,音频由独立高优先级任务保证实时性
相关推荐
半导体憨包8 小时前
共源共栅(Cascode)功率器件:让 SiC / GaN “兼容“你的硅栅驱动
嵌入式硬件·生成对抗网络·硬件工程·半导体·dc-dc·半导体芯片
2501_9226395811 小时前
率能半导体 SS6811H双通道H桥驱动芯片:38V/1.6A,覆盖舞台灯光、安防相机、办公自动化、游戏机、机器人五大应用场景
单片机·嵌入式硬件·硬件工程
恒锐丰科技林技术员13 小时前
EG2304L 高压半桥驱动芯片:中小功率电力电子方案优选器件
经验分享·嵌入式硬件·硬件工程
2501_9226395815 小时前
率能半导体 SS6812T双通道H桥驱动芯片:32V/1.0A,覆盖POS打印机、安防相机、办公自动化、游戏机、机器人五大应用场景
单片机·嵌入式硬件·硬件工程
2501_9226395816 小时前
率能半导体 SS6813H双通道H桥驱动芯片:40V/2.5A,覆盖POS打印机、安防相机、办公自动化、游戏机、机器人五大应用场景
单片机·嵌入式硬件·硬件工程
HQB20261 天前
EG1182|屹晶微电子 60V 内置高压管异步降压 DC‑DC
嵌入式硬件·硬件工程
HQB20261 天前
EG1163 (S)|屹晶微电子 600V 高压同步降压半桥控制器
嵌入式硬件·硬件工程
恒锐丰科技林技术员2 天前
EG2106L 高压半桥驱动芯片解析:高性价比 600V 栅极驱动方案
经验分享·嵌入式硬件·硬件工程
恒锐丰科技林技术员2 天前
大电流同步降压 DC‑DC 芯片 EG11732 解析
经验分享·嵌入式硬件·硬件工程