From 045a803362b5afa8d1a9a1cd1d99a5f3db2f4909 Mon Sep 17 00:00:00 2001 From: chenjintao Date: Thu, 20 Aug 2026 11:02:38 +0800 Subject: [PATCH] feat(control-plane): show listening ui for ptt button --- .../internal/control_plane_internal.h | 1 + .../control_plane_multimodal_local_wake.c | 27 +-------- .../runtime/control_plane_runtime_workers.c | 56 ++++++++++++++++++- components/domain/include/domain.h | 1 + 4 files changed, 58 insertions(+), 27 deletions(-) diff --git a/components/control_plane/internal/control_plane_internal.h b/components/control_plane/internal/control_plane_internal.h index 2c9bd69..9986449 100644 --- a/components/control_plane/internal/control_plane_internal.h +++ b/components/control_plane/internal/control_plane_internal.h @@ -161,6 +161,7 @@ void control_plane_stop_key_input_task(void); void control_plane_reset_wifi_provisioning_and_restart(void); esp_err_t control_plane_schedule_websocket_wait_task(void); void control_plane_set_ptt_active(bool active); +void control_plane_set_ptt_active_from_local_wake(void); esp_err_t control_plane_enter_mini_program_reprovisioning(const char *reason); esp_err_t control_plane_remote_log_start(void); diff --git a/components/control_plane/src/multimodal/control_plane_multimodal_local_wake.c b/components/control_plane/src/multimodal/control_plane_multimodal_local_wake.c index 9acef34..a47b32e 100644 --- a/components/control_plane/src/multimodal/control_plane_multimodal_local_wake.c +++ b/components/control_plane/src/multimodal/control_plane_multimodal_local_wake.c @@ -63,7 +63,6 @@ typedef struct { bool capture_owned; bool prompt_pending; bool prompt_playing; - bool listening_ui_active; TickType_t prompt_wait_started_tick; uint32_t detection_generation; } local_wake_state_t; @@ -88,21 +87,6 @@ static void local_wake_set_capture_owned(bool owned) portEXIT_CRITICAL(&s_local_wake_lock); } -static void local_wake_request_expression(domain_expression_id_t id) -{ - const domain_expression_request_t request = { - .id = id, - .trigger = DOMAIN_EXPRESSION_TRIGGER_LOCAL_WAKE, - }; - esp_err_t err = domain_runtime_request_expression(&request); - if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { - ESP_LOGW(TAG, - "Local wake expression request failed: id=%d err=%s", - (int)id, - esp_err_to_name(err)); - } -} - bool control_plane_local_wake_prompt_gate_active(void) { #if CONFIG_TQ_LOCAL_WAKE_ENABLE && CONFIG_TQ_LOCAL_WAKE_RESPONSE_PROMPT_ENABLE @@ -315,7 +299,6 @@ static void local_wake_handle_detection( return; } s_local_wake.paused_for_foreground = true; - s_local_wake.listening_ui_active = true; s_local_wake.detection_generation = event->detection_generation; #if CONFIG_TQ_LOCAL_WAKE_RESPONSE_PROMPT_ENABLE s_local_wake.prompt_pending = CONFIG_TQ_LOCAL_WAKE_RESPONSE_PROMPT_FILE[0] != '\0'; @@ -324,7 +307,6 @@ static void local_wake_handle_detection( #endif portEXIT_CRITICAL(&s_local_wake_lock); - local_wake_request_expression(DOMAIN_EXPRESSION_LISTENING); ESP_LOGI(TAG, "Local wake foreground entered: generation=%u listening_ui=1 prompt_gate=%d ready_timeout_ms=%u", (unsigned)event->detection_generation, @@ -340,7 +322,7 @@ static void local_wake_handle_detection( (unsigned)event->confidence_x10000, (unsigned)event->detection_generation); - control_plane_set_ptt_active(true); + control_plane_set_ptt_active_from_local_wake(); } static void local_wake_task(void *arg) @@ -437,7 +419,6 @@ esp_err_t control_plane_local_wake_start(void) s_local_wake.capture_owned = false; s_local_wake.prompt_pending = false; s_local_wake.prompt_playing = false; - s_local_wake.listening_ui_active = false; s_local_wake.prompt_wait_started_tick = 0U; s_local_wake.detection_generation = 0U; s_local_wake.started = true; @@ -532,19 +513,13 @@ void control_plane_local_wake_pause_for_foreground(void) void control_plane_local_wake_resume_after_foreground(void) { #if CONFIG_TQ_LOCAL_WAKE_ENABLE - bool restore_idle_ui = false; portENTER_CRITICAL(&s_local_wake_lock); s_local_wake.paused_for_foreground = false; s_local_wake.prompt_pending = false; s_local_wake.prompt_playing = false; s_local_wake.prompt_wait_started_tick = 0U; - restore_idle_ui = s_local_wake.listening_ui_active; - s_local_wake.listening_ui_active = false; TaskHandle_t task = s_local_wake.task; portEXIT_CRITICAL(&s_local_wake_lock); - if (restore_idle_ui) { - local_wake_request_expression(DOMAIN_EXPRESSION_IDLE); - } if (task != NULL) { xTaskNotifyGive(task); } diff --git a/components/control_plane/src/runtime/control_plane_runtime_workers.c b/components/control_plane/src/runtime/control_plane_runtime_workers.c index 86ead39..dc83d77 100644 --- a/components/control_plane/src/runtime/control_plane_runtime_workers.c +++ b/components/control_plane/src/runtime/control_plane_runtime_workers.c @@ -213,6 +213,8 @@ typedef struct { bool pending_press_after_teardown; bool start_action_sent; bool speech_action_sent; + bool listening_ui_active; + domain_expression_trigger_t listening_ui_trigger; } ptt_runtime_t; typedef struct { @@ -552,7 +554,27 @@ static void control_plane_notify_wifi_state_task(void) } } -void control_plane_set_ptt_active(bool active) +static void control_plane_request_ptt_expression( + domain_expression_id_t id, + domain_expression_trigger_t trigger) +{ + const domain_expression_request_t request = { + .id = id, + .trigger = trigger, + }; + esp_err_t err = domain_runtime_request_expression(&request); + if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { + ESP_LOGW(TAG, + "PTT expression request failed: id=%d trigger=%d err=%s", + (int)id, + (int)trigger, + esp_err_to_name(err)); + } +} + +static void control_plane_set_ptt_active_with_trigger( + bool active, + domain_expression_trigger_t listening_ui_trigger) { if (active) { control_plane_local_wake_pause_for_foreground(); @@ -563,6 +585,9 @@ void control_plane_set_ptt_active(bool active) uint32_t generation = 0; const char *transition_reason = active ? "press" : "release"; bool uplink_running = !active && control_plane_multimodal_is_uplink_running(); + bool request_listening_ui = false; + bool restore_idle_ui = false; + domain_expression_trigger_t expression_trigger = listening_ui_trigger; portENTER_CRITICAL(&s_runtime_lock); old_state = s_ptt_runtime.state; s_ptt_active = active; @@ -575,6 +600,9 @@ void control_plane_set_ptt_active(bool active) s_ptt_runtime.foreground_attempts = 0; s_ptt_runtime.start_action_sent = false; s_ptt_runtime.speech_action_sent = false; + s_ptt_runtime.listening_ui_active = true; + s_ptt_runtime.listening_ui_trigger = listening_ui_trigger; + request_listening_ui = true; if (s_ptt_runtime.state == PTT_STATE_TEARDOWN_LOCAL || s_ptt_runtime.state == PTT_STATE_TEARDOWN_REMOTE) { s_ptt_runtime.pending_press_after_teardown = true; @@ -589,6 +617,9 @@ void control_plane_set_ptt_active(bool active) s_ptt_runtime.foreground_attempts = 0; s_ptt_runtime.pending_press_after_teardown = false; s_ptt_runtime.generation++; + restore_idle_ui = s_ptt_runtime.listening_ui_active; + expression_trigger = s_ptt_runtime.listening_ui_trigger; + s_ptt_runtime.listening_ui_active = false; if (uplink_running || s_ptt_runtime.state == PTT_STATE_STREAMING) { control_plane_ptt_transition_locked(PTT_STATE_TEARDOWN_LOCAL, "release_streaming"); transition_reason = "release_streaming"; @@ -608,6 +639,15 @@ void control_plane_set_ptt_active(bool active) generation = s_ptt_runtime.generation; portEXIT_CRITICAL(&s_runtime_lock); control_plane_ptt_log_transition(old_state, new_state, generation, transition_reason); + if (request_listening_ui) { + control_plane_request_ptt_expression( + DOMAIN_EXPRESSION_LISTENING, + expression_trigger); + } else if (restore_idle_ui) { + control_plane_request_ptt_expression( + DOMAIN_EXPRESSION_IDLE, + expression_trigger); + } if (notify_worker) { control_plane_notify_wifi_state_task(); } @@ -616,6 +656,20 @@ void control_plane_set_ptt_active(bool active) } } +void control_plane_set_ptt_active(bool active) +{ + control_plane_set_ptt_active_with_trigger( + active, + DOMAIN_EXPRESSION_TRIGGER_PTT_BUTTON); +} + +void control_plane_set_ptt_active_from_local_wake(void) +{ + control_plane_set_ptt_active_with_trigger( + true, + DOMAIN_EXPRESSION_TRIGGER_LOCAL_WAKE); +} + void control_plane_ptt_reset_capture_window(void) { bool active = false; diff --git a/components/domain/include/domain.h b/components/domain/include/domain.h index df83f40..fe61fc9 100644 --- a/components/domain/include/domain.h +++ b/components/domain/include/domain.h @@ -191,6 +191,7 @@ typedef enum { DOMAIN_EXPRESSION_TRIGGER_LOCAL_WAKE, DOMAIN_EXPRESSION_TRIGGER_OTA_UPDATE, DOMAIN_EXPRESSION_TRIGGER_MODEL_LUCKY_COLOR, + DOMAIN_EXPRESSION_TRIGGER_PTT_BUTTON, } domain_expression_trigger_t; typedef struct {