音频编码与录音
本文档介绍 AD24N GP-MCU SDK 中音频编码(Audio Encoding)与录音(Recording)子系统的完整实现:从 ADC 采集链路、编码器抽象框架(ENC_OPS)、IMA ADPCM / MP2 编码器注册,到 toy_record 录音应用与 norfs 文件系统的存储与回放流程。
Purpose and Scope
本页覆盖以下内容:
- 编码器抽象层:
EN_FILE_IO/ENC_DATA_INFO/ENC_OPS接口定义,以及 IMA ADPCM、MP2 等编码器如何接入(audio_enc_api.h)。 - 编码管理器(encoder_mge):
enc_obj控制块、kick_encode_isr/kick_wfile_isr中断驱动流水线、start_encode/stop_encode的启停语义(encoder_api.c)。 - ADC 采集物理链路:
rec_phy_init/rec_phy_suspend、cbuf_adc环形缓冲、ANS(环境降噪)可选挂接。 - 录音应用:
toy_record模块(toy_record.c/toy_record_key.c)以及录音文件写入/回读 NOR Flash 的实现(enc_in_norfs.c)。
本页不覆盖解码器子系统(decoder_api)、音效处理(sound_effect_api)、文件系统通用抽象(vfs/device_mge)的完整细节——这些属于各自的 catalog 页面,仅在数据流经过时提及。
Overview
AD24N 是杰理科技(Jieli Tech)面向 GP-MCU 应用的音频 SoC。其录音链路是典型的"低功耗、低延迟、中断驱动"嵌入式音频设计:麦克风信号经 ADC 采样后写入环形缓冲,编码器在软中断(IRQ_SOFT1/IRQ_SOFT2)上下文中被"踢"(kick)动,以块为单位读取 PCM 数据并输出压缩码流,最终由写文件中断把码流落盘到 NOR Flash。
系统支持两种编码器家族:
- IMA ADPCM(A 格式):通过
get_ima_code_ops()获取操作集,ENC_DATA_INFO.br字段被解释为 blockSize(典型 256/512/1024/2048,超过 2048 会被限制),适合低码率、低算力的语音录音。 - MP2 家族:
get_mp2_ops()(标准 MP2)与get_mp2standard_ops(),br字段被解释为 bitrate,用于对音质要求更高的场景。
录音文件以"索引文件"(rec_file_index)形式保存在 norfs 文件系统上,回放时通过 FS_IOCTL_FS_INDEX 按索引打开并交给解码器。
Architecture
flowchart TD
subgraph sg_HW["硬件层"]
MIC["麦克风输入"]
ADC["Audio ADC 通道"]
end
subgraph sg_Capture["采集层 (encoder_api.c)"]
CBUF["cbuf_adc 环形缓冲<br/>(.rec_data 段)"]
REC_SOUND["rec_sound (sound_out_obj)"]
ANS["ANS 降噪链路<br/>(可选, ANS_EN)"]
KICK["kick_encode_api / kick_encode_isr"]
end
subgraph sg_ENC["编码管理层 (encoder_mge)"]
ENC_OBJ["enc_obj 控制块"]
SOFT1["IRQ_SOFT1 编码中断"]
SOFT2["IRQ_SOFT2 写文件中断"]
ENC_OPS["ENC_OPS 操作集"]
end
subgraph sg_CODEC["编码器列表 (list/)"]
ADPCM["a_encoder.c<br/>IMA ADPCM"]
MP2["mp3_encoder.c / ump3_encoder.c<br/>MP2 家族"]
end
subgraph sg_APP["录音应用 (toy_record)"]
TOY["toy_record.c / toy_record_key.c"]
NORFS["enc_in_norfs.c<br/>norfs 文件存储"]
end
MIC --> ADC
ADC -->|"regist_audio_adc_channel"| REC_SOUND
REC_SOUND --> CBUF
REC_SOUND -->|"link_ans_sound (可选)"| ANS
ANS --> CBUF
CBUF -->|"kick 触发"| KICK
KICK --> SOFT1
SOFT1 --> ENC_OBJ
ENC_OBJ --> ENC_OPS
ENC_OPS --> ADPCM
ENC_OPS --> MP2
ENC_OBJ -->|"码流输出"| SOFT2
SOFT2 --> NORFS
TOY -->|"Encode_Control 驱动"| ENC_OBJ
TOY --> NORFS
NORFS -->|"vfs_mount / vfs_createfile / decoder_io"| ADC
架构解读: 整条链路自下而上分为五层。硬件层(ADC)通过 regist_audio_adc_channel 把采样数据灌入 rec_sound 输出对象;采样数据经(可选的)ANS 链路进入 cbuf_adc 环形缓冲。编码管理层由软中断驱动:kick_encode_api 在 ADC 数据就绪时被调用,触发 kick_encode_isr 从缓冲取 PCM 并调用 ENC_OPS.run 完成压缩;压缩码流再通过写文件中断(IRQ_SOFT2)交给 norfs 落盘。toy_record 应用负责编排整条链路(创建文件 → 启动编码 → 停止编码 → 同步落盘),并通过 rec_file_index 管理录音文件的索引,便于后续回放。
flowchart LR
subgraph sg_API["公开接口 (audio_enc_api.h)"]
OPS["ENC_OPS<br/>need_buf / open / run"]
IO["EN_FILE_IO<br/>input_data / output_data"]
INFO["ENC_DATA_INFO<br/>sr / br"]
end
OPS -->|"get_ima_code_ops()"| ADPCM["IMA ADPCM 编码器"]
OPS -->|"get_mp2_ops()"| MP2A["MP2 编码器"]
OPS -->|"get_mp2standard_ops()"| MP2B["MP2 Standard 编码器"]
编码器通过 ENC_OPS 统一抽象暴露:need_buf() 返回编码器所需工作缓冲大小,open() 以缓冲指针、数据信息(采样率/码率)和文件 IO 回调初始化编码器,run() 执行一次编码块。这种"操作集 + 回调"的设计使得编码管理器无需关心具体算法,新增编码器只需实现三个函数并注册操作集。
编码管理器与物理层实现
编码管理器的物理层实现在 sdk/app/bsp/common/encoder/encoder_api.c。其核心是 enc_obj(enc_hdl 全局控制块)与两条中断(IRQ_SOFT1 编码、IRQ_SOFT2 写文件)组成的双缓冲流水线。
ADC 采集物理层初始化
rec_phy_init() 完成环形缓冲初始化与 ADC 通道注册:
cbuffer_t cbuf_adc AT(.rec_data);
u8 adc_buff[512 * 10] AT(.rec_data) ;
void rec_phy_init(void)
{
memset(&rec_sound, 0, sizeof(rec_sound));
cbuf_init(&cbuf_adc, &adc_buff[0], sizeof(adc_buff));
rec_sound.p_obuf = &cbuf_adc; //cbuf_adc为audio_adc的数据
sound_out_obj *p_curr_sound = &rec_sound;
#if (defined(ANS_EN) && (ANS_EN))
cbuf_init(&cbuf_ans, &ans_buff[0], sizeof(ans_buff)); //cbuf_ans 为link
p_curr_sound = link_ans_sound(p_curr_sound, &cbuf_ans, read_audio_adc_sr());
#endif
if (p_curr_sound != &rec_sound) {
stream_sound_init(&rec_sound, kick_encode_api);
regist_audio_adc_channel(&rec_sound, (void *)kick_sound);
} else {
regist_audio_adc_channel(&rec_sound, (void *)kick_encode_api);
}
enc_in_sound = p_curr_sound;
rec_sound.enable |= B_DEC_RUN_EN | B_DEC_FIRST;
}
Source: encoder_api.c
设计意图:cbuf_adc(5 KB,位于 .rec_data 内存段)是 ADC 采样数据与编码器之间的解耦缓冲。当 ANS_EN 编译开关打开时,采集链路会插入 ANS(环境降噪)处理节点:link_ans_sound 返回新的 sound 对象,此时 ADC 数据先写入 cbuf_ans,经 ANS 处理后进入 cbuf_adc,且 ADC 通道的回调切换为 kick_sound(驱动 ANS 处理)。无论是否启用 ANS,最终由 regist_audio_adc_channel 注册的"踢"回调保证编码中断被及时触发。
编码启停控制
start_encode() 与 stop_encode() 控制整条录音流水线的运行:
void start_encode(void)
{
START_ADC_RUN;
audio_adc_enable(MIC_PGA_G);
}
void stop_encode(void *pfile, u32 dlen)
{
enc_obj *obj = enc_hdl;
u32 err;
audio_adc_disable();
STOP_ADC_RUN;
log_info("stop encode\n");
if (NULL == enc_hdl) {
rec_phy_suspend();
return;
}
obj->enable |= B_ENC_STOP;
log_info("stop encode A\n");
while (0 != cbuf_get_data_size(obj->p_ibuf)) {
if (obj->enable & B_ENC_FULL) {
break;
}
kick_encode_isr();
delay(100);
}
log_info("stop encode C\n");
while (0 != cbuf_get_data_size(obj->p_obuf)) {
if (obj->enable & B_ENC_FULL) {
break;
}
kick_wfile_isr();
delay(100);
}
log_info("stop encode D\n");
obj->enable &= ~B_ENC_ENABLE;
HWI_Uninstall(IRQ_SOFT1_IDX);
HWI_Uninstall(IRQ_SOFT2_IDX);
u32 flen = dlen;
err = vfs_ioctl(pfile, FS_IOCTL_FILE_SYNC, (int)&flen);
rec_phy_suspend();
}
Source: encoder_api.c
设计意图:stop_encode 是一个"优雅停机"例程——先关闭 ADC 采集(audio_adc_disable + 清除 B_DEC_RUN_EN | B_REC_RUN),再置 B_ENC_STOP 标志,然后主动轮询驱动输入缓冲(PCM)与输出缓冲(码流)逐步排空:只要缓冲里还有数据就反复调用 kick_encode_isr / kick_wfile_isr 推进流水线,直到缓冲清空或 B_ENC_FULL 标志出现(防止因缓冲未及时消费而永久阻塞)。排空完成后卸载两个软中断、调用 FS_IOCTL_FILE_SYNC 将文件数据同步落盘,最后挂起物理层。这一设计保证了停止录音时不会丢帧,且文件内容完整可回放。
录音应用:toy_record 模块
toy_record 是 SDK 中面向"玩具录音"(低成本语音备忘/留言)场景的录音应用,位于 sdk/app/src/voice_func/toy_record/。它由三个文件组成:
| 文件 | 职责 |
|---|---|
toy_record.c | 录音主流程:录音状态机、编码控制、文件生命周期管理 |
toy_record_key.c | 按键触发:将物理按键事件翻译为录音开始/停止命令 |
toy_record.h | Encode_Control 控制结构与模块间接口声明 |
Encode_Control 是贯穿整个录音子系统的核心控制结构,包含设备句柄(device)、文件系统句柄(pfs)、文件句柄(pfile)、设备索引(dev_index)与录音文件索引(rec_file_index)等字段,由录音应用在启动时填充。
录音文件在 norfs 上的创建与回读
录音数据的持久化由 enc_in_norfs.c 负责,它将 Encode_Control 映射为 norfs 文件操作:
int norfs_enc_file_create(Encode_Control *obj)
{
int err = 0;
obj->device = device_open(obj->dev_index);
if (NULL == obj->device) {
log_info("device_open null!\n");
return E_DEV_NULL;
}
err = vfs_mount(&obj->pfs, obj->device, "norfs");
if (err) {
log_info("vfs_mount err:0x%x\n", err);
device_close(obj->dev_index);
return err;
}
err = vfs_createfile(obj->pfs, &obj->pfile, (u32 *)&obj->rec_file_index);
if (err) {
log_info("vfs_createfile err:0x%x\n", err);
vfs_fs_close(&obj->pfs);
device_close(obj->dev_index);
return err;
}
log_info("REC FILE INDEX : %d\n", obj->rec_file_index);
return err;
}
Source: enc_in_norfs.c
设计意图:norfs_enc_file_create 按"设备 → 文件系统 → 文件"的层次依次打开资源,任何一级失败都会逆序释放已获得的资源(device_close / vfs_fs_close),避免句柄泄漏。vfs_createfile 通过出参返回新建文件的索引 rec_file_index——这是 norfs 的按索引寻址模式,后续回放与删除都依赖该索引,而不是路径字符串。
回读侧使用同一套 Encode_Control,按索引打开文件后直接交给解码器:
dec_obj *norfs_enc_file_decode(Encode_Control *obj, u16 dec_type)
{
int err = 0;
obj->device = device_open(obj->dev_index);
if (NULL == obj->device) {
log_info("device_open null!\n");
return NULL;
}
err = vfs_mount(&obj->pfs, obj->device, "norfs");
if (err) {
log_info("vfs_mount err:0x%x\n", err);
device_close(obj->dev_index);
return NULL;
}
err = vfs_ioctl(obj->pfs, FS_IOCTL_FS_INDEX, (int)&obj->rec_file_index);
if (err) {
log_info("vfs_ioctl err:0x%x\n", err);
goto __norfs_enc_fs_exit;
}
err = vfs_openbyindex(obj->pfs, &obj->pfile, obj->rec_file_index);
if (err) {
log_info("vfs_createfile err:0x%x\n", err);
goto __norfs_enc_fs_exit;
}
return decoder_io(obj->pfile, dec_type, NULL, 0);
__norfs_enc_fs_exit:
vfs_fs_close(&obj->pfs);
device_close(obj->dev_index);
return NULL;
}
Source: enc_in_norfs.c
设计意图:回放前先用 FS_IOCTL_FS_INDEX 把目标文件索引设置到文件系统,再通过 vfs_openbyindex 打开。错误路径统一收敛到 __norfs_enc_fs_exit 标签做资源释放(goto 集中式错误处理,嵌入式 C 的典型风格)。成功时 decoder_io 直接返回解码器对象,录音→回放复用同一套文件访问抽象。
核心流程:一次完整录音的生命周期
sequenceDiagram
participant Key as toy_record_key.c<br/>按键处理
participant App as toy_record.c<br/>Encode_Control
participant FS as enc_in_norfs.c<br/>norfs 文件系统
participant PHY as encoder_api.c<br/>rec_phy / enc_obj
participant CODEC as ENC_OPS<br/>ADPCM / MP2
Key->>App: 按键事件(开始录音)
App->>FS: norfs_enc_file_create(obj)
FS-->>App: pfile + rec_file_index
App->>PHY: rec_phy_init() / 注册 ADC 通道
PHY->>CODEC: enc_obj 绑定 ENC_OPS.open(sr, br, IO 回调)
App->>PHY: start_encode() (audio_adc_enable)
loop 录音中(ADC 数据就绪)
PHY->>PHY: kick_encode_isr (IRQ_SOFT1)
PHY->>CODEC: ENC_OPS.run() 压缩一帧
CODEC->>PHY: 码流写入 enc_obj.p_obuf
PHY->>FS: kick_wfile_isr (IRQ_SOFT2) 写盘
end
Key->>App: 按键事件(停止录音)
App->>PHY: stop_encode(pfile, dlen)
Note over PHY: 排空 p_ibuf / p_obuf,卸载中断<br/>FS_IOCTL_FILE_SYNC 落盘
App->>FS: 关闭文件 / 卸载文件系统
App->>PHY: rec_phy_suspend() / 关闭 ADC
App->>FS: norfs_enc_file_decode(obj, dec_type) 回放
FS->>App: decoder_io(pfile, dec_type)
流程要点:
- 创建文件:按键触发开始录音后,先走
norfs_enc_file_create建立文件句柄并获得文件索引;失败则直接退出,不会启动 ADC。 - 物理层就绪:
rec_phy_init初始化cbuf_adc并注册 ADC 通道回调(kick_encode_api),enc_obj绑定编码器操作集。 - 启动采集:
start_encode使能 ADC 与运行标志,采样数据开始流入环形缓冲。 - 中断驱动编码:每次 ADC 数据就绪,
kick_encode_isr(IRQ_SOFT1)从输入缓冲取 PCM 并调用ENC_OPS.run压缩;码流进入输出缓冲后由kick_wfile_isr(IRQ_SOFT2)写盘。两条中断解耦"编码"与"写文件"两个不同速率的阶段,避免慢速 Flash 写入拖慢编码。 - 优雅停机:
stop_encode先停 ADC,再轮询驱动双缓冲排空,最后同步文件并挂起物理层,保证最后一帧不丢失。 - 回放:通过
norfs_enc_file_decode按索引打开文件,交给解码器播放。
编码器接口与数据契约
audio_enc_api.h 定义了编码器与上层之间的全部契约,是新增编码器必须遵循的接口:
typedef struct _EN_FILE_IO_ {
void *priv;
u16(*input_data)(void *priv, s16 *buf, u16 len);
u32(*output_data)(void *priv, u8 *buf, u16 len);
} EN_FILE_IO;
typedef struct _ENC_DATA_INFO_ {
u16 sr; ///<sample rate
u16 br; ///<mp2的时候它是bitrate,但是adpcm的时候,它是blockSize,一般配成256/512/1024/2048,超过2048会被限制成2048
} ENC_DATA_INFO;
typedef struct _ENC_OPS {
u32(*need_buf)();
void (*open)(u8 *ptr, ENC_DATA_INFO *data_info, EN_FILE_IO *audioIO);
u32(*run)(u8 *ptr);
} ENC_OPS;
ENC_OPS *get_ima_code_ops(void);
ENC_OPS *get_mp2_ops(void);
ENC_OPS *get_mp2standard_ops(void);
Source: audio_enc_api.h
接口语义:
EN_FILE_IO:编码器的 IO 回调对。input_data由编码器调用以拉取 PCM(s16 采样),output_data由编码器调用以吐出压缩码流(u8 字节)。priv携带上层上下文(通常是enc_obj),使回调无需全局变量。ENC_DATA_INFO:编码参数。sr为采样率;br是多义字段——MP2 家族下是 bitrate,IMA ADPCM 下是 blockSize(256/512/1024/2048,硬件限制上限 2048)。ENC_OPS:编码器操作集。need_buf返回工作缓冲需求,open完成初始化(绑定参数与 IO 回调),run执行一次编码推进。ptr是编码器私有工作缓冲,由上层按need_buf结果分配。
SDK 内置三种操作集工厂函数:get_ima_code_ops()(IMA ADPCM,实现于 list/a_encoder.c)、get_mp2_ops() 与 get_mp2standard_ops()(MP2 家族,实现于 list/mp3_encoder.c / list/ump3_encoder.c)。对应的头文件 a_encoder.h / mp3_encoder.h 位于 sdk/include_lib/encoder/list/,供上层通过 encoder_mge.h 统一调度。
配置选项
录音子系统的行为主要由编译期宏与编码参数决定:
| 配置项 | 类型 | 默认/示例 | 说明 |
|---|---|---|---|
ANS_EN | 编译宏 | 0(未定义时关闭) | 启用 ANS 环境降噪链路;开启后 rec_phy_init 会插入 cbuf_ans 与 link_ans_sound 节点,ADC 通道回调切换为 kick_sound |
ENC_DATA_INFO.sr | u16 | 由应用设定(如 8000/16000) | 编码采样率,同时用于 read_audio_adc_sr() 对齐 ADC 采样率 |
ENC_DATA_INFO.br | u16 | ADPCM: 256/512/1024/2048;MP2: bitrate | ADPCM 下为 blockSize(上限 2048),MP2 下为 bitrate |
cbuf_adc / adc_buff | 环形缓冲 | 512 * 10 字节(.rec_data 段) | ADC 采样与编码器之间的解耦缓冲,尺寸决定抗抖动能力 |
MIC_PGA_G | extern 常量 | 由平台配置 | 麦克风 PGA 增益,start_encode 时通过 audio_adc_enable 生效 |
dev_index(Encode_Control) | 设备索引 | 由录音应用指定 | 挂载 norfs 的设备编号,传给 device_open |
内存布局说明: cbuf_adc、adc_buff 显式放置在 .rec_data 段,kick_encode_api 放置在 .audio_a.text.cache.L2——这体现了 SDK 对缓存(cache)与 DMA 一致性、以及低延迟中断路径的精细控制:热路径代码驻留 L2 cache 段以减少取指延迟,录音缓冲独立分段以便内存管理器按用途回收。
API 参考
rec_phy_init()
初始化 ADC 采集物理层:清零 rec_sound、初始化 cbuf_adc、按 ANS_EN 决定是否插入 ANS 链路、注册 ADC 通道回调、置位 B_DEC_RUN_EN | B_DEC_FIRST。
- 无参数,无返回值。
- 调用时机:每次录音会话开始前调用一次;与
rec_phy_suspend成对使用。
rec_phy_suspend()
- 无参数,无返回值。
- 调用
stream_sound_uninit()并unregist_audio_adc_channel(&rec_sound),释放采集通道。
start_encode()
- 无参数,无返回值。
- 置位
B_DEC_RUN_EN | B_REC_RUN并audio_adc_enable(MIC_PGA_G),启动 ADC 采样。通常在文件创建成功后调用。
stop_encode(void *pfile, u32 dlen)
停止编码并同步落盘。
参数:
pfile(void*):录音文件句柄,用于FS_IOCTL_FILE_SYNC。dlen(u32):期望的同步数据长度。
行为: 关闭 ADC → 置 B_ENC_STOP → 轮询排空输入/输出缓冲(受 B_ENC_FULL 保护)→ 卸载 IRQ_SOFT1_IDX / IRQ_SOFT2_IDX → 文件同步 → rec_phy_suspend。
kick_encode_api(void *obj) / kick_encode_isr()
- ADC 数据就绪回调,转发到编码中断处理。
kick_encode_api标注为 L2 cache 段热路径。
norfs_enc_file_create(Encode_Control *obj): int
打开设备、挂载 norfs、创建录音文件并获得索引。
参数: obj(Encode_Control*)——输出 pfs/pfile/rec_file_index。
返回: 0 成功;E_DEV_NULL 表示设备打开失败;其他非 0 为 vfs_mount / vfs_createfile 返回的错误码。
norfs_enc_file_decode(Encode_Control *obj, u16 dec_type): dec_obj *
按 rec_file_index 打开录音文件并创建解码器。
参数: obj(Encode_Control*)、dec_type(u16,解码器类型)。
返回: dec_obj * 解码器对象;失败返回 NULL(内部已做资源逆序释放)。
编码器工厂函数
| 函数 | 返回 | 对应编码器 |
|---|---|---|
get_ima_code_ops() | ENC_OPS * | IMA ADPCM(list/a_encoder.c) |
get_mp2_ops() | ENC_OPS * | MP2(list/mp3_encoder.c) |
get_mp2standard_ops() | ENC_OPS * | MP2 Standard(list/ump3_encoder.c) |
故障模式、边界情况与并发
故障模式
| 场景 | 表现 | 处理方式 |
|---|---|---|
device_open 失败 | norfs_enc_file_create 返回 E_DEV_NULL | 录音直接中止,不挂载文件系统 |
vfs_mount 失败 | 返回错误码并 device_close | 逆序释放设备句柄 |
vfs_createfile 失败 | 返回错误码 | vfs_fs_close + device_close,无泄漏 |
| 回放打开失败 | norfs_enc_file_decode 返回 NULL | 统一 goto __norfs_enc_fs_exit 释放资源 |
| 缓冲消费停滞 | stop_encode 可能死等 | 用 B_ENC_FULL 标志兜底跳出轮询 |
边界情况
- blockSize 上限:ADPCM 的
br超过 2048 会被限制为 2048,防止单个块过大导致缓冲溢出。 - 空缓冲停机:
stop_encode在enc_hdl == NULL时直接rec_phy_suspend返回,避免空指针解引用。 - FPGA 仿真模式:
encoder_api.c中#if (0 == FPGA)包裹了全部物理层实现,FPGA 平台下采集/中断路径由仿真环境另行提供。
并发与实时性
- 编码与写文件分别在 IRQ_SOFT1 / IRQ_SOFT2 两个软中断上下文中执行,天然串行化,无需互斥锁;应用层通过
stop_encode的轮询循环与中断协同,保证停机过程中缓冲的并发安全。 kick_encode_api被放置在.audio_a.text.cache.L2段,确保 ADC 中断回调的取指延迟最小化——这是音频实时性敏感路径的典型优化。- 缓冲排空使用
delay(100)让步,避免在中断上下文或主循环中忙等占用 CPU 过久。
扩展点
- 新增编码器:按
ENC_OPS实现need_buf/open/run三函数 + 工厂函数(参考get_ima_code_ops),在encoder_api.c中#include对应头文件即可接入现有调度流水线,无需改动enc_obj与中断框架。 - 启用 ANS 降噪:定义
ANS_EN编译宏,采集链路自动插入 ANS 节点(cbuf_ans、link_ans_sound),ADC 回调自动切换为kick_sound;上层调用方式不变。 - 更换存储介质:
enc_in_norfs.c全部通过vfs/device抽象访问存储,替换"norfs"挂载名为其他文件系统(如 fat)即可复用同一套录音流程。 - 按键扩展:
toy_record_key.c将按键事件翻译为录音命令,可在该层增加长按/双击等触发语义,不影响编码链路。
相关链接
- encoder_api.c(编码物理层与启停控制)
- enc_in_norfs.c(norfs 录音文件创建与回读)
- audio_enc_api.h(编码器接口契约)
- encoder_mge.h(编码管理器)
- a_encoder.c(IMA ADPCM 编码器)
- mp3_encoder.c / ump3_encoder.c(MP2 编码器)
- toy_record.c / toy_record_key.c / toy_record.h(录音应用)
相关子系统请参考各自的 catalog 页面:解码器(decoder_api)、音效处理(sound_effect_api)、文件系统与设备管理(vfs / device_mge)。