播放器与录音器
AC792 SDK 的媒体接口层(sdk/audio/interface/)提供了一整套统一、可扩展的播放器(Player)与录音器(Recorder)抽象,所有实现都构建在 jlstream 媒体流水线框架之上,覆盖本地文件、蓝牙(A2DP/ESCO/LE Audio)、USB、FM、TTS、AI 语音等数十种音源与录音场景。
Purpose and Scope
本页面向"播放器与录音器"这一系统能力,说明:
- 媒体接口层的整体架构:
jlstream流水线如何承载所有播放/录音实例; - 播放器家族(
sdk/audio/interface/player/)的组成与职责划分; - 录音器家族(
sdk/audio/interface/recorder/)的组成与职责划分; - 最具代表性的
file_player(音乐播放器)与file_recorder(文件录音器)的完整实现机制、API 与控制流; - 配置开关、故障模式、并发模型与扩展方式。
以下主题属于兄弟页面,不在本页展开:具体应用层 UI(如 wifi_soundbox 的 LVGL 音乐播放界面)、网络视频播放器(net_avi_player)、编解码器内部算法、jlstream 流水线框架本身的节点机制。有关流水线底层,请参考"媒体流(jlstream)"相关文档。
Overview
在 AC792 这类多核 SoC 音频 SDK 中,"播放"与"录音"是几乎所有上层业务(音乐、通话、对讲、语音助手、FM、TWS 等)的公共底座。直接为每个业务单独实现音频链路会导致大量重复与不可维护的代码,因此 SDK 通过接口层 + 流水线的设计收敛复杂度:
- 接口层(本页主题)为每种音源/录音场景暴露一个面向业务的句柄 API,例如
file_player_open()、file_recorder_open(); - 每个句柄内部持有一个
struct jlstream(媒体流水线),流水线由若干"节点"(source / decoder / encoder / sink 等)串接而成; - 接口层负责将业务语义(打开文件、设置采样率、回调事件、无缝切换等)翻译成流水线操作(
jlstream_pipeline_parse、jlstream_node_ioctl、jlstream_set_scene等)。
该设计带来三个关键收益:
- 统一生命周期:所有播放器/录音器遵循 open → 配置 → start → 事件回调 → stop/close → release 的同一套状态机,上层切换业务时心智负担低;
- 场景隔离:每个实例通过
jlstream_set_scene()声明自己的场景(如STREAM_SCENE_RECODER),底层可据此做资源仲裁(例如录音与播放互斥); - 可组合性:录音器输出的编码数据可以喂给播放器、网络模块或文件系统,接口层之间可以自由组合(例如 AI 语音识别 = file_recorder 采集 + 网络上传)。
Architecture
flowchart TD
subgraph sg_App["应用层 (sdk/apps)"]
AppMusic["音乐播放 App"]
AppRecorder["录音模式 Recorder Mode"]
AppDuer["DUER 语音助手"]
end
subgraph sg_PlayerIF["播放器接口层 sdk/audio/interface/player"]
FilePlayer["file_player (音乐/文件)"]
TonePlayer["tone_player / key_tone_player"]
A2dpPlayer["a2dp_player (蓝牙音乐)"]
EscoPlayer["esco_player (蓝牙通话)"]
TtsPlayer["tts_player (语音合成)"]
OtherPlayers["fm / linein / iis / le_audio / usb_host_spk / net_file ..."]
end
subgraph sg_RecorderIF["录音器接口层 sdk/audio/interface/recorder"]
FileRecorder["file_recorder (文件录音)"]
AiVoiceRec["ai_voice_recorder"]
EscoRec["esco_recorder"]
OtherRecorders["pc_mic / usb_host_mic / le_audio / dev_flow ..."]
end
subgraph sg_Core["媒体核心"]
JLStream["jlstream 流水线框架"]
Demuxer["jldemuxer 解封装"]
Decoder["audio_decoder 解码器"]
Encoder["encoder_fmt 编码器"]
FileOps["fs / stream_file_ops 文件抽象"]
end
AppMusic --> FilePlayer
AppRecorder --> FileRecorder
AppDuer --> AiVoiceRec
FilePlayer --> JLStream
TonePlayer --> JLStream
A2dpPlayer --> JLStream
EscoPlayer --> JLStream
TtsPlayer --> JLStream
OtherPlayers --> JLStream
FileRecorder --> JLStream
AiVoiceRec --> JLStream
EscoRec --> JLStream
OtherRecorders --> JLStream
FilePlayer --> Demuxer
FilePlayer --> Decoder
FilePlayer --> FileOps
FileRecorder --> Encoder
FileRecorder --> FileOps
架构说明:
- 应用层只依赖接口层的公开句柄 API,不感知流水线细节。例如
wifi_bbm、wifi_camera、wifi_soundbox各自都有一份mode/recorder/recorder.c,但底层调用的都是file_recorder_open/start/stop这套接口; - 接口层每个
.c文件对应一种音源/录音场景,它们共享同一套jlstream机制,但封装出不同的业务语义(播放器关心解码与音量,录音器关心编码与文件写入); - 媒体核心提供流水线解析、节点控制、解码/编码格式协商与文件 IO 抽象。
file_recorder通过fops(struct stream_file_ops)或标准fread/fwrite两种方式读写文件,file_player则依赖jldemuxer+audio_decoder完成解封装与解码。
播放器体系
sdk/audio/interface/player/ 下共有 19 个播放器实现,按音源类型可归为几类:
| 播放器文件 | 音源/场景 | 典型业务 |
|---|---|---|
file_player.c | 本地文件系统上的音频文件(MP3/WAV/FLAC 等,经 jldemuxer + audio_decoder) | 音乐播放器、提示音 |
net_file_player.c | 网络文件流 | 在线音乐、网络对讲 |
tone_player.c / key_tone_player.c / tws_tone_player.c | 内部波形/按键音/双耳 TWS 提示音 | UI 反馈音 |
ring_player.c | 来电铃声 | 通话 |
tts_player.c | TTS 语音合成数据流 | 语音播报 |
a2dp_player.c | 蓝牙 A2DP 音频 | 蓝牙音箱 |
esco_player.c | 蓝牙 SCO/eSCO 语音 | 蓝牙通话 |
le_audio_player.c | BLE LE Audio | LE Audio 场景 |
fm_player.c / linein_player.c / iis_player.c / adda_loop_player.c | 模拟/FM/数字/IIS 输入 | 收音机、线路输入 |
local_tws_player.c | 本地 TWS 同步播放 | TWS 音箱 |
usb_host_spk_player.c / pc_spk_player.c | USB 音频(host/device) | USB 声卡 |
avi_audio_player.c | AVI 容器内的音轨 | 录像回放 |
dev_flow_player.c | 设备流播放 | 通用流播放 |
file_player:音乐播放器核心实现
file_player.c 是整个播放器体系中最具代表性的实现,编译开关为 TCFG_APP_MUSIC_EN。它以"多实例 + 引用计数 + 全局句柄表"的方式管理多个并发播放句柄:
struct music_file_player_hdl {
u8 player_id;
OS_MUTEX mutex;
struct list_head head;
#if FILE_DEC_DEST_PLAY || FILE_DEC_REPEAT_EN
struct file_player *cur_player; //当前的音乐播放器句柄
#endif
};
static struct music_file_player_hdl g_file_player;
Source: file_player.c
设计意图:
- 全局单例句柄表
g_file_player用list_head挂接所有打开的播放器,player_id作为事件回调的区分键,mutex保护链表操作——这样多个播放器可以共存(例如音乐与提示音同时播放),而事件分发仍能精确命中对应实例; - 引用计数:
music_player_free()在--player->ref == 0时才真正释放内存,并顺带回收断点续播缓冲(break_point)与 AB 重复缓冲(ab_buf),避免在事件回调中提前释放正在使用的句柄; - 编译期裁剪:断点续播、AB 复读(
FILE_DEC_AB_REPEAT_EN)、定向播放/单曲循环(FILE_DEC_DEST_PLAY/FILE_DEC_REPEAT_EN)均为编译开关,不启用时零开销。
播放事件回调与音效联动
music_player_callback() 是播放器的事件入口,在 STREAM_EVENT_START 事件中联动更新人声分离、虚拟低音与 EQ 参数,并加锁取出链表头部的播放器进行事件分发:
static void music_player_callback(void *_player_id, int event)
{
struct file_player *player;
log_info("music_callback: 0x%x, %d", event, (u8)_player_id);
switch (event) {
case STREAM_EVENT_START:
#if TCFG_VOCAL_REMOVER_NODE_ENABLE
musci_vocal_remover_update_parm();
#endif
#if AUDIO_VBASS_LINK_VOLUME
vbass_link_volume();
#endif
#if AUDIO_EQ_LINK_VOLUME
eq_link_volume();
#endif
//先判断是否为空防止触发异常
if (list_empty(&(g_file_player.head))) {
break;
}
os_mutex_pend(&g_file_player.mutex, 0);
player = list_first_entry(&(g_file_player.head), struct file_player, entry);
if (player->player_id != (u8)_player_id) {
...
Source: file_player.c
这里体现了接口层的联动策略:播放器不孤立工作,而是通过事件钩子把音量/EQ/音效状态同步到整条音频链路(eq_link_volume()、vbass_link_volume()),保证"音量跟随 EQ 变化"等产品需求落在公共层,而不是散落在各个 App 中。
录音器体系
sdk/audio/interface/recorder/ 下共有 7 个录音器实现:
| 录音器文件 | 采集场景 | 典型业务 |
|---|---|---|
file_recorder.c | 编码数据写入文件(编译开关 TCFG_APP_RECORD_EN / TCFG_MIX_RECORD_ENABLE) | 录音笔、语音备忘录、通话录音 |
ai_voice_recorder.c | 麦克风采集 → 编码 → AI 云端识别 | 语音助手(DUER 等) |
esco_recorder.c | 蓝牙 SCO 通话语音录制 | 通话录音 |
le_audio_recorder.c | LE Audio 音频采集 | LE Audio 场景 |
pc_mic_recorder.c | USB device 模式麦克风 | USB 声卡录音 |
usb_host_mic_recorder.c | USB host 麦克风采集 | 外接麦克风 |
dev_flow_recorder.c | 设备流录音 | 通用流录制 |
file_recorder:文件录音器核心实现
file_recorder.c 是录音器体系的代表,其核心设计是把文件 IO 抽象成可替换的 fops:既支持标准 C 库的 fread/fwrite/fseek/fclose,也支持 SDK 自己的 struct stream_file_ops 接口(例如写入加密文件系统或自定义介质),上层业务无需关心底层介质差异:
static int recorder_fread(void *_recorder, u8 *buf, int len)
{
struct file_recorder *recorder = (struct file_recorder *)_recorder;
if (!recorder->file) {
return 0;
}
if (recorder->fops) {
return recorder->fops->read(recorder->file, buf, len);
}
return fread(buf, len, 1, (FILE *)recorder->file);
}
Source: file_recorder.c
录音器实例的数据结构由头文件定义,包含链表节点、文件句柄、回调、IO 操作表与流水线句柄,并内置"掐头去尾"(AUDIO_RECORD_CUT_HEAD_TAIL_EN)支持:
typedef void (*file_recorder_cb_t)(void *, enum stream_event);
struct file_recorder {
struct list_head entry;
void *file;
void *priv;
file_recorder_cb_t callback;
const struct stream_file_ops *fops;
struct jlstream *stream;
#if AUDIO_RECORD_CUT_HEAD_TAIL_EN
u8 head_size;
u16 cut_head_timer;
u32 cut_tail_size;
#endif
};
Source: file_recorder.h
录音器与流水线的绑定
file_recorder_open() 展示了录音器如何把业务句柄挂到 jlstream 流水线上:解析流水线、设置录制场景、启动独立线程、注册事件回调并加入全局链表:
struct file_recorder *file_recorder_open(int pipeline_uuid, int snode_uuid)
{
struct file_recorder *recorder;
struct jlstream *stream;
recorder = zalloc(sizeof(*recorder));
if (!recorder) {
return NULL;
}
stream = jlstream_pipeline_parse(pipeline_uuid, snode_uuid);
if (!stream) {
free(recorder);
return NULL;
}
recorder->stream = stream;
jlstream_node_ioctl(stream, NODE_UUID_SOURCE, NODE_IOC_SET_PRIV_FMT, 256);
jlstream_set_scene(stream, STREAM_SCENE_RECODER);
jlstream_add_thread(stream, NULL);
int id = stream->id;
jlstream_set_callback(stream, (void *)id, file_recorder_callback);
list_add(&recorder->entry, &g_recorder_head);
return recorder;
}
Source: file_recorder.c
几个关键动作的设计意图:
jlstream_node_ioctl(..., NODE_IOC_SET_PRIV_FMT, 256):先为采集源节点申请私有格式缓冲(256 字节),保证在业务设置编码格式之前,节点就能携带格式信息;jlstream_set_scene(stream, STREAM_SCENE_RECODER):声明"录制"场景,让底层资源仲裁知道这是采集链路而非播放链路,从而正确处理录音与播放的互斥/并发;jlstream_add_thread(stream, NULL):为流水线拉起独立线程,避免阻塞调用者(录音是持续性任务,不能占用 UI/业务线程);jlstream_set_callback(stream, (void *)id, ...):以流水线id作为私有数据传入回调,回调再遍历全局链表g_recorder_head,按recorder->stream->id == (int)private_data精确分发事件——多实例场景下每个录音器只收到自己的事件。
核心控制流
一次完整的"录音到文件"业务(例如 wifi_bbm 的录音模式)遵循以下时序:
sequenceDiagram
participant App as 应用层 (recorder mode)
participant FR as file_recorder 接口
participant JS as jlstream 流水线
participant ENC as 编码器节点
participant FS as 文件系统 (fops/fread)
App->>FR: file_recorder_open(pipeline_uuid, snode_uuid)
FR->>JS: jlstream_pipeline_parse(uuid)
JS-->>FR: struct jlstream *
FR->>JS: jlstream_set_scene(STREAM_SCENE_RECODER)
FR->>JS: jlstream_add_thread()
FR->>JS: jlstream_set_callback(id, cb)
FR-->>App: struct file_recorder *
App->>FR: file_recorder_set_fmt(enc_fmt)
FR->>JS: 下发编码格式到节点
App->>FR: file_recorder_open_file(fname) / set_file(file)
FR->>FS: fops->open / fwrite 句柄绑定
App->>FR: file_recorder_start()
loop 录制中
JS->>ENC: 采集 → 编码
ENC->>FR: stream_event / 编码数据
FR->>FS: recorder_fwrite(buf, len)
end
App->>FR: file_recorder_stop(close_file=true)
FR->>FS: fclose / fops->close(含掐尾处理)
App->>FR: file_recorder_release()
播放器的控制流与此对称:file_player 侧由 jldemuxer 解封装 → audio_decoder 解码 → sink 输出,事件回调(STREAM_EVENT_START 等)触发音效联动。两类接口最终都收敛到 jlstream 的 start/stop/事件三件套,这就是接口层统一性的体现。
使用示例
示例 1:录音器公开 API 契约(头文件)
业务侧通过以下 API 完成录音器全生命周期管理,seamless_set 提供无缝续录(换文件不丢数据)能力:
struct file_recorder *file_recorder_open(int pipeline_uuid, int snode_uuid);
int file_recorder_get_fmt(struct file_recorder *recorder, struct stream_enc_fmt *fmt);
int file_recorder_set_fmt(struct file_recorder *recorder, struct stream_enc_fmt *fmt);
int file_recorder_set_priv_fmt(struct file_recorder *recorder, struct encoder_fmt *enc_fmt);
FILE *file_recorder_open_file(struct file_recorder *recorder, const char *fname);
int file_recorder_set_file(struct file_recorder *recorder, void *file,
const struct stream_file_ops *fops);
void *file_recorder_change_file(struct file_recorder *recorder, void *new_file);
void file_recorder_set_callback(struct file_recorder *recorder, void *priv,
file_recorder_cb_t callback);
void file_recorder_seamless_set(struct file_recorder *recorder, struct seamless_recording *seamless);
int file_recorder_start(struct file_recorder *recorder);
int file_recorder_close(struct file_recorder *recorder, bool close_file);
int file_recorder_get_enc_time(struct file_recorder *recorder);
int file_recorder_stop(struct file_recorder *recorder, bool close_file);
int file_recorder_release(struct file_recorder *recorder);
Source: file_recorder.h
典型调用序列:open → set_fmt/set_priv_fmt → set_file(或 open_file) → set_callback → start → (录制中 change_file 轮换文件) → stop → release。
示例 2:录音器文件 IO 双通道抽象
recorder_fwrite 与 recorder_fclose 展示了 fops 优先、标准库兜底的策略;fclose 中额外处理"掐尾"(AUDIO_RECORD_CUT_HEAD_TAIL_EN),即按 cut_tail_size 回退文件指针,把末尾无效数据(如采集启动尾巴)裁掉:
static int recorder_fwrite(void *_recorder, u8 *buf, int len)
{
int wlen;
struct file_recorder *recorder = (struct file_recorder *)_recorder;
if (!recorder->file) {
return 0;
}
if (recorder->fops) {
wlen = recorder->fops->write(recorder->file, buf, len);
} else {
wlen = fwrite(buf, len, 1, (FILE *)recorder->file);
}
return wlen;
}
static int recorder_fclose(void *_recorder)
{
struct file_recorder *recorder = (struct file_recorder *)_recorder;
if (!recorder->file) {
return 0;
}
#if AUDIO_RECORD_CUT_HEAD_TAIL_EN
int f_len = ftell((FILE *)recorder->file);
if ((recorder->cut_tail_size) && ((f_len - recorder->head_size) > recorder->cut_tail_size)) {
f_len -= recorder->cut_tail_size;
fseek(recorder->file, f_len, SEEK_SET);
}
...
Source: file_recorder.c
示例 3:播放器引用计数释放
播放器句柄释放遵循引用计数,只有最后一个引用释放时才回收断点续播缓冲与 AB 复读缓冲,避免多引用场景下的悬垂指针:
static void music_player_free(struct file_player *player)
{
if (--player->ref == 0) {
if (player->break_point_flag == 1) {
free(player->break_point);
player->break_point = NULL;
player->break_point_flag = 0;
}
#if FILE_DEC_AB_REPEAT_EN
if (player->ab_buf) {
free(player->ab_buf);
player->ab_buf = NULL;
}
#endif
free(player);
#if FILE_DEC_DEST_PLAY || FILE_DEC_REPEAT_EN
if (player == g_file_player.cur_player) {
g_file_player.cur_player = NULL;
}
#endif
}
}
Source: file_player.c
配置选项
播放器与录音器的主要行为由编译期宏控制(集中在 app_config.h / audio_config_def.h / 头文件):
| 宏 | 类型 | 默认 | 作用 |
|---|---|---|---|
TCFG_APP_MUSIC_EN | bool | 按产品配置 | 使能 file_player 音乐播放器实现 |
TCFG_APP_RECORD_EN | bool | 按产品配置 | 使能 file_recorder 文件录音器实现 |
TCFG_MIX_RECORD_ENABLE | bool | 按产品配置 | 混音录音使能(与 TCFG_APP_RECORD_EN 二选一启用编译) |
TCFG_VOCAL_REMOVER_NODE_ENABLE | bool | 按产品配置 | 播放启动时联动更新人声分离参数 |
AUDIO_VBASS_LINK_VOLUME | bool | 按产品配置 | 播放启动时联动更新虚拟低音音量 |
AUDIO_EQ_LINK_VOLUME | bool | 按产品配置 | 播放启动时联动更新 EQ 音量 |
FILE_DEC_AB_REPEAT_EN | bool | 按产品配置 | 使能 AB 复读(需要 ab_buf 缓冲) |
FILE_DEC_DEST_PLAY | bool | 按产品配置 | 使能定向播放(维护 cur_player 句柄) |
FILE_DEC_REPEAT_EN | bool | 按产品配置 | 使能单曲/列表循环 |
AUDIO_RECORD_CUT_HEAD_TAIL_EN | int | 1 | 录音掐头去尾:cut_head_timer/cut_tail_size 生效的前提 |
运行时行为(场景、回调、格式)通过接口 API 传入,例如 file_recorder_open(pipeline_uuid, snode_uuid) 的流水线 UUID 由上层根据产品音频拓扑选择。
API Reference
file_recorder_open(pipeline_uuid, snode_uuid) -> struct file_recorder *
按流水线 UUID 创建录音器实例并挂接 jlstream。失败时返回 NULL(内存不足或流水线解析失败)。
参数:
pipeline_uuid(int):要解析的媒体流水线 ID;snode_uuid(int):流水线内源节点 ID。
返回: 录音器句柄;失败返回 NULL。
说明: 成功时内部已设置录制场景、创建线程、注册回调并加入全局链表 g_recorder_head。
file_recorder_set_fmt(recorder, fmt) -> int
设置编码格式(struct stream_enc_fmt),下发给编码器节点。
file_recorder_set_priv_fmt(recorder, enc_fmt) -> int
设置私有格式(struct encoder_fmt),用于非标准编码参数透传。
file_recorder_set_file(recorder, file, fops) -> int
绑定输出文件与 IO 操作表。fops == NULL 时退化为标准 fread/fwrite/fseek/fclose。
file_recorder_change_file(recorder, new_file) -> void *
无缝切换输出文件,返回旧文件句柄(配合 file_recorder_seamless_set 实现不中断录音的分段文件)。
file_recorder_start(recorder) -> int
启动流水线,开始采集与编码写入。
file_recorder_stop(recorder, close_file) / file_recorder_close(recorder, close_file) -> int
停止流水线;close_file=true 时同步关闭文件并执行掐尾回退。
file_recorder_get_enc_time(recorder) -> int
获取已编码时长(用于录音时间显示)。
file_recorder_release(recorder) -> int
释放录音器句柄并从全局链表摘除。
回调:file_recorder_cb_t = void (*)(void *, enum stream_event)
通过 file_recorder_set_callback 注册,事件按 stream->id 精确分发到对应实例(见 file_recorder.c)。
故障模式、边界与并发
- open 失败路径:
file_recorder_open中zalloc或jlstream_pipeline_parse失败都会释放已分配内存并返回NULL,调用方必须判空;music_player_free则用引用计数保证多引用下不会提前释放; - 空链表保护:
music_player_callback在访问g_file_player.head前先list_empty判空,并在链表遍历前os_mutex_pend加锁,防止事件回调与句柄关闭并发时访问已摘除节点; - 文件未打开时的 IO:
recorder_fread/fwrite/fclose对recorder->file == NULL统一返回 0,避免空指针解引用——但这也意味着业务必须在start()前完成set_file/open_file,否则录音数据会静默丢弃; - 多实例并发:所有实例挂在全局链表上,靠
mutex保护链表写操作;事件分发在回调线程中遍历链表,list_for_each_entry_safe保证遍历期间摘除节点安全; - 掐头去尾边界:
recorder_fclose中只有(f_len - head_size) > cut_tail_size时才执行回退,避免对过短文件误裁剪; - 资源互斥:录音场景通过
STREAM_SCENE_RECODER声明,底层可据此拒绝冲突场景(如同时开两条采集链路),这是接口层与底层约定的隐性契约。
性能与运维注意
- 独立线程:
jlstream_add_thread为流水线分配专有线程,录制/播放不阻塞业务线程,但多实例会占用更多 RAM/栈,产品需按并发实例数评估; - IO 双通道:优先
fops(可指向缓存/加密层),标准库路径适合普通 FAT 文件系统;写录音文件建议用足够大的缓冲避免频繁小写; - 编译裁剪:AB 复读、断点续播、音效联动均为宏开关,关掉可省 RAM/代码段;
#pragma段声明(如.file_recorder.data.bss)把各模块数据放入独立段,便于链接器布局与审计内存占用; - 日志:接口层启用
LOG_TAG(如[FILE_RECOREDR]、[MUSIC_PLAYER])与LOG_*_ENABLE,可通过 CLI 打开调试日志定位事件时序问题。
扩展点
- 新增播放器/录音器:在
sdk/audio/interface/player|recorder/下按既有模式新建文件——内部zalloc句柄 +jlstream_pipeline_parse+ 回调分发 +list_add注册,然后在对应头文件声明 API 即可,无需改动框架; - 自定义文件介质:实现
struct stream_file_ops(read/write/seek/close)传给file_recorder_set_file,即可把录音写入加密盘、TF 卡或网络存储; - 事件钩子:在
music_player_callback的STREAM_EVENT_START分支追加音效联动(如新 EQ 参数更新),实现产品级"播放即生效"的策略; - 无缝录音:
file_recorder_seamless_set+file_recorder_change_file组合可实现分段文件连续录制,适合长时间录音按时间切片的需求。
Related Links
- file_player.c — 音乐播放器实现(含断点续播、AB 复读)
- file_recorder.c — 文件录音器实现
- file_recorder.h — 录音器 API 契约
- 播放器接口头文件:
a2dp_player.h、esco_player.h、le_audio_player.h、dev_flow_player.h、avi_audio_player.h(sdk/audio/interface/includes/) - 录音器接口头文件:
le_audio_recorder.h、pc_mic_recorder.h、usb_host_mic_recorder.h(同上) - 应用层录音模式:
sdk/apps/wifi_bbm/mode/recorder/recorder.c、sdk/apps/wifi_camera/mode/recorder/recorder.c、sdk/apps/wifi_soundbox/mode/recorder/recorder.c - DUER 语音助手录音链路:
sdk/apps/common/LLM/duer/intelligent_duer/duer_record.c、my_platform_record.c - 音频流媒体(
jlstream)与编解码器、net_avi_player等为兄弟主题,参见各自页面