AEF overlay 开发指南
AEF 驱动背景知识
AEF 是输出侧的音效和音频后处理框架。MCU 侧负责打开 SOUND、选择输出端口、使能 AEF 类型以及下发参数;DSP overlay 侧负责注册插件、创建算法实例和逐帧处理 PCM。算法不直接管理播放设备或 AT 命令,应用也不应绕过插件接口直接访问算法内部状态。

其中,/src/application/audio/sample_dsp_overlay/aef 是插件集成工程;/src/application/audio/sample_ao/sample_aef.c 是 MCU 侧现有 AEF 控制参考;/src/application/audio/sample_dsp_overlay/aef/component/aef/plugins/aef_lib0/xaaef_lib0_comp.c 是当前 SDK 中可直接阅读的 DSP 插件适配示例代码。
说明:本文示例命令以一站式 CLI 为主。实际开发可从以下三种环境中选择,推荐使用一站式 CLI。
| 开发环境 | 适用场景 | 使用指南 |
|---|---|---|
| 一站式 CLI(推荐) | 快速完成目标选择、构建、烧录和串口监视 | 一站式 CLI 开发环境使用指南 |
| HiSpark Studio for VS Code | 图形化编辑、编译、烧录和调试 | HiSpark Studio for VS Code 开发环境使用指南 |
| WSL 与 Docker | 在 Windows 上使用一致的 Linux 容器构建环境 | WSL 与 Docker 环境使用指南 |
准备工作: 按 一站式 CLI 开发环境使用指南 准备环境、构建和烧录;构建前必须确保 fbb doctor 成功。插件工程还需要可用的 Xtensa 工具链和许可证;其配置文件、变量含义和注意事项见“开发环境配置”。
注意: 代码编译镜像依赖 RG-2017.5-linux、H_3Z_ides 的工具链和编译证书;在 xtensa_cfg.mak 中配置 XTENSA_HOME 工具链文件地址和 XTENSAD_LICENSE_FILE 证书文件地址。工具链和证书需要向 Cadence 购买。
快速跑通 AEF Demo
关键配置
-
工程路径配置
/src/application/audio/sample_dsp_overlay/aef/sap_idp.mak 已将
IDP_OUT_DIR定义为当前 AEF 工程下的out/。快速跑通时保持默认值;替换脚本和后续验收都从out/bin/读取插件,单独修改输出目录会使脚本找不到产物。 -
Xtensa编译工具链配置
xtensa_cfg.mak 默认将
XTENSA_HOME指向名为RG-2017.5-linux的 SDK 配套工具链目录。先检查该目录及其中的xt-make是否随开发包交付;仅在使用外部工具链时才修改XTENSA_HOME。许可证路径未在仓库中写死,需要按本机授权方式设置环境变量XTENSAD_LICENSE_FILE。 -
lsp_file配置 hifi_lsp.mak 和 rules.mak 中的
XTENSA_LSP_FILE,需要设置为 arch/lsp 目录下实际使用的lsp_afe文件名,后续生成的插件会加载到该 LSP 定义的内存地址。
编译
在算法集成开发包所在路径下,执行以下命令:
- 清除历史编译结果:
make clean - 编译算法静态库:
make lib -
编译算法插件 bin 文件:
make all须知: 执行
make前,必须确认xtensa_cfg.mak解析出的XTENSA_HOME下存在工具链,且需要许可证的工具链已设置有效的XTENSAD_LICENSE_FILE。make all会调用xt-make编译plugins/Makefile中aef_libx列出的全部插件;当前默认条目是aef_lib0。 当前/build/xtensa/arch/lsp目录下,没有Hi3322芯片对应的aef加载地址的lsp文件 若想要将编译出来的aef_lib0镜像加载替换进dsp_overlay.bin中,需要修改镜像名称为aef.bin再打包到dsp_overlay.bin中。若想使用该音效算法插件,需要在调用uapi_snd_set_port_aef_enable接口时将uapi_aef_type effect_type设置为UAPI_AEF_TYPE_CUSTOMER
构建验收条件
完成“开发自己的 AEF 插件”后,必须同时满足以下条件,才能判定插件可编译、可打包:
- /src/application/audio/sample_dsp_overlay/aef/build/xtensa/xtensa_cfg.mak 配置的
XTENSA_HOME下存在xt-make,许可证有效。 - 新插件目录、插件 Makefile 的
TARGET、适配源文件名和plugins/Makefile的aef_libx条目一致。 - 目标产品配置已启用与插件类型一致的效果宏;CUSTOMER 插件必须启用
CFG_SAP_EFFECT_CUSTOMER_SUPPORT=y。 make clean、make lib、make all均返回成功,并在 AEF 工程的out/bin输出目录生成目标插件,例如aef_lib0.bin。- 打包前存在目标产品的
dsp_overlay.bin输入文件;打包后使用 CLI 指南完成整机镜像构建和烧录,再通过AT^audio=sample_aef cust on/off验证开关。
任一条件不满足时,不应将插件标记为“已编译通过”。
镜像打包、烧录与运行
生成算法镜像包
在 /src/application/audio/sample_dsp_overlay/aef 中执行命令:
bash ./aef_replace_overlay.sh ../../../../tools/pkg/bin/3322/dsp/normal/dsp_overlay.bin aef_lib0.bin
3322 EVB 的 Overlay 输入和输出文件均为 src/tools/pkg/bin/3322/dsp/normal/dsp_overlay.bin。脚本会校验输入文件,重新构建 AEF 插件,解包 Overlay,以 out/bin/aef_lib0.bin 替换其中的 aef.bin,再将重新打包的结果写回同一路径。
执行脚本前应备份该文件。脚本会直接覆盖产品包中的 dsp_overlay.bin;仅在 aef_lib0.bin 已按前文构建成功、且确认需要替换当前产品包的 AEF 插件时执行。
第一个参数可传
dsp_overlay.bin的完整或相对路径;使用仓库外部交付的旧 brandy 产品包时,也可传该产品包中的 DSP 版本目录名称。第二个参数是out/bin/中生成的插件 bin 文件名。接入自定义插件后,将aef_lib0.bin替换为该插件的实际产物名。
启动 sample_ao 加载和运行算法
-
将产品打包后的镜像按 一站式 CLI 开发环境使用指南 烧录到开发板。
图 1 烧写完成示意图

-
确认产品未启用
CFG_SAP_MINIMIZE_SAMPLE_RELEASE。当前 3322 EVB 配置未启用该宏,因此sample_aef已注册到音频命令分发中;若产品启用了该宏,应在自己的应用中调用 AEF 接口完成开关和参数下发。 -
先使能 CUSTOMER 效果:
cust仅支持on与off,对应 MCU 侧的UAPI_AEF_TYPE_CUSTOMER开关。 -
播放固定 PCM 作为使能后的样本:
输入AT命令:AT^audio=sample_ao /user/stream/pcm/PCM_16k_1ch_16bit.pcm 0 16000 16 1
(sample_ao的AT命令格式需要遵循格式:AT^audio=sample_ao pcm_file volume sample_rate bit_width channels。命令中的pcm_file文件需提前上传至文件系统,或替换为文件系统中已有的pcm文件)
-
关闭效果后播放同一 PCM,形成 A/B 对比:
透传插件在使能、关闭两个阶段都应正常播放且声音无异常;接入实际算法后,应使用同一 PCM 比较输出。需要验证算法参数时,使用前文所述的应用接口下发参数,不能依赖
cust命令。
文件结构与代码走读
算法集成工程与文件结构
概述
本文档主要介绍 AEF overlay 集成相关内容,重点介绍算法集成开发包、开发算法环境配置、开发算法插件、加载和运行算法等。AEF(Audio Effect Framework)用于承载音效算法或音频后处理算法。
算法集成开发包
集成开发包说明
集成开发包见 GitCode 的 AEF Overlay 工程。
AEF 构建目录
build目录:
-
xtensa子目录:存放DSP相关的配置文件和编译脚本,建议只引用不修改。
- hifi_rules.mak:配置编译规则、overlay打包规则和依赖关系。
- hifi_lsp.mak:配置overlay打包规则,被hifi_rules.mak调用。
- xtensa_cfg.mak:配置HiFi工具链和overlay打包工具。
-
/src/application/audio/sample_dsp_overlay/aef/build/xtensa/arch子目录:各个overlay的memmap配置。
- /src/application/audio/sample_dsp_overlay/aef/build/xtensa/tool子目录:overlay打包工具。
AEF 公共头文件目录
include目录:
/src/application/audio/sample_dsp_overlay/aef/include/td_type.h:C语言变量类型重定义。
Overlay 适配目录
overlay目录:
-
component头文件,必须在插件源文件中包含。
/src/application/audio/sample_dsp_overlay/aef/overlay/component.h:通用算法插件注册接口,通过define_component接口将插件entry地址注册到.component内存段中。
-
core_overlay模块作为插件统一入口和C库依赖,被编译到各个算法插件的bin文件中。
/src/application/audio/sample_dsp_overlay/aef/overlay/core_overlay.c:重定向C库函数到相应的钩子函数,以及将overlay引导地址.start指向可访问.component内存的接口。
AEF 组件目录
component目录:
- /src/application/audio/sample_dsp_overlay/aef/component/aef/plugins子目录:AEF插件工程目录。
- /src/application/audio/sample_dsp_overlay/aef/component/aef/plugins/aef_lib0:AEF插件示例工程,开发者可参考该工程创建新的AEF插件工程。
C 库钩子扩展
说明: 如果主镜像未注册相应的C库函数到该新增的“overlay_func->func”函数指针,会导致overlay新增C库函数钩子。开发者可自行实现C库函数,或是知会主镜像发布者发布新的镜像将相应的C库函数注册到“overlay_func->func”函数指针。
修改集成开发包的/src/application/audio/sample_dsp_overlay/aef/overlay/core_overlay.h文件和/src/application/audio/sample_dsp_overlay/aef/overlay/core_overlay.c文件:
/* 在core_overlay.h的overlay_func结构体中,新增一个C库同名函数类型定义 */
typedef struct {
int (*func)(void);
} overlay_func;
/* 在core_overlay.c源码中,新增一个C库同名函数实现,重定向到主镜像的钩子上 */
int func(void)
{
return g_overlay_func->func();
}
示例插件
示例插件见 aef_lib0。
插件目录结构
“/src/application/audio/sample_dsp_overlay/aef/component/aef/plugins/aef_lib0”工程目录结构如下:
include目录:自定义插件需要公共算法头文件时创建。lib目录:自定义插件需要预编译依赖库时创建。src目录:自定义插件需要拆分多个源码文件时创建。- /src/application/audio/sample_dsp_overlay/aef/component/aef/plugins/aef_lib0/xaaef_lib0_comp.c源文件:AEF算法适配样例。
当前 aef_lib0 目录实际只包含 Makefile 和 xaaef_lib0_comp.c。include、lib、src 是自定义算法复杂度增加时的建议分层,并非仓库现有目录。
插件编译脚本配置
-
在“/src/application/audio/sample_dsp_overlay/aef/component/aef/plugins/Makefile”编译脚本中,增加新增的AEF插件aef_lib0:
-
/src/application/audio/sample_dsp_overlay/aef/component/aef/plugins/aef_lib0/Makefile编译脚本内容如下:
CUR_DIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi) # 从当前目录回退到集成开发包所在路径 IDP_TOP_DIR := $(realpath $(CUR_DIR)/../../../..) # 包含集成开发包编译环境配置和编译工具链配置文件 include $(IDP_TOP_DIR)/sap_idp.mak include $(IDP_BUILD_DIR)/xtensa_cfg.mak # 编译待集成的AEF算法源码成静态库 libaef_lib0.a ifdef BUILD_LIB TARGET := libaef_lib0 CFLAGS_EXT := INCLUDES := -Iinclude -I$(IDP_TOP_DIR)/include LIB_INSTALL_DIR := lib /* 只编译待集成AEF算法的源文件 */ SRCFILE := $(wildcard src/*.c) # 编译待集成的AEF插件,并链接算法静态库libaef_lib0.a 到 aef_lib0.bin中 else TARGET := aef_lib0 CFLAGS_EXT := INCLUDES := -Iinclude -I$(IDP_TOP_DIR)/include # 链接待集成AEF算法的静态库 libaef_lib0.a,如还依赖其他静态库也链接进来。 LIBS := -l:lib/libaef_lib0.a # 只编译待集成AEF算法的插件适配源文件 SRCFILE := xaaef_lib0_comp.c endif # 包含编译规则和打包规则配置文件 include ../rules.mak
AEF 插件接口与注册
AEF 插件接口说明
AEF插件接口说明如下:
-
xaaef_lib0_comp.h定义结构体aef_component成员变量(即AEF插件属性):
- reserved:保留,不用配置。
- name:字符串,算法库名称。
- aef_type:AEF插件类型,参考枚举类型aef_type。
- version:版本。
-
xaaef_lib0_comp.h定义结构体aef_component成员接口(即AEF插件适配接口):
- create:创建算法实例并输出唯一的实例句柄给AEF。(必备接口)
- destroy:销毁实例句柄对应的算法实例,并释放相关资源。(必备接口)
- set_config:设置算法配置。(可选接口)
- get_config:获取算法配置。(可选接口)
- set_parameter:设置实例句柄对应的算法实例的参数。(可选接口)
- get_parameter:获取实例句柄对应的算法实例的参数。(可选接口)
- set_enable:使能或停止实例句柄对应的算法实例。(可选接口)
- get_enable:获取实例句柄对应的算法实例的使能状态。(可选接口)
- get_max_pcm_in_size:获取输入PCM数据的最大帧长。(可选接口)
- get_max_pcm_out_size:获取输出PCM数据的最大帧长。(可选接口)
- get_input_pcm_attr:获取输入PCM数据的属性。(必备接口)
-
proc_frame: 执行实例句柄对应的算法实例来处理输入的PCM数据。(必备接口)
表 1 音效算法audio_frame结构体说明
属性项
说明
interleaved
数据是否交织。
channels
声道。
bit_depth
位宽。
sample_rate
采样率。
pts
帧时间戳。
pcm_buffer
未使用,待扩展。
bits_buffer
音频PCM数据缓存指针。
bits_bytes
音频PCM数据大小。
pcm_samples
音频PCM数据采样点数。
frame_index
音频帧索引编号。
eos
帧结束标志。
pkg_loss
丢包标志。
AEF 插件适配样例
请参考算法集成开发包中的 xaaef_lib0_comp.c。
AEF 插件注册方法
AEF插件注册参考样例及说明如下。
/* 定义一个全局的插件 entry结构体 */
static aef_component ha_aef_lib_entry = {
.name = (const td_char *)"customer_aef",
.type = AEF_TYPE_CUSTOMER,
.version = 0x00800001,
.create = customer_aef_create,
.destroy = customer_aef_destroy,
.set_parameter = customer_aef_set_parameter,
.get_parameter = customer_aef_get_parameter,
.proc_frame = customer_aef_proc_frame,
};
/* 将插件entry地址注册到.component地址段中 */
define_component(AEF, ha_aef_lib_entry)
说明: 自研 CUSTOMER 效果的 entry 使用
AEF_TYPE_CUSTOMER;产品必须同时启用CFG_SAP_EFFECT_CUSTOMER_SUPPORT=y。其他效果类型应使用 /src/application/audio/sample_dsp_overlay/aef/include/audio_aef.h 中定义的枚举,并与产品的音效特性配置一致。
基于 AEF Demo 开发自己的插件
创建 AEF 插件工程
AEF 插件工程命名要求
AEF插件镜像bin文件命名要求:AEF插件工程命名建议与插件镜像bin文件名一致。如工程命名为“aef_lib0”,则插件镜像命名为“aef_lib0.bin”。
新建 AEF 插件工程目录
请参考“插件目录结构”,新建工程aef_lib1。
新建工程aef_lib1到“/src/application/audio/sample_dsp_overlay/aef/component/aef/plugins”,工程目录结构如下:
include:按需放置算法公共头文件。lib:按需放置取得合法授权的算法依赖库。src:按需放置拆分后的算法源码。xaaef_lib1_comp.c:由现有 xaaef_lib0_comp.c 复制并改名得到的插件适配源文件。xaaef_lib1_comp.h:仅在插件需要独立声明时创建,不是现有模板的必备文件。
AEF 插件编译脚本
在“/src/application/audio/sample_dsp_overlay/aef/component/aef/plugins/Makefile”编译脚本中,增加新增的AEF插件命令如下:aef_libx += aef_lib1
请参考“插件编译脚本配置”示例插件“/src/application/audio/sample_dsp_overlay/aef/component/aef/plugins/aef_lib0/Makefile”的编译脚本,创建新增插件aef_lib1的编译脚本。
开发 AEF 插件
开发流程
本章节相当于外设类指南中的“基于 Demo 开发自己的应用”,但 AEF 的交付物不是独立应用,而是一个被 DSP overlay 加载的插件。建议以现有 aef_lib0 为模板,按既定目录结构和构建规则创建新插件。

设计插件边界和参数 ABI
先确定插件名称、版本、算法类型、PCM 输入格式、每帧最大采样点数和 MCU/DSP 共用参数结构。audio_frame 的字段含义、aef_component 的回调职责和插件类型限制在下方“AEF插件接口说明”中完整保留;自定义参数应带版本和长度校验,避免 MCU 与 DSP 两端结构体不一致。
| 功能 | 参考代码或接口 |
|---|---|
| AEF 类型、PCM 帧和组件回调定义 | /src/application/audio/sample_dsp_overlay/aef/include/audio_aef.h |
| 插件注册宏 | /src/application/audio/sample_dsp_overlay/aef/overlay/component.h |
| 现有 DSP 适配样例 | /src/application/audio/sample_dsp_overlay/aef/component/aef/plugins/aef_lib0/xaaef_lib0_comp.c |
| MCU 侧 AEF 控制参考 | /src/application/audio/sample_ao/sample_aef.c |
| AEF 参数服务接口 | AudioManagerSetAefParam |
建立插件工程和构建目标
复制 /src/application/audio/sample_dsp_overlay/aef/component/aef/plugins/aef_lib0,建立 aef_lib1 的 include、lib、src 和适配文件。复制后先完成以下机械改名,再开始接入算法:
- 将
xaaef_lib0_comp.c重命名为xaaef_lib1_comp.c,复制 aef_lib0/Makefile 到新插件目录,并把其中的SRCFILE改为该文件名。 - 将
TARGET := aef_lib0改为TARGET := aef_lib1;插件工程名、TARGET、生成的.bin文件名和打包时的插件名必须一致。 - 将 /src/application/audio/sample_dsp_overlay/aef/component/aef/plugins/Makefile 中的
aef_libx := aef_lib0改为aef_libx := aef_lib0 aef_lib1,使新插件参与 DSP 构建。 - 对自研 CUSTOMER 效果,在目标产品的音频配置中启用
CFG_SAP_EFFECT_CUSTOMER_SUPPORT=y;例如 3322 EVB 配置文件为 /src/drivers/drivers/driver/audio/source/build/configs/3322/3322_evb_liteos_cfg.mak。当前 /src/drivers/drivers/driver/audio/source/sap_base.mak 以互斥分支选择效果实现,因此 3322 EVB 同时必须保持CFG_SAP_EFFECT_HVS_SUPPORT未启用;仅打开 CUSTOMER 而保留 HVS,不会选择 CUSTOMER 实现。 - 修改产品
.mak配置后,重新按 一站式 CLI 开发环境使用指南 触发产品构建,使配置重新生成并参与后续镜像构建;不要使用修改配置前生成的构建输出判断结果。
逐函数实现插件适配层
当前 /src/application/audio/sample_dsp_overlay/aef/component/aef/plugins/aef_lib0/xaaef_lib0_comp.c 是最小、可运行的适配参考:
customer_aef_create()返回算法实例;真实算法应在此创建上下文、分配或取得所需资源。customer_aef_set_parameter()/customer_aef_get_parameter()按命令号分发参数,先校验param_size,再读写实例状态。customer_aef_proc_frame()接收audio_frame,处理 PCM 后填充输出帧。当前示例直接*out_frame = *in_frame,仅用于验证框架数据通路;自研算法必须在这里执行实际处理。g_ha_audio_customer_aef_entry汇总名称、类型、版本和回调;最后由define_component(AEF, ...)放入.component段,供 overlay 加载。
static td_s32 customer_aef_proc_frame(td_void *aef,
audio_frame *in_frame, audio_frame *out_frame)
{
aef_check_null_ptr_return(aef);
aef_check_null_ptr_return(in_frame);
aef_check_null_ptr_return(out_frame);
*out_frame = *in_frame; /* 透传版本:先验证 overlay 数据通路。 */
return AUDIO_SUCCESS;
}
static aef_component g_ha_audio_customer_aef_entry = {
.name = (const td_char *)"customer_aef",
.type = AEF_TYPE_CUSTOMER,
.version = 0x00800001,
.create = customer_aef_create,
.destroy = customer_aef_destroy,
.set_parameter = customer_aef_set_parameter,
.get_parameter = customer_aef_get_parameter,
.proc_frame = customer_aef_proc_frame,
};
define_component(AEF, g_ha_audio_customer_aef_entry)
以上代码来自当前 aef_lib0 适配层,作为可编译的透传基线。确认该基线构建、打包和运行成功后,再仅替换 customer_aef_proc_frame() 内部的 PCM 处理,并保留参数长度校验、组件注册和资源释放路径。插件类型应以当前 /src/application/audio/sample_dsp_overlay/aef/include/audio_aef.h 支持的枚举和产品的加载策略为准。
编译、打包、运行和验证
完成适配后,依次执行下方“编译命令”和“生成算法镜像包”的步骤,将生成的 DSP overlay 纳入产品镜像。具体构建、烧录操作仍以 CLI 快速入门为准。
sample_aef 的 cust 分支只调用 uapi_snd_set_port_aef_enable() 打开或关闭 UAPI_AEF_TYPE_CUSTOMER,不会下发自定义参数。算法需要参数时,应在应用中调用 uapi_snd_set_aef_param();PEQ、DRC 的参数读写流程可参考 /src/application/audio/sample_ao/sample_aef.c,接口声明见 /src/drivers/drivers/driver/audio/include/soc_uapi_sound.h,媒体服务封装接口见 AudioManagerSetAefParam。
注意事项与常见问题
调试与常见问题
| 现象 | 优先排查 |
|---|---|
| 插件可编译但没有被调用 | 检查 define_component、plugins Makefile、插件 bin 名称和 overlay 打包目标是否一致。 |
| 加载或运行异常 | 检查 C 库依赖是否已加入 overlay_func->func 转发表,以及工具链、许可证和 DSP 镜像是否匹配。 |
| 参数下发失败或音效异常 | 检查 MCU/DSP 参数结构的版本、长度、对齐和命令号;先验证默认参数。 |
| 听感没有变化 | 确认播放路径经过目标 SOUND 端口、插件类型已使能,使用动态范围较大的固定 PCM 做 A/B 对比。 |
| 爆音、断音或延迟变大 | 检查 PCM 格式、帧长、算法耗时、内存和缓冲区;不要在 proc_frame 中执行阻塞操作。 |