fix(audio): prefer cloud timeout prompts with local fallback

This commit is contained in:
chenjintao
2026-09-23 15:36:09 +08:00
parent beadb79368
commit 1f55943c29
2 changed files with 149 additions and 69 deletions
@@ -24,7 +24,8 @@ static Mp3PlayConfigInfo mp3_configInfo;
static unsigned char mp3_player_status = 0;
QFILE *local_mp3_file_fd=NULL;
static int mp3_player_end_frame = 0;
static int mp3_player_end_frame = 0;
static int mp3_player_last_result = 0;
int current_sample_rate = 0;
static audio_track_handle track_hd;
@@ -278,9 +279,10 @@ u32 local_mp3_data_fetch(const char *uri, uint8_t *buffer, u32 length)
return read_bytes;
}
size_t url_mp3_data_fetch(const char *uri, uint8_t *buffer, size_t length)
{
int url_mp3_data_fetch(const char *uri, uint8_t *buffer, size_t length)
{
int resp_status = -1;
int result = -1;
uint32_t nw = length;
uint32_t page_pos = 0;
uint32_t content_length = 0;
@@ -353,7 +355,10 @@ size_t url_mp3_data_fetch(const char *uri, uint8_t *buffer, size_t length)
total_length += page_pos;
}
printf("end read:%d, %d\n", total_length, session->content_length);
printf("end read:%d, %d\n", total_length, session->content_length);
if(total_length == session->content_length){
result = 0;
}
__exit:
@@ -363,13 +368,13 @@ __exit:
session = NULL;
}
if(total_length<content_length){
total_length = 0;
return -1;
}
return 0;
}
if(result != 0 || total_length < content_length){
total_length = 0;
return -1;
}
return result;
}
struct mp3_decoder* aofei_mp3_decoder = NULL;
@@ -389,24 +394,45 @@ int aofei_mp3_player_init(void)
void aofei_mp3_player(char *file_name)
{
int ret = 0;
uint8_t *mp3_buff = malloc(100*1024);
memset(mp3_buff, 0, 100*1024);
//直接下载到一个100k的buffer
if(strstr(file_name, "http:")){//播放url
ret = url_mp3_data_fetch(file_name, mp3_buff, 100*1024);
int ret = 0;
uint8_t *mp3_buff = NULL;
mp3_player_last_result = -1;
if(file_name == NULL){
printf("mp3 player file name is null\r\n");
return;
}
mp3_buff = malloc(100*1024);
if(mp3_buff == NULL){
printf("mp3 player buffer malloc failed\r\n");
return;
}
memset(mp3_buff, 0, 100*1024);
//直接下载到一个100k的buffer
if(strncmp(file_name, "http://", strlen("http://")) == 0 ||
strncmp(file_name, "https://", strlen("https://")) == 0){//播放url
ret = url_mp3_data_fetch(file_name, mp3_buff, 100*1024);
}else if(strstr(file_name, "test.mp3")){//播放本地音频
total_length = test_data_size;
memcpy(mp3_buff, test_data, total_length);
}else{//播放本地音频
total_length = local_mp3_data_fetch(file_name, mp3_buff, 100*1024);
}
}else{//播放本地音频
total_length = local_mp3_data_fetch(file_name, mp3_buff, 100*1024);
}
if(ret < 0 || total_length == 0){
ret = -1;
goto __exit;
}
mp3_player_end_frame = 0;
if(aofei_mp3_player_init()==-1)return;
if(aofei_mp3_player_init()==-1){
ret = -1;
goto __exit;
}
if(ret>=0){
aofei_mp3_decoder->read_ptr = mp3_buff;
@@ -457,6 +483,7 @@ void aofei_mp3_player(char *file_name)
app_codec_pa_close();
}
__exit:
if(aofei_mp3_decoder!=NULL){
mp3_decoder_delete(aofei_mp3_decoder);
aofei_mp3_decoder = NULL;
@@ -477,10 +504,17 @@ void aofei_mp3_player(char *file_name)
mp3_buff = NULL;
}
total_length = 0;
mp3_player_end_frame = 0;
mp3_player_status = 0;
}
total_length = 0;
mp3_player_end_frame = 0;
mp3_player_status = 0;
mp3_player_last_result = ret;
}
/* 播放调用是同步的,队列线程可在返回后读取本次结果决定是否使用本地兜底。 */
int aofei_mp3_player_get_result(void)
{
return mp3_player_last_result;
}
@@ -30,8 +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 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;
@@ -65,17 +66,22 @@ 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 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);
int audio_packet_type = 0;
typedef struct ice_work_item_s
{
int type; //0-tts_out 1-session_continue 2-session_end 3-error
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;
@@ -198,16 +204,12 @@ static void remove_underscores(char *str) {
*dst = '\0'; // 添加字符串结束符
}
/*
* 将后台下发的任意角色对话超时音频 URL 改为 banban 角色的 HTTP 地址,
* 并在 tts_error00~tts_error09 中随机选择一条。
*/
static int randomize_tts_error_url(char *url, size_t url_size)
{
static uint32_t random_sequence = 0;
static unsigned int last_random_index = 10;
char *file_name;
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;
@@ -215,14 +217,6 @@ static int randomize_tts_error_url(char *url, size_t url_size)
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;
}
/*
* 某些设备上硬件随机接口可能持续返回 0,因此混合伪随机数、系统 tick
* 和递增序列;若仍与上一次相同,则向后偏移,避免连续重复播放。
@@ -244,9 +238,32 @@ static int randomize_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;
}
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)
{
@@ -383,7 +400,8 @@ static void onmessage_text(rws_socket socket, const char *text, const unsigned i
if(tts_playing==2) return;
add_file_to_play_player_queue(url_buff, 0);
/* 对话超时提示使用 type=3,云端播放失败时由播放线程切换到本地兜底。 */
add_file_to_play_player_queue(url_buff, is_tts_error_url == 1 ? 3 : 0);
}
}
@@ -967,9 +985,10 @@ int app_play_ota_tips_file(void)
return player_mq_couter > 0 ? 0 : -1;
}
void app_player_thread(void *arvg)
{
ice_work_item *player_item=NULL;
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);
@@ -979,12 +998,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);
app_set_app_operation(1);
if(player_mq_couter>0) player_mq_couter--;
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){
@@ -1191,9 +1227,19 @@ static void check_connect_thread_entry(void *parameter)
printf("tts_error_set_speech1\n");
vad_set_speech_timeout_flag(1);
app_play_tips_file(9);
//talkingq_ws_send_text("REQUEST_PROMPT_SOUND:tts_error");
//改为播放本地音频 听不清 请再说一遍
/*
* 后台没有返回任何音频 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