【求助】T5 tuya_os_sdk3.13.3播放提示音或停止时卡死
Re: 【求助】T5 tuya_os_sdk3.13.3播放提示音或停止时卡死
有完整的日志么?上电开始的。目前代码如何使用player的完整逻辑看不到,无法判断是否触发了未知场景。
wukong player是单线程的,因此如果有多线程访问,可能触发未测试到的问题。
Re: 【求助】T5 tuya_os_sdk3.13.3播放提示音或停止时卡死
测试比较久才能复现问题,基本都是需要挂机一晚上,第二天唤醒就会出bug,我们是10pcs样品一起测试,出问题可能就一两台,日志没有办法记录那么多。
产品确实是多线程在操作player,但是都有加锁,除非是在一些wokong的代码里面又异步操作了player。
而且现在明显队列满了,处理消息的线程卡死了,这个才是根本原因,处理消息的线程跟我们变更player的状态没有关系,为什么会卡死,我深挖底层代码,在tkl_audio.c里面发现了一段可能的死循环:
Code: Select all
OPERATE_RET tkl_ao_put_frame(INT32_T card, TKL_AO_CHN_E chn, VOID *handle,
TKL_AUDIO_FRAME_INFO_T *pframe)
{
OPERATE_RET ret;
if (pframe == NULL) {
return OPRT_INVALID_PARM;
}
if (!s_audio_init.audio_init || !s_audio_init.audio_start) {
return OPRT_RESOURCE_NOT_READY;
}
int offset = 0; // 偏移量
int remaining_size = pframe->used_size; // 剩余数据大小
int chunk_size = 0;
if (remaining_size < 0) {
return -1;
}
int spk_ringbuf_size = FRAME_SIZE_PER_20MS(s_audio_mic.samp_rate) * DRIVER_SPEAK_FIFO_FRAME_NUM;
//
// bk_printf("rate: %d, spk_ringbuf_size: %d, output size:%d\r\n",
// s_audio_mic.samp_rate, spk_ringbuf_size, remaining_size);
// 分段调用 bk_aud_intf_write_spk_data
while (remaining_size > 0) {
// 计算当前要写入的数据大小
chunk_size = (remaining_size > spk_ringbuf_size) ? spk_ringbuf_size : remaining_size;
write_spk_retry:
ret = bk_voice_write_frame_data(g_voice_write_handle, (char *)(pframe->pbuf + offset), chunk_size);
// ret = bk_voice_write_spk_data(g_voice_handle, (char *)(pframe->pbuf + offset), chunk_size);
if (ret == 0) {
tkl_system_sleep(20);
goto write_spk_retry;
}
if (ret < 0) {
os_printf("audio intf spk semaphore wait fail, ret:%d \r\n", ret);
return ret;
}
// 更新偏移量和剩余大小
offset += chunk_size;
remaining_size -= chunk_size;
}
return OPRT_OK;
}
这里有个goto write_spk_retry;是否有风险?
以下是产品当前使用player的完整代码。
Code: Select all
#include "hly_ai.h"
#include "wukong_ai_agent.h"
#include "tal_memory.h"
#include "tal_log.h"
#include "wukong_kws.h"
#include "tal_sw_timer.h"
#include "wukong_audio_player.h"
#include "wukong_audio_input.h"
#include "wukong_audio_aec_vad.h"
#include "skill_emotion.h"
#include <string.h>
#include "ty_cJSON.h"
#include "hly_fs.h"
#include "tal_mutex.h"
#include "base_event.h"
#include "base_event_info.h"
#include "tal_semaphore.h"
#include "tal_queue.h"
#define AI_AGENT_SCODE_DEFAULT ""
#define AI_AUDIO_SLICE_TIME 50
#define AI_TTS_TIME 10
typedef struct
{
const char* name;
HLY_AI_EMOJI_E emoji;
}_HLY_AI_EMOJI_T;
STATIC hly_ai_config_t* _hly_ai_config;//ai配置
STATIC hly_ai_stat_e _ai_stat=AI_STAT_INIT;//ai状态
STATIC BOOL_T ai_start=FALSE;
STATIC TIMER_ID _re_idel_timer;
STATIC BOOL_T wake_up_flag=false;
STATIC BOOL_T paly_alart=false;
STATIC BOOL_T free_chat=true;
STATIC MUTEX_HANDLE _ai_mutex;
STATIC MUTEX_HANDLE _timer_mutex;
STATIC MUTEX_HANDLE _alert_mutex;
STATIC THREAD_HANDLE _hly_ai_sem_task;
STATIC SEM_HANDLE _hly_ai_sem;
STATIC THREAD_HANDLE _hly_ai_stat_task;
STATIC QUEUE_HANDLE _hly_ai_stat_queue;
STATIC THREAD_HANDLE _hly_ai_debug_task;
STATIC uint16_t debug_step_a=0;
STATIC uint16_t debug_step_b=0;
STATIC uint16_t debug_step_c=0;
STATIC uint16_t debug_step_d=0;
STATIC uint16_t debug_step_e=0;
STATIC _HLY_AI_EMOJI_T _ai_emoji_list[]={
{"NEUTRAL",HLY_AI_EMOJI_NEUTRAL},
{"HAPPY",HLY_AI_EMOJI_HAPPY},
{"LAUGHING",HLY_AI_EMOJI_LAUGHING},
{"FUNNY",HLY_AI_EMOJI_FUNNY},
{"SAD",HLY_AI_EMOJI_SAD},
{"ANGRY",HLY_AI_EMOJI_ANGRY},
{"CRYING",HLY_AI_EMOJI_CRYING},
{"LOVING",HLY_AI_EMOJI_LOVING},
{"EMBARRASSED",HLY_AI_EMOJI_EMBARRASSED},
{"SURPRISE",HLY_AI_EMOJI_SURPRISE},
{"SHOCKED",HLY_AI_EMOJI_SHOCKED},
{"THINKING",HLY_AI_EMOJI_THINKING},
{"WINKING",HLY_AI_EMOJI_WINKING},
{"COOL",HLY_AI_EMOJI_COOL},
{"RELAXED",HLY_AI_EMOJI_RELAXED},
{"DELICIOUS",HLY_AI_EMOJI_DELICIOUS},
{"KISSY",HLY_AI_EMOJI_KISSY},
{"CONFIDENT",HLY_AI_EMOJI_CONFIDENT},
{"SLEEPY",HLY_AI_EMOJI_SLEEPY},
{"SILLY",HLY_AI_EMOJI_SILLY},
{"CONFUSED",HLY_AI_EMOJI_CONFUSED},
};
/** 停止恢复待机定时器*/
STATIC VOID _hly_ai_re_idel_stop()
{
if(tal_sw_timer_is_running(_re_idel_timer))
{
tal_sw_timer_stop(_re_idel_timer);
}
}
/** 启动恢复待机定时器*/
STATIC VOID _hly_ai_re_idel_start(uint16_t time_s)
{
tal_mutex_lock(_timer_mutex);
TAL_PR_DEBUG("======ai re idel time:%d======",time_s);
_hly_ai_re_idel_stop();
if(time_s==0)
{
tal_mutex_unlock(_timer_mutex);
return;
}
tal_sw_timer_start(_re_idel_timer,time_s*1000,TAL_TIMER_ONCE);
tal_mutex_unlock(_timer_mutex);
}
STATIC VOID _hly_ai_stat_task_cb(PVOID_T args)
{
hly_ai_stat_e stat;
while(1)
{
debug_step_a=1;
tal_queue_fetch(_hly_ai_stat_queue, &stat, SEM_WAIT_FOREVER);
debug_step_a=2;
tal_mutex_lock(_ai_mutex);
debug_step_a=3;
if (_ai_stat != stat)
{
TAL_PR_DEBUG("=============ai stat:%d=============", stat);
_ai_stat = stat;
debug_step_a=4;
ty_publish_event(AI_STAT_EVENT, &_ai_stat);
}
debug_step_a=5;
if (_ai_stat == AI_STAT_IDEL)
{
debug_step_a=6;
_hly_ai_re_idel_start(0);
wukong_vad_set_threshold(WUKONG_AUDIO_VAD_LOW);
wake_up_flag = false;
wukong_audio_input_wakeup_set(FALSE);
debug_step_a=7;
}
else
{
debug_step_a=8;
wukong_audio_input_wakeup_set(true);
debug_step_a=9;
}
debug_step_a=10;
if (_ai_stat == AI_STAT_LISTEN)
{
debug_step_a=11;
_hly_ai_re_idel_start(_hly_ai_config->wake_time);
wukong_vad_set_threshold(WUKONG_AUDIO_VAD_LOW);
debug_step_a=12;
}
else if(_ai_stat==AI_STAT_THINK)
{
debug_step_a=13;
_hly_ai_re_idel_start(_hly_ai_config->wake_time);
debug_step_a=14;
}
else if (_ai_stat == AI_STAT_SPEAK)
{
debug_step_a=15;
_hly_ai_re_idel_start(AI_TTS_TIME);
wukong_vad_set_threshold(WUKONG_AUDIO_VAD_HIGH);
debug_step_a=16;
}
debug_step_a=17;
tal_mutex_unlock(_ai_mutex);
debug_step_a=18;
}
}
STATIC VOID _hly_ai_set_stat(hly_ai_stat_e stat)
{
hly_ai_stat_e msg;
msg = stat;
tal_queue_post(_hly_ai_stat_queue, &msg, 10);
}
/**ai表情 */
// STATIC VOID _hly_ai_skill_emoji(void* data)
// {
// WUKONG_AI_EMO_T *emo = (WUKONG_AI_EMO_T *)data;
// TAL_PR_NOTICE("======ai emoji:%s,%s", emo->name,emo->emoji);
// int count = sizeof(_ai_emoji_list)/sizeof(_HLY_AI_EMOJI_T);
// for(int i = 0;i<count;i++)
// {
// if(strcasecmp(emo->name,_ai_emoji_list[i].name)==0)
// {
// _hly_ai_config->hly_ai_emoji_cb(_ai_emoji_list[i].emoji);
// return;
// }
// _hly_ai_config->hly_ai_emoji_cb(HLY_AI_EMOJI_UNKNOWN);
// }
// }
/**ai技能 */
STATIC int _hly_ai_skill(ty_cJSON* data)
{
// ty_cJSON *node = NULL;
// CHAR_T *code = NULL;
// ty_cJSON *skillContent = NULL;
// ty_cJSON *emotions = NULL;
// ty_cJSON *emo = NULL;
// node = ty_cJSON_GetObjectItem(data, "code");
// code = ty_cJSON_GetStringValue(node);
// if(code!=NULL && strcmp(code,"emo")==0)
// {
// TAL_PR_DEBUG("=====emo=======");
// skillContent=ty_cJSON_GetObjectItem(data,"skillContent");
// if(skillContent!=NULL)
// {
// TAL_PR_DEBUG("skillContent:%s",ty_cJSON_Print(skillContent));
// emotions=ty_cJSON_GetObjectItem(skillContent,"emotion");
// if(emotions!=NULL)
// {
// TAL_PR_DEBUG("emotions:%s",ty_cJSON_Print(emotions));
// emo=ty_cJSON_GetArrayItem(emotions,0);
// if(emo!=NULL)
// {
// TAL_PR_DEBUG("emo:%s",ty_cJSON_Print(emo));
// code = ty_cJSON_GetStringValue(emo);
// if(code!=NULL)
// {
// TAL_PR_DEBUG("emo str:%s",code);
// }
// }
// }
// }
// }
// char* str=ty_cJSON_PrintUnformatted(data);
// if(strstr(str,"101"))
// {
// wake_up_flag=FALSE;
// return 0;
// }
return 0;
}
/**ai事件 */
STATIC VOID _hly_ai_event(WUKONG_AI_EVENT_T *event)
{
// wukong_ai_handle_event(event, 0);
TUYA_CHECK_NULL_RETURN(event, OPRT_INVALID_PARM);
TAL_PR_DEBUG("======wukong ai event type: %d", event->type);
switch (event->type)
{
case WUKONG_AI_EVENT_ASR_EMPTY:
case WUKONG_AI_EVENT_ASR_ERROR:
{
tal_mutex_lock(_ai_mutex);
debug_step_d=9;
if (_ai_stat == AI_STAT_THINK)
{
_hly_ai_set_stat(AI_STAT_LISTEN);
}
tal_mutex_unlock(_ai_mutex);
debug_step_d=10;
}
break;
case WUKONG_AI_EVENT_ASR_OK:
{
}
break;
case WUKONG_AI_EVENT_TTS_PRE:
{
_hly_ai_set_stat(AI_STAT_SPEAK);
}
break;
case WUKONG_AI_EVENT_TTS_START:
case WUKONG_AI_EVENT_TTS_DATA:
{
_hly_ai_re_idel_start(AI_TTS_TIME);
}
break;
case WUKONG_AI_EVENT_TTS_STOP:
case WUKONG_AI_EVENT_TTS_ABORT:
case WUKONG_AI_EVENT_TTS_ERROR:
{
_hly_ai_re_idel_start(AI_TTS_TIME);
}
break;
case WUKONG_AI_EVENT_VAD_TIMEOUT:
{
}
break;
case WUKONG_AI_EVENT_TEXT_STREAM_START:
case WUKONG_AI_EVENT_TEXT_STREAM_DATA:
case WUKONG_AI_EVENT_TEXT_STREAM_STOP:
case WUKONG_AI_EVENT_TEXT_STREAM_ABORT:
{
// __ai_wakeup_text_stream(event->type, event->data);
}
break;
case WUKONG_AI_EVENT_EMOTION:
case WUKONG_AI_EVENT_LLM_EMOTION:
{
// _hly_ai_skill_emoji(event->data);
// __ai_wakeup_emition(event->type, event->data);
}
break;
case WUKONG_AI_EVENT_SKILL:
{
_hly_ai_skill(event->data);
}
break;
case WUKONG_AI_EVENT_CHAT_BREAK:
case WUKONG_AI_EVENT_SERVER_VAD:
{
}
break;
case WUKONG_AI_EVENT_EXIT:
_hly_ai_set_stat(AI_STAT_IDEL);
break;
case WUKONG_AI_EVENT_PLAY_CTL_PLAY:
case WUKONG_AI_EVENT_PLAY_CTL_RESUME:
{
wukong_audio_player_set_resume(TRUE);
}
break;
case WUKONG_AI_EVENT_PLAY_CTL_PAUSE:
{
wukong_audio_player_stop(AI_PLAYER_BG);
}
break;
case WUKONG_AI_EVENT_PLAY_CTL_REPLAY:
{
wukong_audio_player_set_replay(TRUE);
}
break;
case WUKONG_AI_EVENT_PLAY_CTL_END:
case WUKONG_AI_EVENT_PLAY_END:
{
tal_mutex_lock(_ai_mutex);
debug_step_d=11;
if(paly_alart)
{
paly_alart=FALSE;
}
if(wake_up_flag)
{
_hly_ai_set_stat(AI_STAT_LISTEN);
}
else
{
_hly_ai_set_stat(AI_STAT_IDEL);
}
tal_mutex_unlock(_ai_mutex);
debug_step_d=12;
}
break;
case WUKONG_AI_EVENT_PLAY_ALERT:
{
//wukong_audio_player_alert((TY_AI_TOY_ALERT_TYPE_E)event->data, TRUE);
}
break;
case WUKONG_AI_EVENT_PLAY_CTL_PREV:
case WUKONG_AI_EVENT_PLAY_CTL_NEXT:
case WUKONG_AI_EVENT_PLAY_CTL_SEQUENTIAL:
case WUKONG_AI_EVENT_PLAY_CTL_SEQUENTIAL_LOOP:
case WUKONG_AI_EVENT_PLAY_CTL_SINGLE_LOOP:
{
}
break;
default:
break;
}
return OPRT_OK;
}
/** 麦克风输入*/
STATIC INT_T _hly_ai_mic_data(UINT8_T *data, UINT16_T datalen)
{
OPERATE_RET rt = OPRT_OK;
UINT64_T pts = 0;
UINT64_T timestamp = 0;
TAL_PR_NOTICE("hly ai -> recv wukong mic data: %d", datalen);
tal_mutex_lock(_ai_mutex);
if (!tuya_ai_agent_is_ready()) {
TAL_PR_DEBUG("ai agent is not ready, ignore audio input");
tal_mutex_unlock(_ai_mutex);
return OPRT_OK;
}
if((_ai_stat == AI_STAT_SPEAK) && (!free_chat))
{
TAL_PR_DEBUG("========off free speak!!========");
tal_mutex_unlock(_ai_mutex);
return OPRT_OK;
}
tal_mutex_unlock(_ai_mutex);
timestamp = pts = tal_system_get_millisecond();
TUYA_CALL_ERR_LOG(tuya_ai_audio_input(timestamp, pts, (UINT8_T *)data, datalen, datalen));
return rt;
}
STATIC OPERATE_RET _hly_ai_agent_init()
{
OPERATE_RET rt = OPRT_OK;
/* Register downlink event callback and init player. */
TUYA_CALL_ERR_LOG(wukong_ai_agent_init(_hly_ai_event));
TUYA_CALL_ERR_LOG(wukong_audio_player_init());
/* Audio input: board (16k, mono, 80 ms slice, VAD by trigger mode) or UART. */
WUKONG_AUDIO_INPUT_CFG_T audio_cfg = {0};
// #if defined(USING_BOARD_AUDIO_INPUT) && (USING_BOARD_AUDIO_INPUT == 1)
audio_cfg.type = WUKONG_AUDIO_USING_BOARD;
audio_cfg.board.sample_rate = TKL_AUDIO_SAMPLE_16K;
audio_cfg.board.sample_bits = TKL_AUDIO_DATABITS_16;
audio_cfg.board.channel = TKL_AUDIO_CHANNEL_MONO;
audio_cfg.board.slice_ms = AI_AUDIO_SLICE_TIME;
/* HOLD trigger -> manual VAD; otherwise auto VAD (e.g. one-shot, free talk). */
audio_cfg.board.vad_mode = WUKONG_AUDIO_VAD_MANIAL;//WUKONG_AUDIO_VAD_AUTO;//是否由按键触发vad
audio_cfg.board.vad_off_ms = 1000;
audio_cfg.board.vad_active_ms = 200;
audio_cfg.board.spk_io = _hly_ai_config->spk_en_pin;
audio_cfg.board.spk_io_level = TUYA_GPIO_LEVEL_LOW;
audio_cfg.board.output_cb = _hly_ai_mic_data;
// #elif defined(USING_UART_AUDIO_INPUT) && (USING_UART_AUDIO_INPUT == 1)
// audio_cfg.type = WUKONG_AUDIO_USING_UART;
// audio_cfg.uart.mic_upload = __on_ai_toy_mic_data;
// #endif
TUYA_CALL_ERR_LOG(wukong_audio_input_init(&audio_cfg));
hly_ai_set_vol(_hly_ai_config->volume);
TUYA_CALL_ERR_LOG(wukong_kws_default_init());
wukong_audio_input_wakeup_mode_set(WUKONG_AUDIO_VAD_AUTO);
// wukong_kws_enable();
return rt;
}
//ai客户端运行事件
STATIC OPERATE_RET _hly_ai_client_run_cb(VOID_T *data)
{
TAL_PR_NOTICE("hly ai -> connected to server");
// wukong_ai_handle_client(NULL, 0);
return OPRT_OK;
}
/** ai唤醒词事件. */
STATIC OPERATE_RET _hly_ai_audio_kws_cb(VOID_T *data)
{
OPERATE_RET rt = OPRT_OK;
tal_mutex_lock(_ai_mutex);
if(_ai_stat != AI_STAT_IDEL)
{
tal_mutex_unlock(_ai_mutex);
return rt;
}
tal_mutex_unlock(_ai_mutex);
if (data) {
INT_T idx = (INT_T)data;
TAL_PR_DEBUG("==========hly wakeup : %d===========", idx);
if (idx)
{
hly_ai_wakeup();
}
}
return rt;
// return wukong_ai_handle_wakeup(NULL, 0);
}
/** VAD 人声检测*/
STATIC OPERATE_RET _hly_ai_vad_change(VOID *data)
{
TUYA_CHECK_NULL_RETURN(data, OPRT_INVALID_PARM);
// wukong_ai_handle_vad(data, 0);
tal_mutex_lock(_ai_mutex);
if (_ai_stat == AI_STAT_IDEL || _ai_stat==AI_STAT_INIT || !ai_start || !wake_up_flag)
{
tal_mutex_unlock(_ai_mutex);
return OPRT_OK;
}
_hly_ai_re_idel_start(_hly_ai_config->wake_time);
WUKONG_AUDIO_VAD_FLAG_E vad_flag = (WUKONG_AUDIO_VAD_FLAG_E)data;
TAL_PR_DEBUG("[====ai_wakeup] vad: [%d]", vad_flag);
if (WUKONG_AUDIO_VAD_START == vad_flag)
{
if (!tuya_ai_agent_is_ready()) {
TAL_PR_DEBUG("ai agent is not ready, ignore audio input");
tal_mutex_unlock(_ai_mutex);
return OPRT_RESOURCE_NOT_READY;
}
tuya_ai_agent_set_scode(AI_AGENT_SCODE_DEFAULT);
tuya_ai_input_start(FALSE);
}
else
{
tuya_ai_input_stop();
if(_ai_stat!=AI_STAT_SPEAK)
{
_hly_ai_set_stat(AI_STAT_THINK);
}
}
tal_mutex_unlock(_ai_mutex);
return OPRT_OK;
}
//恢复待机定时器
STATIC VOID_T _hly_ai_re_idel_timer_cb (TIMER_ID timer_id, VOID_T *arg)
{
TAL_PR_DEBUG("===hly ai time out===");
hly_ai_shutup();
}
STATIC VOID _hly_ai_sem_task_cb(PVOID_T args)
{
while (true)
{
debug_step_c=1;
tal_semaphore_wait(_hly_ai_sem, SEM_WAIT_FOREVER);
debug_step_c=2;
tal_mutex_lock(_ai_mutex);
debug_step_c=3;
wukong_audio_player_stop(AI_PLAYER_FG);
debug_step_c=5;
tuya_ai_agent_event(AI_EVENT_CHAT_BREAK, 0);
debug_step_c=6;
paly_alart=TRUE;
_hly_ai_set_stat(AI_STAT_IDEL);
debug_step_c=7;
tal_mutex_unlock(_ai_mutex);
hly_ai_play_alert(HLY_AI_ALERT_EXIT);
debug_step_c=8;
}
}
STATIC VOID _hly_ai_debug_task_cb(PVOID_T args)
{
while(1)
{
TAL_PR_DEBUG("====*******ai debug A:%d B:%d C:%d D:%d E:%d********====",debug_step_a,debug_step_b,debug_step_c,debug_step_d,debug_step_e);
tal_system_sleep(1000);
}
}
OPERATE_RET hly_ai_init(hly_ai_config_t* config)
{
OPERATE_RET rt = OPRT_OK;
tal_sw_timer_create(_hly_ai_re_idel_timer_cb,NULL,&_re_idel_timer);
TAL_PR_DEBUG("=======_hli_ai_re_idel_timer_cb timer id:%08X========",_re_idel_timer);
tal_mutex_create_init(&_ai_mutex);
tal_mutex_create_init(&_timer_mutex);
tal_mutex_create_init(&_alert_mutex);
_hly_ai_config = tal_psram_malloc(sizeof(hly_ai_config_t));
if(_hly_ai_config==NULL)
{
TAL_PR_ERR("hly ai init malloc fail.");
return OPRT_MALLOC_FAILED;
}
memset(_hly_ai_config,0,sizeof(hly_ai_config_t));
memcpy(_hly_ai_config,config,sizeof(hly_ai_config_t));
ty_subscribe_event(EVENT_AI_CLIENT_RUN, "hly_ai", _hly_ai_client_run_cb, SUBSCRIBE_TYPE_NORMAL);
ty_subscribe_event(EVENT_WUKONG_KWS_WAKEUP, "hly_ai", _hly_ai_audio_kws_cb, SUBSCRIBE_TYPE_NORMAL);
ty_subscribe_event(EVENT_AUDIO_VAD, "hly_ai", _hly_ai_vad_change, SUBSCRIBE_TYPE_NORMAL);
ty_subscribe_event(AI_STAT_EVENT, "hly_ai", _hly_ai_config->hly_ai_stat_cb, SUBSCRIBE_TYPE_NORMAL);
TUYA_CALL_ERR_GOTO( _hly_ai_agent_init(), __error);
tal_queue_create_init(&_hly_ai_stat_queue,sizeof(hly_ai_stat_e),10);
THREAD_CFG_T stat_task_cfg={
.priority=0,
.stackDepth=4096,
.thrdname="hly_ai_stat_task",
.psram_mode=1
};
tal_thread_create_and_start(&_hly_ai_stat_task,NULL,NULL,_hly_ai_stat_task_cb,NULL,&stat_task_cfg);
tal_semaphore_create_init(&_hly_ai_sem,0,1);
THREAD_CFG_T cfg={
.priority=0,
.stackDepth=2048,
.thrdname="hly_ai_sem_task",
.psram_mode=1
};
tal_thread_create_and_start(&_hly_ai_sem_task,NULL,NULL,_hly_ai_sem_task_cb,NULL,&cfg);
THREAD_CFG_T debug_cfg={
.priority=0,
.stackDepth=2048,
.thrdname="hly_ai_debug_task",
.psram_mode=1
};
tal_thread_create_and_start(&_hly_ai_debug_task,NULL,NULL,_hly_ai_debug_task_cb,NULL,&debug_cfg);
return rt;
__error:
return rt;
}
// OPERATE_RET hly_ai_deinit();//取消初始化
OPERATE_RET hly_ai_start(void)
{
TAL_PR_DEBUG("================ai start============");
tal_mutex_lock(_ai_mutex);
debug_step_d=7;
ai_start=TRUE;
_hly_ai_set_stat(AI_STAT_IDEL);
tal_mutex_unlock(_ai_mutex);
debug_step_d=8;
}
//停止运行ai
OPERATE_RET hly_ai_stop(void)
{
tal_mutex_lock(_ai_mutex);
debug_step_d=5;
ai_start=FALSE;
hly_ai_shutup();
tal_mutex_unlock(_ai_mutex);
debug_step_d=6;
}
// OPERATE_RET hly_ai_nw_stat_change(GW_WIFI_NW_STAT_E stat);//设置网络状态变化
//唤醒进入聆听模式
OPERATE_RET hly_ai_wakeup(void)
{
debug_step_b=1;
tal_mutex_lock(_ai_mutex);
if(!ai_start)
{
tal_mutex_unlock(_ai_mutex);
debug_step_b=2;
return 0;
}
debug_step_b = 3;
wukong_audio_player_stop(AI_PLAYER_ALL);
debug_step_b = 4;
wukong_audio_input_reset();
debug_step_b = 5;
tuya_ai_agent_event(AI_EVENT_CHAT_BREAK, 0);
debug_step_b = 6;
wake_up_flag = TRUE;
paly_alart = TRUE;
// wukong_audio_player_alert(AI_TOY_ALERT_TYPE_WAKEUP, FALSE);
_hly_ai_set_stat(AI_STAT_LISTEN);
debug_step_b=7;
tal_mutex_unlock(_ai_mutex);
tal_mutex_lock(_alert_mutex);
wukong_audio_player_alert(AI_TOY_ALERT_TYPE_WAKEUP, FALSE);
tal_mutex_unlock(_alert_mutex);
debug_step_b=8;
return 0;
}
//立刻停止说话
OPERATE_RET hly_ai_shutup(void)
{
TAL_PR_DEBUG("==============hly_ai_shutup publish==============");
tal_semaphore_post(_hly_ai_sem);
}
//结束对话
OPERATE_RET hly_ai_chat_over(void)
{
tal_mutex_lock(_ai_mutex);
debug_step_d=3;
wake_up_flag = FALSE;
paly_alart=TRUE;
tal_mutex_unlock(_ai_mutex);
debug_step_d=4;
hly_ai_play_alert(HLY_AI_ALERT_EXIT);
return 0;
}
//自由对话
OPERATE_RET hly_ai_free_chat(BOOL_T value)
{
tal_mutex_lock(_ai_mutex);
debug_step_d=1;
free_chat=value;
tal_mutex_unlock(_ai_mutex);
debug_step_d=2;
return 0;
}
OPERATE_RET hly_ai_set_vol(uint8_t vol)
{
float f;
f=vol/100.0f;
f=f*70;
return wukong_audio_player_set_vol((int)f);
// return wukong_audio_player_set_vol(vol);
}
OPERATE_RET hly_ai_set_asr(BOOL_T enable)
{
if(enable)
{
wukong_kws_enable();
}
else
{
wukong_kws_disable();
}
return 0;
}
OPERATE_RET hly_ai_play_alert(HLY_AI_ALERT_E alert)
{
static HLY_AI_ALERT_E curr_alert=HLY_AI_ALERT_MAX;
static uint8_t* data=NULL;
static uint32_t len;
uint8_t str[32]={0};
tal_mutex_lock(_alert_mutex);
debug_step_e=1;
// wukong_audio_player_stop(AI_PLAYER_ALL);
debug_step_e=2;
TAL_PR_DEBUG("=====hly ai play alert:%d", alert);
if (curr_alert != alert)
{
curr_alert = alert;
if (data != NULL)
{
hly_free_psram(data);
}
switch (curr_alert)
{
case HLY_AI_ALERT_ALARM:
sprintf(&str, "/mp3/%s.mp3", "alarm");
break;
case HLY_AI_ALERT_CLOCK:
sprintf(&str, "/mp3/%s.mp3", "clock");
break;
case HLY_AI_ALERT_ERROR:
sprintf(&str, "/mp3/%s.mp3", "error");
break;
case HLY_AI_ALERT_EXIT:
sprintf(&str, "/mp3/%s.mp3", "exit");
break;
case HLY_AI_ALERT_START:
sprintf(&str, "/mp3/%s.mp3", "start");
break;
case HLY_AI_ALERT_STOP:
sprintf(&str, "/mp3/%s.mp3", "stop");
break;
case HLY_AI_ALERT_WAKEUP:
sprintf(&str, "/mp3/%s.mp3", "wakeup");
break;
default:
tal_mutex_unlock(_alert_mutex);
debug_step_e=8;
return -1;
break;
}
TAL_PR_DEBUG("=====hly ai load alert:%s", &str);
if (hly_fs_load_psram(&str, &data, &len) != 0)
{
tal_mutex_unlock(_alert_mutex);
debug_step_e=7;
return -3;
}
}
if (data == NULL)
{
debug_step_e=6;
tal_mutex_unlock(_alert_mutex);
return -1;
}
debug_step_e=3;
int rt = wukong_audio_play_data(AI_AUDIO_CODEC_MP3, data, len);
debug_step_e=4;
tal_mutex_unlock(_alert_mutex);
debug_step_e=5;
return rt;
}
OPERATE_RET hly_ai_set_weke_time(uint8_t wake_time)
{
_hly_ai_config->wake_time=wake_time;
return 0;
}
Re: 【求助】T5 tuya_os_sdk3.13.3播放提示音或停止时卡死
包括之前的stop死循环事件,都说明了处理队列消息的线程就是会卡死,不然不会死循环的。
Re: 【求助】T5 tuya_os_sdk3.13.3播放提示音或停止时卡死
可以按照这个先处理再挂机看看。
- 给 tkl_ao_put_frame 的重试加上累计超时——例如 ret==0 连续重试超过 X ms(比如 200500ms)就 return OPRT_TIMEOUT 并丢帧,绝不 goto 死循环。(同时增加超时的日志)
- 兜底(应用/播放器层):
- 把播放消息队列深度从 2 调大(比如10),减少瞬时 -26369;
- tuya_ai_player_stop/start 的 tal_queue_post 给个小超时而非 0;
- 配合方案1(播放线程内不忙等),避免重入。
Re: 【求助】T5 tuya_os_sdk3.13.3播放提示音或停止时卡死
附件是完整的分析报告,可以参考(包括代码重构)
- Attachments
-
- tuyaos-audio-deadlock-bundle.zip
- (46.85 KiB) Downloaded 24 times