From d386de2320a5c0e20ce7e9189021425574e292f6 Mon Sep 17 00:00:00 2001 From: chenjintao Date: Tue, 18 Aug 2026 13:52:07 +0800 Subject: [PATCH] fix(multimodal): prepare session for cloud fortune draw --- .../control_plane_multimodal_runtime.c | 128 ++++++++++++++++-- 1 file changed, 114 insertions(+), 14 deletions(-) diff --git a/components/control_plane/src/multimodal/control_plane_multimodal_runtime.c b/components/control_plane/src/multimodal/control_plane_multimodal_runtime.c index e161a32..7341262 100644 --- a/components/control_plane/src/multimodal/control_plane_multimodal_runtime.c +++ b/components/control_plane/src/multimodal/control_plane_multimodal_runtime.c @@ -39,11 +39,12 @@ #define CONTROL_PLANE_DOWNSTREAM_PLAYBACK_GUARD_MS 220 #define CONTROL_PLANE_DOWNSTREAM_STALL_STOP_GRACE_MS 2000 #define CONTROL_PLANE_IDLE_TRANSPORT_SHUTDOWN_MS 30000 -#define CONTROL_PLANE_WATCHDOG_TASK_STACK_SIZE 6144 +#define CONTROL_PLANE_WATCHDOG_TASK_STACK_SIZE 8192 #define CONTROL_PLANE_SERVER_SUCCESS_PROMPT_FILE "/littlefs/audio_prompts/server_connect_success.opus" #define CONTROL_PLANE_CLIENT_LIFECYCLE_WAIT_MS 30000U #define CONTROL_PLANE_SERVER_SUCCESS_PROMPT_RETRY_MS 1000U #define CONTROL_PLANE_SERVER_SUCCESS_PROMPT_MAX_ATTEMPTS 3U +#define CONTROL_PLANE_CLOUD_CHOUQIAN_PREPARE_TIMEOUT_MS 10000U #ifndef CONFIG_TQ_NETWORK_TASK_CORE #define CONFIG_TQ_NETWORK_TASK_CORE 0 @@ -66,6 +67,9 @@ static bool s_server_success_prompt_in_progress; static uint8_t s_server_success_prompt_attempts; static uint32_t s_server_success_prompt_next_attempt_ms; static bool s_cloud_chouqian_pending; +static bool s_cloud_chouqian_action_in_progress; +static bool s_cloud_chouqian_prompt_sent; +static uint32_t s_cloud_chouqian_requested_ms; static bool s_downstream_stall_recovery_pending; static bool s_downstream_stall_stop_sent; static uint32_t s_downstream_stall_recovery_started_ms; @@ -128,6 +132,14 @@ static void set_multimodal_task_handle(TaskHandle_t *slot, TaskHandle_t task) portEXIT_CRITICAL(&s_multimodal_runtime_lock); } +static void control_plane_wake_multimodal_watchdog(void) +{ + TaskHandle_t task = get_multimodal_task_handle(&s_multimodal_watchdog_task); + if (task != NULL) { + xTaskNotifyGive(task); + } +} + static void clear_multimodal_task_handle_if_match(TaskHandle_t *slot, TaskHandle_t expected_task) { portENTER_CRITICAL(&s_multimodal_runtime_lock); @@ -336,6 +348,9 @@ static void control_plane_clear_cloud_chouqian_pending(const char *reason) portENTER_CRITICAL(&s_multimodal_runtime_lock); was_pending = s_cloud_chouqian_pending; s_cloud_chouqian_pending = false; + s_cloud_chouqian_action_in_progress = false; + s_cloud_chouqian_prompt_sent = false; + s_cloud_chouqian_requested_ms = 0U; portEXIT_CRITICAL(&s_multimodal_runtime_lock); if (was_pending) { @@ -438,6 +453,93 @@ static uint32_t control_plane_now_ms(void) return (uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS); } +static void control_plane_try_cloud_chouqian_request(void) +{ + bool pending = false; + bool prompt_sent = false; + uint32_t requested_ms = 0U; + + portENTER_CRITICAL(&s_multimodal_runtime_lock); + pending = s_cloud_chouqian_pending; + prompt_sent = s_cloud_chouqian_prompt_sent; + requested_ms = s_cloud_chouqian_requested_ms; + portEXIT_CRITICAL(&s_multimodal_runtime_lock); + + if (!pending || prompt_sent) { + return; + } + + uint32_t now_ms = control_plane_now_ms(); + if ((now_ms - requested_ms) >= CONTROL_PLANE_CLOUD_CHOUQIAN_PREPARE_TIMEOUT_MS) { + control_plane_clear_cloud_chouqian_pending("session prepare timeout"); + return; + } + + control_plane_multimodal_runtime_state_t state = {0}; + esp_err_t state_err = control_plane_multimodal_get_runtime_state(&state); + if (state_err != ESP_OK) { + return; + } + + if (!state.connected) { + (void)control_plane_schedule_websocket_wait_task(); + return; + } + + bool should_send_start = !state.has_active_task; + bool should_send_prompt = state.has_active_task && state.server_listening; + if (!should_send_start && !should_send_prompt) { + return; + } + + portENTER_CRITICAL(&s_multimodal_runtime_lock); + if (!s_cloud_chouqian_pending || s_cloud_chouqian_action_in_progress) { + portEXIT_CRITICAL(&s_multimodal_runtime_lock); + return; + } + s_cloud_chouqian_action_in_progress = true; + if (should_send_prompt) { + s_cloud_chouqian_prompt_sent = true; + } + portEXIT_CRITICAL(&s_multimodal_runtime_lock); + + if (should_send_start) { + esp_err_t start_err = control_plane_multimodal_send_start(); + + portENTER_CRITICAL(&s_multimodal_runtime_lock); + s_cloud_chouqian_action_in_progress = false; + portEXIT_CRITICAL(&s_multimodal_runtime_lock); + + if (start_err == ESP_OK) { + ESP_LOGI(TAG, "Cloud chouqian waiting for multimodal session"); + } else if (start_err != ESP_ERR_INVALID_STATE) { + ESP_LOGW(TAG, + "Cloud chouqian session start failed: %s", + esp_err_to_name(start_err)); + control_plane_clear_cloud_chouqian_pending("session start failed"); + } + return; + } + + const control_plane_multimodal_respond_request_t request = { + .type = CONTROL_PLANE_MULTIMODAL_RESPOND_TYPE_PROMPT, + .text = "我要抽签", + .parameters_json = NULL, + }; + esp_err_t request_err = control_plane_multimodal_send_request_to_respond(&request); + + portENTER_CRITICAL(&s_multimodal_runtime_lock); + s_cloud_chouqian_action_in_progress = false; + portEXIT_CRITICAL(&s_multimodal_runtime_lock); + + if (request_err != ESP_OK) { + control_plane_clear_cloud_chouqian_pending("request send failed"); + return; + } + + ESP_LOGI(TAG, "Cloud chouqian prompt sent"); +} + static bool control_plane_is_within_downstream_guard(const control_plane_multimodal_runtime_state_t *state, uint32_t guard_ms) { @@ -549,27 +651,22 @@ esp_err_t control_plane_multimodal_request_to_respond( esp_err_t control_plane_request_cloud_chouqian(void) { + uint32_t requested_ms = control_plane_now_ms(); + portENTER_CRITICAL(&s_multimodal_runtime_lock); if (s_cloud_chouqian_pending) { portEXIT_CRITICAL(&s_multimodal_runtime_lock); return ESP_ERR_INVALID_STATE; } s_cloud_chouqian_pending = true; + s_cloud_chouqian_action_in_progress = false; + s_cloud_chouqian_prompt_sent = false; + s_cloud_chouqian_requested_ms = requested_ms; s_model_command_dispatched = false; portEXIT_CRITICAL(&s_multimodal_runtime_lock); - const control_plane_multimodal_respond_request_t request = { - .type = CONTROL_PLANE_MULTIMODAL_RESPOND_TYPE_PROMPT, - .text = "我要抽签", - .parameters_json = NULL, - }; - esp_err_t err = control_plane_multimodal_send_request_to_respond(&request); - if (err != ESP_OK) { - control_plane_clear_cloud_chouqian_pending("request send failed"); - return err; - } - - ESP_LOGI(TAG, "Cloud chouqian prompt sent"); + ESP_LOGI(TAG, "Cloud chouqian request queued"); + control_plane_wake_multimodal_watchdog(); return ESP_OK; } @@ -613,7 +710,7 @@ static void multimodal_watchdog_task(void *arg) uint32_t idle_transport_started_ms = 0U; while (!get_multimodal_stop_flag(&s_multimodal_watchdog_stop_requested)) { - vTaskDelay(tick_interval); + (void)ulTaskNotifyTake(pdTRUE, tick_interval); control_plane_multimodal_runtime_state_t state = {0}; if (control_plane_multimodal_get_runtime_state(&state) != ESP_OK) { @@ -622,6 +719,7 @@ static void multimodal_watchdog_task(void *arg) } uint32_t now_ms = control_plane_now_ms(); + control_plane_try_cloud_chouqian_request(); control_plane_try_server_success_prompt(&state, now_ms); bool stall_stop_sent = false; uint32_t stall_recovery_started_ms = 0U; @@ -771,9 +869,11 @@ static void control_plane_multimodal_event_bridge(control_plane_multimodal_event break; case CONTROL_PLANE_MULTIMODAL_EVENT_TASK_STARTED: + control_plane_wake_multimodal_watchdog(); break; case CONTROL_PLANE_MULTIMODAL_EVENT_SERVER_LISTENING: + control_plane_wake_multimodal_watchdog(); break; case CONTROL_PLANE_MULTIMODAL_EVENT_SERVER_NOT_LISTENING: