fix: 讯飞语音识别文字覆盖+麦克风未释放
- 使用setChatInput(prev => prev + seg)函数式更新,彻底修复文字覆盖问题 - 提取stopMicrophone函数,在手动停止/VAD自动挂断/报错/关闭时统一释放物理麦克风
This commit is contained in:
@@ -923,31 +923,43 @@ export default function ReportEditor() {
|
||||
}
|
||||
|
||||
const toggleListening = async () => {
|
||||
// 专门提取一个彻底关闭物理麦克风的函数
|
||||
const stopMicrophone = () => {
|
||||
if (xfAudioContextRef.current) {
|
||||
try { xfAudioContextRef.current.close(); } catch {}
|
||||
xfAudioContextRef.current = null;
|
||||
}
|
||||
if (xfMediaStreamRef.current) {
|
||||
xfMediaStreamRef.current.getTracks().forEach(t => t.stop());
|
||||
xfMediaStreamRef.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
if (isListening) {
|
||||
setIsListening(false);
|
||||
// 1. 发送结束帧告诉服务器录音结束
|
||||
stopMicrophone();
|
||||
|
||||
if (xfWsRef.current && xfWsRef.current.readyState === WebSocket.OPEN) {
|
||||
try {
|
||||
const endFrame = { data: { status: 2, format: 'audio/L16;rate=16000', encoding: 'raw', audio: '' } };
|
||||
xfWsRef.current.send(JSON.stringify(endFrame));
|
||||
} catch {}
|
||||
}
|
||||
// 2. 仅关闭本地麦克风收音,保留 WebSocket 等待服务器返回最终结果
|
||||
if (xfAudioContextRef.current) { try { xfAudioContextRef.current.close(); } catch {} xfAudioContextRef.current = null; }
|
||||
if (xfMediaStreamRef.current) { xfMediaStreamRef.current.getTracks().forEach(t => t.stop()); xfMediaStreamRef.current = null; }
|
||||
return;
|
||||
}
|
||||
|
||||
const xfConfig = storage.get<SystemSettings>('systemSettings', {} as SystemSettings).xfSpeechConfig || DEFAULT_XF_SPEECH;
|
||||
if (!xfConfig?.appId || !xfConfig?.apiKey || !xfConfig?.apiSecret) {
|
||||
alert('请先在系统设置中配置讯飞语音 APPID/APIKey/APISecret');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const authUrl = await getXfAuthUrl(xfConfig.apiKey, xfConfig.apiSecret);
|
||||
const ws = new WebSocket(authUrl);
|
||||
xfWsRef.current = ws;
|
||||
let frameStatus = 0;
|
||||
let transcript = chatInput;
|
||||
|
||||
ws.onopen = async () => {
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
@@ -956,8 +968,9 @@ export default function ReportEditor() {
|
||||
xfAudioContextRef.current = audioContext;
|
||||
const source = audioContext.createMediaStreamSource(stream);
|
||||
const processor = audioContext.createScriptProcessor(4096, 1, 1);
|
||||
|
||||
processor.onaudioprocess = (e) => {
|
||||
if (ws.readyState !== WebSocket.OPEN) return;
|
||||
if (ws.readyState !== WebSocket.OPEN || !xfAudioContextRef.current) return;
|
||||
const inputData = e.inputBuffer.getChannelData(0);
|
||||
const pcmBuffer = floatTo16BitPCM(inputData);
|
||||
const base64Audio = arrayBufferToBase64(pcmBuffer);
|
||||
@@ -969,6 +982,7 @@ export default function ReportEditor() {
|
||||
ws.send(JSON.stringify(frame));
|
||||
frameStatus = 1;
|
||||
};
|
||||
|
||||
source.connect(processor);
|
||||
processor.connect(audioContext.destination);
|
||||
setIsListening(true);
|
||||
@@ -978,31 +992,35 @@ export default function ReportEditor() {
|
||||
ws.close();
|
||||
}
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
try {
|
||||
const jsonData = JSON.parse(event.data);
|
||||
if (jsonData.code !== 0 && jsonData.code !== undefined) {
|
||||
alert(`讯飞语音报错: ${jsonData.message || '未知错误'} (错误码: ${jsonData.code})`);
|
||||
setIsListening(false);
|
||||
stopMicrophone();
|
||||
ws.close();
|
||||
return;
|
||||
}
|
||||
if (jsonData.data?.result?.ws) {
|
||||
let seg = '';
|
||||
for (const w of jsonData.data.result.ws) { if (w.cw?.[0]?.w) seg += w.cw[0].w; }
|
||||
if (jsonData.data.result.ls) { transcript += seg; setChatInput(transcript); }
|
||||
else { setChatInput(transcript + seg); }
|
||||
if (seg) {
|
||||
setChatInput(prev => prev + seg);
|
||||
}
|
||||
}
|
||||
// 当接收到服务端的最终状态码 status === 2 时,才彻底断开 websocket
|
||||
if (jsonData.data?.status === 2) {
|
||||
ws.close();
|
||||
xfWsRef.current = null;
|
||||
setIsListening(false);
|
||||
stopMicrophone();
|
||||
}
|
||||
} catch {}
|
||||
};
|
||||
ws.onerror = () => { alert('讯飞语音连接失败'); setIsListening(false); };
|
||||
ws.onclose = () => { setIsListening(false); };
|
||||
|
||||
ws.onerror = () => { alert('讯飞语音连接失败'); setIsListening(false); stopMicrophone(); };
|
||||
ws.onclose = () => { setIsListening(false); stopMicrophone(); };
|
||||
} catch (e: any) {
|
||||
alert('讯飞语音初始化失败: ' + e.message);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user