feat(voice): gate local wake prompt on network readiness

This commit is contained in:
chenjintao
2026-08-12 09:47:55 +08:00
parent 004400fee7
commit 7a4699ea68
15 changed files with 323 additions and 62 deletions
@@ -152,6 +152,7 @@ typedef enum {
PTT_STATE_WAIT_WS,
PTT_STATE_WAIT_START_SENT,
PTT_STATE_WAIT_LISTENING,
PTT_STATE_WAIT_WAKE_PROMPT,
PTT_STATE_WAIT_SPEECH_STARTED,
PTT_STATE_STREAMING,
PTT_STATE_TEARDOWN_LOCAL,
@@ -227,6 +228,8 @@ static const char *ptt_state_name(ptt_state_t state)
return "WAIT_START_SENT";
case PTT_STATE_WAIT_LISTENING:
return "WAIT_LISTENING";
case PTT_STATE_WAIT_WAKE_PROMPT:
return "WAIT_WAKE_PROMPT";
case PTT_STATE_WAIT_SPEECH_STARTED:
return "WAIT_SPEECH_STARTED";
case PTT_STATE_STREAMING:
@@ -349,6 +352,7 @@ void control_plane_set_ptt_active(bool active)
s_ptt_runtime.state == PTT_STATE_WAIT_WS ||
s_ptt_runtime.state == PTT_STATE_WAIT_START_SENT ||
s_ptt_runtime.state == PTT_STATE_WAIT_LISTENING ||
s_ptt_runtime.state == PTT_STATE_WAIT_WAKE_PROMPT ||
s_ptt_runtime.state == PTT_STATE_WAIT_SPEECH_STARTED ||
s_ptt_runtime.state == PTT_STATE_DENIED) {
control_plane_ptt_transition_locked(PTT_STATE_IDLE, "release_before_streaming");
@@ -368,6 +372,30 @@ void control_plane_set_ptt_active(bool active)
}
}
void control_plane_ptt_reset_capture_window(void)
{
bool active = false;
uint32_t generation = 0U;
portENTER_CRITICAL(&s_runtime_lock);
active = s_ptt_runtime.active;
if (active) {
s_ptt_runtime.press_tick = xTaskGetTickCount();
generation = s_ptt_runtime.generation;
}
portEXIT_CRITICAL(&s_runtime_lock);
if (!active) {
ESP_LOGW(TAG, "Skip PTT capture window reset: turn is no longer active");
return;
}
ESP_LOGI(TAG,
"PTT capture window armed after local wake prompt: generation=%u timeout_ms=%u",
(unsigned)generation,
(unsigned)CONFIG_TQ_PTT_CLICK_CAPTURE_TIMEOUT_MS);
control_plane_notify_wifi_state_task();
}
bool control_plane_voice_turn_is_idle(void)
{
bool idle = false;
@@ -1218,12 +1246,14 @@ static void control_plane_drive_ptt_state_machine(TickType_t *last_ws_start_atte
}
TickType_t now = xTaskGetTickCount();
bool local_wake_prompt_gate = control_plane_local_wake_prompt_gate_active();
#if CONFIG_TQ_PTT_MODE_CLICK_TO_TALK
TickType_t capture_timeout_ticks = pdMS_TO_TICKS(CONFIG_TQ_PTT_CLICK_CAPTURE_TIMEOUT_MS);
if (capture_timeout_ticks == 0) {
capture_timeout_ticks = 1;
}
if (ptt.press_tick != 0 &&
if (!local_wake_prompt_gate &&
ptt.press_tick != 0 &&
(now - ptt.press_tick) >= capture_timeout_ticks) {
control_plane_set_ptt_active(false);
return;
@@ -1234,7 +1264,8 @@ static void control_plane_drive_ptt_state_machine(TickType_t *last_ws_start_atte
if (denied_ticks == 0) {
denied_ticks = 1;
}
if (ptt.press_tick != 0 &&
if (!local_wake_prompt_gate &&
ptt.press_tick != 0 &&
(now - ptt.press_tick) >= denied_ticks &&
ptt.state != PTT_STATE_STREAMING &&
ptt.state != PTT_STATE_DENIED) {
@@ -1287,6 +1318,8 @@ static void control_plane_drive_ptt_state_machine(TickType_t *last_ws_start_atte
control_plane_ptt_set_state(PTT_STATE_WAIT_START_SENT, "send_start");
} else if (!state.server_listening) {
control_plane_ptt_set_state(PTT_STATE_WAIT_LISTENING, "wait_listening");
} else if (local_wake_prompt_gate) {
control_plane_ptt_set_state(PTT_STATE_WAIT_WAKE_PROMPT, "wait_local_wake_prompt");
} else if (!state.client_speech_active) {
control_plane_ptt_set_state(PTT_STATE_WAIT_SPEECH_STARTED, "send_speech");
} else if (control_plane_multimodal_is_uplink_running()) {
@@ -1296,7 +1329,8 @@ static void control_plane_drive_ptt_state_machine(TickType_t *last_ws_start_atte
}
ptt = control_plane_ptt_snapshot();
if ((ptt.state == PTT_STATE_WAIT_START_SENT ||
if (!local_wake_prompt_gate &&
(ptt.state == PTT_STATE_WAIT_START_SENT ||
ptt.state == PTT_STATE_WAIT_LISTENING) &&
(now - ptt.state_enter_tick) >=
pdMS_TO_TICKS(CONTROL_PLANE_PTT_LISTENING_TIMEOUT_MS)) {
@@ -1327,6 +1361,9 @@ static void control_plane_drive_ptt_state_machine(TickType_t *last_ws_start_atte
if (ptt.state == PTT_STATE_WAIT_SPEECH_STARTED && ptt.speech_action_sent) {
should_run_press_step = false;
}
if (ptt.state == PTT_STATE_WAIT_WAKE_PROMPT) {
should_run_press_step = false;
}
if (!should_run_press_step) {
return;
}