修改230 ai对话代码,增加打断 2264/1 2264/head
authorhcj <1224667075@qq.com>
Tue, 16 Sep 2025 09:30:18 +0000 (17:30 +0800)
committerhcj <1224667075@qq.com>
Tue, 16 Sep 2025 09:30:18 +0000 (17:30 +0800)
19 files changed:
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceModel.cpp
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoicePresenter.cpp
code/sdk/build/config/target_config/brandy/config.py
code/sdk/middleware/services/media/foundation/sample/wrapper/audio_manager_c_wrapper.cpp
code/sdk/middleware/services/media/foundation/sample/wrapper/audio_manager_c_wrapper.h
code/sdk/zhihui/ai/include/ai_media.h
code/sdk/zhihui/ai/media/ai_media_service_ext.cpp
code/sdk/zhihui/ai_old/ai_old_at_cmd.cpp
code/sdk/zhihui/ai_old/asr_websocket_server.cpp
code/sdk/zhihui/ai_old/asr_websocket_server.h
code/sdk/zhihui/ai_old/chat_websocket_server.cpp
code/sdk/zhihui/ai_old/tts_websocket_server.cpp
code/sdk/zhihui/ai_old/tts_websocket_server.h
code/sdk/zhihui/ai_old/websocket_server_example.cpp
code/sdk/zhihui/ai_old/websocket_server_manager.cpp
code/sdk/zhihui/ai_old/websocket_server_manager.h
code/sdk/zhihui/utils/custom_cmd_service.c
code/sdk/zhihui/utils/custom_utils.c
code/sdk/zhihui/utils/custom_utils.h

index 7620f26..cfa8550 100644 (file)
@@ -180,7 +180,9 @@ namespace OHOS
                 WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GetSelect4gorbt() == AI_SELECT_4G");
                 if (GetInit_4gai_task())
                 {
+#ifdef SUPPORT_AI_SERVICE
                     uapi_start_AI_asr();
+#endif
                 }
                 else
                 {
@@ -970,7 +972,9 @@ namespace OHOS
         WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "停止录音");
         if (GetSelect4gorbt() == AI_SELECT_4G) // 选的是4G需要关闭asr
         {
+#ifdef SUPPORT_AI_SERVICE
             uapi_stop_AI_asr();
+#endif
         }
         else if (GetSelect4gorbt() == AI_SELECT_BT)
         {
@@ -1038,8 +1042,10 @@ namespace OHOS
             if (AiVoiceModel::GetInstance().GetSelect4gorbt() == AI_SELECT_4G)
             {
                 // dinit_ai_task(); // 所有服务都删除重新连一下服务器
-                stop_all_websocket_servers();
-                destroy_all_websocket_servers();
+#ifdef SUPPORT_AI_SERVICE
+                uapi_stop_all_websocket_servers();
+                uapi_destroy_all_websocket_servers();
+#endif
             }
 
             SendMsgToUIService(UI_AI_JUMP_TO_RESPONDERR_VIEW, 0, (void *)str.c_str(), str.length());
@@ -1331,8 +1337,10 @@ namespace OHOS
                     if (AiVoiceModel::GetInstance().GetSelect4gorbt() == AI_SELECT_4G)
                     {
                         // dinit_ai_task(); // 所有服务都删除重新连一下服务器
-                        stop_all_websocket_servers();
-                        destroy_all_websocket_servers();
+#ifdef SUPPORT_AI_SERVICE
+                        uapi_stop_all_websocket_servers();
+                        uapi_destroy_all_websocket_servers();
+#endif
                     }
                     p_AiVoicePresenter->ChangeViewAndLogicOperator(AIVOICE_AIMODE_CONNECTING, AIVOICE_AIMODEL_CONNECT_FAILED_VIEWID);
                 }
@@ -1436,8 +1444,10 @@ namespace OHOS
                     (view_->GetAiVoiceScrollView(AIVOICE_4GSERVICECON_VIEW)->IsVisible()))
                 {
                     // dinit_ai_task(); // 所有服务都删除重新连一下服务器
-                    stop_all_websocket_servers();
-                    destroy_all_websocket_servers();
+#ifdef SUPPORT_AI_SERVICE
+                    uapi_stop_all_websocket_servers();
+                    uapi_destroy_all_websocket_servers();
+#endif
                     p_AiVoicePresenter->ChangeViewAndLogicOperator(AIVOICE_4GSERVICECON_VIEW, AIVOICE_AIMODEL_CONNECT_FAILED_VIEWID);
                 }
             }
index 289f519..b236bb1 100644 (file)
@@ -29,6 +29,7 @@
 #include "aivoice/include/AiVoiceSelectView.h"
 #include "graphic_service.h"
 #include "websocket_server_manager.h"
+#include "custom_utils.h"
 namespace OHOS
 {
 
@@ -124,8 +125,10 @@ namespace OHOS
         model->stop_uapi_stop_tts_timer();
         remove_4GAI_vote(); // 移除4g投票
 
-        stop_all_websocket_servers();
-        destroy_all_websocket_servers();
+#ifdef SUPPORT_AI_SERVICE
+        uapi_stop_all_websocket_servers();
+        uapi_destroy_all_websocket_servers();
+#endif
         
         // dinit_ai_task();
         // ai_cleanup_resources();
@@ -500,8 +503,10 @@ namespace OHOS
                 {
                     /* -------------------------------------------------------------------------- */
                     // init_ai_task(AiVoiceModel::GetInstance().GetCurUsing4GAiModelType());
-                    init_all_websocket_servers();
-                    start_all_websocket_servers(); // 连接服务器
+#ifdef SUPPORT_AI_SERVICE
+                    uapi_init_all_websocket_servers();
+                    uapi_start_all_websocket_servers(); // 连接服务器
+#endif
                     /* -------------------------------------------------------------------------- */
                     model->start_ai4g_connect_timer();
                     ChangeViewAndLogicOperator(AIVOICE_STARTCHAT_VIEWID, AIVOICE_4GSERVICECON_VIEW); // LOADING
@@ -542,8 +547,10 @@ namespace OHOS
             if (!model->GetInit_4gai_task())
             {
                 // init_ai_task(AiVoiceModel::GetInstance().GetCurUsing4GAiModelType());
-                init_all_websocket_servers();
-                start_all_websocket_servers(); // 连接服务器
+#ifdef SUPPORT_AI_SERVICE
+                uapi_init_all_websocket_servers();
+                uapi_start_all_websocket_servers(); // 连接服务器
+#endif
                 model->start_ai4g_connect_timer();
                 ChangeViewAndLogicOperator(model->GetCurView(), AIVOICE_4GSERVICECON_VIEW); // LOADING
             }
@@ -591,8 +598,10 @@ namespace OHOS
                 {
                     AiVoiceModel::GetInstance().stop_ai4g_tts_play_timer();
                     AiVoiceModel::GetInstance().stop_uapi_stop_tts_timer();
-                    stop_all_websocket_servers();
-                    destroy_all_websocket_servers();
+#ifdef SUPPORT_AI_SERVICE
+                    uapi_stop_all_websocket_servers();
+                    uapi_destroy_all_websocket_servers();
+#endif
                 }
             }
             ChangeViewAndLogicOperator(it->second.first, it->second.second);
@@ -614,8 +623,10 @@ namespace OHOS
                 if (model->GetSelect4gorbt() == AI_SELECT_4G)
                 {
                     // dinit_ai_task();
-                    stop_all_websocket_servers();
-                    destroy_all_websocket_servers();
+#ifdef SUPPORT_AI_SERVICE
+                    uapi_stop_all_websocket_servers();
+                    uapi_destroy_all_websocket_servers();
+#endif
                 }
             }
             ChangeViewAndLogicOperator(it->second.first, it->second.second);
index d98a52c..46583a2 100644 (file)
@@ -414,6 +414,7 @@ target = {
             # 'AILPAY_SUPPORT',
             'SUPPORT_FACTORY_SERVICE',
             # 'MEMORY_CORRUPTION',
+            'SUPPORT_AI_SERVICE',
             
         ],
         #添加自定义应用
@@ -452,6 +453,17 @@ target = {
                            "transspecard",
                            "factorytest_service",
                         #    "hid_service",
+             
+                          #websocket 相关配置
+                            "zhihui_websocket",
+                            #ai 相关配置
+                            "aiMediaService",       
+                            "aiService",
+                            #ai_old相关配置
+                            "zhihui_ai_old",
+                            #音频相关配置
+                            "audio_manager",
+                            
                            "producttest",
                             "ppg_hal",
                             "mag_service",
index 7783805..6c00d37 100644 (file)
@@ -334,6 +334,18 @@ int32_t AudioStreamOutPlay(void)
     return AUDIO_SUCCESS;
 }
 
+int32_t AudioStreamOutFlush(void)
+{
+    int32_t ret = g_streamOut->Flush();
+    if (ret != AUDIO_SUCCESS) {
+        ALOGE("audio stream out Flush failed 0x%x", ret);
+        return AUDIO_ERROR;
+    }
+
+    ALOGD("success");
+    return AUDIO_SUCCESS;
+}
+
 int32_t AudioStreamOutStreamWrite(const uint8_t *data, uint32_t size)
 {
     uint64_t writtenSize = 0;
@@ -350,7 +362,7 @@ int32_t AudioStreamOutStreamWrite(const uint8_t *data, uint32_t size)
 
 int32_t AudioStreamOutStop(void)
 {
-    int32_t ret = g_streamOut->Stop();
+    int32_t ret = g_streamOut->Pause();
     if (ret != AUDIO_SUCCESS) {
         ALOGE("audio stream out stop failed 0x%x", ret);
         return AUDIO_ERROR;
index 32e29f6..9a70782 100644 (file)
@@ -60,6 +60,8 @@ int32_t AudioStreamOutStop(void);
 
 int32_t AudioStreamOutDeinit(void);
 
+int32_t AudioStreamOutFlush(void);
+
 /**
  * @brief Sets audio effect algorithm parameters.
  *
index 34f8a74..89a8db4 100644 (file)
@@ -120,6 +120,25 @@ int32_t StopAIVoice(void);
 
 int32_t AI_SendAudioDataToQueue(const uint8_t* data, uint32_t size);
 
+/*
+ * @brief 设置AI语音打断标志
+ * @param interrupt 打断标志,true表示需要清空队列并恢复输出流,false表示清除标志
+ * @return 0 成功,-1 失败
+ */
+int32_t AI_SetInterruptFlag(bool interrupt);
+
+/*
+ * @brief 获取AI语音打断标志
+ * @return true 打断标志已设置,false 打断标志未设置或服务未运行
+ */
+bool AI_GetInterruptFlag(void);
+
+/*
+ * @brief 强制清空AI语音队列并恢复输出流
+ * @return 0 成功,-1 失败
+ */
+int32_t AI_ForceInterrupt(void);
+
 #ifdef __cplusplus
 };
 #endif
index f1adfc5..b8611d8 100644 (file)
@@ -61,6 +61,7 @@ typedef struct {
 typedef struct {
     AudioSession sessionId;
     bool isAIVoiceStopped;
+    bool interruptFlag;                // 打断标志,设置时清空队列并重置流
     MediaThreadCondHandle cond;        // 保留条件变量用于线程同步
     MediaThreadIdHandle taskHandle;
     char threadName[32];               // 线程名称,用于验证线程ID
@@ -417,6 +418,15 @@ static int32_t RunAIVoice(AIVoiceContext *context)
     MEDIA_INFO_LOG("RunAIVoice: waiting for queue data...");
     
     while (!context->isAIVoiceStopped) {
+// 检查打断标志
+        if (context->interruptFlag) {
+            MEDIA_INFO_LOG("Interrupt flag set, clearing queue and resuming output stream...");
+            // 清除打断标志
+            context->interruptFlag = false;
+            
+            MEDIA_INFO_LOG("Interrupt processing completed");
+        }
+        
         if (context->inputQueue != NULL) {
             AIVoiceQueueMessage msg;
             osStatus_t status = osMessageQueueGet(context->inputQueue, &msg, NULL, 100); // 100ms超时
@@ -497,6 +507,91 @@ static bool ReleaseAudioFocus(void)
     return true;
 }
 
+/**
+ * @brief 暂停音频输出流
+ * @return 0 成功,-1 失败
+ */
+static int32_t PauseAudioStreams(void)
+{
+    int32_t ret = 0;
+    
+    // 只暂停输出流
+    ret = AudioStreamOutStop();
+    if (ret != 0) {
+        MEDIA_ERR_LOG("audio stream out stop failed: %d", ret);
+    }
+    
+    MEDIA_INFO_LOG("Audio output stream paused");
+    return 0;
+}
+
+/**
+ * @brief 清空音频输出流缓冲区
+ * @return 0 成功,-1 失败
+ */
+static int32_t ClearAudioStreams(void)
+{
+    int32_t ret = 0;
+    
+    // 只清空输出流缓冲区
+    ret = AudioStreamOutFlush();
+    if (ret != 0) {
+        MEDIA_ERR_LOG("audio stream out flush failed: %d", ret);
+    }
+    
+    MEDIA_INFO_LOG("Audio output stream cleared");
+    return 0;
+}
+
+/**
+ * @brief 恢复音频输出流
+ * @return 0 成功,-1 失败
+ */
+static int32_t ResetAudioStreams(void)
+{
+    int32_t ret = 0;
+    
+    // 只恢复输出流,不进行销毁重建
+    ret = AudioStreamOutPlay();
+    if (ret != 0) {
+        MEDIA_ERR_LOG("audio stream out resume failed: %d", ret);
+    }
+    
+    MEDIA_INFO_LOG("Audio output stream resumed");
+    return 0;
+}
+
+/**
+ * @brief 清空AI语音队列
+ * @param context AI语音上下文
+ * @return 0 成功,-1 失败
+ */
+static int32_t ClearAIVoiceQueue(AIVoiceContext *context)
+{
+    if (context == nullptr || context->inputQueue == NULL) {
+        MEDIA_ERR_LOG("AI voice context or queue is null");
+        return -1;
+    }
+    
+    AIVoiceQueueMessage msg;
+    uint32_t clearedCount = 0;
+    
+    // 清空队列中的所有消息
+    while (osMessageQueueGet(context->inputQueue, &msg, NULL, 0) == osOK) {
+        if (msg.data != nullptr) {
+            free(msg.data);
+            msg.data = nullptr;
+        }
+        clearedCount++;
+    }
+    
+    // 重置队列消息计数
+    context->queueMsgCount = 0;
+    
+    MEDIA_INFO_LOG("AI voice queue cleared: %u messages removed", clearedCount);
+    return 0;
+}
+
 
 static void AIVoiceThread(void *priv)
 {
@@ -752,6 +847,8 @@ int32_t AI_WriteAudioData(const uint8_t* data, uint32_t size)
         return -1;
     }
     AI_WRITE:
+    if(g_aiVoiceContext->interruptFlag)
+    return -1;
     // 获取全局互斥锁(自动初始化)
     MediaMutexHandle mutex = GetGlobalMutex();
     if (mutex == nullptr) {
@@ -770,14 +867,15 @@ int32_t AI_WriteAudioData(const uint8_t* data, uint32_t size)
 
     // 写入音频数据到输出流
     int32_t ret = AudioStreamOutStreamWrite(data, size);
+    usleep(50*size);
     if (ret != 0) {
         // MEDIA_ERR_LOG("Failed to write audio data to output stream, ret=%d", ret);
-        usleep(100000); 
         // return -1;
+        usleep(10000);
         goto AI_WRITE;
     }
     
-    MEDIA_INFO_LOG("Successfully wrote %u bytes of audio data to output stream", size);
+    // MEDIA_INFO_LOG("Successfully wrote %u bytes of audio data to output stream", size);
     return 0;
 }
 
@@ -939,6 +1037,93 @@ int32_t AI_CleanupModule(void)
     return 0;
 }
 
+/**
+ * @brief 设置AI语音打断标志
+ * @param interrupt 打断标志,true表示需要清空队列并重置流,false表示清除标志
+ * @return 0 成功,-1 失败
+ */
+int32_t AI_SetInterruptFlag(bool interrupt)
+{
+    MediaMutexHandle mutex = GetGlobalMutex();
+    if (mutex == nullptr) {
+        MEDIA_ERR_LOG("Failed to get global mutex");
+        return -1;
+    }
+    
+    MediaMutexLock(mutex);
+    if (g_aiVoiceContext == nullptr) {
+        MEDIA_ERR_LOG("AI voice context is null, please start AI voice first");
+        MediaMutexUnLock(mutex);
+        return -1;
+    }
+    
+    g_aiVoiceContext->interruptFlag = interrupt;
+    MEDIA_INFO_LOG("AI voice interrupt flag set: %s", interrupt ? "true" : "false");
+    
+    MediaMutexUnLock(mutex);
+    return 0;
+}
+
+/**
+ * @brief 获取AI语音打断标志
+ * @return true 打断标志已设置,false 打断标志未设置或服务未运行
+ */
+bool AI_GetInterruptFlag(void)
+{
+    bool interruptFlag = false;
+    
+    MediaMutexHandle mutex = GetGlobalMutex();
+    if (mutex == nullptr) {
+        return false;
+    }
+    
+    MediaMutexLock(mutex);
+    if (g_aiVoiceContext != nullptr) {
+        interruptFlag = g_aiVoiceContext->interruptFlag;
+    }
+    MediaMutexUnLock(mutex);
+    
+    return interruptFlag;
+}
+
+/**
+ * @brief 强制清空AI语音队列并重置流
+ * @return 0 成功,-1 失败
+ */
+int32_t AI_ForceInterrupt(void)
+{
+    MediaMutexHandle mutex = GetGlobalMutex();
+    if (mutex == nullptr) {
+        MEDIA_ERR_LOG("Failed to get global mutex");
+        return -1;
+    }
+    
+    MediaMutexLock(mutex);
+    if (g_aiVoiceContext == nullptr) {
+        MEDIA_ERR_LOG("AI voice context is null, please start AI voice first");
+        MediaMutexUnLock(mutex);
+        return -1;
+    }
+    
+    // 设置打断标志
+    g_aiVoiceContext->interruptFlag = true;
+    
+    // 立即清空队列
+    ClearAIVoiceQueue(g_aiVoiceContext);
+    
+    // 立即暂停和清空输出流
+    PauseAudioStreams();
+    ClearAudioStreams();
+    
+    // 立即恢复输出流
+    ResetAudioStreams();
+    
+    MEDIA_INFO_LOG("AI voice force interrupt completed");
+    
+    MediaMutexUnLock(mutex);
+    return 0;
+}
+
 #ifdef __cplusplus
 };
 #endif
index 9e665a6..ccc03da 100644 (file)
@@ -349,8 +349,10 @@ static uint32_t startserver(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
         printf("CAT1TEST ATCMD Convert Command Failed\n");
         return ERRCODE_FAIL;
     }
+#ifdef SUPPORT_AI_SERVICE
     init_all_websocket_servers();
     start_all_websocket_servers();
+#endif
     return 0;
 }
 
@@ -366,7 +368,7 @@ static uint32_t StartTranscription(uint8_t *para, uint32_t paraLen, char *strCom
         printf("CAT1TEST ATCMD Convert Command Failed\n");
         return ERRCODE_FAIL;
     }
-    uapi_start_AI_asr();
+    uapi_start_AI_asr_();
     return 0;
 }
 
@@ -382,7 +384,7 @@ static uint32_t STOPTranscription(uint8_t *para, uint32_t paraLen, char *strComm
         printf("CAT1TEST ATCMD Convert Command Failed\n");
         return ERRCODE_FAIL;
     }
-    uapi_stop_AI_asr();
+    uapi_stop_AI_asr_();
     return 0;
 }
 extern void msleep(uint32_t ms);
@@ -398,9 +400,11 @@ static uint32_t STOPserver(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
         printf("CAT1TEST ATCMD Convert Command Failed\n");
         return ERRCODE_FAIL;
     }
+#ifdef SUPPORT_AI_SERVICE
     stop_all_websocket_servers();
     msleep(1000);
     destroy_all_websocket_servers();
+#endif
     return 0;
 }
 
index 6834839..df87624 100644 (file)
@@ -378,7 +378,7 @@ errcode_t asr_server_init(void)
     
     asr_taskcfg.create_queue_handle = NULL;
     asr_taskcfg.attr.name = "asr_server_init";
-    asr_taskcfg.attr.priority = (osPriority_t)TASK_PRIORITY_APP;
+    asr_taskcfg.attr.priority = (osPriority_t)16;
     asr_taskcfg.attr.stack_size = 0x1000;
     asr_taskcfg.func = bk_websocket_asr;
     asr_taskcfg.use_mem = USE_EXTEND_MEM;
index bc616da..7e08b9d 100644 (file)
@@ -48,8 +48,8 @@ typedef struct {
 /* 任务配置结构体 - 使用系统定义的 app_task_definition_t */
 
 /* 常量定义 */
-#define TASK_PRIORITY_APP 24
-#define USE_EXTEND_MEM 1
+// #define TASK_PRIORITY_APP 24
+// #define USE_EXTEND_MEM 1
 
 /* ASR 服务接口函数 */
 
index bf0dd93..0071fc1 100644 (file)
@@ -207,21 +207,6 @@ chat_event_type_t chat_result_analysis(char *buf, char *out_put, size_t out_put_
             strncpy(out_put, content_str, copy_size);
             out_put[copy_size] = '\0';
         }
-        
-        // 原有的处理逻辑保持不变
-        if (event_type == CHAT_EVENT_MIDDLE) {
-            char *content_str_chat = (char *)malloc(strlen(content_str) + 1);
-            if (content_str_chat != NULL) {
-                strcpy(content_str_chat, content_str);
-                ble_set_ai_Answer_str(content_str_chat, 2);
-                free(content_str_chat);
-            }
-        } else if (event_type == CHAT_EVENT_END) {
-            char end_str_chat[128] = {0};
-            memset(end_str_chat, 0, 128); 
-            memcpy(end_str_chat, content_str, strlen(content_str) < 127 ? strlen(content_str) : 127); 
-            ble_set_ai_Answer_str(end_str_chat, 2);
-        }
     }
 
     cJSON_Delete(root);
index 647fb75..2d16b39 100644 (file)
@@ -62,6 +62,7 @@ static char tts_task_id_buf[128] = {0};
 static char *tts_cached_text = NULL;      // 缓存待发送的文本字符串(动态分配)
 static int tts_cached_length = 0;         // 当前缓存的文本长度
 static int tts_cached_capacity = 0;       // 当前分配的内存容量
+static bool tts_has_stop_cached = false;  // 是否缓存了stop命令
 // static bool tts_is_ready = false;         // TTS是否准备就绪
 
 /**
@@ -321,6 +322,13 @@ bool uapi_tts_process_text(WebSocketClient *tts_client, char *buf, bool ready)
         tts_cached_length = 0;
     }
     
+    // 检查是否有缓存的stop命令需要发送
+    if (tts_has_stop_cached) {
+        printf("TTS ready, sending cached stop command\n");
+        uapi_stop_tts_type_stop(tts_client);
+        tts_has_stop_cached = false;  // 重置标志
+    }
+    
     // 发送本次携带的内容
     if (buf && strlen(buf) > 0) {
         printf("TTS ready, sending current text: %s\n", buf);
@@ -475,9 +483,36 @@ void uapi_clear_tts_cache(void)
         memset(tts_cached_text, 0, tts_cached_capacity);
     }
     tts_cached_length = 0;
+    tts_has_stop_cached = false;  // 同时清空stop缓存标志
     printf("TTS cache cleared\n");
 }
 
+/**
+ * @brief 缓存stop命令
+ * @param tts_client TTS WebSocket客户端
+ * @param ready true: 如果TTS就绪则直接发送stop命令, false: 缓存stop命令等待TTS就绪
+ * @return true 成功,false 失败
+ */
+bool uapi_cache_stop_command(WebSocketClient *tts_client, bool ready)
+{
+    if (ready) {
+        // 如果TTS就绪,直接发送stop命令
+        if (tts_client != NULL) {
+            uapi_stop_tts_type_stop(tts_client);
+            printf("TTS ready, stop command sent directly\n");
+            return true;
+        } else {
+            printf("TTS client is NULL, cannot send stop command\n");
+            return false;
+        }
+    } else {
+        // 如果TTS未就绪,缓存stop命令
+        tts_has_stop_cached = true;
+        printf("TTS not ready, stop command cached\n");
+        return true;
+    }
+}
+
 /**
  * @brief 初始化TTS缓存内存
  * @return true 成功,false 失败
@@ -949,7 +984,7 @@ bool uapi_start_tts_type_start(WebSocketClient *client)
         goto cleanup;
     }
     
-    if (cJSON_AddNumberToObject(payload, "volume", 80) == NULL) {
+    if (cJSON_AddNumberToObject(payload, "volume", 50) == NULL) {
         printf("Failed to add volume field\n");
         goto cleanup;
     }
@@ -1029,6 +1064,21 @@ void uapi_stop_tts_type_stop(WebSocketClient *client)
  * 
  * // 或者使用全局客户端停止
  * uapi_stop_tts_type_stop(g_tts_server->client);
+ * 
+ * // 新增功能:智能stop命令处理
+ * // 检查TTS是否就绪
+ * tts_ready_status_t ready_status = uapi_get_tts_ready();
+ * bool is_ready = (ready_status == TTS_READY_SUCCESS_READY);
+ * 
+ * // 如果就绪则直接发送stop命令,否则缓存等待就绪
+ * uapi_cache_stop_command(client, is_ready);
+ * 
+ * // 或者手动处理文本和stop命令
+ * // 添加文本到缓存(TTS未就绪时)
+ * uapi_tts_process_text(client, "Hello world", false);
+ * 
+ * // 当TTS就绪时,清理缓存并发送所有内容(包括stop命令)
+ * uapi_tts_process_text(client, "", true);  // 空字符串表示只清理缓存
  */
 
 #ifdef __cplusplus
index 5ee5199..dce84f0 100644 (file)
@@ -147,6 +147,14 @@ int uapi_get_cached_text_count(void);
  */
 void uapi_clear_tts_cache(void);
 
+/**
+ * @brief 缓存stop命令
+ * @param tts_client TTS WebSocket客户端
+ * @param ready true: 如果TTS就绪则直接发送stop命令, false: 缓存stop命令等待TTS就绪
+ * @return true 成功,false 失败
+ */
+bool uapi_cache_stop_command(WebSocketClient *tts_client, bool ready);
+
 /**
  * @brief 初始化TTS缓存内存
  * @return true 成功,false 失败
index 7798807..0cac1e7 100644 (file)
@@ -182,6 +182,7 @@ void handle_asr_data(const ws_event_data_t *event_data)
                 break;
 
             case ASR_EVENT_TRANSCRIPTION_COMPLETED:
+                g_chat_server->interrupt_flag=0;
                 ai_chat_send_txt(0, "", g_chat_server->client,true);
                 asr_is_ready=0;
                 break;
@@ -205,9 +206,7 @@ void handle_tts_data(const ws_event_data_t *event_data)
     if (event_data->msg_type == WS_BINARY) {
         printf("TTS binary data: %d bytes\n", event_data->data_len);
         set_AIStreamend(0);
-        // AI_WriteAudioData(event_data->data, event_data->data_len);
         AI_SendAudioDataToQueue(event_data->data,event_data->data_len);
-        // send_msg_data_into_Ai_msg_queue(event_data->data, event_data->data_len, 200);
     } else if (event_data->msg_type == WS_TEXT) {
         printf("TTS text data: %s\n", (char *)event_data->data);
         tts_event_type_t event = tts_analysis((char *)event_data->data);
@@ -216,6 +215,7 @@ void handle_tts_data(const ws_event_data_t *event_data)
             case TTS_EVENT_STARTED_SYNTHESIS:
                 printf("TTS synthesis started successfully\n");
                 tts_is_ready = TTS_READY_SUCCESS_READY;
+                
                 uapi_tts_process_text(g_tts_server->client,"",(tts_is_ready == TTS_READY_SUCCESS_READY));
                 break;
             case TTS_EVENT_END_SYNTHESIS:
@@ -270,6 +270,7 @@ void handle_chat_data(const ws_event_data_t *event_data)
                 if(tts_is_ready == TTS_READY_NOT_SENT) {
 
                     tts_is_ready = TTS_READY_SENT_SUCCESS;
+                    g_tts_server->interrupt_flag=0;
                     uapi_start_tts_type_start(g_tts_server->client);
                     
                 }
@@ -283,7 +284,11 @@ void handle_chat_data(const ws_event_data_t *event_data)
                 
             case CHAT_EVENT_END:
                 printf("Chat event: END - Final content: %s\n", buf);
-                uapi_stop_tts_type_stop(g_tts_server->client);
+                ble_set_ai_Answer_str(buf, 2);
+
+                uapi_tts_process_text(g_tts_server->client,buf,(tts_is_ready == TTS_READY_SUCCESS_READY));
+                uapi_cache_stop_command(g_tts_server->client,(tts_is_ready == TTS_READY_SUCCESS_READY));
+                
                 break;
                 
             case CHAT_EVENT_ERROR:
@@ -418,7 +423,7 @@ errcode_t init_all_websocket_servers(void)
     // 创建ASR服务器
     ws_server_config_t asr_config = ws_server_get_default_config(WS_SERVER_TYPE_ASR);
     asr_config.disconnect_strategy = WS_DISCONNECT_RECONNECT; // 设置自动重连
-    asr_config.reconnect_interval_ms = 3000; // 3秒重连间隔
+    asr_config.reconnect_interval_ms = 500; // 3秒重连间隔
     g_asr_server = ws_server_create(&asr_config, websocket_event_callback, NULL);
     if (!g_asr_server) {
         printf("Failed to create ASR server\n");
@@ -428,7 +433,7 @@ errcode_t init_all_websocket_servers(void)
     // 创建TTS服务器
     ws_server_config_t tts_config = ws_server_get_default_config(WS_SERVER_TYPE_TTS);
     tts_config.disconnect_strategy = WS_DISCONNECT_RECONNECT; // 设置自动重连
-    tts_config.reconnect_interval_ms = 5000; // 5秒重连间隔
+    tts_config.reconnect_interval_ms = 500; // 5秒重连间隔
     g_tts_server = ws_server_create(&tts_config, websocket_event_callback, NULL);
     if (!g_tts_server) {
         printf("Failed to create TTS server\n");
@@ -439,7 +444,7 @@ errcode_t init_all_websocket_servers(void)
     // 创建Chat服务器
     ws_server_config_t chat_config = ws_server_get_default_config(WS_SERVER_TYPE_CHAT);
     chat_config.disconnect_strategy = WS_DISCONNECT_RECONNECT; // 设置自动重连
-    chat_config.reconnect_interval_ms = 2000; // 2秒重连间隔
+    chat_config.reconnect_interval_ms = 500; // 2秒重连间隔
     g_chat_server = ws_server_create(&chat_config, websocket_event_callback, NULL);
     if (!g_chat_server) {
         printf("Failed to create Chat server\n");
@@ -737,13 +742,18 @@ void ai_media_init(void)
 
 }
 
-void uapi_start_AI_asr(void)
+void uapi_start_AI_asr_(void)
 {
+    if(g_asr_server)
     uapi_start_asr_StartTranscription(g_asr_server->client);
+    g_tts_server->interrupt_flag=1;
+    g_chat_server->interrupt_flag=1;
+    AI_ForceInterrupt();
 }
 
-void uapi_stop_AI_asr(void)
+void uapi_stop_AI_asr_(void)
 {
+    if(g_asr_server)
     uapi_stop_asr_StopTranscription(g_asr_server->client);
 }
 
index 0ddd3f6..b406eee 100644 (file)
@@ -329,7 +329,7 @@ ws_server_config_t ws_server_get_default_config(ws_server_type_t type)
     config.type = type;
     config.handshake_timeout_ms = 10000;
     config.receive_timeout_ms = 30000;
-    config.max_retry_count = 3;
+    config.max_retry_count = 0x1000;
     config.buffer_size = 4096;
     config.url_callback = NULL;
     config.url_user_data = NULL;
@@ -455,6 +455,27 @@ static void ws_server_thread_func(void *data)
     handle->is_initialized = 1;
     
     while (!handle->need_stop) {
+        // 检查打断标志,如果设置了则主动重连
+         if (handle->interrupt_flag && !handle->need_stop ) {
+            printf("Interrupt flag set, attempting reconnect...\n");
+            handle->interrupt_flag = 0;  // 清除打断标志
+            ws_server_trigger_event(handle, WS_EVENT_RECONNECTING, NULL, 0, WS_TEXT, 0);
+            
+            if (ws_server_should_reconnect(handle)) {
+                if (ws_server_attempt_reconnect(handle)) {
+                    last_activity = (uint32_t)osKernelGetTickCount();
+                    printf("Reconnect successful after interrupt\n");
+                    continue;
+                } else {
+                    printf("Reconnect failed after interrupt\n");
+                    break;
+                }
+            } else {
+                printf("Reconnect not allowed after interrupt\n");
+                break;
+            }
+        }
+        
         // 检查超时
         if ((uint32_t)osKernelGetTickCount() - last_activity > handle->config.receive_timeout_ms) {
             printf("Receive timeout, checking reconnect strategy...\n");
@@ -479,6 +500,26 @@ static void ws_server_thread_func(void *data)
         //                                               handle->config.receive_timeout_ms);
         int len = receive_websocket_message(handle->client,(unsigned char *)handle->recv_buffer,handle->config.buffer_size, &msg_type, handle->config.receive_timeout_ms);
         
+        if (handle->interrupt_flag && !handle->need_stop ) {
+            printf("Interrupt flag set, attempting reconnect...\n");
+            handle->interrupt_flag = 0;  // 清除打断标志
+            ws_server_trigger_event(handle, WS_EVENT_RECONNECTING, NULL, 0, WS_TEXT, 0);
+            
+            if (ws_server_should_reconnect(handle)) {
+                if (ws_server_attempt_reconnect(handle)) {
+                    last_activity = (uint32_t)osKernelGetTickCount();
+                    printf("Reconnect successful after interrupt\n");
+                    continue;
+                } else {
+                    printf("Reconnect failed after interrupt\n");
+                    break;
+                }
+            } else {
+                printf("Reconnect not allowed after interrupt\n");
+                break;
+            }
+        }
+
         if (len == -1 || msg_type == WS_CLOSE) {
             printf("WebSocket connection closed, checking reconnect strategy...\n");
             ws_server_trigger_event(handle, WS_EVENT_DISCONNECTED, NULL, 0, WS_TEXT, 0);
@@ -609,7 +650,7 @@ static bool ws_server_connect(ws_server_handle_t *handle)
     printf("Connecting to: %s\n", url_buf);
     
     // 创建WebSocket客户端
-    uint8_t client_count = handle->config.max_retry_count;
+    uint32_t client_count = handle->config.max_retry_count;
     while (client_count > 0) {
         handle->client = init_websocket_client(url_buf, NULL, 0);
         if (handle->client) {
@@ -784,6 +825,52 @@ static bool ws_server_attempt_reconnect(ws_server_handle_t *handle)
     return success;
 }
 
+/**
+ * @brief 设置WebSocket服务器打断标志
+ * @param server_type 服务器类型
+ * @param interrupt 打断标志,1表示需要重连,0表示清除标志
+ * @return errcode_t 错误码
+ */
+errcode_t ws_server_set_interrupt_flag(ws_server_type_t server_type, uint8_t interrupt)
+{
+    if (server_type >= WS_SERVER_TYPE_MAX) {
+        printf("Invalid server type: %d\n", server_type);
+        return ERRCODE_FAIL;
+    }
+    
+    ws_server_handle_t *handle = g_thread_handles[server_type];
+    if (!handle) {
+        printf("Server handle not found for type: %d\n", server_type);
+        return ERRCODE_FAIL;
+    }
+    
+    handle->interrupt_flag = interrupt;
+    printf("WebSocket server interrupt flag set: type=%d, interrupt=%d\n", server_type, interrupt);
+    
+    return ERRCODE_SUCC;
+}
+
+/**
+ * @brief 获取WebSocket服务器打断标志
+ * @param server_type 服务器类型
+ * @return uint8_t 打断标志状态
+ */
+uint8_t ws_server_get_interrupt_flag(ws_server_type_t server_type)
+{
+    if (server_type >= WS_SERVER_TYPE_MAX) {
+        printf("Invalid server type: %d\n", server_type);
+        return 0;
+    }
+    
+    ws_server_handle_t *handle = g_thread_handles[server_type];
+    if (!handle) {
+        printf("Server handle not found for type: %d\n", server_type);
+        return 0;
+    }
+    
+    return handle->interrupt_flag;
+}
+
 #ifdef __cplusplus
 }
 #endif
index 78afb3a..6c0c2d0 100644 (file)
@@ -106,6 +106,7 @@ typedef struct {
     uint8_t is_running;            // 运行标志
     uint8_t need_stop;             // 停止标志
     uint8_t is_initialized;        // 初始化标志
+    uint8_t interrupt_flag;        // 打断标志,设置时主动重连
     char *recv_buffer;             // 接收缓冲区
     uint32_t reconnect_count;      // 重连次数
     uint32_t last_reconnect_time;  // 上次重连时间
@@ -235,17 +236,38 @@ errcode_t start_all_websocket_servers(void);
 
 errcode_t init_all_websocket_servers(void);
 
-void uapi_start_AI_asr(void);
 
-void uapi_stop_AI_asr(void);
 
 void stop_all_websocket_servers(void);
 
+void destroy_all_websocket_servers(void);
+
+
+
 bool are_all_services_ready(void);
 
 uint8_t get_asr_is_ready_start_old(void);
 
-void destroy_all_websocket_servers(void);
+
+
+void uapi_start_AI_asr_(void);
+
+void uapi_stop_AI_asr_(void);
+
+/**
+ * @brief 设置WebSocket服务器打断标志
+ * @param server_type 服务器类型
+ * @param interrupt 打断标志,1表示需要重连,0表示清除标志
+ * @return errcode_t 错误码
+ */
+errcode_t ws_server_set_interrupt_flag(ws_server_type_t server_type, uint8_t interrupt);
+
+/**
+ * @brief 获取WebSocket服务器打断标志
+ * @param server_type 服务器类型
+ * @return uint8_t 打断标志状态
+ */
+uint8_t ws_server_get_interrupt_flag(ws_server_type_t server_type);
 
 
 #ifdef __cplusplus
index a391099..ba5fe03 100644 (file)
 
 #include "custom_utils.h"
 
+#ifdef SUPPORT_AI_SERVICE
+#include "asr_websocket_server.h"
+#endif
+
+#ifdef SUPPORT_AI_SERVICE
+#include "websocket_server_manager.h"
+#endif
+
 #ifdef FD230_650
 #include "ui_serviceC.h"
 #include "alarm/include/AlarmClockModelC.h"
@@ -398,6 +406,60 @@ static void custom_cmd_service_check_task(void const *arg)
             uapi_check_mic(0);
             break;
 
+case CUSTOM_CMD_MSG_START_AI_ASR:
+#ifdef SUPPORT_AI_SERVICE
+            uapi_start_AI_asr_();
+            PRINT("AI ASR started via custom cmd\n");
+#else
+            PRINT("AI ASR service not supported\n");
+#endif
+            break;
+
+        case CUSTOM_CMD_MSG_STOP_AI_ASR:
+#ifdef SUPPORT_AI_SERVICE
+            uapi_stop_AI_asr_();
+            PRINT("AI ASR stopped via custom cmd\n");
+#else
+            PRINT("AI ASR service not supported\n");
+#endif
+            break;
+
+        case CUSTOM_CMD_MSG_START_ALL_WEBSOCKET_SERVERS:
+#ifdef SUPPORT_AI_SERVICE
+            start_all_websocket_servers();
+            PRINT("All WebSocket servers started via custom cmd\n");
+#else
+            PRINT("WebSocket service not supported\n");
+#endif
+            break;
+
+        case CUSTOM_CMD_MSG_INIT_ALL_WEBSOCKET_SERVERS:
+#ifdef SUPPORT_AI_SERVICE
+            init_all_websocket_servers();
+            PRINT("All WebSocket servers initialized via custom cmd\n");
+#else
+            PRINT("WebSocket service not supported\n");
+#endif
+            break;
+
+        case CUSTOM_CMD_MSG_STOP_ALL_WEBSOCKET_SERVERS:
+#ifdef SUPPORT_AI_SERVICE
+            stop_all_websocket_servers();
+            PRINT("All WebSocket servers stopped via custom cmd\n");
+#else
+            PRINT("WebSocket service not supported\n");
+#endif
+            break;
+
+        case CUSTOM_CMD_MSG_DESTROY_ALL_WEBSOCKET_SERVERS:
+#ifdef SUPPORT_AI_SERVICE
+            destroy_all_websocket_servers();
+            PRINT("All WebSocket servers destroyed via custom cmd\n");
+#else
+            PRINT("WebSocket service not supported\n");
+#endif
+            break;
+
         default:
             PRINT("Unknown CUSTOM_CMD_MSG cmd 0x%02X \r\n", mail.cmd);
             break;
@@ -462,4 +524,56 @@ errcode_t uapi_custom_cmd_service_init(void)
 // void custom_cmd_service_service_suspend(void)
 // {
 //     PRINT("custom_cmd_service_service suspend!\r\n");
-// }
\ No newline at end of file
+// }
+
+#ifdef SUPPORT_AI_SERVICE
+/**
+ * @brief 启动AI ASR服务
+ */
+void uapi_start_AI_asr(void)
+{
+    do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_START_AI_ASR, NULL, 0);
+}
+
+/**
+ * @brief 停止AI ASR服务
+ */
+void uapi_stop_AI_asr(void)
+{
+    do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_STOP_AI_ASR, NULL, 0);
+}
+
+#ifdef SUPPORT_AI_SERVICE
+/**
+ * @brief 启动所有WebSocket服务器
+ */
+void uapi_start_all_websocket_servers(void)
+{
+    do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_START_ALL_WEBSOCKET_SERVERS, NULL, 0);
+}
+
+/**
+ * @brief 初始化所有WebSocket服务器
+ */
+void uapi_init_all_websocket_servers(void)
+{
+    do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_INIT_ALL_WEBSOCKET_SERVERS, NULL, 0);
+}
+
+/**
+ * @brief 停止所有WebSocket服务器
+ */
+void uapi_stop_all_websocket_servers(void)
+{
+    do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_STOP_ALL_WEBSOCKET_SERVERS, NULL, 0);
+}
+
+/**
+ * @brief 销毁所有WebSocket服务器
+ */
+void uapi_destroy_all_websocket_servers(void)
+{
+    do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_DESTROY_ALL_WEBSOCKET_SERVERS, NULL, 0);
+}
+#endif
+#endif
\ No newline at end of file
index b9c93d7..9c6d142 100644 (file)
@@ -171,6 +171,39 @@ errcode_t uapi_create_osThread_custom(app_task_definition_t *task_cfg)
     return ERRCODE_SUCC;
 }
 
+/**
+ * @brief 扩展的任务定义结构体,支持传入实例参数
+ */
+/**
+ * @brief 创建带实例参数的自定义线程
+ * @param task_cfg 扩展的任务配置结构体,包含inst_args参数
+ * @return 成功返回ERRCODE_SUCC,失败返回ERRCODE_FAIL
+ */
+errcode_t uapi_create_osThread_custom_with_args(app_task_definition_ext_t *task_cfg)
+{
+    if (task_cfg == NULL) {
+        return ERRCODE_FAIL;
+    }
+    
+    /* Create queues before tasks in case they are used during initialisation. */
+    if (task_cfg->create_queue_handle) {
+        task_cfg->create_queue_handle();
+    }
+    
+    /* Create tasks */
+    if (task_cfg->use_mem == USE_EXTEND_MEM) {
+        task_cfg->attr.stack_mem = memalign(16, task_cfg->attr.stack_size); // 16字节对齐
+    }
+    
+    /* 创建线程,传入inst_args作为参数 */
+    task_cfg->task_handle = osThreadNew(task_cfg->func, task_cfg->inst_args, &(task_cfg->attr));
+    if (task_cfg->task_handle == NULL) {
+        return ERRCODE_FAIL;
+    }
+    
+    return ERRCODE_SUCC;
+}
+
 errcode_t uapi_terminate_thread(void* thread_id)
 {
     osStatus_t ret = osThreadTerminate((osThreadId_t)thread_id);
index cfbd24c..7936ef9 100644 (file)
@@ -243,6 +243,18 @@ uint32_t uapi_calendar_store_date(void);
 
 #define CUSTOM_CMD_MSG_CONNECT_AG 0x1F
 
+#define CUSTOM_CMD_MSG_START_AI_ASR 0x20
+
+#define CUSTOM_CMD_MSG_STOP_AI_ASR 0x21
+
+#define CUSTOM_CMD_MSG_START_ALL_WEBSOCKET_SERVERS 0x22
+
+#define CUSTOM_CMD_MSG_INIT_ALL_WEBSOCKET_SERVERS 0x23
+
+#define CUSTOM_CMD_MSG_STOP_ALL_WEBSOCKET_SERVERS 0x24
+
+#define CUSTOM_CMD_MSG_DESTROY_ALL_WEBSOCKET_SERVERS 0x25
+
 typedef enum {
     BR_HFP_CONNECT=1,
     BR_HFP_DISCONNECT,
@@ -257,6 +269,18 @@ errcode_t uapi_custom_cmd_service_init(void);
 errcode_t do_custom_cmd_service_check_msg(int cmd, void *params, int paramlen);
 errcode_t do_custom_cmd_service_check_msg_head(int cmd, void *params, int paramlen);
 
+#ifdef SUPPORT_AI_SERVICE
+void uapi_start_AI_asr(void);
+void uapi_stop_AI_asr(void);
+#endif
+
+#ifdef SUPPORT_AI_SERVICE
+void uapi_start_all_websocket_servers(void);
+void uapi_init_all_websocket_servers(void);
+void uapi_stop_all_websocket_servers(void);
+void uapi_destroy_all_websocket_servers(void);
+#endif
+
 /***custom file operate cmd service*/
 #define CUSTOM_FILEOPERATE_MSG_TYPE_SPORTDATA_SAVE 0x01 //运动数据
 #define CUSTOM_FILEOPERATE_MSG_TYPE_HEARTRATE_SAVE 0x02 //心率数据
@@ -445,6 +469,28 @@ void uapi_get_lcd_id(uint32_t *id);
 void uapi_lcd_backlight_on(uint8_t brightness);
 void uapi_lcd_backlight_off(void);
 
+
+/**
+ * @brief 扩展的任务定义结构体,支持传入实例参数
+ */
+typedef struct {
+    osThreadAttr_t attr;                    // 线程属性
+    osThreadFunc_t func;                    // 线程函数
+    uint32_t *task_handle;                  // 任务句柄
+    CreateQueueFunction_t create_queue_handle; // 队列创建函数
+    uint32_t use_mem;                       // 内存使用类型
+    void *inst_args;                        // 实例参数指针
+} app_task_definition_ext_t;
+
+/**
+ * @brief 创建带实例参数的自定义线程
+ * @param task_cfg 扩展的任务配置结构体,包含inst_args参数
+ * @return 成功返回ERRCODE_SUCC,失败返回ERRCODE_FAIL
+ */
+errcode_t uapi_create_osThread_custom_with_args(app_task_definition_ext_t *task_cfg);
+
+
+
 #include "custom_utilscpp.h"