小智ESP32代码(4):音频处理

本文包含多个mermaid示意图,有助于理解音频系统的设计思路、数据流向和各个组件之间的交互关系,可点击链接酌情查看。

  1. 整体架构:从硬件层到应用层的完整音频处理链路
  2. 数据流:音频数据的输入、处理、输出完整流程
  3. 状态机:应用的状态转换逻辑
  4. 任务交互:各个音频任务之间的协作关系
  5. 唤醒词检测:不同唤醒词检测方案的实现流程
  6. 音频处理:AFE音频处理器的架构和处理流程
  7. 事件驱动:基于事件的状态更新机制
  8. 队列管理:音频数据队列的管理和同步
  9. 编解码流程:Opus编解码和重采样的处理流程
  10. 系统初始化:完整的系统启动和初始化流程
  11. 详细处理流程:音频数据的详细处理路径
  12. AFE内部流程:AFE音频处理器的内部工作机制
  13. 唤醒词检测流程:唤醒词检测函数调用流程
  14. VAD状态变化检测流程:VAD状态变化函数调用流程

1. 音频系统整体架构

graph TB subgraph "硬件层" MIC[麦克风] SPK[扬声器] CODEC[音频编解码器<br/>ES8311/ES8374/ES8388等] end subgraph "音频服务层" AS[AudioService<br/>音频服务管理器] AC[AudioCodec<br/>编解码器接口] AP[AudioProcessor<br/>音频处理器] WW[WakeWord<br/>唤醒词检测] end subgraph "应用层" APP[Application<br/>主应用程序] PROTO[Protocol<br/>通信协议] DISPLAY[Display<br/>显示界面] end subgraph "任务层" AIT[AudioInputTask<br/>音频输入任务] AOT[AudioOutputTask<br/>音频输出任务] OCT[OpusCodecTask<br/>编解码任务] ADT[AudioDetectionTask<br/>音频检测任务] APT[AudioProcessorTask<br/>音频处理任务] end MIC --> AC AC --> AS SPK --> AC AC --> AS AS --> AP AS --> WW AS --> AIT AS --> AOT AS --> OCT AP --> APT WW --> ADT AS --> APP APP --> PROTO APP --> DISPLAY style AS fill:#e1f5fe style APP fill:#f3e5f5 style AC fill:#e8f5e8 style AP fill:#fff3e0 style WW fill:#fce4ec

架构说明

这个架构图展示了小智ESP32音频系统的完整分层结构:

硬件层

  • 麦克风:负责音频输入,支持单声道或双声道(麦克风+参考通道)
  • 扬声器:负责音频输出播放
  • 音频编解码器:支持多种编解码器芯片(ES8311、ES8374、ES8388等),负责模拟音频与数字音频的转换

音频服务层

  • AudioService:整个音频系统的核心管理器,协调各个组件的工作
  • AudioCodec:提供统一的编解码器接口,屏蔽不同芯片的差异
  • AudioProcessor:负责音频信号处理,包括AEC(回声消除)、VAD(语音活动检测)、NS(噪声抑制)
  • WakeWord:唤醒词检测模块,支持多种检测方案

应用层

  • Application:主应用程序,管理设备状态和用户交互
  • Protocol:通信协议层,支持MQTT和WebSocket两种协议
  • Display:显示界面管理,提供用户反馈

任务层

  • AudioInputTask:音频输入任务,负责从麦克风读取音频数据
  • AudioOutputTask:音频输出任务,负责向扬声器输出音频
  • OpusCodecTask:编解码任务,负责Opus音频编解码
  • AudioDetectionTask:音频检测任务,负责唤醒词检测
  • AudioProcessorTask:音频处理任务,负责AFE音频处理

这种分层设计实现了关注点分离,每一层都有明确的职责,便于维护和扩展。

2. 音频数据流图

flowchart LR subgraph "输入流程" MIC[麦克风输入] RES_IN[重采样<br/>16kHz] ENC[Opus编码] SEND[发送队列] end subgraph "输出流程" RECV[接收队列] DEC[Opus解码] RES_OUT[重采样<br/>输出采样率] SPK[扬声器输出] end subgraph "处理流程" AFE[AFE音频处理<br/>AEC/VAD/NS] WW[唤醒词检测] VAD[语音活动检测] end MIC --> RES_IN RES_IN --> AFE AFE --> ENC ENC --> SEND RECV --> DEC DEC --> RES_OUT RES_OUT --> SPK AFE --> WW AFE --> VAD style AFE fill:#e1f5fe style WW fill:#fce4ec style VAD fill:#fff3e0

数据流说明

这个流程图展示了音频数据在系统中的完整流动路径:

输入流程

  • 麦克风输入:原始音频信号从麦克风采集
  • 重采样:将音频重采样到16kHz,统一处理采样率
  • Opus编码:将PCM音频数据压缩编码为Opus格式,减少传输带宽
  • 发送队列:编码后的音频数据进入发送队列,等待网络传输

输出流程

  • 接收队列:从网络接收到的音频数据包
  • Opus解码:将Opus格式的音频数据解码为PCM格式
  • 重采样:根据设备输出采样率进行重采样(如48kHz)
  • 扬声器输出:最终播放到扬声器

处理流程

  • AFE音频处理:ESP32的音频前端处理,包括:
    • AEC(回声消除):消除扬声器输出对麦克风输入的干扰
    • VAD(语音活动检测):检测是否有语音输入
    • NS(噪声抑制):抑制环境噪声
  • 唤醒词检测:实时检测预设的唤醒词
  • 语音活动检测:监控用户是否在说话

关键特点

  • 输入和输出采用不同的采样率,通过重采样进行适配
  • 使用Opus编解码器实现高效的音频压缩
  • AFE处理提供高质量的音频信号处理
  • 支持实时唤醒词检测和语音活动检测

3. 应用状态机

stateDiagram-v2 [*] --> Starting: 系统启动 Starting --> Configuring: 初始化完成 Configuring --> Idle: 配置完成 Idle --> Connecting: 用户交互/唤醒词 Connecting --> Listening: 连接成功 Listening --> Speaking: 收到TTS开始 Speaking --> Listening: TTS结束 Speaking --> Idle: 手动停止 Listening --> Idle: 停止监听 Connecting --> Idle: 连接失败 Idle --> Upgrading: 检测到新版本 Upgrading --> [*]: 升级完成重启 Idle --> Activating: 需要激活 Activating --> Idle: 激活完成 Idle --> AudioTesting: WiFi配置模式 AudioTesting --> Idle: 测试完成 Speaking --> Speaking: 唤醒词中断 Listening --> Speaking: 直接播放 note right of Idle 待机状态: - 唤醒词检测开启 - 语音处理关闭 - 显示待机界面 end note note right of Listening 监听状态: - 语音处理开启 - 唤醒词检测关闭 - VAD状态监控 end note note right of Speaking 播放状态: - 音频解码播放 - 根据模式决定 是否开启唤醒词 end note

状态机说明

这个状态机图展示了小智设备在不同工作状态之间的转换逻辑:

核心状态

  • Starting:系统启动状态,进行硬件初始化
  • Configuring:配置状态,加载配置文件和网络设置
  • Idle:待机状态,设备空闲,等待用户交互
  • Connecting:连接状态,正在建立与服务器的连接
  • Listening:监听状态,正在接收用户语音输入
  • Speaking:播放状态,正在播放TTS音频输出

特殊状态

  • Upgrading:升级状态,执行固件升级
  • Activating:激活状态,等待设备激活
  • AudioTesting:音频测试状态,用于WiFi配置模式下的音频测试

状态转换触发条件

  • 用户交互:按键、触摸等用户操作
  • 唤醒词检测:检测到预设的唤醒词
  • 网络事件:连接成功/失败、收到服务器消息
  • 系统事件:检测到新版本、需要激活等

状态特性

  • Idle状态:唤醒词检测开启,语音处理关闭,功耗较低
  • Listening状态:语音处理开启,唤醒词检测关闭,实时处理音频
  • Speaking状态:音频解码播放,根据AEC模式决定是否开启唤醒词检测

这种状态机设计确保了设备在不同工作模式下都能正确配置音频处理参数,实现高效的状态管理。

4. 音频服务任务交互

sequenceDiagram participant APP as Application participant AS as AudioService participant AIT as AudioInputTask participant AOT as AudioOutputTask participant OCT as OpusCodecTask participant AP as AudioProcessor participant WW as WakeWord Note over APP,WW: 系统启动阶段 APP->>AS: Initialize(codec) AS->>AP: Initialize(codec, frame_duration) AS->>WW: Initialize(codec) AS->>AIT: Start() AS->>AOT: Start() AS->>OCT: Start() Note over APP,WW: 待机状态 APP->>AS: EnableWakeWordDetection(true) AS->>WW: Start() loop 音频输入循环 AIT->>AS: ReadAudioData() AS->>WW: Feed(audio_data) WW-->>AS: WakeWordDetected() AS-->>APP: on_wake_word_detected() end Note over APP,WW: 监听状态 APP->>AS: EnableVoiceProcessing(true) AS->>AP: Start() loop 语音处理循环 AIT->>AS: ReadAudioData() AS->>AP: Feed(audio_data) AP->>OCT: PushTaskToEncodeQueue() OCT->>AS: PushPacketToSendQueue() AS-->>APP: on_send_queue_available() end Note over APP,WW: 播放状态 APP->>AS: PushPacketToDecodeQueue() loop 音频输出循环 OCT->>AS: PopPacketFromDecodeQueue() OCT->>AOT: PushTaskToPlaybackQueue() AOT->>AS: OutputData() end

任务交互说明

这个时序图展示了音频系统中各个任务之间的协作关系:

系统启动阶段

  • Application初始化AudioService,传入音频编解码器
  • AudioService依次初始化音频处理器、唤醒词检测器
  • 启动三个核心任务:音频输入任务、音频输出任务、编解码任务

待机状态

  • 启用唤醒词检测功能
  • 音频输入任务持续从麦克风读取音频数据
  • 将音频数据喂给唤醒词检测器
  • 检测到唤醒词时,通过回调通知Application

监听状态

  • 启用语音处理功能
  • 音频输入任务读取音频数据
  • 音频处理器进行AFE处理(AEC、VAD、NS)
  • 处理后的音频数据进入编码队列
  • 编解码任务将PCM数据编码为Opus格式
  • 编码后的数据进入发送队列
  • 通知Application有数据可发送

播放状态

  • Application将接收到的音频数据推入解码队列
  • 编解码任务从解码队列取出数据并解码
  • 解码后的PCM数据进入播放队列
  • 音频输出任务从播放队列取出数据并播放

关键特点

  • 采用多任务并发设计,提高系统响应性
  • 使用队列机制实现任务间的解耦
  • 通过回调机制实现异步事件通知
  • 不同状态下启用不同的音频处理模块,优化资源使用

5. 唤醒词检测流程

flowchart TD subgraph "AFE唤醒词检测" AFE_INIT[初始化AFE<br/>加载模型] AFE_FEED[音频数据输入] AFE_PROC[AFE处理<br/>特征提取] AFE_DET[唤醒词检测] AFE_RES[检测结果] end subgraph "ESP唤醒词检测" ESP_INIT[初始化Wakenet<br/>加载模型] ESP_FEED[音频数据输入] ESP_PROC[Wakenet处理] ESP_DET[唤醒词检测] ESP_RES[检测结果] end subgraph "自定义唤醒词检测" CUST_INIT[初始化Multinet<br/>加载模型] CUST_FEED[音频数据输入] CUST_PROC[Multinet处理] CUST_DET[命令词检测] CUST_RES[检测结果] end subgraph "通用流程" START[开始检测] STORE[存储唤醒词数据] ENCODE[编码唤醒词数据] CALLBACK[触发回调] STATE[状态转换] end START --> AFE_INIT START --> ESP_INIT START --> CUST_INIT AFE_INIT --> AFE_FEED AFE_FEED --> AFE_PROC AFE_PROC --> AFE_DET AFE_DET --> AFE_RES ESP_INIT --> ESP_FEED ESP_FEED --> ESP_PROC ESP_PROC --> ESP_DET ESP_DET --> ESP_RES CUST_INIT --> CUST_FEED CUST_FEED --> CUST_PROC CUST_PROC --> CUST_DET CUST_DET --> CUST_RES AFE_RES --> STORE ESP_RES --> STORE CUST_RES --> STORE STORE --> ENCODE ENCODE --> CALLBACK CALLBACK --> STATE style AFE_INIT fill:#e1f5fe style ESP_INIT fill:#fce4ec style CUST_INIT fill:#fff3e0 style STORE fill:#e8f5e8

唤醒词检测说明

这个流程图展示了小智系统支持的三种唤醒词检测方案:

AFE唤醒词检测

  • 初始化AFE:加载ESP-SR模型,配置AFE音频前端
  • 音频数据输入:从麦克风获取音频数据
  • AFE处理:进行音频特征提取和预处理
  • 唤醒词检测:使用WakeNet模型进行唤醒词识别
  • 检测结果:输出检测到的唤醒词类型

ESP唤醒词检测

  • 初始化Wakenet:直接加载WakeNet模型
  • 音频数据输入:获取音频数据
  • Wakenet处理:使用WakeNet进行特征提取和识别
  • 唤醒词检测:识别预设的唤醒词
  • 检测结果:返回检测结果

自定义唤醒词检测

  • 初始化Multinet:加载MultiNet模型
  • 音频数据输入:获取音频数据
  • Multinet处理:使用MultiNet进行命令词识别
  • 命令词检测:识别自定义的命令词
  • 检测结果:返回检测到的命令词

通用流程

  • 开始检测:根据配置选择检测方案
  • 存储唤醒词数据:保存检测到唤醒词时的音频数据
  • 编码唤醒词数据:将音频数据编码为Opus格式
  • 触发回调:通知Application检测到唤醒词
  • 状态转换:切换到监听状态

技术特点

  • 支持多种检测方案,适应不同应用场景
  • AFE方案提供更好的音频预处理效果
  • ESP方案更轻量级,适合资源受限场景
  • 自定义方案支持用户定义的命令词
  • 检测到唤醒词后保存音频数据,便于后续处理

6. 音频处理器架构

graph TB subgraph "AFE音频处理器" AFE_CONFIG[AFE配置<br/>AEC/VAD/NS] AFE_FEED[音频数据输入] AFE_PROC[AFE处理] AFE_OUT[处理输出] AFE_VAD[VAD状态] end subgraph "无音频处理器" NO_PROC[直通处理] NO_OUT[原始输出] end subgraph "处理流程" INPUT[音频输入] BUFFER[输出缓冲] FRAME[帧分割] CALLBACK[输出回调] end INPUT --> AFE_CONFIG AFE_CONFIG --> AFE_FEED AFE_FEED --> AFE_PROC AFE_PROC --> AFE_OUT AFE_PROC --> AFE_VAD AFE_OUT --> BUFFER BUFFER --> FRAME FRAME --> CALLBACK INPUT --> NO_PROC NO_PROC --> NO_OUT NO_OUT --> CALLBACK style AFE_CONFIG fill:#e1f5fe style AFE_PROC fill:#fce4ec style BUFFER fill:#fff3e0 style CALLBACK fill:#e8f5e8

音频处理器说明

这个架构图展示了音频处理器的两种工作模式:

AFE音频处理器模式

  • AFE配置:配置音频前端参数,包括:
    • AEC(回声消除):消除扬声器输出对麦克风的干扰
    • VAD(语音活动检测):检测是否有语音输入
    • NS(噪声抑制):抑制环境噪声
  • 音频数据输入:接收来自麦克风的音频数据
  • AFE处理:ESP32的音频前端进行实时信号处理
  • 处理输出:输出经过处理的音频数据
  • VAD状态:输出语音活动检测状态

无音频处理器模式

  • 直通处理:音频数据不经过任何处理
  • 原始输出:直接输出原始音频数据

处理流程

  • 音频输入:从音频编解码器获取音频数据
  • 输出缓冲:缓存处理后的音频数据
  • 帧分割:将音频数据分割成固定长度的帧
  • 输出回调:通过回调函数输出处理后的音频帧

技术特点

  • 支持AFE处理和直通处理两种模式
  • AFE处理提供高质量的音频信号处理
  • 支持实时VAD状态检测
  • 使用缓冲机制确保音频数据的连续性
  • 通过回调机制实现异步音频输出

应用场景

  • AFE模式:用于需要高质量音频处理的场景,如语音交互
  • 直通模式:用于简单的音频传输场景,如音频测试

7. 事件驱动机制

flowchart LR subgraph "事件源" WW_EVENT[唤醒词检测事件] VAD_EVENT[VAD状态变化事件] SEND_EVENT[发送队列可用事件] ERROR_EVENT[错误事件] SCHEDULE_EVENT[调度事件] end subgraph "事件处理" EVENT_GROUP[事件组<br/>xEventGroup] MAIN_LOOP[主事件循环] CALLBACK[回调处理] end subgraph "状态更新" STATE_CHANGE[状态转换] UI_UPDATE[界面更新] AUDIO_CTRL[音频控制] end WW_EVENT --> EVENT_GROUP VAD_EVENT --> EVENT_GROUP SEND_EVENT --> EVENT_GROUP ERROR_EVENT --> EVENT_GROUP SCHEDULE_EVENT --> EVENT_GROUP EVENT_GROUP --> MAIN_LOOP MAIN_LOOP --> CALLBACK CALLBACK --> STATE_CHANGE STATE_CHANGE --> UI_UPDATE STATE_CHANGE --> AUDIO_CTRL style EVENT_GROUP fill:#e1f5fe style MAIN_LOOP fill:#fce4ec style STATE_CHANGE fill:#fff3e0

事件驱动机制说明

这个流程图展示了小智系统的事件驱动架构:

事件源

  • 唤醒词检测事件:检测到预设的唤醒词时触发
  • VAD状态变化事件:语音活动检测状态发生变化时触发
  • 发送队列可用事件:音频发送队列有数据可发送时触发
  • 错误事件:系统发生错误时触发
  • 调度事件:需要执行异步任务时触发

事件处理

  • 事件组:使用FreeRTOS的xEventGroup管理事件位
  • 主事件循环:Application的主事件循环,等待事件发生
  • 回调处理:根据事件类型执行相应的回调函数

状态更新

  • 状态转换:根据事件更新设备状态
  • 界面更新:更新显示界面,提供用户反馈
  • 音频控制:控制音频处理模块的启用/禁用

工作机制

  • 各个模块通过设置事件位来通知主事件循环
  • 主事件循环通过xEventGroupWaitBits等待事件
  • 事件发生后,执行相应的回调函数
  • 回调函数更新系统状态和界面

技术特点

  • 采用事件驱动架构,提高系统响应性
  • 使用FreeRTOS事件组实现高效的事件管理
  • 支持多种事件类型,满足不同应用需求
  • 通过回调机制实现模块间的解耦

8. 音频队列管理

flowchart TD subgraph "编码队列" ENCODE_QUEUE[编码任务队列] ENCODE_MUTEX[队列互斥锁] ENCODE_CV[条件变量] end subgraph "解码队列" DECODE_QUEUE[解码包队列] DECODE_MUTEX[队列互斥锁] DECODE_CV[条件变量] end subgraph "播放队列" PLAYBACK_QUEUE[播放任务队列] PLAYBACK_MUTEX[队列互斥锁] PLAYBACK_CV[条件变量] end subgraph "发送队列" SEND_QUEUE[发送包队列] SEND_MUTEX[队列互斥锁] end subgraph "任务处理" INPUT_TASK[音频输入任务] OUTPUT_TASK[音频输出任务] CODEC_TASK[编解码任务] end INPUT_TASK --> ENCODE_QUEUE ENCODE_QUEUE --> CODEC_TASK CODEC_TASK --> SEND_QUEUE DECODE_QUEUE --> CODEC_TASK CODEC_TASK --> PLAYBACK_QUEUE PLAYBACK_QUEUE --> OUTPUT_TASK ENCODE_MUTEX -.-> ENCODE_QUEUE DECODE_MUTEX -.-> DECODE_QUEUE PLAYBACK_MUTEX -.-> PLAYBACK_QUEUE SEND_MUTEX -.-> SEND_QUEUE style ENCODE_QUEUE fill:#e1f5fe style DECODE_QUEUE fill:#fce4ec style PLAYBACK_QUEUE fill:#fff3e0 style SEND_QUEUE fill:#e8f5e8

音频队列管理说明

这个流程图展示了音频系统中队列的管理机制:

队列类型

  • 编码队列:存储待编码的PCM音频数据任务
  • 解码队列:存储待解码的Opus音频数据包
  • 播放队列:存储待播放的PCM音频数据任务
  • 发送队列:存储待发送的Opus音频数据包

同步机制

  • 队列互斥锁:保护队列的并发访问,防止数据竞争
  • 条件变量:实现生产者-消费者模式,当队列为空时阻塞消费者

数据流向

  • 输入流程:音频输入任务 → 编码队列 → 编解码任务 → 发送队列
  • 输出流程:解码队列 → 编解码任务 → 播放队列 → 音频输出任务

任务处理

  • 音频输入任务:从麦克风读取音频数据,推入编码队列
  • 音频输出任务:从播放队列取出数据,输出到扬声器
  • 编解码任务:处理编码队列和解码队列中的数据

技术特点

  • 使用互斥锁保护队列的线程安全
  • 使用条件变量实现高效的等待机制
  • 支持多生产者-多消费者模式
  • 队列大小有限制,防止内存溢出
  • 通过队列实现任务间的解耦

应用场景

  • 编码队列:缓存音频输入数据,等待编码处理
  • 解码队列:缓存网络接收的音频数据,等待解码
  • 播放队列:缓存解码后的音频数据,等待播放
  • 发送队列:缓存编码后的音频数据,等待网络发送

9. 音频编解码流程

flowchart LR subgraph "编码流程" PCM_IN[PCM音频数据] OPUS_ENC[Opus编码器] OPUS_PKT[Opus数据包] SEND_PKT[发送包] end subgraph "解码流程" RECV_PKT[接收包] OPUS_PKT_IN[Opus数据包] OPUS_DEC[Opus解码器] PCM_OUT[PCM音频数据] end subgraph "重采样" RES_IN[输入重采样<br/>16kHz] RES_OUT[输出重采样<br/>设备采样率] end PCM_IN --> RES_IN RES_IN --> OPUS_ENC OPUS_ENC --> OPUS_PKT OPUS_PKT --> SEND_PKT RECV_PKT --> OPUS_PKT_IN OPUS_PKT_IN --> OPUS_DEC OPUS_DEC --> PCM_OUT PCM_OUT --> RES_OUT style OPUS_ENC fill:#e1f5fe style OPUS_DEC fill:#fce4ec style RES_IN fill:#fff3e0 style RES_OUT fill:#e8f5e8

音频编解码说明

这个流程图展示了音频编解码的完整流程:

编码流程

  • PCM音频数据:从麦克风获取的原始PCM格式音频数据
  • 输入重采样:将音频重采样到16kHz,统一处理采样率
  • Opus编码器:使用Opus编解码器将PCM数据压缩编码
  • Opus数据包:编码后的Opus格式音频数据包
  • 发送包:准备发送到服务器的音频数据包

解码流程

  • 接收包:从网络接收到的音频数据包
  • Opus数据包:提取Opus格式的音频数据
  • Opus解码器:使用Opus解码器将数据解码为PCM格式
  • PCM音频数据:解码后的PCM格式音频数据
  • 输出重采样:根据设备输出采样率进行重采样

重采样处理

  • 输入重采样:将不同采样率的输入音频统一到16kHz
  • 输出重采样:将16kHz的音频重采样到设备输出采样率(如48kHz)

技术特点

  • 使用Opus编解码器实现高效的音频压缩
  • 支持多种采样率的自适应处理
  • 编码和解码过程对称,确保音频质量
  • 重采样确保音频数据的兼容性

性能优势

  • Opus编码提供高压缩比,减少网络带宽占用
  • 实时编解码,支持低延迟语音交互
  • 自适应比特率,根据网络条件调整质量
  • 支持多种音频格式和采样率

10. 系统初始化流程

flowchart TD START[系统启动] --> INIT_BOARD[初始化开发板] INIT_BOARD --> INIT_DISPLAY[初始化显示] INIT_DISPLAY --> INIT_AUDIO[初始化音频服务] INIT_AUDIO --> INIT_CODEC[初始化编解码器] INIT_CODEC --> INIT_OPUS[初始化Opus编解码器] INIT_OPUS --> INIT_PROCESSOR[初始化音频处理器] INIT_PROCESSOR --> INIT_WAKEWORD[初始化唤醒词] INIT_WAKEWORD --> START_TASKS[启动音频任务] START_TASKS --> START_NETWORK[启动网络] START_NETWORK --> CHECK_VERSION[检查版本更新] CHECK_VERSION --> HAS_UPDATE{有新版本?} HAS_UPDATE -->|是| UPGRADE[执行升级] HAS_UPDATE -->|否| INIT_PROTOCOL[初始化通信协议] UPGRADE --> REBOOT[重启系统] INIT_PROTOCOL --> SET_IDLE[设置为待机状态] SET_IDLE --> ENABLE_WW[启用唤醒词检测] ENABLE_WW --> READY[系统就绪] style INIT_AUDIO fill:#e1f5fe style INIT_WAKEWORD fill:#fce4ec style INIT_PROTOCOL fill:#fff3e0 style READY fill:#e8f5e8

系统初始化说明

这个流程图展示了小智系统的完整启动和初始化流程:

硬件初始化阶段

  • 系统启动:ESP32芯片上电启动
  • 初始化开发板:初始化GPIO、I2C、SPI等硬件接口
  • 初始化显示:初始化显示屏,显示启动界面

音频系统初始化

  • 初始化音频服务:创建AudioService实例
  • 初始化编解码器:配置音频编解码器芯片
  • 初始化Opus编解码器:创建Opus编码器和解码器
  • 初始化音频处理器:配置AFE音频处理器
  • 初始化唤醒词:加载唤醒词检测模型

系统服务启动

  • 启动音频任务:创建音频输入、输出、编解码任务
  • 启动网络:初始化WiFi连接
  • 检查版本更新:连接服务器检查固件版本

版本管理

  • 有新版本:如果检测到新版本,执行OTA升级
  • 执行升级:下载并安装新固件
  • 重启系统:升级完成后重启设备

系统就绪

  • 初始化通信协议:根据配置初始化MQTT或WebSocket协议
  • 设置为待机状态:将设备设置为空闲状态
  • 启用唤醒词检测:启动唤醒词检测功能
  • 系统就绪:设备完全启动,等待用户交互

技术特点

  • 采用分阶段初始化,确保各模块正确启动
  • 支持OTA升级,便于固件更新
  • 错误处理机制,确保系统稳定性
  • 状态管理,确保设备处于正确的工作状态

11. 详细音频处理流程

flowchart TD A[麦克风输入] --> B[AudioCodec读取] B --> C{输入通道数?} C -->|单声道| D[重采样到16kHz] C -->|双声道| E[分离麦克风和参考通道] E --> F[麦克风通道重采样] E --> G[参考通道重采样] F --> H[合并为双声道数据] G --> H D --> I[音频数据预处理] H --> I I --> J{当前运行模式?} J -->|音频测试模式| K[编码到测试队列] J -->|唤醒词检测模式| L[唤醒词检测] J -->|语音处理模式| M[AFE音频处理器] L --> N{检测到唤醒词?} N -->|是| O[触发唤醒词回调] N -->|否| P[继续检测] O --> Q[存储唤醒词音频] Q --> R[编码唤醒词数据] M --> S[AFE处理] S --> T[VAD状态检测] T --> U{检测到语音?} U -->|是| V[触发VAD回调] U -->|否| W[静音处理] V --> X[启用AEC处理] X --> Y[输出处理后的音频] Y --> Z[编码到发送队列] K --> AA[测试队列管理] Z --> BB[发送队列管理] R --> CC[唤醒词队列管理] BB --> DD[触发发送队列可用回调] DD --> EE[Application处理] EE --> FF[Protocol发送] style A fill:#e1f5fe style O fill:#c8e6c9 style V fill:#c8e6c9 style DD fill:#fff3e0 style FF fill:#f3e5f5

详细音频处理说明

这个流程图展示了音频数据的详细处理路径:

音频输入处理

  • 麦克风输入:从麦克风获取原始音频信号
  • AudioCodec读取:通过音频编解码器读取数字音频数据
  • 通道数判断:根据设备配置判断是单声道还是双声道

通道处理

  • 单声道处理:直接重采样到16kHz
  • 双声道处理
    • 分离麦克风通道和参考通道
    • 分别对两个通道进行重采样
    • 合并为双声道数据用于AEC处理

运行模式判断

  • 音频测试模式:用于WiFi配置时的音频测试
  • 唤醒词检测模式:设备空闲时的唤醒词监听
  • 语音处理模式:正常语音交互时的音频处理

唤醒词检测流程

  • 唤醒词检测:使用AI模型检测预设唤醒词
  • 检测结果判断:判断是否检测到唤醒词
  • 触发回调:检测到唤醒词时通知Application
  • 存储音频:保存检测到唤醒词时的音频数据
  • 编码数据:将唤醒词音频编码为Opus格式

语音处理流程

  • AFE处理:ESP32音频前端进行信号处理
  • VAD状态检测:检测是否有语音活动
  • 语音检测判断:判断是否检测到语音
  • 触发VAD回调:语音状态变化时通知Application
  • AEC处理:启用回声消除处理
  • 输出处理:输出经过处理的音频数据
  • 编码发送:将音频编码并加入发送队列

队列管理

  • 测试队列:管理音频测试数据
  • 发送队列:管理待发送的音频数据
  • 唤醒词队列:管理唤醒词音频数据

网络发送

  • 触发回调:发送队列有数据时通知Application
  • Application处理:Application处理发送事件
  • Protocol发送:通过通信协议发送音频数据

技术特点

  • 支持单声道和双声道音频处理
  • 多种运行模式适应不同应用场景
  • 实时唤醒词检测和语音活动检测
  • 完整的音频处理链路,从输入到网络发送

12. AFE音频处理器内部流程

flowchart TD A[AFE音频处理器] --> B[初始化AFE接口] B --> C[配置音频参数] C --> D[启动处理任务] D --> E[接收音频数据] E --> F[AFE前端处理] F --> G[噪声抑制] G --> H[回声消除AEC] H --> I[波束形成] I --> J[VAD语音活动检测] J --> K{检测到语音?} K -->|是| L[设置speaking=true] K -->|否| M[设置speaking=false] L --> N[触发VAD状态变化回调] M --> N N --> O[输出处理后的音频] O --> P[触发音频输出回调] style A fill:#e3f2fd style J fill:#fff8e1 style N fill:#e8f5e8 style P fill:#f3e5f5

AFE音频处理器说明

这个流程图展示了ESP32 AFE(Audio Front End)音频处理器的内部工作机制:

初始化阶段

  • AFE音频处理器:ESP32的音频前端处理模块
  • 初始化AFE接口:创建和配置AFE接口
  • 配置音频参数:设置采样率、通道数、处理模式等参数
  • 启动处理任务:创建AFE处理任务,开始音频处理

音频处理流程

  • 接收音频数据:从音频输入任务接收音频数据
  • AFE前端处理:ESP32音频前端进行基础信号处理
  • 噪声抑制:使用NS(Noise Suppression)算法抑制环境噪声
  • 回声消除AEC:使用AEC(Acoustic Echo Cancellation)算法消除回声
  • 波束形成:如果支持多麦克风,进行波束形成处理
  • VAD语音活动检测:检测音频中是否包含语音

状态管理

  • 检测到语音判断:根据VAD结果判断是否有语音
  • 设置speaking状态
    • 检测到语音时设置speaking=true
    • 未检测到语音时设置speaking=false
  • 触发VAD状态变化回调:语音状态变化时通知Application

输出处理

  • 输出处理后的音频:输出经过AFE处理的音频数据
  • 触发音频输出回调:通过回调函数将音频数据传递给后续处理

技术特点

  • 使用ESP32专用的AFE硬件加速器
  • 支持多种音频处理算法(NS、AEC、VAD)
  • 实时处理,低延迟响应
  • 硬件加速,降低CPU占用
  • 支持多种音频配置和参数调整

应用优势

  • 提供高质量的音频信号处理
  • 有效抑制环境噪声和回声
  • 实时语音活动检测
  • 硬件加速,提高处理效率

13. 唤醒词检测函数调用流程

sequenceDiagram participant AIT as AudioInputTask participant AS as AudioService participant WW as WakeWord participant APP as Application participant PROTO as Protocol participant LED as LED指示灯 Note over AIT,LED: 唤醒词检测启动 APP->>AS: EnableWakeWordDetection(true) AS->>WW: Initialize(codec) AS->>WW: Start() AS->>AIT: 启动音频输入任务 Note over AIT,LED: 音频数据循环 loop 音频输入循环 AIT->>AS: ReadAudioData() AS->>WW: Feed(audio_data) Note over WW: 唤醒词检测处理 WW->>WW: 音频特征提取 WW->>WW: AI模型推理 WW->>WW: 检测结果判断 alt 检测到唤醒词 WW->>WW: StoreWakeWordData() WW->>WW: EncodeWakeWordData() WW-->>AS: WakeWordDetected(wake_word) AS-->>APP: on_wake_word_detected(wake_word) Note over APP: Application处理唤醒词事件 APP->>APP: OnWakeWordDetected() APP->>AS: EncodeWakeWord() APP->>PROTO: SendWakeWordDetected(wake_word) APP->>AS: EnableVoiceProcessing(true) APP->>AS: EnableWakeWordDetection(false) APP->>APP: SetDeviceState(kDeviceStateListening) APP->>LED: OnStateChanged() Note over AS: 发送唤醒词音频数据 loop 发送唤醒词音频 AS->>AS: PopWakeWordPacket() AS-->>APP: on_send_queue_available() APP->>PROTO: SendAudio(wake_word_packet) end end end

唤醒词检测函数调用说明

这个时序图展示了从音频输入到唤醒词检测的完整函数调用流程:

初始化阶段

  • Application调用AudioService的EnableWakeWordDetection(true)
  • AudioService初始化WakeWord对象并启动
  • 启动AudioInputTask开始音频数据采集

音频数据循环

  • AudioInputTask持续调用ReadAudioData()获取音频数据
  • AudioService将音频数据喂给WakeWord进行检测

唤醒词检测处理

  • WakeWord内部进行音频特征提取
  • 使用AI模型进行推理判断
  • 判断是否检测到预设的唤醒词

检测到唤醒词的处理流程

  1. 数据存储:WakeWord存储检测到唤醒词时的音频数据
  2. 数据编码:将唤醒词音频编码为Opus格式
  3. 事件通知:通过回调通知AudioService检测到唤醒词
  4. Application处理
    • 调用OnWakeWordDetected()处理唤醒词事件
    • 编码唤醒词音频数据
    • 发送唤醒词检测消息给服务器
    • 启用语音处理,禁用唤醒词检测
    • 设置设备状态为监听状态
    • 更新LED指示灯状态
  5. 音频数据发送:循环发送唤醒词音频数据包

关键函数调用

  • EnableWakeWordDetection(): 启用/禁用唤醒词检测
  • Feed(): 喂入音频数据
  • WakeWordDetected(): 唤醒词检测回调
  • OnWakeWordDetected(): Application处理唤醒词事件
  • SendWakeWordDetected(): 发送唤醒词检测消息
  • SetDeviceState(): 设置设备状态

14. VAD状态变化函数调用流程

sequenceDiagram participant AIT as AudioInputTask participant AS as AudioService participant AP as AudioProcessor participant APP as Application participant LED as LED指示灯 participant DISPLAY as Display Note over AIT,DISPLAY: 语音处理启动 APP->>AS: EnableVoiceProcessing(true) AS->>AP: Initialize(codec, frame_duration) AS->>AP: Start() AS->>AIT: 启动音频输入任务 Note over AIT,DISPLAY: 音频处理循环 loop 音频处理循环 AIT->>AS: ReadAudioData() AS->>AP: Feed(audio_data) Note over AP: AFE音频处理 AP->>AP: AFE前端处理 AP->>AP: 噪声抑制(NS) AP->>AP: 回声消除(AEC) AP->>AP: VAD语音活动检测 Note over AP: VAD状态判断 AP->>AP: 检测语音活动状态 alt 检测到语音 (speaking=true) AP->>AP: 设置is_speaking_=true AP-->>AS: on_vad_change(true) AS-->>APP: on_vad_change(true) Note over APP: Application处理VAD事件 APP->>APP: 处理VAD状态变化事件 APP->>LED: OnStateChanged() APP->>DISPLAY: 更新界面显示 Note over AP: 输出处理后的音频 AP->>AS: 输出处理后的音频数据 AS->>AS: PushTaskToEncodeQueue() else 检测到静音 (speaking=false) AP->>AP: 设置is_speaking_=false AP-->>AS: on_vad_change(false) AS-->>APP: on_vad_change(false) Note over APP: Application处理VAD事件 APP->>APP: 处理VAD状态变化事件 APP->>LED: OnStateChanged() APP->>DISPLAY: 更新界面显示 Note over AP: 输出处理后的音频 AP->>AS: 输出处理后的音频数据 AS->>AS: PushTaskToEncodeQueue() end end Note over AIT,DISPLAY: 编码和发送 AS->>AS: OpusCodecTask处理 AS-->>APP: on_send_queue_available() APP->>PROTO: SendAudio(audio_packet)

VAD状态变化函数调用说明

这个时序图展示了VAD(语音活动检测)状态变化的完整函数调用流程:

初始化阶段

  • Application调用AudioService的EnableVoiceProcessing(true)
  • AudioService初始化AudioProcessor并启动
  • 启动AudioInputTask开始音频数据采集

音频处理循环

  • AudioInputTask持续调用ReadAudioData()获取音频数据
  • AudioService将音频数据喂给AudioProcessor进行AFE处理

AFE音频处理

  • AudioProcessor进行AFE前端处理
  • 执行噪声抑制(NS)算法
  • 执行回声消除(AEC)算法
  • 进行VAD语音活动检测

VAD状态判断

  • AudioProcessor根据VAD结果判断当前是否有语音活动
  • 根据检测结果设置speaking状态

检测到语音的处理流程

  1. 状态设置:AudioProcessor设置is_speaking_=true
  2. 事件通知:通过回调通知AudioService VAD状态变化
  3. Application处理
    • 处理VAD状态变化事件
    • 更新LED指示灯状态
    • 更新显示界面
  4. 音频输出:输出经过AFE处理的音频数据
  5. 数据编码:将音频数据加入编码队列

检测到静音的处理流程

  1. 状态设置:AudioProcessor设置is_speaking_=false
  2. 事件通知:通过回调通知AudioService VAD状态变化
  3. Application处理
    • 处理VAD状态变化事件
    • 更新LED指示灯状态
    • 更新显示界面
  4. 音频输出:输出经过AFE处理的音频数据
  5. 数据编码:将音频数据加入编码队列

编码和发送

  • OpusCodecTask处理编码队列中的音频数据
  • 通知Application有数据可发送
  • Application通过Protocol发送音频数据包

关键函数调用

  • EnableVoiceProcessing(): 启用/禁用语音处理
  • Feed(): 喂入音频数据
  • on_vad_change(): VAD状态变化回调
  • OnStateChanged(): LED状态更新
  • PushTaskToEncodeQueue(): 将音频数据加入编码队列
  • SendAudio(): 发送音频数据包

技术特点

  • 实时VAD检测,响应速度快
  • 通过回调机制实现异步事件通知
  • 状态变化触发界面和LED更新
  • 支持连续音频处理和数据发送
posted @ 2025-08-29 16:37  icuic  阅读(196)  评论(0)    收藏  举报