修复了第一次双击和对话没有反应问题

This commit is contained in:
CSBOOK\44744
2026-06-27 16:23:21 +08:00
parent 6aaf13d0a8
commit b829cd8ebc
6 changed files with 512 additions and 67 deletions
@@ -286,13 +286,6 @@ static esp_err_t control_plane_start_uplink_if_ready(void)
esp_err_t control_plane_multimodal_handle_ptt_press_step(void)
{
esp_err_t capture_err = control_plane_multimodal_start_capture();
if (capture_err != ESP_OK &&
capture_err != ESP_ERR_INVALID_STATE &&
capture_err != ESP_ERR_NOT_SUPPORTED) {
ESP_LOGW(TAG, "PTT capture start failed: %s", esp_err_to_name(capture_err));
}
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) {
@@ -327,6 +320,7 @@ esp_err_t control_plane_multimodal_handle_ptt_press_step(void)
if (speech_err != ESP_OK) {
return speech_err;
}
return ESP_ERR_INVALID_STATE;
}
if (control_plane_multimodal_is_uplink_running()) {
@@ -496,6 +490,10 @@ static void control_plane_multimodal_event_bridge(control_plane_multimodal_event
control_plane_multimodal_stop_uplink();
break;
case CONTROL_PLANE_MULTIMODAL_EVENT_TRANSPORT_ERROR:
control_plane_multimodal_stop_uplink();
break;
case CONTROL_PLANE_MULTIMODAL_EVENT_TASK_FAILED:
control_plane_request_server_error_expression(DOMAIN_EXPRESSION_TRIGGER_SERVER_TASK_FAILED);
control_plane_multimodal_stop_uplink();
@@ -85,7 +85,8 @@
#define CONTROL_PLANE_LOCAL_RESPONDING_EVENT_IDLE_EXIT_MS 5000U
#define CONTROL_PLANE_MULTIMODAL_BINARY_SUMMARY_INTERVAL 200U
#define CONTROL_PLANE_UPLINK_READY_WAIT_MS 6000U
#define CONTROL_PLANE_UPLINK_READY_POLL_MS 20U
#define CONTROL_PLANE_AUDIO_SEND_FAILURE_WINDOW_MS 100U
#define CONTROL_PLANE_AUDIO_SEND_FAILURE_THRESHOLD 2U
#ifndef CONFIG_TQ_LOCAL_TASK_CORE
#define CONFIG_TQ_LOCAL_TASK_CORE 1
@@ -124,6 +125,7 @@ static char s_task_id[40];
static char s_pending_start_task_id[40];
static char s_dialog_id[CONTROL_PLANE_MULTIMODAL_AUTH_ID_MAX_LEN];
static bool s_start_in_progress;
static bool s_transport_available;
static TickType_t s_last_heartbeat_tick;
static TickType_t s_last_downstream_tick;
@@ -141,6 +143,8 @@ static bool s_downstream_playback_completed;
static bool s_drop_downstream_audio;
static bool s_received_downstream_audio;
static bool s_current_response_received_audio;
static uint32_t s_audio_send_failure_count;
static TickType_t s_audio_send_failure_window_start_tick;
static size_t s_last_asr_text_len;
static size_t s_last_tts_text_len;
static uint32_t s_downstream_binary_packet_total;
@@ -376,12 +380,79 @@ static void reset_session_state_locked(void)
s_drop_downstream_audio = false;
s_received_downstream_audio = false;
s_current_response_received_audio = false;
s_audio_send_failure_count = 0;
s_audio_send_failure_window_start_tick = 0;
s_local_responding_started_send_pending = false;
s_local_responding_ended_send_pending = false;
s_last_asr_text_len = 0;
s_last_tts_text_len = 0;
}
static bool transport_available_locked(void)
{
return s_transport_available && domain_runtime_multimodal_transport_is_connected();
}
static bool transport_available(void)
{
bool available = false;
if (lock_state()) {
available = transport_available_locked();
unlock_state();
}
return available;
}
static const char *transport_loss_reason_name(control_plane_transport_loss_reason_t reason)
{
switch (reason) {
case CONTROL_PLANE_TRANSPORT_LOSS_WS_ERROR:
return "ws_error";
case CONTROL_PLANE_TRANSPORT_LOSS_WS_DISCONNECTED:
return "ws_disconnected";
case CONTROL_PLANE_TRANSPORT_LOSS_SEND_TEXT_FAILURE:
return "send_text_failure";
case CONTROL_PLANE_TRANSPORT_LOSS_SEND_BINARY_FAILURE:
return "send_binary_failure";
case CONTROL_PLANE_TRANSPORT_LOSS_LISTENING_TIMEOUT:
return "listening_timeout";
case CONTROL_PLANE_TRANSPORT_LOSS_NO_RESPONSE_TIMEOUT:
return "no_response_timeout";
default:
return "unknown";
}
}
void control_plane_multimodal_reset_uplink_failure_window(void)
{
if (!lock_state()) {
return;
}
s_audio_send_failure_count = 0;
s_audio_send_failure_window_start_tick = 0;
unlock_state();
}
void control_plane_multimodal_mark_transport_unavailable(
control_plane_transport_loss_reason_t reason,
const char *caller)
{
ESP_LOGW(TAG,
"Transport unavailable: reason=%s caller=%s",
transport_loss_reason_name(reason),
caller != NULL ? caller : "-");
if (lock_state()) {
s_started = false;
s_transport_available = false;
memset(&s_auth, 0, sizeof(s_auth));
reset_session_state_locked();
unlock_state();
}
control_plane_multimodal_stop_uplink();
}
static void reset_session_state(void)
{
if (!lock_state()) {
@@ -915,6 +986,11 @@ static esp_err_t send_directive(const char *action,
domain_runtime_multimodal_transport_send_text_realtime(directive, json) :
domain_runtime_multimodal_transport_send_text("directive", json);
free(json);
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
control_plane_multimodal_mark_transport_unavailable(
CONTROL_PLANE_TRANSPORT_LOSS_SEND_TEXT_FAILURE,
__func__);
}
return err;
}
@@ -972,6 +1048,11 @@ static esp_err_t send_request_to_respond_directive(
err = domain_runtime_multimodal_transport_send_text("request_to_respond", json);
free(json);
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
control_plane_multimodal_mark_transport_unavailable(
CONTROL_PLANE_TRANSPORT_LOSS_SEND_TEXT_FAILURE,
__func__);
}
return err;
}
@@ -1026,6 +1107,11 @@ static esp_err_t send_update_info_directive(
err = domain_runtime_multimodal_transport_send_text("update_info", json);
free(json);
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
control_plane_multimodal_mark_transport_unavailable(
CONTROL_PLANE_TRANSPORT_LOSS_SEND_TEXT_FAILURE,
__func__);
}
return err;
}
@@ -1323,6 +1409,7 @@ static void transport_event_bridge(const domain_multimodal_transport_event_t *ev
switch (event->type) {
case DOMAIN_MULTIMODAL_TRANSPORT_EVENT_CONNECTED:
if (lock_state()) {
s_transport_available = true;
s_last_heartbeat_tick = xTaskGetTickCount();
s_last_downstream_tick = s_last_heartbeat_tick;
unlock_state();
@@ -1331,16 +1418,16 @@ static void transport_event_bridge(const domain_multimodal_transport_event_t *ev
break;
case DOMAIN_MULTIMODAL_TRANSPORT_EVENT_DISCONNECTED:
if (lock_state()) {
s_started = false;
memset(&s_auth, 0, sizeof(s_auth));
reset_session_state_locked();
unlock_state();
}
control_plane_multimodal_mark_transport_unavailable(
CONTROL_PLANE_TRANSPORT_LOSS_WS_DISCONNECTED,
__func__);
notify_event(CONTROL_PLANE_MULTIMODAL_EVENT_TRANSPORT_DISCONNECTED);
break;
case DOMAIN_MULTIMODAL_TRANSPORT_EVENT_ERROR:
control_plane_multimodal_mark_transport_unavailable(
CONTROL_PLANE_TRANSPORT_LOSS_WS_ERROR,
__func__);
notify_event(CONTROL_PLANE_MULTIMODAL_EVENT_TRANSPORT_ERROR);
break;
@@ -1440,30 +1527,6 @@ static void downstream_playback_event_bridge(
static esp_err_t control_plane_audio_uplink_send_cb(const uint8_t *data, size_t len, void *ctx)
{
(void)ctx;
uint32_t waited_ms = 0U;
while (waited_ms < CONTROL_PLANE_UPLINK_READY_WAIT_MS) {
esp_err_t err = control_plane_multimodal_send_audio_realtime(data, len);
if (err != ESP_ERR_INVALID_STATE) {
return err;
}
control_plane_multimodal_runtime_state_t state = {0};
if (control_plane_multimodal_get_runtime_state(&state) == ESP_OK &&
state.connected) {
if (!state.has_active_task) {
(void)control_plane_multimodal_send_start();
} else if (state.server_listening &&
!state.client_speech_active &&
!state.ptt_release_required &&
!state.remote_responding) {
(void)control_plane_multimodal_send_speech_start();
}
}
vTaskDelay(pdMS_TO_TICKS(CONTROL_PLANE_UPLINK_READY_POLL_MS));
waited_ms += CONTROL_PLANE_UPLINK_READY_POLL_MS;
}
return control_plane_multimodal_send_audio_realtime(data, len);
}
@@ -1534,14 +1597,14 @@ void control_plane_multimodal_stop(void)
bool control_plane_multimodal_is_connected(void)
{
return domain_runtime_multimodal_transport_is_connected();
return transport_available();
}
esp_err_t control_plane_multimodal_send_start(void)
{
control_plane_multimodal_auth_info_t auth = {0};
if (!domain_runtime_multimodal_transport_is_connected()) {
if (!transport_available()) {
return ESP_ERR_INVALID_STATE;
}
@@ -1701,6 +1764,11 @@ esp_err_t control_plane_multimodal_send_start(void)
free(json);
if (err != ESP_OK) {
clear_start_in_progress();
if (err != ESP_ERR_INVALID_STATE) {
control_plane_multimodal_mark_transport_unavailable(
CONTROL_PLANE_TRANSPORT_LOSS_SEND_TEXT_FAILURE,
__func__);
}
return err;
}
@@ -1761,7 +1829,7 @@ esp_err_t control_plane_multimodal_send_stop(const char *reason)
esp_err_t control_plane_multimodal_send_request_to_speak(void)
{
if (!domain_runtime_multimodal_transport_is_connected()) {
if (!transport_available()) {
return ESP_ERR_INVALID_STATE;
}
@@ -1794,7 +1862,7 @@ esp_err_t control_plane_multimodal_send_request_to_speak(void)
esp_err_t control_plane_multimodal_send_speech_start(void)
{
if (!domain_runtime_multimodal_transport_is_connected()) {
if (!transport_available()) {
return ESP_ERR_INVALID_STATE;
}
@@ -1841,7 +1909,7 @@ esp_err_t control_plane_multimodal_send_speech_stop(void)
unlock_state();
esp_err_t err = ESP_OK;
if (domain_runtime_multimodal_transport_is_connected() && has_active_task) {
if (transport_available() && has_active_task) {
err = send_directive("continue-task", "StopSpeech", true, false);
}
@@ -1860,7 +1928,7 @@ esp_err_t control_plane_multimodal_send_speech_stop(void)
esp_err_t control_plane_multimodal_send_cancel_speech(void)
{
if (!domain_runtime_multimodal_transport_is_connected()) {
if (!transport_available()) {
return ESP_ERR_INVALID_STATE;
}
@@ -1896,7 +1964,7 @@ esp_err_t control_plane_multimodal_send_request_to_respond(
return ESP_ERR_INVALID_ARG;
}
if (!domain_runtime_multimodal_transport_is_connected()) {
if (!transport_available()) {
return ESP_ERR_INVALID_STATE;
}
@@ -1928,7 +1996,7 @@ esp_err_t control_plane_multimodal_send_update_info(
return ESP_ERR_INVALID_ARG;
}
if (!domain_runtime_multimodal_transport_is_connected()) {
if (!transport_available()) {
return ESP_ERR_INVALID_STATE;
}
@@ -1988,7 +2056,7 @@ esp_err_t control_plane_multimodal_send_audio_realtime(const uint8_t *data, size
return ESP_ERR_INVALID_ARG;
}
if (!domain_runtime_multimodal_transport_is_connected()) {
if (!transport_available()) {
return ESP_ERR_INVALID_STATE;
}
@@ -2008,7 +2076,41 @@ esp_err_t control_plane_multimodal_send_audio_realtime(const uint8_t *data, size
return ESP_ERR_INVALID_STATE;
}
return domain_runtime_multimodal_transport_send_binary_realtime(data, len);
esp_err_t err = domain_runtime_multimodal_transport_send_binary_realtime(data, len);
if (err == ESP_OK) {
control_plane_multimodal_reset_uplink_failure_window();
return ESP_OK;
}
if (err == ESP_ERR_INVALID_STATE) {
return err;
}
bool threshold_reached = false;
if (lock_state()) {
TickType_t now = xTaskGetTickCount();
TickType_t window_ticks = pdMS_TO_TICKS(CONTROL_PLANE_AUDIO_SEND_FAILURE_WINDOW_MS);
if (window_ticks == 0) {
window_ticks = 1;
}
if (s_audio_send_failure_window_start_tick == 0 ||
(now - s_audio_send_failure_window_start_tick) > window_ticks) {
s_audio_send_failure_window_start_tick = now;
s_audio_send_failure_count = 0;
}
s_audio_send_failure_count++;
threshold_reached =
s_audio_send_failure_count >= CONTROL_PLANE_AUDIO_SEND_FAILURE_THRESHOLD;
unlock_state();
}
if (threshold_reached) {
control_plane_multimodal_mark_transport_unavailable(
CONTROL_PLANE_TRANSPORT_LOSS_SEND_BINARY_FAILURE,
__func__);
}
return err;
}
esp_err_t control_plane_multimodal_get_runtime_state(control_plane_multimodal_runtime_state_t *out_state)
@@ -2020,7 +2122,7 @@ esp_err_t control_plane_multimodal_get_runtime_state(control_plane_multimodal_ru
if (!lock_state()) {
return ESP_ERR_TIMEOUT;
}
out_state->connected = domain_runtime_multimodal_transport_is_connected();
out_state->connected = transport_available_locked();
out_state->has_active_task = s_task_id[0] != '\0';
out_state->server_listening = s_server_listening;
out_state->remote_responding = s_remote_responding;
@@ -2082,7 +2184,7 @@ static esp_err_t control_plane_multimodal_prepare_audio_runtime(void)
unlock_state();
}
if (!domain_runtime_multimodal_transport_is_connected() || !has_active_task) {
if (!transport_available() || !has_active_task) {
return ESP_ERR_INVALID_STATE;
}