From 8b01debe4d4442e3dc19bd5afcfa2f501d8bb43a Mon Sep 17 00:00:00 2001 From: chenjintao Date: Tue, 22 Sep 2026 17:50:42 +0800 Subject: [PATCH] fix(audio): recover cleanly after barge-in --- .../threadx/interface/custom_app/hal_key.c | 3 ++ .../interface/custom_app/ws_talkingq.c | 40 ++++++++++++++----- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/ql-application/threadx/interface/custom_app/hal_key.c b/ql-application/threadx/interface/custom_app/hal_key.c index 0441fda..8eb650d 100644 --- a/ql-application/threadx/interface/custom_app/hal_key.c +++ b/ql-application/threadx/interface/custom_app/hal_key.c @@ -187,6 +187,9 @@ static void key_thread_entry(void *parameter) if(ql_rtos_get_systicks() - key_press_mic_time > KEY_LONG_PRESS_3S && power_down_status==0){ nfc_tx_click_count = 0; power_down_status = 1; + /* Shutdown audio must own the codec. Stop VAD and any + * interrupted TTS before queueing the power-off prompt. */ + stop_player_func(); app_play_tips_file(10); power_down_status = 2; //ql_rtos_task_sleep_s(3); diff --git a/ql-application/threadx/interface/custom_app/ws_talkingq.c b/ql-application/threadx/interface/custom_app/ws_talkingq.c index f0bc864..5046bab 100644 --- a/ql-application/threadx/interface/custom_app/ws_talkingq.c +++ b/ql-application/threadx/interface/custom_app/ws_talkingq.c @@ -1001,26 +1001,40 @@ void app_player_thread(void *arvg) int tts_play_interrupt_func(void) { + int playback_interrupted = 0; + //如果在vad状态,则直接返回 if(vad_audio_is_recording()||g_mic_working) return -1; g_mic_working = 1;//等待转为vad状态就清0 或者拾音超时 或者ws没有正常 - + + /* Remember whether this key press is interrupting TTS. tts_playing == 2 + * is only a cancellation signal for the old player; it must not leak into + * the next conversation, otherwise prompts and error audio are discarded. */ + playback_interrupted = (tts_playing != 0 || player_mq_couter > 0); xiaoice_close_all_audio(); talkingq_ws_connect(); - if(get_xiaoice_connected_status()!=2) { - g_mic_working = 0; - return -2; - } - - if(tts_playing==2){ + if(get_xiaoice_connected_status()!=2) { + /* Let the caller play its local network-error prompt. */ + tts_play_status = 0; + tts_playing = 0; + g_mic_working = 0; + return -2; + } + + if(playback_interrupted){ printf("vad_start_func0\n"); + /* The old player has finished consuming the cancellation state. */ + tts_play_status = 0; + tts_playing = 0; vad_start_func();//如果是打断就不播报 }else{ app_play_tips_file(18); } + + return 0; } void stop_player_func(void) @@ -1028,6 +1042,7 @@ void stop_player_func(void) vad_audio_stop_record(); xiaoice_close_all_audio(); + tts_play_status = 0; tts_playing = 0; } @@ -1194,9 +1209,16 @@ void xiaoice_close_all_audio(void) timeout = hal_os_up_time_ms(); - while(tts_play_status&&tts_playing!=2){ + /* The queue counter also includes the item currently owned by the + * player task. Wait for that item to observe tts_playing == 2 and + * finish cleanup before the cancellation state is reused/reset. */ + while(player_mq_couter>0){ ql_rtos_task_sleep_ms(20); - if(hal_os_up_time_ms()-timeout>10000) break; + if(hal_os_up_time_ms()-timeout>OTA_AUDIO_STOP_TIMEOUT_MS){ + printf("wait player stop timeout, counter:%d\r\n", + player_mq_couter); + break; + } } } #endif