Merge #2368 into sdk650pathc0423 from refs/changes/2368/head 2371/target/1
author胡传军 <1224667075@qq.com>
Mon, 22 Sep 2025 11:46:31 +0000 (11:46 +0000)
committer袁清梦 <3449750381@qq.com>
Mon, 22 Sep 2025 11:46:31 +0000 (11:46 +0000)
修复因多线程操作导致的多次播放重复文字问题(增加锁保护 )

* refs/changes/2368/head: (1 commits squashed)

  - 修复因多线程操作导致的多次播放重复文字问题(增加锁保护 )

Signed-off-by: aliyun8003852482 <1224667075@qq.com>
Merged-by: Caisking <3449750381@qq.com>
link: https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230/change/2368
code/sdk/zhihui/ai_old/CMakeLists.txt
code/sdk/zhihui/ai_old/ai_old_at_cmd.cpp
code/sdk/zhihui/ai_old/chat_https_servrt.cpp [new file with mode: 0644]
code/sdk/zhihui/ai_old/chat_https_servrt.h [new file with mode: 0644]
code/sdk/zhihui/ai_old/tts_websocket_server.cpp
code/sdk/zhihui/ai_old/tts_websocket_server.h

index 226a3b6..63e56b4 100644 (file)
@@ -24,6 +24,8 @@ ${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
+${CMAKE_CURRENT_SOURCE_DIR}/chat_https_servrt.cpp
+
 )
 
 set(COMPONENT_PUBLIC_CCFLAGS
index ccc03da..566b6dd 100644 (file)
@@ -32,6 +32,7 @@ extern "C" {
 #include "zhihui_ws.h"
 #include "websocket_test.h"
 #include "cmsis_os2.h"
+#include "chat_https_servrt.h"
 
 static int ConvertCmdToParam(uint8_t *para, uint32_t paraLen,
         uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN], uint32_t* argc)
@@ -145,7 +146,7 @@ static uint32_t start_record(uint8_t *para, uint32_t paraLen, char *strCommonCmd
         return ERRCODE_FAIL;
     }
     uapi_start_asr();
-    streamingRecordAndSend_AI(0);
+    // streamingRecordAndSend_AI(0);
     return 0;
 }
 
@@ -426,6 +427,30 @@ static uint32_t websocket_status(uint8_t *para, uint32_t paraLen, char *strCommo
     return ERRCODE_SUCC;
 }
 
+static uint32_t test_http_chat(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;
+
+
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    
+    // 调用http_posttest函数
+    ret = http_posttest("你好,请介绍一下你自己", NULL, 0);
+    if (ret == 0) {
+        printf("HTTP请求成功!\n");
+        return ERRCODE_SUCC;
+    } else {
+        printf("HTTP请求失败,错误码: %d\n", ret);
+        return ERRCODE_FAIL;
+    }
+}
+
 static const at_cmd_table_t g_ai_old_cmd[] = {
     { (char *)"AT^WSTEST",      wstest, (char *)"1" },
     { (char *)"AT^AI_MSG",      ai_msg, (char *)"1" },
@@ -447,6 +472,7 @@ static const at_cmd_table_t g_ai_old_cmd[] = {
     { (char *)"AT^STARTTRAN", StartTranscription, (char *)"1" },
     { (char *)"AT^STOPTRAN", STOPTranscription, (char *)"1" },
     { (char *)"AT^WEBSOCKSTOP", STOPserver, (char *)"1" },
+    { (char *)"AT^TESTHTTPCHAT", test_http_chat, (char *)"HTTP聊天测试" },
     
     
     
diff --git a/code/sdk/zhihui/ai_old/chat_https_servrt.cpp b/code/sdk/zhihui/ai_old/chat_https_servrt.cpp
new file mode 100644 (file)
index 0000000..081cdf3
--- /dev/null
@@ -0,0 +1,152 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "netstack/http/include/httpclient.h"
+#include "chat_https_servrt.h"
+
+/* @brief http request buffer */
+#define REQ_BUF_SIZE 2048
+static char req_buf[REQ_BUF_SIZE];
+
+/* @brief http response buffer */
+#define RSP_BUF_SIZE 2048
+static char rsp_buf[RSP_BUF_SIZE] = {0};
+
+
+// { 1
+//     "userId": "user123",
+//     "characterId": "char456",
+//     "message": "你好,请介绍⼀下你⾃⼰"
+//     }
+
+
+// {
+//     "errorCode": null,
+//     "message": null,
+//     "data": {
+//     "message": "你好!我是你的AI助⼿,很⾼兴为你服务。我可以帮助你解答问题、提供建议或者
+//     陪你聊天。请问有什么我可以帮助你的吗?"
+//     }
+//     }
+
+/**
+ * @brief 解析HTTP响应JSON数据,提取data.message字段
+ * @param json_str JSON字符串
+ * @param out_message 输出消息缓冲区
+ * @param max_len 缓冲区最大长度
+ * @return 0成功,-1失败
+ */
+int parse_http_response_message(const char *json_str, char *out_message, size_t max_len)
+{
+    if (!json_str || !out_message || max_len == 0) {
+        return -1;
+    }
+    
+    // 初始化输出缓冲区
+    memset(out_message, 0, max_len);
+    
+    // 查找data.message字段
+    const char *data_start = strstr(json_str, "\"data\"");
+    if (data_start) {
+        const char *data_message_start = strstr(data_start, "\"message\"");
+        if (data_message_start) {
+            data_message_start = strchr(data_message_start, ':');
+            if (data_message_start) {
+                data_message_start++; // 跳过冒号
+                while (*data_message_start == ' ' || *data_message_start == '\t') {
+                    data_message_start++; // 跳过空格
+                }
+                // 查找引号
+                const char *quote_start = strchr(data_message_start, '"');
+                if (quote_start) {
+                    quote_start++; // 跳过开始引号
+                    const char *quote_end = strchr(quote_start, '"');
+                    if (quote_end) {
+                        size_t len = quote_end - quote_start;
+                        if (len < max_len) {
+                            strncpy(out_message, quote_start, len);
+                            out_message[len] = '\0';
+                            return 0;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    return -1;
+}
+
+int http_posttest(const char *message, char *out_message, size_t max_len)
+{
+    HttpClient client = {0};
+    HttpClientData client_data = {0};
+    char *req_url = "https://ambybox-api.test.leiniao.com/ambybox-device-api/v1/textChat/chat?deviceId=860132060562402&deviceToken=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJXWVNaIiwiZGV2aWNlTW9kZWwiOiJBQjEwMSIsImRldmljZVZlcnNpb24iOiJWQjY1MF8yMDI1MDkxOV8x\NDI4MDMiLCJkZXZpY2VJZCI6Ijg2MDEzMjA2MDU2MjQwMiIsImV4cCI6MTc2MDg1OTE5OX0.B6zIfQyE9iGLlknIIDomQ3jnWxdNtcF5LHVrKS9WQFg";
+    int ret = -1;
+    // 
+    // 构建JSON数据,使用第13行开始的格式
+    char json_data[512];
+    snprintf(json_data, sizeof(json_data), 
+        "{"
+        "\"userId\": \"test_user_001\","
+        "\"characterId\": \"char_001\","
+        "\"message\": \"%s\""
+        "}", 
+        message ? message : "你好,请介绍一下你自己");
+
+    client_data.postBuf = json_data;
+    size_t length = strlen(client_data.postBuf);
+    client_data.postBufLen = length;
+
+    memset(req_buf, 0, sizeof(req_buf));
+    client_data.headerBuf = req_buf;
+    client_data.headerBufLen = sizeof(req_buf);
+
+    memset(rsp_buf, 0, sizeof(rsp_buf));
+    client_data.responseBuf = rsp_buf;
+    client_data.responseBufLen= sizeof(rsp_buf);
+
+    printf("\n http request: %s \r\n", req_url);
+    printf("JSON data: %s \r\n", json_data);
+
+
+     char *header_buf = (char *)malloc(128);
+    if (!header_buf)
+    return ret;
+    int hdr = snprintf(header_buf,128,
+                        "deviceId: %s \r\n"
+                        "Content-Type: application/json\r\n","860132060562402");
+    if (hdr <= 0)
+    {
+        free(header_buf);
+        return ret;
+    }
+    HttpClientSetCustomHeader(&client, header_buf);
+
+
+    ret = HttpClientPostRequest(&client, req_url, &client_data);
+    if (ret >= 0 && client.responseCode == 200) {
+        printf("http test success!\r\n");
+        
+        // 解析响应数据中的message字段
+        if (out_message && max_len > 0) {
+            if (parse_http_response_message(client_data.responseBuf, out_message, max_len) == 0) {
+                printf("Response message: %s\n", out_message);
+            } else {
+                printf("Failed to parse response message\n");
+                memset(out_message, 0, max_len);
+            }
+        }
+        
+        ret = 0;
+    } else {
+        printf("responsecode = %d \n", client.responseCode);
+        printf("http test failed! ret= 0x%x \r\n", ret);
+        
+        // 如果请求失败,清空输出缓冲区
+        if (out_message && max_len > 0) {
+            memset(out_message, 0, max_len);
+        }
+    }
+    return ret;
+}
\ No newline at end of file
diff --git a/code/sdk/zhihui/ai_old/chat_https_servrt.h b/code/sdk/zhihui/ai_old/chat_https_servrt.h
new file mode 100644 (file)
index 0000000..58cc740
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __CHAT_HTTPS_SERVRT_H__
+#define __CHAT_HTTPS_SERVRT_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* @brief http request buffer size */
+#define REQ_BUF_SIZE 2048
+
+/* @brief http response buffer size */
+#define RSP_BUF_SIZE 2048
+
+/* @brief JSON data buffer size */
+#define JSON_DATA_SIZE 512
+
+/* @brief response message buffer size */
+#define RESPONSE_MSG_SIZE 1024
+
+/**
+ * @brief 解析HTTP响应JSON数据,提取data.message字段
+ * @param json_str JSON字符串
+ * @param out_message 输出消息缓冲区
+ * @param max_len 缓冲区最大长度
+ * @return 0成功,-1失败
+ */
+int parse_http_response_message(const char *json_str, char *out_message, size_t max_len);
+
+/**
+ * @brief HTTP POST测试函数
+ * @param message 要发送的消息内容,如果为NULL则使用默认消息
+ * @param out_message 输出响应消息,可以为NULL
+ * @param max_len 输出缓冲区最大长度
+ * @return 0成功,-1失败
+ */
+int http_posttest(const char *message, char *out_message, size_t max_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CHAT_HTTPS_SERVRT_H__ */
index c67e897..70c51d0 100644 (file)
@@ -49,6 +49,7 @@ 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);
+static bool tts_cache_ensure_capacity(int required_size);
 
 /* TTS 配置和常量 */
 #define AI_MAX_RETRY_COUNT 3
@@ -65,6 +66,199 @@ static int tts_cached_capacity = 0;       // 当前分配的内存容量
 static bool tts_has_stop_cached = false;  // 是否缓存了stop命令
 // static bool tts_is_ready = false;         // TTS是否准备就绪
 
+/* TTS 缓存互斥锁 */
+static osMutexId_t tts_cache_mutex = NULL;
+
+/**
+ * @brief 带互斥锁保护的缓存追加操作
+ * @param buf 要追加的文本
+ * @return true 成功,false 失败
+ */
+static bool tts_cache_append_with_mutex(const char *buf)
+{
+    if (tts_cache_mutex != NULL) {
+        if (osMutexAcquire(tts_cache_mutex, osWaitForever) == osOK) {
+            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");
+                osMutexRelease(tts_cache_mutex);
+                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);
+            
+            osMutexRelease(tts_cache_mutex);
+            return true;
+        } else {
+            printf("Failed to acquire TTS cache mutex for append\n");
+            return false;
+        }
+    } else {
+        // 如果互斥锁未初始化,直接操作(向后兼容)
+        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;
+    }
+}
+
+/**
+ * @brief 带互斥锁保护的缓存清空操作
+ * @return true 成功,false 失败
+ */
+static bool tts_cache_clear_with_mutex(void)
+{
+    if (tts_cache_mutex != NULL) {
+        if (osMutexAcquire(tts_cache_mutex, osWaitForever) == osOK) {
+            if (tts_cached_text != NULL) {
+                memset(tts_cached_text, 0, tts_cached_capacity);
+            }
+            tts_cached_length = 0;
+            tts_has_stop_cached = false;  // 同时清空stop缓存标志
+            osMutexRelease(tts_cache_mutex);
+            printf("TTS cache cleared with mutex protection\n");
+            return true;
+        } else {
+            printf("Failed to acquire TTS cache mutex for clear\n");
+            return false;
+        }
+    } else {
+        // 如果互斥锁未初始化,直接清空(向后兼容)
+        if (tts_cached_text != NULL) {
+            memset(tts_cached_text, 0, tts_cached_capacity);
+        }
+        tts_cached_length = 0;
+        tts_has_stop_cached = false;  // 同时清空stop缓存标志
+        printf("TTS cache cleared without mutex (mutex not available)\n");
+        return true;
+    }
+}
+
+/**
+ * @brief 带互斥锁保护的获取缓存长度操作
+ * @return 缓存长度
+ */
+static int tts_cache_get_length_with_mutex(void)
+{
+    int length = 0;
+    
+    if (tts_cache_mutex != NULL) {
+        if (osMutexAcquire(tts_cache_mutex, osWaitForever) == osOK) {
+            length = tts_cached_length;
+            osMutexRelease(tts_cache_mutex);
+        } else {
+            printf("Failed to acquire TTS cache mutex for count\n");
+            length = 0;
+        }
+    } else {
+        // 如果互斥锁未初始化,直接返回(向后兼容)
+        length = tts_cached_length;
+    }
+    
+    return length;
+}
+
+/**
+ * @brief 带互斥锁保护的检查缓存是否有内容
+ * @return true 有内容,false 无内容
+ */
+static bool tts_cache_has_content_with_mutex(void)
+{
+    bool has_content = false;
+    
+    if (tts_cache_mutex != NULL) {
+        if (osMutexAcquire(tts_cache_mutex, osWaitForever) == osOK) {
+            has_content = (tts_cached_length > 0);
+            osMutexRelease(tts_cache_mutex);
+        } else {
+            printf("Failed to acquire TTS cache mutex for check\n");
+            has_content = false;
+        }
+    } else {
+        // 如果互斥锁未初始化,直接检查(向后兼容)
+        has_content = (tts_cached_length > 0);
+    }
+    
+    return has_content;
+}
+
+/**
+ * @brief 带互斥锁保护的发送缓存文本操作
+ * @param tts_client TTS WebSocket客户端
+ * @return true 成功,false 失败
+ */
+static bool tts_cache_send_with_mutex(WebSocketClient *tts_client)
+{
+    if (tts_cache_mutex != NULL) {
+        if (osMutexAcquire(tts_cache_mutex, osWaitForever) == osOK) {
+            bool result = false;
+            
+            if (tts_cached_length > 0) {
+                printf("TTS ready, sending cached text (length: %d): %s\n", tts_cached_length, tts_cached_text);
+                result = uapi_send_single_tts_text(tts_client, tts_cached_text);
+                if (!result) {
+                    printf("Failed to send cached text: %s\n", tts_cached_text);
+                } 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;
+                tts_has_stop_cached = false;  // 同时清空stop缓存标志
+                printf("TTS cache cleared after sending\n");
+            }
+            
+            osMutexRelease(tts_cache_mutex);
+            return result;
+        } else {
+            printf("Failed to acquire TTS cache mutex for send\n");
+            return false;
+        }
+    } else {
+        // 如果互斥锁未初始化,直接操作(向后兼容)
+        bool result = false;
+        
+        if (tts_cached_length > 0) {
+            printf("TTS ready, sending cached text (length: %d): %s\n", tts_cached_length, tts_cached_text);
+            result = uapi_send_single_tts_text(tts_client, tts_cached_text);
+            if (!result) {
+                printf("Failed to send cached text: %s\n", tts_cached_text);
+            } 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;
+            tts_has_stop_cached = false;  // 同时清空stop缓存标志
+            printf("TTS cache cleared after sending\n");
+        }
+        
+        return result;
+    }
+}
+
 /**
  * @brief 初始化TTS缓存内存
  * @return true 成功,false 失败
@@ -82,6 +276,17 @@ static bool tts_cache_init(void)
         memset(tts_cached_text, 0, TTS_MAX_CACHED_LENGTH);
         printf("TTS cache initialized with %d bytes\n", TTS_MAX_CACHED_LENGTH);
     }
+
+    // 创建互斥锁
+    if (tts_cache_mutex == NULL) {
+        tts_cache_mutex = osMutexNew(NULL);
+        if (tts_cache_mutex == NULL) {
+            printf("Failed to create TTS cache mutex\n");
+            return false;
+        }
+        printf("TTS cache mutex created\n");
+    }
+    
     return true;
 }
 
@@ -97,6 +302,13 @@ static void tts_cache_deinit(void)
         tts_cached_length = 0;
         printf("TTS cache deinitialized\n");
     }
+
+    // 删除互斥锁
+    if (tts_cache_mutex != NULL) {
+        osMutexDelete(tts_cache_mutex);
+        tts_cache_mutex = NULL;
+        printf("TTS cache mutex deleted\n");
+    }
 }
 
 /**
@@ -287,39 +499,17 @@ bool uapi_tts_process_text(WebSocketClient *tts_client, char *buf, bool ready)
     // 如果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 tts_cache_append_with_mutex(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 (tts_cache_has_content_with_mutex()) {
+        bool result = tts_cache_send_with_mutex(tts_client);
         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;
     }
     
     // 检查是否有缓存的stop命令需要发送
@@ -471,7 +661,7 @@ tts_ready_status_t uapi_get_tts_ready(void)
  */
 int uapi_get_cached_text_count(void)
 {
-    return tts_cached_length;
+    return tts_cache_get_length_with_mutex();
 }
 
 /**
@@ -479,12 +669,7 @@ int uapi_get_cached_text_count(void)
  */
 void uapi_clear_tts_cache(void)
 {
-    if (tts_cached_text != NULL) {
-        memset(tts_cached_text, 0, tts_cached_capacity);
-    }
-    tts_cached_length = 0;
-    tts_has_stop_cached = false;  // 同时清空stop缓存标志
-    printf("TTS cache cleared\n");
+    tts_cache_clear_with_mutex();
 }
 
 /**
@@ -852,22 +1037,6 @@ tts_event_type_t tts_analysis(char *buf)
                 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;
                 }
@@ -1049,6 +1218,167 @@ void uapi_stop_tts_type_stop(WebSocketClient *client)
     }
 }
 
+
+
+     //  "{  \"header\": { \
+        //     \"event\": \"LongTextStream\", \
+        //     \"trace_id\": \"3fa6b9e6a30b407ea38ad7ae69e6c291\"\
+    // },\
+    // \"payload\": {\
+        //     \"voice\":\"xiaoyun\",\
+        //     \"format\":\"mp3\",\
+        //     \"sample_rate\":16000,\
+        //     \"volume\":80,\
+        //     \"speech_rate\":0,\
+        //     \"text\":\"%s\"\
+     //  } }"
+
+/**
+ * @brief 发送长文本TTS合成请求
+ * @param client WebSocket客户端
+ * @param text 要合成的文本
+ * @param voice 语音类型,默认为"xiaoyun"
+ * @param format 音频格式,默认为"mp3"
+ * @param sample_rate 采样率,默认为16000
+ * @param volume 音量,默认为80
+ * @param speech_rate 语速,默认为0
+ * @param trace_id 跟踪ID,可以为NULL
+ * @return 成功返回true,失败返回false
+ */
+bool uapi_send_long_text_tts(WebSocketClient *client, const char *text, 
+                            const char *voice, const char *format,
+                            int sample_rate, int volume, int speech_rate,
+                            const char *trace_id)
+{
+    cJSON *json = NULL;
+    cJSON *header = NULL;
+    cJSON *payload = NULL;
+    char *jsonString = NULL;
+    bool result = false;
+    
+    // 参数验证
+    if (client == NULL || text == NULL) {
+        printf("TTS client or text is NULL\n");
+        return false;
+    }
+    
+    // 设置默认值
+    if (voice == NULL) voice = "xiaoyun";
+    if (format == NULL) format = "mp3";
+    if (trace_id == NULL) trace_id = "3fa6b9e6a30b407ea38ad7ae69e6c291";
+    
+    // 创建根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", "LongTextStream") == NULL) {
+        printf("Failed to add event field\n");
+        goto cleanup;
+    }
+    
+    if (cJSON_AddStringToObject(header, "trace_id", 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", voice) == NULL) {
+        printf("Failed to add voice field\n");
+        goto cleanup;
+    }
+    
+    if (cJSON_AddStringToObject(payload, "format", format) == NULL) {
+        printf("Failed to add format field\n");
+        goto cleanup;
+    }
+    
+    if (cJSON_AddNumberToObject(payload, "sample_rate", sample_rate) == NULL) {
+        printf("Failed to add sample_rate field\n");
+        goto cleanup;
+    }
+    
+    if (cJSON_AddNumberToObject(payload, "volume", volume) == NULL) {
+        printf("Failed to add volume field\n");
+        goto cleanup;
+    }
+    
+    if (cJSON_AddNumberToObject(payload, "speech_rate", speech_rate) == NULL) {
+        printf("Failed to add speech_rate field\n");
+        goto cleanup;
+    }
+    
+    if (cJSON_AddStringToObject(payload, "text", text) == NULL) {
+        printf("Failed to add text 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_send_long_text_tts: %s\r\n", jsonString);
+    if (jsonString == NULL) {
+        printf("Failed to print JSON to string\n");
+        goto cleanup;
+    }
+    
+    // 发送WebSocket消息
+    if (send_websocket_message(client, (uint8_t *)jsonString, strlen(jsonString), WS_TEXT) == 0) {
+        printf("Long text TTS message sent successfully\n");
+        result = true;
+    } else {
+        printf("Long text TTS 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;
+}
+
+
 /*
  * 使用示例:
  * 
index dce84f0..5c591f7 100644 (file)
@@ -121,6 +121,23 @@ bool uapi_start_tts(void);
  */
 bool uapi_start_tts_type_start(WebSocketClient *client);
 
+/**
+ * @brief 发送长文本TTS合成请求
+ * @param client WebSocket客户端
+ * @param text 要合成的文本
+ * @param voice 语音类型,默认为"xiaoyun"
+ * @param format 音频格式,默认为"mp3"
+ * @param sample_rate 采样率,默认为16000
+ * @param volume 音量,默认为80
+ * @param speech_rate 语速,默认为0
+ * @param trace_id 跟踪ID,可以为NULL
+ * @return 成功返回true,失败返回false
+ */
+bool uapi_send_long_text_tts(WebSocketClient *client, const char *text, 
+                            const char *voice, const char *format,
+                            int sample_rate, int volume, int speech_rate,
+                            const char *trace_id);
+
 /**
  * @brief TTS文本处理函数(组合版本)
  * @param tts_client TTS WebSocket客户端