Azure Speech识别在Angular+.NET Core环境下失效问题求助
Angular→.NET Core→Azure Speech PushStream实时语音识别失败
问题概述
我们尝试基于Azure Speech的PushStream实现实时语音识别:在Angular 17应用中通过navigator.mediaDevices.getUserMedia()录制音频,将音频发送至.NET 8.0后端后,Azure无法识别该音频内容。
场景对比
- 可正常运行的场景:Angular/React + Node.js 18后端,通过socket.io传输音频流,能无缝对接Azure Speech转文本识别
- 失败场景:切换为.NET Core后端后,无论是使用SignalR(将base64编码音频转为
byte[]传输)还是原生WebSocket,音频均无法被Azure识别
限制条件(不采用Azure JS SDK的原因)
- 后端团队仅具备.NET技术能力,无法维护前端侧的Azure Speech集成逻辑
- 出于安全考虑,禁止在前端硬编码Azure Speech的配置信息
可正常运行的Angular+Node.js+Azure代码
Angular 前端代码(音频录制与传输)
import { Component, OnInit } from '@angular/core'; import * as io from 'socket.io-client'; @Component({ selector: 'app-speech-recognition', templateUrl: './speech-recognition.component.html', styleUrls: ['./speech-recognition.component.css'] }) export class SpeechRecognitionComponent implements OnInit { private socket: any; private mediaRecorder: MediaRecorder | null = null; ngOnInit(): void { this.socket = io('http://localhost:3000'); } startRecording(): void { navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { this.mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/wav' }); this.mediaRecorder.ondataavailable = (event) => { if (event.data.size > 0) { const reader = new FileReader(); reader.onload = () => { const base64Audio = reader.result as string; this.socket.emit('audio-stream', base64Audio); }; reader.readAsDataURL(event.data); } }; this.mediaRecorder.start(100); }) .catch(err => console.error('录音启动失败:', err)); } stopRecording(): void { this.mediaRecorder?.stop(); this.socket.emit('audio-stop'); } }
Node.js 后端代码(对接Azure Speech)
const express = require('express'); const http = require('http'); const { Server } = require('socket.io'); const sdk = require('microsoft-cognitiveservices-speech-sdk'); const app = express(); const server = http.createServer(app); const io = new Server(server, { cors: { origin: "*" } }); const speechConfig = sdk.SpeechConfig.fromSubscription('YOUR_AZURE_KEY', 'YOUR_AZURE_REGION'); speechConfig.speechRecognitionLanguage = 'zh-CN'; io.on('connection', (socket) => { console.log('客户端已连接'); const pushStream = sdk.AudioInputStream.createPushStream(); const audioConfig = sdk.AudioConfig.fromStreamInput(pushStream); const recognizer = new sdk.SpeechRecognizer(speechConfig, audioConfig); recognizer.recognized = (s, e) => { if (e.result.reason === sdk.ResultReason.RecognizedSpeech) { socket.emit('recognition-result', e.result.text); } }; recognizer.startContinuousRecognitionAsync(); socket.on('audio-stream', (base64Audio) => { const audioBuffer = Buffer.from(base64Audio.split(',')[1], 'base64'); pushStream.write(audioBuffer); }); socket.on('audio-stop', () => { recognizer.stopContinuousRecognitionAsync(); pushStream.close(); }); socket.on('disconnect', () => { recognizer.stopContinuousRecognitionAsync(); pushStream.close(); console.log('客户端已断开'); }); }); server.listen(3000, () => { console.log('后端服务运行在端口3000'); });
无法运行的Angular+.NET Core+Azure代码
Angular 前端代码(SignalR传输)
import { Component, OnInit } from '@angular/core'; import { HubConnection, HubConnectionBuilder } from '@microsoft/signalr'; @Component({ selector: 'app-speech-recognition', templateUrl: './speech-recognition.component.html', styleUrls: ['./speech-recognition.component.css'] }) export class SpeechRecognitionComponent implements OnInit { private hubConnection: HubConnection | null = null; private mediaRecorder: MediaRecorder | null = null; ngOnInit(): void { this.hubConnection = new HubConnectionBuilder() .withUrl('http://localhost:5000/speechHub') .build(); this.hubConnection.start().catch(err => console.error('SignalR连接失败:', err)); this.hubConnection.on('RecognitionResult', (result) => { console.log('识别结果:', result); }); } startRecording(): void { navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { this.mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/wav' }); this.mediaRecorder.ondataavailable = (event) => { if (event.data.size > 0) { const reader = new FileReader(); reader.onload = () => { const base64Audio = reader.result as string; this.hubConnection?.invoke('SendAudioStream', base64Audio); }; reader.readAsDataURL(event.data); } }; this.mediaRecorder.start(100); }) .catch(err => console.error('录音启动失败:', err)); } stopRecording(): void { this.mediaRecorder?.stop(); this.hubConnection?.invoke('StopAudioStream'); } }
.NET Core 后端代码(SignalR + Azure Speech)
using Microsoft.AspNetCore.SignalR; using Microsoft.CognitiveServices.Speech; using Microsoft.CognitiveServices.Speech.Audio; namespace SpeechRecognitionBackend.Hubs { public class SpeechHub : Hub { private SpeechRecognizer? _recognizer; private PushAudioInputStream? _pushStream; public async Task SendAudioStream(string base64Audio) { if (_pushStream == null) { var speechConfig = SpeechConfig.FromSubscription("YOUR_AZURE_KEY", "YOUR_AZURE_REGION"); speechConfig.SpeechRecognitionLanguage = "zh-CN"; _pushStream = AudioInputStream.CreatePushStream(); var audioConfig = AudioConfig.FromStreamInput(_pushStream); _recognizer = new SpeechRecognizer(speechConfig, audioConfig); _recognizer.Recognized += (s, e) => { if (e.Result.Reason == ResultReason.RecognizedSpeech) { Clients.Caller.SendAsync("RecognitionResult", e.Result.Text); } }; await _recognizer.StartContinuousRecognitionAsync(); } byte[] audioBytes = Convert.FromBase64String(base64Audio.Split(',')[1]); _pushStream.Write(audioBytes, 0, audioBytes.Length); } public async Task StopAudioStream() { if (_recognizer != null) { await _recognizer.StopContinuousRecognitionAsync(); _recognizer.Dispose(); _pushStream?.Close(); _pushStream?.Dispose(); } } } }
后端Program.cs 配置
var builder = WebApplication.CreateBuilder(args); builder.Services.AddSignalR(); builder.Services.AddCors(options => { options.AddPolicy("AllowAll", policy => { policy.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); }); var app = builder.Build(); app.UseCors("AllowAll"); app.MapHub<SpeechHub>("/speechHub"); app.Run();
内容的提问来源于stack exchange,提问作者Raj
相关产品推荐
相关产品推荐

