You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor应用如何传递音频流实现Azure认知服务连续语音转文本

Blazor 客户端音频流转服务端实现方案

针对你用Azure Speech做连续语音转文本的场景,核心要求是低延迟、分片连续传输,不能等完整音频生成后一次性上传,否则连续识别会出现卡顿、延迟过高的问题,以下是可直接落地的实现方案:

方案选型

  • 优先选SignalR双向流传输:Blazor原生集成通信能力,无需额外搭建服务,延迟最低,最适配实时音频场景
  • 备选为分片HTTP上传:适合部署环境不支持WebSocket的场景,延迟略高,需要自行维护会话和分片顺序

方案1:SignalR流传输(推荐)

你用的16kHz、16位、单声道PCM格式,每100ms音频对应3200字节数据,传输时单分片大小控制在100ms~300ms数据量即可,分片太大会拉高延迟,太小会产生过多无效请求开销。

  1. 服务端先定义Speech识别Hub,支持流式接收音频分片、实时返回识别结果:
public class SpeechRecognitionHub : Hub
{
    public async Task<Channel<string>> StartContinuousRecognition(IAsyncEnumerable<byte[]> audioChunks, CancellationToken ct)
    {
        var resultChannel = Channel.CreateUnbounded<string>();
        // 复用你已有的Azure Speech配置逻辑
        var audioFormat = AudioStreamFormat.GetWaveFormatPCM(16000, 16, 1);
        var pushStream = AudioInputStream.CreatePushStream(audioFormat);
        var audioConfig = AudioConfig.FromStreamInput(pushStream);
        
        // 后台消费客户端上传的音频分片,直接写入Speech输入流
        _ = Task.Run(async () =>
        {
            await foreach (var chunk in audioChunks.WithCancellation(ct))
            {
                pushStream.Write(chunk);
            }
            // 客户端传完所有分片后关闭输入流,触发识别收尾
            pushStream.Close();
        }, ct);

        // 补全Speech识别器的事件绑定逻辑,把实时识别出的文本写入resultChannel返回给客户端即可
        return resultChannel;
    }
}

记得在Program.cs里注册Hub:app.MapHub<SpeechRecognitionHub>("/speech-recog");

  1. 客户端侧连接Hub,边采集音频边推流,同时实时接收识别结果:
// 初始化Hub连接
var hubConn = new HubConnectionBuilder()
    .WithUrl("/speech-recog")
    .Build();
await hubConn.StartAsync();

// 建通道缓存待上传的音频分片
var audioUploadChannel = Channel.CreateUnbounded<byte[]>();
// 调用服务端识别方法,拿到识别结果流
var resultStream = hubConn.StreamAsync<string>("StartContinuousRecognition", audioUploadChannel.Reader.ReadAllAsync());

// 本地从audioStream读到PCM分片时,直接写入上传通道即可,不需要攒包
// 例:读到3200字节的100ms PCM数据,直接执行
await audioUploadChannel.Writer.WriteAsync(pcmChunk);

// 音频采集结束时标记上传完成
audioUploadChannel.Writer.Complete();

// 实时消费识别结果更新UI
await foreach (var text in resultStream)
{
    // 把text绑定到页面显示字段即可
}

注意事项:

  • 客户端不需要做任何音频转码,直接传原始PCM分片就行,和Azure Speech要求的输入格式完全匹配,省掉两端转码开销
  • 页面跳转/组件销毁时记得触发CancellationToken,释放Speech识别器、流和Hub连接资源,避免内存泄漏
  • Blazor Server模式下SignalR复用现有circuits连接,额外开销几乎为0;Blazor WASM模式下自动走WebSocket传输,延迟可以控制在200ms以内,完全满足实时识别要求

方案2:分片HTTP上传(备选)

如果部署环境不支持WebSocket,可以用分片POST的方式实现:

  • 客户端给每个识别会话生成唯一ID,每采集到固定大小的PCM分片,就按顺序带会话ID、分片序号POST到服务端接口
  • 服务端按会话ID维护对应的PushStream实例,收到分片后校验序号、按顺序写入对应流
  • 识别结果可以通过SSE(服务器发送事件)推回客户端,或者短轮询拉取
    这个方案需要自行处理分片乱序、会话过期、流资源释放的逻辑,延迟比SignalR方案高100~300ms,非必要不选。

踩坑提醒:不要尝试直接把完整Stream对象通过Blazor组件参数、JS互操作直接传值给服务端,Blazor的跨端传值走序列化逻辑,会把整个流内容一次性加载到内存,既没法实现实时连续识别,还容易触发内存溢出。

内容的提问来源于stack exchange,提问作者Harini Muralidharan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 09:22:01