fix(audio): isolate NFC leave-message sessions
This commit is contained in:
@@ -30,9 +30,9 @@
|
||||
|
||||
|
||||
#define PCM_FRAME_LENGTH 1152
|
||||
#define CLOUD_TTS_ERROR_URL_FORMAT \
|
||||
"http://101.35.224.118:8080/assets/roles/banban/tts_error/tts_error%02u.mp3"
|
||||
#define LOCAL_TTS_ERROR_PATH "U:/tts_error.mp3"
|
||||
#define CLOUD_TTS_ERROR_URL_FORMAT \
|
||||
"http://101.35.224.118:8080/assets/roles/banban/tts_error/tts_error%02u.mp3"
|
||||
#define LOCAL_TTS_ERROR_PATH "U:/tts_error.mp3"
|
||||
|
||||
static int g_sim_ready = 0;
|
||||
|
||||
@@ -50,14 +50,14 @@ static uint8_t sender_buf[PCM_FRAME_LENGTH]={0};
|
||||
static int16 mp3_buff[2*PCM_FRAME_LENGTH];
|
||||
static int16 *ppbuff=mp3_buff;
|
||||
|
||||
static int onmessage_status = -1;
|
||||
volatile int tts_playing = 0;
|
||||
unsigned char wss_connect_start = 0;
|
||||
static volatile int player_mq_couter = 0;
|
||||
/* Set while a barge-in prompt bridges the old and new sessions. The old
|
||||
* server response can still deliver URLs after its player queue was cleared. */
|
||||
static volatile int barge_in_transition = 0;
|
||||
static unsigned char audio_in_task_cancel = 0;
|
||||
static int onmessage_status = -1;
|
||||
volatile int tts_playing = 0;
|
||||
unsigned char wss_connect_start = 0;
|
||||
static volatile int player_mq_couter = 0;
|
||||
/* Set while a barge-in prompt bridges the old and new sessions. The old
|
||||
* server response can still deliver URLs after its player queue was cleared. */
|
||||
static volatile int barge_in_transition = 0;
|
||||
static volatile unsigned char audio_in_task_cancel = 0;
|
||||
|
||||
static unsigned char xiaoice_wss_connect_status = 0;
|
||||
static unsigned char wss_connect_counter = 0;
|
||||
@@ -66,22 +66,24 @@ int fota_start = 0;
|
||||
int mqtt_task_run_flag = 0;
|
||||
|
||||
extern int sub_topic_status;
|
||||
extern int mqtt_task_run_flag;
|
||||
static unsigned char shine_init = 0;
|
||||
extern int fisrt_net_start;
|
||||
extern u8 power_down_status;
|
||||
extern int aofei_mp3_player_get_result(void);
|
||||
|
||||
void sendAuthentication(void);
|
||||
void vad_start_func(void);
|
||||
void xiaoice_close_all_audio(void);
|
||||
extern int mqtt_task_run_flag;
|
||||
static unsigned char shine_init = 0;
|
||||
extern int fisrt_net_start;
|
||||
extern u8 power_down_status;
|
||||
extern int aofei_mp3_player_get_result(void);
|
||||
extern int vad_leave_message_is_active(void);
|
||||
extern int vad_cancel_leave_message(void);
|
||||
|
||||
void sendAuthentication(void);
|
||||
void vad_start_func(void);
|
||||
void xiaoice_close_all_audio(void);
|
||||
|
||||
int audio_packet_type = 0;
|
||||
|
||||
|
||||
typedef struct ice_work_item_s
|
||||
{
|
||||
int type; //0-tts_out 1-session_continue 2-session_end 3-云端超时提示(失败时播放本地兜底)
|
||||
typedef struct ice_work_item_s
|
||||
{
|
||||
int type; //0-tts_out 1-session_continue 2-session_end 3-云端超时提示(失败时播放本地兜底)
|
||||
int error;
|
||||
int del_url;
|
||||
void *data;
|
||||
@@ -117,11 +119,11 @@ static librws_app_t app = &_app;
|
||||
static ql_sem_t ws_connect_sem = NULL;
|
||||
extern int fota_start;
|
||||
|
||||
#define OTA_AUDIO_STOP_TIMEOUT_MS 3000
|
||||
#define OTA_AUDIO_STOP_POLL_MS 20
|
||||
|
||||
void xiaoice_clear_player_mq(void);
|
||||
|
||||
#define OTA_AUDIO_STOP_TIMEOUT_MS 3000
|
||||
#define OTA_AUDIO_STOP_POLL_MS 20
|
||||
|
||||
void xiaoice_clear_player_mq(void);
|
||||
|
||||
|
||||
static int tts_play_status = 0;//1播放中 2播放完成
|
||||
|
||||
@@ -204,12 +206,12 @@ static void remove_underscores(char *str) {
|
||||
*dst = '\0'; // 添加字符串结束符
|
||||
}
|
||||
|
||||
/* 生成 banban 角色的随机云端对话超时提示音 URL。 */
|
||||
static int build_random_tts_error_url(char *url, size_t url_size)
|
||||
{
|
||||
static uint32_t random_sequence = 0;
|
||||
static unsigned int last_random_index = 10;
|
||||
uint32_t random_value;
|
||||
/* 生成 banban 角色的随机云端对话超时提示音 URL。 */
|
||||
static int build_random_tts_error_url(char *url, size_t url_size)
|
||||
{
|
||||
static uint32_t random_sequence = 0;
|
||||
static unsigned int last_random_index = 10;
|
||||
uint32_t random_value;
|
||||
unsigned int random_index;
|
||||
int written;
|
||||
|
||||
@@ -238,32 +240,32 @@ static int build_random_tts_error_url(char *url, size_t url_size)
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("random cloud tts error index:%02u, url:%s\n", random_index, url);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 后台下发任意角色的对话超时 URL 时,统一替换成 banban 的随机云端资源。
|
||||
* 非对话超时 URL 保持不变。
|
||||
*/
|
||||
static int randomize_tts_error_url(char *url, size_t url_size)
|
||||
{
|
||||
char *file_name;
|
||||
|
||||
if(url == NULL || url_size == 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
file_name = strrchr(url, '/');
|
||||
file_name = (file_name == NULL) ? url : file_name + 1;
|
||||
|
||||
if(strncmp(file_name, "tts_error", strlen("tts_error")) != 0 &&
|
||||
strncmp(file_name, "tts_err", strlen("tts_err")) != 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
return build_random_tts_error_url(url, url_size);
|
||||
}
|
||||
printf("random cloud tts error index:%02u, url:%s\n", random_index, url);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 后台下发任意角色的对话超时 URL 时,统一替换成 banban 的随机云端资源。
|
||||
* 非对话超时 URL 保持不变。
|
||||
*/
|
||||
static int randomize_tts_error_url(char *url, size_t url_size)
|
||||
{
|
||||
char *file_name;
|
||||
|
||||
if(url == NULL || url_size == 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
file_name = strrchr(url, '/');
|
||||
file_name = (file_name == NULL) ? url : file_name + 1;
|
||||
|
||||
if(strncmp(file_name, "tts_error", strlen("tts_error")) != 0 &&
|
||||
strncmp(file_name, "tts_err", strlen("tts_err")) != 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
return build_random_tts_error_url(url, url_size);
|
||||
}
|
||||
|
||||
void add_file_to_play_player_queue(char *path, int type)
|
||||
{
|
||||
@@ -312,21 +314,21 @@ void add_file_to_play_player_queue(char *path, int type)
|
||||
|
||||
|
||||
//如果录音后 超过10s 还没有收到信息 提示本轮对话结束
|
||||
static void onmessage_text(rws_socket socket, const char *text, const unsigned int len)
|
||||
{
|
||||
if (fota_start == 1) {
|
||||
printf("ignore websocket audio during OTA\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* The new session id is generated only when recording starts. Until
|
||||
* then, every TTS message on this socket belongs to the interrupted
|
||||
* session and must not be allowed to refill the cleared player queue. */
|
||||
if (barge_in_transition) {
|
||||
printf("drop stale websocket message during barge-in\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
static void onmessage_text(rws_socket socket, const char *text, const unsigned int len)
|
||||
{
|
||||
if (fota_start == 1) {
|
||||
printf("ignore websocket audio during OTA\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* The new session id is generated only when recording starts. Until
|
||||
* then, every TTS message on this socket belongs to the interrupted
|
||||
* session and must not be allowed to refill the cleared player queue. */
|
||||
if (barge_in_transition) {
|
||||
printf("drop stale websocket message during barge-in\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// printf("message(txt), %d(byte): %s ", len, text);
|
||||
|
||||
char url_buff[128]={0x00};
|
||||
@@ -351,6 +353,7 @@ static void onmessage_text(rws_socket socket, const char *text, const unsigned i
|
||||
char *ret_str2 = NULL;
|
||||
size_t url_len = 0;
|
||||
int is_tts_error_url = 0;
|
||||
int is_message_ok_url = 0;
|
||||
if(ret_str1 == NULL){
|
||||
ret_str1 = strstr(text, "http://");
|
||||
}
|
||||
@@ -367,6 +370,14 @@ static void onmessage_text(rws_socket socket, const char *text, const unsigned i
|
||||
}
|
||||
memcpy(url_buff, ret_str1, url_len);
|
||||
url_buff[url_len] = '\0';
|
||||
is_message_ok_url = strstr(url_buff, "message_ok") != NULL;
|
||||
|
||||
/* A cancelled NFC transaction may still have a response in flight.
|
||||
* Never let that acknowledgement enter a normal conversation. */
|
||||
if(is_message_ok_url && !vad_leave_message_is_active()){
|
||||
printf("drop stale leave message ack\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 两个角色统一使用 banban 的 HTTP 随机超时提示音 */
|
||||
is_tts_error_url = randomize_tts_error_url(url_buff, sizeof(url_buff));
|
||||
@@ -391,7 +402,7 @@ static void onmessage_text(rws_socket socket, const char *text, const unsigned i
|
||||
tts_play_status = 2;
|
||||
}
|
||||
|
||||
if(is_tts_error_url == 1 || strstr(url_buff, "message_ok")!=NULL){
|
||||
if(is_tts_error_url == 1 || is_message_ok_url){
|
||||
printf("tts_error or message_ok\n");
|
||||
vad_set_speech_timeout_flag(1);
|
||||
}
|
||||
@@ -400,8 +411,8 @@ static void onmessage_text(rws_socket socket, const char *text, const unsigned i
|
||||
if(tts_playing==2) return;
|
||||
|
||||
|
||||
/* 对话超时提示使用 type=3,云端播放失败时由播放线程切换到本地兜底。 */
|
||||
add_file_to_play_player_queue(url_buff, is_tts_error_url == 1 ? 3 : 0);
|
||||
/* 对话超时提示使用 type=3,云端播放失败时由播放线程切换到本地兜底。 */
|
||||
add_file_to_play_player_queue(url_buff, is_tts_error_url == 1 ? 3 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -772,12 +783,12 @@ void generateSessionId(void)
|
||||
|
||||
|
||||
#if 1
|
||||
void sendStartPacket(void) {
|
||||
generateSessionId();
|
||||
/* sessionId now identifies the new conversation. Late URLs from the old
|
||||
* conversation will fail the existing session-id check below. */
|
||||
barge_in_transition = 0;
|
||||
generateDeviceId();
|
||||
void sendStartPacket(void) {
|
||||
generateSessionId();
|
||||
/* sessionId now identifies the new conversation. Late URLs from the old
|
||||
* conversation will fail the existing session-id check below. */
|
||||
barge_in_transition = 0;
|
||||
generateDeviceId();
|
||||
gSequenceNumber = 0;
|
||||
|
||||
AudioPacket startPacket = {0};
|
||||
@@ -894,23 +905,23 @@ void sendRecordingAudioPacket(AudioPacket *packet) {
|
||||
|
||||
extern const char *mp3_file[];
|
||||
|
||||
int app_play_tips_file(int index)
|
||||
{
|
||||
int file_valid_check = 0;
|
||||
int access_ret = 0;
|
||||
|
||||
printf("xiaoice_play_index:%d\n", index);
|
||||
|
||||
//正在录音过程中不允许播放
|
||||
// if(xiaoice_get_tts_play_status() || get_start_mic_flag()==1) return -1;
|
||||
if(power_down_status!=1){
|
||||
if(vad_audio_is_recording() || tts_playing!=0 || fota_start==1 || power_down_status==2 || get_sleep_mode()==1) {
|
||||
printf("tips blocked:index=%d vad=%d tts=%d fota=%d power=%d sleep=%d\r\n",
|
||||
index, vad_audio_is_recording(), tts_playing, fota_start,
|
||||
power_down_status, get_sleep_mode());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
int app_play_tips_file(int index)
|
||||
{
|
||||
int file_valid_check = 0;
|
||||
int access_ret = 0;
|
||||
|
||||
printf("xiaoice_play_index:%d\n", index);
|
||||
|
||||
//正在录音过程中不允许播放
|
||||
// if(xiaoice_get_tts_play_status() || get_start_mic_flag()==1) return -1;
|
||||
if(power_down_status!=1){
|
||||
if(vad_audio_is_recording() || tts_playing!=0 || fota_start==1 || power_down_status==2 || get_sleep_mode()==1) {
|
||||
printf("tips blocked:index=%d vad=%d tts=%d fota=%d power=%d sleep=%d\r\n",
|
||||
index, vad_audio_is_recording(), tts_playing, fota_start,
|
||||
power_down_status, get_sleep_mode());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
char filename_buff[64]={0x00};
|
||||
|
||||
@@ -919,18 +930,18 @@ int app_play_tips_file(int index)
|
||||
if(index==0) {
|
||||
file_valid_check = 0;
|
||||
}else{
|
||||
access_ret = ql_access(filename_buff, 0);
|
||||
if(access_ret==0){
|
||||
file_valid_check = 1;
|
||||
}else{
|
||||
printf("tips file missing:index=%d path=%s access=%d\r\n",
|
||||
index, filename_buff, access_ret);
|
||||
file_valid_check = 2;
|
||||
}
|
||||
access_ret = ql_access(filename_buff, 0);
|
||||
if(access_ret==0){
|
||||
file_valid_check = 1;
|
||||
}else{
|
||||
printf("tips file missing:index=%d path=%s access=%d\r\n",
|
||||
index, filename_buff, access_ret);
|
||||
file_valid_check = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(file_valid_check!=2){
|
||||
if(index==18 || index==19){
|
||||
if(index==18 || index==19){
|
||||
add_file_to_play_player_queue(filename_buff, 2);
|
||||
}else{
|
||||
add_file_to_play_player_queue(filename_buff, 0);
|
||||
@@ -942,53 +953,53 @@ int app_play_tips_file(int index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_play_ota_tips_file(void)
|
||||
{
|
||||
char filename_buff[64] = {0};
|
||||
uint32_t timeout;
|
||||
|
||||
/* OTA owns the audio path from this point on. Stop the active conversation
|
||||
* before queuing the prompt, otherwise recording/TTS rejects or masks it. */
|
||||
if (vad_audio_is_recording()) {
|
||||
vad_audio_stop_record();
|
||||
}
|
||||
|
||||
if (get_xiaoice_connected_status() == 2) {
|
||||
talkingq_ws_disconnect();
|
||||
}
|
||||
|
||||
tts_playing = 2;
|
||||
xiaoice_clear_player_mq();
|
||||
|
||||
timeout = hal_os_up_time_ms();
|
||||
while (player_mq_couter > 0) {
|
||||
ql_rtos_task_sleep_ms(OTA_AUDIO_STOP_POLL_MS);
|
||||
if (hal_os_up_time_ms() - timeout > OTA_AUDIO_STOP_TIMEOUT_MS) {
|
||||
printf("OTA wait previous audio timeout, counter:%d\r\n",
|
||||
player_mq_couter);
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
||||
tts_play_status = 0;
|
||||
tts_playing = 0;
|
||||
|
||||
/* Normal prompts are blocked while fota_start is set. Queue the dedicated
|
||||
* OTA prompt directly after the old conversation has fully stopped. */
|
||||
snprintf(filename_buff, sizeof(filename_buff), "U:/%s", mp3_file[3]);
|
||||
printf("xiaoice_play_index:3\n");
|
||||
if (ql_access(filename_buff, 0) != 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
add_file_to_play_player_queue(filename_buff, 0);
|
||||
return player_mq_couter > 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
void app_player_thread(void *arvg)
|
||||
{
|
||||
ice_work_item *player_item=NULL;
|
||||
int play_ret;
|
||||
int app_play_ota_tips_file(void)
|
||||
{
|
||||
char filename_buff[64] = {0};
|
||||
uint32_t timeout;
|
||||
|
||||
/* OTA owns the audio path from this point on. Stop the active conversation
|
||||
* before queuing the prompt, otherwise recording/TTS rejects or masks it. */
|
||||
if (vad_audio_is_recording()) {
|
||||
vad_audio_stop_record();
|
||||
}
|
||||
|
||||
if (get_xiaoice_connected_status() == 2) {
|
||||
talkingq_ws_disconnect();
|
||||
}
|
||||
|
||||
tts_playing = 2;
|
||||
xiaoice_clear_player_mq();
|
||||
|
||||
timeout = hal_os_up_time_ms();
|
||||
while (player_mq_couter > 0) {
|
||||
ql_rtos_task_sleep_ms(OTA_AUDIO_STOP_POLL_MS);
|
||||
if (hal_os_up_time_ms() - timeout > OTA_AUDIO_STOP_TIMEOUT_MS) {
|
||||
printf("OTA wait previous audio timeout, counter:%d\r\n",
|
||||
player_mq_couter);
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
||||
tts_play_status = 0;
|
||||
tts_playing = 0;
|
||||
|
||||
/* Normal prompts are blocked while fota_start is set. Queue the dedicated
|
||||
* OTA prompt directly after the old conversation has fully stopped. */
|
||||
snprintf(filename_buff, sizeof(filename_buff), "U:/%s", mp3_file[3]);
|
||||
printf("xiaoice_play_index:3\n");
|
||||
if (ql_access(filename_buff, 0) != 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
add_file_to_play_player_queue(filename_buff, 0);
|
||||
return player_mq_couter > 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
void app_player_thread(void *arvg)
|
||||
{
|
||||
ice_work_item *player_item=NULL;
|
||||
int play_ret;
|
||||
|
||||
while(1){
|
||||
ql_rtos_queue_wait(player_queue, (u8*)(&player_item), sizeof(ice_work_item *), 0xFFFFFFFF);
|
||||
@@ -998,29 +1009,29 @@ void app_player_thread(void *arvg)
|
||||
if(player_item->data){
|
||||
// printf("xiaoice player! %s\n",player_item->data);
|
||||
|
||||
app_set_app_operation(1);
|
||||
aofei_mp3_player(player_item->data);
|
||||
play_ret = aofei_mp3_player_get_result();
|
||||
app_set_app_operation(1);
|
||||
|
||||
if(player_mq_couter>0) player_mq_couter--;
|
||||
|
||||
/*
|
||||
* type=3 只用于对话超时提示。云端连接、HTTP、读取或播放器初始化
|
||||
* 失败时才排入本地兜底;如果用户已经开始下一轮录音,则丢弃旧提示。
|
||||
*/
|
||||
if(play_ret != 0 && player_item->type == 3 &&
|
||||
!vad_audio_is_recording() && tts_playing_ret() != 2){
|
||||
printf("cloud tts error play failed:%d, fallback:%s\r\n",
|
||||
play_ret, LOCAL_TTS_ERROR_PATH);
|
||||
if(ql_access(LOCAL_TTS_ERROR_PATH, 0) == 0){
|
||||
add_file_to_play_player_queue(LOCAL_TTS_ERROR_PATH, 0);
|
||||
}else{
|
||||
printf("local tts error fallback missing:%s\r\n", LOCAL_TTS_ERROR_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
if(player_mq_couter==0){
|
||||
app_set_app_operation(1);
|
||||
aofei_mp3_player(player_item->data);
|
||||
play_ret = aofei_mp3_player_get_result();
|
||||
app_set_app_operation(1);
|
||||
|
||||
if(player_mq_couter>0) player_mq_couter--;
|
||||
|
||||
/*
|
||||
* type=3 只用于对话超时提示。云端连接、HTTP、读取或播放器初始化
|
||||
* 失败时才排入本地兜底;如果用户已经开始下一轮录音,则丢弃旧提示。
|
||||
*/
|
||||
if(play_ret != 0 && player_item->type == 3 &&
|
||||
!vad_audio_is_recording() && tts_playing_ret() != 2){
|
||||
printf("cloud tts error play failed:%d, fallback:%s\r\n",
|
||||
play_ret, LOCAL_TTS_ERROR_PATH);
|
||||
if(ql_access(LOCAL_TTS_ERROR_PATH, 0) == 0){
|
||||
add_file_to_play_player_queue(LOCAL_TTS_ERROR_PATH, 0);
|
||||
}else{
|
||||
printf("local tts error fallback missing:%s\r\n", LOCAL_TTS_ERROR_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
if(player_mq_couter==0){
|
||||
printf("player_mq_couter==0\r\n");
|
||||
|
||||
if(tts_play_status==2){
|
||||
@@ -1060,46 +1071,69 @@ void app_player_thread(void *arvg)
|
||||
|
||||
int tts_play_interrupt_func(void)
|
||||
{
|
||||
int playback_interrupted = 0;
|
||||
|
||||
int playback_interrupted = 0;
|
||||
int leave_message_cancelled = 0;
|
||||
|
||||
/* A short press explicitly starts a normal conversation. Cancel an NFC
|
||||
* leave-message before the generic "already recording" guard, otherwise a
|
||||
* pending/recording leave-message can leak packetType=4 into this session. */
|
||||
leave_message_cancelled = vad_cancel_leave_message();
|
||||
if(leave_message_cancelled){
|
||||
uint64_t cancel_start;
|
||||
|
||||
/* Let the sender task discard buffered PCM and its encoder without
|
||||
* emitting END. Only then close the old leave-message socket. */
|
||||
audio_in_task_cancel = 1;
|
||||
ql_rtos_semaphore_release(sender_sem);
|
||||
cancel_start = hal_os_up_time_ms();
|
||||
while(audio_in_task_cancel &&
|
||||
hal_os_up_time_ms() - cancel_start < OTA_AUDIO_STOP_TIMEOUT_MS){
|
||||
ql_rtos_task_sleep_ms(20);
|
||||
}
|
||||
if(audio_in_task_cancel){
|
||||
printf("wait leave message sender cancel timeout\r\n");
|
||||
}
|
||||
talkingq_ws_disconnect();
|
||||
}
|
||||
|
||||
//如果在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);
|
||||
barge_in_transition = playback_interrupted;
|
||||
xiaoice_close_all_audio();
|
||||
|
||||
/* 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);
|
||||
barge_in_transition = playback_interrupted;
|
||||
xiaoice_close_all_audio();
|
||||
|
||||
talkingq_ws_connect();
|
||||
|
||||
if(get_xiaoice_connected_status()!=2) {
|
||||
/* Let the caller play its local network-error prompt. */
|
||||
tts_play_status = 0;
|
||||
tts_playing = 0;
|
||||
barge_in_transition = 0;
|
||||
g_mic_working = 0;
|
||||
return -2;
|
||||
}
|
||||
|
||||
if(playback_interrupted){
|
||||
printf("barge_in_prompt\n");
|
||||
/* The old player has finished consuming the cancellation state. */
|
||||
tts_play_status = 0;
|
||||
tts_playing = 0;
|
||||
/* Use the same local-prompt flow as ai_active_zh.mp3. Queue type 2
|
||||
* starts VAD after playback; fall back to VAD if the file is absent. */
|
||||
if(app_play_tips_file(19) != 0){
|
||||
vad_start_func();
|
||||
}
|
||||
if(get_xiaoice_connected_status()!=2) {
|
||||
/* Let the caller play its local network-error prompt. */
|
||||
tts_play_status = 0;
|
||||
tts_playing = 0;
|
||||
barge_in_transition = 0;
|
||||
g_mic_working = 0;
|
||||
return -2;
|
||||
}
|
||||
|
||||
if(playback_interrupted){
|
||||
printf("barge_in_prompt\n");
|
||||
/* The old player has finished consuming the cancellation state. */
|
||||
tts_play_status = 0;
|
||||
tts_playing = 0;
|
||||
/* Use the same local-prompt flow as ai_active_zh.mp3. Queue type 2
|
||||
* starts VAD after playback; fall back to VAD if the file is absent. */
|
||||
if(app_play_tips_file(19) != 0){
|
||||
vad_start_func();
|
||||
}
|
||||
}else{
|
||||
app_play_tips_file(18);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stop_player_func(void)
|
||||
@@ -1107,7 +1141,7 @@ void stop_player_func(void)
|
||||
vad_audio_stop_record();
|
||||
xiaoice_close_all_audio();
|
||||
|
||||
tts_play_status = 0;
|
||||
tts_play_status = 0;
|
||||
tts_playing = 0;
|
||||
}
|
||||
|
||||
@@ -1227,19 +1261,19 @@ static void check_connect_thread_entry(void *parameter)
|
||||
printf("tts_error_set_speech1\n");
|
||||
vad_set_speech_timeout_flag(1);
|
||||
|
||||
/*
|
||||
* 后台没有返回任何音频 URL 时,也先由设备生成随机云端提示音。
|
||||
* type=3 会在 HTTP 下载或播放初始化失败时自动切换到本地音频。
|
||||
*/
|
||||
{
|
||||
char cloud_tts_error_url[128] = {0};
|
||||
if(build_random_tts_error_url(cloud_tts_error_url,
|
||||
sizeof(cloud_tts_error_url)) == 1){
|
||||
add_file_to_play_player_queue(cloud_tts_error_url, 3);
|
||||
}else{
|
||||
app_play_tips_file(9);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 后台没有返回任何音频 URL 时,也先由设备生成随机云端提示音。
|
||||
* type=3 会在 HTTP 下载或播放初始化失败时自动切换到本地音频。
|
||||
*/
|
||||
{
|
||||
char cloud_tts_error_url[128] = {0};
|
||||
if(build_random_tts_error_url(cloud_tts_error_url,
|
||||
sizeof(cloud_tts_error_url)) == 1){
|
||||
add_file_to_play_player_queue(cloud_tts_error_url, 3);
|
||||
}else{
|
||||
app_play_tips_file(9);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1258,7 +1292,7 @@ void xiaoice_clear_player_mq(void)
|
||||
free(player_item->data);
|
||||
player_item->data = NULL;
|
||||
}
|
||||
if(player_mq_couter>0) player_mq_couter--;
|
||||
if(player_mq_couter>0) player_mq_couter--;
|
||||
free(player_item);
|
||||
player_item = NULL;
|
||||
}
|
||||
@@ -1284,16 +1318,16 @@ void xiaoice_close_all_audio(void)
|
||||
|
||||
timeout = hal_os_up_time_ms();
|
||||
|
||||
/* 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){
|
||||
/* 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>OTA_AUDIO_STOP_TIMEOUT_MS){
|
||||
printf("wait player stop timeout, counter:%d\r\n",
|
||||
player_mq_couter);
|
||||
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
|
||||
@@ -1313,6 +1347,23 @@ void app_sender_thread(void *arvg)
|
||||
ql_rtos_semaphore_wait(sender_sem, 0xFFFFFFFF);
|
||||
|
||||
sender_loop:
|
||||
if(audio_in_task_cancel){
|
||||
left = rb_get_space_used(ring_sender);
|
||||
while(left > 0){
|
||||
int discard_len = left > PCM_FRAME_LENGTH ? PCM_FRAME_LENGTH : left;
|
||||
hal_os_rb_read(ring_sender, sender_buf, discard_len, 0);
|
||||
left = rb_get_space_used(ring_sender);
|
||||
}
|
||||
if(shine_init != 0){
|
||||
shine_close(sh_shine);
|
||||
sh_shine = NULL;
|
||||
shine_init = 0;
|
||||
}
|
||||
audio_packet_type = 0;
|
||||
audio_in_task_cancel = 0;
|
||||
printf("leave message sender cancelled\r\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!app_get_data_call_net_status()) continue;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user