From 7e6744134376bf86ac92c959ba702f50c8fe97bd Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Mon, 23 Mar 2026 19:07:54 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8C=89=E9=92=AE=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/mobile_elf_controller.dart | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/lib/modules/mobile_elf/controllers/mobile_elf_controller.dart b/lib/modules/mobile_elf/controllers/mobile_elf_controller.dart index b59fc43aa..356b0f726 100644 --- a/lib/modules/mobile_elf/controllers/mobile_elf_controller.dart +++ b/lib/modules/mobile_elf/controllers/mobile_elf_controller.dart @@ -48,6 +48,7 @@ class MobileElfController extends GetxController { StreamSubscription? _eventSub; Timer? _callTimer; Timer? _pttTimer; + Timer? _pttSafetyTimer; bool _inCallMode = false; bool _callStarting = false; // 防止并发 startCall // PTT 松开后仍有异步事件待处理(recognition_result / assistant_response / tts) @@ -56,6 +57,8 @@ class MobileElfController extends GetxController { bool _pttStarting = false; // BLE/AI 唤醒触发的会话(非通话、非PTT模式下的唤醒) bool _bleWakeupActive = false; + // PTT 被中止(轻点松手),用于忽略原生层的残留事件 + bool _pttAborted = false; final _storage = GetStorage(); // 滚动:layout 变化前是否已在底部 bool _atBottom = true; @@ -107,6 +110,7 @@ class MobileElfController extends GetxController { _eventSub?.cancel(); _callTimer?.cancel(); _pttTimer?.cancel(); + _pttSafetyTimer?.cancel(); AgentService.stopConversation(); scrollController.dispose(); super.onClose(); @@ -127,6 +131,11 @@ class MobileElfController extends GetxController { final sessionActive = _inCallMode || pttRecording.value || _pttResultPending || _bleWakeupActive; switch (event.type) { case AgentServiceEventType.recognitionStarted: + // 忽略刚刚中止的 PTT 会话的残留事件,避免误触发 BLE 唤醒 + if (_pttAborted && !sessionActive) { + _pttAborted = false; + break; + } // BLE/AI 唤醒:即使没有主动会话也激活 if (!sessionActive) _bleWakeupActive = true; status.value = MobileElfStatus.recording; @@ -175,6 +184,7 @@ class MobileElfController extends GetxController { case AgentServiceEventType.ttsCompleted: if (!sessionActive) break; _pttResultPending = false; + _pttSafetyTimer?.cancel(); _endBleWakeup(); // BLE 唤醒一轮结束,清理 native PTT 状态 if (_inCallMode) { status.value = MobileElfStatus.recording; @@ -189,6 +199,7 @@ class MobileElfController extends GetxController { case AgentServiceEventType.ttsStopped: if (!sessionActive) break; _pttResultPending = false; + _pttSafetyTimer?.cancel(); _endBleWakeup(); status.value = _inCallMode ? MobileElfStatus.recording : MobileElfStatus.idle; micAlive.value = _inCallMode; @@ -197,6 +208,7 @@ class MobileElfController extends GetxController { case AgentServiceEventType.error: if (!sessionActive) break; _pttResultPending = false; + _pttSafetyTimer?.cancel(); _endBleWakeup(); final msg = event.data['message']?.toString() ?? '未知错误'; status.value = MobileElfStatus.error; @@ -240,6 +252,7 @@ class MobileElfController extends GetxController { Future startCall() async { if (inCall.value || _callStarting) return; _callStarting = true; + _pttAborted = false; _checkHeartbeat(); try { // 若有正在播报的 PTT/BLE 唤醒会话,先强制中断 TTS/AI 流, @@ -281,6 +294,7 @@ class MobileElfController extends GetxController { _inCallMode = false; _pttStarting = false; _pttResultPending = false; // 强制结束所有等待 + _pttSafetyTimer?.cancel(); _bleWakeupActive = false; inCall.value = false; _callTimer?.cancel(); @@ -306,6 +320,7 @@ class MobileElfController extends GetxController { Future startPtt() async { if (pttRecording.value || _pttStarting) return; _pttStarting = true; + _pttAborted = false; _checkHeartbeat(); // BLE 唤醒/PTT 等待结果期间用户按下 PTT,先中断当前会话(同 startCall 逻辑) if (_bleWakeupActive || _pttResultPending) { @@ -343,10 +358,33 @@ class MobileElfController extends GetxController { } if (!pttRecording.value) return; pttRecording.value = false; - _pttResultPending = true; // 等待 fin_result/assistant_response/tts 异步回来 _pttTimer?.cancel(); _pttTimer = null; + + // 如果还在连接中(还未开始识别),说明用户轻点了一下就松手, + // 直接恢复空闲,不需要等待异步事件回来 + if (status.value == MobileElfStatus.connecting) { + _pttAborted = true; // 标记中止,忽略原生层的残留事件 + _pttResultPending = false; + status.value = MobileElfStatus.idle; + micAlive.value = false; + AgentService.stopConversation(); + return; + } + + _pttResultPending = true; // 等待 fin_result/assistant_response/tts 异步回来 AgentService.stopConversation(); + + // 安全超时:防止原生层未返回事件导致状态永久卡住 + _pttSafetyTimer?.cancel(); + _pttSafetyTimer = Timer(const Duration(seconds: 8), () { + if (_pttResultPending && !_inCallMode) { + Logger.info('$_tag PTT safety timeout — force reset to idle'); + _pttResultPending = false; + status.value = MobileElfStatus.idle; + micAlive.value = false; + } + }); } void interruptSpeaking() {