小智ESP32代码(2):系统任务
小智AI客户端的代码中存在以下这些task:
任务名称 | 入口函数 | 主要功能 | 优先级 | 栈大小 |
---|---|---|---|---|
系统核心调度任务 | Application::MainEventLoop() | 系统核心调度任务 | 3 | - |
audio_input | AudioService::AudioInputTask() | 音频输入处理 | 8 | 6144B/4096B |
audio_output | AudioService::AudioOutputTask() | 音频输出处理 | 3 | 4096B/2048B |
opus_codec | AudioService::OpusCodecTask() | 音频编解码 | 2 | 26624B |
audio_communication | AfeAudioProcessor::AudioProcessorTask() | AFE 音频处理 | 3 | 4096B |
audio_detection | AfeWakeWord::AudioDetectionTask() | 唤醒词检测 | 3 | 4096B |
encode_wake_word | Lambda 函数 | AFE 唤醒词编码 | 2 | 28672B |
接下来逐个任务看一下。
核心调度任务
作为系统核心调度任务,通过等待事件组中的事件(如唤醒词触发、VAD 状态变化、任务调度指令等),协调各模块(音频服务、网络协议、设备状态管理等)的交互。负责处理调度任务队列、响应唤醒词触发、管理设备状态切换(如从空闲到监听模式)等核心逻辑,是系统的 “中枢调度器”。
audio_input
该任务是音频上行链路(从麦克风到处理模块)的起点,负责高效采集并分发音频数据,确保唤醒词检测、语音处理等核心功能的实时性。
其核心功能是从音频编解码器(AudioCodec)读取原始 PCM 音频数据,并根据系统当前状态分发至不同处理模块,具体如下:
- 状态监听与任务循环
通过事件组(event_group_)等待并响应系统状态事件(如音频测试、唤醒词检测、音频处理等),在任务循环中持续处理音频输入,直至服务停止(service_stopped_ 为 true)。 - 数据分发
- 音频测试模式:当触发音频测试事件(AS_EVENT_AUDIO_TESTING_RUNNING)时,从麦克风读取 16kHz 单声道 PCM 数据,存入 audio_testing_queue_ 供测试使用(如通过按键触发的网络配置模式音频采集)。
- 唤醒词检测模式:当唤醒词检测事件(AS_EVENT_WAKE_WORD_RUNNING)激活时,按唤醒词引擎(WakeWord)要求的采样长度读取音频数据,并通过 wake_word_->Feed(data) 喂给唤醒词模型进行实时检测。
- 音频处理模式:当音频处理器事件(AS_EVENT_AUDIO_PROCESSOR_RUNNING)激活时,按音频处理器(AudioProcessor)要求的采样长度读取数据,通过 audio_processor_->Feed(std::move(data)) 传入处理器进行降噪(NS)、回声消除(AEC)、语音活动检测(VAD)等处理。
- 数据预处理与适配
若音频编解码器的输入采样率与目标采样率(16kHz)不符,会通过重采样器(input_resampler_)进行格式转换;若输入为双声道,会提取单声道数据(如麦克风通道)以适配后续处理模块的单声道需求。 - 通过 ReadAudioData 方法与 AudioCodec 交互,读取硬件麦克风的原始音频数据,并更新最后输入时间(last_input_time_)用于电源管理(如超时自动关闭音频输入以节能)。
audio_output
该任务是音频下行链路(从服务器到扬声器)的最后一环,负责将数字音频信号转换为可听声音,保障音频播放的连续性和实时性,具体如下:
- 以阻塞方式等待队列数据或服务停止信号。
- 数据获取
从音频播放队列 audio_playback_queue_ 中等待并获取解码后的 PCM 音频数据(该队列由 OpusCodecTask 解码完成后填充)。 - 硬件输出
将获取到的 PCM 数据发送到 AudioCodec(音频编解码器硬件抽象层),通过 I2S 接口传输到扬声器,实现音频播放。
opus_codec
其核心功能是同时处理音频的编码(将 PCM 转为 Opus 格式)和解码(将 Opus 转为 PCM 格式),其中,PCM 格式是模数转换后的原始数据格式,将其压缩为 Opus 格式后便于传输。此任务是连接音频输入 / 输出与网络传输的关键中间层,具体如下:
- 编码流程(上行链路:麦克风→服务器)
- 数据来源:从 audio_encode_queue_ 中获取待编码的 PCM 音频数据(来自 AudioInputTask 处理后的麦克风输入,包含语音活动检测(VAD)、回声消除(AEC)等预处理结果)。
- 编码逻辑:
通过 OpusEncoderWrapper 将 PCM 数据编码为 Opus 格式(低延迟、高压缩特性,适合语音流传输)。
根据任务类型(kAudioTaskTypeEncodeToSendQueue 或 kAudioTaskTypeEncodeToTestingQueue),将编码后的 Opus 数据包分别存入 audio_send_queue_(供应用层发送到服务器)或 audio_testing_queue_(用于本地音频测试)。 - 通知机制:当 audio_send_queue_ 中有数据时,通过回调 on_send_queue_available 通知应用层可读取并发送数据。
- 解码流程(下行链路:服务器→扬声器)
- 数据来源:从 audio_decode_queue_ 中获取待解码的 Opus 数据包(来自服务器通过网络发送的音频数据)。
- 解码逻辑:
通过 OpusDecoderWrapper 将 Opus 数据包解码为 PCM 格式,并根据音频编解码器(AudioCodec)的输出采样率进行重采样(通过 output_resampler_),确保与硬件播放格式匹配。
解码后的 PCM 数据存入 audio_playback_queue_,供 AudioOutputTask 读取并通过扬声器播放。 - 状态维护:解码过程中会更新时间戳队列(timestamp_queue_),用于回声消除(AEC)等同步处理。
- 任务循环与资源管理
以阻塞方式等待 audio_encode_queue_ 或 audio_decode_queue_ 中的数据,通过条件变量(audio_queue_cv_)实现高效唤醒,避免无效轮询。
严格控制队列长度(如 MAX_ENCODE_TASKS_IN_QUEUE、MAX_DECODE_PACKETS_IN_QUEUE),防止内存溢出,同时保证音频流的实时性。
当服务停止(service_stopped_)时,退出循环并释放资源。
audio_communication
其核心功能是基于 ESP 音频前端(AFE)框架对输入音频进行实时处理(如降噪、回声消除、语音活动检测等),并将处理后的音频数据分发给后续模块。
audio_detection
其核心功能是基于 AFE(音频前端)框架实时检测音频中的唤醒词,并在检测到唤醒词后触发回调通知,同时存储相关音频数据供后续处理。
encode_wake_word
其核心功能是将检测到唤醒词前后的原始 PCM 音频数据编码为 Opus 格式,以便后续发送至服务器进行处理或分析。
代码中使用了大量的回调函数,暂时知道各任务的大致功能就行了,目前不必深究细节。