一句话定位

azure-speech-gateway 是一个 Bun + TypeScript 的 Azure Speech 兼容网关。它把
Microsoft Azure 实时语音识别(ASR)与语音合成(TTS)包装成与平台本地 / 阿里云语音
链路一致的协议,让 callflow-esl、FreeSWITCH mod_audio_fork 或管理台测试工具在
不改调用方式的情况下切换到 Azure。

它和 阿里云语音网关 是一对”姊妹网关”:协议形态、健康检查、
TTS 返回结构都一致,只是底座换成了 Azure。默认主链路仍然是
mod_audio_fork + sherpa-asr-online-server + sherpa-tts-server;当你想验证 Azure
识别 / 多语言效果、给本地模型做兜底、或临时借用 Azure 音色时,单独启动这个网关即可。

Azure 网关相比阿里云网关多了一项工程能力:支持 bun build --compile 打成
Windows / Linux x64 独立可执行文件,便于在没有 Bun 运行时的机器上直接部署。

服务形态

能力 默认地址 协议 用途
ASR 健康检查 http://127.0.0.1:10098/health HTTP 查看网关状态与会话数
ASR 实时识别 ws://127.0.0.1:10098/audio WebSocket 兼容 mod_audio_fork 子协议
TTS 健康检查 http://127.0.0.1:9082/health HTTP 查看采样率、音色列表
普通 TTS POST http://127.0.0.1:9082/tts HTTP JSON 返回 wav URL
流式 TTS POST http://127.0.0.1:9082/tts-stream HTTP JSON + MP3 GET 先返回短期 MP3 播放链接

ASR 侧使用 audio.drachtio.org 子协议,输入按 16kHz、单声道、PCM16 处理;TTS 侧返回
{ wavUrl, fileName, sampleRate, cached },因此管理台试听与 callflow-esl 的 TTS 调用
可以复用同一套逻辑。端口与阿里云网关错开(ASR 10098 / TTS 9082,阿里云是
10097 / 9081),两个网关可以同时启动做对比。

启动

在仓库根目录安装依赖并启动:

1
2
bun install
bun run dev:azure-speech

也可以进入子项目:

1
2
3
4
cd apps/azure-speech-gateway
bun run dev # 监听模式
bun run start # 启动一次
bun run typecheck # TypeScript 类型检查

默认不包含在根目录 bun run dev 的 8 服务并发启动组中,需要按需单独运行。

构建独立可执行文件

1
2
3
4
bun run build        # typecheck 后构建 Windows x64
bun run build:win # 构建 dist/win_x64/azure-speech-gateway.exe
bun run build:linux # 从当前环境交叉构建 dist/linux_x64/azure-speech-gateway
bun run build:all # typecheck 后构建 Windows + Linux x64

构建产物是可直接部署的目录,含一个独立可执行文件和外置 config.json

1
2
dist/win_x64/azure-speech-gateway.exe + config.json
dist/linux_x64/azure-speech-gateway + config.json

运行时默认读取可执行文件同目录下的 config.json,也可用环境变量
AZURE_SPEECH_GATEWAY_CONFIG_PATH 指定其它配置文件:

1
2
3
cd dist\win_x64
$env:AZURE_SPEECH_GATEWAY_CONFIG_PATH = "C:\deploy\azure-speech-gateway\config.json"
.\azure-speech-gateway.exe

Linux 二进制可在 Windows 上交叉编译,但仍需在目标 Linux 主机验证 Azure 网络访问、端口
监听、缓存目录权限。

凭据与配置

配置文件位于 apps/azure-speech-gateway/config.json。Azure Speech 凭据可以写在配置
文件里,但实际部署优先用环境变量覆盖,便于轮换:

1
2
3
4
$env:AZURE_SPEECH_KEY="your-subscription-key"
$env:AZURE_SPEECH_REGION="uksouth"
$env:AZURE_SPEECH_TTS_ENDPOINT="https://uksouth.tts.speech.microsoft.com/cognitiveservices/v1"
bun run --cwd apps/azure-speech-gateway start

关键配置:

配置段 字段 说明
azure region / endpoint / ttsEndpoint Azure Speech 区域、资源 endpoint 与 TTS REST endpoint
azure subscriptionKey Azure Speech key,可被 AZURE_SPEECH_KEY 覆盖
asr host / port / wsPath ASR 监听地址、端口(默认 10098)与 WebSocket 路径
asr wsSubprotocol 默认 audio.drachtio.org,用于兼容 mod_audio_fork
asr maxSessions 最大并发 ASR 会话数,默认 64
asr maxQueuedAudioBytes Azure SDK 启动完成前每路最多缓存的音频字节数,默认 524288
asr startTimeoutMs Azure SDK 启动超时,默认 10000
asr autoDetectLanguages 自动识别候选语言,默认 ["zh-CN", "en-US"]
asr sampleRate / bitsPerSample / channels / format 输入音频格式,默认 16000 / 16 / 1 / pcm
tts host / port / publicBaseUrl TTS 监听地址、端口(默认 9082)与返回给调用方的公开基址
tts defaultVoice / voices 默认音色与 speakerId 到 Azure voice 的映射
tts outputFormat / streamOutputFormat WAV 与 MP3 输出格式
tts requestTimeoutMs / maxTextLength TTS 请求超时与单次合成文本长度上限
logging dir / maxSize / maxFiles / level 控制台与按天轮转文件日志

默认内置三个中文音色:zh-CN-XiaoxiaoNeural(id 0,默认)、zh-CN-YunxiNeural(id 1)、
zh-CN-YunjianNeural(id 2);按需在 tts.voices 里补充 Azure 提供的其它 Neural 音色。

注意

仓库自带 config.json 里的 subscriptionKey 只是本地样例,不要直接用于生产
部署时务必替换为你自己的 key,并优先用 AZURE_SPEECH_KEY 环境变量注入。
tts.publicBaseUrl 必须是 FreeSWITCH 或浏览器能访问到的地址,网关部署到另一台机器后
不要继续使用 http://127.0.0.1:9082

多语言自动识别

Azure 网关的一个特点是同一路 ASR 服务内自动检测语种asr.autoDetectLanguages
列出候选语言,Azure 会在识别时自动判定。默认同时支持中文普通话 zh-CN 与美式英语
en-US,常用候选还包括 zh-HKzh-TWyue-CNen-GBja-JPko-KR
fr-FRde-DEes-ES 等,完整列表以 Microsoft Azure Speech 官方文档为准。

本地 sherpa ASR 默认中文 int8 模型(可切中英双语预设);如果你的场景需要多语种自动
识别又不想自建模型,Azure 网关是最省事的方案。

切换 callflow-esl 到 Azure

ASR

apps/callflow-esl/config.jsonaudioFork.wsUrl 改成网关地址:

1
2
3
4
5
6
7
8
{
"audioFork": {
"wsUrl": "ws://<gateway-host>:10098/audio",
"bugName": "callflow_asr",
"mixType": "mono",
"sampleRate": "16k"
}
}

bugNamemixTypesampleRate 不需要因为切到 Azure 而改变;关键是上游音频仍要保持
16kHz mono PCM16。

TTS

tts 端点改成网关的 HTTP 接口:

1
2
3
4
5
6
7
8
9
10
{
"tts": {
"defaults": { "speakerId": 0, "speed": 1, "requestTimeoutMs": 10000 },
"use": { "call": "shout", "conference": "wav" },
"profiles": {
"wav": { "endpoint": "http://<gateway-host>:9082/tts", "playbackTarget": "wav-url", "fsPlaybackBaseDir": "" },
"shout": { "endpoint": "http://<gateway-host>:9082/tts-stream", "playbackPrefix": "shout://" }
}
}
}

普通播放仍返回 wav URL;流式播放仍先返回 streamUrl,再由 FreeSWITCH 通过 shout://
拉取 MP3(Azure 流式输出格式由 tts.streamOutputFormat 控制,默认
audio-16khz-128kbitrate-mono-mp3)。

管理台测试

  • TTS 试听页把端点填为 http://<gateway-host>:9082/tts,直接试听 Azure 音色;
  • ASR 测试页把主机、端口、路径改为 <gateway-host>10098/audio,上传音频或用
    浏览器录音验证;
  • /api/asr/recognize 会把浏览器侧音频统一转为 16kHz mono PCM16 WAV,再通过 WebSocket
    发到网关。

会话收尾

ASR 会话在客户端发送零长度二进制帧(flush)或断开时收尾。网关会先关闭 Azure 识别会话、
close() 期间补发的最后一段 final 结果下发给客户端,再关闭 WebSocket
,避免零长度
flush 时丢掉尾部识别;识别错误以结构化错误回调(含 errorCodeerrorDetails
azureSessionId 等)记录。该收尾时序由 src/asr-server.test.ts 覆盖。

三种语音底座的取舍

维度 本地 sherpa ASR/TTS 阿里云语音网关 Azure 语音网关
数据出网 不出网 发往阿里云 发往 Azure
成本 主要是机器成本 阿里云 NLS 计费 Azure Speech 计费
多语言自动识别 需自行换模型 需按会话指定 autoDetectLanguages 内置
独立可执行文件 C++ 构建 需 Bun 运行时 支持 --compile 打包
适合场景 私有化、稳定生产链路 国内云、效果对比 多语言、海外、临时兜底

安全与运维

  • 网关本身没有内置鉴权,生产环境应只暴露在可信网络内,或放到带鉴权的反向代理后;
  • Azure key 泄露风险高,务必走环境变量、不要把生产 key 提交进仓库;
  • WAV / MP3 缓存位于 apps/azure-speech-gateway/public/,生产环境应按需定期清理;
  • /wav/:fileName/tts-stream/:fileName 只允许读取本服务生成的 tts-<16位hash> 文件,
    不能通过 URL 读取其它本地文件;
  • 手动启动过服务后,联调结束记得停止 Bun 进程,避免端口被后续本地服务占用。

下一步