外观
配置参考
配置文件与路径解析
config.toml 按域分组:server / upstream / concurrency / socket / logging / recording / vad。各组字段如下(键名不带组前缀),未出现的键使用下表默认值, 出现未知键会直接报错(deny_unknown_fields),避免拼错字段名却静默失效。
配置文件按以下顺序解析,命中即止:
- 第一个位置参数:
stream-vad-proxy ./my-config.toml - 环境变量
STREAM_VAD_PROXY_CONFIG_PATH - 进程当前工作目录下的
./config.toml
logging.dir 与 recording.dir 的相对路径按配置文件所在目录解析,所以从安装目录 (dist/<platform>/)运行时日志与录音都落在安装目录里。根 bun run dev:vad 正是以交付目录 为 CWD 启动的。
启动时会做一次配置自检 + 模型预检,任一项不通过就直接退出:
- 端口非 0;
wsPath/healthPath以/开头且互不相同;maxSessions > 0;vad.windowSize == 512、vad.threshold ∈ [0, 1];upstream.defaultProfile在upstream.profiles中必须存在;- 激活的 Profile 参数防御性校验(如
iflytek-iat校验url为http://、appid非空、svc非空、采样率组合受支持、攒批与超时参数合法等); - 模型可加载且能跑通一窗推理。
凭据与部署地址走环境变量,优先于配置文件:IFLYTEK_IAT_URL 覆盖激活 Profile 的 url、 IFLYTEK_IAT_APPID 覆盖激活 Profile 的 appid。仓库内的 config.toml 这两项一律留空。
server — 监听
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
host | string | "0.0.0.0" | 实际监听地址 |
port | uint16 | 10093 | 实际监听端口 |
healthPath | string | "/health" | HTTP 健康检查路径 |
wsPath | string | "/audio" | WebSocket 升级路径 |
wsSubprotocol | string | "audio.drachtio.org" | 要求客户端声明的子协议;为空则不强制 |
upstream — 上游 ASR Profile 配置
采用 Profile 模式组织上游,由 defaultProfile 指定当前激活的 Profile 名称:
toml
[upstream]
defaultProfile = "iflytek"
[upstream.profiles.iflytek]
provider = "iflytek-iat"
url = ""
appid = ""
svc = "iat"
type = "1"
busid = "stream-vad-proxy"
authNeed = false
sampleRate = 8000
chunkBytes = 800
maxChunkBytes = 8000
requestTimeoutMs = 10000
connectTimeoutMs = 3000
grsPollIntervalMs = 20
grsMaxPolls = 100
drainIdleMs = 1500
drainTimeoutMs = 8000| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
defaultProfile | string | "iflytek" | 默认激活的 Profile 名称 |
profiles | map | { "iflytek": ... } | Profile 映射表,键为 Profile 名称,值为具体厂商配置 |
Profile: iflytek-iat(科大讯飞私有云实时识别)
当 Profile 的 provider 为 "iflytek-iat"(或别名 "iflytek")时生效。协议细节与命令时序见上游适配器。
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
provider | enum | "iflytek-iat" | 上游提供方类型 |
url | string | "" | 形如 http://host:port/iat/。只支持 http://,适配器不实现 TLS |
appid | string | "" | 厂商分配的应用 ID |
svc | string | "iat" | 厂商服务名,实时识别取 iat |
type | string | "1" | 语种:1 普通话 / 2 维语 / 3 英语 / 4 粤语。厂商要求字符串形态 |
busid | string | "stream-vad-proxy" | 业务 ID,仅用于厂商侧日志追踪 |
authNeed | bool | false | 透传给厂商的 auth_need |
sampleRate | i32 | 8000 | 厂商侧采样率。与 vad.sampleRate(16000)不一致时由适配器做抗混叠降采样 |
chunkBytes | usize | 800 | 单次 auw 的目标字节数(8kHz 下 800 字节 ≈ 50ms)。按降采样后计 |
maxChunkBytes | usize | 8000 | 攒批上限。命令是串行 HTTP 往返,逐 20ms 帧一发追不上实时流 |
requestTimeoutMs | uint64 | 10000 | 单次 HTTP 往返超时 |
connectTimeoutMs | uint64 | 3000 | 建链探测超时 |
grsPollIntervalMs | uint64 | 20 | 段末取结果的轮询间隔 |
grsMaxPolls | uint32 | 100 | 轮询次数上限;超限按当前累计文本收尾并记 warn,不算致命错误 |
drainIdleMs | uint64 | 1500 | 客户端 flush 后等待收尾帧的帧间空闲上限 |
drainTimeoutMs | uint64 | 8000 | 同一次排空的硬上限 |
url 与 appid 是凭据性质的部署参数,仓库内的 config.toml 一律留空,运行时用环境变量注入:
powershell
$env:IFLYTEK_IAT_URL = "http://<host>:<port>/iat/"
$env:IFLYTEK_IAT_APPID = "<appid>"concurrency — 并发
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
maxSessions | usize | 256 | 并发会话上限;超过后新连接返回 503 |
workerThreads | usize | 0 | tokio 工作线程数;0 表示按 CPU 核心数自动 |
socket — 套接字
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
tcpNoDelay | bool | true | 对下游连接与上游连接同时启用 TCP_NODELAY |
maxFrameBytes | usize | 4194304 | 单个 WebSocket 帧最大字节数;超过即 1002 协议错误 |
logging — 日志
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
dir | string | "logs" | 日志目录,按天滚动;相对路径按配置文件所在目录解析 |
level | string | "info" | 本 crate 的日志级别(实际过滤器是 stream_vad_proxy=<level>,warn);设了 RUST_LOG 则以环境变量为准 |
debugTextFrames | bool | false | 打印转发的客户端文本帧与上游回传文本帧;客户端首帧 metadata 始终记录,不受此开关影响 |
debugAudioFrames | bool | false | 每个二进制帧落一条日志(字节数) |
debugVadState | bool | false | VAD 边沿落日志:开嗓、段完成、pre-roll 回补,调阈值时打开 |
recording — 录音
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enabled | bool | false | 启用上行音频录制 |
dir | string | "recordings" | 录制目录;相对路径按配置文件所在目录解析 |
录的是客户端推来的原始流,也就是本地 VAD 实际看到的那份音频,可以直接拿它回放复现某次误判。
vad — 语音活动检测
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
model | string | "silero-vad/silero_vad.onnx" | Silero VAD 模型文件名或路径 |
bufferSizeSeconds | float | 30.0 | VAD 内部环形缓冲秒数 |
threshold | float | 0.35 | 语音判定阈值,取值 [0, 1];调高更抗噪、更容易漏掉轻声 |
minSilenceDuration | float | 0.35 | 判定语音段结束所需的尾部静音秒数 |
minSpeechDuration | float | 0.15 | 有效语音段的最短秒数,低于此值不算一段 |
windowSize | int32 | 512 | 单窗采样点数,必须是 512 |
maxSpeechDuration | float | 20.0 | 单段语音最长秒数,超过强制切段 |
sampleRate | int32 | 16000 | 采样率,全链路固定 16kHz 单声道 PCM16 |
numThreads | int32 | 1 | ONNX 推理线程数 |
provider | string | "cpu" | ONNX 执行后端 |
debug | bool | false | sherpa-onnx 自身的调试输出 |
preRollMs | uint32 | 500 | 开嗓前预缓冲毫秒数,上升沿时一次性冲给上游,避免吃掉首字 |
vad.pool — Silero VAD 实例池
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enabled | bool | true | 是否启用 VAD 实例池化复用(基于无锁环形队列 crossbeam_queue::ArrayQueue) |
prewarmSessions | usize | 16 | 服务启动在监听网络端口前并发预热加载并热身的实例数 |
maxIdleSessions | usize | 64 | 实例池允许缓存的最大空闲实例数上限,超额归还实例自然析构 |
校验规则:prewarmSessions <= maxIdleSessions <= concurrency.maxSessions。
两点必须知道:
- 默认值对齐的是
onnx-platform/sherpa-asr-server/config.toml的实际运行值 (0.35/0.35/0.15),不是编译期默认(0.5/0.5/0.25)。 windowSize不是可调旋钮。仓库内的silero_vad.onnx是 silero v4,输入签名x:[1,512],窗口大小写死在计算图里,填别的值启动时就会被拦下。音频按 512 采样点整窗喂入, 余数跨帧保留。
模型路径解析
vad.model 按以下顺序解析,命中即止:
- 绝对路径直接使用
<配置文件所在目录>/<model><配置文件所在目录>/../models/<model>- 从配置目录向上最多 4 级,查找
onnx-platform/models/<model>与models/<model>
构建脚本已把 onnx-platform/models/silero-vad/silero_vad.onnx 拷进交付目录,所以从交付目录运行时走第 2 条 即命中;在仓库内直接 cargo run 则走第 4 条回落到 onnx-platform/models/。
与其它配置的关系
- 接入侧只改
apps/callflow-esl/config.toml的audioFork.wsUrl指向本代理,bugName/mixType/sampleRate全部不动。 - 要吃到开嗓提速,业务侧需把
bargeInTrigger设为"speech-start";默认的partial策略 只认有文本的帧,空文本 VAD 帧不会触发打断,抗环境底噪误触最稳妥。 - 部署到 WSL docker 计算集群时使用
deploy/wsl-docker/configs/stream-vad-proxy.toml, 端口与上游地址按集群约定另有一套值,见deploy/wsl-docker/README.md。