杰理 SDK 文档中心
首页
首页
  • SDK 概述与快速开始

    • SDK 概览与 AC791N 芯片平台
    • 环境搭建与编译指南
    • 烧录与固件升级
    • 工程结构导览
  • 产品方案应用

    • WiFi 摄像头方案
    • WiFi IPC 可视对讲方案
    • WiFi 故事机方案
    • 扫码枪 HID 方案
    • 开发板示例工程
  • 公共应用组件

    • 语音识别 ASR 引擎
    • LLM 与 AI 语音助手接入
    • 摄像头传感器驱动
    • UI 显示框架与驱动
    • USB 主机与设备栈
    • 文件系统与存储管理
    • 系统服务与外设管理
    • 生产测试与射频工具
  • 蓝牙协议栈

    • 经典蓝牙 BR/EDR
    • BLE 低功耗蓝牙
    • 蓝牙 Mesh 网络
    • 蓝牙扩展协议(RCSP/广播/无线麦克风)
  • WiFi 与网络协议栈

    • WiFi 驱动与网络模式
    • lwIP TCP/IP 协议栈
    • 网络安全与加密库
    • 应用层网络协议
    • 流媒体与音视频传输
    • 云平台接入 SDK
    • P2P 远程访问与设备互联
  • 芯片平台与驱动

    • wl82 平台与硬件加速
    • 外设驱动框架
    • 平台配置与固件打包工具
  • 媒体与音频引擎

    • 音频编解码与音源
    • 音效处理引擎
    • 视频与图像处理
  • 操作系统与运行时

    • 实时操作系统与 POSIX 层
    • C/C++ 运行时库
  • 开发资源与文档

    • 文档与规格书
    • 公共示例工程
    • UI 资源工程与打包
    • SDK 辅助工具与脚本

音频编解码与音源

本文档介绍 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 将这条链路抽象为「任务 + 服务 + 算法库」三层结构:

  1. 音频服务器(audio_server):以消息命令形式对外提供统一的解码/编码控制接口,应用通过 AUDIO_DEC_* 系列命令操作解码器生命周期;
  2. 音频任务(audio_decoder / audio_encoder / audio_mix):独立 RTOS 任务,承载解码、编码与混音的数据搬运和调度;
  3. 编解码算法库:通过编译期宏(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 /*!< 设置循环播放 */

来源:audio_server.h

设计意图分析:

  • 命令从 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 等)
};

来源:audio_server.h

解码器采用 pull 模型:消费者先通过 get_buf 申请一块 PCM 缓冲区,解码器将解码结果写入该缓冲区后再交还。这种「消费者驱动」设计使解码速率天然跟随 DAC 的消费速率,避免缓冲区溢出或欠载,是嵌入式音频中避免卡顿的关键。

编解码算法矩阵与使能宏

SDK 的编解码能力全部由编译期宏控制,相关运行参数集中在 apps/common/audio_music/audio_config.c。下表汇总了源码中可验证的格式支持:

格式方向使能宏关键运行参数
MP3解码CONFIG_MP3_DEC_ENABLEMP3_OUTPUT_LEN、MP3_TGF_AB_EN、MP3_SEARCH_MAX、MP3_TGF_POSPLAY_EN
MP3编码CONFIG_MP3_ENC_ENABLEmp3encode_input_mode
WAV解码CONFIG_WAV_DEC_ENABLEWAV_MAX_BITRATEV、WAV_DECODER_PCM_POINTS、support_HR_FLAG
MIDI解码CONFIG_MIDI_CTRL_DEC_ENABLEMIDI_TONE_MODE、MAX_DEC_PLAYER_CNT、MIDI_DEC_SR、MIDI_SAVE_DIV_ENBALE
OPUS/Silk解码CONFIG_OPUS_DEC_ENABLEsilk_fsN_enable、silk_fsW_enable
JLA编/解码CONFIG_JLA_ENC_ENABLE / CONFIG_JLA_DEC_ENABLEJLA_DMS_VAL、JLA_DMS_FSINDEX、JLA_QUALTIY_CONFIG、JLA_PLC_EN、JLA_HW_FFT
DNS编码CONFIG_DNS_ENC_ENABLEdns_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

来源:audio_config.c

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

来源:audio_config.c

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;

来源:audio_config.c

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

来源:audio_config.c

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

来源:audio_config.c

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: 释放解码器实例

流程要点:

  1. OPEN → try_open 探测:解码器对文件依次尝试各算法库的 try_open,首个匹配者接管。多格式自动识别能力由此实现,应用无需指定格式;
  2. 两阶段启动:OPEN 只完成资源分配与格式绑定,START 才真正开始拉取数据,中间可插入音量、断点、AB 复读等参数设置;
  3. pull 消费模型:解码循环中 DAC 通过 audio_dec_output_ops.get_buf 驱动 PCM 消费,解码速率与播放速率自动同步;
  4. 暂停/停止语义分离:PAUSE 保留解码器实例可恢复,STOP 彻底释放,二者内存占用差异显著,长暂停场景应使用 PAUSE,切换曲目应使用 STOP。

音源与任务系统

SDK 以 RTOS 任务承载音频数据流,任务表在各应用的 app_main.c 中集中注册。以 demo_DevKitBoard/app_main.c 为例:

{"audio_decoder",       30,     1024,   64    },
{"audio_encoder",       12,      384,   64    },

来源:demo_DevKitBoard/app_main.c

各应用的任务配置体现了产品形态决定资源分配的设计:

应用audio_decoder (优先级/栈)audio_encoder (优先级/栈)audio_mix备注
demo_audio未注册解码任务12/384/6428/512/0偏编码演示
demo_DevKitBoard30/1024/6412/384/6428/512/0编解码均衡
wifi_camera30/1024/6414/1024/6427/512/64编码栈翻倍,供视频流
wifi_ipc30/1024/6414/1024/6427/512/64同上
scan_box未注册解码任务12/384/64未注册纯采集编码
wifi_story_machine未注册解码任务12/384/6428/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_pointsint160 (AEC: 320)每次中断需读取的 PCM 点数,AEC 场景加倍
audio_src_temp_buf_sizeintpoints*4*3 (AEC: ×2)采样率转换(SRC)临时缓冲大小
audio_sync_temp_buf_sizeintpoints*4*3 (AEC: ×2)同步处理临时缓冲大小
audio_ps_temp_buf_sizeintpoints*4*10 (AEC: ×2)变速变调(PS)临时缓冲大小
audio_src_flt_in_sramint1SRC 滤波器是否放置于 SRAM(低延迟访问)
audio_dac_ch_numint2 (CH_TWO)DAC 输出通道数,固定双声道
audio_mix_enu80/1 (CONFIG_AUDIO_MIX_ENABLE)混音功能使能
config_audio_dac_auto_src_enu80DAC 自动采样率转换使能
audio_mix_temp_buf_sizeintpoints*2*4*ch (低功耗: ×10)混音临时缓冲大小

各编解码器参数

配置项类型默认值说明
MP3_OUTPUT_LENint4MP3 解码输出长度配置
MP3_TGF_TWS_ENint0MP3 TWS 双耳传输使能
MP3_TGF_AB_ENint1MP3 AB 复读使能
MP3_SEARCH_MAXint20MP3 最大帧搜索次数(快速定位)
MP3_TGF_POSPLAY_ENint1MP3 按位置播放使能
mp3encode_input_modeint1MP3 编码输入模式(1 为 short 输入)
WAV_MAX_BITRATEVint96232WAV 最大支持比特率(kbps)
WAV_DECODER_PCM_POINTSint128WAV 单次解码输出点数(32–900)
support_HR_FLAGint1支持 64k/88.2k/96k 高采样率
MIDI_TONE_MODEint0/1音色访问方式:0 地址访问,1 文件访问
MAINTRACK_USE_CHNint0主旋律选定方式:0 轨道,1 通道
MAX_DEC_PLAYER_CNTint18MIDI 解码最大同时播放 key 数
MAX_CTR_PLAYER_CNTint18MIDI 琴最大同时播放 key 数
MIDI_SAVE_DIV_ENBALEint1小节回退功能使能(关闭可省内存)
MIDI_DEC_SRint44100MIDI 输出采样率
silk_fsN_enableint1Silk 8–12k 窄带采样率支持
silk_fsW_enableint1Silk 16–24k 宽带采样率支持
dns_enc_enableu81 (CONFIG_DNS_ENC_ENABLE)DNS 编码使能
JLA_INT24bit_INOUTint0JLA 24bit 输入输出(1 为 int 存 24bit)
JLA_DMS_VALint100JLA 帧长:25/50/75/100 ms
JLA_DMS_FSINDEXint5JLA 采样率:0–4 固定,5 可变
JLA_QUALTIY_CONFIGint1JLA 质量档位:1/2/3/4
JLA_PLC_ENint1JLA 丢包隐藏(PLC)使能
JLA_HW_FFTint0JLA 使用硬件 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_server.h

用途: 配合 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空间 */
    // ... 其余回调
};

来源:audio_server.h

参数:

  • priv (void*):消费者私有上下文;
  • len (u32*):入参为期望的缓冲区长度,出参为实际分配长度。

返回: PCM 缓冲区指针;返回 NULL 表示暂无可消费空间(解码器应等待)。

解码器操作接口

struct audio_dec_ops 中可验证的成员:

方法签名职责
openvoid *(*open)(FILE *file, void *priv, const struct audio_dec_output_ops *ops, struct audio_dec_breakpoint *)打开文件并创建解码实例
try_openvoid *(*try_open)(FILE *file, void *priv, const struct audio_dec_output_ops *ops, struct audio_dec_breakpoint *)格式探测后尝试打开
get_audio_infoint (*get_audio_info)(void *, struct audio_finfo *info)获取采样率/声道等信息

来源:audio_server.h

设计意图: 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 级别观察帧级日志。

扩展点

  1. 新增编解码格式:实现 struct audio_dec_ops 的 try_open/open/get_audio_info 及输出回调契约,在解码任务中注册;解码器的运行参数仿照现有格式在 audio_config.c 中添加 CONFIG_XXX_ENABLE 宏保护段;
  2. 音效挂接:通过 AUDIO_DEC_GET_EFFECT_HANDLE(14) 获取音效算法句柄,在解码输出后、混音前插入自定义音效;默认参数可写入 audio_eff_default_parm.c;
  3. 变速变调:AUDIO_DEC_PS_PARM_SET(10) 设置 PS 参数,audio_ps_temp_buf_size 为 PS 预留了独立缓冲,复读机类产品可直接复用该通道;
  4. 音量策略:单路增益走 AUDIO_DEC_SET_VOLUME,整机音量走 audio_digital_vol;需要独立音量曲线(如 AGC)时可替换数字音量实现而不动解码器;
  5. 任务资源重配:各应用的 app_main.c 任务表是唯一资源入口,新增音频通道(如双解码播放)时按 {名称, 优先级, 栈大小, 预留} 格式追加即可。

相关链接

  • audio_server.h(命令协议与解码器接口)
  • audio_config.c(编解码参数配置)
  • audio_digital_vol.c(数字音量)
  • audio_eff_default_parm.c(音效默认参数)
  • demo_DevKitBoard/app_main.c(音频任务注册示例)
  • wifi_ipc/app_main.c(音视频场景任务配置)
  • midi/audio_dec_midi_ctrl.c(MIDI 解码控制)
  • usb_audio_api.c(USB 音频 API)
Next
音效处理引擎