Skip to content

Commit 23c7289

Browse files
authored
修复从默认麦克风切换到别的麦克风时可能出现无法使用的问题 (#247)
* 修复从默认麦克风切换到别的麦克风时可能出现无法使用的问题 切换时会出现“连接异常关闭: Session not initialized”报错 * 加 await + 防并发 * 修复清理逻辑不完整的问题 * 修复屏幕推流和主动视觉悄悄失效 * 修复会误触发屏幕共享重启
1 parent 05c7c64 commit 23c7289

1 file changed

Lines changed: 124 additions & 6 deletions

File tree

static/app.js

Lines changed: 124 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,11 +1034,126 @@ function init_app() {
10341034
// 先显示选择提示
10351035
showStatusToast(window.t ? window.t('app.deviceSelected', { device: deviceName }) : `已选择 ${deviceName}`, 3000);
10361036
// 延迟重启录音,让用户看到选择提示
1037-
await stopMicCapture();
1038-
// 等待一小段时间,确保选择提示显示出来
1039-
await new Promise(resolve => setTimeout(resolve, 500));
1040-
if (wasRecording) {
1041-
await startMicCapture();
1037+
1038+
// 保存需要恢复的状态
1039+
const shouldRestartProactiveVision = proactiveVisionEnabled && isRecording;
1040+
const shouldRestartScreening = videoSenderInterval !== undefined && videoSenderInterval !== null;
1041+
1042+
// 防止并发切换导致状态混乱
1043+
if (window._isSwitchingMicDevice) {
1044+
console.warn('设备切换中,请稍后再试');
1045+
showStatusToast(window.t ? window.t('app.deviceSwitching') : '设备切换中...', 2000);
1046+
return;
1047+
}
1048+
window._isSwitchingMicDevice = true;
1049+
1050+
try {
1051+
// 停止语音期间主动视觉定时
1052+
stopProactiveVisionDuringSpeech();
1053+
// 停止屏幕共享
1054+
stopScreening();
1055+
// 停止静音检测
1056+
stopSilenceDetection();
1057+
// 清理输入analyser
1058+
inputAnalyser = null;
1059+
// 停止所有轨道
1060+
if (stream instanceof MediaStream) {
1061+
stream.getTracks().forEach(track => track.stop());
1062+
stream = null;
1063+
}
1064+
// 清理 AudioContext 本地资源
1065+
if (audioContext) {
1066+
if (audioContext.state !== 'closed') {
1067+
await audioContext.close().catch((e) => console.warn('AudioContext close 失败:', e));
1068+
}
1069+
audioContext = null;
1070+
}
1071+
workletNode = null;
1072+
1073+
// 等待一小段时间,确保选择提示显示出来
1074+
await new Promise(resolve => setTimeout(resolve, 500));
1075+
1076+
if (wasRecording) {
1077+
await startMicCapture();
1078+
1079+
// 重启屏幕共享(如果之前正在共享)
1080+
if (shouldRestartScreening) {
1081+
if (typeof startScreenSharing === 'function') {
1082+
try {
1083+
await startScreenSharing();
1084+
} catch (e) {
1085+
console.warn('重启屏幕共享失败:', e);
1086+
}
1087+
}
1088+
}
1089+
// 重启主动视觉(如果之前已启用)
1090+
if (shouldRestartProactiveVision) {
1091+
startProactiveVisionDuringSpeech();
1092+
}
1093+
}
1094+
} catch (e) {
1095+
console.error('切换麦克风设备失败:', e);
1096+
showStatusToast(window.t ? window.t('app.deviceSwitchFailed') : '设备切换失败', 3000);
1097+
1098+
// 完整清理:重置状态
1099+
isRecording = false;
1100+
window.isRecording = false;
1101+
1102+
// 重置所有按钮状态(参考 stopMicCapture 逻辑)
1103+
micButton.classList.remove('recording', 'active');
1104+
muteButton.classList.remove('recording', 'active');
1105+
screenButton.classList.remove('active');
1106+
if (stopButton) stopButton.classList.remove('recording', 'active');
1107+
1108+
// 同步浮动按钮状态
1109+
syncFloatingMicButtonState(false);
1110+
syncFloatingScreenButtonState(false);
1111+
1112+
// 启用/禁用按钮状态
1113+
micButton.disabled = false;
1114+
muteButton.disabled = true;
1115+
screenButton.disabled = true;
1116+
if (stopButton) stopButton.disabled = true;
1117+
1118+
// 显示文本输入区域
1119+
const textInputArea = document.getElementById('text-input-area');
1120+
if (textInputArea) {
1121+
textInputArea.classList.remove('hidden');
1122+
}
1123+
1124+
// 清理资源
1125+
stopScreening();
1126+
stopSilenceDetection();
1127+
inputAnalyser = null;
1128+
1129+
if (stream instanceof MediaStream) {
1130+
stream.getTracks().forEach(track => track.stop());
1131+
stream = null;
1132+
}
1133+
1134+
if (audioContext) {
1135+
if (audioContext.state !== 'closed') {
1136+
await audioContext.close().catch((err) => console.warn('AudioContext close 失败:', err));
1137+
}
1138+
audioContext = null;
1139+
}
1140+
workletNode = null;
1141+
1142+
// 通知后端
1143+
if (socket.readyState === WebSocket.OPEN) {
1144+
socket.send(JSON.stringify({ action: 'pause_session' }));
1145+
}
1146+
1147+
// 如果主动搭话/主动视觉已启用,重置并开始定时
1148+
if (proactiveChatEnabled || proactiveVisionEnabled) {
1149+
lastUserInputTime = Date.now();
1150+
resetProactiveChatBackoff();
1151+
}
1152+
1153+
window._isSwitchingMicDevice = false;
1154+
return;
1155+
} finally {
1156+
window._isSwitchingMicDevice = false;
10421157
}
10431158
} else {
10441159
// 如果不在录音,直接显示选择提示
@@ -2524,7 +2639,10 @@ function init_app() {
25242639

25252640
// 停止录屏
25262641
function stopScreening() {
2527-
if (videoSenderInterval) clearInterval(videoSenderInterval);
2642+
if (videoSenderInterval) {
2643+
clearInterval(videoSenderInterval);
2644+
videoSenderInterval = null;
2645+
}
25282646
}
25292647

25302648
// 停止录音

0 commit comments

Comments
 (0)