跳转至

音频驱动开发指南

本文档介绍 HiDiTing V100 音频子系统的基本特性、组件关系和典型场景开发流程。文档直接以 SDK src/application/audio 中已有的音频场景代码为参考,开发者可通过内置 AT^AUDIO 命令验证场景,并据此阅读和修改业务代码。


音频驱动背景知识

音频子系统概述

HiDiTing V100 音频子系统包含输入采集、数据适配、播放、编解码和语音算法等能力。应用可使用服务层接口,也可参考 src/application/audio 的已有场景代码理解底层 UAPI 的初始化、建链、运行和释放顺序。

音频子系统架构图

组件基本特性

组件 基本特性 典型使用场景 代码和接口参考
SYS 音频全局初始化、产品形态、场景、音量和静音管理 所有音频业务的生命周期管理 AudioManagerInitAudioManagerSetVolume
ADP 在输入、算法、编解码和播放组件间适配流、帧和缓冲 AI→AENC、AI→SOUND、SEA 链路 /src/drivers/drivers/driver/audio/include/soc_uapi_adp.h
SOUND / AO 输出设备、端口、Track、音量和音效管理 PCM 播放、解码播放、回环 AudioStreamOutInitAudioStreamOutPlay
AI 从 ADC、PDM、I2S 等端口采集 PCM 录音、回环、实时编码 AudioStreamInInitAudioStreamInStart
AENC 将 PCM 编码为 SBC、mSBC、OPUS、MP3 等码流 录音压缩、语音上行、存储 AudioCodecFormat/src/drivers/drivers/driver/audio/include/soc_uapi_aenc.h
ADEC 将压缩音频码流解码为 PCM 本地文件、网络或蓝牙码流播放 AudioCodecFormat/src/drivers/drivers/driver/audio/include/soc_uapi_adec.h
SEA 语音增强和算法引擎管理,可插入 AEC、降噪等能力 语音通话、ASR 前处理 AudioManagerSetSeaEnableAudioManagerSetSeaParam
VAD 识别静音、说话开始和结束 按需录音、低功耗语音业务 /src/drivers/drivers/driver/audio/include/soc_uapi_sea.h
VENDOR Codec、电源、时钟、端口路由与板级设备适配 新板卡、外部 Codec、PA/MIC 路由 audio/vendor
ANC / HAID 主动降噪、助听等产品化算法能力 耳机、助听类产品 受产品功能开关、算法参数和校准数据控制

SYS、ADP 与 SOUND 的职责

SYS 不直接处理 PCM,却决定音频实例能否按正确的场景、音量和生命周期运行。ADP 是组件间的数据适配层,负责向下游提供流或帧;SOUND 则管理播放端口和 Track。一个典型实时场景的资源顺序是:SYS/ADP 初始化 → 创建输入或解码实例 → 创建 SOUND Track → 建立连接 → 启动数据流 → 反向停止和释放

SOUND、输出端口、Track 与 Cast

概念 含义 关键接口 使用边界
SOUND 一个播放设备实例,持有输出格式、端口和音效配置 uapi_snd_openuapi_snd_close 先打开 SOUND,才可创建 Track 或配置端口
输出端口 SOUND 的实际或逻辑输出目的地,如 DAC、I2S、BT、CAST uapi_snd_out_port_attruapi_snd_set_track_mode PCM 格式必须与端口能力匹配
Track SOUND 内承载一条 PCM 输入流的播放通道,可单独设音量、启动和停止 uapi_snd_create_trackuapi_snd_track_startuapi_snd_track_stop 多 Track 可由 SOUND 混音,Track 是 ADP 的常见下游
Cast SOUND 的逻辑输出端口,不连接物理扬声器;用于把播放侧 PCM 转送给 AENC 等下游 UAPI_SND_OUT_PORT_CAST0uapi_snd_attach_output 适合“播放侧 PCM 再编码/转发”,不能替代 DAC/I2S 输出

SOUND设备关系图

图示说明: SOUND 实例处于播放侧中心位置。上游组件可经 ADP 将 PCM 送到 Track;Track 再按 SOUND 配置输出到 DAC、I2S、蓝牙等物理端口,或输出到 CAST 逻辑端口。开发时应先确定最终输出端口,再创建对应 SOUND 和 Track,避免出现“Track 已启动但输出端口未配置”的无声问题。

SOUND设备框图

图示说明: 一个 SOUND 可以管理多个输出端口和 Track。端口属性决定设备侧 PCM 格式和路由,Track 属性决定单路业务的输入、音量和播放状态;音效参数属于 SOUND/端口侧,不能只通过修改输入 PCM 属性替代。

原始架构中定义 UAPI_SND_0UAPI_SND_1UAPI_SND_2 三个 SOUND 设备供组合使用;同一时刻最多允许打开 2 个 SOUND 设备、4 路 Track 和 4 个 OUTPORT。Track 输入可在 SOUND 内完成重采样和混音后输出。Track 音量和 OUTPORT 音量分两级设置,均为绝对音量,范围为 -81 dB+18 dB,步长为 0.125 dB

说明: CAST 使能后会形成虚拟 CAST OUTPORT,可投射系统解码输出的音频数据。它适合连接编码或分析下游,不等同于物理扬声器输出。

ADP 到 SOUND 的数据连接关系

下图不是前两张 SOUND 设备图的重复:前两图解释 SOUND、Track、OUTPORT 的设备模型;本图仅说明一条播放数据从 ADP 接入 Track 后,如何分别流向物理端口或 CAST 下游。它用于理解 PCM 播放、回环和“播放侧 PCM 再编码”场景的 attach_output 调用位置。

音频数据连接关系图

SOUND 默认属性说明

SOUND 的默认属性不是固定常量,而是由目标板、Codec 和产品配置决定。创建前应先调用 uapi_snd_get_default_attr() 获取默认属性,再只覆盖业务必须修改的字段。

默认属性项 获取方式 覆盖时机 说明
输出端口 uapi_snd_get_default_attr() 切换 DAC/I2S/CAST 等路由时 必须与 Vendor Codec 和板级连线一致
采样率、位宽、声道 默认 uapi_snd_attr 输入 PCM 或下游设备格式变化时 必须与 Track、ADP 和端口能力兼容
Track 属性 uapi_snd_get_track_default_attr() 创建 Track 前 用默认值创建后,再按业务设置音量和模式
音效 Profile / Bypass SOUND 默认配置 启用特定音效或场景时 应在 SOUND 打开后、Track 运行前设置

AI 属性与数据流

AI 属性 含义 配置要点
ai_port 音频输入端口,如 ADC、PDM、I2S 必须与板级 Codec、MIC 和引脚路由一致
pcm_attr.sample_rate 采样率 与下游 ADP、SEA、AENC 或 SOUND 的格式兼容
pcm_attr.bit_depth PCM 位宽 常用 16 bit;高位宽链路需确认端口和算法能力
pcm_attr.channels 声道数 单 MIC 常为单声道;双麦算法需匹配实际 MIC 数
sample_per_frame 每帧采样点数 决定帧时长、缓冲大小和算法处理粒度
volume / mute 输入增益和静音 仅在端口支持时生效;过高增益会造成削波
ref_attr 参考信号属性 AEC 等场景需指定参考输出端口

AI的数据流处理过程

图示说明: 图中 AI 只负责从输入端口采集 PCM;ADP 才是供应用读取、缓存或继续挂接下游组件的数据出口。SEA、AENC、SOUND 等组件可作为 AI 或 ADP 的下游,使同一份 PCM 进入算法、编码或播放链路。

AI 默认参数说明

下表是语音采集场景的默认基线,用于快速验证 ADC/PDM/I2S 输入。实际项目应先通过 uapi_ai_get_default_attr() 取得目标板默认属性,再根据 Codec、MIC 数量和算法要求覆盖参数。

参数 语音采集默认基线 配置原因
采样率 16 kHz 满足常见语音、mSBC、ASR/VAD 输入需求
位宽 16 bit 兼顾语音精度、带宽和多数算法输入要求
声道数 1 单 MIC 采集;双麦算法按实际 MIC 数设置
每帧采样点 sample_rate / 100 对应 10 ms 帧长,便于实时处理和算法调度
输入增益 0 dB 先以无附加增益验证硬件,确认后再调节
静音 关闭 仅在业务需要时打开
参考信号 默认关闭 AEC 等场景才开启,并指定参考输出端口

说明: AI 没有可供应用直接读取的音频数据出口。需要创建一路 ADP,并通过 uapi_ai_attach_output(h_ai, h_adp) 将 ADP 绑定到 AI 输出;应用或下游组件再从 ADP 获取 PCM。若下游是 SEA 或 AENC,则将 AI 输出直接绑定到对应句柄,由该组件继续处理。

AI→ADP 的关键顺序为:获取默认 AI 属性 → 设置端口和 PCM 属性 → 创建 ADP → 打开 AI → 设置音量/静音 → uapi_ai_attach_output() 绑定下游 → uapi_ai_start() 启动采集。停止时先停止 AI,再解除绑定、关闭 AI、销毁 ADP。

音频参数与接口说明

常用服务层接口可参考 AudioManager API;底层接口以表格中的头文件声明为准。


音频特性场景开发

内置 AT 命令的命令名为 AUDIO,定义在 /src/middleware/utils/at/at_audio_cmd/at/at_audio_cmd_table.h。发送 AT^AUDIO=<命令行> 后,调用链如下:audio_at_cmd_process()audio_at_cmd_handle()audio_para_to_args()audio_execute_function()

audio_execute_function() 的声明在 /src/application/audio/sample_audio.h,实现位于 /src/application/audio/sample_audio.c;该函数在 g_audio_func[] 表中查找首个参数对应的场景函数并执行。例如 AT^AUDIO=sample_ai_ao ... 最终调用 sample_ai_ao()

/* at_audio.c:AT 参数进入现有音频场景代码的入口 */
audio_para_to_args(para_str, &argc, msg_argv);
audio_execute_function(argc, msg_argv);
函数 作用 与场景流程的关系
audio_para_to_args() 按空格分割 AT^AUDIO 参数并分配 argv 把串口文本转换为场景函数参数
audio_at_cmd_handle() 复制 AT 原始参数、调用参数拆分,并在结束时释放内存 AT 层只负责入口和参数生命周期,不处理 PCM
audio_execute_function() g_audio_func 表中查找首个参数对应的场景函数并调用 连接 AT 与 sample_aisample_aosample_adec 等既有场景代码
audio_auto_exit_function() 新实时场景启动前停止已运行的场景;收到 q 时标记结束 防止音频资源被多个实时场景同时占用

本文示例命令以一站式 CLI 为主。实际开发可从以下三种环境中选择,推荐使用一站式 CLI。

开发环境 适用场景 使用指南
一站式 CLI(推荐) 快速完成目标选择、构建、烧录和串口监视 一站式 CLI 开发环境使用指南
HiSpark Studio for VS Code 图形化编辑、编译、烧录和调试 HiSpark Studio for VS Code 开发环境使用指南
WSL 与 Docker 在 Windows 上使用一致的 Linux 容器构建环境 WSL 与 Docker 环境使用指南

准备工作:按 一站式 CLI 开发环境使用指南 准备环境、构建和烧录;构建前必须确保 fbb doctor 成功。

PCM 播放场景(SOUND / AO)

功能说明:读取 PCM 文件,创建播放通路和 Track 后输出至 DAC 或 I2S,适用于提示音、音乐片段和扬声器验证。

音频脉冲编码调制播放流程

实现流程:确认 PCM 格式 → 初始化 SOUND/AO → 创建并启动 Track → 循环写入 PCM → 停止 Track → 释放资源。

代码走读:参考 /src/application/audio/sample_ao/sample_ao.c。它按“文件、音量、采样率、位宽、声道”解析参数;SOUND 负责 Track 和输出设备,AO 负责将 Track 数据输出到实际端口。

流程步骤 关键函数 逐函数说明
初始化 sample_ao_sys_init() 初始化 ADP 与 SOUND;失败时不进入设备和 Track 创建。
打开设备 sample_ao_open_snd() 获取默认 uapi_snd_attr,设置端口、采样率、位宽、声道和 AEF Profile,调用 uapi_snd_open()
创建通道 sample_ao_open_track() 获取 Track 默认属性,调用 uapi_snd_create_track(),再设置该 Track 音量。
建立数据连接 sample_ao_open_adp() 创建 ADP 并调用 uapi_adp_attach_output() 把 ADP 输出接到 Track。
送数播放 sample_ao_track_thread() 构造 uapi_audio_frame,读取 PCM,检查 ADP 空闲空间并送入播放链路。
启停释放 sample_ao_track_start_inst() / sample_ao_track_stop_inst() 依次启动/停止 Track 与送数线程;释放时按 ADP、Track、SOUND、SYS 的反向顺序关闭。

下面保留完整的最小初始化、送帧和释放顺序。实际应用应为每个接口补充返回值检查,并在失败分支中按相反顺序释放已创建资源。

uapi_adp_init();
uapi_snd_init();

uapi_snd snd_id;
uapi_snd_attr snd_attr;
uapi_snd_get_default_attr(snd_id, &snd_attr);
snd_attr.port_num = 1;
snd_attr.port_attr[0].out_port = UAPI_SND_OUT_PORT_I2S0;
snd_attr.channels = UAPI_AUDIO_CHANNEL_2;
snd_attr.bit_depth = UAPI_AUDIO_BIT_DEPTH_16;
snd_attr.sample_rate = UAPI_AUDIO_SAMPLE_RATE_48K;

td_handle h_snd = 0;
uapi_snd_open(&h_snd, snd_id, &snd_attr);

uapi_snd_track_attr track_attr;
uapi_snd_get_track_default_attr(&track_attr);
td_handle h_track = 0;
uapi_snd_create_track(&h_track, h_snd, &track_attr);

uapi_adp_attr adp_attr;
uapi_adp_get_def_attr(&adp_attr);
td_handle h_adp = 0;
uapi_adp_create(&h_adp, &adp_attr);
uapi_adp_attach_output(h_adp, h_track);
uapi_snd_track_start(h_track, TD_NULL);

while (task_active) {
    uapi_audio_frame frame;
    read_frame(&frame); /* 由应用实现,从文件或内存取得一帧 PCM。 */
    if (uapi_adp_send_frame(h_adp, &frame) != EXT_SUCCESS) {
        continue;
    }
}

uapi_snd_track_stop(h_track);
uapi_adp_detach_output(h_adp, h_track);
uapi_adp_destroy(h_adp);
uapi_snd_destroy_track(h_track);
uapi_snd_close(h_snd);
uapi_snd_deinit();
uapi_adp_deinit();
AT^AUDIO=sample_ao /mnt/data/test.pcm 0 48000 16 2

预期能听到 PCM 内容;无声音时先执行 AT^AUDIO=sample_proc ao,再检查 PCM 格式、输出端口、Codec、PA 电源和音量。

PCM 采集与录制场景(AI)

功能说明:AI 从 ADC、PDM 或 I2S 输入端口采集 PCM 并保存为文件,用于验证 MIC、输入路由和采样参数。

音频脉冲编码调制采集录制流程

实现流程:确认输入端口 → 初始化 AI/ADP → 配置 PCM 属性和增益 → 启动采集 → 写文件 → 停止 AI → 释放资源。

代码走读:参考 /src/application/audio/sample_ai/sample_ai.c。文件录制入口使用固定容量模型,参数为录制大小(MB)和输出文件;AI/AO 回环等实时入口也在该文件中实现。

流程步骤 关键函数 逐函数说明
解析和创建 sample_ai_entry() 解析录制容量和文件,分配实例并准备 PCM 属性。
准备下游 sample_ai_open_file() 创建 PCM 输出文件;文件失败时不启动 AI。
打开采集 sample_ai_open_ai() 填充 AI 端口和 PCM 属性,创建并启动 AI 输入。
建立处理实例 sample_ai_open_inst() 完成 ADP、AI 及可选 SEA 的资源打开。
启动与停止 sample_ai_start_inst() / sample_ai_stop_inst() 启动采集线程;停止 AI 后再关闭实例和文件。
AT^AUDIO=sample_ai 10 /mnt/data/ai.pcm

录制结束后用相同的采样率、位宽和声道播放该文件。文件为空时检查 MIC 偏置、AI 端口、文件系统写权限和 Codec 输入路由。

实时回环场景(AI → ADP → SOUND)

功能说明:将 AI 采集到的 PCM 经 ADP 直接送入播放通路,是验证输入、缓冲适配和输出设备的最短链路。

音频实时回环流程

实现流程:初始化 ADP、AI 和播放端 → 配置输入格式 → 创建并连接数据通路 → 同时启动采集与播放 → 发送 q 停止并按反向顺序释放。

代码走读:参考 /src/application/audio/sample_ai/sample_ai.csample_ai_ao()。该函数解析 -p/-c/-b/-s/-v 参数,并在内部完成 AI、ADP、SOUND 的实例建立和连接。

流程步骤 关键函数 逐函数说明
参数检查 sample_ai_ao_parse_cmd_line() 将端口、采样率、位宽、声道、音量及 Track 模式写入实例。
输出端准备 sample_ai_player_open() 创建播放侧对象和 SOUND Track,确定采集 PCM 的输出位置。
输入端准备 sample_ai_open_adp() / sample_ai_open_ai() 建立 ADP 与 AI,配置 AI 输入端口和 PCM 格式。
建链启动 sample_ai_ao_start_inst() 启动 AI 和播放链路,让 ADP 中的 PCM 持续流向 Track。
停止 sample_ai_ao_exit() 收到 q 后停止实例并反向释放 AI、ADP、播放器资源。
AT^AUDIO=sample_ai_ao -p adc0 -c 1 -s 16000
AT^AUDIO=sample_ai_ao q

预期对 MIC 说话后扬声器实时输出声音。出现啸叫时先降低音量、拉开 MIC 与扬声器距离或改用耳机;这是声学反馈,不应通过改变 ADP 参数掩盖。

用户送帧编码场景(AENC)

编码协议与输入默认约束

AENC 接收前级模块或用户送入的 PCM,按所选编码器产生码流供文件、网络或远端解码使用。编码前必须先根据协议确定输入 PCM 属性;PCM 文件本身不携带格式信息,不能仅依据文件扩展名判断。

协议 通道数 支持的典型采样率(kHz) 位宽(bit) 使用说明
SBC 1 / 2 16 / 32 / 44.1 / 48 16 常用于音乐和蓝牙音频
mSBC 1 16 16 常用于窄带语音和通话
OPUS 1 / 2 8 / 12 / 16 / 24 / 48 16 常用于低时延语音/网络传输
PCM 1 / 2 8 / 16 / 32 / 44.1 / 48 16 / 32 用于透传或无压缩处理
MP3 / AAC / FLAC 以解码器能力为准 以解码器能力为准 以解码器能力为准 主要用于 ADEC 解码播放;是否可用受目标配置约束

说明: 语音编码通常采用 16 kHz / 16 bit / 单声道;若编码器属性、AI 输出和下游传输属性不一致,可能造成编码失败、变速或杂音。

功能说明:将应用已有的 PCM 文件、内存数据或其他算法输出编码为压缩码流,适用于本地存储、网络上行和蓝牙语音。

音频编码输入约束图

实现流程:选择编码格式 → 创建 AENC 并设置 PCM 属性 → 启动编码器 → 循环送入 PCM 帧、获取码流 → 停止并销毁编码器。

代码走读:参考 /src/application/audio/sample_encode/sample_encode.c。其核心参数顺序为 pcm_file codec sample_rate bit_depth channels;产品改为实时送帧时,仍需保持编码器属性与输入 PCM 属性一致。

流程步骤 关键函数 逐函数说明
配置参数 sample_encode_parse_arg() / sample_encode_set_param() 解析 PCM 和 codec 属性,设置码率、帧长等编码参数。
初始化 sample_encode_sys_init() 初始化 AENC 与 ADP 公共环境。
输入输出 ADP sample_encode_open_adp_input() / sample_encode_open_adp_output() 建立 PCM 输入和编码码流输出的 ADP 通道。
创建编码器 sample_encode_open_aenc() 填充 uapi_aenc_attr 并创建 AENC 实例。
送帧 sample_encode_open_in_stream() / sample_encode_start_inst() 打开 PCM 来源并启动实例,按帧向编码器输入 PCM。
清理 sample_encode_stop_inst() / sample_encode_close_inst() 停止数据流后依次关闭 AENC、ADP 和文件。
AT^AUDIO=sample_encode /mnt/data/test.pcm sbc 48000 16 2

编码失败时优先检查 codec 名称及 PCM 的采样率、位宽、声道。部分语音编码格式只支持 16 kHz / 16 bit / 单声道

实时采集编码场景(AI → AENC)

功能说明:实时采集 AI PCM,通过 ADP 送入 AENC,编码结果可写文件或发往下游,适用于压缩录音和语音上行。

音频实时采集编码流程

实现流程:初始化 ADP、AI、AENC → 打开输出文件或下游播放器 → 创建输入实例 → 启动采集线程 → 获取码流 → 停止线程并反向释放。

代码走读:参考 /src/application/audio/sample_ai/sample_ai_aenc.c。该代码先打开文件、播放器和实例,再启动线程;这保证编码输出的去向在采集开始前已经就绪。

流程步骤 关键函数 逐函数说明
公共初始化 sample_ai_aenc_sys_init() 依次初始化 ADP、AI、可选 SEA 与 AENC。
建立对象 sample_ai_aenc_open_adp()sample_ai_aenc_open_ai()sample_ai_aenc_open_aenc() 创建 AI→ADP→AENC 的三个核心对象。
输出处理 sample_ai_aenc_open_file() / sample_ai_aenc_proc_stream() 有文件名时把编码码流写文件;无文件名时将码流送往下游播放器。
线程运行 sample_ai_aenc_thread() 循环从 ADP 获取流、处理码流并释放流。
启停 sample_ai_aenc_start_inst() / sample_ai_aenc_exit() 创建采集处理线程;q 触发停止、关闭对象和反初始化。
ret = sample_ai_aenc_open_file(inst);
ret = sample_ai_aenc_open_player(inst);
ret = sample_ai_aenc_open_inst(inst);
ret = sample_ai_aenc_start_inst(inst);
AT^AUDIO=sample_ai_aenc -p adc0 -c 1 -s 16000 -t opus -o /mnt/data/capture.opus
AT^AUDIO=sample_ai_aenc q

运行期间确认输出文件持续增长;若文件为空,依次查询 AT^AUDIO=sample_proc aiadpaenc,再检查端口和编码格式。

码流解码播放场景(ADEC)

功能说明:将 AAC、MP3、OPUS、SBC、mSBC 等压缩码流解码为 PCM,并交给 SOUND/AO 播放。

音频码流解码播放流程

实现流程:确认码流格式 → 创建 ADEC 并设置属性 → 连接播放端 → 启动解码 → 输入码流、获取 PCM → 停止并销毁。

代码走读:参考 /src/application/audio/sample_decode/sample_adec.c-i 指定文件或内存输入,-t 指定编码格式,-o play 表示解码后直接送入播放通路。

流程步骤 关键函数 逐函数说明
参数与数据源 sample_adec_parse_cmd_line() / sample_adec_open_data_io() 解析输入文件、codec 和输出方式,并初始化文件、内存或 ADP 数据 I/O。
公共初始化 sample_adec_sys_init() 初始化 ADEC 与 ADP 所需公共资源。
输入输出通道 sample_adec_open_adp_in() / sample_adec_open_adp_out() 输入端接收码流,输出端承接解码后的 PCM。
创建解码器 sample_adec_attr_cfg() / sample_adec_open_adec() 根据 codec 和 PCM 属性配置并创建 ADEC。
数据线程 sample_adec_data_in_thread() / sample_adec_data_out_thread() 分别持续送入码流、取出解码 PCM 并交给文件或播放 ADP。
启停 sample_adec_start_inst() / sample_adec_exit() 启动解码和数据线程;结束时先停线程再关闭 ADEC、ADP 与数据源。
AT^AUDIO=sample_adec -i /mnt/data/test.opus -t opus -o play

无声音或解码失败时,先确认文件实际格式与 -t 一致;不要把容器文件、裸码流和 PCM 混用。

语音识别与通话场景(SEA / ASR)

功能说明:SEA 用于语音增强和算法引擎管理;ASR 处理 PCM 识别任务;通话场景按是否启用 SEA 和编码格式构建双向音频链路。

语音识别通话流程

实现流程:初始化 ADP/AI → 按需初始化 SEA 并加载算法 → 初始化 AENC 或 ASR → 启动处理 → 获取结果或码流 → 卸载算法并反向释放。

代码走读:ASR 参考 /src/application/audio/sample_asr/sample_asr.c,SEA 场景参考 /src/application/audio/sample_sea/sample_sea.c,通话参考 /src/application/audio/sample_phone/sample_phone_apps.c。通话参数解析直接决定 SEA 和编码器属性:

流程步骤 ASR 关键函数 通话关键函数
初始化 sample_asr_sys_init():初始化 ADP、AI、可选 SEA 和识别环境 sample_phone_sys_init():初始化 ADP、AI、可选 SEA、AENC
打开链路 sample_asr_open_adp()sample_asr_open_ai()sample_asr_open_sea() sample_phone_open_adp()sample_phone_open_ai()sample_phone_open_sea()sample_phone_open_aenc()
处理 sample_asr_thread():从 ADP 取帧并执行识别任务 sample_phone_start_inst():启动通话数据链路
释放 sample_asr_exit():关闭实例、SEA、AI、ADP sample_phone_exit():停止实例并按反向顺序关闭所有对象
case 'm':
    return sample_phone_sea_status(opt_arg, inst); /* sea / nosea */
case 't':
    return sample_audio_get_acodec_id(opt_arg, &inst->acodec_id); /* pcm / msbc */
AT^AUDIO=sample_asr 1 /mnt/data/asr.pcm
AT^AUDIO=sample_phone -m sea -t msbc
AT^AUDIO=sample_phone q

ASR 依赖 NPU、模型和 CFG_SAP_ASR_SUPPORT;通话依赖板级双向音频能力。应查看识别/建链日志和 sample_proc seasample_proc aenc,不能仅根据 AT 返回值判断成功。

语音活动检测场景(VAD)

功能说明:VAD 判断静音、说话开始和结束,可用于按需录音、低功耗语音业务和减少上行数据。

语音活动检测流程

实现流程:初始化 AI/ADP/SEA/AENC → 设置 VAD 处理参数 → 启动采集与处理线程 → 输出活动状态 → 发送 q 停止线程和释放实例。

代码走读:参考 /src/application/audio/sample_asr/sample_vad_feed.c。该代码使用单例保护同一时刻只有一个 VAD 实例;退出时显式停止线程、关闭实例和文件。

流程步骤 关键函数 逐函数说明
参数与状态 sample_vad_feed_parse_cmd_line() / sample_vad_feed_set_proc() 解析 AI 端口、PCM 属性和编码选项,设置 VAD 处理状态。
打开资源 sample_vad_feed_open_adp()sample_vad_feed_open_ai()sample_vad_feed_open_sea()sample_vad_feed_open_aenc() 根据场景依次建立 AI、ADP、SEA、AENC。
活动检测 sample_vad_feed_thread() / sample_vad_feed_nomal_proc() 处理 ADP 流,按 VAD 状态缓存、编码或转存数据。
启停 sample_vad_feed_start_inst() / sample_vad_feed_exit() 启动线程;收到 q 后停止线程、关闭实例和文件。
if (strcmp(argv[1], "q") == 0) {
    return sample_vad_feed_exit();
}
return sample_vad_feed_entry(argc, argv);
AT^AUDIO=sample_vad_feed -p adc0 -c 1 -s 16000
AT^AUDIO=sample_vad_feed q

VAD 代码受 CFG_SAP_SMART_WATCH_PRODUCT 控制;若功能不可用,先确认产品配置和输入端口,再检查运行日志。

板级适配与高级能力(VENDOR / ANC / HAID)

VENDOR:参考 /src/application/audio/vendor。新增板卡应先完成 Codec 电源、时钟、引脚、MIC/PA 和 I2S 路由适配,再按“录制 → 回环 → 播放 → 编解码”验证。不要在业务代码中硬编码端口来规避板级配置问题。

ANC / HAID:分别由 sample_ahasample_haid 代码提供场景参考,仅在 CFG_SAP_ANC_SUPPORT=yCFG_SAP_HAID_SUPPORT=y 时纳入构建。它们还依赖耳机/助听硬件、算法参数和校准数据;未启用相应配置时不应将命令入口视为可用功能。


基于音频场景开发自己的应用

前面的 AT^AUDIO 用于运行和验证 SDK 已有场景。产品应用可使用 app_run 在系统启动时自动创建自己的任务,再在任务中按所选场景的流程调用音频接口。

app_run(func) 定义在 /src/middleware/utils/app_init/app_init.h,它将无参、无返回值的入口函数登记到启动段;系统启动时会统一调用已登记的应用入口。因此,app_run 负责何时启动应用,而 AI、ADP、SOUND、AENC 等接口负责如何建立音频业务

开发步骤

  1. 选择与业务最接近的现有场景,例如播放使用 sample_ao.c,录制使用 sample_ai.c,回环使用 sample_ai_ao(),实时编码使用 sample_ai_aenc.c
  2. 在应用目录新增 audio_app.caudio_app.hCMakeLists.txt,将应用纳入目标组件列表。
  3. audio_app_task() 中按本指南对应场景的“初始化 → 打开设备 → 创建 ADP/Track/编解码器 → attach → start → 运行 → stop → destroy/deinit”顺序实现业务。
  4. audio_app_entry() 中创建任务,并用 app_run(audio_app_entry) 登记启动入口。
  5. 启动后通过串口日志和 AT^AUDIO=sample_proc <module> 验证资源状态;不要让 app_run 入口直接执行长时间阻塞的音频循环。

文件结构

以下目录仅说明应用组织方式,名称可按产品工程调整:

/application/audio_app/
├── audio_app.c              # app_run 入口和音频任务
├── audio_app.h              # 应用配置和函数声明
└── CMakeLists.txt           # 应用构建规则

app_run 入口代码

#include "app_init.h"
#include "osal.h"
#include "audio_app.h"

#define AUDIO_APP_TASK_STACK_SIZE 0x1000
#define AUDIO_APP_TASK_PRIO       26

static void audio_app_task(void *arg)
{
    (void)arg;

    /*
     * 按所选场景实现:
     * 1. 获取默认属性并设置板级端口/PCM 参数;
     * 2. 初始化 SYS、ADP、AI/SOUND/AENC/ADEC;
     * 3. 创建实例并 attach 下游;
     * 4. start 后进入业务循环;
     * 5. 退出时按反向顺序 stop、destroy、deinit。
     */
    audio_app_start();
}

static void audio_app_entry(void)
{
    osal_task *task = NULL;

    osal_kthread_lock();
    task = osal_kthread_create((osal_kthread_handler)audio_app_task, NULL,
        "AudioAppTask", AUDIO_APP_TASK_STACK_SIZE);
    if (task != NULL) {
        osal_kthread_set_priority(task, AUDIO_APP_TASK_PRIO);
    }
    osal_kthread_unlock();
}

app_run(audio_app_entry);

代码说明: audio_app_entry() 只创建任务,避免启动框架被音频业务阻塞;audio_app_task() 承载完整音频生命周期;audio_app_start() 应由开发者按目标场景实现,不能直接照搬 AT 命令字符串。

CMakeLists.txt 示例

set(COMPONENT_NAME "audio_app")

set(SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/audio_app.c
)

set(PRIVATE_HEADER
    ${ROOT_DIR}/middleware/utils/app_init
    ${ROOT_DIR}/application/audio
)

set(WHOLE_LINK true)
set(MAIN_COMPONENT false)

build_component()

将该组件加入目标构建配置后,检查链接脚本是否保留 app_run 段:acore.prelds 中需要包含 KEEP (*(SORT(.zinitcall.app_run*.init)))。3322 EVB 的文件路径为 acore.prelds

验证要点

  • app_run 应用在开机阶段执行,日志会与启动日志混合输出。
  • 先用 AT^AUDIO 验证端口、PCM 格式和场景流程,再启用 app_run 应用,便于区分应用问题和板级音频问题。
  • 回环、录制、编码等实时业务必须提供退出条件;退出时按场景代码的反向顺序释放 AI、ADP、SOUND、AENC/ADEC 等资源。

注意事项

  • 同一时间不要启动多个占用同一 AI、ADP、SOUND 或 AENC 资源的实时场景;先发送对应的 q 停止命令。
  • 使用 AT^AUDIO=sample_proc ai|adp|ao|sea|adec|aenc 查询模块状态;必要时使用 sample_dump 抓取链路数据。
  • PCM 的采样率、位宽和声道必须在 AI、ADP、AENC/ADEC、SOUND/AO 各端保持兼容。
  • 路径必须位于目标系统已经挂载、且具备读写权限的文件系统;AT 参数以空格分隔,文件路径中不要包含空格。
  • sample_audio.c 会在启动新场景前自动尝试停止已运行场景,但产品代码仍应显式管理资源生命周期。

常见编译与运行错误

现象 优先检查
AT^AUDIO 命令不可用 AT_COMMAND_AUDIO 是否纳入目标配置,串口是否连接到正确固件
没有声音 PCM 格式、sample_proc ao、Codec/PA 电源、输出端口和音量
录音文件为空 AI 端口、MIC 偏置、输入路由、文件系统写权限
already running 上一个实时场景未发送 q,先停止对应场景
ASR、VAD、ANC、HAID 不可用 NPU/算法资源、CFG_SAP_ASR_SUPPORTCFG_SAP_SMART_WATCH_PRODUCT、ANC/HAID 功能开关
编码或解码失败 codec 名称、输入数据真实格式、采样率/位宽/声道及算法库