fix: 修复录音按钮快速按放导致按钮卡死的异步竞态问题

This commit is contained in:
2026-03-01 05:30:47 +08:00
parent 0ae2533421
commit b22b27db75

View File

@@ -36,6 +36,8 @@ import audioProcessorUrl from "./audio-processor.js?worker&url";
ws: null,
connected: false,
recording: false,
pendingStart: false,
startCancelled: false,
audioCtx: null,
workletNode: null,
stream: null,
@@ -185,16 +187,25 @@ import audioProcessorUrl from "./audio-processor.js?worker&url";
state.audioCtx = audioCtx;
}
async function startRecording() {
if (state.recording) return;
if (state.recording || state.pendingStart) return;
state.pendingStart = true;
state.startCancelled = false;
try {
await initAudio();
if (state.startCancelled) { state.pendingStart = false; return; }
// Ensure AudioContext is running (may suspend between recordings)
if (state.audioCtx.state === "suspended") {
await state.audioCtx.resume();
}
if (state.startCancelled) { state.pendingStart = false; return; }
const stream = await navigator.mediaDevices.getUserMedia({
audio: { echoCancellation: true, noiseSuppression: true, channelCount: 1 },
});
if (state.startCancelled) {
stream.getTracks().forEach((t) => t.stop());
state.pendingStart = false;
return;
}
state.stream = stream;
const source = state.audioCtx.createMediaStreamSource(stream);
const worklet = new AudioWorkletNode(state.audioCtx, "audio-processor");
@@ -208,15 +219,23 @@ import audioProcessorUrl from "./audio-processor.js?worker&url";
worklet.port.postMessage({ command: "start" });
// Don't connect worklet to destination (no playback)
state.workletNode = worklet;
state.pendingStart = false;
state.recording = true;
sendJSON({ type: "start" });
micBtn.classList.add("recording");
setPreview("", false);
} catch (err) {
state.pendingStart = false;
showToast(`麦克风错误: ${err.message}`);
}
}
function stopRecording() {
// Cancel pending async start if still initializing
if (state.pendingStart) {
state.startCancelled = true;
micBtn.classList.remove("recording");
return;
}
if (!state.recording) return;
state.recording = false;
// Stop worklet