fix(audio): defer and coalesce role switch notices
This commit is contained in:
@@ -108,6 +108,7 @@ static char payload[MQTT_PAYLOAD_SIZE] = {0};
|
||||
|
||||
extern int fota_start;
|
||||
int app_play_ota_tips_file(void);
|
||||
int app_role_notice_handle_url(const char *url);
|
||||
int xiaoice_get_play_counter(void);
|
||||
|
||||
typedef struct {
|
||||
@@ -1510,7 +1511,9 @@ void handle_command(command_t *cmd)
|
||||
app_mqtt_publish(resp, strlen(resp), 0);
|
||||
free(resp);
|
||||
|
||||
add_file_to_play_player_queue(cmd->params.nfc.url, 0);
|
||||
if (!app_role_notice_handle_url(cmd->params.nfc.url)) {
|
||||
add_file_to_play_player_queue(cmd->params.nfc.url, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ extern ql_sem_t sender_sem;
|
||||
extern void conversation_no_speech(void);
|
||||
extern void conversation_record_begin(void);
|
||||
extern void conversation_cancel_wait(void);
|
||||
extern int app_role_notice_before_finish(void);
|
||||
|
||||
// 配置
|
||||
static int sample_rate = 16000; // FVAD 支持的采样率:8k/16k/32k/48k
|
||||
@@ -502,6 +503,7 @@ void vad_audio_process(void) {
|
||||
|
||||
case STATE_WAITING_COMMAND:
|
||||
if(vad_tts_playback_finished_status == 1) {
|
||||
if (app_role_notice_before_finish()) break;
|
||||
int leave_message_finished = vad_leave_message_flag != 0;
|
||||
printf("finished_status:%d, no_speech_timeout:%d\n", vad_tts_playback_finished_status, no_speech_timeout);
|
||||
set_state(STATE_IDLE);
|
||||
|
||||
@@ -65,6 +65,13 @@ static int round_response_received = 0;
|
||||
static unsigned int active_session_round = 0;
|
||||
static int active_session_valid = 0;
|
||||
static uint64_t startup_start_ms = 0;
|
||||
#define ROLE_NOTICE_TYPE 5
|
||||
#define ROLE_NOTICE_URL_SIZE 256
|
||||
static char role_notice_url[ROLE_NOTICE_URL_SIZE];
|
||||
static int role_notice_pending = 0;
|
||||
static int role_notice_playing = 0;
|
||||
static int role_notice_consumed = 0;
|
||||
static unsigned int role_notice_round = 0;
|
||||
|
||||
static void conversation_lock(void)
|
||||
{
|
||||
@@ -84,6 +91,9 @@ static void conversation_begin_round(void)
|
||||
round_response_received = 0;
|
||||
active_session_valid = 0;
|
||||
startup_start_ms = hal_os_up_time_ms();
|
||||
/* Accepted restart cancels the preceding round's deferred notice. */
|
||||
role_notice_pending = role_notice_playing = role_notice_consumed = 0;
|
||||
role_notice_url[0] = '\0';
|
||||
}
|
||||
|
||||
void conversation_record_begin(void)
|
||||
@@ -98,6 +108,8 @@ void conversation_cancel_wait(void)
|
||||
{
|
||||
conversation_lock();
|
||||
conversation_wait = WAIT_NONE;
|
||||
role_notice_pending = role_notice_playing = role_notice_consumed = 0;
|
||||
role_notice_url[0] = '\0';
|
||||
conversation_unlock();
|
||||
}
|
||||
|
||||
@@ -129,6 +141,7 @@ extern int aofei_mp3_player_get_result(void);
|
||||
extern int vad_leave_message_is_active(void);
|
||||
extern int vad_cancel_leave_message(void);
|
||||
extern void vad_reset_conversation_flags(void);
|
||||
extern system_state_t vad_audio_get_state(void);
|
||||
|
||||
void sendAuthentication(void);
|
||||
void vad_start_func(void);
|
||||
@@ -139,8 +152,8 @@ int audio_packet_type = 0;
|
||||
|
||||
typedef struct ice_work_item_s
|
||||
{
|
||||
int type; //0-tts_out 1-session_continue 2-session_end 3-云端超时提示(失败时播放本地兜底) 4-本地超时兜底
|
||||
unsigned int timeout_round; /* Timeout items (type 3/4) use this cancellation token. */
|
||||
int type; //0-tts_out 1-session_continue 2-session_end 3-云端超时提示(失败时播放本地兜底) 4-本地超时兜底 5-角色切换提示
|
||||
unsigned int timeout_round; /* Startup, timeout and role notices use this round token. */
|
||||
int error;
|
||||
int del_url;
|
||||
void *data;
|
||||
@@ -373,6 +386,99 @@ int add_file_to_play_player_queue(char *path, int type)
|
||||
}
|
||||
|
||||
|
||||
/* Only this resource is a role-change notice. Other NFC notices keep their
|
||||
* existing immediate queue path, including binding and card audio. */
|
||||
static int role_notice_is_url(const char *url)
|
||||
{
|
||||
const char *host, *path;
|
||||
const char resource[] = "/assets/audio/switch_role.mp3";
|
||||
size_t n = sizeof(resource) - 1;
|
||||
if (!url) return 0;
|
||||
host = strstr(url, "://");
|
||||
if (!host) return 0;
|
||||
path = strchr(host + 3, '/');
|
||||
return path && strncmp(path, resource, n) == 0 &&
|
||||
(path[n] == '\0' || path[n] == '?' || path[n] == '#');
|
||||
}
|
||||
|
||||
/* Caller holds conversation_mutex. A full queue/failed download must not
|
||||
* prevent the original conversation completion from proceeding. */
|
||||
static int role_notice_start_locked(void)
|
||||
{
|
||||
role_notice_pending = 0;
|
||||
role_notice_consumed = 1;
|
||||
role_notice_playing = 1;
|
||||
role_notice_round = conversation_round;
|
||||
if (add_file_to_play_player_queue(role_notice_url, ROLE_NOTICE_TYPE) != 0) {
|
||||
role_notice_playing = 0;
|
||||
printf("role notice queue failed:round=%u\n", conversation_round);
|
||||
return 0;
|
||||
}
|
||||
printf("role notice queued once:round=%u\n", conversation_round);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Called only after the normal VAD playback-finished signal, or while idle.
|
||||
* The original finished flag/no-speech flag stays untouched during the notice. */
|
||||
static int role_notice_poll_locked(int finishing)
|
||||
{
|
||||
if (fota_start || power_down_status || get_sleep_mode()) {
|
||||
role_notice_pending = role_notice_playing = 0;
|
||||
return 0;
|
||||
}
|
||||
if (role_notice_playing) return 1;
|
||||
if (!role_notice_pending) return 0;
|
||||
if (role_notice_round != conversation_round) {
|
||||
role_notice_pending = 0;
|
||||
return 0;
|
||||
}
|
||||
if (vad_audio_is_recording() || g_mic_working || shine_init ||
|
||||
timeout_action_busy || player_mq_couter > 0 || tts_playing != 0 ||
|
||||
conversation_wait != WAIT_NONE) return 1;
|
||||
if (!finishing && vad_audio_get_state() != STATE_IDLE) return 1;
|
||||
return role_notice_start_locked();
|
||||
}
|
||||
|
||||
int app_role_notice_handle_url(const char *url)
|
||||
{
|
||||
if (!role_notice_is_url(url)) return 0;
|
||||
conversation_lock();
|
||||
if (strlen(url) >= sizeof(role_notice_url)) {
|
||||
printf("role notice URL too long\n");
|
||||
} else if (role_notice_playing ||
|
||||
(role_notice_consumed && vad_audio_get_state() != STATE_IDLE)) {
|
||||
printf("role notice coalesced:round=%u\n", conversation_round);
|
||||
} else {
|
||||
/* Repeated commands before playback replace one pending slot. */
|
||||
snprintf(role_notice_url, sizeof(role_notice_url), "%s", url);
|
||||
role_notice_pending = 1;
|
||||
role_notice_round = conversation_round;
|
||||
printf("role notice pending:round=%u\n", conversation_round);
|
||||
role_notice_poll_locked(0);
|
||||
}
|
||||
conversation_unlock();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int app_role_notice_before_finish(void)
|
||||
{
|
||||
int wait;
|
||||
conversation_lock();
|
||||
wait = role_notice_poll_locked(1);
|
||||
conversation_unlock();
|
||||
return wait;
|
||||
}
|
||||
|
||||
static void role_notice_finished(unsigned int round, int result)
|
||||
{
|
||||
conversation_lock();
|
||||
if (role_notice_round == round && round == conversation_round) {
|
||||
role_notice_playing = 0;
|
||||
printf("role notice finished:round=%u result=%d\n", round, result);
|
||||
}
|
||||
conversation_unlock();
|
||||
}
|
||||
|
||||
//如果录音后 超过10s 还没有收到信息 提示本轮对话结束
|
||||
static void onmessage_text_locked(rws_socket socket, const char *text, const unsigned int len)
|
||||
{
|
||||
@@ -1104,6 +1210,9 @@ int app_play_tips_file(int index)
|
||||
|
||||
int app_play_ota_tips_file(void)
|
||||
{
|
||||
conversation_lock();
|
||||
role_notice_pending = role_notice_playing = role_notice_consumed = 0;
|
||||
conversation_unlock();
|
||||
char filename_buff[64] = {0};
|
||||
uint32_t timeout;
|
||||
|
||||
@@ -1170,8 +1279,10 @@ void app_player_thread(void *arvg)
|
||||
if(player_item!=NULL){
|
||||
int stale_timeout;
|
||||
conversation_lock();
|
||||
stale_timeout = (player_item->type == 2 || player_item->type == 3 || player_item->type == 4) &&
|
||||
player_item->timeout_round != conversation_round;
|
||||
stale_timeout = ((player_item->type == 2 || player_item->type == 3 || player_item->type == 4 ||
|
||||
player_item->type == ROLE_NOTICE_TYPE) &&
|
||||
player_item->timeout_round != conversation_round) ||
|
||||
(player_item->type == ROLE_NOTICE_TYPE && !role_notice_playing);
|
||||
conversation_unlock();
|
||||
if (stale_timeout) {
|
||||
if (player_mq_couter > 0) player_mq_couter--;
|
||||
@@ -1210,7 +1321,7 @@ void app_player_thread(void *arvg)
|
||||
|
||||
conversation_unlock();
|
||||
|
||||
if(player_mq_couter==0){
|
||||
if(player_mq_couter==0 && player_item->type != ROLE_NOTICE_TYPE){
|
||||
printf("player_mq_couter==0\r\n");
|
||||
|
||||
if(tts_play_status==2){
|
||||
@@ -1233,6 +1344,9 @@ void app_player_thread(void *arvg)
|
||||
vad_leave_message();
|
||||
}
|
||||
}
|
||||
if (player_item->type == ROLE_NOTICE_TYPE) {
|
||||
role_notice_finished(player_item->timeout_round, play_ret);
|
||||
}
|
||||
if (player_item->type == 2) {
|
||||
conversation_finish_startup_prompt(player_item->timeout_round, play_ret);
|
||||
}
|
||||
@@ -1507,6 +1621,9 @@ static void check_connect_thread_entry(void *parameter)
|
||||
#endif
|
||||
#if 1
|
||||
conversation_check_timeout();
|
||||
conversation_lock();
|
||||
role_notice_poll_locked(0);
|
||||
conversation_unlock();
|
||||
#endif
|
||||
|
||||
ql_rtos_task_sleep_ms(3000);
|
||||
|
||||
Reference in New Issue
Block a user