Browse Source

优化按钮状态锁

newdev_shunjiawei
liwei1dao 7 months ago
parent
commit
7e67441343
  1. 40
      lib/modules/mobile_elf/controllers/mobile_elf_controller.dart

40
lib/modules/mobile_elf/controllers/mobile_elf_controller.dart

@ -48,6 +48,7 @@ class MobileElfController extends GetxController {
StreamSubscription<AgentServiceEvent>? _eventSub; StreamSubscription<AgentServiceEvent>? _eventSub;
Timer? _callTimer; Timer? _callTimer;
Timer? _pttTimer; Timer? _pttTimer;
Timer? _pttSafetyTimer;
bool _inCallMode = false; bool _inCallMode = false;
bool _callStarting = false; // 防止并发 startCall bool _callStarting = false; // 防止并发 startCall
// PTT 松开后仍有异步事件待处理(recognition_result / assistant_response / tts) // PTT 松开后仍有异步事件待处理(recognition_result / assistant_response / tts)
@ -56,6 +57,8 @@ class MobileElfController extends GetxController {
bool _pttStarting = false; bool _pttStarting = false;
// BLE/AI 唤醒触发的会话(非通话、非PTT模式下的唤醒) // BLE/AI 唤醒触发的会话(非通话、非PTT模式下的唤醒)
bool _bleWakeupActive = false; bool _bleWakeupActive = false;
// PTT 被中止(轻点松手),用于忽略原生层的残留事件
bool _pttAborted = false;
final _storage = GetStorage(); final _storage = GetStorage();
// 滚动:layout 变化前是否已在底部 // 滚动:layout 变化前是否已在底部
bool _atBottom = true; bool _atBottom = true;
@ -107,6 +110,7 @@ class MobileElfController extends GetxController {
_eventSub?.cancel(); _eventSub?.cancel();
_callTimer?.cancel(); _callTimer?.cancel();
_pttTimer?.cancel(); _pttTimer?.cancel();
_pttSafetyTimer?.cancel();
AgentService.stopConversation(); AgentService.stopConversation();
scrollController.dispose(); scrollController.dispose();
super.onClose(); super.onClose();
@ -127,6 +131,11 @@ class MobileElfController extends GetxController {
final sessionActive = _inCallMode || pttRecording.value || _pttResultPending || _bleWakeupActive; final sessionActive = _inCallMode || pttRecording.value || _pttResultPending || _bleWakeupActive;
switch (event.type) { switch (event.type) {
case AgentServiceEventType.recognitionStarted: case AgentServiceEventType.recognitionStarted:
// 忽略刚刚中止的 PTT 会话的残留事件,避免误触发 BLE 唤醒
if (_pttAborted && !sessionActive) {
_pttAborted = false;
break;
}
// BLE/AI 唤醒:即使没有主动会话也激活 // BLE/AI 唤醒:即使没有主动会话也激活
if (!sessionActive) _bleWakeupActive = true; if (!sessionActive) _bleWakeupActive = true;
status.value = MobileElfStatus.recording; status.value = MobileElfStatus.recording;
@ -175,6 +184,7 @@ class MobileElfController extends GetxController {
case AgentServiceEventType.ttsCompleted: case AgentServiceEventType.ttsCompleted:
if (!sessionActive) break; if (!sessionActive) break;
_pttResultPending = false; _pttResultPending = false;
_pttSafetyTimer?.cancel();
_endBleWakeup(); // BLE 唤醒一轮结束,清理 native PTT 状态 _endBleWakeup(); // BLE 唤醒一轮结束,清理 native PTT 状态
if (_inCallMode) { if (_inCallMode) {
status.value = MobileElfStatus.recording; status.value = MobileElfStatus.recording;
@ -189,6 +199,7 @@ class MobileElfController extends GetxController {
case AgentServiceEventType.ttsStopped: case AgentServiceEventType.ttsStopped:
if (!sessionActive) break; if (!sessionActive) break;
_pttResultPending = false; _pttResultPending = false;
_pttSafetyTimer?.cancel();
_endBleWakeup(); _endBleWakeup();
status.value = _inCallMode ? MobileElfStatus.recording : MobileElfStatus.idle; status.value = _inCallMode ? MobileElfStatus.recording : MobileElfStatus.idle;
micAlive.value = _inCallMode; micAlive.value = _inCallMode;
@ -197,6 +208,7 @@ class MobileElfController extends GetxController {
case AgentServiceEventType.error: case AgentServiceEventType.error:
if (!sessionActive) break; if (!sessionActive) break;
_pttResultPending = false; _pttResultPending = false;
_pttSafetyTimer?.cancel();
_endBleWakeup(); _endBleWakeup();
final msg = event.data['message']?.toString() ?? '未知错误'; final msg = event.data['message']?.toString() ?? '未知错误';
status.value = MobileElfStatus.error; status.value = MobileElfStatus.error;
@ -240,6 +252,7 @@ class MobileElfController extends GetxController {
Future<void> startCall() async { Future<void> startCall() async {
if (inCall.value || _callStarting) return; if (inCall.value || _callStarting) return;
_callStarting = true; _callStarting = true;
_pttAborted = false;
_checkHeartbeat(); _checkHeartbeat();
try { try {
// 若有正在播报的 PTT/BLE 唤醒会话,先强制中断 TTS/AI 流, // 若有正在播报的 PTT/BLE 唤醒会话,先强制中断 TTS/AI 流,
@ -281,6 +294,7 @@ class MobileElfController extends GetxController {
_inCallMode = false; _inCallMode = false;
_pttStarting = false; _pttStarting = false;
_pttResultPending = false; // 强制结束所有等待 _pttResultPending = false; // 强制结束所有等待
_pttSafetyTimer?.cancel();
_bleWakeupActive = false; _bleWakeupActive = false;
inCall.value = false; inCall.value = false;
_callTimer?.cancel(); _callTimer?.cancel();
@ -306,6 +320,7 @@ class MobileElfController extends GetxController {
Future<void> startPtt() async { Future<void> startPtt() async {
if (pttRecording.value || _pttStarting) return; if (pttRecording.value || _pttStarting) return;
_pttStarting = true; _pttStarting = true;
_pttAborted = false;
_checkHeartbeat(); _checkHeartbeat();
// BLE 唤醒/PTT 等待结果期间用户按下 PTT,先中断当前会话(同 startCall 逻辑) // BLE 唤醒/PTT 等待结果期间用户按下 PTT,先中断当前会话(同 startCall 逻辑)
if (_bleWakeupActive || _pttResultPending) { if (_bleWakeupActive || _pttResultPending) {
@ -343,10 +358,33 @@ class MobileElfController extends GetxController {
} }
if (!pttRecording.value) return; if (!pttRecording.value) return;
pttRecording.value = false; pttRecording.value = false;
_pttResultPending = true; // 等待 fin_result/assistant_response/tts 异步回来
_pttTimer?.cancel(); _pttTimer?.cancel();
_pttTimer = null; _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(); 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() { void interruptSpeaking() {

Loading…
Cancel
Save