ai对话提交,有bug待调试,与ui协调有问题
authorhcj <1224667075@qq.com>
Sat, 13 Sep 2025 10:14:02 +0000 (18:14 +0800)
committerhcj <1224667075@qq.com>
Sat, 13 Sep 2025 10:14:02 +0000 (18:14 +0800)
22 files changed:
code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceModel.cpp
code/sdk/zhihui/4g/cat1Serviccpp/cat1_UI_hal.cpp [new file with mode: 0644]
code/sdk/zhihui/ai/include/ai_media.h
code/sdk/zhihui/ai/media/CMakeLists.txt
code/sdk/zhihui/ai/media/ai_media_service.cpp
code/sdk/zhihui/ai/media/ai_media_service_ext.cpp [new file with mode: 0644]
code/sdk/zhihui/ai_old/CMakeLists.txt
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/bk_websocket.h
code/sdk/zhihui/ai_old/chat_websocket_server.cpp
code/sdk/zhihui/ai_old/chat_websocket_server.h
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 [new file with mode: 0644]
code/sdk/zhihui/ai_old/websocket_server_manager.cpp [new file with mode: 0644]
code/sdk/zhihui/ai_old/websocket_server_manager.h [new file with mode: 0644]
code/sdk/zhihui/ai_old/zhihui_ws.cpp
code/sdk/zhihui/ai_old/zhihui_ws.h
code/sdk/zhihui/services/ble_service/blemoder/CMakeLists.txt
code/sdk/zhihui/services/ble_service/blemoder/ble_instruct_init.cpp

index 19e457e..7f8bde1 100644 (file)
@@ -186,7 +186,7 @@ namespace OHOS
 #if AI_VOICE_ENABLE
                     uapi_UI_start_asr(GetCurUsing4GAiModelType());
 #endif
-                }
+                                }
                 else
                 {
                     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "init_4gai_task fail!!");
@@ -534,14 +534,6 @@ namespace OHOS
                 return;
             }
             userQuestionStr += str;
-            if (!entryTextViewState)
-            {
-                SendMsgToUIService(UI_AI_JUMP_TO_RESULT_VIEW, 0, nullptr, 0);
-                entryTextViewState = true; // 进入返回结果界面的标志  避免重复发消息
-                usleep(50000);             // 延时等待创建完成,0.05秒
-            }
-            /* -------------------------------------------------------------------------- */
-            SendMsgToUIService(UI_UPDATE_USER_QUESTION_STR, 0, nullptr, 0);
         }
         else if (GetSelect4gorbt() == AI_SELECT_BT)
         {
@@ -552,9 +544,9 @@ namespace OHOS
                 usleep(50000);             // 延时等待创建完成,0.05秒
             }
             /* -------------------------------------------------------------------------- */
-            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "传入的问题:%s", str.c_str());
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "传入的问题:%s", str.c_str());
             userQuestionStr = str;
-            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "拼接的问题:%s", userQuestionStr.c_str());
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "拼接的问题:%s", userQuestionStr.c_str());
             /* -------------------------------------------------------------------------- */
             SendMsgToUIService(UI_UPDATE_USER_QUESTION_STR, 0, nullptr, 0);
         }
@@ -1062,7 +1054,7 @@ namespace OHOS
             {
                 if (AiVoiceModel::GetInstance().is_need_to_jump_result_view())
                 {
-                    SendMsgToUIService(UI_AI_JUMP_TO_RESULT_VIEW, 0, nullptr, 0); // 跳转到结果界面
+                    SendMsgToUIService(UI_AI_JUMP_TO_RESULT_VIEW, 0, nullptr, 0);
                 }
                 return;
             }
@@ -1258,7 +1250,7 @@ namespace OHOS
 #if AI_VOICE_ENABLE
                 uapi_UI_stop_asr();
 #endif
-                AiVoicePresenter::GetInstance()->ChangeViewAndLogicOperator(AIVOICE_LISTENING_VIEWID, AIVOICE_THINKING_VIEWID); // 切换到思考中界面
+                            AiVoicePresenter::GetInstance()->ChangeViewAndLogicOperator(AIVOICE_LISTENING_VIEWID, AIVOICE_THINKING_VIEWID); // 切换到思考中界面
             }
         }
         else
@@ -1361,7 +1353,7 @@ namespace OHOS
 #if AI_VOICE_ENABLE
                     state = get_asr_is_ready_start();
 #endif
-                    if (state)
+                                        if (state)
                     {
                         bool state = true;
                         SendMsgToUIService(UI_AI_JUMP_TO_LISTENING_VIEW, 0, &state, sizeof(bool));
@@ -1656,6 +1648,9 @@ namespace OHOS
         }
         else
         {
+            // if(AiVoiceModel::GetInstance().GetUserQuestionStr() !=)
+            // SendMsgToUIService(UI_UPDATE_USER_QUESTION_STR, 0, nullptr, 0); 
+
             SendMsgToUIService(UI_UPDATE_AI_ANSWER_STR, 0, nullptr, 0);
         }
     }
@@ -1834,7 +1829,7 @@ namespace OHOS
         chat_state = get_ai_chat_service_init_flag();
         tts_state = get_ai_tts_server_init_flag();
 #endif
-        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "asr_state:%d,chat_state:%d,tts_state:%d", asr_state, chat_state, tts_state);
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "asr_state:%d,chat_state:%d,tts_state:%d", asr_state, chat_state, tts_state);
         if ((asr_state == 1) && (chat_state == 1) && (tts_state == 1))
         {
             init_4gai_task = true;
@@ -2008,6 +2003,35 @@ extern "C"
         clear_queue_stream = state;
     }
 
+
+    #ifdef BLE_INSTRUCT
+
+    #include "bleEvent.h"
+    #include "bleInstruct.h"
+
+    void ble_set_ai_Question_str_(char *buf)
+    {
+        OHOS::AiVoiceModel::GetInstance().SetUserQuestionStr(std::string(buf));
+    }
+
+
+    void ble_set_ai_Answer_str_(char *buf,uint8_t type)
+    {
+        OHOS::AiVoiceModel::GetInstance().SetAiAnswerStrStr(std::string(buf),type);
+    }
+
+    extern bleInstruct_t_ bleInstruct_t;
+
+    void ble_AI_init(void)
+    {
+        bleInstruct_t.ble_set_ai_Question_str= ble_set_ai_Question_str_;
+
+        bleInstruct_t.ble_set_ai_Answer_str=ble_set_ai_Answer_str_;
+    }
+
+    #endif
+
+
 #ifdef __cplusplus
 #if __cplusplus
 }
diff --git a/code/sdk/zhihui/4g/cat1Serviccpp/cat1_UI_hal.cpp b/code/sdk/zhihui/4g/cat1Serviccpp/cat1_UI_hal.cpp
new file mode 100644 (file)
index 0000000..e2f2217
--- /dev/null
@@ -0,0 +1,135 @@
+/* BSD Socket API Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <string.h>
+
+#include "wearable_log.h"
+#include "securec.h"
+#include "broadcast_service.h"
+#include "broadcast_feature.h"
+#include "service_id_define.h"
+#include "samgr_lite.h"
+#include "thread_adapter.h"
+#include "graphic_service.h"
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <string.h>
+
+#include "errcode.h"
+#include "errno.h"
+
+#include "cat1_server_hal.h"
+#include "custom_utils.h"
+
+
+static errcode_t calldial_event_notify(char* callno)
+{
+
+    CustomEventPublish(TOPIC_EVENT_CAT1_CALLDIAL,(uint8_t*)callno,strlen(callno)+1);
+    return 0;
+}
+
+
+static errcode_t incomingcall_event_notify(char* callno)
+{
+    CustomEventPublish(TOPIC_EVENT_CAT1_INCOMMING,(uint8_t*)callno,strlen(callno)+1);
+    return 0;
+}
+
+static errcode_t incomed_call_event_notify(char* callno)
+{
+    CustomEventPublish(TOPIC_EVENT_CAT1_CALLCONNTED,(uint8_t*)callno,strlen(callno)+1);
+    return 0;
+}
+
+static errcode_t callend_event_notify(char* callno)
+{
+    CustomEventPublish(TOPIC_EVENT_CAT1_CALLENDED,(uint8_t*)callno,strlen(callno)+1);
+    return 0;
+}
+
+static errcode_t cat1msg_event_notify(char* callno)
+{
+    CustomEventPublish(TOPIC_EVENT_CAT1_SIGNAL_UPDATE,(uint8_t*)callno,strlen(callno)+1);
+    return 0;
+}
+//传地址应设置固定内存,否则异进程内存安全没法保证
+
+// 将 std::string 改为 char 数组
+static char call_number_end[64] = {0};
+static char incomedcall_number_end[64] = {0};
+static char incomingcall_number[64] = {0};
+static char call_number[64] = {0};
+
+int callend_event_sendmsg_toUI(char* callno)
+{
+    /**通过UI事件发送Notify*/
+    strncpy(call_number_end, callno, sizeof(call_number_end) - 1);
+    call_number_end[sizeof(call_number_end) - 1] = '\0';
+    
+    GraphicService::GetInstance()->PostGraphicEvent(std::bind(callend_event_notify, call_number_end));
+    return ERRCODE_SUCC;
+}
+
+int incomedcall_event_sendmsg_toUI(char* callno)
+{
+    /**通过UI事件发送Notify*/
+    strncpy(incomedcall_number_end, callno, sizeof(incomedcall_number_end) - 1);
+    incomedcall_number_end[sizeof(incomedcall_number_end) - 1] = '\0';
+    
+    GraphicService::GetInstance()->PostGraphicEvent(std::bind(incomed_call_event_notify, incomedcall_number_end));
+    return ERRCODE_SUCC;
+}
+
+int incomingcall_event_sendmsg_toUI(char* callno)
+{
+    /**通过UI事件发送Notify*/
+    strncpy(incomingcall_number, callno, sizeof(incomingcall_number) - 1);
+    incomingcall_number[sizeof(incomingcall_number) - 1] = '\0';
+    
+    GraphicService::GetInstance()->PostGraphicEvent(std::bind(incomingcall_event_notify, incomingcall_number));
+    return ERRCODE_SUCC;
+}
+
+int calldial_event_sendmsg_toUI(char* callno)
+{
+    /**通过UI事件发送Notify*/
+    strncpy(call_number, callno, sizeof(call_number) - 1);
+    call_number[sizeof(call_number) - 1] = '\0';
+    
+    // 移除空格
+    char* p = call_number;
+    char* q = call_number;
+    while (*p) {
+        if (*p != ' ') {
+            *q++ = *p;
+        }
+        p++;
+    }
+    *q = '\0';
+    
+    GraphicService::GetInstance()->PostGraphicEvent(std::bind(calldial_event_notify, call_number));
+    return ERRCODE_SUCC;
+}
+
+int cat1_msg_event_sendmsg_toUI(char* callno)
+{
+    /**通过UI事件发送Notify*/
+    GraphicService::GetInstance()->PostGraphicEvent(std::bind(cat1msg_event_notify, callno));
+    return ERRCODE_SUCC;
+}
+
+
+#ifdef __cplusplus
+
+}
+
+#endif /* __cplusplus */
index 1a466fe..34f8a74 100644 (file)
@@ -89,6 +89,37 @@ uint8_t ai_media_get_play_status(void);
  */
 void ai_media_play_buffer(uint8_t *data, uint32_t size);
 
+typedef void (*AIVoiceDataCallback)(const uint8_t* data, uint32_t size, void* userData);
+
+int32_t old_Start_AIVoice(AIVoiceDataCallback dataCallback, void* userData);
+
+/*
+ * @brief 写入音频数据到输出流
+ * @param data 音频数据指针
+ * @param size 音频数据大小
+ * @return 0 成功,-1 失败
+ */
+int32_t AI_WriteAudioData(const uint8_t* data, uint32_t size);
+
+/*
+ * @brief 检查AI语音服务是否正在运行
+ * @return true 正在运行,false 未运行
+ */
+bool AI_IsVoiceServiceRunning(void);
+
+/*
+ * @brief 获取AI语音服务状态信息
+ * @param isRunning 输出参数:是否正在运行
+ * @param hasOutput 输出参数:是否有输出流
+ * @return 0 成功,-1 失败
+ */
+// int32_t AI_GetVoiceServiceStatus(bool* isRunning, bool* hasOutput);
+
+int32_t StopAIVoice(void);
+
+
+int32_t AI_SendAudioDataToQueue(const uint8_t* data, uint32_t size);
+
 #ifdef __cplusplus
 };
 #endif
index cd631ab..f93f445 100644 (file)
@@ -16,10 +16,13 @@ ${ROOT_DIR}/middleware/services/media/foundation/audiomanager/interfaces/kits/au
 ${ROOT_DIR}/middleware/services/media/foundation/audiomanager/frameworks/audiostream/include
 ${ROOT_DIR}/middleware/services/media/foundation/sample/wrapper
 ${ROOT_DIR}/middleware/services/media/foundation/utils/include
+${ROOT_DIR}/include
 )
 
 set(AI_SOURCES
 ${CMAKE_CURRENT_SOURCE_DIR}/ai_media_service.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/ai_media_service_ext.cpp
+
 )
 
 set(SOURCES
index ac80cef..f7e6ec0 100644 (file)
 #include "media_log.h"
 #include "media_thread_adapt.h"
 #include "audio_manager_c_wrapper.h"
+#include "thread_init.h"
+#include "errcode.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
+#include "errcode.h"
 
 using namespace::Audio;
 
@@ -246,17 +249,21 @@ static void CleanupRecordingResources(AIRecordContext *context)
     context->isInitialized = false;
 }
 
+// 全局变量用于传递录制上下文(因为uapi_create_osThread_custom不支持参数传递)
+static AIRecordContext *g_recording_context = nullptr;
+
 /**
  * @brief Recording thread function
- * @param priv Recording context pointer
- * @return nullptr
+ * @param data 线程参数(uapi_create_osThread_custom固定为NULL)
+ * @return void
  */
-static void* RecordingThreadFunc(void* priv)
+static void RecordingThreadFunc(void *data)
 {
-    AIRecordContext *context = (AIRecordContext*)priv;
+    // 由于uapi_create_osThread_custom不支持参数传递,使用全局变量
+    AIRecordContext *context = g_recording_context;
     if (context == nullptr) {
         MEDIA_ERR_LOG("Recording context is null in thread");
-        return nullptr;
+        return;
     }
 
     MEDIA_INFO_LOG("Recording thread started");
@@ -280,12 +287,14 @@ static void* RecordingThreadFunc(void* priv)
             }
         } else {
             // Sleep briefly if no data available
+            printf("AudioStreamInObtainBuffer error\r\n");
             usleep(10000);  // 10ms
         }
     }
 
     MEDIA_INFO_LOG("Recording thread stopped");
-    return nullptr;
+    // 清理全局变量
+    g_recording_context = nullptr;
 }
 
 /**
@@ -409,11 +418,28 @@ void ai_media_record_start(uint8_t* format)
 
     // Start recording thread
     g_recordContext->isRecordingStopped = false;
-    MediaThreadattr attr = { "AIRecordingThread", 0x2000, THREAD_SCHED_INVALID, 0, false };
-    g_recordContext->recordThread = MediaThreadCreate(RecordingThreadFunc, g_recordContext, &attr);
     
-    if (g_recordContext->recordThread == nullptr) {
-        MEDIA_ERR_LOG("Failed to create recording thread");
+    // 设置全局变量供线程函数使用
+    g_recording_context = g_recordContext;
+    
+    // 创建线程配置
+    app_task_definition_t task_cfg;
+    memset(&task_cfg, 0, sizeof(task_cfg));
+    
+    task_cfg.create_queue_handle = NULL;
+    task_cfg.attr.name = "AIRecordingThread";
+    task_cfg.attr.priority = (osPriority_t)16;  // 使用合适的优先级
+    task_cfg.attr.stack_size = 0x2000;  // 8KB栈空间
+    task_cfg.func = RecordingThreadFunc;
+    task_cfg.use_mem = USE_EXTEND_MEM;
+    
+    // 创建线程
+    extern errcode_t uapi_create_osThread_custom(app_task_definition_t* task_cfg);
+    errcode_t ret_errcode_t = uapi_create_osThread_custom(&task_cfg);
+    
+    if (ret_errcode_t != ERRCODE_SUCC) {
+        MEDIA_ERR_LOG("Failed to create recording thread: %d", ret);
+        g_recording_context = nullptr;  // 清理全局变量
         AudioStreamInStop();
         AudioStreamInDeinit();
         g_amInstance.DeactivateAudioInterrupt(g_recordContext->interrupt);
@@ -423,6 +449,9 @@ void ai_media_record_start(uint8_t* format)
         MediaMutexUnLock(g_aiMediaMutex);
         return;
     }
+    
+    // 保存线程句柄(如果需要的话)
+    g_recordContext->recordThread = (void*)task_cfg.task_handle;
 
     g_recordStatus = 1;  // Set recording status
     MediaMutexUnLock(g_aiMediaMutex);
diff --git a/code/sdk/zhihui/ai/media/ai_media_service_ext.cpp b/code/sdk/zhihui/ai/media/ai_media_service_ext.cpp
new file mode 100644 (file)
index 0000000..4150296
--- /dev/null
@@ -0,0 +1,944 @@
+/*
+ * Copyright (c) CompanyNameMagicTag. 2023-2023. All rights reserved.
+ * Description: AI voice conversation sample wrapper
+ * Author: Media Software Group
+ * Create: 2023-07-06
+ */
+
+#include "voice_call_volte_sample_wrapper.h"
+
+#include <climits>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string>
+#include <iostream>
+#include <unistd.h>
+#include <time.h>
+#include "securec.h"
+
+#include "audio_manager.h"
+#include "audio_stream_in.h"
+#include "audio_stream_out.h"
+#include "audio_base_type.h"
+
+#include "media_log.h"
+#include "media_thread_adapt.h"
+#include "audio_manager_c_wrapper.h"
+#include "thread_init.h"
+#include "errcode.h"
+#include "ai_media.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+using namespace::Audio;
+
+#define MEDIA_CMD_LEN_MAX 128
+#define MEDIA_UNUSED(x) ((void)(x))
+
+#define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0]))
+
+const int32_t NUMBER_BASE = 10;
+const int32_t CHANNEL_COUNT = 2;
+const int32_t SAMPLERATE_16000 = 16000;
+const uint32_t AI_VOICE_BUFFER_SIZE = 0x800;  // 2KB buffer for AI voice
+const uint32_t AI_VOICE_QUEUE_SIZE = 10;      // 队列大小
+
+// 定义音频数据回调函数类型
+
+// 定义队列消息结构体
+typedef struct {
+    uint8_t *data;
+    uint32_t size;
+    uint32_t timestamp;
+} AIVoiceQueueMessage;
+
+
+typedef struct {
+    AudioSession sessionId;
+    bool isAIVoiceStopped;
+    MediaThreadCondHandle cond;        // 保留条件变量用于线程同步
+    MediaThreadIdHandle taskHandle;
+    char threadName[32];               // 线程名称,用于验证线程ID
+    uint8_t *dataBuffer;
+    uint32_t bufferSize;
+    AIVoiceDataCallback dataCallback;  // 音频数据回调函数
+    void* callbackUserData;            // 回调函数用户数据
+    osMessageQueueId_t inputQueue;     // 输入播放数据队列
+    uint32_t queueMsgCount;            // 队列消息数量
+} AIVoiceContext;
+
+static MediaMutexHandle g_aiVoiceContextMutex = nullptr;
+static AIVoiceContext *g_aiVoiceContext = nullptr;
+
+// 全局互斥锁初始化函数(只创建一次,不释放)
+static bool InitGlobalMutex(void)
+{
+    if (g_aiVoiceContextMutex == nullptr) {
+        g_aiVoiceContextMutex = MediaMutexCreate(nullptr);
+        if (g_aiVoiceContextMutex == nullptr) {
+            MEDIA_ERR_LOG("Failed to create global AI voice context mutex");
+            return false;
+        }
+        MEDIA_INFO_LOG("Global AI voice context mutex created successfully");
+    }
+    return true;
+}
+
+// 获取全局互斥锁(线程安全,只创建一次)
+static MediaMutexHandle GetGlobalMutex(void)
+{
+    if (g_aiVoiceContextMutex == nullptr) {
+        // 使用简单的初始化,避免重复创建
+        static bool init_once = false;
+        if (!init_once) {
+            init_once = true;
+            g_aiVoiceContextMutex = MediaMutexCreate(nullptr);
+            if (g_aiVoiceContextMutex != nullptr) {
+                MEDIA_INFO_LOG("Global AI voice context mutex created successfully");
+            } else {
+                MEDIA_ERR_LOG("Failed to create global AI voice context mutex");
+            }
+        }
+    }
+    return g_aiVoiceContextMutex;
+}
+
+// 注意:全局互斥锁不释放,程序运行期间持续存在
+
+static std::shared_ptr<AudioStreamIn> g_streamIn = nullptr;
+static std::shared_ptr<AudioStreamOut> g_streamOut = nullptr;
+
+// 注意:g_aiVoiceContext 已在上方定义,这里不需要重复定义
+
+
+
+typedef struct {
+    char cmd[MEDIA_CMD_LEN_MAX];
+    int32_t (*func)(const char **param);
+} FuncsMap;
+
+
+static int32_t CreateAIVoiceInputThread(AIVoiceContext *context);
+
+static void AIVoiceInputThreadFunc(void *data);
+
+// 队列创建函数
+static void CreateAIVoiceQueue(void)
+{
+    if (g_aiVoiceContext != nullptr) {
+        // 创建消息队列
+        g_aiVoiceContext->inputQueue = osMessageQueueNew(AI_VOICE_QUEUE_SIZE, sizeof(AIVoiceQueueMessage), NULL);
+        if (g_aiVoiceContext->inputQueue == NULL) {
+            MEDIA_ERR_LOG("Failed to create AI voice input queue");
+        } else {
+            g_aiVoiceContext->queueMsgCount = 0;
+            MEDIA_INFO_LOG("AI voice input queue created successfully");
+        }
+    }
+}
+
+// 验证线程名和ID是否匹配,避免ID被复用
+static bool IsValidThread(osThreadId_t threadId, const char* expectedName)
+{
+    if (threadId == NULL || expectedName == NULL) {
+        return false;
+    }
+    
+    // 首先检查线程状态,如果线程已经不存在,直接返回false
+    osThreadState_t threadState = osThreadGetState(threadId);
+    if (threadState == osThreadError) {
+        return false;  // 线程不存在或无效
+    }
+    
+    // 获取线程名称
+    const char* actualName = osThreadGetName(threadId);
+    if (actualName == NULL) {
+        return false;
+    }
+    
+    // 比较线程名称
+    bool nameMatch = (strcmp(actualName, expectedName) == 0);
+    
+    // 调试信息(可选,在需要时启用)
+    // printf("Thread validation: ID=%p, Expected='%s', Actual='%s', State=%d, Match=%s\r\n", 
+    //        threadId, expectedName, actualName, threadState, nameMatch ? "YES" : "NO");
+    
+    return nameMatch;
+}
+
+static void DeinitAIVoiceResources(AIVoiceContext *context)
+{
+    (void)g_streamIn.reset();
+    (void)g_streamOut.reset();
+    
+    if (context != nullptr) {
+        if (context->dataBuffer != nullptr) {
+            free(context->dataBuffer);
+            context->dataBuffer = nullptr;
+        }
+        
+        // 清理队列
+        if (context->inputQueue != NULL) {
+            // 清空队列中的所有消息
+            AIVoiceQueueMessage msg;
+            while (osMessageQueueGet(context->inputQueue, &msg, NULL, 0) == osOK) {
+                if (msg.data != nullptr) {
+                    free(msg.data);
+                }
+            }
+            
+            // 删除队列
+            osMessageQueueDelete(context->inputQueue);
+            context->inputQueue = NULL;
+            MEDIA_INFO_LOG("AI voice input queue deleted");
+        }
+    }
+}
+
+static bool InitAIVoiceResources(AIVoiceContext *context)
+{
+    context->cond = MediaThreadCondCreate();
+    if (context->cond == nullptr) {
+        MEDIA_ERR_LOG("create Voice Call Volte thread cond failed");
+        return false;
+    }
+    
+    // Allocate data buffer for AI voice
+    context->dataBuffer = (uint8_t*)malloc(AI_VOICE_BUFFER_SIZE);
+    if (context->dataBuffer == nullptr) {
+        MEDIA_ERR_LOG("Failed to allocate AI voice buffer");
+        MediaThreadCondDestroy(&context->cond);
+        return false;
+    }
+    
+    context->bufferSize = AI_VOICE_BUFFER_SIZE;
+    return true;
+}
+
+static int32_t LocalAIVoiceStart(AIVoiceContext *context)
+{
+    int32_t ret = 0;
+    // AudioManagerSetDeviceConnectionState(IN_MODEM, AUDIO_DEVICE_CONNECTED);
+    // if (ret != 0) {
+    //     MEDIA_ERR_LOG("set modem in device connect failed");
+    // }
+
+    // ret = AudioManagerSetDeviceConnectionState(OUT_MODEM, AUDIO_DEVICE_CONNECTED);
+    // if (ret != 0) {
+    //     MEDIA_ERR_LOG("set modem out device connect failed");
+    // }
+
+    // create downlink AudioStreamIn
+    CapturerInputConfig captureConfig = {};
+    captureConfig.audioFormat = MP3;
+    captureConfig.channelCount = 1;
+    captureConfig.linkDir = AUDIO_DOWN_LINK;
+    captureConfig.sampleRate = SAMPLERATE_16000;
+    captureConfig.sessionID = context->sessionId;
+    captureConfig.streamType = AUDIO_STREAM_VOICE_ASSISTANT;
+
+    ret = AudioStreamInInit(captureConfig);
+    if (ret != 0) {
+        MEDIA_ERR_LOG("audio stream in init failed");
+    }
+
+    // create uplink AudioStreamOut
+    AudioRendererConfig renderConfig = {};
+    renderConfig.audioFormat = MP3;
+    renderConfig.channelCount = 1;
+    renderConfig.linkDir = AUDIO_UP_LINK;
+    renderConfig.sampleRate = SAMPLERATE_16000;
+    renderConfig.sessionID = context->sessionId;
+    renderConfig.streamType = AUDIO_STREAM_VOICE_ASSISTANT;
+
+    ret = AudioStreamOutInit(renderConfig);
+    if (ret != 0) {
+        MEDIA_ERR_LOG("audio stream out init failed");
+    }
+
+    ret = AudioStreamInStart();
+    if (ret != 0) {
+        MEDIA_ERR_LOG("audio stream in start failed");
+    }
+
+    ret = AudioStreamOutPlay();
+    if (ret != 0) {
+        MEDIA_ERR_LOG("audio stream out play failed");
+    }
+
+    // Create input thread for data processing
+    ret = CreateAIVoiceInputThread(context);
+    if (ret != 0) {
+        MEDIA_ERR_LOG("Failed to create AI voice input thread");
+        return ret;
+    }
+    
+    return ret;
+}
+
+static int32_t LocalAIVoiceStop(void)
+{
+    int32_t ret = AudioStreamInStop();
+    if (ret != 0) {
+        MEDIA_ERR_LOG("audio stream in stop failed");
+    }
+
+    ret = AudioStreamOutStop();
+    if (ret != 0) {
+        MEDIA_ERR_LOG("audio stream out stop failed");
+    }
+
+    ret = AudioStreamInDeinit();
+    if (ret != 0) {
+        MEDIA_ERR_LOG("audio stream in release failed");
+    }
+
+    ret = AudioStreamOutDeinit();
+    if (ret != 0) {
+        MEDIA_ERR_LOG("audio stream out release failed");
+    }
+    return ret;
+}
+
+/**
+ * @brief Create AI voice input thread
+ * @param context AI voice context
+ * @return 0 on success, -1 on failure
+ */
+static int32_t CreateAIVoiceInputThread(AIVoiceContext *context)
+{
+    if (context == nullptr) {
+        MEDIA_ERR_LOG("AI voice context is null");
+        return -1;
+    }
+
+    // 设置全局变量供线程函数使用(使用统一的全局变量)
+    // g_aiVoiceContext 已经在上面设置过了
+    
+    // 创建线程配置
+    app_task_definition_t task_cfg;
+    memset(&task_cfg, 0, sizeof(task_cfg));
+    
+    task_cfg.create_queue_handle = NULL;
+    task_cfg.attr.name = "AIVoiceInputThread";
+    task_cfg.attr.priority = (osPriority_t)16;  // 使用合适的优先级
+    task_cfg.attr.stack_size = 0x2000;  // 8KB栈空间
+    task_cfg.func = AIVoiceInputThreadFunc;
+    task_cfg.use_mem = USE_EXTEND_MEM;
+    
+    // 创建线程
+    extern errcode_t uapi_create_osThread_custom(app_task_definition_t* task_cfg);
+    errcode_t ret_errcode_t = uapi_create_osThread_custom(&task_cfg);
+    
+    if (ret_errcode_t != ERRCODE_SUCC) {
+        MEDIA_ERR_LOG("Failed to create AI voice input thread: %d", ret_errcode_t);
+        // 清理全局变量
+        return -1;
+    }
+    
+    // 保存线程句柄
+    context->taskHandle = (void*)task_cfg.task_handle;
+    
+    MEDIA_INFO_LOG("AI voice input thread created successfully");
+    return 0;
+}
+
+/**
+ * @brief AI voice input stream reading thread function
+ * @param data 线程参数(uapi_create_osThread_custom固定为NULL)
+ * @return void
+ */
+static void AIVoiceInputThreadFunc(void *data)
+{
+    // 由于uapi_create_osThread_custom不支持参数传递,使用全局变量
+    AIVoiceContext *context = g_aiVoiceContext;
+    if (context == nullptr) {
+        MEDIA_ERR_LOG("AI voice context is null in thread");
+        return;
+    }
+
+    MEDIA_INFO_LOG("AI voice input thread started");
+
+    while (true) {
+        MediaMutexHandle mutex = GetGlobalMutex();
+        if (mutex != nullptr) {
+            MediaMutexLock(mutex);
+            if (context->isAIVoiceStopped) {
+                MediaMutexUnLock(mutex);
+                break;
+            }
+            MediaMutexUnLock(mutex);
+        }
+
+        // Obtain audio data from input stream
+        uint32_t readSize = context->bufferSize;
+        int32_t ret = AudioStreamInObtainBuffer(context->dataBuffer, &readSize);
+        
+        if (ret == 0 && readSize > 0) {
+            // 调用音频数据回调函数
+            if (context->dataCallback != nullptr) {
+                context->dataCallback(context->dataBuffer, readSize, context->callbackUserData);
+            }
+            
+            // Write audio data to output stream (echo back)
+            // int32_t writeRet = AudioStreamOutStreamWrite(context->dataBuffer, readSize);
+            // if (readSize != 0) {
+            //     MEDIA_ERR_LOG("Failed to write audio data to output stream, ret=%d", readSize);
+            // }
+            
+        } 
+        usleep(10000);  // 10ms
+        }
+
+
+    MEDIA_INFO_LOG("AI voice input thread stopped");
+    // 清理全局变量
+    // g_aiVoiceContext 的清理由主线程负责
+}
+
+static int32_t RunAIVoice(AIVoiceContext *context)
+{
+    bool success = InitAIVoiceResources(context);
+    if (!success) {
+        MEDIA_ERR_LOG("init AI voice resources failed");
+        return -1;
+    }
+    int32_t ret = LocalAIVoiceStart(context);
+    if (ret != 0) {
+        return ret;
+    }
+
+// Wait for stop signal and process queue data
+    MEDIA_INFO_LOG("RunAIVoice: waiting for queue data...");
+    
+    while (!context->isAIVoiceStopped) {
+        if (context->inputQueue != NULL) {
+            AIVoiceQueueMessage msg;
+            osStatus_t status = osMessageQueueGet(context->inputQueue, &msg, NULL, 100); // 100ms超时
+            
+            if (status == osOK) {
+                // 成功接收到队列数据
+                MEDIA_INFO_LOG("RunAIVoice: received queue data: size=%u, timestamp=%u", msg.size, msg.timestamp);
+                
+                // 处理接收到的音频数据
+                if (msg.data != nullptr && msg.size > 0) {
+                    // 写入音频数据到输出流
+                    AI_WriteAudioData(msg.data,msg.size);
+                    
+                    // 释放消息数据内存
+                    free(msg.data);
+                }
+                
+                // 更新队列消息计数
+                if (context->queueMsgCount > 0) {
+                    context->queueMsgCount--;
+                }
+            } else if (status == osErrorTimeout) {
+                // 超时,继续循环检查停止标志
+                continue;
+            } else {
+                // 其他错误
+                MEDIA_ERR_LOG("RunAIVoice: failed to get message from queue: %d", status);
+                usleep(10000); // 10ms延时
+            }
+        } else {
+            // 队列未创建,使用条件变量等待
+            MediaMutexHandle mutex = GetGlobalMutex();
+            if (mutex != nullptr) {
+                MediaMutexLock(mutex);
+                if (!context->isAIVoiceStopped) {
+                    MediaThreadCondWait(context->cond, mutex);
+                }
+                MediaMutexUnLock(mutex);
+            }
+        }
+    }
+
+    LocalAIVoiceStop();
+    DeinitAIVoiceResources(context);
+    return 0;
+}
+
+static bool RequsetAudioFocus(AIVoiceContext *context)
+{
+    bool success = AudioManagerInit();
+    if (!success) {
+        MEDIA_ERR_LOG("audiomanager init failed");
+        return false;
+    }
+
+    AudioSession sessionId = AudioManagerMakeSessionId();
+    if (sessionId == AUDIO_SESSION_ID_NONE) {
+        MEDIA_ERR_LOG("audio session id invalid");
+        return false;
+    }
+
+    if (AudioManagerActivateInterrupt(AUDIO_STREAM_VOICE_ASSISTANT, sessionId) == INTERRUPT_FAILED) {
+        MEDIA_ERR_LOG("activate audio interrupt failed");
+        return false;
+    }
+
+    context->sessionId = sessionId;
+
+    return true;
+}
+
+static bool ReleaseAudioFocus(void)
+{
+    if (AudioManagerDeactivateInterrupt() != 0) {
+        MEDIA_ERR_LOG("deactivate audio interrupt failed");
+        return false;
+    }
+    return true;
+}
+
+
+static void AIVoiceThread(void *priv)
+{
+    // 由于uapi_create_osThread_custom不支持参数传递,使用全局变量
+    AIVoiceContext *context = g_aiVoiceContext;
+    if (context == nullptr) {
+        MEDIA_ERR_LOG("AI voice context is null in thread");
+        return;
+    }
+
+    bool success = RequsetAudioFocus(context);
+    if (!success) {
+        MEDIA_ERR_LOG("requset audio focus failed");
+        return;
+    }
+
+    int32_t ret = RunAIVoice(context);
+    if (ret != 0) {
+        MEDIA_ERR_LOG("run AI voice failed");
+        (void)ReleaseAudioFocus();
+        return;
+    }
+
+    success = ReleaseAudioFocus();
+    if (!success) {
+        MEDIA_ERR_LOG("release audio focus failed");
+    }
+    // 简单清理,避免复杂的互斥锁操作
+    printf("AI voice thread cleanup completed\r\n");
+}
+int32_t old_Start_AIVoice(AIVoiceDataCallback dataCallback, void* userData)
+{
+    MEDIA_ERR_LOG("StartAIVoice");
+    app_task_definition_t task_cfg;
+     errcode_t ret_errcode_t;
+
+    // 获取全局互斥锁(自动初始化)
+    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("invalid operation");
+        goto EXIT;
+    }
+    g_aiVoiceContext = (AIVoiceContext *)malloc(sizeof(AIVoiceContext));
+    if (g_aiVoiceContext == nullptr) {
+        MEDIA_ERR_LOG("malloc failed");
+        goto EXIT;
+    }
+    if (memset_s(g_aiVoiceContext, sizeof(AIVoiceContext), 0, sizeof(AIVoiceContext)) != EOK) {
+        MEDIA_ERR_LOG("memset_s failed");
+        goto EXIT;
+    }
+    
+    // 设置回调函数
+    g_aiVoiceContext->dataCallback = dataCallback;
+    g_aiVoiceContext->callbackUserData = userData;
+    
+    MediaMutexUnLock(mutex);
+    MediaThreadJoin(&g_aiVoiceContext->taskHandle);
+
+    MEDIA_ERR_LOG("g_aiVoiceContext->taskHandle");
+
+    // 设置全局变量供线程函数使用(g_aiVoiceContext 已经设置好了)
+    
+    // 创建线程配置
+    memset(&task_cfg, 0, sizeof(task_cfg));
+    
+    task_cfg.create_queue_handle = CreateAIVoiceQueue;  // 设置队列创建函数
+    task_cfg.attr.name = "AIVoiceThread";
+    task_cfg.attr.priority = (osPriority_t)16;  // 使用合适的优先级
+    task_cfg.attr.stack_size = 0x2000;  // 8KB栈空间
+    task_cfg.func = AIVoiceThread;
+    task_cfg.use_mem = USE_EXTEND_MEM;
+    
+    // 创建线程
+    extern errcode_t uapi_create_osThread_custom(app_task_definition_t* task_cfg);
+    ret_errcode_t= uapi_create_osThread_custom(&task_cfg);
+    
+    if (ret_errcode_t != ERRCODE_SUCC) {
+        MEDIA_ERR_LOG("Failed to create AI voice thread: %d", ret_errcode_t);
+        free(g_aiVoiceContext);
+        g_aiVoiceContext = nullptr;
+        return -1;
+    }
+    
+    // 保存线程句柄和名称
+    g_aiVoiceContext->taskHandle = (void*)task_cfg.task_handle;
+    strncpy(g_aiVoiceContext->threadName, task_cfg.attr.name, sizeof(g_aiVoiceContext->threadName) - 1);
+    g_aiVoiceContext->threadName[sizeof(g_aiVoiceContext->threadName) - 1] = '\0';  // 确保字符串结束
+    
+    MEDIA_INFO_LOG("AI voice thread created successfully with name: %s", g_aiVoiceContext->threadName);
+    return 0;
+EXIT:
+    // 清理已分配的资源
+    if (g_aiVoiceContext != nullptr) {
+        DeinitAIVoiceResources(g_aiVoiceContext);
+        free(g_aiVoiceContext);
+        g_aiVoiceContext = nullptr;
+    }
+    MediaMutexUnLock(mutex);
+    return -1;
+}
+
+
+int32_t StopAIVoice(void)
+{
+    AIVoiceContext *context = nullptr;
+    
+    // 获取全局互斥锁(自动初始化)
+    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, execute start command first");
+        MediaMutexUnLock(mutex);
+        return -1;
+    }
+    
+    if (g_aiVoiceContext->isAIVoiceStopped) {
+        MEDIA_ERR_LOG("AI voice already stopped");
+        MediaMutexUnLock(mutex);
+        return 0;
+    }
+    
+    // 保存上下文指针
+    context = g_aiVoiceContext;
+    
+    // 设置停止标志(在全局锁保护下)
+    context->isAIVoiceStopped = true;
+    
+    // 释放全局互斥锁
+    MediaMutexUnLock(g_aiVoiceContextMutex);
+    
+    // 等待线程结束 - 使用 osThread 接口
+    printf("Waiting for AI voice thread to stop...\r\n");
+    
+    if (context != nullptr && context->taskHandle != nullptr) {
+        osThreadId_t threadId = (osThreadId_t)context->taskHandle;
+        
+        // 验证线程ID和名称是否匹配,避免ID被复用
+        if (!IsValidThread(threadId, context->threadName)) {
+            printf("Thread ID may have been reused, thread name mismatch. Expected: %s\r\n", context->threadName);
+            printf("Assuming thread already stopped due to ID reuse\r\n");
+        } else {
+            printf("Thread validation passed, waiting for thread: %s\r\n", context->threadName);
+            
+            // 首先尝试使用 osThreadJoin 等待线程结束
+            osStatus_t joinStatus = osThreadJoin(threadId);
+            if (joinStatus == osOK) {
+                printf("AI voice thread stopped successfully (osThreadJoin)\r\n");
+            } else {
+                // 如果 osThreadJoin 不可用或失败,使用状态检查
+                printf("osThreadJoin failed (%d), using state check...\r\n", joinStatus);
+                
+                // 使用 osThreadGetState 检查线程状态
+                for (int i = 0; i < 50; i++) {
+                    usleep(100000); // 100ms
+                    
+                    // 再次验证线程,防止在等待过程中ID被复用
+                    if (!IsValidThread(threadId, context->threadName)) {
+                        printf("Thread ID reused during wait, stopping check\r\n");
+                        break;
+                    }
+                    
+                    osThreadState_t threadState = osThreadGetState(threadId);
+                    
+                    // 检查线程状态,如果线程不存在或已终止,则认为已停止
+                    bool thread_running = (threadState == osThreadReady || 
+                                         threadState == osThreadRunning || 
+                                         threadState == osThreadBlocked);
+                    
+                    printf("Waiting... %d/50 (state: %d, running: %s)\r\n", 
+                           i + 1, threadState, thread_running ? "yes" : "no");
+                    
+                    if (!thread_running) {
+                        printf("AI voice thread stopped successfully (state check)\r\n");
+                        break;
+                    }
+                }
+            }
+        }
+    } else {
+        printf("No valid thread handle, assuming thread already stopped\r\n");
+    }
+    
+    // 重新获取全局互斥锁进行最终清理
+    MediaMutexLock(g_aiVoiceContextMutex);
+    
+    // 清理线程相关资源
+    if (context != nullptr) {
+        // 首先清理AI语音资源(包括队列)
+        DeinitAIVoiceResources(context);
+        
+        // 清理线程同步资源
+        if (context->cond != nullptr) {
+            (void)MediaThreadCondDestroy(&context->cond);
+        }
+        
+        // 释放上下文内存
+        free(context);
+        g_aiVoiceContext = nullptr;
+    }
+    
+    MediaMutexUnLock(g_aiVoiceContextMutex);
+    
+    // 注意:全局互斥锁不释放,程序运行期间持续存在
+    
+    printf("AI voice stopped and resources cleaned up\r\n");
+    return 0;
+}
+
+// 示例音频数据回调函数
+static void ExampleAIVoiceDataCallback(const uint8_t* data, uint32_t size, void* userData)
+{
+    MEDIA_INFO_LOG("Received audio data: size=%u bytes", size);
+    // 在这里处理音频数据,例如:
+    // - 发送到AI语音识别服务
+    // - 保存到文件
+    // - 进行音频处理等
+    // 注意:data指针指向的缓冲区在回调函数返回后可能被释放,如需保存数据请复制
+}
+
+// 使用示例:
+// int32_t result = old_Start_AIVoice(ExampleAIVoiceDataCallback, nullptr);
+// 
+// 队列使用示例:
+// uint8_t audioData[] = {0x01, 0x02, 0x03, 0x04};
+// int32_t sendResult = AI_SendAudioDataToQueue(audioData, sizeof(audioData));
+// 
+// 获取队列状态:
+// uint32_t queueSize, queueCapacity;
+// AI_GetQueueStatus(&queueSize, &queueCapacity);
+
+/**
+ * @brief 写入音频数据到输出流
+ * @param data 音频数据指针
+ * @param size 音频数据大小
+ * @return 0 成功,-1 失败
+ */
+int32_t AI_WriteAudioData(const uint8_t* data, uint32_t size)
+{
+    if (data == nullptr || size == 0) {
+        MEDIA_ERR_LOG("Invalid audio data parameters");
+        return -1;
+    }
+    AI_WRITE:
+    // 获取全局互斥锁(自动初始化)
+    MediaMutexHandle mutex = GetGlobalMutex();
+    if (mutex == nullptr) {
+        MEDIA_ERR_LOG("Failed to get global mutex");
+        return -1;
+    }
+    
+    // 检查AI语音上下文是否存在
+    MediaMutexLock(mutex);
+    if (g_aiVoiceContext == nullptr) {
+        MEDIA_ERR_LOG("AI voice context is null, please start AI voice first");
+        MediaMutexUnLock(mutex);
+        return -1;
+    }
+    MediaMutexUnLock(g_aiVoiceContextMutex);
+
+    // 写入音频数据到输出流
+    int32_t ret = AudioStreamOutStreamWrite(data, size);
+    if (ret != 0) {
+        // MEDIA_ERR_LOG("Failed to write audio data to output stream, ret=%d", ret);
+        usleep(100000); 
+        // return -1;
+        goto AI_WRITE;
+    }
+    
+    MEDIA_INFO_LOG("Successfully wrote %u bytes of audio data to output stream", size);
+    return 0;
+}
+
+/**
+ * @brief 检查AI语音服务是否正在运行
+ * @return true 正在运行,false 未运行
+ */
+bool AI_IsVoiceServiceRunning(void)
+{
+    bool isRunning = false;
+    
+    // 获取全局互斥锁(自动初始化)
+    MediaMutexHandle mutex = GetGlobalMutex();
+    if (mutex == nullptr) {
+        return false;  // 互斥锁创建失败,服务未运行
+    }
+    
+    MediaMutexLock(mutex);
+    if (g_aiVoiceContext != nullptr && !g_aiVoiceContext->isAIVoiceStopped) {
+        isRunning = true;
+    }
+    MediaMutexUnLock(mutex);
+    
+    return isRunning;
+}
+
+/**
+ * @brief 发送音频数据到AI语音播放队列
+ * @param data 音频数据指针
+ * @param size 音频数据大小
+ * @return 0 成功,-1 失败
+ */
+int32_t AI_SendAudioDataToQueue(const uint8_t* data, uint32_t size)
+{
+    if (data == nullptr || size == 0) {
+        MEDIA_ERR_LOG("Invalid audio data parameters");
+        return -1;
+    }
+    
+    MediaMutexHandle mutex = GetGlobalMutex();
+    if (mutex == nullptr) {
+        MEDIA_ERR_LOG("Failed to get global mutex");
+        return -1;
+    }
+    
+    MediaMutexLock(mutex);
+    if (g_aiVoiceContext == nullptr || g_aiVoiceContext->inputQueue == NULL) {
+        MEDIA_ERR_LOG("AI voice context or queue is null, please start AI voice first");
+        MediaMutexUnLock(mutex);
+        return -1;
+    }
+    
+    // 分配内存并复制数据
+    uint8_t *dataCopy = (uint8_t*)malloc(size);
+    if (dataCopy == nullptr) {
+        MEDIA_ERR_LOG("Failed to allocate memory for audio data");
+        MediaMutexUnLock(mutex);
+        return -1;
+    }
+    
+    memcpy(dataCopy, data, size);
+    
+    // 创建队列消息
+    AIVoiceQueueMessage msg;
+    msg.data = dataCopy;
+    msg.size = size;
+    msg.timestamp = (uint32_t)time(NULL);
+    
+    // 发送消息到队列
+    osStatus_t status = osMessageQueuePut(g_aiVoiceContext->inputQueue, &msg, 0, 0);
+    if (status == osOK) {
+        g_aiVoiceContext->queueMsgCount++;
+        MEDIA_INFO_LOG("Successfully sent %u bytes to AI voice queue", size);
+        MediaMutexUnLock(mutex);
+        return 0;
+    } else {
+        MEDIA_ERR_LOG("Failed to send data to queue: %d", status);
+        free(dataCopy);  // 释放分配的内存
+        MediaMutexUnLock(mutex);
+        return -1;
+    }
+}
+
+/**
+ * @brief 获取AI语音队列状态
+ * @param queueSize 输出参数:队列当前大小
+ * @param queueCapacity 输出参数:队列容量
+ * @return 0 成功,-1 失败
+ */
+int32_t AI_GetQueueStatus(uint32_t* queueSize, uint32_t* queueCapacity)
+{
+    if (queueSize == nullptr || queueCapacity == nullptr) {
+        MEDIA_ERR_LOG("Invalid output parameters");
+        return -1;
+    }
+    
+    MediaMutexHandle mutex = GetGlobalMutex();
+    if (mutex == nullptr) {
+        MEDIA_ERR_LOG("Failed to get global mutex");
+        return -1;
+    }
+    
+    MediaMutexLock(mutex);
+    if (g_aiVoiceContext == nullptr || g_aiVoiceContext->inputQueue == NULL) {
+        *queueSize = 0;
+        *queueCapacity = 0;
+        MediaMutexUnLock(mutex);
+        return -1;
+    }
+    
+    *queueSize = g_aiVoiceContext->queueMsgCount;
+    *queueCapacity = AI_VOICE_QUEUE_SIZE;
+    MediaMutexUnLock(mutex);
+    
+    return 0;
+}
+
+/**
+ * @brief 获取AI语音服务状态信息
+ * @param isRunning 输出参数:是否正在运行
+ * @param hasOutput 输出参数:是否有输出流
+ * @return 0 成功,-1 失败
+ */
+// int32_t AI_GetVoiceServiceStatus(bool* isRunning, bool* hasOutput)
+// {
+//     if (isRunning == nullptr || hasOutput == nullptr) {
+//         MEDIA_ERR_LOG("Invalid output parameters");
+//         return -1;
+//     }
+    
+//     MediaMutexLock(g_aiVoiceContextMutex);
+//     // if (g_aiVoiceContext != nullptr) {
+//     //     *isRunning = !g_aiVoiceContext->isAIVoiceStopped;
+//     //     // *hasOutput = (g_streamOut != nullptr);
+//     // } else {
+//     //     *isRunning = false;
+//     //     *hasOutput = false;
+//     // }
+//     MediaMutexUnLock(g_aiVoiceContextMutex);
+    
+//     return 0;
+// }
+
+/**
+ * @brief 清理AI语音模块资源(程序退出时调用)
+ * @return 0 成功,-1 失败
+ */
+int32_t AI_CleanupModule(void)
+{
+    // 如果AI语音服务还在运行,先停止它
+    if (AI_IsVoiceServiceRunning()) {
+        MEDIA_INFO_LOG("AI voice service is still running, stopping it first...");
+        StopAIVoice();
+    }
+    
+    // 注意:全局互斥锁不释放,程序运行期间持续存在
+    
+    MEDIA_INFO_LOG("AI voice module cleanup completed");
+    return 0;
+}
+
+#ifdef __cplusplus
+};
+#endif
index ae9d840..226a3b6 100644 (file)
@@ -22,6 +22,8 @@ ${CMAKE_CURRENT_SOURCE_DIR}/zhihui_ai_server.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/asr_websocket_server.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/tts_websocket_server.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/chat_websocket_server.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/websocket_server_example.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/websocket_server_manager.cpp
 )
 
 set(COMPONENT_PUBLIC_CCFLAGS
index fdc572b..17743ea 100644 (file)
@@ -10,6 +10,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#include "ai_core_types.h"
+#include "websocket_server_manager.h"
+
 // #include "phoneaddressmodel.h" // Commented out due to missing header
 
 #ifdef __cplusplus
@@ -67,7 +70,7 @@ static int ConvertCmdToParam(uint8_t *para, uint32_t paraLen,
 extern void uapi_set4GCapability(bool isopen);
 extern bool init_ai_task(uint8_t type);
 extern errcode_t chat_server_init(void);
-extern bool ai_chat_send_txt(uint8_t type,char *msg);
+// extern bool ai_chat_send_txt(uint8_t type,char *msg);
 extern bool uapi_start_tts(void);
 extern void uapi_start_tts_single();
 extern void uapi_UI_start_asr(uint8_t type);
@@ -126,7 +129,7 @@ static uint32_t ai_msg(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
         printf("CAT1TEST ATCMD Convert Command Failed\n");
         return ERRCODE_FAIL;
     }
-    ai_chat_send_txt(0,(char *)argv[0]);
+    // ai_chat_send_txt(0, (char *)argv[0], NULL);
     return 0;
 }
 
@@ -335,6 +338,73 @@ static uint32_t stop_websocket_test_cmd(uint8_t *para, uint32_t paraLen, char *s
     return ERRCODE_SUCC;
 }
 
+static uint32_t startserver(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    init_all_websocket_servers();
+    start_all_websocket_servers();
+    return 0;
+}
+
+
+static uint32_t StartTranscription(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    uapi_start_asr_StartTranscription();
+    return 0;
+}
+
+
+static uint32_t STOPTranscription(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    uapi_stop_asr_StopTranscription();
+    return 0;
+}
+extern void msleep(uint32_t ms);
+
+static uint32_t STOPserver(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    stop_all_websocket_servers();
+    msleep(1000);
+    destroy_all_websocket_servers();
+    return 0;
+}
+
+
 static uint32_t websocket_status(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
 {
     UNUSED(strCommonCmd);
@@ -369,6 +439,13 @@ static const at_cmd_table_t g_ai_old_cmd[] = {
     { (char *)"AT^TESTWEBSOCKET", test_websocket, (char *)"1" },
     { (char *)"AT^STOPWEBSOCKET", stop_websocket_test_cmd, (char *)"1" },
     { (char *)"AT^WEBSOCKETSTATUS", websocket_status, (char *)"1" },
+    { (char *)"AT^WEBSOCKETSTART", startserver, (char *)"1" },
+    { (char *)"AT^STARTTRAN", StartTranscription, (char *)"1" },
+    { (char *)"AT^STOPTRAN", STOPTranscription, (char *)"1" },
+    { (char *)"AT^WEBSOCKSTOP", STOPserver, (char *)"1" },
+    
+    
+    
 };
 
 at_cmd_table_t *get_ai_old_cmd_table(uint32_t *cmd_count)
index 840675b..d15c214 100644 (file)
@@ -143,8 +143,8 @@ void uapi_UI_stop_asr(void)
     if(strlen(result_str_asr))
     {
         // 发送ASR结果到聊天服务
-        extern bool ai_chat_send_txt(uint8_t type, char *msg);
-        ai_chat_send_txt(0, result_str_asr);
+        // extern bool ai_chat_send_txt(uint8_t type, char *msg);
+        // ai_chat_send_txt(0, result_str_asr, NULL);
         ble_set_ai_Question_str(result_str_asr);
         
         memset(result_str_asr, 0, AI_RESULT_STR_LEN);
@@ -435,6 +435,118 @@ void asr_server_deinit(void)
     set_ai_asr_service_init_flag(0);
 }
 
+
+
+uint8_t asr_is_ready=0;
+
+
+
+asr_event_type_t aer_result_analysis(char *buf, asr_result_output_t *output)
+{
+    // 初始化输出结构体
+    if (output) {
+        memset(output, 0, sizeof(asr_result_output_t));
+        output->event_type = ASR_EVENT_UNKNOWN;
+    }
+    
+    cJSON* root = cJSON_Parse((const char *)buf);
+    if (root == NULL) {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"解析失败 %s\n",buf);
+        if (output) {
+            output->event_type = ASR_EVENT_ERROR;
+        }
+        return ASR_EVENT_ERROR;
+    }
+    
+    char *result_str = NULL;
+    int start_time_int = 0;
+    int end_time_int = 0;
+    bool is_end_bool = false;
+    char *event_str = NULL;
+    asr_event_type_t event_type = ASR_EVENT_UNKNOWN;
+
+    // 解析event字段
+    cJSON* event = cJSON_GetObjectItem(root, "event");
+    if (event && cJSON_IsString(event)) {
+        event_str = event->valuestring;
+    }
+
+    // 解析result字段
+    cJSON* result = cJSON_GetObjectItem(root, "result");
+    if (result) {
+        cJSON* result_ = cJSON_GetObjectItem(result, "result");
+        if (result_ && cJSON_IsString(result_)) {
+            result_str = result_->valuestring;
+        }
+        
+        cJSON* start_time = cJSON_GetObjectItem(result, "start_time");
+        if (start_time && cJSON_IsNumber(start_time)) {
+            start_time_int = start_time->valueint;
+        }
+        
+        cJSON* end_time = cJSON_GetObjectItem(result, "end_time");
+        if (end_time && cJSON_IsNumber(end_time)) {
+            end_time_int = end_time->valueint;
+        }
+        
+        cJSON* is_end = cJSON_GetObjectItem(result, "is_end");
+        if (is_end && cJSON_IsBool(is_end)) {
+            is_end_bool = cJSON_IsTrue(is_end);
+        }
+    }
+    
+    // 根据事件字符串确定事件类型
+    if (event_str) {
+        if (strcmp(event_str, "TranscriptionStarted") == 0) {
+            event_type = ASR_EVENT_TRANSCRIPTION_STARTED;
+            asr_is_ready = 1;
+        } else if (strcmp(event_str, "TranscriptionCompleted") == 0) {
+            event_type = ASR_EVENT_TRANSCRIPTION_COMPLETED;
+        } else if (strcmp(event_str, "Failed") == 0) {
+            event_type = ASR_EVENT_FAILED;
+        } else {
+            event_type = ASR_EVENT_UNKNOWN;
+        }
+    }
+    
+    // 如果有结果文本,设置为结果事件
+    if (result_str && strlen(result_str) > 0) {
+        if (is_end_bool) {
+            event_type = ASR_EVENT_RESULT;
+        } else {
+            event_type = ASR_EVENT_PARTIAL_RESULT;
+        }
+    }
+    
+    // 填充输出结构体
+    if (output) {
+        output->event_type = event_type;
+        output->start_time = start_time_int;
+        output->end_time = end_time_int;
+        output->is_end = is_end_bool;
+        output->is_ready = (event_type == ASR_EVENT_TRANSCRIPTION_STARTED);
+        
+        if (result_str) {
+            strncpy(output->result_text, result_str, sizeof(output->result_text) - 1);
+            output->result_text[sizeof(output->result_text) - 1] = '\0';
+        }
+    }
+    
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"Event: %s, Result: %s, Start: %d, End: %d, IsEnd: %d, EventType: %d\n", 
+                  event_str ? event_str : "NULL", 
+                  result_str ? result_str : "NULL", 
+                  start_time_int, end_time_int, is_end_bool, event_type);
+    
+
+    cJSON_Delete(root);
+    return event_type;
+}
+
+
+
+
+
+
 #ifdef __cplusplus
 }
 #endif 
\ No newline at end of file
index 5023af2..1448dec 100644 (file)
@@ -20,6 +20,31 @@ extern "C" {
 
 /* ASR 服务相关类型定义 - errcode_t is defined in errcode.h */
 
+/**
+ * @brief ASR事件类型枚举
+ */
+typedef enum {
+    ASR_EVENT_UNKNOWN = 0,           ///< 未知事件
+    ASR_EVENT_TRANSCRIPTION_STARTED, ///< 转录开始
+    ASR_EVENT_TRANSCRIPTION_COMPLETED, ///< 转录完成
+    ASR_EVENT_FAILED,                ///< 转录失败
+    ASR_EVENT_RESULT,                ///< 转录结果
+    ASR_EVENT_PARTIAL_RESULT,        ///< 部分结果
+    ASR_EVENT_ERROR                  ///< 错误事件
+} asr_event_type_t;
+
+/**
+ * @brief ASR结果输出结构体
+ */
+typedef struct {
+    asr_event_type_t event_type;     ///< 事件类型
+    char result_text[512];           ///< 识别结果文本
+    int start_time;                  ///< 开始时间
+    int end_time;                    ///< 结束时间
+    bool is_end;                     ///< 是否结束
+    bool is_ready;                   ///< 是否准备就绪
+} asr_result_output_t;
+
 /* 任务配置结构体 - 使用系统定义的 app_task_definition_t */
 
 /* 常量定义 */
@@ -48,6 +73,14 @@ uint8_t get_ai_asr_service_init_flag(void);
  */
 void set_ai_asr_service_init_flag(uint8_t flag);
 
+/**
+ * @brief ASR结果分析函数
+ * @param buf JSON格式的ASR结果数据
+ * @param output 输出结构体指针,用于返回解析结果
+ * @return asr_event_type_t 返回事件类型
+ */
+asr_event_type_t aer_result_analysis(char *buf, asr_result_output_t *output);
+
 /**
  * @brief 获取ASR准备开始标志
  * @return 准备开始标志
index 0af58d5..e43b0fc 100644 (file)
@@ -76,7 +76,7 @@ int ws_process_received_data(WebSocketClient *client, const uint8_t *data, size_
 void close_websocket_client(WebSocketClient *client) ;
 
 // 接收 WebSocket 消息
-int  receive_websocket_message(WebSocketClient *client, unsigned char *buf,int len,WebSocketMessageType *code);
+int  receive_websocket_message(WebSocketClient *client, unsigned char *buf,int len,WebSocketMessageType *code, uint32_t timeout_ms);
 int send_websocket_message(WebSocketClient *client, uint8_t *message, size_t message_len, WebSocketMessageType type) ;
 
 // WebSocket测试客户端(当SUPPORT_WEBSOCKET_TEST定义时可用)
index e9339d7..bf0dd93 100644 (file)
 #include "los_printf.h"
 #include "../../../../../open_source/openharmony/third_party/cJSON/cJSON.h"
 
+
 #ifdef __cplusplus
 extern "C" {
 #endif
+#include "chat_websocket_server.h"
+#include "ai_core_types.h"
 
 /* Chat 相关全局变量 */
 WebSocketClient *chat_client = NULL;
@@ -37,10 +40,80 @@ static uint8_t is_bk_websocket_chat = 0;
 static uint8_t ai_chat_service_init_flag = 0;
 static uint8_t chat_client_ping = 0;
 
+/* Chat 缓存相关变量 */
+#define CHAT_MAX_CACHED_LENGTH 10240       // 最大缓存文本总长度
+static char *chat_cached_text = NULL;      // 缓存待发送的文本字符串(动态分配)
+static int chat_cached_length = 0;         // 当前缓存的文本长度
+static int chat_cached_capacity = 0;       // 当前分配的内存容量
+
 /* 外部函数声明 */
 extern bool read_dev_token(char *data_token);
 extern bool get_dev_id(char *device_id);
 // extern void uapi_cat1_keep_wakeup(uint8_t state); // Commented out due to missing implementation
+
+/**
+ * @brief 初始化Chat缓存内存
+ * @return true 成功,false 失败
+ */
+static bool chat_cache_init(void)
+{
+    if (chat_cached_text == NULL) {
+        chat_cached_text = (char*)malloc(CHAT_MAX_CACHED_LENGTH);
+        if (chat_cached_text == NULL) {
+            printf("Failed to allocate memory for Chat cache\n");
+            return false;
+        }
+        chat_cached_capacity = CHAT_MAX_CACHED_LENGTH;
+        chat_cached_length = 0;
+        memset(chat_cached_text, 0, CHAT_MAX_CACHED_LENGTH);
+        printf("Chat cache initialized with %d bytes\n", CHAT_MAX_CACHED_LENGTH);
+    }
+    return true;
+}
+
+/**
+ * @brief 释放Chat缓存内存
+ */
+static void chat_cache_deinit(void)
+{
+    if (chat_cached_text != NULL) {
+        free(chat_cached_text);
+        chat_cached_text = NULL;
+        chat_cached_capacity = 0;
+        chat_cached_length = 0;
+        printf("Chat cache deinitialized\n");
+    }
+}
+
+/**
+ * @brief 确保Chat缓存有足够的空间
+ * @param required_size 需要的空间大小
+ * @return true 成功,false 失败
+ */
+static bool chat_cache_ensure_capacity(int required_size)
+{
+    if (chat_cached_text == NULL) {
+        return chat_cache_init();
+    }
+    
+    if (required_size > chat_cached_capacity) {
+        // 需要扩容
+        int new_capacity = (required_size > CHAT_MAX_CACHED_LENGTH) ? 
+                          required_size + 1024 : CHAT_MAX_CACHED_LENGTH;
+        
+        char *new_buffer = (char*)realloc(chat_cached_text, new_capacity);
+        if (new_buffer == NULL) {
+            printf("Failed to reallocate Chat cache memory\n");
+            return false;
+        }
+        
+        chat_cached_text = new_buffer;
+        chat_cached_capacity = new_capacity;
+        printf("Chat cache expanded to %d bytes\n", new_capacity);
+    }
+    
+    return true;
+}
 extern void ble_set_ai_Answer_str(char *str, uint8_t type);
 extern void msleep(uint32_t ms);
 
@@ -82,17 +155,19 @@ void set_ai_chat_service_init_flag(uint8_t flag)
 /**
  * @brief Chat结果分析
  */
-bool chat_result_analysis(char *buf)
+chat_event_type_t chat_result_analysis(char *buf, char *out_put, size_t out_put_size)
 {
     extern cJSON* cJSON_Parse(const char *value);
     extern cJSON* cJSON_GetObjectItem(const cJSON * const object, const char * const string);
     extern int cJSON_IsString(const cJSON * const item);
     extern void cJSON_Delete(cJSON *c);
     
+    chat_event_type_t event_type = CHAT_EVENT_UNKNOWN;
+    
     cJSON* root = cJSON_Parse((const char *)buf);
     if (root == NULL) {
         printf("Chat result parse failed\n");
-        return false;
+        return CHAT_EVENT_ERROR;
     }
     
     char *type_str = NULL;
@@ -108,32 +183,54 @@ bool chat_result_analysis(char *buf)
         content_str = content->valuestring;
     }
     
-    if(strcmp("middle", type_str) == 0)
-    {   
-        if(strlen(content_str) > 0) 
-        {
-            char *content_str_chat = (char *)malloc(strlen(content_str) + 1);
-            strcpy(content_str_chat, content_str);
-            ble_set_ai_Answer_str(content_str_chat, 2);
-            free(content_str_chat);
+    // 根据type字段确定事件类型
+    if (type_str != NULL) {
+        if (strcmp("start", type_str) == 0) {
+            event_type = CHAT_EVENT_START;
+        } else if (strcmp("middle", type_str) == 0) {
+            event_type = CHAT_EVENT_MIDDLE;
+        } else if (strcmp("end", type_str) == 0) {
+            event_type = CHAT_EVENT_END;
+        } else if (strcmp("error", type_str) == 0) {
+            event_type = CHAT_EVENT_ERROR;
+        } else {
+            event_type = CHAT_EVENT_UNKNOWN;
         }
     }
     
-    if(strcmp("end", type_str) == 0)
-    {   
-        char end_str_chat[128] = {0};
-        if(strlen(content_str) > 0) 
-        {
+    // 处理内容输出
+    if (content_str != NULL && strlen(content_str) > 0) {
+        // 如果提供了输出缓冲区,复制内容到输出缓冲区
+        if (out_put != NULL && out_put_size > 0) {
+            size_t copy_size = (strlen(content_str) < out_put_size - 1) ? 
+                              strlen(content_str) : out_put_size - 1;
+            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)); 
+            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);
-    return true;
+    return event_type;
 }
 
+
+
+
 /**
  * @brief Chat URL初始化
  */
@@ -188,12 +285,69 @@ bool chat_ws_url_init(char * put_buf, uint8_t type)
 
 /**
  * @brief 发送聊天文本
+ * @param type 消息类型
+ * @param msg 要发送的消息
+ * @param chat_client WebSocket客户端
+ * @param cache 是否缓存,false: 缓存文本,true: 发送缓存+当前文本
+ * @return true 成功,false 失败
  */
-bool ai_chat_send_txt(uint8_t type, char *msg)
+bool ai_chat_send_txt(uint8_t type, char *msg, WebSocketClient *chat_client, bool cache)
 {   
     if(msg)
-        printf("ai_chat_send_txt message: %s\n", msg);
+        printf("ai_chat_send_txt message: %s, cache: %s\n", msg, cache ? "true" : "false");
+    
+    // 如果没有传入chat_client,使用全局变量
+    if (chat_client == NULL) {
+        extern WebSocketClient *chat_client;
+        // 使用全局chat_client
+        printf("chat_client ==null\r\n");
+    }
 
+    // 如果cache为false,将文本追加到缓存
+    if (!cache) {
+        if (msg && strlen(msg) > 0) {
+            int msg_len = strlen(msg);
+            int required_size = chat_cached_length + msg_len + 1; // 预留结束符空间
+            
+            // 确保有足够的空间
+            if (!chat_cache_ensure_capacity(required_size)) {
+                printf("Chat cache allocation failed\n");
+                return false;
+            }
+            
+            // 追加文本到缓存字符串
+            strcat(chat_cached_text, msg);
+            chat_cached_length += msg_len;
+            printf("Chat text appended to cache (length: %d/%d): %s\n", chat_cached_length, chat_cached_capacity, msg);
+        }
+        return true;
+    }
+    
+    // 如果cache为true,先发送缓存的文本,然后发送当前文本
+    char *final_msg = msg;
+    
+    if (chat_cached_length > 0) {
+        printf("Chat sending cached text (length: %d): %s\n", chat_cached_length, chat_cached_text);
+        
+        // 将缓存文本和当前文本组合
+        int msg_len = msg ? strlen(msg) : 0;
+        int total_len = chat_cached_length + msg_len + 1;
+        
+        if (!chat_cache_ensure_capacity(total_len)) {
+            printf("Chat cache allocation failed for combined text\n");
+            return false;
+        }
+        
+        // 如果当前有消息,追加到缓存文本
+        if (msg && strlen(msg) > 0) {
+            strcat(chat_cached_text, msg);
+            chat_cached_length += msg_len;
+        }
+        
+        final_msg = chat_cached_text;
+        printf("Chat combined text: %s\n", final_msg);
+    }
+    
     extern cJSON* cJSON_CreateObject(void);
     extern cJSON* cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
     extern char* cJSON_PrintUnformatted(const cJSON *item);
@@ -208,7 +362,7 @@ bool ai_chat_send_txt(uint8_t type, char *msg)
     }
     
     cJSON_AddStringToObject(dataJSON, "type", "jiutian-lan");
-    cJSON_AddStringToObject(dataJSON, "content", msg);
+    cJSON_AddStringToObject(dataJSON, "content", final_msg);
 
     char *jsonString = cJSON_PrintUnformatted(dataJSON);
     
@@ -227,16 +381,30 @@ bool ai_chat_send_txt(uint8_t type, char *msg)
         return false;
     }
     
-    if (send_websocket_message(chat_client, (uint8_t *)jsonString, strlen(jsonString), WS_TEXT) == 0)
+    // 使用传入的chat_client或全局chat_client
+    WebSocketClient *client_to_use = chat_client;
+    if (client_to_use == NULL) {
+        extern WebSocketClient *chat_client;
+        client_to_use = chat_client;
+    }
+    
+    if (send_websocket_message(client_to_use, (uint8_t *)jsonString, strlen(jsonString), WS_TEXT) == 0)
     {
         chat_reconnect = 0;
         printf("Chat message sent successfully\n");
         cJSON_free(jsonString);
+        
+        // 清空缓存
+        if (chat_cached_text != NULL) {
+            memset(chat_cached_text, 0, chat_cached_capacity);
+        }
+        chat_cached_length = 0;
+        
         return true;
     }
     else
     {
-        if(chat_client == NULL)
+        if(client_to_use == NULL)
         {
             printf("chat_client is NULL\n");
         }
@@ -246,6 +414,44 @@ bool ai_chat_send_txt(uint8_t type, char *msg)
     }
 }
 
+/**
+ * @brief 初始化Chat缓存内存
+ * @return true 成功,false 失败
+ */
+bool ai_chat_cache_init(void)
+{
+    return chat_cache_init();
+}
+
+/**
+ * @brief 释放Chat缓存内存
+ */
+void ai_chat_cache_deinit(void)
+{
+    chat_cache_deinit();
+}
+
+/**
+ * @brief 清空Chat缓存
+ */
+void ai_chat_clear_cache(void)
+{
+    if (chat_cached_text != NULL) {
+        memset(chat_cached_text, 0, chat_cached_capacity);
+    }
+    chat_cached_length = 0;
+    printf("Chat cache cleared\n");
+}
+
+/**
+ * @brief 获取Chat缓存长度
+ * @return 当前缓存的文本长度
+ */
+int ai_chat_get_cached_length(void)
+{
+    return chat_cached_length;
+}
+
 /**
  * @brief Chat WebSocket主线程
  */
@@ -395,7 +601,7 @@ CHAT_START:
             
             if (msg_type == WS_TEXT) {
                 printf("Chat text data received: %s\n", recv_buf);
-                chat_result_analysis(recv_buf);
+                // chat_result_analysis(recv_buf);
             } else if (msg_type == WS_BINARY) {
                 printf("Chat binary data received: %d bytes\n", len);
             }
index 9d50a0e..1b50825 100644 (file)
@@ -22,6 +22,16 @@ extern "C" {
 /* Chat 服务相关类型定义 */
 // errcode_t is defined in errcode.h
 
+/* Chat事件类型枚举 */
+typedef enum {
+    CHAT_EVENT_UNKNOWN = 0,        // 未知事件
+    CHAT_EVENT_MIDDLE,             // 中间结果事件
+    CHAT_EVENT_END,                // 结束事件
+    CHAT_EVENT_ERROR,              // 错误事件
+    CHAT_EVENT_START,              // 开始事件
+    CHAT_EVENT_MAX
+} chat_event_type_t;
+
 /* AI类型枚举 - 使用zhihui_ws.h中的定义 */
 
 /* 任务配置结构体 - 使用系统定义的 app_task_definition_t */
@@ -55,9 +65,11 @@ void set_ai_chat_service_init_flag(uint8_t flag);
 /**
  * @brief Chat结果分析
  * @param buf 结果字符串
- * @return 成功返回true,失败返回false
+ * @param out_put 输出内容缓冲区(可选,为NULL时不输出内容)
+ * @param out_put_size 输出缓冲区大小
+ * @return 返回事件类型枚举值
  */
-bool chat_result_analysis(char *buf);
+chat_event_type_t chat_result_analysis(char *buf, char *out_put, size_t out_put_size);
 
 /**
  * @brief Chat URL初始化
@@ -71,9 +83,32 @@ bool chat_ws_url_init(char * put_buf, uint8_t type);
  * @brief 发送聊天文本
  * @param type 消息类型
  * @param msg 消息内容
+ * @param chat_client WebSocket客户端(可选,为NULL时使用全局chat_client)
  * @return 成功返回true,失败返回false
  */
-bool ai_chat_send_txt(uint8_t type, char *msg);
+bool ai_chat_send_txt(uint8_t type, char *msg, WebSocketClient *chat_client, bool cache);
+
+/**
+ * @brief 初始化Chat缓存内存
+ * @return true 成功,false 失败
+ */
+bool ai_chat_cache_init(void);
+
+/**
+ * @brief 释放Chat缓存内存
+ */
+void ai_chat_cache_deinit(void);
+
+/**
+ * @brief 清空Chat缓存
+ */
+void ai_chat_clear_cache(void);
+
+/**
+ * @brief 获取Chat缓存长度
+ * @return 当前缓存的文本长度
+ */
+int ai_chat_get_cached_length(void);
 
 /**
  * @brief Chat WebSocket主线程
@@ -92,6 +127,8 @@ errcode_t chat_server_init(void);
  */
 void chat_server_deinit(void);
 
+// bool ai_chat_send_txt(uint8_t type, char *msg, WebSocketClient *chat_client, bool cache)
+
 /* 全局变量声明 */
 extern WebSocketClient *chat_client;
 
index ee6afb3..b6fbaf7 100644 (file)
@@ -36,7 +36,7 @@ static uint8_t tts_break = 0;
 static uint8_t tts_reconnect = 0;
 static uint8_t is_bk_websocket_tts = 0;
 static uint8_t ai_tts_server_init_flag = 0;
-static uint8_t tts_is_ready = 0;
+static tts_ready_status_t tts_is_ready = TTS_READY_NOT_SENT;
 static uint8_t tts_client_ping = 0;
 static uint32_t bk_websocket_tts_tick = 0;
 
@@ -48,6 +48,8 @@ extern int send_msg_data_into_Ai_msg_queue(void *data, uint16_t len, uint16_t ty
 extern void msleep(uint32_t ms);
 extern int32_t VoiceCallVolteSample(int32_t argc, const char **argv);
 
+static bool uapi_send_single_tts_text(WebSocketClient *tts_client, const char *text);
+
 /* TTS 配置和常量 */
 #define AI_MAX_RETRY_COUNT 3
 #define AI_WS_HANDSHAKE_TIMEOUT_MS 10000
@@ -55,6 +57,77 @@ extern int32_t VoiceCallVolteSample(int32_t argc, const char **argv);
 
 static char tts_task_id_buf[128] = {0};
 
+/* TTS 缓存相关变量 */
+#define TTS_MAX_CACHED_LENGTH 1024       // 最大缓存文本总长度
+static char *tts_cached_text = NULL;      // 缓存待发送的文本字符串(动态分配)
+static int tts_cached_length = 0;         // 当前缓存的文本长度
+static int tts_cached_capacity = 0;       // 当前分配的内存容量
+// static bool tts_is_ready = false;         // TTS是否准备就绪
+
+/**
+ * @brief 初始化TTS缓存内存
+ * @return true 成功,false 失败
+ */
+static bool tts_cache_init(void)
+{
+    if (tts_cached_text == NULL) {
+        tts_cached_text = (char*)malloc(TTS_MAX_CACHED_LENGTH);
+        if (tts_cached_text == NULL) {
+            printf("Failed to allocate memory for TTS cache\n");
+            return false;
+        }
+        tts_cached_capacity = TTS_MAX_CACHED_LENGTH;
+        tts_cached_length = 0;
+        memset(tts_cached_text, 0, TTS_MAX_CACHED_LENGTH);
+        printf("TTS cache initialized with %d bytes\n", TTS_MAX_CACHED_LENGTH);
+    }
+    return true;
+}
+
+/**
+ * @brief 释放TTS缓存内存
+ */
+static void tts_cache_deinit(void)
+{
+    if (tts_cached_text != NULL) {
+        free(tts_cached_text);
+        tts_cached_text = NULL;
+        tts_cached_capacity = 0;
+        tts_cached_length = 0;
+        printf("TTS cache deinitialized\n");
+    }
+}
+
+/**
+ * @brief 确保TTS缓存有足够的空间
+ * @param required_size 需要的空间大小
+ * @return true 成功,false 失败
+ */
+static bool tts_cache_ensure_capacity(int required_size)
+{
+    if (tts_cached_text == NULL) {
+        return tts_cache_init();
+    }
+    
+    if (required_size > tts_cached_capacity) {
+        // 需要扩容
+        int new_capacity = (required_size > TTS_MAX_CACHED_LENGTH) ? 
+                          required_size + 1024 : TTS_MAX_CACHED_LENGTH;
+        
+        char *new_buffer = (char*)realloc(tts_cached_text, new_capacity);
+        if (new_buffer == NULL) {
+            printf("Failed to reallocate TTS cache memory\n");
+            return false;
+        }
+        
+        tts_cached_text = new_buffer;
+        tts_cached_capacity = new_capacity;
+        printf("TTS cache expanded to %d bytes\n", new_capacity);
+    }
+    
+    return true;
+}
+
 /**
  * @brief TTS WebSocket数据包回调函数
  */
@@ -197,12 +270,90 @@ bool uapi_start_tts(void)
 }
 
 /**
- * @brief 启动单个TTS文本合成
+ * @brief TTS文本处理函数(组合版本)
+ * @param tts_client TTS WebSocket客户端
+ * @param buf 要处理的文本
+ * @param ready true: 清理缓存并发送本次文本, false: 将文本添加到缓存
+ * @return true 成功,false 失败
+ */
+bool uapi_tts_process_text(WebSocketClient *tts_client, char *buf, bool ready)
+{
+    if (tts_client == NULL) {
+        printf("TTS client is NULL\n");
+        return false;
+    }
+    
+    // 如果ready为false,将文本追加到缓存字符串
+    if (!ready) {
+        if (buf && strlen(buf) > 0) {
+            int buf_len = strlen(buf);
+            int required_size = tts_cached_length + buf_len + 1; // 预留结束符空间
+            
+            // 确保有足够的空间
+            if (!tts_cache_ensure_capacity(required_size)) {
+                printf("TTS cache allocation failed\n");
+                return false;
+            }
+            
+            // 追加文本到缓存字符串
+            strcat(tts_cached_text, buf);
+            tts_cached_length += buf_len;
+            printf("TTS text appended to cache (length: %d/%d): %s\n", tts_cached_length, tts_cached_capacity, buf);
+        }
+        return true;
+    }
+    
+    // 如果ready为true,先发送缓存的文本,然后发送本次携带的内容
+    if (tts_cached_length > 0) {
+        printf("TTS ready, sending cached text (length: %d): %s\n", tts_cached_length, tts_cached_text);
+        bool result = uapi_send_single_tts_text(tts_client, tts_cached_text);
+        if (!result) {
+            printf("Failed to send cached text: %s\n", tts_cached_text);
+            return false;
+        } else {
+            printf("Successfully sent cached text: %s\n", tts_cached_text);
+        }
+        
+        // 清空缓存
+        if (tts_cached_text != NULL) {
+            memset(tts_cached_text, 0, tts_cached_capacity);
+        }
+        tts_cached_length = 0;
+    }
+    
+    // 发送本次携带的内容
+    if (buf && strlen(buf) > 0) {
+        printf("TTS ready, sending current text: %s\n", buf);
+        bool result = uapi_send_single_tts_text(tts_client, buf);
+        if (!result) {
+            printf("Failed to send current text: %s\n", buf);
+            return false;
+        } else {
+            printf("Successfully sent current text: %s\n", buf);
+        }
+    } else {
+        printf("TTS ready but no current text to send\n");
+    }
+    
+    return true;
+}
+    // "{\"header\" : { \
+    // \"event\": \"RunSynthesis\", \
+    // \"trace_id\": \"%s\" \
+    // }, \
+    // \"payload\": { \
+    // \"text\":\"%s\" \
+    // }}"
+
+/**
+ * @brief 发送单个TTS文本(内部函数)
+ * @param tts_client TTS WebSocket客户端
+ * @param text 要发送的文本
+ * @return true 成功,false 失败
  */
-bool uapi_start_tts_single_txt(char *buf)
+static bool uapi_send_single_tts_text(WebSocketClient *tts_client, const char *text)
 {
-    if (!buf || strlen(buf) == 0) {
-        printf("TTS text buffer is empty\n");
+    if (!text || strlen(text) == 0) {
         return false;
     }
     
@@ -211,34 +362,150 @@ bool uapi_start_tts_single_txt(char *buf)
         return false;
     }
     
-    // 构建TTS请求JSON
-    char *json_template = 
-        "{"
-        "\"type\":\"text\","
-        "\"task_id\":\"%s\","
-        "\"text\":\"%s\""
-        "}";
+    // 使用cJSON构建TTS请求
+    cJSON *json = cJSON_CreateObject();
+    if (json == NULL) {
+        printf("Failed to create JSON object\n");
+        return false;
+    }
+    
+    // 创建header对象
+    cJSON *header = cJSON_CreateObject();
+    if (header == NULL) {
+        printf("Failed to create header object\n");
+        cJSON_Delete(json);
+        return false;
+    }
     
-    char *jsonString = (char *)malloc(strlen(json_template) + strlen(buf) + strlen(tts_task_id_buf) + 100);
-    if (!jsonString) {
-        printf("Failed to allocate memory for TTS JSON\n");
+    // 添加header字段
+    if (cJSON_AddStringToObject(header, "event", "RunSynthesis") == NULL) {
+        printf("Failed to add event field\n");
+        cJSON_Delete(header);
+        cJSON_Delete(json);
         return false;
     }
     
-    sprintf(jsonString, json_template, tts_task_id_buf, buf);
+    if (cJSON_AddStringToObject(header, "trace_id", "") == NULL) {
+        printf("Failed to add trace_id field\n");
+        cJSON_Delete(header);
+        cJSON_Delete(json);
+        return false;
+    }
     
+    // 将header添加到根对象
+    if (cJSON_AddItemToObject(json, "header", header) == 0) {
+        printf("Failed to add header to root object\n");
+        cJSON_Delete(header);
+        cJSON_Delete(json);
+        return false;
+    }
+    
+    // 创建payload对象
+    cJSON *payload = cJSON_CreateObject();
+    if (payload == NULL) {
+        printf("Failed to create payload object\n");
+        cJSON_Delete(json);
+        return false;
+    }
+    
+    // 添加payload字段
+    if (cJSON_AddStringToObject(payload, "text", text) == NULL) {
+        printf("Failed to add text field\n");
+        cJSON_Delete(payload);
+        cJSON_Delete(json);
+        return false;
+    }
+    
+    // 将payload添加到根对象
+    if (cJSON_AddItemToObject(json, "payload", payload) == 0) {
+        printf("Failed to add payload to root object\n");
+        cJSON_Delete(payload);
+        cJSON_Delete(json);
+        return false;
+    }
+    
+    // 生成JSON字符串
+    char *jsonString = cJSON_Print(json);
+    if (jsonString == NULL) {
+        printf("Failed to print JSON to string\n");
+        cJSON_Delete(json);
+        return false;
+    }
+    
+    // 发送WebSocket消息
     bool result = false;
     if (send_websocket_message(tts_client, (uint8_t *)jsonString, strlen(jsonString), WS_TEXT) == 0) {
-        printf("TTS text message sent successfully: %s\n", buf);
         result = true;
+        printf("TTS text %s\n", jsonString);
     } else {
         printf("TTS text message send failed\n");
     }
     
+    // 清理资源
     free(jsonString);
+    cJSON_Delete(json);
+    
     return result;
 }
 
+/**
+ * @brief 获取TTS就绪状态
+ * @return true 准备就绪,false 未准备就绪
+ */
+tts_ready_status_t uapi_get_tts_ready(void)
+{
+    return tts_is_ready;
+}
+
+/**
+ * @brief 获取缓存的文本数量
+ * @return 缓存的文本数量
+ */
+int uapi_get_cached_text_count(void)
+{
+    return tts_cached_length;
+}
+
+/**
+ * @brief 清空TTS缓存
+ */
+void uapi_clear_tts_cache(void)
+{
+    if (tts_cached_text != NULL) {
+        memset(tts_cached_text, 0, tts_cached_capacity);
+    }
+    tts_cached_length = 0;
+    printf("TTS cache cleared\n");
+}
+
+/**
+ * @brief 初始化TTS缓存内存
+ * @return true 成功,false 失败
+ */
+bool uapi_tts_cache_init(void)
+{
+    return tts_cache_init();
+}
+
+/**
+ * @brief 释放TTS缓存内存
+ */
+void uapi_tts_cache_deinit(void)
+{
+    tts_cache_deinit();
+}
+
+/**
+ * @brief TTS文本处理函数(使用全局客户端,向后兼容)
+ * @param buf 要处理的文本
+ * @param ready true: 清理缓存并发送本次文本, false: 将文本添加到缓存
+ * @return true 成功,false 失败
+ */
+bool uapi_tts_process_text_global(char *buf, bool ready)
+{
+    return uapi_tts_process_text(tts_client, buf, ready);
+}
+
 /**
  * @brief 停止TTS服务
  */
@@ -510,6 +777,83 @@ void tts_server_deinit(void)
     set_ai_tts_server_init_flag(0);
 }
 
+
+
+//  {"header":{"event":"StartedSynthesis","msg":"success","status":20000000,"task_id":"8e8996f9148b66738309602ec3219412"}}
+tts_event_type_t tts_analysis(char *buf)
+{
+    tts_event_type_t event_type = TTS_EVENT_UNKNOWN;
+    
+    cJSON* root = cJSON_Parse((const char *)buf);
+    if (root == NULL) {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"解析失败\n");
+        return TTS_EVENT_ERROR;
+    }
+    
+    char *event_str = NULL;
+    char *task_id_str = NULL;
+    char *msg_str = NULL;
+
+    cJSON* header = cJSON_GetObjectItem(root, "header");
+    if (header) {
+        cJSON* event = cJSON_GetObjectItem(header, "event");
+        if (event && cJSON_IsString(event)) {
+            event_str = event->valuestring;
+        }
+
+        cJSON* msg = cJSON_GetObjectItem(header, "msg");
+        if (msg && cJSON_IsString(msg)) {
+            msg_str = msg->valuestring;
+        }
+
+        cJSON* task_id = cJSON_GetObjectItem(header, "task_id");
+        if (task_id && cJSON_IsString(task_id)) {
+            // memcpy_s(tts_task_id_buf, 128, task_id->valuestring, strlen(task_id->valuestring));
+        }
+        
+        // 根据事件类型和消息状态确定事件类型
+        if (event_str != NULL) {
+            if (strcmp("StartedSynthesis", event_str) == 0) {
+                if (msg_str != NULL && strcmp("success", msg_str) == 0) {
+                    event_type = TTS_EVENT_STARTED_SYNTHESIS;
+                    tts_is_ready = TTS_READY_SUCCESS_READY;
+                    
+                    // TTS准备就绪,发送缓存的文本(如果有的话)
+                    if (tts_cached_length > 0) {
+                        printf("TTS is ready, sending cached text (length: %d): %s\n", tts_cached_length, tts_cached_text);
+                        if (tts_client != NULL) {
+                            bool result = uapi_send_single_tts_text(tts_client, tts_cached_text);
+                            if (result) {
+                                printf("Successfully sent cached text: %s\n", tts_cached_text);
+                                // 清空缓存
+                                memset(tts_cached_text, 0, tts_cached_capacity);
+                                tts_cached_length = 0;
+                            } else {
+                                printf("Failed to send cached text: %s\n", tts_cached_text);
+                            }
+                        }
+                    }
+                } else {
+                    event_type = TTS_EVENT_SYNTHESIS_ERROR;
+                }
+            } else if (strcmp("SynthesisComplete", event_str) == 0) {
+                event_type = TTS_EVENT_SYNTHESIS_COMPLETE;
+            } else if (strcmp("AudioData", event_str) == 0) {
+                event_type = TTS_EVENT_AUDIO_DATA;
+            } else if (strcmp("TaskComplete", event_str) == 0) {
+                event_type = TTS_EVENT_TASK_COMPLETE;
+            } else if (strcmp("Error", event_str) == 0) {
+                event_type = TTS_EVENT_ERROR;
+            } else {
+                event_type = TTS_EVENT_UNKNOWN;
+            }
+        }
+    }
+    
+    cJSON_Delete(root);
+    return event_type;
+}
+
 #ifdef __cplusplus
 }
 #endif 
\ No newline at end of file
index b08e766..e819219 100644 (file)
@@ -20,6 +20,25 @@ extern "C" {
 
 /* TTS 服务相关类型定义 - errcode_t is defined in errcode.h */
 
+/* TTS事件类型枚举 */
+typedef enum {
+    TTS_EVENT_UNKNOWN = 0,         // 未知事件
+    TTS_EVENT_STARTED_SYNTHESIS,   // 开始合成事件
+    TTS_EVENT_SYNTHESIS_COMPLETE,  // 合成完成事件
+    TTS_EVENT_SYNTHESIS_ERROR,     // 合成错误事件
+    TTS_EVENT_AUDIO_DATA,          // 音频数据事件
+    TTS_EVENT_TASK_COMPLETE,       // 任务完成事件
+    TTS_EVENT_ERROR,               // 错误事件
+    TTS_EVENT_MAX
+} tts_event_type_t;
+
+/* TTS就绪状态枚举 */
+typedef enum {
+    TTS_READY_NOT_SENT = 0,        // 未发送
+    TTS_READY_SENT_SUCCESS,        // 发送成功
+    TTS_READY_SUCCESS_READY        // 成功就绪
+} tts_ready_status_t;
+
 /* 任务配置结构体 - 使用系统定义的 app_task_definition_t */
 
 /* 常量定义 */
@@ -92,11 +111,49 @@ int32_t uapi_tts_paly_stop(void);
 bool uapi_start_tts(void);
 
 /**
- * @brief 启动单个TTS文本合成
- * @param buf 文本内容
+ * @brief TTS文本处理函数(组合版本)
+ * @param tts_client TTS WebSocket客户端
+ * @param buf 要处理的文本
+ * @param ready true: 清理缓存并发送本次文本, false: 将文本添加到缓存
  * @return 成功返回true,失败返回false
  */
-bool uapi_start_tts_single_txt(char *buf);
+bool uapi_tts_process_text(WebSocketClient *tts_client, char *buf, bool ready);
+
+/**
+ * @brief 获取TTS就绪状态
+ * @return true 准备就绪,false 未准备就绪
+ */
+tts_ready_status_t uapi_get_tts_ready(void);
+
+/**
+ * @brief 获取缓存的文本数量
+ * @return 缓存的文本数量
+ */
+int uapi_get_cached_text_count(void);
+
+/**
+ * @brief 清空TTS缓存
+ */
+void uapi_clear_tts_cache(void);
+
+/**
+ * @brief 初始化TTS缓存内存
+ * @return true 成功,false 失败
+ */
+bool uapi_tts_cache_init(void);
+
+/**
+ * @brief 释放TTS缓存内存
+ */
+void uapi_tts_cache_deinit(void);
+
+/**
+ * @brief TTS文本处理函数(使用全局客户端,向后兼容)
+ * @param buf 要处理的文本
+ * @param ready true: 清理缓存并发送本次文本, false: 将文本添加到缓存
+ * @return 成功返回true,失败返回false
+ */
+bool uapi_tts_process_text_global(char *buf, bool ready);
 
 /**
  * @brief 停止TTS服务
@@ -120,6 +177,13 @@ errcode_t tts_server_init(void);
  */
 void tts_server_deinit(void);
 
+/**
+ * @brief TTS结果分析
+ * @param buf 结果字符串
+ * @return 返回事件类型枚举值
+ */
+tts_event_type_t tts_analysis(char *buf);
+
 /* 全局变量声明 */
 extern WebSocketClient *tts_client;
 
diff --git a/code/sdk/zhihui/ai_old/websocket_server_example.cpp b/code/sdk/zhihui/ai_old/websocket_server_example.cpp
new file mode 100644 (file)
index 0000000..d89cd31
--- /dev/null
@@ -0,0 +1,1034 @@
+/**
+ * @file websocket_server_example.cpp
+ * @brief WebSocket服务器使用示例
+ * @version 1.0.0
+ * @date 2024-09-05
+ * 
+ * 展示如何使用统一的WebSocket服务器管理接口
+ */
+
+#include "websocket_server_manager.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "ai_core_types.h"
+#include "ai_connection_manager.h"
+#include "ai_media.h"
+#include "cJSON.h"
+#include "asr_websocket_server.h"
+#include "chat_websocket_server.h"
+#include "tts_websocket_server.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 全局服务器句柄 */
+static ws_server_handle_t *g_asr_server = NULL;
+static ws_server_handle_t *g_tts_server = NULL;
+static ws_server_handle_t *g_chat_server = NULL;
+
+static uint8_t asr_is_ready=0;
+
+tts_ready_status_t tts_is_ready = TTS_READY_NOT_SENT;
+
+/* 外部函数声明 */
+extern void ble_set_ai_Question_str(char *str);
+extern void ble_set_ai_Answer_str(char *str, uint8_t type);
+extern int send_msg_data_into_Ai_msg_queue(void *data, uint16_t len, uint16_t type);
+extern void set_AIStreamend(uint8_t state);
+extern bool uapi_start_tts(void);
+// extern bool ai_chat_send_txt(uint8_t type, char *msg, WebSocketClient *chat_client);
+extern bool read_dev_token(char *data_token);
+extern bool get_dev_id(char *device_id);
+
+void handle_asr_data(const ws_event_data_t *event_data);
+
+void handle_tts_data(const ws_event_data_t *event_data);
+
+void handle_chat_data(const ws_event_data_t *event_data);
+
+char* extract_json_content( char *json_str,  char *key);
+
+void parse_chat_result(char *json_str);
+
+void uapi_stop_tts_type_stop(void);
+
+bool uapi_start_tts_type_start(void);
+
+void ai_media_init(void);
+
+void uapi_stop_asr(void);
+
+/**
+ * @brief WebSocket事件回调函数
+ */
+void websocket_event_callback(const ws_event_data_t *event_data)
+{
+    if (!event_data) {
+        return;
+    }
+
+    // handle->callback(&event_data);
+    
+    switch (event_data->event_type) {
+        case WS_EVENT_CONNECTED:
+            printf("WebSocket connected: type=%d\n", event_data->server_type);
+            break;
+            
+        case WS_EVENT_DATA_RECEIVED:
+            printf("WebSocket data received: type=%d, len=%d\n", 
+                   event_data->server_type, event_data->data_len);
+            
+            // 根据服务器类型处理数据
+            switch (event_data->server_type) {
+                case WS_SERVER_TYPE_ASR:
+                    handle_asr_data(event_data);
+                    break;
+                case WS_SERVER_TYPE_TTS:
+                    handle_tts_data(event_data);
+                    break;
+                case WS_SERVER_TYPE_CHAT:
+                    handle_chat_data(event_data);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case WS_EVENT_DISCONNECTED:
+            printf("WebSocket disconnected: type=%d\n", event_data->server_type);
+            // 可以在这里添加断连后的处理逻辑
+             switch (event_data->server_type) {
+                case WS_SERVER_TYPE_ASR:
+                    // handle_asr_data(event_data);
+                    asr_is_ready=0;
+                    break;
+                case WS_SERVER_TYPE_TTS:
+                    tts_is_ready = TTS_READY_NOT_SENT;
+                    // handle_tts_data(event_data);
+                    break;
+                case WS_SERVER_TYPE_CHAT:
+                    // handle_chat_data(event_data);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case WS_EVENT_RECONNECTING:
+            printf("WebSocket reconnecting: type=%d\n", event_data->server_type);
+            // 可以在这里添加重连前的处理逻辑
+            switch (event_data->server_type) {
+                case WS_SERVER_TYPE_ASR:
+                    // handle_asr_data(event_data);
+                    asr_is_ready=0;
+                    break;
+                case WS_SERVER_TYPE_TTS:
+                    tts_is_ready = TTS_READY_NOT_SENT;
+                    // handle_tts_data(event_data);
+                    break;
+                case WS_SERVER_TYPE_CHAT:
+                    // handle_chat_data(event_data);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case WS_EVENT_ERROR:
+            printf("WebSocket error: type=%d, error_code=%d\n", 
+                   event_data->server_type, event_data->error_code);
+            break;
+            
+        default:
+            break;
+    }
+} 
+
+
+extern asr_event_type_t aer_result_analysis(char *buf, asr_result_output_t *output);
+/**
+ * @brief 处理ASR数据
+ */
+void handle_asr_data(const ws_event_data_t *event_data)
+{
+    if (event_data->msg_type == WS_TEXT && event_data->data) {
+        printf("ASR text data: %s\n", (char *)event_data->data);
+        
+        // 解析ASR结果并发送到聊天服务
+        if (strlen((char *)event_data->data) > 0) {
+            asr_result_output_t data;
+            int asr_event_type_t= aer_result_analysis((char *)event_data->data,&data);
+            switch (asr_event_type_t)
+            {
+            case ASR_EVENT_TRANSCRIPTION_STARTED :
+                // /* code */
+                asr_is_ready=1;
+                break;
+            case ASR_EVENT_FAILED  :
+                // /* code */
+                asr_is_ready=0;
+                break;
+            case ASR_EVENT_RESULT  :
+                // /* code */
+                // asr_is_ready=0;
+                if(data.is_end)
+                {
+                    ai_chat_send_txt(0, data.result_text, g_chat_server->client,false);
+                    ble_set_ai_Question_str(data.result_text);
+
+                    // uapi_stop_asr_StopTranscription();
+                }
+
+                break;
+
+            case ASR_EVENT_TRANSCRIPTION_COMPLETED:
+                ai_chat_send_txt(0, "", g_chat_server->client,true);
+                asr_is_ready=0;
+                break;
+            default:
+                break;
+            }
+        }
+    } else if (event_data->msg_type == WS_BINARY) {
+        printf("ASR binary data: %d bytes\n", event_data->data_len);
+        send_msg_data_into_Ai_msg_queue(event_data->data, event_data->data_len, 100);
+    }
+}
+
+
+
+/**
+ * @brief 处理TTS数据
+ */
+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);
+
+        switch (event) {
+            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_SYNTHESIS_COMPLETE:
+                printf("TTS synthesis completed\n");
+                break;
+            case TTS_EVENT_AUDIO_DATA:
+                printf("TTS audio data received\n");
+                break;
+            case TTS_EVENT_TASK_COMPLETE:
+                printf("TTS task completed\n");
+                tts_is_ready = TTS_READY_NOT_SENT;
+                break;
+            case TTS_EVENT_SYNTHESIS_ERROR:
+                printf("TTS synthesis error\n");
+                break;
+            case TTS_EVENT_ERROR:
+                printf("TTS general error\n");
+                break;
+            case TTS_EVENT_UNKNOWN:
+                printf("TTS unknown event\n");
+                break;
+        }
+    }
+}
+
+/**
+ * @brief 处理Chat数据
+ */
+void handle_chat_data(const ws_event_data_t *event_data)
+{
+    if ((event_data->msg_type == WS_TEXT || event_data->msg_type == WS_BINARY) && event_data->data) {
+        printf("Chat text data: %s\n", (char *)event_data->data);
+        
+        // 解析Chat结果
+        char buf[512]={0};
+        chat_event_type_t ret=chat_result_analysis((char*)event_data->data, buf, 512);
+        
+        // 根据事件类型进行处理
+        switch (ret) {
+            case CHAT_EVENT_START:
+                printf("Chat event: START\n");
+                if(tts_is_ready == TTS_READY_NOT_SENT) {
+
+                    tts_is_ready = TTS_READY_SENT_SUCCESS;
+                    uapi_start_tts_type_start();
+                    
+                }
+                break;
+                
+            case CHAT_EVENT_MIDDLE:
+                printf("Chat event: MIDDLE - Content: %s\n", buf);
+                ble_set_ai_Answer_str(buf, 2);
+                uapi_tts_process_text(g_tts_server->client,buf,(tts_is_ready == TTS_READY_SUCCESS_READY));
+                break;
+                
+            case CHAT_EVENT_END:
+                printf("Chat event: END - Final content: %s\n", buf);
+                uapi_stop_tts_type_stop();
+                break;
+                
+            case CHAT_EVENT_ERROR:
+                printf("Chat event: ERROR\n");
+                break;
+                
+            case CHAT_EVENT_UNKNOWN:
+                printf("Chat event: UNKNOWN\n");
+                break;
+                
+            default:
+                printf("Chat event: Invalid type (%d)\n", ret);
+                break;
+        }
+        
+    } 
+}
+
+/**
+ * @brief 解析Chat结果
+ */
+void parse_chat_result(char *json_str)
+{
+    // 这里可以添加JSON解析逻辑
+    // 简化示例,直接显示结果
+    if (strstr(json_str, "\"type\":\"middle\"")) {
+        // 中间结果
+        char *content = extract_json_content(json_str, "content");
+        if (content) {
+            ble_set_ai_Answer_str(content, 2);
+            free(content);
+        }
+    } else if (strstr(json_str, "\"type\":\"end\"")) {
+        // 最终结果
+        char *content = extract_json_content(json_str, "content");
+        if (content) {
+            ble_set_ai_Answer_str(content, 2);
+            free(content);
+        }
+    }
+}
+
+/**
+ * @brief 提取JSON内容(简化实现)
+ */
+char* extract_json_content( char *json_str,  char *key)
+{
+    // 这是一个简化的实现,实际应该使用cJSON库
+    char *start = strstr(json_str, key);
+    if (!start) return NULL;
+    
+    start = strchr(start, '"');
+    if (!start) return NULL;
+    start++;
+    
+    char *end = strchr(start, '"');
+    if (!end) return NULL;
+    
+    size_t len = end - start;
+    char *result = (char *)malloc(len + 1);
+    if (result) {
+        strncpy(result, start, len);
+        result[len] = '\0';
+    }
+    
+    return result;
+}
+
+/**
+ * @brief ASR URL生成回调函数
+ */
+bool asr_url_callback(ws_server_type_t type, char *url_buf, uint32_t url_size, void *user_data)
+{
+    char token[64] = {0};
+    if (read_dev_token(token)) {
+        snprintf(url_buf, url_size, "ws://amp.raisound.com/asr/ws?dt=%s&platform=aliyun&noCache=1", token);
+    } else {
+        snprintf(url_buf, url_size, "ws://118.145.158.207:22080/asr/ws");
+    }
+    return true;
+}
+
+/**
+ * @brief TTS URL生成回调函数
+ */
+bool tts_url_callback(ws_server_type_t type, char *url_buf, uint32_t url_size, void *user_data)
+{
+    char token[64] = {0};
+    if (read_dev_token(token)) {
+        snprintf(url_buf, url_size, "ws://amp.raisound.com/tts/stream?dt=%s&platform=aliyun&noCache=1", token);
+    } else {
+        snprintf(url_buf, url_size, "ws://118.145.158.207:22080/tts/stream?audio_buffer_size=512");
+    }
+    return true;
+}
+
+/**
+ * @brief Chat URL生成回调函数
+ */
+bool chat_url_callback(ws_server_type_t type, char *url_buf, uint32_t url_size, void *user_data)
+{
+    char token[64] = {0};
+    if (read_dev_token(token)) {
+        char device_id[128] = {0};
+        get_dev_id(device_id);
+        char *product_id = "1927646275585744898";
+        snprintf(url_buf, url_size, "ws://amp.raisound.com/chat/ws?device_id=%s&product_id=%s&dt=%s&platform=aliyun&noCache=1", 
+                device_id, product_id, token);
+    } else {
+        char device_id[128] = {0};
+        get_dev_id(device_id);
+        char *product_id = "1927646275585744898";
+        
+        // 根据AI类型选择不同的URL
+        uint8_t *ai_type = (uint8_t *)user_data;
+        if (ai_type && *ai_type == 1) { // AI_TYPE_JIU
+            snprintf(url_buf, url_size, "ws://118.145.158.207:22080/chat/ws?device_id=%s&product_id=%s&platform=chinamobiledevice&bot_type=jiutian-lan", 
+                    device_id, product_id);
+        } else if (ai_type && *ai_type == 2) { // AI_TYPE_DOU
+            snprintf(url_buf, url_size, "ws://118.145.158.207:22080/chat/ws?platform=huoshan");
+        } else if (ai_type && *ai_type == 3) { // AI_TYPE_WEN
+            snprintf(url_buf, url_size, "ws://118.145.158.207:22080/chat/ws?platform=baidu");
+        } else if (ai_type && *ai_type == 4) { // AI_TYPE_KIMI
+            snprintf(url_buf, url_size, "ws://118.145.158.207:22080/chat/ws?platform=moonshot");
+        } else if (ai_type && *ai_type == 5) { // AI_TYPE_DE
+            snprintf(url_buf, url_size, "ws://118.145.158.207:22080/chat/ws?platform=huoshan&model=ep-20250205103849-582m7");
+        } else {
+            snprintf(url_buf, url_size, "ws://118.145.158.207:22080/chat/ws?platform=aliyun");
+        }
+    }
+    return true;
+}
+
+/**
+ * @brief 初始化所有WebSocket服务器
+ */
+errcode_t init_all_websocket_servers(void)
+{
+    // 初始化管理器
+    errcode_t ret = ws_server_manager_init();
+    if (ret != ERRCODE_SUCC) {
+        printf("Failed to initialize WebSocket manager\n");
+        return ret;
+    }
+    
+    
+    // 注册URL回调函数
+    ws_server_register_url_callback(WS_SERVER_TYPE_ASR, asr_url_callback, NULL);
+    ws_server_register_url_callback(WS_SERVER_TYPE_TTS, tts_url_callback, NULL);
+    
+    // Chat服务器需要AI类型参数
+    static uint8_t chat_ai_type = 0; // 默认类型
+    ws_server_register_url_callback(WS_SERVER_TYPE_CHAT, chat_url_callback, &chat_ai_type);
+    
+    // 创建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秒重连间隔
+    g_asr_server = ws_server_create(&asr_config, websocket_event_callback, NULL);
+    if (!g_asr_server) {
+        printf("Failed to create ASR server\n");
+        return ERRCODE_FAIL;
+    }
+    
+    // 创建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秒重连间隔
+    g_tts_server = ws_server_create(&tts_config, websocket_event_callback, NULL);
+    if (!g_tts_server) {
+        printf("Failed to create TTS server\n");
+        ws_server_destroy(g_asr_server);
+        return ERRCODE_FAIL;
+    }
+    
+    // 创建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秒重连间隔
+    g_chat_server = ws_server_create(&chat_config, websocket_event_callback, NULL);
+    if (!g_chat_server) {
+        printf("Failed to create Chat server\n");
+        ws_server_destroy(g_asr_server);
+        ws_server_destroy(g_tts_server);
+        return ERRCODE_FAIL;
+    }
+    
+    printf("All WebSocket servers created successfully\n");
+    return ERRCODE_SUCC;
+}
+
+static void AIVoiceDataCallback_(const uint8_t* data, uint32_t size, void* userData)
+{
+    // MEDIA_INFO_LOG("Received audio data: size=%u bytes", size);
+    // 在这里处理音频数据,例如:
+    // - 发送到AI语音识别服务
+    // - 保存到文件
+    // - 进行音频处理等
+    // 注意:data指针指向的缓冲区在回调函数返回后可能被释放,如需保存数据请复制
+    if (g_asr_server == NULL || !g_asr_server->is_initialized) {
+        printf("Services context not initialized");
+        return;
+    }
+    // printf("Audio record callback, size: %d", size);
+    
+    /* 🆕 根据ASR服务启动标识决定是否发送音频数据 */
+    if (asr_is_ready) {
+        // printf("Sending %u bytes audio data to ASR service", size);
+        
+        /* 通过连接管理器发送原始音频数据到ASR服务 */
+        // ai_error_t ret = ai_connection_manager_send_rawdata(AI_SERVICE_ASR, (const void*)data, (size_t)size);
+        // g_asr_server
+        ws_server_send_message(g_asr_server,( uint8_t  *)data,size,WS_BINARY);
+        // if (ret != AI_OK) {
+        //     printf("Failed to send audio data to ASR service: %d", ret);
+        // }
+    }
+
+}
+
+
+/**
+ * @brief 启动所有WebSocket服务器
+ */
+errcode_t start_all_websocket_servers(void)
+{
+    errcode_t ret;
+    
+    // 启动ASR服务器
+    ret = ws_server_start(g_asr_server);
+    if (ret != ERRCODE_SUCC) {
+        printf("Failed to start ASR server\n");
+        return ret;
+    }
+    
+    // 启动TTS服务器
+    ret = ws_server_start(g_tts_server);
+    if (ret != ERRCODE_SUCC) {
+        printf("Failed to start TTS server\n");
+        ws_server_stop(g_asr_server);
+        return ret;
+    }
+    
+    // 启动Chat服务器
+    ret = ws_server_start(g_chat_server);
+    if (ret != ERRCODE_SUCC) {
+        printf("Failed to start Chat server\n");
+        ws_server_stop(g_asr_server);
+        ws_server_stop(g_tts_server);
+        return ret;
+    }
+
+    // ai_media_init();
+    old_Start_AIVoice(AIVoiceDataCallback_,nullptr);
+    
+    printf("All WebSocket servers started successfully\n");
+    return ERRCODE_SUCC;
+}
+
+/**
+ * @brief 停止所有WebSocket服务器
+ */
+void stop_all_websocket_servers(void)
+{
+    if (g_asr_server) {
+        ws_server_stop(g_asr_server);
+    }
+    
+    if (g_tts_server) {
+        ws_server_stop(g_tts_server);
+    }
+    
+    if (g_chat_server) {
+        ws_server_stop(g_chat_server);
+    }
+    
+    StopAIVoice();
+
+    printf("All WebSocket servers stopped\n");
+}
+
+/**
+ * @brief 销毁所有WebSocket服务器
+ */
+void destroy_all_websocket_servers(void)
+{
+    if (g_asr_server) {
+        ws_server_destroy(g_asr_server);
+        g_asr_server = NULL;
+    }
+    
+    if (g_tts_server) {
+        ws_server_destroy(g_tts_server);
+        g_tts_server = NULL;
+    }
+    
+    if (g_chat_server) {
+        ws_server_destroy(g_chat_server);
+        g_chat_server = NULL;
+    }
+    
+    ws_server_manager_deinit();
+    printf("All WebSocket servers destroyed\n");
+}
+
+/**
+ * @brief 发送TTS文本
+ */
+bool send_tts_text(const char *text)
+{
+    if (!g_tts_server || !text) {
+        return false;
+    }
+    
+    // 构建TTS请求JSON
+    char json_template[] = 
+        "{"
+        "\"type\":\"text\","
+        "\"task_id\":\"\","
+        "\"text\":\"%s\""
+        "}";
+    
+    char *json_str = (char *)malloc(strlen(json_template) + strlen(text) + 100);
+    if (!json_str) {
+        return false;
+    }
+    
+    sprintf(json_str, json_template, text);
+    
+    bool result = ws_server_send_message(g_tts_server, (uint8_t *)json_str, 
+                                        strlen(json_str), WS_TEXT);
+    
+    free(json_str);
+    return result;
+}
+
+/**
+ * @brief 发送Chat消息
+ */
+bool send_chat_message(const char *message)
+{
+    if (!g_chat_server || !message) {
+        return false;
+    }
+    
+    // 构建Chat请求JSON
+    char json_template[] = 
+        "{"
+        "\"type\":\"jiutian-lan\","
+        "\"content\":\"%s\""
+        "}";
+    
+    char *json_str = (char *)malloc(strlen(json_template) + strlen(message) + 100);
+    if (!json_str) {
+        return false;
+    }
+    
+    sprintf(json_str, json_template, message);
+    
+    bool result = ws_server_send_message(g_chat_server, (uint8_t *)json_str, 
+                                        strlen(json_str), WS_TEXT);
+    
+    free(json_str);
+    return result;
+}
+
+/**
+ * @brief 启动TTS服务
+ */
+bool start_tts_service(void)
+{
+    if (!g_tts_server) {
+        return false;
+    }
+    
+    char *start_json = 
+        "{"
+        "\"type\":\"start\","
+        "\"task_id\":\"\","
+        "\"audio_config\":{"
+        "\"sample_rate\":16000,"
+        "\"format\":\"mp3\","
+        "\"channel\":1"
+        "},"
+        "\"request_config\":{"
+        "\"protocol\":1,"
+        "\"audio_buffer_size\":1024"
+        "}"
+        "}";
+    
+    return ws_server_send_message(g_tts_server, (uint8_t *)start_json, 
+                                 strlen(start_json), WS_TEXT);
+}
+
+/**
+ * @brief 停止TTS服务
+ */
+void stop_tts_service(void)
+{
+    if (!g_tts_server) {
+        return;
+    }
+    
+    char *stop_json = "{\"type\":\"stop\",\"task_id\":\"\"}";
+    ws_server_send_message(g_tts_server, (uint8_t *)stop_json, 
+                          strlen(stop_json), WS_TEXT);
+}
+
+
+void uapi_start_asr_StartTranscription(void)
+{
+    if (!g_asr_server) {
+        return;
+    }
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"uapi_start_asr_StartTranscription \n");
+
+
+    char *jsonString = "{\"header\":{\"event\":\"StartTranscription\",\"trace_id\":\
+      \"\"},\"payload\":{\"format\":\"MP3\",\"sample_rate\":16000}}";
+    
+    ws_server_send_message(g_asr_server,( uint8_t  *)jsonString,strlen(jsonString),WS_TEXT);
+
+}
+
+/**
+ * @brief 设置服务器断连处理策略
+ */
+void set_server_disconnect_strategy(ws_server_type_t type, ws_disconnect_strategy_t strategy)
+{
+    ws_server_handle_t *server = NULL;
+    
+    switch (type) {
+        case WS_SERVER_TYPE_ASR:
+            server = g_asr_server;
+            break;
+        case WS_SERVER_TYPE_TTS:
+            server = g_tts_server;
+            break;
+        case WS_SERVER_TYPE_CHAT:
+            server = g_chat_server;
+            break;
+        default:
+            return;
+    }
+    
+    if (server) {
+        ws_server_set_disconnect_strategy(server, strategy);
+    }
+}
+
+/**
+ * @brief 手动触发服务器重连
+ */
+bool trigger_server_reconnect(ws_server_type_t type)
+{
+    ws_server_handle_t *server = NULL;
+    
+    switch (type) {
+        case WS_SERVER_TYPE_ASR:
+            server = g_asr_server;
+            break;
+        case WS_SERVER_TYPE_TTS:
+            server = g_tts_server;
+            break;
+        case WS_SERVER_TYPE_CHAT:
+            server = g_chat_server;
+            break;
+        default:
+            return false;
+    }
+    
+    if (server) {
+        return ws_server_trigger_reconnect(server);
+    }
+    
+    return false;
+}
+
+/**
+ * @brief 获取服务器状态信息
+ */
+void print_server_status(void)
+{
+    printf("=== WebSocket Server Status ===\n");
+    
+    if (g_asr_server) {
+        printf("ASR Server: %s, Running: %s\n", 
+               ws_server_get_state(g_asr_server) == WS_SERVER_STATE_CONNECTED ? "Connected" : "Disconnected",
+               ws_server_is_running(g_asr_server) ? "Yes" : "No");
+    }
+    
+    if (g_tts_server) {
+        printf("TTS Server: %s, Running: %s, Ready: %s\n", 
+               ws_server_get_state(g_tts_server) == WS_SERVER_STATE_CONNECTED ? "Connected" : "Disconnected",
+               ws_server_is_running(g_tts_server) ? "Yes" : "No",
+               (uapi_get_tts_ready() == TTS_READY_SUCCESS_READY) ? "Yes" : "No");
+    }
+    
+    if (g_chat_server) {
+        printf("Chat Server: %s, Running: %s\n", 
+               ws_server_get_state(g_chat_server) == WS_SERVER_STATE_CONNECTED ? "Connected" : "Disconnected",
+               ws_server_is_running(g_chat_server) ? "Yes" : "No");
+    }
+    
+    printf("===============================\n");
+}
+
+/**
+ * @brief 检查所有服务是否都就绪
+ * @return true 所有服务都就绪,false 有服务未就绪
+ */
+bool are_all_services_ready(void)
+{
+    bool asr_ready = false;
+    bool tts_ready = false;
+    bool chat_ready = false;
+    
+    // 检查ASR服务状态
+    if (g_asr_server) {
+        asr_ready = (ws_server_get_state(g_asr_server) == WS_SERVER_STATE_CONNECTED) && 
+                    ws_server_is_running(g_asr_server);
+    }
+    
+    // 检查TTS服务状态
+    if (g_tts_server) {
+        tts_ready = (ws_server_get_state(g_tts_server) == WS_SERVER_STATE_CONNECTED) && 
+                    ws_server_is_running(g_tts_server);
+    }
+    
+    // 检查Chat服务状态
+    if (g_chat_server) {
+        chat_ready = (ws_server_get_state(g_chat_server) == WS_SERVER_STATE_CONNECTED) && 
+                     ws_server_is_running(g_chat_server);
+    }
+    
+    // 打印详细状态信息
+    printf("Service Status Check:\n");
+    printf("  ASR: %s\n", asr_ready ? "Ready" : "Not Ready");
+    printf("  TTS: %s (State: %d)\n", tts_ready ? "Ready" : "Not Ready", uapi_get_tts_ready());
+    printf("  Chat: %s\n", chat_ready ? "Ready" : "Not Ready");
+    
+    return asr_ready && tts_ready && chat_ready;
+}
+
+
+/// @brief //
+/// @param data 
+/// @param size //
+static void audio_record_callback(uint8_t *data, uint32_t size)
+{
+    if (g_asr_server == NULL || !g_asr_server->is_initialized) {
+        printf("Services context not initialized (%s)",g_asr_server);
+        return;
+    }
+    printf("Audio record callback, size: %d", size);
+    
+    /* 🆕 根据ASR服务启动标识决定是否发送音频数据 */
+    if (asr_is_ready) {
+        printf("Sending %u bytes audio data to ASR service", size);
+        
+        /* 通过连接管理器发送原始音频数据到ASR服务 */
+        // ai_error_t ret = ai_connection_manager_send_rawdata(AI_SERVICE_ASR, (const void*)data, (size_t)size);
+        // g_asr_server
+        ws_server_send_message(g_asr_server,( uint8_t  *)data,size,WS_TEXT);
+        // if (ret != AI_OK) {
+        //     printf("Failed to send audio data to ASR service: %d", ret);
+        // }
+    }
+}
+
+
+void ai_media_init(void)
+{
+    printf("Initializing audio media service...");
+    int32_t media_ret = ai_media_service_init();
+    if (media_ret != 0) {
+        printf("Failed to initialize media service: %d", media_ret);
+
+        return ;
+    }
+    
+    /* 🆕 设置录音回调 */
+    ai_media_set_record_callback(audio_record_callback);
+    
+    /* 🆕 启动录音服务 */
+    printf("Starting audio recording...");
+    ai_media_record_start((uint8_t *)"MP3");  // 使用PCM格式
+    
+    /* 🆕 启动播放服务 */
+    // printf("Starting audio playback...");
+    // ai_media_play_start((uint8_t *)"MP3"); // 使用PCM格式
+
+}
+
+
+/**
+ * @brief 启动TTS服务
+ */
+bool uapi_start_tts_type_start(void)
+{
+    cJSON *json = NULL;
+    cJSON *header = NULL;
+    cJSON *payload = NULL;
+    char *jsonString = NULL;
+    bool result = false;
+    
+    if (g_tts_server->client == NULL) {
+        printf("TTS client is NULL\n");
+        return false;
+    }
+    
+    // 创建根JSON对象
+    json = cJSON_CreateObject();
+    if (json == NULL) {
+        printf("Failed to create JSON object\n");
+        return false;
+    }
+    
+    // 创建header对象
+    header = cJSON_CreateObject();
+    if (header == NULL) {
+        printf("Failed to create header object\n");
+        goto cleanup;
+    }
+    
+    // 添加header字段
+    if (cJSON_AddStringToObject(header, "event", "StartSynthesis") == NULL) {
+        printf("Failed to add event field\n");
+        goto cleanup;
+    }
+    
+    if (cJSON_AddStringToObject(header, "trace_id", "") == NULL) {
+        printf("Failed to add trace_id field\n");
+        goto cleanup;
+    }
+    
+    // 将header添加到根对象
+    if (cJSON_AddItemToObject(json, "header", header) == 0) {
+        printf("Failed to add header to root object\n");
+        goto cleanup;
+    }
+    header = NULL; // 防止重复释放
+    
+    // 创建payload对象
+    payload = cJSON_CreateObject();
+    if (payload == NULL) {
+        printf("Failed to create payload object\n");
+        goto cleanup;
+    }
+    
+    // 添加payload字段
+    if (cJSON_AddStringToObject(payload, "voice", "xiaoyun") == NULL) {
+        printf("Failed to add voice field\n");
+        goto cleanup;
+    }
+    
+    if (cJSON_AddStringToObject(payload, "format", "mp3") == NULL) {
+        printf("Failed to add format field\n");
+        goto cleanup;
+    }
+    
+    if (cJSON_AddNumberToObject(payload, "sample_rate", 16000) == NULL) {
+        printf("Failed to add sample_rate field\n");
+        goto cleanup;
+    }
+    
+    if (cJSON_AddNumberToObject(payload, "volume", 80) == NULL) {
+        printf("Failed to add volume field\n");
+        goto cleanup;
+    }
+    
+    if (cJSON_AddNumberToObject(payload, "speech_rate", 0) == NULL) {
+        printf("Failed to add speech_rate field\n");
+        goto cleanup;
+    }
+    
+    // 将payload添加到根对象
+    if (cJSON_AddItemToObject(json, "payload", payload) == 0) {
+        printf("Failed to add payload to root object\n");
+        goto cleanup;
+    }
+    payload = NULL; // 防止重复释放
+    
+    // 生成JSON字符串
+    jsonString = cJSON_Print(json);
+    printf("uapi_start_tts_type_start: %s\r\n",jsonString);
+    if (jsonString == NULL) {
+        printf("Failed to print JSON to string\n");
+        goto cleanup;
+    }
+    
+    // 发送WebSocket消息
+    if (send_websocket_message(g_tts_server->client, (uint8_t *)jsonString, strlen(jsonString), WS_TEXT) == 0) {
+        printf("TTS start message sent successfully\n");
+        // printf("JSON: %s\n", jsonString);
+        result = true;
+    } else {
+        printf("TTS start message send failed\n");
+    }
+    
+cleanup:
+    // 清理资源
+    if (jsonString != NULL) {
+        free(jsonString);
+    }
+    if (header != NULL) {
+        cJSON_Delete(header);
+    }
+    if (payload != NULL) {
+        cJSON_Delete(payload);
+    }
+    if (json != NULL) {
+        cJSON_Delete(json);
+    }
+    
+    return result;
+}
+
+void uapi_stop_tts_type_stop(void)
+{
+    if (g_tts_server->client) {
+        char *stop_json = "{\"header\":{\"event\":\"StopSynthesis\",\"trace_id\":\"\"}}";
+        send_websocket_message(g_tts_server->client, (uint8_t *)stop_json, strlen(stop_json), WS_TEXT);
+        tts_is_ready = TTS_READY_NOT_SENT;
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"uapi_stop_tts_type_stop \n");
+    }
+}
+
+
+void uapi_stop_asr_StopTranscription(void)
+{
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"uapi_stop_asr_StopTranscription \n");
+
+    char *jsonString ="{\"header\":{\"event\":\"StopTranscription\",\"trace_id\":\"3fa6b9e6a30b407ea38ad7ae69e6c291\"}}";
+
+    if (send_websocket_message(g_asr_server->client,( uint8_t *)jsonString,strlen(jsonString),WS_TEXT)==0)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"send_websocket_message succ 0\n");
+    }
+    else
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"send_websocket_message  erro\n");
+    }
+}
+
+uint8_t get_asr_is_ready_start_old(void)
+{
+    return asr_is_ready;
+}
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/code/sdk/zhihui/ai_old/websocket_server_manager.cpp b/code/sdk/zhihui/ai_old/websocket_server_manager.cpp
new file mode 100644 (file)
index 0000000..0ddd3f6
--- /dev/null
@@ -0,0 +1,789 @@
+/**
+ * @file websocket_server_manager.cpp
+ * @brief 统一WebSocket服务器管理实现
+ * @version 1.0.0
+ * @date 2024-09-05
+ * 
+ * 提供统一的WebSocket服务器管理实现,支持事件回调
+ */
+
+#include "websocket_server_manager.h"
+#include "thread_init.h"
+#include "cmsis_os2.h"
+#include "soc_osal.h"
+#include "wearable_log.h"
+#include "custom_runtime.h"
+#include "los_printf.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include "chat_websocket_server.h"
+#include "tts_websocket_server.h"
+#include "asr_websocket_server.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 外部函数声明 */
+extern bool read_dev_token(char *data_token);
+extern bool get_dev_id(char *device_id);
+extern void msleep(uint32_t ms);
+extern errcode_t uapi_create_osThread_custom(app_task_definition_t* task_cfg);
+extern int receive_websocket_message_from_queue(ws_message_queue_t* queue, uint8_t* buffer, 
+                                               uint16_t buffer_size, WebSocketMessageType* type, uint32_t timeout_ms);
+
+/* 全局变量 */
+static uint8_t g_ws_manager_initialized = 0;
+static ws_server_handle_t *g_ws_servers[WS_SERVER_TYPE_MAX] = {0};
+static ws_url_callback_t g_url_callbacks[WS_SERVER_TYPE_MAX] = {0};
+static void *g_url_user_data[WS_SERVER_TYPE_MAX] = {0};
+static ws_server_handle_t *g_thread_handles[WS_SERVER_TYPE_MAX] = {0};  // 每个服务类型的线程handle
+
+/* 内部函数声明 */
+static void ws_server_thread_func(void *data);
+static void ws_server_packet_callback(uint8_t* data, size_t datalen, WebSocketMessageType type, ws_server_handle_t *handle);
+static void ws_server_trigger_event(ws_server_handle_t *handle, ws_event_type_t event_type, 
+                                   const uint8_t *data, uint32_t data_len, WebSocketMessageType msg_type, uint32_t error_code);
+static bool ws_server_connect(ws_server_handle_t *handle);
+static void ws_server_disconnect(ws_server_handle_t *handle);
+static void ws_server_cleanup(ws_server_handle_t *handle);
+static bool ws_server_should_reconnect(ws_server_handle_t *handle);
+static bool ws_server_attempt_reconnect(ws_server_handle_t *handle);
+
+/**
+ * @brief 初始化WebSocket服务器管理器
+ */
+errcode_t ws_server_manager_init(void)
+{
+    if (g_ws_manager_initialized) {
+        return ERRCODE_SUCC;
+    }
+    
+    memset(g_ws_servers, 0, sizeof(g_ws_servers));
+    g_ws_manager_initialized = 1;
+    
+    printf("WebSocket Server Manager initialized\n");
+    return ERRCODE_SUCC;
+}
+
+/**
+ * @brief 反初始化WebSocket服务器管理器
+ */
+void ws_server_manager_deinit(void)
+{
+    if (!g_ws_manager_initialized) {
+        return;
+    }
+    
+    // 停止所有服务器
+    for (int i = 0; i < WS_SERVER_TYPE_MAX; i++) {
+        if (g_ws_servers[i]) {
+            ws_server_destroy(g_ws_servers[i]);
+            g_ws_servers[i] = NULL;
+        }
+    }
+    
+    g_ws_manager_initialized = 0;
+    printf("WebSocket Server Manager deinitialized\n");
+}
+
+/**
+ * @brief 创建WebSocket服务器
+ */
+ws_server_handle_t* ws_server_create(const ws_server_config_t *config, 
+                                   ws_event_callback_t callback, 
+                                   void *user_data)
+{
+    if (!config || !callback) {
+        printf("Invalid parameters for ws_server_create\n");
+        return NULL;
+    }
+    
+    if (config->type >= WS_SERVER_TYPE_MAX) {
+        printf("Invalid server type: %d\n", config->type);
+        return NULL;
+    }
+    
+    // 检查是否已存在
+    if (g_ws_servers[config->type]) {
+        printf("Server type %d already exists\n", config->type);
+        return NULL;
+    }
+    
+    // 分配内存
+    ws_server_handle_t *handle = (ws_server_handle_t *)malloc(sizeof(ws_server_handle_t));
+    if (!handle) {
+        printf("Failed to allocate memory for server handle\n");
+        return NULL;
+    }
+    
+    memset(handle, 0, sizeof(ws_server_handle_t));
+    
+    // 初始化配置
+    memcpy(&handle->config, config, sizeof(ws_server_config_t));
+    handle->callback = callback;
+    handle->user_data = user_data;
+    handle->type = config->type;
+    handle->state = WS_SERVER_STATE_INIT;
+    
+    // 设置URL回调函数
+    handle->url_callback = config->url_callback;
+    handle->url_user_data = config->url_user_data;
+    
+    // 初始化重连相关变量
+    handle->reconnect_count = 0;
+    handle->last_reconnect_time = 0;
+    
+    // 初始化消息队列
+    ws_queue_init(&handle->msg_queue, 0);
+    
+    // 分配接收缓冲区
+    handle->recv_buffer = (char *)malloc(config->buffer_size);
+    if (!handle->recv_buffer) {
+        printf("Failed to allocate receive buffer\n");
+        free(handle);
+        return NULL;
+    }
+    
+    g_ws_servers[config->type] = handle;
+    
+    printf("WebSocket server created: type=%d, name=%s\n", config->type, config->name);
+    return handle;
+}
+
+/**
+ * @brief 销毁WebSocket服务器
+ */
+void ws_server_destroy(ws_server_handle_t *handle)
+{
+    if (!handle) {
+        return;
+    }
+    
+    // 停止服务器
+    ws_server_stop(handle);
+    
+    // 清理资源
+    ws_server_cleanup(handle);
+    
+    // 从全局数组中移除
+    if (g_ws_servers[handle->type] == handle) {
+        g_ws_servers[handle->type] = NULL;
+    }
+    
+    free(handle);
+    printf("WebSocket server destroyed: type=%d\n", handle->type);
+}
+
+/**
+ * @brief 启动WebSocket服务器
+ */
+errcode_t ws_server_start(ws_server_handle_t *handle)
+{
+    if (!handle) {
+        return ERRCODE_FAIL;
+    }
+    
+    if (handle->is_running) {
+        printf("Server is already running\n");
+        return ERRCODE_FAIL;
+    }
+    
+    // 设置对应服务类型的全局变量,供线程函数使用
+    g_thread_handles[handle->type] = handle;
+    
+    // 创建线程配置
+    app_task_definition_t task_cfg;
+    memset(&task_cfg, 0, sizeof(task_cfg));
+    
+    task_cfg.create_queue_handle = NULL;
+    task_cfg.attr.name = handle->config.name;
+    task_cfg.attr.priority = (osPriority_t)16;
+    task_cfg.attr.stack_size =0x2000;// handle->config.stack_size;
+    task_cfg.func = ws_server_thread_func;
+    task_cfg.use_mem = USE_EXTEND_MEM;
+    
+    // 创建线程
+    errcode_t ret = uapi_create_osThread_custom(&task_cfg);
+    if (ret != ERRCODE_SUCC) {
+        printf("Failed to create server thread: %d\n", ret);
+        g_thread_handles[handle->type] = NULL;  // 清理对应服务类型的全局变量
+        return ret;
+    }
+    
+    handle->need_stop = 0;
+    
+    printf("WebSocket server started: type=%d %s\n", handle->type,handle->config.name);
+    return ERRCODE_SUCC;
+}
+
+/**
+ * @brief 停止WebSocket服务器
+ */
+void ws_server_stop(ws_server_handle_t *handle)
+{
+    if (!handle || !handle->is_running) {
+        return;
+    }
+    
+    handle->need_stop = 1;
+    handle->is_running = 0;
+    
+    // 发送关闭消息
+    if (handle->client) {
+        send_websocket_message(handle->client, (uint8_t *)"WS_CLOSE", strlen("WS_CLOSE"), WS_CLOSE);
+    }
+    
+    printf("WebSocket server stopped: type=%d\n", handle->type);
+}
+
+/**
+ * @brief 发送WebSocket消息
+ */
+bool ws_server_send_message(ws_server_handle_t *handle, 
+                            uint8_t *data, 
+                           uint32_t len, 
+                           WebSocketMessageType msg_type)
+{
+    if (!handle || !handle->client || !data || len == 0) {
+        return false;
+    }
+    
+    if (send_websocket_message(handle->client, data, len, msg_type) == 0) {
+        return true;
+    }
+    
+    return false;
+}
+
+/**
+ * @brief 获取服务器状态
+ */
+ws_server_state_t ws_server_get_state(const ws_server_handle_t *handle)
+{
+    if (!handle) {
+        return WS_SERVER_STATE_ERROR;
+    }
+    
+    return handle->state;
+}
+
+/**
+ * @brief 检查服务器是否运行
+ */
+bool ws_server_is_running(const ws_server_handle_t *handle)
+{
+    if (!handle) {
+        return false;
+    }
+    
+    return handle->is_running;
+}
+
+/**
+ * @brief 设置服务器停止标志
+ */
+void ws_server_set_stop_flag(ws_server_handle_t *handle, bool stop)
+{
+    if (!handle) {
+        return;
+    }
+    
+    handle->need_stop = stop;
+}
+
+/**
+ * @brief 设置断连处理策略
+ */
+void ws_server_set_disconnect_strategy(ws_server_handle_t *handle, ws_disconnect_strategy_t strategy)
+{
+    if (!handle) {
+        return;
+    }
+    
+    handle->config.disconnect_strategy = strategy;
+    printf("Disconnect strategy set to %d for server type %d\n", strategy, handle->type);
+}
+
+/**
+ * @brief 手动触发重连
+ */
+bool ws_server_trigger_reconnect(ws_server_handle_t *handle)
+{
+    if (!handle || !handle->is_running) {
+        return false;
+    }
+    
+    printf("Manual reconnect triggered for server type %d\n", handle->type);
+    return ws_server_attempt_reconnect(handle);
+}
+
+/**
+ * @brief 获取默认配置
+ */
+ws_server_config_t ws_server_get_default_config(ws_server_type_t type)
+{
+    ws_server_config_t config = {};
+    
+    config.type = type;
+    config.handshake_timeout_ms = 10000;
+    config.receive_timeout_ms = 30000;
+    config.max_retry_count = 3;
+    config.buffer_size = 4096;
+    config.url_callback = NULL;
+    config.url_user_data = NULL;
+    config.disconnect_strategy = WS_DISCONNECT_RECONNECT;
+    config.reconnect_interval_ms = 5000;
+    
+    switch (type) {
+        case WS_SERVER_TYPE_ASR:
+            strcpy(config.name, "asr_server");
+            config.stack_size = 0x1000;
+            break;
+        case WS_SERVER_TYPE_TTS:
+            strcpy(config.name, "tts_server");
+            config.stack_size = 0x2000;
+            break;
+        case WS_SERVER_TYPE_CHAT:
+            strcpy(config.name, "chat_server");
+            config.stack_size = 0x1000;
+            break;
+        default:
+            break;
+    }
+    
+    return config;
+}
+
+/**
+ * @brief 注册URL生成回调函数
+ */
+bool ws_server_register_url_callback(ws_server_type_t type, 
+                                    ws_url_callback_t url_callback, 
+                                    void *user_data)
+{
+    if (type >= WS_SERVER_TYPE_MAX) {
+        printf("Invalid server type: %d\n", type);
+        return false;
+    }
+    
+    g_url_callbacks[type] = url_callback;
+    g_url_user_data[type] = user_data;
+    
+    printf("URL callback registered for server type: %d\n", type);
+    return true;
+}
+
+/**
+ * @brief 创建URL(使用注册的回调函数)
+ */
+bool ws_server_create_url(ws_server_handle_t *handle, 
+                         char *url_buf, 
+                         uint32_t url_size)
+{
+    if (!handle || !url_buf || url_size == 0) {
+        return false;
+    }
+    
+    // 优先使用句柄中的URL回调函数
+    if (handle->url_callback) {
+        return handle->url_callback(handle->type, url_buf, url_size, handle->url_user_data);
+    }
+    
+    // 使用全局注册的URL回调函数
+    if (g_url_callbacks[handle->type]) {
+        return g_url_callbacks[handle->type](handle->type, url_buf, url_size, g_url_user_data[handle->type]);
+    }
+    
+    // 如果没有注册回调函数,使用默认URL
+    switch (handle->type) {
+        case WS_SERVER_TYPE_ASR:
+            snprintf(url_buf, url_size, "ws://118.145.158.207:22080/asr/ws");
+            break;
+        case WS_SERVER_TYPE_TTS:
+            snprintf(url_buf, url_size, "ws://118.145.158.207:22080/tts/stream?audio_buffer_size=512");
+            break;
+        case WS_SERVER_TYPE_CHAT:
+            snprintf(url_buf, url_size, "ws://118.145.158.207:22080/chat/ws");
+            break;
+        default:
+            return false;
+    }
+    
+    return true;
+}
+
+/**
+ * @brief WebSocket服务器线程函数
+ */
+static void ws_server_thread_func(void *data)
+{
+    // 由于uapi_create_osThread_custom不支持参数传递,需要找到当前线程对应的handle
+    // 遍历所有服务类型,找到正在运行且需要启动的服务器
+    ws_server_handle_t *handle = NULL;
+    for (int i = 0; i < WS_SERVER_TYPE_MAX; i++) {
+        if (g_thread_handles[i] && !g_thread_handles[i]->is_running && !g_thread_handles[i]->need_stop) {
+            handle = g_thread_handles[i];
+            break;
+        }
+    }
+   
+    if (!handle) {
+        printf("WebSocket server thread: no running server found\n");
+        return;
+    }
+    handle->is_running = 1;
+
+    uint32_t last_activity;
+    
+    printf("WebSocket server thread started: type=%d\n", handle->type);
+    
+    // 连接服务器
+    if (!ws_server_connect(handle)) {
+        printf("Failed to connect server: type=%d\n", handle->type);
+        ws_server_trigger_event(handle, WS_EVENT_ERROR, NULL, 0, WS_TEXT, 1);
+        goto cleanup;
+    }
+    
+    // 触发连接完成事件
+    ws_server_trigger_event(handle, WS_EVENT_CONNECTED, NULL, 0, WS_TEXT, 0);
+    
+    // 主循环
+    last_activity = (uint32_t)osKernelGetTickCount();
+
+    handle->is_initialized = 1;
+    
+    while (!handle->need_stop) {
+        // 检查超时
+        if ((uint32_t)osKernelGetTickCount() - last_activity > handle->config.receive_timeout_ms) {
+            printf("Receive timeout, checking reconnect strategy...\n");
+            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();
+                    continue;
+                }
+            }
+            break;
+        }
+        
+        // 接收消息
+        memset(handle->recv_buffer, 0, handle->config.buffer_size);
+        WebSocketMessageType msg_type;
+        // int len = receive_websocket_message_from_queue(&handle->msg_queue, 
+        //                                               (unsigned char *)handle->recv_buffer, 
+        //                                               handle->config.buffer_size, 
+        //                                               &msg_type, 
+        //                                               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 (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);
+            
+            if (ws_server_should_reconnect(handle)) {
+                if (ws_server_attempt_reconnect(handle)) {
+                    last_activity = (uint32_t)osKernelGetTickCount();
+                    continue;
+                }
+            }
+            break;
+        }
+
+        if(len==0)
+        {
+            printf("handle->config.receive_timeout_ms \n");
+        }
+        
+        if (len > 0) {
+            last_activity = (uint32_t)osKernelGetTickCount();
+            
+            // 确保字符串以null结尾
+            if (len < handle->config.buffer_size) {
+                handle->recv_buffer[len] = '\0';
+            }
+            
+            // 触发数据接收事件
+            ws_server_trigger_event(handle, WS_EVENT_DATA_RECEIVED, 
+                                  (uint8_t *)handle->recv_buffer, len, msg_type, 0);
+        }
+        
+        msleep(10);
+    }
+    
+cleanup:
+    msleep(100);
+    ws_server_disconnect(handle);
+    ws_server_cleanup(handle);
+    
+    // 清理对应服务类型的全局变量
+    if (handle) {
+        g_thread_handles[handle->type] = NULL;
+        printf("WebSocket server thread ended: type=%d\n", handle->type);
+    }
+}
+
+/**
+ * @brief WebSocket数据包回调函数
+ */
+static void ws_server_packet_callback(uint8_t* data, size_t datalen, WebSocketMessageType type, ws_server_handle_t *handle)
+{
+    if (handle && handle->client && handle->client->msg_queue) {
+        ws_queue_put(handle->client->msg_queue, data, datalen, type);
+    }
+}
+
+/**
+ * @brief 触发事件
+ */
+static void ws_server_trigger_event(ws_server_handle_t *handle, ws_event_type_t event_type, 
+                                   const uint8_t *data, uint32_t data_len, WebSocketMessageType msg_type, uint32_t error_code)
+{
+    if (!handle || !handle->callback) {
+        return;
+    }
+    
+    ws_event_data_t event_data = {};
+    event_data.event_type = event_type;
+    event_data.server_type = handle->type;
+    event_data.data = (uint8_t *)data;
+    event_data.data_len = data_len;
+    event_data.msg_type = msg_type;
+    event_data.error_code = error_code;
+    
+    handle->callback(&event_data);
+}
+
+/**
+ * @brief 连接服务器
+ */
+static bool ws_server_connect(ws_server_handle_t *handle)
+{
+    if (!handle) {
+        return false;
+    }
+    
+    handle->state = WS_SERVER_STATE_CONNECTING;
+    
+    // 创建URL
+    char url_buf[256] = {0};
+    if (!ws_server_create_url(handle, url_buf, sizeof(url_buf))) {
+        printf("Failed to create URL for server type %d\n", handle->type);
+        return false;
+    }
+    
+    // 根据测试服务器索引选择URL
+    extern uint8_t g_test_server_index;
+    if (g_test_server_index == 1) {
+        switch (handle->type) {
+            case WS_SERVER_TYPE_ASR:
+                strcpy(url_buf, "ws://118.145.158.207:22080/asr/ws");
+                break;
+            case WS_SERVER_TYPE_TTS:
+                strcpy(url_buf, "ws://118.145.158.207:22080/tts/stream");
+                break;
+            case WS_SERVER_TYPE_CHAT:
+                strcpy(url_buf, "ws://118.145.158.207:22080/chat/ws");
+                break;
+            default:
+                break;
+        }
+    } else if (g_test_server_index == 2) {
+        switch (handle->type) {
+            case WS_SERVER_TYPE_ASR:
+                strcpy(url_buf, "ws://110.42.224.129:8910/asr/ws");
+                break;
+            case WS_SERVER_TYPE_TTS:
+                strcpy(url_buf, "ws://110.42.224.129:8910/tts/stream");
+                break;
+            case WS_SERVER_TYPE_CHAT:
+                strcpy(url_buf, "ws://110.42.224.129:8910/chat/ws");
+                break;
+            default:
+                break;
+        }
+    }
+    
+    printf("Connecting to: %s\n", url_buf);
+    
+    // 创建WebSocket客户端
+    uint8_t client_count = handle->config.max_retry_count;
+    while (client_count > 0) {
+        handle->client = init_websocket_client(url_buf, NULL, 0);
+        if (handle->client) {
+            handle->client->msg_queue = &handle->msg_queue;
+            ws_set_packet_callback(handle->client, (void (*)(uint8_t*, size_t, WebSocketMessageType))ws_server_packet_callback);
+            break;
+        }
+        
+        printf("WebSocket client creation failed, retrying... (%d/%d)\n", 
+               handle->config.max_retry_count - client_count + 1, handle->config.max_retry_count);
+        client_count--;
+        msleep(2000);
+    }
+    
+    if (!handle->client) {
+        printf("Failed to create WebSocket client after %d retries\n", handle->config.max_retry_count);
+        handle->state = WS_SERVER_STATE_ERROR;
+        return false;
+    }
+    
+    printf("WebSocket client created successfully\n");
+    
+    // 等待握手完成
+    uint32_t handshake_start_time = (uint32_t)osKernelGetTickCount();
+    while (handle->client->handshake == 0) {
+        if ((uint32_t)osKernelGetTickCount() - handshake_start_time > handle->config.handshake_timeout_ms) {
+            printf("WebSocket handshake timeout (%d ms)\n", handle->config.handshake_timeout_ms);
+            close_websocket_client(handle->client);
+            handle->client = NULL;
+            handle->state = WS_SERVER_STATE_ERROR;
+            return false;
+        }
+        
+        msleep(1000);
+        printf("Waiting for WebSocket handshake... (%d ms)\n", 
+               (uint32_t)osKernelGetTickCount() - handshake_start_time);
+    }
+    
+    printf("WebSocket handshake completed in %d ms\n", 
+           (uint32_t)osKernelGetTickCount() - handshake_start_time);
+    
+    handle->state = WS_SERVER_STATE_CONNECTED;
+    return true;
+}
+
+/**
+ * @brief 断开服务器连接
+ */
+static void ws_server_disconnect(ws_server_handle_t *handle)
+{
+    if (!handle) {
+        return;
+    }
+    
+    if (handle->client) {
+        close_websocket_client(handle->client);
+        handle->client = NULL;
+    }
+    
+    handle->state = WS_SERVER_STATE_DISCONNECTED;
+}
+
+/**
+ * @brief 清理服务器资源
+ */
+static void ws_server_cleanup(ws_server_handle_t *handle)
+{
+    if (!handle) {
+        return;
+    }
+    
+    ws_server_disconnect(handle);
+    
+    if (handle->recv_buffer) {
+        free(handle->recv_buffer);
+        handle->recv_buffer = NULL;
+    }
+    
+    ws_queue_deinit(&handle->msg_queue);
+    handle->is_running = 0;
+    handle->is_initialized = 0;
+}
+
+/**
+ * @brief 判断是否应该重连
+ */
+static bool ws_server_should_reconnect(ws_server_handle_t *handle)
+{
+    if (!handle) {
+        return false;
+    }
+    
+    // 如果设置了停止标志,不重连
+    if (handle->need_stop) {
+        printf("Server stop flag set, no reconnect\n");
+        return false;
+    }
+    uint32_t current_time;
+    // 根据断连处理策略判断
+    switch (handle->config.disconnect_strategy) {
+        case WS_DISCONNECT_STOP:
+            printf("Disconnect strategy is STOP, no reconnect\n");
+            return false;
+            
+        case WS_DISCONNECT_RECONNECT:
+            // 检查重连次数限制
+            if (handle->reconnect_count >= handle->config.max_retry_count) {
+                printf("Max reconnect count (%d) reached, no more reconnects\n", 
+                       handle->config.max_retry_count);
+                return false;
+            }
+            
+            // 检查重连间隔时间
+             current_time = (uint32_t)osKernelGetTickCount();
+            if (handle->last_reconnect_time > 0 && 
+                current_time - handle->last_reconnect_time < handle->config.reconnect_interval_ms) {
+                printf("Reconnect interval not reached, waiting...\n");
+                return false;
+            }
+            
+            printf("Should reconnect: count=%d/%d\n", 
+                   handle->reconnect_count, handle->config.max_retry_count);
+            return true;
+            
+        case WS_DISCONNECT_CUSTOM:
+            // 自定义处理,由事件回调函数决定
+            printf("Custom disconnect strategy, let callback decide\n");
+            return true;
+            
+        default:
+            return false;
+    }
+}
+
+/**
+ * @brief 尝试重连
+ */
+static bool ws_server_attempt_reconnect(ws_server_handle_t *handle)
+{
+    if (!handle) {
+        return false;
+    }
+    
+    printf("Attempting to reconnect server type %d (attempt %d/%d)\n", 
+           handle->type, handle->reconnect_count + 1, handle->config.max_retry_count);
+    
+    // 断开当前连接
+    ws_server_disconnect(handle);
+    
+    // 等待重连间隔
+    if (handle->config.reconnect_interval_ms > 0) {
+        msleep(handle->config.reconnect_interval_ms);
+    }
+    
+    // 尝试重新连接
+    bool success = ws_server_connect(handle);
+    
+    if (success) {
+        handle->reconnect_count++;
+        handle->last_reconnect_time = (uint32_t)osKernelGetTickCount();
+        printf("Reconnect successful for server type %d\n", handle->type);
+        
+        // 触发重连成功事件
+        ws_server_trigger_event(handle, WS_EVENT_CONNECTED, NULL, 0, WS_TEXT, 0);
+    } else {
+        printf("Reconnect failed for server type %d\n", handle->type);
+        
+        // 触发重连失败事件
+        ws_server_trigger_event(handle, WS_EVENT_ERROR, NULL, 0, WS_TEXT, 1);
+    }
+    
+    return success;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/code/sdk/zhihui/ai_old/websocket_server_manager.h b/code/sdk/zhihui/ai_old/websocket_server_manager.h
new file mode 100644 (file)
index 0000000..6814096
--- /dev/null
@@ -0,0 +1,255 @@
+/**
+ * @file websocket_server_manager.h
+ * @brief 统一WebSocket服务器管理接口
+ * @version 1.0.0
+ * @date 2024-09-05
+ * 
+ * 提供统一的WebSocket服务器管理接口,支持事件回调
+ */
+
+#ifndef WEBSOCKET_SERVER_MANAGER_H
+#define WEBSOCKET_SERVER_MANAGER_H
+
+#include "zhihui_ws.h"
+#include "bk_websocket.h"
+#include "ws_queue_common.h"
+#include "common_def.h"
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+
+/* WebSocket服务器类型定义 */
+typedef enum {
+    WS_SERVER_TYPE_ASR = 0,    // ASR服务器
+    WS_SERVER_TYPE_TTS = 1,    // TTS服务器
+    WS_SERVER_TYPE_CHAT = 2,   // Chat服务器
+    WS_SERVER_TYPE_MAX
+} ws_server_type_t;
+
+
+/* URL生成回调函数类型 */
+typedef bool (*ws_url_callback_t)(ws_server_type_t type, char *url_buf, uint32_t url_size, void *user_data);
+
+/* WebSocket服务器状态 */
+typedef enum {
+    WS_SERVER_STATE_INIT = 0,      // 初始化
+    WS_SERVER_STATE_CONNECTING,    // 连接中
+    WS_SERVER_STATE_CONNECTED,     // 已连接
+    WS_SERVER_STATE_DISCONNECTED,  // 已断开
+    WS_SERVER_STATE_ERROR,         // 错误状态
+    WS_SERVER_STATE_MAX
+} ws_server_state_t;
+
+/* WebSocket事件类型 */
+typedef enum {
+    WS_EVENT_CONNECTED = 0,        // 连接完成
+    WS_EVENT_DATA_RECEIVED,        // 数据接收
+    WS_EVENT_DISCONNECTED,         // 连接断开
+    WS_EVENT_RECONNECTING,         // 重连中
+    WS_EVENT_ERROR,                // 错误事件
+    WS_EVENT_MAX
+} ws_event_type_t;
+
+/* 断连处理策略 */
+typedef enum {
+    WS_DISCONNECT_STOP = 0,        // 停止服务
+    WS_DISCONNECT_RECONNECT,       // 重连服务
+    WS_DISCONNECT_CUSTOM           // 自定义处理
+} ws_disconnect_strategy_t;
+
+/* WebSocket服务器配置 */
+typedef struct {
+    ws_server_type_t type;         // 服务器类型
+    char name[32];                 // 服务器名称
+    ws_url_callback_t url_callback; // URL生成回调函数
+    void *url_user_data;           // URL回调用户数据
+    uint32_t stack_size;           // 线程栈大小
+    uint32_t handshake_timeout_ms; // 握手超时时间(ms)
+    uint32_t receive_timeout_ms;   // 接收超时时间(ms)
+    uint32_t max_retry_count;      // 最大重试次数
+    uint32_t buffer_size;          // 接收缓冲区大小
+    ws_disconnect_strategy_t disconnect_strategy; // 断连处理策略
+    uint32_t reconnect_interval_ms; // 重连间隔时间(ms)
+} ws_server_config_t;
+
+/* WebSocket事件数据 */
+typedef struct {
+    ws_event_type_t event_type;    // 事件类型
+    ws_server_type_t server_type;  // 服务器类型
+    uint8_t *data;                 // 数据指针
+    uint32_t data_len;             // 数据长度
+    WebSocketMessageType msg_type; // 消息类型
+    uint32_t error_code;           // 错误码
+} ws_event_data_t;
+
+/* 事件回调函数类型 */
+typedef void (*ws_event_callback_t)(const ws_event_data_t *event_data);
+
+
+/* WebSocket服务器句柄 */
+typedef struct {
+    ws_server_type_t type;         // 服务器类型
+    ws_server_state_t state;       // 当前状态
+    WebSocketClient *client;       // WebSocket客户端
+    ws_message_queue_t msg_queue;  // 消息队列
+    ws_server_config_t config;     // 服务器配置
+    ws_event_callback_t callback;  // 事件回调函数
+    void *user_data;               // 用户数据
+    ws_url_callback_t url_callback; // URL生成回调函数
+    void *url_user_data;           // URL回调用户数据
+    uint8_t is_running;            // 运行标志
+    uint8_t need_stop;             // 停止标志
+    uint8_t is_initialized;        // 初始化标志
+    char *recv_buffer;             // 接收缓冲区
+    uint32_t reconnect_count;      // 重连次数
+    uint32_t last_reconnect_time;  // 上次重连时间
+} ws_server_handle_t;
+
+/* 函数声明 */
+
+/**
+ * @brief 初始化WebSocket服务器管理器
+ * @return errcode_t 错误码
+ */
+errcode_t ws_server_manager_init(void);
+
+/**
+ * @brief 反初始化WebSocket服务器管理器
+ */
+void ws_server_manager_deinit(void);
+
+/**
+ * @brief 创建WebSocket服务器
+ * @param config 服务器配置
+ * @param callback 事件回调函数
+ * @param user_data 用户数据
+ * @return ws_server_handle_t* 服务器句柄,失败返回NULL
+ */
+ws_server_handle_t* ws_server_create(const ws_server_config_t *config, 
+                                   ws_event_callback_t callback, 
+                                   void *user_data);
+
+/**
+ * @brief 销毁WebSocket服务器
+ * @param handle 服务器句柄
+ */
+void ws_server_destroy(ws_server_handle_t *handle);
+
+/**
+ * @brief 启动WebSocket服务器
+ * @param handle 服务器句柄
+ * @return errcode_t 错误码
+ */
+errcode_t ws_server_start(ws_server_handle_t *handle);
+
+/**
+ * @brief 停止WebSocket服务器
+ * @param handle 服务器句柄
+ */
+void ws_server_stop(ws_server_handle_t *handle);
+
+/**
+ * @brief 发送WebSocket消息
+ * @param handle 服务器句柄
+ * @param data 数据指针
+ * @param len 数据长度
+ * @param msg_type 消息类型
+ * @return bool 成功返回true,失败返回false
+ */
+bool ws_server_send_message(ws_server_handle_t *handle, 
+                            uint8_t *data, 
+                           uint32_t len, 
+                           WebSocketMessageType msg_type);
+
+/**
+ * @brief 获取服务器状态
+ * @param handle 服务器句柄
+ * @return ws_server_state_t 服务器状态
+ */
+ws_server_state_t ws_server_get_state(const ws_server_handle_t *handle);
+
+/**
+ * @brief 检查服务器是否运行
+ * @param handle 服务器句柄
+ * @return bool 运行返回true,否则返回false
+ */
+bool ws_server_is_running(const ws_server_handle_t *handle);
+
+/**
+ * @brief 设置服务器停止标志
+ * @param handle 服务器句柄
+ * @param stop 停止标志
+ */
+void ws_server_set_stop_flag(ws_server_handle_t *handle, bool stop);
+
+/**
+ * @brief 设置断连处理策略
+ * @param handle 服务器句柄
+ * @param strategy 断连处理策略
+ */
+void ws_server_set_disconnect_strategy(ws_server_handle_t *handle, ws_disconnect_strategy_t strategy);
+
+/**
+ * @brief 手动触发重连
+ * @param handle 服务器句柄
+ * @return bool 成功返回true,失败返回false
+ */
+bool ws_server_trigger_reconnect(ws_server_handle_t *handle);
+
+/**
+ * @brief 获取默认配置
+ * @param type 服务器类型
+ * @return ws_server_config_t 默认配置
+ */
+ws_server_config_t ws_server_get_default_config(ws_server_type_t type);
+
+/**
+ * @brief 注册URL生成回调函数
+ * @param type 服务器类型
+ * @param url_callback URL生成回调函数
+ * @param user_data 用户数据
+ * @return bool 成功返回true,失败返回false
+ */
+bool ws_server_register_url_callback(ws_server_type_t type, 
+                                    ws_url_callback_t url_callback, 
+                                    void *user_data);
+
+/**
+ * @brief 创建URL(使用注册的回调函数)
+ * @param handle 服务器句柄
+ * @param url_buf URL缓冲区
+ * @param url_size URL缓冲区大小
+ * @return bool 成功返回true,失败返回false
+ */
+bool ws_server_create_url(ws_server_handle_t *handle, 
+                         char *url_buf, 
+                         uint32_t url_size);
+
+errcode_t start_all_websocket_servers(void);
+
+errcode_t init_all_websocket_servers(void);
+
+void uapi_start_asr_StartTranscription(void);
+
+
+void uapi_stop_asr_StopTranscription(void);
+
+void stop_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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WEBSOCKET_SERVER_MANAGER_H */
index a8adc55..0f69010 100644 (file)
@@ -65,7 +65,7 @@
 // 包含新的WebSocket解析器
 #include "websocket_parser_wrapper.h"
 
-#define TEST_AI_WS 0
+#define TEST_AI_WS 1
 
 #ifdef __cplusplus
 extern "C" {
@@ -674,7 +674,7 @@ WebSocketClient *init_websocket_client(const char *url, const char *headers,uint
     ssize_t bytes_received;
     struct in_addr in_addr_t={0};
     ip_addr_t  ip;
-    struct cat1_ws_init_t ip_sem={0};
+    // struct cat1_ws_init_t ip_sem={0};
     int opt = 1;
     int sockfd = -1;
 
@@ -748,7 +748,7 @@ WebSocketClient *init_websocket_client(const char *url, const char *headers,uint
     if (lwip_connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
         printf("init_websocket_client connection failed\r\n");
         msleep(100);
-        close(sockfd);
+        lwip_close(sockfd);
 
         goto client_ERROR;
 
@@ -765,7 +765,7 @@ WebSocketClient *init_websocket_client(const char *url, const char *headers,uint
     if (send_handshake(client,headers) < 0) { //发送头
         printf("socket send_handshake client_ERROR");
 
-        close(sockfd);
+        lwip_close(sockfd);
         goto client_ERROR;
     }
 
@@ -776,7 +776,7 @@ WebSocketClient *init_websocket_client(const char *url, const char *headers,uint
          printf("aic_zalloc(BUFFER_SIZE);null ");
           goto client_ERROR;
     }
-    printf("recv: ???  ");
+    printf("recv:%s\r\n",parsed_url.path);
 
     bytes_received = lwip_recv(sockfd, buffer, BUFFER_SIZE - 1, 0);
 
@@ -799,21 +799,13 @@ WebSocketClient *init_websocket_client(const char *url, const char *headers,uint
 
      printf("init_websocket_client end 2");
 
-    client->tcp_handle = tcp_add_existing_connection(sockfd, parsed_url.host, parsed_url.port,
-                                                    _tcp_on_connect_cb, _tcp_on_disconnect_cb, _tcp_on_data_received_cb);
-    
-    client->parser = ws_parser_init();
+
 
     free(buffer);
     free_url(parsed_url);
 
     client->handshake=1;
 
-    if (!client->parser) {
-        WS_LOG_ERROR("init_websocket_client Error: Failed to initialize WebSocket parser");
-        close(sockfd);
-        goto client_ERROR;
-    }
 
     return client;
 client_ERROR:
@@ -876,6 +868,7 @@ WebSocketClient *init_websocket_client(const char *url, const char *headers,uint
     }
     
     // 使用标准 socket 替代 TCP 管理器
+    printf("lwip_socket init_websocket_client\r\n");
     client->sockfd = lwip_socket(AF_INET, SOCK_STREAM, 0);
     if (client->sockfd < 0) {
         WS_LOG_ERROR("init_websocket_client Error: Socket creation failed");
@@ -883,11 +876,11 @@ WebSocketClient *init_websocket_client(const char *url, const char *headers,uint
     }
     
     // 设置 socket 选项
-    lwip_setsockopt(client->sockfd, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val));
+    // lwip_setsockopt(client->sockfd, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val));
     
-    // 设置非阻塞模式
-    flags = fcntl(client->sockfd, F_GETFL, 0);
-    fcntl(client->sockfd, F_SETFL, flags | O_NONBLOCK);
+    // // 设置非阻塞模式
+    // flags = fcntl(client->sockfd, F_GETFL, 0);
+    // fcntl(client->sockfd, F_SETFL, flags | O_NONBLOCK);
     
     // 解析主机地址
     memset(&server_addr, 0, sizeof(server_addr));
@@ -905,12 +898,13 @@ WebSocketClient *init_websocket_client(const char *url, const char *headers,uint
     }
     
     // 连接到服务器
+
     connect_result = lwip_connect(client->sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
     if (connect_result < 0 && errno != EINPROGRESS) {
         WS_LOG_ERROR("init_websocket_client Error: Socket connection failed for %s:%d", parsed_url.host, parsed_url.port);
         goto client_ERROR;
     }
-    
+    printf("lwip_connect init_websocket_client\r\n");
     // 等待连接完成
     if (connect_result == 0 || errno == EINPROGRESS) {
         FD_ZERO(&write_fds);
@@ -940,11 +934,16 @@ WebSocketClient *init_websocket_client(const char *url, const char *headers,uint
                 WS_LOG_ERROR("Socket connection failed with error: %d", error);
                 goto client_ERROR;
             }
-        } else {
+        } 
+        else {
             WS_LOG_ERROR("Socket connection timeout or failed");
             goto client_ERROR;
         }
     }
+    else
+    {
+        printf("connect_result fail init_websocket_client\r\n");
+    }
     
     // 设置回阻塞模式用于后续通信
     flags = fcntl(client->sockfd, F_GETFL, 0);
@@ -1006,15 +1005,15 @@ void close_websocket_client(WebSocketClient *client) {
         
         // 先关闭socket连接,避免数据继续流入
         if (client->sockfd >= 0) {
-            close(client->sockfd);
+            lwip_close(client->sockfd);
             client->sockfd = -1;
         }
         
         // 释放WebSocket解析器
-        if (client->parser) {
-            ws_parser_destroy(client->parser);
-            client->parser = NULL;
-        }
+        // if (client->parser) {
+        //     ws_parser_destroy(client->parser);
+        //     client->parser = NULL;
+        // }
         
         // 清理客户端状态
         client->handshake = 0;
@@ -1336,6 +1335,327 @@ static int start_websocket_receive_thread(WebSocketClient* client) {
     return 0;
 }
 
+
+// 带超时的lwip_recv包装函数
+static int lwip_recv_with_timeout(int sockfd, void *buf, size_t len, int flags, uint32_t timeout_ms) {
+    uint32_t start_time = (uint32_t)osKernelGetTickCount();
+    int bytes_received = 0;
+    
+    while (bytes_received < (int)len) {
+        // 检查超时
+        uint32_t current_time = (uint32_t)osKernelGetTickCount();
+        if ((current_time - start_time) >= timeout_ms) {
+            printf("lwip_recv_with_timeout: timeout after %u ms\n", timeout_ms);
+            return -1;
+        }
+        
+        // 尝试接收数据
+        int ret = lwip_recv(sockfd, (char*)buf + bytes_received, len - bytes_received, flags);
+        
+        if (ret > 0) {
+            bytes_received += ret;
+        } else if (ret == 0) {
+            printf("lwip_recv_with_timeout: connection closed by peer\n");
+            return 0;
+        } else {
+            // ret < 0, 检查是否是EAGAIN或EWOULDBLOCK
+            if (errno == EAGAIN || errno == EWOULDBLOCK) {
+                // 没有数据可读,短暂等待后重试
+                printf("errno == EAGAIN || errno == EWOULDBLOCK");
+                msleep(10);  // 等待10ms
+                continue;
+            } else {
+                printf("lwip_recv_with_timeout: error %d\n", errno);
+                return -1;
+            }
+        }
+    }
+    
+    return bytes_received;
+}
+
+int  receive_websocket_message(WebSocketClient *client, unsigned char *buf,int len,WebSocketMessageType *code, uint32_t timeout_ms) {
+    uint32_t start_time = (uint32_t)osKernelGetTickCount();
+    uint32_t timer_ms = start_time;
+    //printf("receive_websocket_message 1 timer_ms=%d\n",timer_ms);
+    unsigned char frame[20]={0};
+    unsigned char masking_key[4];
+    int bytes_received = 0;
+    int recv_len = 0 ;
+    static uint8_t last_byte = 0;
+    
+    // 超时检查函数
+    auto check_timeout = [&]() -> bool {
+        uint32_t current_time = (uint32_t)osKernelGetTickCount();
+        return (current_time - start_time) >= timeout_ms;
+    };
+    // while(1)
+    // {
+    //     recv_len = lwip_send(client->sockfd, frame+bytes_received, 2-bytes_received, 0);
+    //     bytes_received +=recv_len;
+    //     if(bytes_received>=2)
+    //         break;
+    // }
+    int max_count=len;
+
+    while(max_count)
+    {
+        // 检查超时
+        if (check_timeout()) {
+            printf("receive_websocket_message: timeout while waiting for frame header\n");
+            return -1;
+        }
+        
+        // 使用带超时的lwip_recv
+        uint32_t remaining_time = timeout_ms - ((uint32_t)osKernelGetTickCount() - start_time);
+        if (remaining_time <= 0) {
+            printf("receive_websocket_message: timeout while waiting for frame header\n");
+            return -1;
+        }
+        
+        bytes_received = lwip_recv_with_timeout(client->sockfd, frame, 1, 0, remaining_time);
+
+        if (bytes_received <= 0) 
+        {
+            if (bytes_received == 0) {
+                printf("Connection lwip_closed by server.\n");
+            } else {
+                printf("receive message failed");
+            }
+            return -1;
+        }
+        max_count--;
+
+        if(frame[0]!= 0x80 && frame[0]!= 0x81 && frame[0]!= 0x82 && frame[0]!= 0x88 && frame[0]!= 0x89 && frame[0]!= 0x8A)
+        {
+            printf("receive_websocket_message:hend =0x%X,0x%X ,last_byte =0x%x ERROR!!!!!!!!!",frame[0],frame[1],last_byte);
+
+            if(last_byte!= 0x80 && last_byte!= 0x81 && last_byte!= 0x82 && last_byte!= 0x88 && last_byte!= 0x89 && last_byte!= 0x8A)
+            {
+                printf("receive_websocket_message:hend =0x%X,0x%X ,last_byte =0x%x ERROR222222222!!!!!!!!!",frame[0],frame[1],last_byte);
+                continue;
+            }
+            if(frame[0]==0 && frame[1]==0 && last_byte==0)
+            {
+                break;
+            }
+                
+        }
+        else
+        {
+            break;
+        }
+    }
+    if(max_count==0)
+    {
+        return -1;
+    }
+    // 检查超时
+    if (check_timeout()) {
+        printf("receive_websocket_message: timeout while waiting for frame length\n");
+        return -1;
+    }
+    
+    timer_ms = (uint32_t)osKernelGetTickCount();
+    //printf("receive_websocket_message 2 timer_ms=%d\n",timer_ms);
+    
+    // 使用带超时的lwip_recv
+    uint32_t remaining_time = timeout_ms - ((uint32_t)osKernelGetTickCount() - start_time);
+    if (remaining_time <= 0) {
+        printf("receive_websocket_message: timeout while waiting for frame length\n");
+        return -1;
+    }
+    
+    bytes_received = lwip_recv_with_timeout(client->sockfd, frame+1, 1, 0, remaining_time);
+    if (bytes_received <= 0) {
+        if (bytes_received == 0) {
+            printf("Connection lwip_closed by server.\n");
+        } else {
+            printf("receive message failed");
+        }
+        return -1;
+    }
+    //unsigned char fin = (frame[0] & 0x80) >> 7;
+    *code = (WebSocketMessageType) (frame[0] & 0x0F);
+    unsigned char mask = (frame[1] & 0x80) >> 7;
+    unsigned int payload_len = frame[1] & 0x7F;
+    
+
+    size_t offset = 2;
+    if (payload_len == 126) {
+        // 检查超时
+        if (check_timeout()) {
+            printf("receive_websocket_message: timeout while waiting for extended length (126)\n");
+            return -1;
+        }
+        
+        // 使用带超时的lwip_recv
+        uint32_t remaining_time = timeout_ms - ((uint32_t)osKernelGetTickCount() - start_time);
+        if (remaining_time <= 0) {
+            printf("receive_websocket_message: timeout while waiting for extended length (126)\n");
+            return -1;
+        }
+        
+        unsigned short extended_payload_len;
+        int ret = lwip_recv_with_timeout(client->sockfd, frame+offset, 2, 0, remaining_time);
+        if (ret <= 0) {
+            printf("receive_websocket_message: failed to receive extended length (126)\n");
+            return -1;
+        }
+        bytes_received += ret;
+        memcpy(&extended_payload_len, frame + 2, 2);
+        payload_len = ntohs(extended_payload_len);
+        //printf("receive_websocket_message:payload_len=0x%X",extended_payload_len);
+        offset += 2;
+    } else if (payload_len == 127) {
+        // 检查超时
+        if (check_timeout()) {
+            printf("receive_websocket_message: timeout while waiting for extended length (127)\n");
+            return -1;
+        }
+        
+        // 使用带超时的lwip_recv
+        uint32_t remaining_time = timeout_ms - ((uint32_t)osKernelGetTickCount() - start_time);
+        if (remaining_time <= 0) {
+            printf("receive_websocket_message: timeout while waiting for extended length (127)\n");
+            return -1;
+        }
+        
+        uint64_t extended_payload_len;
+        int ret = lwip_recv_with_timeout(client->sockfd, frame+offset, 8, 0, remaining_time);
+        if (ret <= 0) {
+            printf("receive_websocket_message: failed to receive extended length (127)\n");
+            return -1;
+        }
+        bytes_received += ret;
+        memcpy(&extended_payload_len, frame + 2, 8);
+        payload_len = ntohll(extended_payload_len);
+        offset += 8;
+    }
+    if(payload_len>len)
+    {
+        printf("receive_websocket_message:len =%d ERROR",payload_len);
+
+        // if(*code == WS_BINARY)
+        // {
+
+        // }
+        // fopen
+        // 使用带超时的lwip_recv丢弃多余数据
+        uint32_t remaining_time = timeout_ms - ((uint32_t)osKernelGetTickCount() - start_time);
+        if (remaining_time > 0) {
+            lwip_recv_with_timeout(client->sockfd, buf, len, 0, remaining_time);
+        }
+        return -1;
+    }
+    timer_ms = (uint32_t)osKernelGetTickCount();
+    //printf("receive_websocket_message 3 timer_ms=%d\n",timer_ms);
+    // printf("receive_websocket_message :");
+    // for(int i = 0;i<offset;i++)
+    // {
+    //     printf("%02X",frame[i]);
+    // }
+    // printf("receive_websocket_message:payload_len=%d frame[0]&0x8E=%d",payload_len,frame[0]&0x8E);
+    if (mask) {
+        // 检查超时
+        if (check_timeout()) {
+            printf("receive_websocket_message: timeout while waiting for masking key\n");
+            return -1;
+        }
+        
+        // 使用带超时的lwip_recv
+        uint32_t remaining_time = timeout_ms - ((uint32_t)osKernelGetTickCount() - start_time);
+        if (remaining_time <= 0) {
+            printf("receive_websocket_message: timeout while waiting for masking key\n");
+            return -1;
+        }
+        
+        int ret = lwip_recv_with_timeout(client->sockfd, frame+offset, 4, 0, remaining_time);
+        if (ret <= 0) {
+            printf("receive_websocket_message: failed to receive masking key\n");
+            return -1;
+        }
+        bytes_received = ret;
+        memcpy(masking_key, frame + offset, 4);
+        offset += 4;    
+    } 
+    bytes_received = 0;
+    
+    while(1)//读主体内容
+    {
+        // 检查超时
+        if (check_timeout()) {
+            printf("receive_websocket_message: timeout while receiving payload data\n");
+            return -1;
+        }
+        
+        // 使用带超时的lwip_recv
+        uint32_t remaining_time = timeout_ms - ((uint32_t)osKernelGetTickCount() - start_time);
+        if (remaining_time <= 0) {
+            printf("receive_websocket_message: timeout while receiving payload data\n");
+            return -1;
+        }
+        
+        //bk_sleep(recv_len/1000+1);
+        recv_len = lwip_recv_with_timeout(client->sockfd, buf+bytes_received, payload_len-bytes_received, 0, remaining_time);
+        if(recv_len>0)
+            bytes_received += recv_len;
+        else if(recv_len<0)
+        {
+            printf("receive_websocket_message: recv_len =%d  lwip_recv ERROR!!!!!!",recv_len);
+            return -1;
+        }
+        //printf("receive_websocket_message:bytes_received=%d recv_len =%d",bytes_received,recv_len);
+        if(bytes_received >=  payload_len)
+        {
+            //printf("receive_websocket_message:payload_len=%d,bytes_received=%d",payload_len,bytes_received);
+            break;
+        }
+        
+    }
+    if(mask)
+    {
+        for (size_t i = 0; i < payload_len; ++i) {
+            buf[i] = buf[i] ^ masking_key[i % 4];
+        }
+    }
+    
+    // if (*code == WS_TEXT) {
+    //     printf("Received text message: %.*s\n", (int)payload_len, buf);
+    // } else if (*code == WS_BINARY) {
+    //     printf("Received binary message of length %zu\n", payload_len);
+    // }
+
+    if (*code == WS_TEXT)
+    {
+
+    }else if(*code == WS_BINARY)
+    {
+
+    }else if(*code == WS_CLOSE)
+    {
+        payload_len = 0;
+    }else if(*code == WS_PONG)
+    {
+        payload_len = 0;
+    }else if(*code == WS_PING)
+    {
+        printf("send_websocket_message  WS_PONG \n");
+        send_websocket_message(client,buf,payload_len,WS_PONG);
+        payload_len = 0;
+    }else if(*code == WS_CONT)
+    {
+        payload_len = 0;
+    }
+    last_byte = buf[payload_len-1];
+    timer_ms = (uint32_t)osKernelGetTickCount();
+    //printf("receive_websocket_message 4 timer_ms=%d len = %d\n",timer_ms,payload_len);
+    return payload_len;//parse_frame(buf, bytes_received, buf,code);
+}
+
+
+
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
\ No newline at end of file
index 7b5908b..5e583b7 100644 (file)
@@ -3,6 +3,14 @@
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
+
+#include <sys/types.h>
+
+#include <stdint.h>
+#include <stddef.h>
+#include "bk_websocket.h"
+
+
 ////////////////////////// UI 使用接口/////////////////////////////////
 bool init_ai_task(uint8_t type);
 
@@ -21,15 +29,15 @@ bool uapi_start_tts_single_txt(char *buf);
 void uapi_UI_stop_start_asr_timeout(void);
 
 void ai_cleanup_resources(void);
-typedef enum
-{
-    AI_TYPE_0=0,
-    AI_TYPE_JIU, //九天
-    AI_TYPE_DE, //deepseek
-    AI_TYPE_DOU,//豆包
-    AI_TYPE_WEN,//文心一言
-    AI_TYPE_KIMI,//KIMI
-}G_AI_TYPE;
+// typedef enum
+// {
+//     AI_TYPE_0=0,
+//     AI_TYPE_JIU, //九天
+//     AI_TYPE_DE, //deepseek
+//     AI_TYPE_DOU,//豆包
+//     AI_TYPE_WEN,//文心一言
+//     AI_TYPE_KIMI,//KIMI
+// }G_AI_TYPE;
 
 bool pre_AI_init(void);
 
@@ -62,13 +70,13 @@ void uapi_start_asr_task(void);
 
 void asr_record_test(void);
 
-bool ai_chat_send_txt(uint8_t type,char *msg);
+// bool ai_chat_send_txt(uint8_t type, char *msg, WebSocketClient *chat_client);
 
 void uapi_start_asr(void);
 
 void uapi_stop_tts(void);
 
-
+int  receive_websocket_message(WebSocketClient *client, unsigned char *buf,int len,WebSocketMessageType *code, uint32_t timeout_ms);
 
 
 #ifdef __cplusplus
index aaca2b2..05b9f00 100644 (file)
@@ -67,6 +67,7 @@ set(PRIVATE_HEADER
     ${ROOT_DIR}/application/wearable/${DEVICE_PATH}/nativeapp/nativelauncher/include
     ${ROOT_DIR}/middleware/services/gui/uikit/ui/frameworks
     ${ROOT_DIR}/zhihui/AI/AImain
+    ${ROOT_DIR}/application/wearable/${DEVICE_PATH}/nativeapp/nativeui/aivoice/include
     # ${ROOT_DIR}/application/wearable/${DEVICE_PATH}/nativeapp/nativeui/schedule/include/ScheduleModel.h
     # ${ROOT_DIR}/middleware/services/gui/uikit/surface/interfaces/kits
 # /home/hcj/FD230/code/sdk/middleware/services/gui/uikit/surface/interfaces/kits/ibuffer_consumer_listener.h
index a52b27e..fcc943b 100644 (file)
 #include "app_store.h"
 #include "rebootandshutdown/include/RebootAndShutdownModelC.h"
 #include "ScheduleModel.h"
+#include "AiVoiceModelC.h"
+
 
 void ble_instruct_init(void)
 {
+    ble_AI_init();
+    
     ble_Schedule_init();
     
     ble_dial_init();