本文包含多个mermaid示意图,有助于理解音频系统的设计思路、数据流向和各个组件之间的交互关系,可点击链接酌情查看。
- 整体架构:从硬件层到应用层的完整音频处理链路
- 数据流:音频数据的输入、处理、输出完整流程
- 状态机:应用的状态转换逻辑
- 任务交互:各个音频任务之间的协作关系
- 唤醒词检测:不同唤醒词检测方案的实现流程
- 音频处理:AFE音频处理器的架构和处理流程
- 事件驱动:基于事件的状态更新机制
- 队列管理:音频数据队列的管理和同步
- 编解码流程:Opus编解码和重采样的处理流程
- 系统初始化:完整的系统启动和初始化流程
- 详细处理流程:音频数据的详细处理路径
- AFE内部流程:AFE音频处理器的内部工作机制
- 唤醒词检测流程:唤醒词检测函数调用流程
- 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模型进行推理判断
- 判断是否检测到预设的唤醒词
检测到唤醒词的处理流程:
- 数据存储:WakeWord存储检测到唤醒词时的音频数据
- 数据编码:将唤醒词音频编码为Opus格式
- 事件通知:通过回调通知AudioService检测到唤醒词
- Application处理:
- 调用OnWakeWordDetected()处理唤醒词事件
- 编码唤醒词音频数据
- 发送唤醒词检测消息给服务器
- 启用语音处理,禁用唤醒词检测
- 设置设备状态为监听状态
- 更新LED指示灯状态
- 音频数据发送:循环发送唤醒词音频数据包
关键函数调用:
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状态
检测到语音的处理流程:
- 状态设置:AudioProcessor设置is_speaking_=true
- 事件通知:通过回调通知AudioService VAD状态变化
- Application处理:
- 处理VAD状态变化事件
- 更新LED指示灯状态
- 更新显示界面
- 音频输出:输出经过AFE处理的音频数据
- 数据编码:将音频数据加入编码队列
检测到静音的处理流程:
- 状态设置:AudioProcessor设置is_speaking_=false
- 事件通知:通过回调通知AudioService VAD状态变化
- Application处理:
- 处理VAD状态变化事件
- 更新LED指示灯状态
- 更新显示界面
- 音频输出:输出经过AFE处理的音频数据
- 数据编码:将音频数据加入编码队列
编码和发送:
- OpusCodecTask处理编码队列中的音频数据
- 通知Application有数据可发送
- Application通过Protocol发送音频数据包
关键函数调用:
EnableVoiceProcessing(): 启用/禁用语音处理
Feed(): 喂入音频数据
on_vad_change(): VAD状态变化回调
OnStateChanged(): LED状态更新
PushTaskToEncodeQueue(): 将音频数据加入编码队列
SendAudio(): 发送音频数据包
技术特点:
- 实时VAD检测,响应速度快
- 通过回调机制实现异步事件通知
- 状态变化触发界面和LED更新
- 支持连续音频处理和数据发送