fix: 修复录音按钮快速按放导致按钮卡死的异步竞态问题
This commit is contained in:
21
web/app.js
21
web/app.js
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user