语音唤醒组件

简介

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;

音频帧大小定义

组件提供了一组宏定义用于计算音频帧大小:

输入音频帧信息:

宏定义

说明

ACOMP_WAKEUP_AUDIO_INPUT_LEN_ONE_SAMPLE

单个输入音频采样点的字节数

sizeof(acomp_wakeup_audio_in_t)

ACOMP_WAKEUP_AUDIO_INPUT_SAMPLE_CNT

每帧输入音频的采样点数量

256

ACOMP_WAKEUP_AUDIO_INPUT_LEN_ONCE_FRAME

单帧输入音频数据的总字节数

单麦: 1024 字节
双麦: 2048 字节

ACOMP_WAKEUP_ESR_NEED_FRAME_CNT

一次完整识别需要输入的音频帧数量

10

输出音频帧信息:

宏定义

说明

ACOMP_WAKEUP_AUDIO_OUTPUT_CHANNELS_PER_SAMPLE

输出音频每个采样点的通道数

5

ACOMP_WAKEUP_AUDIO_OUTPUT_LEN_ONE_SAMPLE

单个输出音频采样点的字节数

10 字节

ACOMP_WAKEUP_AUDIO_OUTPUT_MAX_LEN_ONCE_FRAME

单次输出音频数据的最大字节数

25600 字节

配置选项

基本配置

配置项

说明

默认值

CONFIG_ACOMP

启用ACOMP组件

n

CONFIG_ACOMP_WAKEUP

启用ACOMP组件的语音唤醒组件

n

算法类型配置

注意: 单麦和双麦算法互斥,只能选择其中一种。

配置项

说明

默认值

CONFIG_ACOMP_WAKEUP_ALGORITHM_TYPE_SINGLE_MIC

单麦克风唤醒算法

y

CONFIG_ACOMP_WAKEUP_ALGORITHM_TYPE_DUAL_MIC

双麦克风唤醒算法

n

资源配置

配置项

说明

默认值

CONFIG_ACOMP_WAKEUP_RES_CAE_ESR_MLP_ADDRESS

CAE ESR MLP 模型地址(存储在flash)

0xcd00000

CONFIG_ACOMP_WAKEUP_RES_CAE_ESR_MLP_LENGTH

CAE ESR MLP 模型长度

419904

CONFIG_ACOMP_WAKEUP_RES_AI_WRAP_ADDRESS

AI Wrap 资源地址(存储在flash)

0xcd00000

CONFIG_ACOMP_WAKEUP_RES_AI_WRAP_LENGTH

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);
        }
    }
}

注意事项

  1. 初始化顺序:必须先调用 acomp_init() 初始化 ACOMP 框架,再调用 acomp_wakeup_init()

  2. 生命周期管理:启动前必须调用 acomp_wakeup_prepare(),停止后应调用 acomp_wakeup_cleanup() 释放资源

  3. 状态检查:所有 API 都会进行状态检查,确保在正确的状态下调用相应的函数

  4. 事件回调:回调函数在组件内部线程中执行,应避免长时间阻塞操作

  5. 内存管理:组件使用动态内存分配,确保系统有足够的堆内存

  6. 资源配置:确保配置的模型地址和长度与实际烧录的模型匹配

  7. 算法选择:单麦和双麦算法互斥,只能选择其中一种

  8. 门限调整:根据实际使用场景调整唤醒门限,平衡误唤醒率和唤醒成功率

  9. 音频流管理:使用音频流接口时,必须成对调用 get/release 和 alloc/submit

  10. 跨核通信:音频流基于 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 接口文档

  • 语音唤醒算法说明文档