FunASR C# 实时语音识别客户端实战:基于 WebSocket 的 Online/2pass 流式识别与离线文件转录
【免费下载链接】FunASROpen-source speech recognition toolkit for training, inference, streaming ASR, VAD, punctuation, speaker diarization pipelines, and OpenAI-compatible/MCP serving.项目地址: https://gitcode.com/GitHub_Trending/fun/FunASR
本指南以 FunASR 仓库 runtime/csharp/ws-client/FunASRWSClient_Online 目录下的 C# 客户端为主体,讲解如何构建一个连接 FunASR WebSocket 服务端的实时语音识别程序:既支持麦克风实时流式识别(online / 2pass 两种模式),也支持对本地音频文件进行离线转录。读完本文,你将掌握该客户端的工程结构、WebSocket 协议消息的构造方式、麦克风采集与音频分块发送的实现细节,以及从编译到联调运行的全流程操作。
一、客户端能力概览
FunASRWSClient_Online 是一个基于 FunASR WebSocket 服务器的 C# 控制台客户端,核心能力在 README.md 中有明确说明:
- 实时语音识别:使用
online或2pass模式,对麦克风采集到的音频流进行持续识别; - 离线文件转录:默认使用
offline模式,转录本地音频文件; - 配置驱动:将配置文件放在与程序相同目录下的 config 文件夹中,在
config.ini中配置服务器 IP 地址和端口号; - 开箱即测:配置好服务端 IP 和端口后,在 Visual Studio 中打开项目,添加
NAudio和Websocket.Client两个 NuGet 程序包即可直接测试,按控制台提示操作即可。
该客户端在 Windows 11 下完成测试,编译环境为 VS2022。工程目录中包含四个核心文件:Program.cs(主流程与交互)、WebScoketClient.cs(WebSocket 通信与协议封装)、WaveCollect.cs(麦克风采集)、FunASRWSClient_Online.csproj(工程配置)。
同仓库还提供了只做离线文件转录的姊妹工程 FunASRWSClient_Offline,并支持热词与时间戳(热词需将 config 文件夹下的hotword.txt放置在执行路径下,且热词与时间戳为不同模型,需注意后台部署时模型选择)。
二、环境要求与编译运行
2.1 依赖清单
从 FunASRWSClient_Online.csproj 可以看到工程的目标框架与依赖:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <PackageReference Include="NAudio" Version="2.1.0" /> <PackageReference Include="Websocket.Client" Version="4.6.1" /> </ItemGroup> </Project>- 目标框架:net6.0(.NET 6);
- NAudio 2.1.0:负责麦克风音频采集、WAV 格式处理(如
WaveInEvent、WaveFileWriter、MMDeviceEnumerator); - Websocket.Client 4.6.1:负责与 FunASR WebSocket 服务端的连接、收发与断线重连(基于 System.Reactive 提供
MessageReceived等可观察订阅)。
2.2 服务端与客户端配置
客户端通过 config.ini 读取服务端地址(注意仓库中目录名为confg):
host=127.0.0.1 port=10095配置解析逻辑位于 Program.cs 的loadconfig()方法中:逐行读取config.ini,忽略空行以及;、#开头的注释行,按key=value形式解析,仅识别host与port两个键;程序内默认值分别为0.0.0.0与10095(对应 FunASR WebSocket 服务端默认端口)。
启动前需先运行 FunASR 的 WebSocket 服务端(如funasr-wss-server或其 2pass 版本),确保服务端监听端口与config.ini一致。
2.3 编译与运行步骤
- 用 VS2022 打开解决方案 FunASRClient_CShape.sln(仓库中实际文件名为
FunASRClient_CShape.sln)下的FunASRWSClient_Online工程; - 通过 NuGet 还原
NAudio与Websocket.Client程序包; - 将
config.ini放到程序运行目录(或与程序同目录的 config 文件夹中),填写服务端 IP 与端口; - 编译运行,程序会先做麦克风与通信自检,随后进入菜单交互。
三、程序主流程:启动自检与双线程架构
3.1 启动自检
FunASR_Main()(Program.cs)启动后依次执行两类自检:
- 麦克风状态监测:通过
GetCurrentMicVolume()枚举系统录音设备,返回-2表示麦克风被静音、-1表示麦克风未连接、0表示音量被调为 0,任一异常都会在控制台给出提示并退出; - 通信连接测试:
ClientConnTest()尝试建立 WebSocket 连接,若返回信息不包含"成功"字样则判定连接失败并退出。
3.2 双线程并发架构
自检通过后,主程序启动两个后台线程再进入交互循环:
- SendAudioThread:执行
SendAudioToSeverAsync(),持续从ActiveAudioSet(并发队列)取出麦克风音频块,调用ClientSendAudioFunc()发送给服务端; - AudioFileThread:执行
SendAudioFileToSeverAsync(),轮询AudioFileQueue,有文件路径入队即调用ClientSendFileFunc()进行离线转录。
主线程则循环读取控制台输入,提供交互菜单:输入1进入离线文件转写(随后输入文件路径),输入2进入实时语音识别(再选择1为 online、2为 2pass)。两个并发队列(ActiveAudioSet、AudioFileQueue)均声明为ConcurrentQueue<T>,保证多线程安全。
四、麦克风采集:WaveCollect 的实现细节
WaveCollect.cs 基于 NAudio 实现音频采集,关键参数:
| 参数 | 值 | 说明 |
|---|---|---|
wave_buffer_milliseconds | 600 | 每次采集缓冲的毫秒数(BufferMilliseconds) |
wave_buffer_collectbits | 16 | 位深 16bit |
wave_buffer_collectchannels | 1 | 单声道 |
wave_buffer_collectfrequency | 16000 | 采样率 16kHz |
采集流程:StartRec()先枚举并打印系统录音设备信息,随后创建WaveInEvent(16kHz / 16bit / 单声道),在DataAvailable事件回调中将e.Buffer入队到静态并发队列voicebuff,同时用WaveFileWriter写入tmp.wav;StopRec()停止录制并释放资源。实时识别循环中,主线程不断从voicebuff出队并转存到ActiveAudioSet供发送线程消费。
五、WebSocket 协议交互:客户端与服务端的消息约定
5.1 首帧:识别启动参数
实时识别开始前,ClientFirstConnOnline()构造首帧 JSON 文本发送给服务端(WebScoketClient.cs):
{"mode": "online", "chunk_size": [5,10,5], "chunk_interval": 10, "wav_name": "microphone", "is_speaking": true}mode:online或2pass(由用户选择,2pass 会在流式识别结果基础上输出修正后的最终结果);chunk_size:[5,10,5],服务端在 websocket-server-2pass.cpp 中会校验其长度为 3 且第二个元素非 0,否则报Wrong chunk_size!;chunk_interval:10(毫秒,客户端据此计算发送切片大小);wav_name:microphone(实时识别会话标识);is_speaking:true(正在说话,流式会话进行中)。
5.2 音频数据帧
采集线程送来的每个缓冲块,在ClientSendAudioFunc()中按公式CHUNK = 采样率/1000 * 60 * chunk_size[1] / chunk_interval切成更小的片段逐段发送,每个片段之间Thread.Sleep(1)限速,保证与服务端流式处理节奏匹配。当连接断开时调用client.Reconnect()触发重连。
5.3 结束帧
实时识别退出(捕获 Ctrl+C)后,ClientLastConnOnline()发送{"is_speaking": false}通知服务端当前说话结束;finally块中同时执行StopRec()停止采集。服务端收到is_speaking=false后结束本次会话并返回最终结果。
5.4 离线文件转录的消息约定
ClientSendFileFunc()按扩展名区分处理(WebScoketClient.cs):
- wav / pcm:发送
{"mode": "office", "chunk_size": [5,10,5], "chunk_interval": 10, "wav_name": "xxx.wav", "is_speaking": true, "wav_format": "pcm"},随后 wav 文件跳过 44 字节 WAV 头按 102400 字节分块发送,pcm 文件按 1024000 字节分块发送; - mp3 / mp4:发送
{"mode": "offline", "chunk_size": "5,10,5", "chunk_interval": 10, "wav_name": "xxx.mp3", "is_speaking": true, "wav_format": "mp3"}(chunk_size为字符串形式),同样分块发送; - 不支持的扩展名返回
-1,通信断开返回-2。
发送完所有数据后统一发送{"is_speaking": false}收尾。
5.5 服务端响应与结果解析
rec_message()解析服务端返回的 JSON,读取mode、text、is_final、wav_name字段:
mode == "2pass-online":流式中间结果,累积到onlinebuff后与recbuff拼接打印;mode == "2pass-offline":2pass 修正后的最终结果,累积到recbuff打印;is_final == true:当前识别段结束,清空recbuff缓存。
这一消息结构与服务端 websocket-server-2pass.cpp 中的行为一致:在线阶段返回mode: "2pass-online"的临时文本,离线修正阶段返回mode: "2pass-offline"的最终文本,并在会话结束时返回is_final: true与wav_name。协议细节可进一步参阅 WebSocket 协议文档。
六、完整运行流程实操
- 启动 FunASR WebSocket 服务端(online 或 2pass 版本),确认端口(默认 10095);
- 在
config.ini中配置服务端host与port,与程序放在同一运行目录; - VS2022 编译运行,程序自动完成麦克风与通信自检;
- 按提示输入
1(离线文件转写)并给出音频文件路径,等待转录结果打印; - 输入
2(实时语音识别)再选择1(online)或2(2pass),对着麦克风说话,控制台实时打印识别文本;按 Ctrl+C 结束本次会话并返回菜单。
七、结合仓库源码的扩展提示
- 服务端对应实现:客户端的 JSON 消息字段(
mode、chunk_size、chunk_interval、wav_name、is_speaking、wav_format)与 runtime/websocket/bin 下的服务端解析逻辑一一对应,联调时可直接对照该目录源码排查字段不匹配问题; - 离线纯转录场景:若只需批量转写本地文件,可改用 FunASRWSClient_Offline 工程,其还支持热词(
hotword.txt)与时间戳能力; - 多语言服务端:仓库中 runtime/websocket 目录下包含 online / 2pass 多种服务端实现,均可与本 C# 客户端配合使用。
结语
FunASRWSClient_Online 演示了在 .NET 生态中对接 FunASR WebSocket 服务端的完整路径:从 config.ini 配置、NAudio 麦克风采集,到符合 FunASR 协议的 JSON 首帧、分块音频数据帧与结束帧发送,再到 2pass 中间/最终结果解析。理解其消息约定与线程模型后,你可以轻松将此客户端改造为 WinForms / WPF 图形界面、集成到现有 C# 业务系统,或扩展支持更多音频格式与热词功能。
【免费下载链接】FunASROpen-source speech recognition toolkit for training, inference, streaming ASR, VAD, punctuation, speaker diarization pipelines, and OpenAI-compatible/MCP serving.项目地址: https://gitcode.com/GitHub_Trending/fun/FunASR
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考