语音识别 ASR 引擎
AC79 AIoT SDK 中的语音识别(ASR)引擎能力,涵盖 asr_server 服务任务接口、Roobo/Fig 本地识别算法 API、简洁封装层以及 Wanson、腾讯云等第三方 ASR 供应商集成。
Purpose and Scope
本页说明 AC79 系列芯片 SDK 中 ASR 引擎的完整架构与实现,包括:
- 服务框架层:
include_lib/server/asr_server.h定义的 ASR 服务器消息/请求/事件协议,以及app_main.c中asr_server任务注册方式; - 本地算法层:Roobo/Fig 引擎的公开 API(
fig_asr_api.h)与数据类型(fig_asr_type.h),即神经网络(NNET)+ WFST 解码器架构; - 简洁封装层:
apps/common/asr/roobo/asr.h提供的asr_init/asr_process等极简接口; - 第三方供应商集成:Wanson 引擎(
apps/common/asr/wanson/fn_asr.h及预编译库lib_wanson_asr.a)与腾讯云 IoT 云端 ASR(qcloud_iot_export_asr.h)。
以下主题属于相邻页面,不在本页展开:语音唤醒(wake-on-voice / KWS)算法的内部实现、音频采集与播报链路、各应用(wifi_story_machine 等)的 ASR 业务交互逻辑。本页聚焦 ASR 引擎本身的接口、分层与运行机制。
Overview
在 AC79 这类资源受限的 AIoT 芯片上,语音识别被设计为分层、可替换的子系统,其核心设计意图有四点:
- 任务隔离:ASR 作为一个独立 server 任务运行(见
apps/wifi_camera/app_main.c中"asr_server"任务注册,优先级 15、栈 1024),与音频采集、网络、UI 任务解耦,避免识别计算阻塞其他关键路径。 - 算法可替换:SDK 同时提供 Roobo/Fig 本地引擎(
apps/common/asr/roobo/)与 Wanson 引擎(apps/common/asr/wanson/及预编译库),上层业务通过统一的服务器接口使用,切换供应商无需改动业务代码。 - 在线/离线双模式:本地引擎(Fig、Wanson)用于无网络或低延迟场景;腾讯云 IoT SDK 提供云端 ASR 出口,用于需要大词表或云端语义理解的场景。
- 实时流式处理:本地识别以 30ms(16kHz/16bit/mono 下 480 个采样点)为音频帧粒度流式送入引擎,配合唤醒(wake-on-voice)机制,实现"先唤醒、后识别"的低功耗交互链路。
理解这套机制的关键是掌握三个层次:服务框架层(server 协议)→ 算法抽象层(Fig API / 简洁封装)→ 供应商实现(预编译库 / 云端 SDK)。
Architecture
flowchart TD
subgraph sg_App["应用层 (apps)"]
AppMain["app_main.c<br/>server 任务注册表"]
StoryApp["wifi_story_machine 等业务应用"]
end
subgraph sg_Server["服务框架层 (server)"]
AsrServer["asr_server 任务<br/>prio=15, stack=1024, qsize=64"]
WakeVoice["wake-on-voice 任务<br/>prio=7, stack=1024"]
AsrProto["asr_server.h<br/>STATE / ASR_REQ / ASR_SER_EVENT"]
end
subgraph sg_Algo["本地算法层"]
FigApi["Fig API (Roobo)<br/>fig_asr_api.h / fig_asr_type.h"]
SimpleAsr["简洁封装 asr.h<br/>asr_init / asr_process"]
Wanson["Wanson 引擎<br/>fn_asr.h + lib_wanson_asr.a"]
end
subgraph sg_Cloud["云端"]
Tencent["腾讯云 IoT ASR<br/>qcloud_iot_export_asr.h"]
end
AppMain -->|"注册 server 任务"| AsrServer
AsrServer --> AsrProto
AsrServer -->|"唤醒开/关请求"| WakeVoice
WakeVoice -->|"ASR_SER_EVENT_WAKE"| AsrServer
AsrServer --> FigApi
AsrServer --> SimpleAsr
AsrServer --> Wanson
StoryApp -->|"识别请求/结果"| AsrServer
StoryApp -->|"云端识别"| Tencent
架构分层说明
- 应用层:
app_main.c中的 server 任务表把asr_server注册为系统任务(wifi_camera、wifi_ipc 均以{"asr_server", 15, 1024, 64}登记,即优先级 15、栈 1024 字节、消息队列深度 64);业务应用如wifi_story_machine通过任务消息与 ASR 引擎交互。 - 服务框架层:
asr_server.h定义引擎对外的最小协议面——开关状态、唤醒请求、唤醒事件,以及struct asr_wake携带的唤醒参数。该头文件放在include_lib/server/下,说明它是被 server 框架与各应用共同引用的公共契约。 - 本地算法层:Fig API 以不透明句柄
FIG_INST隔离实现细节;asr.h则是更上层的极简封装(面向"喂 30ms 音频、拿文本"的直白用法)。Wanson 引擎以预编译库形式提供,编译期通过CONFIG_ASR_ALGORITHM等宏选择(见apps/wifi_story_machine/app_music_dui.c中的条件编译引用)。 - 云端:腾讯云 IoT C SDK 导出
qcloud_iot_export_asr.h,为联网设备提供云端 ASR 通道,与本地引擎互补。
设计上,算法层与服务器层之间没有强绑定:只要满足 asr_server.h 的请求/事件协议,任何供应商引擎都可以接入,这正是该分层结构存在的根本原因。
主要实现剖析
服务框架层:asr_server.h 协议与任务注册
include_lib/server/asr_server.h 是整个 ASR 引擎对外的最小协议契约,全文仅三个枚举、一个结构体和一个联合体,但定义了引擎的全部对外交互面:
enum {
STATE_OFF,
STATE_ON,
};
enum {
ASR_REQ_WAKE_ON_VOICE_ON,
ASR_REQ_WAKE_ON_VOICE_OFF,
};
enum {
ASR_SER_EVENT_WAKE,
};
struct asr_wake {
void *enc_buf;
int enc_buf_len;
const char *data_file_path;
u32 idle_gap_16ms;
u32 run_gap_16ms;
int best_sc;
};
union asr_req {
struct asr_wake wake;
};
Source: asr_server.h
各部分的语义与设计意图:
- STATE_OFF / STATE_ON:引擎(或唤醒功能)的运行状态。服务任务用这两个状态维护内部状态机,供请求处理时校验当前是否处于可接受状态。
- ASR_REQ_WAKE_ON_VOICE_ON / OFF:外部(如按键、App 指令)向 ASR 服务发送"开启/关闭语音唤醒"请求。把唤醒开关做成请求而非直接调用,是为了让唤醒与识别都在同一任务上下文内串行执行,避免并发访问模型与音频缓冲。
- ASR_SER_EVENT_WAKE:唤醒命中后由服务任务发出的事件,业务层监听该事件后进入识别会话(或点亮屏幕、开始录音等)。事件驱动是典型嵌入式状态机风格:引擎不主动回调,而是把状态变化"上报"给消息循环。
- struct asr_wake:一次唤醒配置的载体——
enc_buf/enc_buf_len为编码后的唤醒模型缓冲区(预加载进内存,避免运行时读 Flash 抖动),data_file_path指向模型文件路径,idle_gap_16ms与run_gap_16ms分别是以 16ms 为单位的静默间隔与运行间隔(用于控制唤醒检测节奏、省电),best_sc为最佳得分阈值参考。 - union asr_req:为将来扩展其他请求类型预留的联合体(目前只有
wake成员)。联合体保证请求消息体积最小,节省任务消息队列(qsize=64)的拷贝开销。
该任务在应用侧注册的实例如下(wifi_camera 与 wifi_ipc 配置一致):
{"asr_server", 15, 1024, 64 },
Source: apps/wifi_camera/app_main.c
即优先级 15、栈 1024 字节、消息队列 64。注意同表里 "wake-on-voice" 任务优先级为 7、栈 1024:唤醒任务优先级更低,说明唤醒检测被刻意设计为后台低开销活动,而 asr_server 优先级更高,保证识别阶段(计算密集)能及时抢占资源。
本地算法层:Fig ASR API(Roobo)
apps/common/asr/roobo/fig_asr_api.h 是本地识别引擎(Fig,来自 Roobo 方案)的公开 C 接口,采用"不透明句柄 + 生命周期管理"模式:
typedef void *FIG_INST;
int FigCreateInst(FIG_INST *inst, const char *szNnet, const char *szGraph);
int FigDestroyInst(FIG_INST inst);
int FigSetParameter(FIG_INST inst, AsrParamType eType, const char *szValue);
int FigStartProcess(FIG_INST inst);
int FigStopProcess(FIG_INST inst);
int FigWriteAudio(FIG_INST inst, char *pData, int nLen, int bFinish, PAsrResult *ppResult);
Source: fig_asr_api.h
关键设计:
- FIG_INST 不透明句柄:引擎内部状态(神经网络、WFST 解码图、中间缓冲)全部隐藏在句柄之后,接口层零暴露,供应商可自由升级算法而保持 ABI 稳定。
- 创建/销毁配对:
FigCreateInst需要两个资源参数——szNnet(神经网络模型,通常是训练好的声学模型文件路径)与szGraph(WFST 加权有限状态转换器解码图,即命令词表编译产物);FigDestroyInst负责释放。这对应fig_asr_type.h中的资源类型:
typedef enum {
NNET_MODEL = 0,
WFST_COMMAND,
WFST_FILLER,
} AsrResType;
typedef enum {
REC_CM_THRES,
REC_RESET_CM_THRES,
REC_DECODER_BEAM,
REC_FILLER_NUM,
} AsrParamType;
typedef struct tagResult {
int nBegin;
int nEnd;
char szText[32];
short nWordId;
int nCmScore;
} AsrResult, *PAsrResult;
Source: fig_asr_type.h
- AsrResType 描述引擎持有的三类资源:声学模型(NNET_MODEL)、命令词 WFST 图(WFST_COMMAND)、填充词 WFST 图(WFST_FILLER)。命令词与填充词分开,是经典"关键词检出 + 拒识"设计:非命令词(填充词)命中时不输出结果,可显著降低误识别。
- AsrParamType 是运行期可调参数:
REC_CM_THRES置信度(confidence measure)阈值,控制输出结果的严格程度;REC_RESET_CM_THRES用于动态重置阈值;REC_DECODER_BEAM解码束宽,权衡识别率与算力;REC_FILLER_NUM填充词数量。FigSetParameter统一以字符串传值,天然支持从配置文件读取。 - AsrResult 输出结构:
nBegin/nEnd是命中词在音频流中的起止位置,szText[32]是识别文本(固定 32 字节,命令词场景足够),nWordId是词表 ID(便于程序化处理,不依赖字符串比较),nCmScore是置信度得分。 - FigWriteAudio 的 bFinish 标志:流式接口。
bFinish=1表示本次为音频流末尾,引擎需冲刷解码器并输出最终结果——这一"半开式"(half-open)语义让调用方既能边录边识别,又能在端点检测(VAD)结束时拿到确定结果。
简洁封装层:asr.h
apps/common/asr/roobo/asr.h 面向最简单的使用方式:初始化 → 循环喂音频 → 取结果。它把 Fig API 的复杂度收敛为四个函数,并明确约定了音频格式与帧长:
// Return value : 0 - OK, -1 - Error
int asr_init();
void asr_reset();
/*****************************************
* Input:
* - buf : Audio data (16k, 16bit, mono)
* - buf_len : Now must be 480 (30ms)
*
* Output:
* - text : The text of ASR
* - score : The confidence of ASR (Now not used)
*
* Return value : 0 - No result
* 1 - Has result
* -1 - Error
******************************************/
int asr_process(short *buf, int buf_len, const char **text, float *score);
void asr_release();
Source: asr.h
设计要点:
- 固定帧长契约:注释明确
buf_len现在必须为 480(即 30ms @16kHz/16bit/mono)。这既是约束也是优化依据——内部环形缓冲与解码步进可按 480 对齐,避免动态分帧的运行时开销。 - 返回值三态语义:
0表示当前帧无结果(正常、持续喂帧),1表示本帧产出了识别文本,-1表示错误(如未初始化、参数非法)。调用方只需轮询即可,无需理解引擎内部状态。 - score 暂未使用:注释坦诚"Now not used",说明该接口保留了置信度输出通道,为将来按分数过滤预留。
- asr_reset 与 asr_release 分离:
reset清空会话状态(结束上一轮识别、可立即开始新一轮),release释放全部资源(退出识别功能时调用)。会话复用(reset)与资源销毁(release)的区分,对长时间运行设备至关重要——每轮唤醒对话只 reset、不 release,避免反复加载模型。
第三方供应商:Wanson 与腾讯云
- Wanson(本地):
apps/common/asr/wanson/fn_asr.h为 Wanson 引擎头文件,实现以预编译库cpu/wl82/liba/lib_wanson_asr.a形式提供,与 Fig 引擎形成"双本地引擎"格局。应用层通过CONFIG_ASR_ALGORITHM宏条件编译选择算法(如apps/wifi_story_machine/app_music_dui.c中#ifdef CONFIG_ASR_ALGORITHM引用aisp_open)。具体函数签名未在本页读取范围内,未在源码中进一步核实的细节不做展开。 - 腾讯云(云端):
lib/net/tencent/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_asr.h是腾讯云 IoT C SDK 导出的 ASR 接口,用于联网设备把音频上传云端识别。它属于完整的网络 SDK 子系统,接口细节不在本页范围内。
核心流程
ASR 引擎的典型运行过程是"唤醒 → 建实例 → 流式识别 → 取结果 → 收尾",其完整时序如下:
sequenceDiagram
participant App as 业务应用/服务任务
participant Svr as asr_server 任务
participant Fig as Fig 引擎 (FIG_INST)
participant Audio as 音频采集 (16k/16bit/mono)
App->>Svr: ASR_REQ_WAKE_ON_VOICE_ON (asr_wake 参数)
Svr->>Svr: 校验状态 STATE_OFF -> STATE_ON
Note over Svr,Fig: 唤醒命中后
Svr-->>App: ASR_SER_EVENT_WAKE
App->>Svr: 开始识别会话
Svr->>Fig: FigCreateInst(szNnet, szGraph)
Fig-->>Svr: FIG_INST 句柄
Svr->>Fig: FigSetParameter(REC_CM_THRES, ...)
Svr->>Fig: FigStartProcess()
loop 每 30ms 一帧 (480 samples)
Audio->>Svr: buf[480]
Svr->>Fig: FigWriteAudio(pData, 960B, bFinish=0, &pResult)
alt 命中命令词
Fig-->>Svr: AsrResult { szText, nWordId, nCmScore }
Svr-->>App: 识别文本/词ID
else 无结果
Fig-->>Svr: pResult 为空
end
end
App->>Svr: 会话结束 (VAD 超时/用户停止)
Svr->>Fig: FigWriteAudio(..., bFinish=1, &pResult)
Svr->>Fig: FigStopProcess()
Svr->>Fig: FigDestroyInst(inst)
Svr->>Svr: 状态复位,等待下一轮唤醒
流程关键点说明:
- 唤醒先行:识别会话不是任意时刻都能开始。
asr_server收到ASR_REQ_WAKE_ON_VOICE_ON后进入STATE_ON,底层wake-on-voice任务(优先级 7,低于 asr_server 的 15)持续监听;命中后服务任务发出ASR_SER_EVENT_WAKE,业务层才启动识别。这种两级流水线把功耗最高的识别阶段压缩到最短时间窗内。 - 实例生命周期:每轮识别
FigCreateInst→FigStartProcess→FigStopProcess→FigDestroyInst成对出现,保证模型与解码图在会话结束后立即释放,为下一轮(或低功耗模式)腾出内存。 - 流式写音频:识别阶段以 30ms 帧为粒度
FigWriteAudio,返回值可即时反馈——既支持"边说话边出字"的流式体验,也支持等bFinish=1时一次性拿最终结果。 - 参数可调:在 Start 之前通过
FigSetParameter设置置信度阈值与解码束宽,允许不同产品(安静家居 vs 嘈杂商场)运行时差异化调优,无需重新编译模型。
使用示例
以下示例均直接取自仓库源码,展示三种层级的典型用法。
示例一:服务层请求/事件协议(asr_server.h)
enum {
STATE_OFF,
STATE_ON,
};
enum {
ASR_REQ_WAKE_ON_VOICE_ON,
ASR_REQ_WAKE_ON_VOICE_OFF,
};
enum {
ASR_SER_EVENT_WAKE,
};
struct asr_wake {
void *enc_buf;
int enc_buf_len;
const char *data_file_path;
u32 idle_gap_16ms;
u32 run_gap_16ms;
int best_sc;
};
Source: asr_server.h
业务侧据此构造唤醒请求:填充 struct asr_wake(预加载的编码唤醒模型 enc_buf、模型文件路径 data_file_path、16ms 粒度的静默/运行间隔、最佳得分参考 best_sc),以 ASR_REQ_WAKE_ON_VOICE_ON 发送给 asr_server;之后在消息循环中监听 ASR_SER_EVENT_WAKE 即可获知唤醒命中。
示例二:本地引擎生命周期(fig_asr_api.h)
typedef void *FIG_INST;
int FigCreateInst(FIG_INST *inst, const char *szNnet, const char *szGraph);
int FigDestroyInst(FIG_INST inst);
int FigSetParameter(FIG_INST inst, AsrParamType eType, const char *szValue);
int FigStartProcess(FIG_INST inst);
int FigStopProcess(FIG_INST inst);
int FigWriteAudio(FIG_INST inst, char *pData, int nLen, int bFinish, PAsrResult *ppResult);
Source: fig_asr_api.h
典型调用序列:FigCreateInst(&inst, nnet_path, graph_path) 创建实例 → FigSetParameter(inst, REC_CM_THRES, "60") 调阈值 → FigStartProcess(inst) 启动 → 循环 FigWriteAudio(inst, pcm, len, 0, &res) 喂音频并收集结果 → 结束时以 bFinish=1 冲刷 → FigStopProcess + FigDestroyInst 收尾。
示例三:简洁封装逐帧处理(asr.h)
// Return value : 0 - OK, -1 - Error
int asr_init();
void asr_reset();
/*****************************************
* Input:
* - buf : Audio data (16k, 16bit, mono)
* - buf_len : Now must be 480 (30ms)
*
* Output:
* - text : The text of ASR
* - score : The confidence of ASR (Now not used)
*
* Return value : 0 - No result
* 1 - Has result
* -1 - Error
******************************************/
int asr_process(short *buf, int buf_len, const char **text, float *score);
void asr_release();
Source: asr.h
主循环写法:asr_init() 后,每次取 480 个采样(30ms)调用 asr_process;返回 1 时从 *text 读取识别文本;一轮会话结束后调用 asr_reset() 复用引擎;退出识别时调用 asr_release()。该接口屏蔽了 Fig 的实例管理与参数细节,适合业务快速集成。
示例四:引擎选择宏(wifi_story_machine)
#ifdef CONFIG_ASR_ALGORITHM
extern int aisp_open(u16 sample_rate);
Source: apps/wifi_story_machine/app_music_dui.c
应用层通过 CONFIG_ASR_ALGORITHM 编译宏选择具体算法实现(此处引用的 aisp_open 属于另一供应商接口),印证了"算法可替换"的分层设计:业务代码只依赖宏开关,不直接依赖某个引擎头文件。
配置选项
ASR 引擎的可配置项分布在三个层面:服务器任务注册参数、Fig 引擎运行参数、唤醒参数。
服务器任务注册参数
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| 任务名 | string | "asr_server" | 在 server 任务表中注册的名称,须与框架约定一致 |
| 优先级 | int | 15 | 高于 "wake-on-voice"(7),保证识别阶段抢占资源 |
| 栈大小 | int | 1024 | 任务栈字节数,识别调用链深度受此约束 |
| 消息队列深度 | int | 64 | 请求消息容量,union asr_req 保持请求体最小以降低拷贝压力 |
(来源:apps/wifi_camera/app_main.c,wifi_ipc 配置相同)
Fig 引擎运行参数(AsrParamType)
| 枚举值 | 说明 | 典型用途 |
|---|---|---|
REC_CM_THRES | 置信度阈值 | 控制输出严格度;调高降误识别、调低提召回 |
REC_RESET_CM_THRES | 重置置信度阈值 | 会话间动态恢复默认阈值 |
REC_DECODER_BEAM | 解码束宽 | 权衡识别率与 CPU 开销,束宽越大越慢但越准 |
REC_FILLER_NUM | 填充词数量 | 配置拒识词数量,抑制非命令词误触发 |
FigSetParameter 统一以 const char *szValue 传值,便于从配置文件或服务器下发参数直接透传。
唤醒配置(struct asr_wake)
| 字段 | 类型 | 说明 |
|---|---|---|
enc_buf | void * | 预加载的编码唤醒模型内存缓冲 |
enc_buf_len | int | 编码模型缓冲长度 |
data_file_path | const char * | 唤醒模型文件路径 |
idle_gap_16ms | u32 | 静默间隔(单位 16ms),控制检测节奏 |
run_gap_16ms | u32 | 运行间隔(单位 16ms),省电相关 |
best_sc | int | 最佳得分参考,用于唤醒判定 |
简洁封装层约定
| 项 | 值 | 说明 |
|---|---|---|
| 音频格式 | 16kHz / 16bit / mono | asr_process 输入硬性要求 |
| 帧长 | 480 samples(30ms) | 当前版本 buf_len 必须为 480 |
asr_process 返回值 | 0 / 1 / -1 | 无结果 / 有结果 / 错误 |
API Reference
Fig 引擎(fig_asr_api.h)
int FigCreateInst(FIG_INST *inst, const char *szNnet, const char *szGraph)
创建 ASR 引擎实例。
参数:
inst(FIG_INST *):输出参数,接收不透明实例句柄szNnet(const char *):神经网络(声学)模型路径szGraph(const char *):WFST 解码图(命令词表)路径
返回: int,0 成功,非零失败(具体错误码未在头文件定义)。
说明: 创建过程加载声学模型与解码图,应在识别会话开始前调用,与 FigDestroyInst 配对。
int FigDestroyInst(FIG_INST inst)
销毁引擎实例,释放模型与解码资源。
参数: inst (FIG_INST):待销毁的实例句柄。
返回: int,0 成功。
int FigSetParameter(FIG_INST inst, AsrParamType eType, const char *szValue)
设置运行参数(见上文 AsrParamType 表)。
参数:
inst(FIG_INST):实例句柄eType(AsrParamType):参数类型szValue(const char *):字符串形式的参数值
返回: int,0 成功。
int FigStartProcess(FIG_INST inst)
启动识别处理(进入可写音频状态)。
参数: inst (FIG_INST)。
返回: int,0 成功。
int FigStopProcess(FIG_INST inst)
停止识别处理。
参数: inst (FIG_INST)。
返回: int,0 成功。
int FigWriteAudio(FIG_INST inst, char *pData, int nLen, int bFinish, PAsrResult *ppResult)
写入一帧音频并(可能)返回识别结果。
参数:
inst(FIG_INST):实例句柄pData(char *):PCM 音频数据(16kHz/16bit/mono)nLen(int):数据字节数bFinish(int):1表示音频流结束,引擎冲刷解码器ppResult(PAsrResult *):输出参数,命中时指向AsrResult(含szText/nWordId/nCmScore/nBegin/nEnd),无结果时为空
返回: int,0 成功。
简洁封装(asr.h)
int asr_init()
初始化 ASR 引擎(加载模型等一次性资源)。返回 0 成功,-1 错误。
void asr_reset()
重置会话状态,清空上一轮识别上下文,可立即开始新一轮识别(不释放资源)。
int asr_process(short *buf, int buf_len, const char **text, float *score)
逐帧识别。
参数:
buf(short *):音频数据,16kHz/16bit/monobuf_len(int):采样点数,必须为 480(30ms)text(const char **):输出识别文本score(float *):置信度输出(当前版本未使用)
返回: 0 无结果;1 有结果(读取 *text);-1 错误。
Throws/错误: 头文件未声明异常,错误统一以 -1 返回值表示(如未初始化、帧长非法)。
void asr_release()
释放引擎全部资源,退出识别功能时调用。
故障模式、边界情况与并发
错误处理
asr_process返回-1:表示引擎错误(如未asr_init、buf_len非 480)。调用方必须检查返回值,不能把-1当"无结果"继续喂帧,否则可能掩盖引擎异常状态。FigCreateInst/FigDestroyInst失败:模型文件缺失或内存不足时返回非零。由于句柄是不透明指针,失败后inst内容不可用,调用方应终止会话并重试或回退到提示音(SDK 提供AiAsrFail.mp3提示资源,见 wifi_story_machine 的提示音表)。- 识别为空:静音或全是填充词时无输出,SDK 提供
AsrEmpty.mp3提示资源(APP_LOCAL_PROMPT_ASR_EMPTY),业务层据此播报"没听清"。
边界条件
- 帧长契约:
asr_process的buf_len被硬性约定为 480(30ms)。音频采集侧必须按此粒度切帧;若采集粒度不匹配,需在中间层重采样/缓冲对齐,否则引擎行为未定义。 szText[32]定长缓冲:AsrResult.szText固定 32 字节,命令词场景足够;若词表出现超长命令词,文本会被截断,业务侧应以nWordId为准做程序化匹配。- 唤醒参数以 16ms 为粒度:
idle_gap_16ms/run_gap_16ms均以 16ms 为单位,配置时需按此粒度换算。
并发与一致性
- 单任务串行模型:
asr_server以独立任务运行,唤醒开关请求(ASR_REQ_WAKE_ON_VOICE_*)与识别会话都在该任务消息循环内处理,天然避免了对模型、音频缓冲的并发访问。业务层不得跨任务直接调用 Fig 接口,必须通过 server 消息间接驱动。 - 唤醒与识别优先级分层:
wake-on-voice(优先级 7)与asr_server(优先级 15)形成"低开销监听 + 高优先级识别"的配合。唤醒命中的瞬间存在任务切换延迟,但识别帧率由 30ms 帧长兜底,通常可容忍。 - 会话资源独占:
FigCreateInst创建的实例在本轮会话内独占模型资源,FigStopProcess/FigDestroyInst前不得开启新一轮会话,否则可能造成资源泄漏或解码状态错乱。
性能与运维
- 实时性预算:识别以 30ms 音频帧为输入,算法处理必须在帧间隔内完成(含
FigWriteAudio内部解码)。解码束宽(REC_DECODER_BEAM)是主要性能旋钮:束宽越大识别率越高、CPU 占用越大,产品需按主控频率实测标定。 - 内存占用:
asr_server栈仅 1024 字节,Fig 引擎的大块内存(声学模型、WFST 图、内部缓冲)应通过堆分配管理,避免压栈;唤醒模型建议预加载到enc_buf(内存常驻),换取运行时无 Flash 读取抖动。 - 任务优先级语义:asr_server 优先级 15 高于多数业务任务,识别会话期间会抢占 CPU;若同时有网络/显示关键路径,需评估整体调度余量(优先级数值越小越高的平台需按 SDK 约定核对)。
- 编译期引擎选择:通过
CONFIG_ASR_ALGORITHM等宏在编译期选定算法(Fig / Wanson / 云端),可裁剪未用引擎代码以减小固件体积;预编译库(如lib_wanson_asr.a)按目标平台(cpu/wl82/)配套提供。
扩展点
- 接入新 ASR 供应商:只需满足
asr_server.h的请求/事件协议(ASR_REQ_WAKE_ON_VOICE_*、ASR_SER_EVENT_WAKE、struct asr_wake),并把引擎调用封装进asr_server任务内部即可;union asr_req预留了扩展新请求类型的空间。 - 运行参数动态下发:
FigSetParameter的字符串传值设计支持把阈值、束宽等参数接入配置系统或服务器下发通道,实现产品级远程调优而不改固件。 - 提示音资产替换:识别失败(
AiAsrFail.mp3)、进入 ASR 模式(AiAsrMode.mp3)、识别为空(AsrEmpty.mp3)等提示音位于提示音映射表中,可替换音频文件以适配不同产品语种与话术。 - 上层封装复用:
asr.h的极简接口适合被业务模块直接复用;如需流式中间结果,可下沉到 Fig 层自行管理AsrResult的nBegin/nEnd时间戳。
测试
仓库中未发现针对 ASR 引擎的独立单元测试文件(apps/common/asr/ 目录仅包含引擎头文件与实现)。引擎验证主要依赖:
- 应用级集成验证:wifi_story_machine 等应用通过提示音资产(
AiAsrFail.mp3、AsrEmpty.mp3等)反馈识别成败,可据此做端到端冒烟测试; - 模型/词表迭代:
WFST_COMMAND/WFST_FILLER图的替换与REC_CM_THRES阈值标定属于离线评测范畴,需在真实环境(信噪比、麦克风距离)下采集数据验证。
说明:本页基于仓库中可读取的头文件与任务注册代码整理;引擎内部实现以预编译库形式提供,函数内部算法细节未在源码中体现。
Related Links
- asr_server.h — 服务层协议
- fig_asr_api.h — Fig 引擎 API
- fig_asr_type.h — 资源/参数/结果类型
- asr.h — 简洁封装接口
- fn_asr.h — Wanson 引擎接口
- qcloud_iot_export_asr.h — 腾讯云 ASR
- apps/wifi_camera/app_main.c — asr_server 任务注册
- apps/wifi_story_machine/app_music_dui.c — 算法宏选择与提示音
相关目录页:语音唤醒(wake-on-voice / KWS)机制、server 框架任务模型、音频采集与处理链路、腾讯云 IoT 接入。