音频编解码与音源
本文档介绍 AC79NN AIoT SDK 中的音频编解码体系与音源管理机制,涵盖音频服务器(audio_server)命令协议、解码器/编码器任务、各类编解码算法(MP3、WAV、MIDI、OPUS/Silk、JLA、DNS、Speex)的配置与使能方式,以及数字音量、混音等音源处理链路。
Purpose and Scope
本页面聚焦 SDK 的 音频编解码(Audio Codec)与音源(Audio Source) 能力,说明:
- 音频服务器的解码/编码命令协议与数据结构(
include_lib/server/audio_server.h); - 各编解码算法的使能宏与运行参数(
apps/common/audio_music/audio_config.c); - 解码器、编码器、混音等音频任务的注册与调度(各
app_main.c中的任务表); - 数字音量、音效默认参数等音源处理组件(
apps/common/audio_music/目录)。
以下相关主题由兄弟页面负责,本页不做展开:音频外设驱动(DAC/ADC 硬件层)、USB 音频(apps/common/usb/host/audio.c)、MIDI 琴键控制(apps/common/audio_music/midi/)、LLM 语音输入(apps/common/LLM/audio/)。
概述
在 AC79NN 这类 AIoT SoC 上,音频是一条贯穿采集(ADC)→ 编码 → 传输 → 解码 → 混音 → 输出(DAC)的全链路。SDK 将这条链路抽象为「任务 + 服务 + 算法库」三层结构:
- 音频服务器(audio_server):以消息命令形式对外提供统一的解码/编码控制接口,应用通过
AUDIO_DEC_*系列命令操作解码器生命周期; - 音频任务(audio_decoder / audio_encoder / audio_mix):独立 RTOS 任务,承载解码、编码与混音的数据搬运和调度;
- 编解码算法库:通过编译期宏(
CONFIG_MP3_DEC_ENABLE、CONFIG_WAV_DEC_ENABLE等)裁剪,支持 MP3、WAV、MIDI、OPUS/Silk、JLA、DNS、Speex 等格式,并在audio_config.c中集中配置运行参数。
这种分层设计的意图在于:格式识别、参数调优、任务资源分配三者解耦——应用只面向统一命令,算法库可独立裁剪以控制 Flash/RAM 占用,任务优先级与栈大小则在应用入口集中注册,便于按产品形态(故事机、IPC、WiFi 摄像头、扫描盒)差异化配置。
架构
flowchart TD
subgraph sg_App["应用层 (apps)"]
AppMain["app_main.c<br/>音频任务注册表"]
AudioConfig["audio_config.c<br/>编解码参数配置"]
AudioVol["audio_digital_vol<br/>数字音量"]
end
subgraph sg_Server["音频服务层"]
AudioServer["audio_server<br/>命令协议 AUDIO_DEC_*"]
DecTask["audio_decoder 任务"]
EncTask["audio_encoder 任务"]
MixTask["audio_mix 任务"]
end
subgraph sg_Codec["编解码算法库"]
MP3["MP3 编/解码"]
WAV["WAV 解码"]
MIDI["MIDI 解码"]
OPUS["OPUS/Silk 解码"]
JLA["JLA 编/解码"]
DNS["DNS 编码"]
SPEEX["Speex 编码"]
end
subgraph sg_HW["硬件与数据流"]
ADC["ADC 采集"]
DAC["DAC 输出"]
end
AppMain --> AudioServer
AudioConfig --> AudioServer
AudioServer --> DecTask
AudioServer --> EncTask
DecTask --> MP3
DecTask --> WAV
DecTask --> MIDI
DecTask --> OPUS
DecTask --> JLA
EncTask --> JLA
EncTask --> DNS
EncTask --> SPEEX
EncTask --> ADC
DecTask --> MixTask
EncTask --> MixTask
MixTask --> AudioVol
AudioVol --> DAC
架构要点说明:
audio_server是应用与解码/编码任务之间的命令通道,AUDIO_DEC_*命令覆盖打开、启动、暂停、停止、快进快退、断点、音量、AB 复读、变速变调等全生命周期操作;audio_decoder任务通过try_open探测文件格式后绑定具体算法库实例,audio_encoder任务采集 ADC 数据并按使能宏选择编码器;audio_mix任务将多路解码/编码输出混合后经数字音量控制送入 DAC,audio_dac_ch_num固定为双声道(CH_TWO = 2);- 各算法库仅在对应
CONFIG_*_ENABLE宏定义时才编译进固件,audio_config.c中相应配置段随之生效,实现按需裁剪。
音频服务器命令协议
音频服务器对外暴露的是命令编号 + 参数的消息式接口,定义于 audio_server.h。解码器全部操作通过以下宏进行:
#define AUDIO_DEC_OPEN 0 /*!< 打开解码 */
#define AUDIO_DEC_START 1 /*!< 开始解码 */
#define AUDIO_DEC_PAUSE 2 /*!< 暂停解码 */
#define AUDIO_DEC_STOP 3 /*!< 停止解码 */
#define AUDIO_DEC_FF 4 /*!< 快进 */
#define AUDIO_DEC_FR 5 /*!< 快退 */
#define AUDIO_DEC_GET_BREAKPOINT 6 /*!< 获取断点数据 */
#define AUDIO_DEC_PP 7 /*!< 暂停/播放 */
#define AUDIO_DEC_SET_VOLUME 8 /*!< 设置解码音量 */
#define AUDIO_DEC_DIGITAL_MUTE_SET 9 /*!< 设置当前解码的MUTE状态 */
#define AUDIO_DEC_PS_PARM_SET 10 /*!< 设置变速变调的参数 */
#define AUDIO_DEC_GET_STATUS 11 /*!< 获取当前解码器状态 */
#define AUDIO_DEC_AB_REPEAT_SET 12 /*!< 设置AB点复读播放 */
#define AUDIO_DEC_AB_REPEAT_CLOSE 13 /*!< 关闭AB点复读播放 */
#define AUDIO_DEC_GET_EFFECT_HANDLE 14 /*!< 获取对应音效算法的句柄 */
#define AUDIO_DEC_REPEAT_SET 15 /*!< 设置循环播放 */
设计意图分析:
- 命令从 0 开始递增且永不移除旧编号,保证固件升级后新旧应用二进制兼容;
OPEN(0)与START(1)分离,使应用可以在打开后先读取音频信息(get_audio_info)、配置音量或断点,再真正启动数据流——这是流式音频播放的标准两阶段模式;GET_BREAKPOINT(6)配合struct audio_dec_breakpoint用于断电续播:断点记录了文件位置与解码状态,重开后可直接从断点恢复,故事机/复读机类产品依赖此能力;SET_VOLUME(8)与DIGITAL_MUTE_SET(9)区分「解码器通道增益」与「静音开关」,二者独立,便于混音场景下单独控制某一路的响度而不影响其它音源;AB_REPEAT_SET/CLOSE(12/13)与REPEAT_SET(15)将复读/循环逻辑下沉到解码器内部,应用侧无需自行管理播放位置。
解码器输出回调
解码器通过输出回调与上层数据消费者解耦,接口为 struct audio_dec_output_ops:
struct audio_dec_output_ops {
void *(*get_buf)(void *priv, u32 *len); /*!< 获取buf空间 */
// ... 其余回调(put_buf / write 等)
};
解码器采用 pull 模型:消费者先通过 get_buf 申请一块 PCM 缓冲区,解码器将解码结果写入该缓冲区后再交还。这种「消费者驱动」设计使解码速率天然跟随 DAC 的消费速率,避免缓冲区溢出或欠载,是嵌入式音频中避免卡顿的关键。
编解码算法矩阵与使能宏
SDK 的编解码能力全部由编译期宏控制,相关运行参数集中在 apps/common/audio_music/audio_config.c。下表汇总了源码中可验证的格式支持:
| 格式 | 方向 | 使能宏 | 关键运行参数 |
|---|---|---|---|
| MP3 | 解码 | CONFIG_MP3_DEC_ENABLE | MP3_OUTPUT_LEN、MP3_TGF_AB_EN、MP3_SEARCH_MAX、MP3_TGF_POSPLAY_EN |
| MP3 | 编码 | CONFIG_MP3_ENC_ENABLE | mp3encode_input_mode |
| WAV | 解码 | CONFIG_WAV_DEC_ENABLE | WAV_MAX_BITRATEV、WAV_DECODER_PCM_POINTS、support_HR_FLAG |
| MIDI | 解码 | CONFIG_MIDI_CTRL_DEC_ENABLE | MIDI_TONE_MODE、MAX_DEC_PLAYER_CNT、MIDI_DEC_SR、MIDI_SAVE_DIV_ENBALE |
| OPUS/Silk | 解码 | CONFIG_OPUS_DEC_ENABLE | silk_fsN_enable、silk_fsW_enable |
| JLA | 编/解码 | CONFIG_JLA_ENC_ENABLE / CONFIG_JLA_DEC_ENABLE | JLA_DMS_VAL、JLA_DMS_FSINDEX、JLA_QUALTIY_CONFIG、JLA_PLC_EN、JLA_HW_FFT |
| DNS | 编码 | CONFIG_DNS_ENC_ENABLE | dns_enc_enable |
| Speex | 编码 | 任务注册 speex_encoder | 见 app_main 任务表 |
MP3 解码配置
#ifdef CONFIG_MP3_DEC_ENABLE
const int MP3_OUTPUT_LEN = 4;
const int MP3_TGF_TWS_EN = 0;
const int MP3_TGF_AB_EN = 1;
const int MP3_TGF_FASTMO = 0;
const int MP3_SEARCH_MAX = 20;
const int MP3_TGF_POSPLAY_EN = 1;
#endif
MP3_TGF_AB_EN = 1 使能 AB 复读能力,MP3_SEARCH_MAX = 20 限制解码器在文件中的帧搜索次数(用于快速定位),MP3_TGF_POSPLAY_EN = 1 支持按位置播放(跳播)。这些参数配合服务器命令 AUDIO_DEC_AB_REPEAT_SET、AUDIO_DEC_FF/FR 使用,说明 MP3 解码器内置了定位与复读引擎,而非简单的顺序解码。
JLA 编解码配置
#if (defined CONFIG_JLA_ENC_ENABLE) || (defined CONFIG_JLA_DEC_ENABLE)
const int JLA_INT24bit_INOUT = 0;
//如果是1,则认为编码input的时候,读到的数据认为是int的类型,存放着24bit的数据。 解码output的时候也是int类型,存放24bit数据。
//如果为0,则 认为是short的。
const int JLA_DMS_VAL = 100; //配置: 25ms 50ms 75ms 100ms 帧
const int JLA_DMS_FSINDEX = 5; //采样率配置:8000:0, 16000:1 ,24000:2, 32000:3, 48000:4, 可配采样率:5 (0-4固定采样率,5为可变采样率)
const int JLA_QUALTIY_CONFIG = 1; //可选1/2/3/4
const int JLA_PLC_EN = 1; //置1做plc,置0的效果类似补静音包
const int JLA_HW_FFT = 0; //置1使用硬件模块FFT, 置0使用软件模块FFT
#endif
JLA 是杰理自有的低码率语音编码格式,用于对讲/录音场景。JLA_DMS_FSINDEX = 5 表示支持可变采样率(8k/16k/24k/32k/48k 自适应),JLA_PLC_EN = 1 开启丢包隐藏(PLC)——在网络丢包时通过波形外推掩盖丢包,而非直接补静音,显著提升无线对讲的听感;JLA_HW_FFT 允许在具备硬件 FFT 的平台上卸载计算负载。
WAV 解码配置
#if defined CONFIG_WAV_DEC_ENABLE
// wav最大支持比特率,单位kbps
const int WAV_MAX_BITRATEV = (96 * 2 * 32);
// 解码一次输出点数,建议范围32到900,例如128代表128对点
const int WAV_DECODER_PCM_POINTS = 128;
// 是否支持64k,88.2k,96k采样率
const int support_HR_FLAG = 1;
WAV_DECODER_PCM_POINTS = 128 控制每次解码输出的 PCM 点数(128 对点 = 256 样本),直接决定解码中断频率与缓冲深度;support_HR_FLAG = 1 使能 64k/88.2k/96k 高采样率,用于 Hi-Res 音频播放。设计上 WAV 解码器对输出点数和比特率做了显式上限约束,防止畸形 WAV 文件导致内存越界。
OPUS/Silk 解码配置
#ifdef CONFIG_OPUS_DEC_ENABLE
const int silk_fsN_enable = 1; //支持8-12k采样率
const int silk_fsW_enable = 1; //支持16-24k采样率
#endif
OPUS 解码器(含 Silk 窄带/宽带模式)面向低码率语音通信:silk_fsN_enable 支持 8–12k 窄带采样率,silk_fsW_enable 支持 16–24k 宽带采样率。两档开关允许产品按通话质量需求裁剪,窄带省带宽、宽带保音质。
MIDI 解码配置
#ifdef CONFIG_MIDI_CTRL_DEC_ENABLE
#ifdef CONFIG_MIDI_DEC_ADDR
const int MIDI_TONE_MODE = 0; //音色访问方式 0为地址访问(仅支持在内置flash),1为文件访问(内置、外挂flash,sd,u盘均可)
#else
const int MIDI_TONE_MODE = 1;
#endif
const int MAINTRACK_USE_CHN = 0; //主旋律选定方式0 为轨道 1为通道
const int MAX_DEC_PLAYER_CNT = 18; //MIDI解码最大同时播放的key数,立体声音色按下一个key 占播放两个key
const int MAX_CTR_PLAYER_CNT = 18; //MIDI琴最大同时播放的key数,立体声音色按下一个key 占播放两个key
const int NOTE_OFF_TRIGGER = 0; //MIDI琴NOTE_OFF回调,设置为1 time 传0不回调
const int MIDI_TONE_CURVE = 1; //音色文件访问时,如果需使用包络必需置为1
const int MIDI_SAVE_DIV_ENBALE = 1; //小节回退功能,如不使用该功能可置为0。减少midi解码运行buf
const int MIDI_DEC_SR = 44100; //输出采样率配置
#endif
MIDI 解码器支持两种音色访问方式(内置 Flash 地址访问 / 文件访问),MAX_DEC_PLAYER_CNT = 18 限定了最大复音数(立体声音色占 2 个 key),MIDI_DEC_SR = 44100 固定输出采样率。MIDI_SAVE_DIV_ENBALE 控制小节回退功能的运行时缓冲,关闭可减小解码运行内存——这是嵌入式产品典型的「功能 ↔ 内存」权衡开关。
核心流程:解码播放生命周期
一个典型的音频解码播放流程(如播放一首 MP3)如下:
sequenceDiagram
participant App as 应用层
participant Svr as audio_server
participant Dec as audio_decoder 任务
participant Codec as 算法库 (MP3/WAV/MIDI...)
participant Mix as audio_mix/DAC
App->>Svr: AUDIO_DEC_OPEN(文件)
Svr->>Dec: 创建解码器实例
Dec->>Codec: try_open() 探测格式
Codec-->>Dec: 格式匹配成功
Dec->>Codec: get_audio_info() 读取采样率/声道
Codec-->>Svr: audio_finfo 信息回传
App->>Svr: AUDIO_DEC_SET_VOLUME / 断点恢复(可选)
App->>Svr: AUDIO_DEC_START
Svr->>Dec: 启动解码循环
loop 播放循环
Dec->>Codec: 解码一帧
Codec-->>Dec: PCM 数据 (经 get_buf 回调)
Dec->>Mix: 写入混音缓冲区
Mix-->>Dec: DAC 消费完成 (pull)
end
App->>Svr: AUDIO_DEC_PAUSE / AUDIO_DEC_PP
App->>Svr: AUDIO_DEC_STOP
Svr->>Dec: 释放解码器实例
流程要点:
- OPEN → try_open 探测:解码器对文件依次尝试各算法库的
try_open,首个匹配者接管。多格式自动识别能力由此实现,应用无需指定格式; - 两阶段启动:
OPEN只完成资源分配与格式绑定,START才真正开始拉取数据,中间可插入音量、断点、AB 复读等参数设置; - pull 消费模型:解码循环中 DAC 通过
audio_dec_output_ops.get_buf驱动 PCM 消费,解码速率与播放速率自动同步; - 暂停/停止语义分离:
PAUSE保留解码器实例可恢复,STOP彻底释放,二者内存占用差异显著,长暂停场景应使用 PAUSE,切换曲目应使用 STOP。
音源与任务系统
SDK 以 RTOS 任务承载音频数据流,任务表在各应用的 app_main.c 中集中注册。以 demo_DevKitBoard/app_main.c 为例:
{"audio_decoder", 30, 1024, 64 },
{"audio_encoder", 12, 384, 64 },
各应用的任务配置体现了产品形态决定资源分配的设计:
| 应用 | audio_decoder (优先级/栈) | audio_encoder (优先级/栈) | audio_mix | 备注 |
|---|---|---|---|---|
| demo_audio | 未注册解码任务 | 12/384/64 | 28/512/0 | 偏编码演示 |
| demo_DevKitBoard | 30/1024/64 | 12/384/64 | 28/512/0 | 编解码均衡 |
| wifi_camera | 30/1024/64 | 14/1024/64 | 27/512/64 | 编码栈翻倍,供视频流 |
| wifi_ipc | 30/1024/64 | 14/1024/64 | 27/512/64 | 同上 |
| scan_box | 未注册解码任务 | 12/384/64 | 未注册 | 纯采集编码 |
| wifi_story_machine | 未注册解码任务 | 12/384/64 | 28/512/0 | 附带 speex_encoder |
各应用任务表来源:demo_audio/app_main.c、wifi_camera/app_main.c、wifi_ipc/app_main.c、wifi_story_machine/app_main.c、scan_box/app_main.c
关键观察:
audio_decoder栈需求(1024)明显大于audio_encoder(384–1024),因为解码器需容纳帧搜索、断点、AB 复读等状态;- IPC/摄像头类应用将
audio_encoder栈增至 1024 并提高优先级至 14,以满足音视频同步的低延迟要求; audio_mix任务在部分纯采集应用(scan_box)中不注册——混音只服务于多路播放场景,按需裁剪可省下任务栈 RAM;speex_encoder(13/512/0)作为独立编码任务存在,说明 Speex 与通用 encoder 任务分离,便于单独控制码率与资源。
数字音量与音源处理
音源输出路径上,audio_digital_vol(数字音量)负责在混音后、DAC 前做增益控制,位于 apps/common/audio_music/audio_digital_vol.c/h。它与服务器命令 AUDIO_DEC_SET_VOLUME 配合:后者控制单路解码器增益,前者控制全局输出音量。分层音量设计的目的是让「单音源音量」与「整机音量」独立可调,混音场景下避免一路音量调节影响其它音源。
音效默认参数(audio_eff_default_parm.c)与变速变调(PS,CONFIG_AUDIO_PS_ENABLE)挂接在解码输出之后,通过 AUDIO_DEC_GET_EFFECT_HANDLE 获取算法句柄后配置参数,实现复读机的变速不变调朗读等功能。
配置选项
以下配置项全部定义于 audio_config.c,受对应 CONFIG_*_ENABLE 宏保护,仅当宏开启时生效。
全局音频链路
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
audio_irq_sr_points | int | 160 (AEC: 320) | 每次中断需读取的 PCM 点数,AEC 场景加倍 |
audio_src_temp_buf_size | int | points*4*3 (AEC: ×2) | 采样率转换(SRC)临时缓冲大小 |
audio_sync_temp_buf_size | int | points*4*3 (AEC: ×2) | 同步处理临时缓冲大小 |
audio_ps_temp_buf_size | int | points*4*10 (AEC: ×2) | 变速变调(PS)临时缓冲大小 |
audio_src_flt_in_sram | int | 1 | SRC 滤波器是否放置于 SRAM(低延迟访问) |
audio_dac_ch_num | int | 2 (CH_TWO) | DAC 输出通道数,固定双声道 |
audio_mix_en | u8 | 0/1 (CONFIG_AUDIO_MIX_ENABLE) | 混音功能使能 |
config_audio_dac_auto_src_en | u8 | 0 | DAC 自动采样率转换使能 |
audio_mix_temp_buf_size | int | points*2*4*ch (低功耗: ×10) | 混音临时缓冲大小 |
各编解码器参数
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
MP3_OUTPUT_LEN | int | 4 | MP3 解码输出长度配置 |
MP3_TGF_TWS_EN | int | 0 | MP3 TWS 双耳传输使能 |
MP3_TGF_AB_EN | int | 1 | MP3 AB 复读使能 |
MP3_SEARCH_MAX | int | 20 | MP3 最大帧搜索次数(快速定位) |
MP3_TGF_POSPLAY_EN | int | 1 | MP3 按位置播放使能 |
mp3encode_input_mode | int | 1 | MP3 编码输入模式(1 为 short 输入) |
WAV_MAX_BITRATEV | int | 96232 | WAV 最大支持比特率(kbps) |
WAV_DECODER_PCM_POINTS | int | 128 | WAV 单次解码输出点数(32–900) |
support_HR_FLAG | int | 1 | 支持 64k/88.2k/96k 高采样率 |
MIDI_TONE_MODE | int | 0/1 | 音色访问方式:0 地址访问,1 文件访问 |
MAINTRACK_USE_CHN | int | 0 | 主旋律选定方式:0 轨道,1 通道 |
MAX_DEC_PLAYER_CNT | int | 18 | MIDI 解码最大同时播放 key 数 |
MAX_CTR_PLAYER_CNT | int | 18 | MIDI 琴最大同时播放 key 数 |
MIDI_SAVE_DIV_ENBALE | int | 1 | 小节回退功能使能(关闭可省内存) |
MIDI_DEC_SR | int | 44100 | MIDI 输出采样率 |
silk_fsN_enable | int | 1 | Silk 8–12k 窄带采样率支持 |
silk_fsW_enable | int | 1 | Silk 16–24k 宽带采样率支持 |
dns_enc_enable | u8 | 1 (CONFIG_DNS_ENC_ENABLE) | DNS 编码使能 |
JLA_INT24bit_INOUT | int | 0 | JLA 24bit 输入输出(1 为 int 存 24bit) |
JLA_DMS_VAL | int | 100 | JLA 帧长:25/50/75/100 ms |
JLA_DMS_FSINDEX | int | 5 | JLA 采样率:0–4 固定,5 可变 |
JLA_QUALTIY_CONFIG | int | 1 | JLA 质量档位:1/2/3/4 |
JLA_PLC_EN | int | 1 | JLA 丢包隐藏(PLC)使能 |
JLA_HW_FFT | int | 0 | JLA 使用硬件 FFT(1)或软件 FFT(0) |
API 参考
音频编解码的公共接口由 audio_server.h 定义,核心为命令宏与两个数据结构。
解码命令宏
AUDIO_DEC_OPEN(0) ~ AUDIO_DEC_REPEAT_SET(15) 共 16 条命令,语义见上文「音频服务器命令协议」。应用通过音频服务器统一入口发送命令,命令编号即协议版本,向后兼容。
struct audio_dec_breakpoint
struct audio_dec_breakpoint {
int len; /*!< buf长度 */
// ... 断点数据缓冲区
};
用途: 配合 AUDIO_DEC_GET_BREAKPOINT 获取、AUDIO_DEC_OPEN 传入断点实现断电续播。len 标明断点数据长度,调用方需根据 len 分配/校验缓冲区。
struct audio_dec_output_ops
struct audio_dec_output_ops {
void *(*get_buf)(void *priv, u32 *len); /*!< 获取buf空间 */
// ... 其余回调
};
参数:
priv(void*):消费者私有上下文;len(u32*):入参为期望的缓冲区长度,出参为实际分配长度。
返回: PCM 缓冲区指针;返回 NULL 表示暂无可消费空间(解码器应等待)。
解码器操作接口
struct audio_dec_ops 中可验证的成员:
| 方法 | 签名 | 职责 |
|---|---|---|
open | void *(*open)(FILE *file, void *priv, const struct audio_dec_output_ops *ops, struct audio_dec_breakpoint *) | 打开文件并创建解码实例 |
try_open | void *(*try_open)(FILE *file, void *priv, const struct audio_dec_output_ops *ops, struct audio_dec_breakpoint *) | 格式探测后尝试打开 |
get_audio_info | int (*get_audio_info)(void *, struct audio_finfo *info) | 获取采样率/声道等信息 |
设计意图: try_open 与 open 分离,使多格式自动识别成为可能——服务器依次调用各算法库的 try_open 探测格式,匹配成功后才走正式 open,避免打开失败时留下半初始化资源。
故障模式、边界情况与并发
格式识别失败
try_open 依次探测所有已使能的算法库,若全部失败则 AUDIO_DEC_OPEN 返回错误,应用需提示「不支持的格式」。源码层面的防护在于各解码器的显式上限校验:例如 WAV 解码器对 WAV_MAX_BITRATEV 和 WAV_DECODER_PCM_POINTS 的约束,防止畸形文件触发越界读写。
缓冲区欠载/溢出
解码器采用 get_buf pull 模型:当 DAC 消费慢时 get_buf 返回 NULL,解码循环自然阻塞,避免 PCM 溢出;当消费快时解码器持续产出,依赖混音缓冲(audio_mix_temp_buf_size)吸收抖动。缓冲区大小由 audio_irq_sr_points 及其衍生宏统一推导,修改中断点数时必须同步评估各缓冲是否足够,否则会出现爆音或卡顿。
并发与互斥
- 解码器实例与应用控制命令分属不同任务:应用发
AUDIO_DEC_*命令,解码任务执行数据流,二者通过服务器消息队列串行化,命令不会并发进入解码器状态机; audio_decoder、audio_encoder、audio_mix为独立任务,共享 PCM 数据通过缓冲区和回调交接,不共享可变全局状态;- 音频中断(
audio_irq_sr_points定义节奏)与任务上下文并发访问 DAC 时,由驱动层中断保护;应用侧切勿在中断回调中直接调用解码命令。
资源限制
- MIDI 复音数受
MAX_DEC_PLAYER_CNT = 18限制,立体声音色按 2 个 key 计,超出部分将被丢弃(源码注释明确该语义); - 解码任务栈 1024 字、编码任务栈 384–1024 字,是各算法库最坏情况的余量值;新增算法库或加大缓冲区时需复核任务栈,栈溢出在本 SDK 中通常表现为随机崩溃或解码停顿,无显式报错。
AEC 场景的采样点放大
CONFIG_AEC_USE_PLAY_MUSIC_ENABLE 开启时 audio_irq_sr_points 从 160 翻倍为 320,SRC/SYNC/PS 缓冲同步放大。这是因为回声抵消需要更长的分析窗;未同步放大缓冲会导致 AEC 处理欠载。同理,低功耗模式(CONFIG_LOW_POWER_ENABLE)下混音缓冲由 4 倍放大到 10 倍,用于吸收低功耗唤醒延迟。
性能与运维考虑
- 中断节奏:
audio_irq_sr_points = 160意味着每次音频中断搬运 160 点 × 4 字节 × 声道数,中断频率 ≈ 采样率/160(44.1kHz 下约 276 次/秒)。该值决定了 CPU 负载与延迟的平衡点,AEC/低功耗场景需按上文规则调整; - 内存占用量级:解码/编码/混音任务栈、SRC/SYNC/PS 临时缓冲均在
app_main.c与audio_config.c中显式声明,产品化时可用任务表里的栈值直接估算音频子系统 RAM 占用; - 按产品裁剪:纯采集产品(scan_box)可不注册
audio_mix与audio_decoder;纯播放产品可不注册audio_encoder;未使用的编解码宏应保持关闭,从固件中剔除对应算法库以减小 Flash 占用; - 调试手段:
audio_config.c顶部定义了AUDIO_ENCODER/AUDIO_DECODER的 log tag(v/d/i/w/e五级),由CONFIG_DEBUG_LIB控制开合,排查编解码问题时可临时打开 verbose 级别观察帧级日志。
扩展点
- 新增编解码格式:实现
struct audio_dec_ops的try_open/open/get_audio_info及输出回调契约,在解码任务中注册;解码器的运行参数仿照现有格式在audio_config.c中添加CONFIG_XXX_ENABLE宏保护段; - 音效挂接:通过
AUDIO_DEC_GET_EFFECT_HANDLE(14) 获取音效算法句柄,在解码输出后、混音前插入自定义音效;默认参数可写入audio_eff_default_parm.c; - 变速变调:
AUDIO_DEC_PS_PARM_SET(10) 设置 PS 参数,audio_ps_temp_buf_size为 PS 预留了独立缓冲,复读机类产品可直接复用该通道; - 音量策略:单路增益走
AUDIO_DEC_SET_VOLUME,整机音量走audio_digital_vol;需要独立音量曲线(如 AGC)时可替换数字音量实现而不动解码器; - 任务资源重配:各应用的
app_main.c任务表是唯一资源入口,新增音频通道(如双解码播放)时按{名称, 优先级, 栈大小, 预留}格式追加即可。