基本功能正常,需要解决首次双击没有效果,首次对话没有反应

This commit is contained in:
CSBOOK\44744
2026-06-27 10:50:29 +08:00
parent 0635bd17f7
commit 6aaf13d0a8
7 changed files with 80 additions and 168 deletions
@@ -130,6 +130,17 @@ static esp_err_t app_composition_run_plan_a_boot_sequence(void)
return err;
}
#if CONFIG_TQ_SCREEN_ENABLE
if (lcd_ready) {
esp_err_t expression_err = control_plane_request_boot_expression();
if (expression_err != ESP_OK) {
ESP_LOGW(TAG,
"Boot LCD expression request failed: %s",
esp_err_to_name(expression_err));
}
}
#endif
#if CONFIG_TQ_BOOT_TURNTABLE_CALIBRATION_ENABLE
app_composition_log_stage(APP_COMPOSITION_BOOT_STAGE_TURNTABLE_CALIBRATION,
"turntable_calibration",
@@ -82,6 +82,7 @@
#define CONTROL_PLANE_LOCAL_RESPONDING_EVENT_TASK_STACK_BYTES 4096U
#define CONTROL_PLANE_LOCAL_RESPONDING_EVENT_TASK_PRIORITY 5U
#define CONTROL_PLANE_LOCAL_RESPONDING_EVENT_QUEUE_LEN 4U
#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
@@ -446,8 +447,14 @@ static void local_responding_event_worker(void *arg)
local_responding_event_msg_t msg = {0};
while (true) {
if (xQueueReceive(s_local_responding_event_queue, &msg, portMAX_DELAY) != pdTRUE) {
continue;
TickType_t idle_ticks = pdMS_TO_TICKS(CONTROL_PLANE_LOCAL_RESPONDING_EVENT_IDLE_EXIT_MS);
if (idle_ticks == 0) {
idle_ticks = 1;
}
if (xQueueReceive(s_local_responding_event_queue, &msg, idle_ticks) != pdTRUE) {
s_local_responding_event_task = NULL;
vTaskDelete(NULL);
return;
}
bool should_send = false;
@@ -23,7 +23,7 @@
#define CONTROL_PLANE_MODEL_CMD_TASK_STACK_SIZE (1024 * 4)
#define CONTROL_PLANE_DIRECTION_TASK_STACK_SIZE (1024 * 4)
#define CONTROL_PLANE_LCD_RENDER_LOOP_TASK_STACK_SIZE (1024 * 12)
#define CONTROL_PLANE_WIFI_STATE_TASK_STACK_SIZE (1024 * 6)
#define CONTROL_PLANE_WIFI_STATE_TASK_STACK_SIZE (1024 * 12)
#define CONTROL_PLANE_TASK_MONITOR_TASK_STACK_SIZE (1024 * 6)
#define CONTROL_PLANE_MODEL_CMD_QUEUE_LEN 4
#define CONTROL_PLANE_MODEL_CMD_RECV_TIMEOUT_MS 200
@@ -18,6 +18,7 @@
#include "esp_err.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "esp_opus_dec.h"
#include "esp_opus_enc.h"
#include "freertos/FreeRTOS.h"
@@ -232,7 +233,6 @@
#define MULTIMODAL_PCM_SAMPLE_BYTES 2U
#define MULTIMODAL_MIN_DECODER_PCM_BUFFER_BYTES 2048U
#define MULTIMODAL_DECODER_BUFFER_GUARD_BYTES 512U
#define MULTIMODAL_AUDIO_DOWNSTREAM_IDLE_MUTE_TASK_STACK_BYTES 4096U
#define MULTIMODAL_AUDIO_DOWNSTREAM_TX_BOUNCE_BYTES 3200U
#define MULTIMODAL_AUDIO_DEFAULT_MIC_CHANNEL ((uint8_t)CONFIG_MULTIMODAL_AUDIO_MIC_CHANNEL)
@@ -273,7 +273,6 @@ typedef struct {
uint8_t *downstream_tx_bounce_buf;
size_t downstream_tx_bounce_buf_bytes;
uint32_t downstream_playback_generation;
uint32_t downstream_audio_activity_generation;
volatile bool downstream_decoder_reset_pending;
bool downstream_playback_in_progress;
bool downstream_output_muted;
@@ -281,8 +280,7 @@ typedef struct {
bool downstream_output_primed;
bool downstream_response_active;
bool downstream_response_end_received;
TaskHandle_t downstream_idle_mute_task;
bool downstream_idle_mute_stop_requested;
esp_timer_handle_t downstream_idle_mute_timer;
QueueHandle_t downstream_playback_queue;
bool downstream_playback_queue_with_caps;
TaskHandle_t downstream_playback_task;
@@ -206,46 +206,24 @@ static void audio_set_uplink_send_task(multimodal_audio_ctx_t *ctx, TaskHandle_t
portEXIT_CRITICAL(&s_audio_runtime_lock);
}
static bool audio_get_downstream_idle_mute_stop_requested(const multimodal_audio_ctx_t *ctx)
static esp_timer_handle_t audio_get_downstream_idle_mute_timer(const multimodal_audio_ctx_t *ctx)
{
bool stop_requested = true;
esp_timer_handle_t timer = NULL;
portENTER_CRITICAL(&s_audio_runtime_lock);
if (ctx != NULL) {
stop_requested = ctx->downstream_idle_mute_stop_requested;
timer = ctx->downstream_idle_mute_timer;
}
portEXIT_CRITICAL(&s_audio_runtime_lock);
return stop_requested;
return timer;
}
static void audio_set_downstream_idle_mute_stop_requested(multimodal_audio_ctx_t *ctx, bool stop_requested)
static void audio_set_downstream_idle_mute_timer(multimodal_audio_ctx_t *ctx, esp_timer_handle_t timer)
{
portENTER_CRITICAL(&s_audio_runtime_lock);
if (ctx != NULL) {
ctx->downstream_idle_mute_stop_requested = stop_requested;
}
portEXIT_CRITICAL(&s_audio_runtime_lock);
}
static TaskHandle_t audio_get_downstream_idle_mute_task(const multimodal_audio_ctx_t *ctx)
{
TaskHandle_t task = NULL;
portENTER_CRITICAL(&s_audio_runtime_lock);
if (ctx != NULL) {
task = ctx->downstream_idle_mute_task;
}
portEXIT_CRITICAL(&s_audio_runtime_lock);
return task;
}
static void audio_set_downstream_idle_mute_task(multimodal_audio_ctx_t *ctx, TaskHandle_t task)
{
portENTER_CRITICAL(&s_audio_runtime_lock);
if (ctx != NULL) {
ctx->downstream_idle_mute_task = task;
ctx->downstream_idle_mute_timer = timer;
}
portEXIT_CRITICAL(&s_audio_runtime_lock);
}
@@ -1118,32 +1096,6 @@ static bool clear_downstream_decoder_reset_pending(uint32_t expected_generation)
return cleared;
}
static uint32_t snapshot_downstream_audio_activity_generation(void)
{
uint32_t generation = 0U;
portENTER_CRITICAL(&s_audio_runtime_lock);
generation = s_audio.downstream_audio_activity_generation;
portEXIT_CRITICAL(&s_audio_runtime_lock);
return generation;
}
static uint32_t advance_downstream_audio_activity_generation(void)
{
uint32_t generation = 0U;
portENTER_CRITICAL(&s_audio_runtime_lock);
s_audio.downstream_audio_activity_generation++;
if (s_audio.downstream_audio_activity_generation == 0U) {
s_audio.downstream_audio_activity_generation = 1U;
}
generation = s_audio.downstream_audio_activity_generation;
portEXIT_CRITICAL(&s_audio_runtime_lock);
return generation;
}
static void snapshot_downstream_output_mute_state(bool *out_known, bool *out_muted)
{
if (out_known == NULL || out_muted == NULL) {
@@ -1337,71 +1289,30 @@ static esp_err_t set_downstream_output_mute_if_needed(multimodal_audio_ctx_t *ct
return (esp_err_t)ret;
}
static TickType_t get_downstream_idle_mute_timeout_ticks(void)
static uint32_t get_downstream_idle_mute_timeout_ms(void)
{
uint32_t timeout_ms = (uint32_t)CONFIG_MULTIMODAL_AUDIO_DOWNSTREAM_IDLE_MUTE_MS;
if (timeout_ms < 50U) {
timeout_ms = 50U;
}
TickType_t ticks = pdMS_TO_TICKS(timeout_ms);
return ticks == 0 ? 1 : ticks;
return timeout_ms;
}
static void downstream_idle_mute_task(void *arg)
static void downstream_idle_mute_timer_cb(void *arg)
{
multimodal_audio_ctx_t *ctx = (multimodal_audio_ctx_t *)arg;
TickType_t idle_timeout_ticks = get_downstream_idle_mute_timeout_ticks();
if (ctx == NULL || snapshot_downstream_response_active()) {
return;
}
if (ctx->initialized && ctx->codec_dev != NULL) {
(void)set_downstream_output_mute_if_needed(ctx, true, "Idle mute");
}
ESP_LOGI(TAG,
"Downstream idle mute task started (timeout=%ums)",
(unsigned)CONFIG_MULTIMODAL_AUDIO_DOWNSTREAM_IDLE_MUTE_MS);
while (ctx != NULL && !audio_get_downstream_idle_mute_stop_requested(ctx)) {
(void)ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if (audio_get_downstream_idle_mute_stop_requested(ctx)) {
break;
}
uint32_t observed_generation = snapshot_downstream_audio_activity_generation();
while (!audio_get_downstream_idle_mute_stop_requested(ctx)) {
uint32_t notify_count = ulTaskNotifyTake(pdTRUE, idle_timeout_ticks);
if (audio_get_downstream_idle_mute_stop_requested(ctx)) {
break;
}
if (notify_count > 0U) {
observed_generation = snapshot_downstream_audio_activity_generation();
continue;
}
uint32_t current_generation = snapshot_downstream_audio_activity_generation();
if (current_generation != observed_generation) {
observed_generation = current_generation;
continue;
}
if (snapshot_downstream_response_active()) {
continue;
}
if (ctx->initialized && ctx->codec_dev != NULL) {
(void)set_downstream_output_mute_if_needed(ctx, true, "Idle mute");
}
ESP_LOGI(TAG,
"Downstream idle mute after %ums (response_active=%d)",
(unsigned)CONFIG_MULTIMODAL_AUDIO_DOWNSTREAM_IDLE_MUTE_MS,
snapshot_downstream_response_active() ? 1 : 0);
maybe_notify_downstream_playback_completed_after_drain("idle");
break;
}
}
if (ctx != NULL) {
audio_set_downstream_idle_mute_task(ctx, NULL);
audio_set_downstream_idle_mute_stop_requested(ctx, false);
}
ESP_LOGI(TAG, "Downstream idle mute task stopped");
delete_audio_task_with_caps(NULL);
"Downstream idle mute after %ums (response_active=%d)",
(unsigned)get_downstream_idle_mute_timeout_ms(),
snapshot_downstream_response_active() ? 1 : 0);
maybe_notify_downstream_playback_completed_after_drain("idle");
}
static esp_err_t ensure_downstream_idle_mute_task(multimodal_audio_ctx_t *ctx)
@@ -1409,38 +1320,39 @@ static esp_err_t ensure_downstream_idle_mute_task(multimodal_audio_ctx_t *ctx)
if (ctx == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (audio_get_downstream_idle_mute_task(ctx) != NULL) {
if (audio_get_downstream_idle_mute_timer(ctx) != NULL) {
return ESP_OK;
}
audio_set_downstream_idle_mute_stop_requested(ctx, false);
TaskHandle_t task = NULL;
BaseType_t created = create_audio_task_with_caps(downstream_idle_mute_task,
"mm_audio_idle_mute",
MULTIMODAL_AUDIO_DOWNSTREAM_IDLE_MUTE_TASK_STACK_BYTES,
ctx,
4,
&task,
false,
MULTIMODAL_AUDIO_CORE_ID);
if (created != pdPASS) {
audio_set_downstream_idle_mute_task(ctx, NULL);
return ESP_ERR_NO_MEM;
const esp_timer_create_args_t timer_args = {
.callback = downstream_idle_mute_timer_cb,
.arg = ctx,
.dispatch_method = ESP_TIMER_TASK,
.name = "mm_audio_idle_mute",
.skip_unhandled_events = true,
};
esp_timer_handle_t timer = NULL;
esp_err_t err = esp_timer_create(&timer_args, &timer);
if (err != ESP_OK) {
return err;
}
audio_set_downstream_idle_mute_task(ctx, task);
audio_set_downstream_idle_mute_timer(ctx, timer);
ESP_LOGI(TAG,
"Downstream idle mute timer ready (timeout=%ums)",
(unsigned)get_downstream_idle_mute_timeout_ms());
return ESP_OK;
}
static void notify_downstream_audio_active(multimodal_audio_ctx_t *ctx)
{
TaskHandle_t task = audio_get_downstream_idle_mute_task(ctx);
if (ctx == NULL || task == NULL) {
esp_timer_handle_t timer = audio_get_downstream_idle_mute_timer(ctx);
if (ctx == NULL || timer == NULL) {
return;
}
(void)advance_downstream_audio_activity_generation();
xTaskNotifyGive(task);
(void)esp_timer_stop(timer);
(void)esp_timer_start_once(timer, (uint64_t)get_downstream_idle_mute_timeout_ms() * 1000ULL);
}
static esp_err_t ensure_downstream_tx_bounce_buffer(multimodal_audio_ctx_t *ctx)
@@ -1566,6 +1478,7 @@ static esp_err_t prime_downstream_output_path(multimodal_audio_ctx_t *ctx)
static esp_err_t stop_downstream_idle_mute_task(multimodal_audio_ctx_t *ctx, int timeout_ms)
{
(void)timeout_ms;
if (timeout_ms < 0) {
return ESP_ERR_INVALID_ARG;
}
@@ -1574,34 +1487,22 @@ static esp_err_t stop_downstream_idle_mute_task(multimodal_audio_ctx_t *ctx, int
return ESP_OK;
}
TaskHandle_t task = audio_get_downstream_idle_mute_task(ctx);
if (task == NULL) {
audio_set_downstream_idle_mute_stop_requested(ctx, false);
esp_timer_handle_t timer = audio_get_downstream_idle_mute_timer(ctx);
if (timer == NULL) {
return ESP_OK;
}
audio_set_downstream_idle_mute_stop_requested(ctx, true);
xTaskNotifyGive(task);
if (timeout_ms == 0) {
return ESP_OK;
esp_err_t stop_err = esp_timer_stop(timer);
if (stop_err != ESP_OK && stop_err != ESP_ERR_INVALID_STATE) {
ESP_LOGW(TAG, "Downstream idle mute timer stop failed: %s", esp_err_to_name(stop_err));
}
int effective_timeout_ms = timeout_ms;
int waited_ms = 0;
while (audio_get_downstream_idle_mute_task(ctx) != NULL && waited_ms < effective_timeout_ms) {
vTaskDelay(pdMS_TO_TICKS(20));
waited_ms += 20;
esp_err_t delete_err = esp_timer_delete(timer);
if (delete_err != ESP_OK) {
ESP_LOGW(TAG, "Downstream idle mute timer delete failed: %s", esp_err_to_name(delete_err));
return delete_err;
}
esp_err_t result = ESP_OK;
task = audio_get_downstream_idle_mute_task(ctx);
if (task != NULL) {
ESP_LOGW(TAG, "Downstream idle mute task stop timeout, force delete");
delete_audio_task_with_caps(task);
audio_set_downstream_idle_mute_task(ctx, NULL);
result = ESP_ERR_TIMEOUT;
}
audio_set_downstream_idle_mute_stop_requested(ctx, false);
return result;
audio_set_downstream_idle_mute_timer(ctx, NULL);
return ESP_OK;
}
static void downstream_playback_task(void *arg)
@@ -173,16 +173,11 @@ static void seed_default_credentials(const char *ssid, const char *password)
return;
}
if (saved_count > 0U) {
ESP_LOGI(TAG,
"Configured Wi-Fi SSID \"%s\" overrides %u saved credential candidate(s)",
ssid,
(unsigned)saved_count);
manager.Clear();
}
manager.AddSsid(ssid, password != NULL ? password : "");
ESP_LOGI(TAG, "Configured Wi-Fi credentials for SSID \"%s\"", ssid);
ESP_LOGI(TAG,
"Ensured configured Wi-Fi credentials for SSID \"%s\" with %u previous candidate(s)",
ssid,
(unsigned)saved_count);
}
static int normalize_connect_timeout_ms(int timeout_ms)