语音唤醒组件
简介
ACOMP Wakeup 是 ARCS SDK 的语音唤醒组件,提供基于音频流的语音唤醒功能。该组件支持单麦克风和双麦克风唤醒算法,支持WAKUP/ESR模式,并提供灵活的唤醒门限配置和音频流管理接口。
主要特性
多麦克风支持:支持单麦克风和双麦克风唤醒算法
双模式运行:支持唤醒模式和 ESR 模式
灵活门限配置:提供 6 级唤醒门限等级,从极易唤醒到禁用唤醒
事件回调机制:支持唤醒结果、音频流更新、超时等多种事件通知
音频流管理:提供完整的音频流通道管理和缓冲区操作接口
状态管理:支持初始化、就绪、启动、停止等完整的生命周期管理
跨核通信:基于 IPC 机制实现音频流的跨核传输
组件架构
ACOMP Wakeup 组件采用双核异构架构,CP 核(应用核)通过 ACOMP IPC 框架与 AP 核(算法核)进行通信,实现语音唤醒功能。
┌─────────────────────────────────────────────────────────────────────┐
│ CP 核 (Application Core) │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ 用户应用层 │ │
│ │ ┌────────────────────────────────────────────────────────┐ │ │
│ │ │ • 唤醒事件回调处理 (关键词/角度/超时) │ │ │
│ │ │ • 音频数据采集 (麦克风/回采) │ │ │
│ │ │ • 算法输出音频处理 (回声消除后的音频) │ │ │
│ │ └────────────────────┬───────────────────────────────────┘ │ │
│ └───────────────────────┼──────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────▼──────────────────────────────────────┐ │
│ │ ACOMP Wakeup 组件 (CP 侧) │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ 生命周期管理 │ │ 事件回调管理 │ │ 参数配置接口 │ │ │
│ │ │ init/prepare │ │ add_callback │ │ set_mode/ │ │ │
│ │ │ start/stop │ │ remove_cb │ │ threshold │ │ │
│ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │
│ │ │ │ │ │ │
│ │ ┌──────▼─────────────────▼─────────────────▼───────┐ │ │
│ │ │ 音频流管理 (Stream API) │ │ │
│ │ │ • M2R 流: 音频输入 (mic+ref → 算法) │ │ │
│ │ │ • R2M 流: 算法输出 (回声消除后的音频 → 应用) │ │ │
│ │ │ • tx_alloc/submit, rx_get/release │ │ │
│ │ └──────────────────────┬───────────────────────────┘ │ │
│ └─────────────────────────┼───────────────────────────────────── │
│ │ │
│ ┌─────────────────────────▼─────────────────────────────────────┐ │
│ │ ACOMP IPC 层 (CP 侧) │ │
│ │ • IPC 消息封装 (NEW/FREE/CONTROL/NOTIFY) │ │
│ │ • 设备查询和管理 │ │
│ │ • 同步/异步命令处理 │ │
│ └─────────────────────────┬─────────────────────────────────────┘ │
└────────────────────────────┼────────────────────────────────────────┘
│
│ IC Message (IPC 消息通道)
│
┌────────────────────────────▼────────────────────────────────────────┐
│ AP 核 (Algorithm Core) │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ACOMP Framework (AP 侧) │ │
│ │ │ │
│ │ • 接收 CP 核的 IPC 命令 (prepare/start/stop/control) │ │
│ │ • 处理音频流数据 (M2R 接收 / R2M 发送) │ │
│ │ • 执行唤醒算法引擎 │ │
│ │ • 推送唤醒事件到 CP 核 (关键词/角度/超时) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 唤醒算法引擎 (Wakeup Engine) │ │
│ │ │ │
│ │ • 音频预处理 (降噪/回声消除) │ │
│ │ • 特征提取和关键词识别 │ │
│ │ • 角度估计 (DOA) │ │
│ │ • 支持单麦/双麦、Wakeup/ESR 模式 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────┐
│ 共享内存 (Shared Mem) │
│ ┌────────────────────┐ │
│ │ VirtQueue 环形缓冲 │ │
│ │ (Stream IPC 数据) │ │
│ └────────────────────┘ │
└─────────────────────────┘
架构说明
1. CP 核 (应用核) - 开放接口层
用户应用层: 处理唤醒事件,采集音频数据,处理算法输出
ACOMP Wakeup 组件: 提供生命周期管理、事件回调、参数配置等 API
音频流管理: 管理 M2R(Master to Remote) 和 R2M(Remote to Master) 数据流
ACOMP IPC 层: 封装 IPC 消息,与 AP 核通信
2. AP 核 (算法核) - 算法实现层
ACOMP Framework: 接收 IPC 命令,管理算法生命周期,处理音频流数据
唤醒算法引擎: 执行语音唤醒算法,支持单麦/双麦、Wakeup/ESR 模式
注意: AP 核的具体实现为闭源算法库,开发者只需关注 CP 核的 API 使用即可。
3. 通信机制
控制通道: 通过 IC Message 传递控制命令 (prepare/start/stop/control)
数据通道: 通过 VirtQueue 共享内存实现零拷贝音频流传输
事件通知: AP 核通过 NOTIFY 消息主动推送唤醒结果到 CP 核
4. 数据流向
M2R 流: CP 核采集的音频数据 (麦克风+回采) → AP 核算法引擎
R2M 流: AP 核算法输出 (回声消除后的音频) → CP 核应用层
事件流: AP 核唤醒结果/角度/超时事件 → CP 核回调函数
音频数据结构
输入音频数据结构
根据配置的算法类型,输入音频数据结构有所不同:
双麦克风模式 (CONFIG_ACOMP_WAKEUP_ALGORITHM_TYPE_DUAL_MIC=y):
typedef struct {
short mic0; /* mic0的音频 */
short mic1; /* mic1的音频 */
short ref0; /* 回采的音频 */
short ref1; /* 回采的音频,如只有一路回采,则可复制ref0的数据 */
} acomp_wakeup_audio_in_t;
单麦克风模式 (CONFIG_ACOMP_WAKEUP_ALGORITHM_TYPE_SINGLE_MIC=y):
typedef struct {
short mic0; /* mic0的音频 */
short ref0; /* 回采的音频 */
} acomp_wakeup_audio_in_t;
输出音频数据结构
算法处理后输出的音频数据为 5 通道格式:
typedef struct {
short mic0; /* mic0的音频 */
short mic1; /* mic1的音频,在单麦算法的情况下,mic1的音频实际为mic0的音频 */
short ref0; /* 回采的音频 */
short out1; /* 回声消除之后的音频 */
short out2; /* 算法输出的其他音频 */
} acomp_wakeup_audio_out_t;
音频帧大小定义
组件提供了一组宏定义用于计算音频帧大小:
输入音频帧信息:
宏定义 |
说明 |
值 |
|---|---|---|
|
单个输入音频采样点的字节数 |
|
|
每帧输入音频的采样点数量 |
256 |
|
单帧输入音频数据的总字节数 |
单麦: 1024 字节 |
|
一次完整识别需要输入的音频帧数量 |
10 |
输出音频帧信息:
宏定义 |
说明 |
值 |
|---|---|---|
|
输出音频每个采样点的通道数 |
5 |
|
单个输出音频采样点的字节数 |
10 字节 |
|
单次输出音频数据的最大字节数 |
25600 字节 |
配置选项
基本配置
配置项 |
说明 |
默认值 |
|---|---|---|
|
启用ACOMP组件 |
n |
|
启用ACOMP组件的语音唤醒组件 |
n |
算法类型配置
注意: 单麦和双麦算法互斥,只能选择其中一种。
配置项 |
说明 |
默认值 |
|---|---|---|
|
单麦克风唤醒算法 |
y |
|
双麦克风唤醒算法 |
n |
资源配置
配置项 |
说明 |
默认值 |
|---|---|---|
|
CAE ESR MLP 模型地址(存储在flash) |
0xcd00000 |
|
CAE ESR MLP 模型长度 |
419904 |
|
AI Wrap 资源地址(存储在flash) |
0xcd00000 |
|
AI Wrap 资源长度 |
419904 |
快速开始
1. 启用组件
在项目的 prj.conf 文件中添加:
# 启用 ACOMP 组件
CONFIG_ACOMP=y
# 启用ACOMP组件的WAKEUP组件
CONFIG_ACOMP_WAKEUP=y
# 选择算法类型(单麦或双麦)
CONFIG_ACOMP_WAKEUP_ALGORITHM_TYPE_DUAL_MIC=y
# 配置wakeup组件所需资源在flash的位置和大小(由用户来决定资源的放置位置和大小)
CONFIG_ACOMP_WAKEUP_RES_CAE_ESR_MLP_ADDRESS=0x30200000
CONFIG_ACOMP_WAKEUP_RES_CAE_ESR_MLP_LENGTH=2926656
CONFIG_ACOMP_WAKEUP_RES_AI_WRAP_ADDRESS=0x304D0000
CONFIG_ACOMP_WAKEUP_RES_AI_WRAP_LENGTH=1008
2. 初始化唤醒组件
在应用程序中初始化唤醒组件:
#include "acomp.h"
#include "wakeup/acomp_wakeup.h"
int main(int argc, char **argv)
{
// 初始化 ACOMP 框架
acomp_init();
// 初始化唤醒组件
int ret = acomp_wakeup_init();
if (ret != ACOMP_ERR_OK) {
printf("Wakeup init failed: %d\n", ret);
return -1;
}
// 你的应用代码
return 0;
}
3. 注册事件回调
使用事件回调函数接收唤醒结果和状态更新:
#include "wakeup/acomp_wakeup.h"
void wakeup_event_handler(uint32_t event, void *event_data,
uint32_t event_data_len, void *priv)
{
if (event & WAKEUP_CB_EVENT_ENGINE_RLT) {
// 唤醒结果
printf("Wakeup result: %s\n", (char *)event_data);
} else if (event & WAKEUP_CB_EVENT_STREAM_UPDATE) {
// 音频流更新
printf("Stream update\n");
} else if (event & WAKEUP_CB_EVENT_ENGINE_TIMEOUT) {
// 唤醒超时
printf("Wakeup timeout\n");
} else if (event & WAKEUP_CB_EVENT_ENGINE_ANGLE) {
// 角度信息
printf("Angle info received\n");
}
}
// 注册回调
int ret = acomp_wakeup_add_callback(
WAKEUP_CB_EVENT_ENGINE_RLT |
WAKEUP_CB_EVENT_STREAM_UPDATE |
WAKEUP_CB_EVENT_ENGINE_TIMEOUT |
WAKEUP_CB_EVENT_ENGINE_ANGLE,
wakeup_event_handler,
NULL
);
4. 启动唤醒服务
完整的启动流程:
#include "wakeup/acomp_wakeup.h"
void start_wakeup_service(void)
{
int ret;
// 1. 就绪组件(分配资源)
ret = acomp_wakeup_prepare();
if (ret != ACOMP_ERR_OK) {
printf("Wakeup prepare failed: %d\n", ret);
return;
}
// 2. 启动唤醒
ret = acomp_wakeup_start();
if (ret != ACOMP_ERR_OK) {
printf("Wakeup start failed: %d\n", ret);
return;
}
printf("Wakeup service started\n");
}
void stop_wakeup_service(void)
{
int ret;
// 1. 停止唤醒
ret = acomp_wakeup_stop();
if (ret != ACOMP_ERR_OK) {
printf("Wakeup stop failed: %d\n", ret);
return;
}
// 2. 清理资源
ret = acomp_wakeup_cleanup();
if (ret != ACOMP_ERR_OK) {
printf("Wakeup cleanup failed: %d\n", ret);
return;
}
printf("Wakeup service stopped\n");
}
5. 配置唤醒参数
设置算法模式和唤醒门限(必须在启动后设置):
#include "wakeup/acomp_wakeup.h"
void configure_wakeup(void)
{
int ret;
// 1. 就绪并启动唤醒组件
ret = acomp_wakeup_prepare();
ret = acomp_wakeup_start();
// 2. 启动后设置算法模式和门限(必须在 start 之后)
acomp_wakeup_set_algo_mode(ACOMP_WAKEUP_ALGO_MODE_WAKEUP);
acomp_wakeup_set_threshold(ACOMP_WAKEUP_THRESHOLD_LEVEL_3);
// 或者设置为 ESR 模式
// acomp_wakeup_set_algo_mode(ACOMP_WAKEUP_ALGO_MODE_ESR);
}
6. 把音频数据通过TX流通道发送给AP核算法引擎处理
使能 M2R (Master to Remote) 流通道,用于将音频数据发送给 AP 核:
#include "wakeup/acomp_wakeup.h"
#define TX_STREAM_CH_INDEX 0
#define TX_STREAM_CH_NAME "stream.mix2ch"
void setup_tx_stream(void)
{
// 1. 创建 M2R 流通道描述符
acomp_stream_chn_create_desc_t desc = {
.cname = TX_STREAM_CH_NAME,
.direction = ACOMP_STREAM_DIRECTION_M2R, // Master to Remote
.index = TX_STREAM_CH_INDEX,
.buffer_size = ACOMP_WAKEUP_AUDIO_INPUT_LEN_ONCE_FRAME, // 单帧音频数据大小
.num_descs = 4, // 缓冲区描述符数量(根据实际需求设置)
.kick_policy = 1, // 自动触发
};
// 2. 使能流通道
int ret = acomp_wakeup_stream_ch_enable(TX_STREAM_CH_INDEX, &desc);
if (ret != ACOMP_ERR_OK) {
printf("Failed to enable tx stream: %d\n", ret);
}
}
void send_data_to_remote(void)
{
uint8_t *buffer;
uint32_t buf_size;
uint16_t desc_idx;
// 1. 分配发送缓冲区
buffer = acomp_wakeup_stream_tx_buffer_alloc(TX_STREAM_CH_INDEX,
&buf_size, &desc_idx);
if (buffer && buf_size > 0) {
// 2. 填充音频数据到缓冲区
// 数据格式为 acomp_wakeup_audio_in_t 数组,包含 256 个采样点
// 双麦: {mic0, mic1, ref0, ref1} * 256
// 单麦: {mic0, ref0} * 256
acomp_wakeup_audio_in_t *audio_frame = (acomp_wakeup_audio_in_t *)buffer;
// 填充从麦克风采集的音频数据
// fill_audio_data(audio_frame, ACOMP_WAKEUP_AUDIO_INPUT_SAMPLE_CNT);
// 3. 提交缓冲区发送
acomp_wakeup_stream_tx_buffer_submit(TX_STREAM_CH_INDEX,
buffer, buf_size, desc_idx);
}
}
7. 使能 RX 流通道并接收数据
使能 R2M (Remote to Master) 流通道,用于接收 AP 核的输出数据:
#include "wakeup/acomp_wakeup.h"
#define RX_STREAM_CH_INDEX 1
#define RX_STREAM_CH_NAME "stream.tocloud"
void setup_rx_stream(void)
{
// 1. 创建 R2M 流通道描述符
acomp_stream_chn_create_desc_t desc = {
.cname = RX_STREAM_CH_NAME,
.direction = ACOMP_STREAM_DIRECTION_R2M, // Remote to Master
.index = RX_STREAM_CH_INDEX,
.buffer_size = ACOMP_WAKEUP_AUDIO_OUTPUT_MAX_LEN_ONCE_FRAME, // 最大输出帧大小
.num_descs = 8, // 缓冲区描述符数量
.kick_policy = 1, // 自动触发
};
// 2. 使能流通道
int ret = acomp_wakeup_stream_ch_enable(RX_STREAM_CH_INDEX, &desc);
if (ret != ACOMP_ERR_OK) {
printf("Failed to enable rx stream: %d\n", ret);
}
}
void receive_data_from_remote(void)
{
uint8_t *buffer;
uint32_t len;
uint16_t desc_idx;
// 1. 获取算法输出的音频数据
buffer = acomp_wakeup_stream_rx_buffer_get(RX_STREAM_CH_INDEX, &len, &desc_idx);
if (buffer && len > 0) {
// 2. 处理接收到的数据
// 数据格式为 acomp_wakeup_audio_out_t 数组,5通道交织
// {mic0, mic1, ref0, out1, out2} * N 个采样点
// 其中 out1 为回声消除后的音频,可用于云端识别
acomp_wakeup_audio_out_t *audio_out = (acomp_wakeup_audio_out_t *)buffer;
int sample_count = len / sizeof(acomp_wakeup_audio_out_t);
// process_output_audio(audio_out, sample_count);
// 3. 释放缓冲区
acomp_wakeup_stream_rx_buffer_release(RX_STREAM_CH_INDEX,
desc_idx, len, buffer);
}
}
API 参考
生命周期管理
acomp_wakeup_init
int acomp_wakeup_init(void);
功能:初始化语音唤醒组件
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_NO_MEM:内存不足ACOMP_ERR_INVALID_STATE:无效状态ACOMP_ERR_NOT_FOUND:设备未找到
acomp_wakeup_prepare
int acomp_wakeup_prepare(void);
功能:就绪语音唤醒组件,初始化内存块及算法资源
说明:在调用 acomp_wakeup_start() 之前必须调用此函数
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_NO_MEM:内存不足ACOMP_ERR_INVALID_STATE:无效状态
acomp_wakeup_cleanup
int acomp_wakeup_cleanup(void);
功能:复位语音唤醒组件,释放内存块及算法资源
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_STATE:无效状态
acomp_wakeup_start
int acomp_wakeup_start(void);
功能:启动语音唤醒组件,同步启动音频流传输
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_NO_MEM:内存不足ACOMP_ERR_INVALID_STATE:无效状态
acomp_wakeup_stop
int acomp_wakeup_stop(void);
功能:停止语音唤醒组件,同步停止音频流传输
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_STATE:无效状态
参数配置
acomp_wakeup_set_algo_mode
int acomp_wakeup_set_algo_mode(acomp_wakeup_algo_mode_e mode);
功能:设置算法模式
说明:该函数必须在调用 acomp_wakeup_start() 之后设置才能生效
参数:
mode:算法模式ACOMP_WAKEUP_ALGO_MODE_WAKEUP:唤醒模式ACOMP_WAKEUP_ALGO_MODE_ESR:ESR 模式
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_ARG:参数错误ACOMP_ERR_INVALID_STATE:无效状态
acomp_wakeup_set_threshold
int acomp_wakeup_set_threshold(acomp_wakeup_threshold_level_e level);
功能:设置唤醒门限等级
说明:该函数必须在调用 acomp_wakeup_start() 之后设置才能生效
参数:
level:门限等级 (1-6)ACOMP_WAKEUP_THRESHOLD_LEVEL_1:最低,极易唤醒ACOMP_WAKEUP_THRESHOLD_LEVEL_2:易唤醒ACOMP_WAKEUP_THRESHOLD_LEVEL_3:默认档位ACOMP_WAKEUP_THRESHOLD_LEVEL_4:难唤醒ACOMP_WAKEUP_THRESHOLD_LEVEL_5:极难唤醒
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_ARG:参数错误ACOMP_ERR_INVALID_STATE:无效状态
事件回调
acomp_wakeup_add_callback
int acomp_wakeup_add_callback(uint32_t events, wakeup_event_cb_t cb, void *priv);
功能:添加事件回调函数
参数:
events:事件位掩码,可同时注册多个事件WAKEUP_CB_EVENT_STREAM_UPDATE:音频数据流更新WAKEUP_CB_EVENT_ENGINE_RLT:语音唤醒引擎结果返回WAKEUP_CB_EVENT_ENGINE_TIMEOUT:唤醒超时WAKEUP_CB_EVENT_ENGINE_ANGLE:角度信息
cb:回调函数指针priv:回调函数的私有数据指针
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_NO_MEM:内存不足ACOMP_ERR_INVALID_ARG:参数错误ACOMP_ERR_INVALID_STATE:无效状态
acomp_wakeup_remove_callback
int acomp_wakeup_remove_callback(wakeup_event_cb_t cb);
功能:移除回调函数
参数:
cb:待移除的回调函数
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_ARG:参数错误ACOMP_ERR_INVALID_STATE:无效状态ACOMP_ERR_NOT_SUPPORTED:不支持的操作
音频流管理
acomp_wakeup_stream_ch_enable
int acomp_wakeup_stream_ch_enable(int chn, acomp_stream_chn_create_desc_t *desc);
功能:使能音频流通道
参数:
chn:通道索引desc:通道描述符指针
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_STATE:无效状态ACOMP_ERR_INVALID_ARG:参数错误ACOMP_ERR_CREATE_STREAM_FAILED:创建流失败
acomp_wakeup_stream_ch_disable
int acomp_wakeup_stream_ch_disable(int chn);
功能:禁用音频流通道
参数:
chn:通道索引
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_STATE:无效状态ACOMP_ERR_INVALID_ARG:参数错误
acomp_wakeup_stream_rx_buffer_get
void* acomp_wakeup_stream_rx_buffer_get(int chn, uint32_t* len, uint16_t* desc_idx);
功能:获取 RX 流缓冲区
参数:
chn:通道索引len:数据长度指针(输出)desc_idx:描述符索引指针(输出)
返回值:缓冲区指针,失败返回 NULL
acomp_wakeup_stream_rx_buffer_release
int acomp_wakeup_stream_rx_buffer_release(int chn, uint16_t desc_idx,
uint32_t len, void* buffer);
功能:释放 RX 流缓冲区
参数:
chn:通道索引desc_idx:描述符索引len:数据长度buffer:缓冲区指针
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_STATE:无效状态ACOMP_ERR_INVALID_ARG:参数错误
acomp_wakeup_stream_tx_buffer_alloc
void* acomp_wakeup_stream_tx_buffer_alloc(int chn, uint32_t* len, uint16_t* desc_idx);
功能:分配 TX 流缓冲区用于向 remote 发送音频数据
参数:
chn:通道索引len:可用缓冲区长度指针(输出)desc_idx:描述符索引指针(输出)
返回值:缓冲区指针,失败返回 NULL
acomp_wakeup_stream_tx_buffer_submit
int acomp_wakeup_stream_tx_buffer_submit(int chn, void* buffer,
uint32_t len, uint16_t desc_idx);
功能:提交 TX 流缓冲区发送音频数据到 remote
参数:
chn:通道索引buffer:缓冲区指针len:数据长度desc_idx:描述符索引
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_STATE:无效状态ACOMP_ERR_INVALID_ARG:参数错误
使用示例
完整示例
#include "acomp.h"
#include "wakeup/acomp_wakeup.h"
#include "lisa_log.h"
#define TAG "wakeup_demo"
// 事件回调函数
void wakeup_event_handler(uint32_t event, void *event_data,
uint32_t event_data_len, void *priv)
{
if (event & WAKEUP_CB_EVENT_ENGINE_RLT) {
LISA_LOGI(TAG, "Wakeup result: %d, %s",
event_data_len, (char *)event_data);
} else if (event & WAKEUP_CB_EVENT_STREAM_UPDATE) {
LISA_LOGI(TAG, "Stream update data: %d, len: %d",
*(uint32_t*)event_data, event_data_len);
} else if (event & WAKEUP_CB_EVENT_ENGINE_TIMEOUT) {
LISA_LOGI(TAG, "Wakeup timeout");
} else {
LISA_LOGW(TAG, "Unknown wakeup event: 0x%X", event);
}
}
void wakeup_demo(void)
{
int ret;
// 1. 初始化 ACOMP 框架
acomp_init();
// 2. 初始化唤醒组件
ret = acomp_wakeup_init();
if (ret != ACOMP_ERR_OK) {
LISA_LOGE(TAG, "Wakeup init failed: %d", ret);
return;
}
// 3. 注册事件回调
ret = acomp_wakeup_add_callback(
WAKEUP_CB_EVENT_ENGINE_RLT |
WAKEUP_CB_EVENT_STREAM_UPDATE |
WAKEUP_CB_EVENT_ENGINE_TIMEOUT,
wakeup_event_handler,
NULL
);
if (ret != ACOMP_ERR_OK) {
LISA_LOGE(TAG, "Add callback failed: %d", ret);
return;
}
// 4. 就绪组件
ret = acomp_wakeup_prepare();
if (ret != ACOMP_ERR_OK) {
LISA_LOGE(TAG, "Wakeup prepare failed: %d", ret);
return;
}
LISA_LOGI(TAG, "Wakeup prepared");
// 5. 启动唤醒
ret = acomp_wakeup_start();
if (ret != ACOMP_ERR_OK) {
LISA_LOGE(TAG, "Wakeup start failed: %d", ret);
return;
}
LISA_LOGI(TAG, "Wakeup started");
// 6. 配置唤醒参数(必须在 start 之后)
acomp_wakeup_set_algo_mode(ACOMP_WAKEUP_ALGO_MODE_WAKEUP);
acomp_wakeup_set_threshold(ACOMP_WAKEUP_THRESHOLD_LEVEL_3);
// 7. 运行一段时间
vTaskDelay(pdMS_TO_TICKS(10000));
// 8. 停止唤醒
ret = acomp_wakeup_stop();
if (ret != ACOMP_ERR_OK) {
LISA_LOGE(TAG, "Wakeup stop failed: %d", ret);
}
LISA_LOGI(TAG, "Wakeup stopped");
// 9. 清理资源
ret = acomp_wakeup_cleanup();
if (ret != ACOMP_ERR_OK) {
LISA_LOGE(TAG, "Wakeup cleanup failed: %d", ret);
}
LISA_LOGI(TAG, "Wakeup cleaned up");
}
音频流处理示例
音频数据输入给算法引擎
#include "wakeup/acomp_wakeup.h"
void audio_stream_tx_example(void)
{
int chn = 0; // 通道 0
uint32_t len;
uint16_t desc_idx;
void *buffer;
while (1) {
// 发送音频数据
buffer = acomp_wakeup_stream_tx_buffer_alloc(chn, &len, &desc_idx);
if (buffer) {
// 填充音频数据
fill_audio_data(buffer, len);
// 提交发送
acomp_wakeup_stream_tx_buffer_submit(chn, buffer, len, desc_idx);
}
}
}
获取算法引擎输出的音频数据,并处理
#include "wakeup/acomp_wakeup.h"
void audio_stream_rx_example(void)
{
int chn = 0; // 通道 0
uint32_t len;
uint16_t desc_idx;
void *buffer;
while (1) {
// 接收音频数据
buffer = acomp_wakeup_stream_rx_buffer_get(chn, &len, &desc_idx);
if (buffer) {
// 处理算法输出的音频数据
process_audio_data(buffer, len);
// 释放缓冲区
acomp_wakeup_stream_rx_buffer_release(chn, desc_idx, len, buffer);
}
}
}
注意事项
初始化顺序:必须先调用
acomp_init()初始化 ACOMP 框架,再调用acomp_wakeup_init()生命周期管理:启动前必须调用
acomp_wakeup_prepare(),停止后应调用acomp_wakeup_cleanup()释放资源状态检查:所有 API 都会进行状态检查,确保在正确的状态下调用相应的函数
事件回调:回调函数在组件内部线程中执行,应避免长时间阻塞操作
内存管理:组件使用动态内存分配,确保系统有足够的堆内存
资源配置:确保配置的模型地址和长度与实际烧录的模型匹配
算法选择:单麦和双麦算法互斥,只能选择其中一种
门限调整:根据实际使用场景调整唤醒门限,平衡误唤醒率和唤醒成功率
音频流管理:使用音频流接口时,必须成对调用 get/release 和 alloc/submit
跨核通信:音频流基于 IPC 机制,注意跨核数据传输的延迟和同步问题
常见问题
Q: 唤醒组件初始化失败怎么办?
A: 检查以下几点:
确保 ACOMP 框架已正确初始化
检查系统是否有足够的堆内存
确认音频硬件设备是否正常工作
检查配置的模型资源地址和长度是否正确
Q: 无法触发唤醒回调?
A: 检查:
确认已正确注册事件回调函数
检查唤醒门限设置是否过高(尝试降低门限等级)
确认麦克风是否正常采集音频数据
检查算法模式设置是否正确
Q: 唤醒成功率低怎么办?
A: 可以尝试:
降低唤醒门限等级(如从 3 降到 2)
检查麦克风音频质量和增益设置
确认使用的算法类型(单麦/双麦)与硬件配置匹配
检查环境噪声是否过大
Q: 误唤醒率高怎么办?
A: 可以尝试:
提高唤醒门限等级(如从 3 升到 4)
检查是否有持续的背景噪声干扰
确认麦克风位置和方向是否合理
Q: 如何在唤醒模式和 ESR 模式之间切换?
A: 使用 acomp_wakeup_set_algo_mode() 函数:
// 切换到唤醒模式
acomp_wakeup_set_algo_mode(ACOMP_WAKEUP_ALGO_MODE_WAKEUP);
// 切换到 ESR 模式
acomp_wakeup_set_algo_mode(ACOMP_WAKEUP_ALGO_MODE_ESR);
注意:模式切换应在停止状态下进行。
依赖项
ACOMP 框架:音频组件框架ACOMP Stream IPC:音频流跨核通信lisa_log:日志系统FreeRTOS:实时操作系统唤醒算法库:语音唤醒算法引擎音频驱动:麦克风和音频处理硬件驱动
相关文档
ACOMP 框架文档
音频流 IPC 接口文档
语音唤醒算法说明文档