# 鸿蒙AI服务-架构设计图\r
\r
-\r
-\r
\r
\r
[AI聚合平台接入文档](https://zytjtkeb0k.feishu.cn/docx/BJcAduKpdoidt6x3xgYcDhWPnPf)\r
\r
73519@5J\r
\r
-1. ## WebSocketService \r
-\r
-1. ### 功能描述:\r
+1. ## WebSocketService\r
+2. ### 功能描述:\r
\r
提供基础Websocket连接能力的模块,\r
\r
\r
支持回调式的 连接状态反馈,接收消息(不区分文本和二进制数据)\r
\r
- 接收和发送都是异步的,有缓存。\r
+接收和发送都是异步的,有缓存。\r
\r
- 支持文本模式,二进制模式,连续数据 模式的消息发送。 \r
+支持文本模式,二进制模式,连续数据 模式的消息发送。\r
\r
1. ### 接口定义:SDK650 730 Patch 适用\r
\r
-net_websocket_type.h \r
+net_websocket_type.h\r
\r
-net_websocket.h \r
+net_websocket.h\r
\r
1. ## Audio Play Service\r
\r
- 1. ### 功能描述:\r
\r
- 提供基础音频播放能力,\r
+ 1. ### 功能描述:\r
\r
- 支持指定播放格式的流媒体播放,\r
+ 提供基础音频播放能力,\r
\r
- 提供播放服务控制接口:开始播放服务,停止播放服务,发送播放数据。\r
+ 支持指定播放格式的流媒体播放,\r
\r
- 1. ### 接口定义:\r
+ 提供播放服务控制接口:开始播放服务,停止播放服务,发送播放数据。\r
+\r
+ 1. ### 接口定义:\r
\r
ai_media.h\r
\r
\r
1. ## Audio Record Service\r
\r
- 1. ### 功能描述:\r
\r
- 提供基础音频录音能力,\r
+ 1. ### 功能描述:\r
+\r
+ 提供基础音频录音能力,\r
\r
- 支持指定格式的流媒体录音,支持格式"pcm","opus","mp3"\r
+ 支持指定格式的流媒体录音,支持格式"pcm","opus","mp3"\r
\r
- 提供录音服务控制接口:开始录音服务,停止录音服务,录音数据回调。\r
+ 提供录音服务控制接口:开始录音服务,停止录音服务,录音数据回调。\r
\r
- 1. ### 接口定义:\r
+ 1. ### 接口定义:\r
\r
- ai_media.h\r
+ ai_media.h\r
\r
```C++\r
/*\r
* @return 0 on success, -1 on failure\r
*/\r
int32_t ai_media_service_init(void);\r
- \r
+\r
/*\r
* @brief 反初始化AI媒体服务\r
*/\r
* @return 无\r
*/\r
void ai_media_record_start(uint8_t* format);\r
- \r
+\r
/*\r
* @brief 停止录音\r
* @param 无\r
* @return 无\r
*/\r
void ai_media_record_stop(void);\r
- \r
+\r
/*\r
* @brief 获取录音状态\r
* @param 无\r
* @return 录音状态\r
*/\r
uint8_t ai_media_get_record_status(void);\r
- \r
+\r
/*\r
* @brief 录音回调\r
* @param 录音数据\r
* @return 无\r
*/\r
typedef void (*ai_media_record_callback)(uint8_t *data, uint32_t size);\r
- \r
+\r
/*\r
* @brief 设置录音回调\r
* @param 录音回调\r
*/\r
void ai_media_set_record_callback(ai_media_record_callback callback);\r
```\r
+2. ## ASR Server\r
\r
-1. ## ASR Server\r
\r
- 1. ### 功能描述:\r
+ 1. ### 功能描述:\r
\r
- 连接管理:\r
- ASR服务生命周期内,保持websocket在连接状态,退出服务,websocket也要断开连接。\r
+ - 服务器地址:\r
+ ```\r
+ /*\r
+ * @brief 正式服务器URL\r
+ */\r
+ #define WS_SERVER_URL "ws://amp.raisound.com/asr/ws"\r
+ /**\r
+ * @brief 测试服务器URL\r
+ */\r
+ #define WS_TEST_SERVER_URL "ws://118.145.158.207:22080/asr/ws";\r
+\r
+ /**\r
+ * @brief Snicker测试服务器URL\r
+ */\r
+ #define WS_SNICKER_TEST_SERVER_URL "ws://110.42.224.129:8910/asr/ws";\r
+\r
+\r
+ /**\r
+ * @brief 初始化ASR WebSocket URL\r
+ * @param put_buf 输出缓冲区,存储构建的URL\r
+ * @return bool true表示成功,false表示失败\r
+ * @note 从设备令牌构建完整的ASR WebSocket URL\r
+ * 格式:ws://amp.raisound.com/asr/ws?dt={token}&platform=aliyun\r
+ */\r
+ bool asr_api_ws_url_init(char *put_buf)\r
+ {\r
+ char token[64] = {0};\r
+ if (read_dev_token(token)) {\r
+ sprintf(put_buf, "ws://amp.raisound.com/asr/ws?dt=%s&platform=aliyun", token);\r
+ return true;\r
+ } else {\r
+ return false;\r
+ }\r
+ }\r
+ ```\r
- 录音服务管理:\r
- ASR服务生命周期内,保持录音服务开启,随时可以通过callback拿到录音数据,只是根据上传控制来决定是否上传消息到服务器。退出服务,才停止录音服务。\r
- 上传控制:\r
- 消息管理:\r
- 负责接收和解析服务器返回的消息。通过回调,让Ai全家桶去进行语音播放,或者执行对应的逻辑状态。\r
\r
- 例如 通过下面的数据解析,区分处不同的event做不同的响应。\r
+ ```\r
+ 例如 通过下面的数据解析,区分处不同的event做不同的响应。\r
+ ```\r
\r
- **TranscriptionStarted** 表示服务器连接成功,可以发送语音数据。必须有这个才能发送语音数据。\r
+ **TranscriptionStarted** 表示服务器连接成功,可以发送语音数据。必须有这个才能发送语音数据。\r
\r
- **Changed** 表示刚刚识别出的语句,这个可能不是最终结果,在这种event下,只要把当前语句追加显示即可。 注意是当前语句 ,之前的句子不必更改。这个是临时显示,只是为了显示的更快,给人体验更好。\r
+ **Changed** 表示刚刚识别出的语句,这个可能不是最终结果,在这种event下,只要把当前语句追加显示即可。 注意是当前语句 ,之前的句子不必更改。这个是临时显示,只是为了显示的更快,给人体验更好。\r
\r
- **SentenceEnd** 并且 **is_end**为true代表 这一句结束,识别的语句为最终的结论。之前临时作为优化体验的临时数据要用最终数据进行覆盖。在这样的语句出现后,才认为这句话为可信语句,可以被上传给 Chat Server开始对话。 \r
+ ```\r
\r
- \r
+ ```\r
\r
- \r
+ **SentenceEnd** 并且 **is_end**为true代表 这一句结束,识别的语句为最终的结论。之前临时作为优化体验的临时数据要用最终数据进行覆盖。在这样的语句出现后,才认为这句话为可信语句,可以被上传给 Chat Server开始对话。\r
\r
- 参考消息格式:\r
+ 参考消息格式:\r
\r
```JSON\r
{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"TranscriptionStarted"}\r
{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"Changed","result":{"result":"今天早上我去可能去温","is_end":false,"sentence_id":"","start_time":0,"end_time":0}}\r
{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"SentenceEnd","result":{"result":"今天早上有没有什么趣味?","is_end":true,"sentence_id":"","start_time":0,"end_time":0}}\r
{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"TranscriptionCompleted"}\r
- \r
+\r
{\r
"status" : 20000000, \r
"msg" : "success", \r
}\r
```\r
\r
- 1. ### 接口定义:\r
+ 1. ### 接口定义:\r
+3. ## Chat Server\r
\r
-1. ## Chat Server\r
\r
- 1. ### 功能描述:\r
+ 1. ### 功能描述:\r
\r
- 连接管理\r
- Chat服务生命周期内,保持websocket在连接状态,退出服务,websocket也要断开连接。\r
+ - 服务器地址\r
+ ```\r
+ bool chat_api_ws_url_init(char * put_buf,uint8_t type)\r
+ {\r
+ char token[64]={0};\r
+ if(read_dev_token(token))\r
+ {\r
+ if(type_ai==AI_TYPE_JIU)\r
+ {\r
+ sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=chinamobiledevice&bot_type=jiutian-lan",token);\r
+ }\r
+ else if(type_ai==AI_TYPE_DOU)\r
+ {\r
+ sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=huoshan",token);\r
+ }\r
+ else if(type_ai==AI_TYPE_WEN)\r
+ {\r
+ sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=baidu",token);\r
+ }\r
+ else if(type_ai==AI_TYPE_KIMI)\r
+ {\r
+ sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=moonshot",token);\r
+ }\r
+ else if(type_ai==AI_TYPE_DE)\r
+ {\r
+ sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=huoshan&model=ep-20250205103849-582m7",token);\r
+ }\r
+ else \r
+ {\r
+ sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=aliyun",token);\r
+ }\r
+ return true;\r
+\r
+ }\r
+ else\r
+ {\r
+ char * Service_url="118.145.158.207:22080";\r
+\r
+ char device_id[128]={0};\r
+ get_dev_id(device_id);\r
+\r
+ char * product_id="1927646275585744898";\r
+\r
+ if(type_ai==AI_TYPE_JIU)\r
+ {\r
+ sprintf(put_buf,"ws://%s/chat/ws?device_id=%s&product_id=%s&platform=chinamobiledevice&bot_type=jiutian-lan",Service_url,device_id,product_id);\r
+ }\r
+ else if(type_ai==AI_TYPE_DOU)\r
+ {\r
+ sprintf(put_buf,"ws://%s/chat/ws?platform=huoshan",Service_url);\r
+ }\r
+ else if(type_ai==AI_TYPE_WEN)\r
+ {\r
+ sprintf(put_buf,"ws://%s/chat/ws?platform=baidu",Service_url);\r
+ }\r
+ else if(type_ai==AI_TYPE_KIMI)\r
+ {\r
+ sprintf(put_buf,"ws://%s/chat/ws?platform=moonshot",Service_url);\r
+ }\r
+ else if(type_ai==AI_TYPE_DE)\r
+ {\r
+ sprintf(put_buf,"ws://%s/chat/ws?platform=huoshan&model=ep-20250205103849-582m7",Service_url);\r
+ }\r
+ else \r
+ {\r
+ sprintf(put_buf,"ws://%s/chat/ws?platform=aliyun",Service_url);\r
+ }\r
+ return false;\r
+ }\r
+\r
+\r
+ }\r
+ ```\r
- 事件管理\r
- 通过回调的方式,通知UI,让其对异常情况等进行响应。\r
- 消息管理\r
- Type middle 表示回复中,回复内容为递增数据,直接递增显示即可。实际上不管start还是end,只要middle就显示出来就行。换行等内容大模型都会自动给,无需手动添加。\r
- Type end 回复结束。\r
\r
- 参考消息格式:\r
+ 参考消息格式:\r
\r
```JSON\r
{"type":"start","content":null,"task_id":"","reasoning_content":""}\r
{"type":"end","content":null,"task_id":"","reasoning_content":""}\r
```\r
\r
- 1. ### 接口定义:\r
+ 1. ### 接口定义:\r
+4. ## TTS Server\r
\r
-1. ## TTS Server\r
\r
- 1. ### 功能描述:双向流式合成\r
+ 1. ### 功能描述:双向流式合成\r
\r
- 连接管理\r
+\r
- TTS服务生命周期内,保持websocket在连接状态,退出服务,websocket也要断开连接。\r
- - 事件管理\r
- - 通过回调的方式,通知UI,让其对异常情况等进行响应。\r
- - 消息管理\r
- - 文本发送完毕,要发出特定指令。\r
- - ```JSON\r
- {\r
- "header": {\r
- "event": "StopSynthesis",\r
- "trace_id": "3fa6b9e6a30b407ea38ad7ae69e6c291"\r
- }\r
- }\r
- ```\r
+ - 服务器地址\r
\r
- - 文本发送开始,要发送特定指令\r
- - ```JSON\r
+ ```\r
+ /*\r
+ * @brief 初始化TTS服务URL\r
+ * @note 根据设备token初始化TTS服务URL\r
+ */\r
+ bool tts_api_ws_url_init(char * put_buf)\r
{\r
- "header": {\r
- "event": "StartSynthesis",\r
- "trace_id": "3fa6b9e6a30b407ea38ad7ae69e6c291"\r
- },\r
- "payload": {\r
- "voice":"xiaoyun", // 音色 xiaoyun zhixiaomei\r
- "format":"WAV",\r
- "sample_rate":16000,\r
- "volume":50,\r
- "speech_rate":0\r
+ // 测试用例\r
+ // tts_client = init_websocket_client("ws://118.145.158.207:22080/tts/stream?audio_buffer_size=512", NULL, 0);\r
+\r
+ char token[64]={0};\r
+ if(read_dev_token(token))\r
+ {\r
+ // /tts/stream?audio_buffer_size=1024\r
+ sprintf(put_buf,"ws://amp.raisound.com/tts/stream?dt=%s&platform=aliyun&noCache=1",token);\r
+ return true;\r
+ }\r
+ else\r
+ {\r
+ return false;\r
}\r
+\r
}\r
- ```\r
\r
- - 文本发送 可多次发送\r
+ ```\r
+ - 事件管理\r
+\r
+ - 通过回调的方式,通知UI,让其对异常情况等进行响应。\r
+ - 消息管理\r
+\r
+ - 文本发送完毕,要发出特定指令。\r
+ - ```JSON\r
+ {\r
+ "header": {\r
+ "event": "StopSynthesis",\r
+ "trace_id": "3fa6b9e6a30b407ea38ad7ae69e6c291"\r
+ }\r
+ }\r
+ ```\r
+ - 文本发送开始,要发送特定指令\r
+ - ```JSON\r
+ {\r
+ "header": {\r
+ "event": "StartSynthesis",\r
+ "trace_id": "3fa6b9e6a30b407ea38ad7ae69e6c291"\r
+ },\r
+ "payload": {\r
+ "voice":"xiaoyun", // 音色 xiaoyun zhixiaomei\r
+ "format":"WAV",\r
+ "sample_rate":16000,\r
+ "volume":50,\r
+ "speech_rate":0\r
+ }\r
+ }\r
+ ```\r
+ - 文本发送 可多次发送\r
\r
```JSON\r
{\r
}\r
```\r
\r
-服务器返回 \r
+服务器返回\r
\r
- SentenceBegin 检测到一句话开始\r
+SentenceBegin 检测到一句话开始\r
\r
```JSON\r
{\r
}\r
```\r
\r
- SentenceSynthesis (表示有新的合成结果返回)\r
+SentenceSynthesis (表示有新的合成结果返回)\r
\r
```JSON\r
{\r
}\r
```\r
\r
- SentenceEnd(服务端检测到了一句话的结束)\r
+SentenceEnd(服务端检测到了一句话的结束)\r
\r
```JSON\r
{\r
}\r
```\r
\r
- EndSynthesis (合成结束)\r
+EndSynthesis (合成结束)\r
\r
```JSON\r
{\r
- TTS服务通过callback返回的消息,要区分是json数据还是二进制数据,\r
- json数据解析判定是什么事件(通过callback返回给Ai全家桶)\r
- 二进制数据 根据播放控制是否允许,决定是否发给音频服务的播放接口。(通过callback返回给Ai全家桶)\r
- - \r
+ -\r
\r
1. ### 接口定义:\r
+2. ## Ai全家桶\r
\r
-1. ## Ai全家桶\r
\r
- 1. ### 功能描述:\r
+ 1. ### 功能描述:\r
\r
- - Ai交互总入口,开启应用,直接开启ASR Server,Chat Server, TTS Server, 进行对话服务,直到退出服务才退出三个服务。\r
+ - Ai交互总入口,开启应用,直接开启ASR Server,Chat Server, TTS Server, 进行对话服务,直到退出服务才退出三个服务。\r
\r
- 交互窗口,
\ No newline at end of file
+ ```\r
+ 交互窗口,\r
+ ```\r
+++ /dev/null
-#ifndef __CAT1_WS_H__
-#define __CAT1_WS_H__
-
-#include "bk_websocket.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-////////////////////////// UI 使用接口/////////////////////////////////
-bool init_ai_task(uint8_t type);
-
-bool dinit_ai_task(void);
-
-void uapi_UI_start_asr(uint8_t type);
-
-void uapi_UI_stop_asr(void);
-
-void uapi_start_tts(void);
-
-void uapi_stop_tts(void);
-
-bool uapi_start_tts_single_txt(char *buf);
-
-void uapi_UI_stop_start_asr_timeout(void);
-
-bool uapi_get_server_state_is_end(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;
-
-bool pre_AI_init(void);
-
-
-////////////////////////////////////////////////////////////////////////
-
-void start_send_voice(void);
-
-void tts_server_deinit(void);
-
-void asr_server_deinit(void);
-
-
-void chat_server_deinit(void);
-
-void uapi_set_tts_break(uint8_t data);
-
-uint8_t uapi_get_tts_break(void);
-
-uint8_t get_ai_asr_service_init_flag(void);
-void set_ai_asr_service_init_flag(uint8_t flag);
-uint8_t get_ai_chat_service_init_flag(void);
-void set_ai_chat_service_init_flag(uint8_t flag);
-uint8_t get_ai_tts_server_init_flag(void);
-void set_ai_tts_server_init_flag(uint8_t flag);
-uint32_t get_bk_websocket_tts_tick(void);
-
-void uapi_start_asr_task(void);
-
-void asr_record_test(void);
-
-bool send_ai_txt(uint8_t type,char *msg);
-
-void uapi_start_asr(void);
-
-void uapi_stop_tts(void);
-
-/* ========== WebSocket 多实例服务管理器接口 ========== */
-
-// WebSocket 实例状态枚举
-typedef enum {
- WS_INSTANCE_IDLE = 0,
- WS_INSTANCE_CONNECTING,
- WS_INSTANCE_CONNECTED,
- WS_INSTANCE_HANDSHAKING,
- WS_INSTANCE_READY,
- WS_INSTANCE_ERROR,
- WS_INSTANCE_CLOSING,
- WS_INSTANCE_CLOSED
-} ws_instance_state_t;
-
-// WebSocket 管理器函数
-int ws_manager_init(void);
-void ws_manager_deinit(void);
-int ws_manager_create_instance(const char *name, const char *url, const char *headers, uint8_t use_dns);
-int ws_manager_destroy_instance(int instance_id);
-int ws_manager_send_data(int instance_id, uint8_t *data, size_t length, WebSocketMessageType type);
-ws_instance_state_t ws_manager_get_instance_state(int instance_id);
-
-// 回调函数类型定义
-typedef void (*ws_on_connect_callback)(int instance_id);
-typedef void (*ws_on_disconnect_callback)(int instance_id);
-typedef void (*ws_on_error_callback)(int instance_id, int error_code);
-typedef void (*ws_on_message_callback)(int instance_id, uint8_t *data, size_t length, WebSocketMessageType type);
-
-// 回调函数注册
-int ws_manager_register_callbacks(int instance_id,
- ws_on_connect_callback on_connect,
- ws_on_disconnect_callback on_disconnect,
- ws_on_error_callback on_error,
- ws_on_message_callback on_message);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif
\ No newline at end of file
#ifndef __DEV_AUTHENTICATION_H__\r
#define __DEV_AUTHENTICATION_H__\r
\r
+#include <stdbool.h>\r
+#include <stdint.h>\r
+\r
#ifdef __cplusplus\r
extern "C" {\r
#endif /* __cplusplus */\r
\r
int active_md5_buf(char *in_buf,char*md5_str);\r
\r
+/**\r
+ * @brief 读取设备令牌\r
+ * @param data_token 输出缓冲区,存储读取的令牌(可以为NULL)\r
+ * @return true 成功,false 失败\r
+ */\r
+bool read_dev_token(char *data_token);\r
+\r
+/**\r
+ * @brief 获取设备ID\r
+ * @param device_id 输出缓冲区,存储设备ID\r
+ * @return 无返回值\r
+ */\r
+void get_dev_id(char *device_id);\r
+\r
#ifdef __cplusplus\r
}\r
#endif /* __cplusplus */\r
+++ /dev/null
-/*
- * ASR (Automatic Speech Recognition) 服务实现
- * 负责建立与ASR服务器的WebSocket连接管理,上传录音数据,接收识别结果
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include "asr_server.h"
-#include "ai_media.h" // 添加 AI Media 接口
-#include "../../../../application/wearable/ohos_deps/wearable_log.h"
-#include "../../../../../open_source/openharmony/third_party/cJSON/cJSON.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* 内部宏定义 */
-#define ASR_LOG_TAG "ASR_SERVER"
-
-/*
- * @brief 正式服务器URL
- */
-#define WS_SERVER_URL "ws://amp.raisound.com/asr/ws"
-/**
- * @brief 测试服务器URL
- */
-#define WS_TEST_SERVER_URL "ws://118.145.158.207:22080/asr/ws";
-
-/**
- * @brief Snicker测试服务器URL
- */
-#define WS_SNICKER_TEST_SERVER_URL "ws://110.42.224.129:8910/asr/ws";
-
-/* 全局变量 */
-static asr_server_context_t *g_asr_context = NULL; // 全局ASR上下文
-static bool g_audio_upload_enabled = false; // 录音数据上传标识位
-static bool g_recording_service_active = false; // 录音服务状态
-static bool g_websocket_connected = false; // WebSocket连接状态
-
-/* 内部函数声明 */
-static void asr_server_on_connected(void *context);
-static void asr_server_on_disconnected(void *context);
-static void asr_server_on_message_received(void *context, const char *data, size_t length);
-static void asr_server_on_error(void *context, int error_code, const char *error_msg);
-static ai_service_error_t asr_server_parse_recognition_result(asr_server_context_t *context,
- const char *json_data,
- asr_recognition_result_t *result);
-
-/* AI Media 录音回调函数 */
-static void asr_audio_record_callback(uint8_t *data, uint32_t size);
-
-/* 公共接口实现 */
-
-/**
- * @brief 初始化ASR WebSocket URL
- * @param put_buf 输出缓冲区,存储构建的URL
- * @return bool true表示成功,false表示失败
- * @note 从设备令牌构建完整的ASR WebSocket URL
- * 格式:ws://amp.raisound.com/asr/ws?dt={token}&platform=aliyun
- */
-bool asr_api_ws_url_init(char *put_buf)
-{
- char token[64] = {0};
- if (read_dev_token(token)) {
- sprintf(put_buf, "ws://amp.raisound.com/asr/ws?dt=%s&platform=aliyun", token);
- return true;
- } else {
- return false;
- }
-}
-
-ai_service_error_t asr_server_init(asr_server_context_t *context,
- const char *server_url,
- const asr_audio_config_t *audio_config,
- const asr_recognition_config_t *recognition_config)
-{
- if (!context || !server_url || !audio_config || !recognition_config) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- // 清零上下文
- memset(context, 0, sizeof(asr_server_context_t));
-
- // 创建基础服务配置
- ai_service_config_t base_config = {0};
- strncpy(base_config.server_url, server_url, sizeof(base_config.server_url) - 1);
- base_config.server_port = 80;
- strncpy(base_config.protocol, "asr-protocol", sizeof(base_config.protocol) - 1);
- base_config.connect_timeout_ms = AI_CONNECT_TIMEOUT_MS;
- base_config.receive_timeout_ms = AI_RECEIVE_TIMEOUT_MS;
- base_config.reconnect_interval_ms = AI_RECONNECT_INTERVAL_MS;
- base_config.heartbeat_interval_ms = AI_HEARTBEAT_INTERVAL_MS;
- base_config.max_retry_count = AI_MAX_RETRY_COUNT;
- base_config.auto_reconnect = true;
-
- // 初始化基础服务
- ai_service_error_t ret = ai_service_init(&context->base, "ASR_SERVER", &base_config);
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to init base service: %d", ASR_LOG_TAG, ret);
- return ret;
- }
-
- // 复制ASR特定配置
- memcpy(&context->audio_config, audio_config, sizeof(asr_audio_config_t));
- memcpy(&context->recognition_config, recognition_config, sizeof(asr_recognition_config_t));
-
- // 分配音频缓冲区
- context->audio_buffer_size = ASR_MAX_AUDIO_BUFFER_SIZE;
- context->audio_buffer = (char *)malloc(context->audio_buffer_size);
- if (!context->audio_buffer) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to allocate audio buffer", ASR_LOG_TAG);
- ai_service_destroy(&context->base);
- return AI_SERVICE_ERROR_MEMORY_ALLOC;
- }
-
- context->audio_buffer_used = 0;
-
- // 创建音频缓冲区互斥锁
- context->audio_buffer_mutex = osMutexNew(NULL);
- if (!context->audio_buffer_mutex) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to create audio buffer mutex", ASR_LOG_TAG);
- free(context->audio_buffer);
- ai_service_destroy(&context->base);
- return AI_SERVICE_ERROR_INTERNAL;
- }
-
- // 初始化会话状态
- context->session_active = false;
- memset(context->current_session_id, 0, sizeof(context->current_session_id));
-
- // 设置基础服务回调
- ai_service_set_callbacks(&context->base,
- asr_server_on_connected,
- asr_server_on_disconnected,
- asr_server_on_message_received,
- asr_server_on_error);
-
- // 设置用户数据指向ASR上下文
- ai_service_set_user_data(&context->base, context);
-
- // 设置全局上下文
- g_asr_context = context;
-
- // 初始化 AI Media 服务
- if (ai_media_service_init() != 0) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to init AI media service", ASR_LOG_TAG);
- free(context->audio_buffer);
- osMutexDelete(context->audio_buffer_mutex);
- ai_service_destroy(&context->base);
- return AI_SERVICE_ERROR_INTERNAL;
- }
-
- // 设置录音回调
- ai_media_set_record_callback(asr_audio_record_callback);
-
- // 启动录音服务(但不开启上传)
- ai_media_record_start((uint8_t*)"pcm");
- g_recording_service_active = true;
- g_audio_upload_enabled = false; // 初始状态不上传
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] ASR server initialized with recording service", ASR_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t asr_server_destroy(asr_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- // 停止服务
- asr_server_stop(context);
-
- // 停止录音服务
- if (g_recording_service_active) {
- g_audio_upload_enabled = false;
- ai_media_record_stop();
- g_recording_service_active = false;
- }
-
- // 反初始化 AI Media 服务
- ai_media_service_deinit();
-
- // 删除音频缓冲区互斥锁
- if (context->audio_buffer_mutex) {
- osMutexDelete(context->audio_buffer_mutex);
- context->audio_buffer_mutex = NULL;
- }
-
- // 释放音频缓冲区
- if (context->audio_buffer) {
- free(context->audio_buffer);
- context->audio_buffer = NULL;
- }
-
- // 销毁基础服务
- ai_service_destroy(&context->base);
-
- // 清除全局上下文
- g_asr_context = NULL;
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] ASR server destroyed", ASR_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t asr_server_start(asr_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- ai_service_error_t ret = ai_service_start(&context->base);
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to start ASR server: %d", ASR_LOG_TAG, ret);
- return ret;
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] ASR server started", ASR_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t asr_server_stop(asr_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- // 停止当前识别会话
- if (context->session_active) {
- asr_server_stop_recognition(context);
- }
-
- // 关闭录音数据上传
- g_audio_upload_enabled = false;
-
- ai_service_error_t ret = ai_service_stop(&context->base);
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to stop ASR server: %d", ASR_LOG_TAG, ret);
- return ret;
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] ASR server stopped", ASR_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t asr_server_start_recognition(asr_server_context_t *context,
- const char *session_id)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- if (!ai_service_is_connected(&context->base)) {
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[%s] ASR server is not connected", ASR_LOG_TAG);
- return AI_SERVICE_ERROR_NOT_CONNECTED;
- }
-
- if (context->session_active) {
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[%s] Recognition session is already active", ASR_LOG_TAG);
- return AI_SERVICE_ERROR_ALREADY_CONNECTED;
- }
-
- // 生成或使用提供的会话ID
- if (session_id && strlen(session_id) > 0) {
- strncpy(context->current_session_id, session_id, sizeof(context->current_session_id) - 1);
- } else {
- ai_service_generate_uuid(context->current_session_id, sizeof(context->current_session_id));
- }
-
- // 创建并发送开始识别消息
- asr_api_start_asr(context);
-
- context->session_active = true;
- context->recognition_sessions++;
-
- // 开启录音数据上传
- g_audio_upload_enabled = true;
-
- // 调用用户回调
- if (context->on_recognition_start) {
- context->on_recognition_start(context, context->current_session_id);
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Recognition started, session: %s, audio upload enabled",
- ASR_LOG_TAG, context->current_session_id);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t asr_server_stop_recognition(asr_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- if (!context->session_active) {
- return AI_SERVICE_OK;
- }
-
- // 关闭录音数据上传
- g_audio_upload_enabled = false;
-
- // 创建并发送停止识别消息
- asr_api_stop_asr(context);
-
- // 调用用户回调
- if (context->on_recognition_end) {
- context->on_recognition_end(context, context->current_session_id);
- }
-
- context->session_active = false;
- memset(context->current_session_id, 0, sizeof(context->current_session_id));
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Recognition stopped, audio upload disabled", ASR_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t asr_server_send_audio_stream(asr_server_context_t *context,
- const char *audio_data,
- size_t data_length,
- bool is_last)
-{
- if (!context || !audio_data || data_length == 0) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- if (!context->session_active) {
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[%s] No active recognition session", ASR_LOG_TAG);
- return AI_SERVICE_ERROR_NOT_CONNECTED;
- }
-
- if (!ai_service_is_connected(&context->base)) {
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[%s] ASR server is not connected", ASR_LOG_TAG);
- return AI_SERVICE_ERROR_NOT_CONNECTED;
- }
-
- // 检查录音数据上传标识位
- if (!g_audio_upload_enabled) {
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "[%s] Audio upload disabled, skipping data", ASR_LOG_TAG);
- return AI_SERVICE_OK;
- }
-
-
- // 发送音频消息
- if(!asr_api_send_ai_bin(context, (uint8_t *)audio_data, data_length))
- {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to send audio message", ASR_LOG_TAG);
- return AI_SERVICE_ERROR_INTERNAL;
- }
-
- context->total_audio_sent += data_length;
-
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "[%s] Sent %zu bytes audio data, level: %.2f",
- ASR_LOG_TAG, data_length, audio_level);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t asr_server_set_audio_config(asr_server_context_t *context,
- const asr_audio_config_t *audio_config)
-{
- if (!context || !audio_config) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- memcpy(&context->audio_config, audio_config, sizeof(asr_audio_config_t));
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Audio config updated", ASR_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t asr_server_set_recognition_config(asr_server_context_t *context,
- const asr_recognition_config_t *recognition_config)
-{
- if (!context || !recognition_config) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- memcpy(&context->recognition_config, recognition_config, sizeof(asr_recognition_config_t));
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Recognition config updated", ASR_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-const char* asr_server_get_current_session_id(asr_server_context_t *context)
-{
- if (!context || !context->session_active) {
- return NULL;
- }
-
- return context->current_session_id;
-}
-
-bool asr_server_is_recognition_active(asr_server_context_t *context)
-{
- return context ? context->session_active : false;
-}
-
-void asr_server_set_callbacks(asr_server_context_t *context,
- void (*on_recognition_result)(void *context, const asr_recognition_result_t *result),
- void (*on_recognition_start)(void *context, const char *session_id),
- void (*on_recognition_end)(void *context, const char *session_id),
- void (*on_audio_level)(void *context, float level))
-{
- if (!context) {
- return;
- }
-
- context->on_recognition_result = on_recognition_result;
- context->on_recognition_start = on_recognition_start;
- context->on_recognition_end = on_recognition_end;
- context->on_audio_level = on_audio_level;
-}
-
-void asr_server_get_stats(asr_server_context_t *context,
- uint32_t *total_audio_sent,
- uint32_t *total_results_received,
- uint32_t *recognition_sessions)
-{
- if (!context) {
- return;
- }
-
- if (total_audio_sent) {
- *total_audio_sent = context->total_audio_sent;
- }
-
- if (total_results_received) {
- *total_results_received = context->total_results_received;
- }
-
- if (recognition_sessions) {
- *recognition_sessions = context->recognition_sessions;
- }
-}
-
-/* 工具函数实现 */
-
-void asr_server_create_default_audio_config(asr_audio_config_t *config)
-{
- if (!config) {
- return;
- }
-
- config->format = ASR_AUDIO_FORMAT_PCM;
- config->sample_rate = ASR_SAMPLE_RATE_DEFAULT;
- config->channels = ASR_CHANNELS_DEFAULT;
- config->bits_per_sample = ASR_BITS_PER_SAMPLE_DEFAULT;
- config->frame_size_ms = ASR_FRAME_SIZE_MS_DEFAULT;
-}
-
-void asr_server_create_default_recognition_config(asr_recognition_config_t *config)
-{
- if (!config) {
- return;
- }
-
- config->mode = ASR_MODE_CONTINUOUS;
- config->language = ASR_LANGUAGE_ZH_CN;
- config->enable_punctuation = true;
- config->enable_word_timestamp = false;
- config->enable_confidence_score = true;
- config->max_silence_ms = 3000;
- config->max_speech_ms = 60000;
-}
-
-void asr_server_free_recognition_result(asr_recognition_result_t *result)
-{
- if (!result) {
- return;
- }
-
- if (result->text) {
- free(result->text);
- result->text = NULL;
- }
-
- if (result->session_id) {
- free(result->session_id);
- result->session_id = NULL;
- }
-}
-
-const char* asr_server_audio_format_to_string(asr_audio_format_t format)
-{
- switch (format) {
- case ASR_AUDIO_FORMAT_PCM: return "PCM";
- case ASR_AUDIO_FORMAT_WAV: return "WAV";
- case ASR_AUDIO_FORMAT_MP3: return "MP3";
- case ASR_AUDIO_FORMAT_OPUS: return "OPUS";
- default: return "UNKNOWN";
- }
-}
-
-const char* asr_server_recognition_mode_to_string(asr_recognition_mode_t mode)
-{
- switch (mode) {
- case ASR_MODE_CONTINUOUS: return "CONTINUOUS";
- case ASR_MODE_SINGLE_SHOT: return "SINGLE_SHOT";
- case ASR_MODE_STREAMING: return "STREAMING";
- default: return "UNKNOWN";
- }
-}
-
-const char* asr_server_language_to_string(asr_language_t language)
-{
- switch (language) {
- case ASR_LANGUAGE_ZH_CN: return "zh-CN";
- case ASR_LANGUAGE_EN_US: return "en-US";
- case ASR_LANGUAGE_AUTO: return "auto";
- default: return "unknown";
- }
-}
-
-/* 内部函数实现 */
-
-static void asr_server_on_connected(void *context)
-{
- asr_server_context_t *asr_context = (asr_server_context_t *)ai_service_get_user_data((ai_service_context_t *)context);
- if (!asr_context) {
- return;
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] ASR server connected", ASR_LOG_TAG);
-}
-
-static void asr_server_on_disconnected(void *context)
-{
- asr_server_context_t *asr_context = (asr_server_context_t *)ai_service_get_user_data((ai_service_context_t *)context);
- if (!asr_context) {
- return;
- }
-
- // WebSocket断连时,关闭录音数据上传标识位,但不停止录音服务
- g_audio_upload_enabled = false;
-
- // 停止当前识别会话
- if (asr_context->session_active) {
- asr_context->session_active = false;
- if (asr_context->on_recognition_end) {
- asr_context->on_recognition_end(asr_context, asr_context->current_session_id);
- }
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] ASR server disconnected, audio upload disabled", ASR_LOG_TAG);
-}
-
-static void asr_server_on_message_received(void *context, const char *data, size_t length)
-{
- asr_server_context_t *asr_context = (asr_server_context_t *)ai_service_get_user_data((ai_service_context_t *)context);
- if (!asr_context || !data || length == 0) {
- return;
- }
-
- // 使用 asr_api_result_analysis 分析服务器返回的数据
- char *buffer = (char*)malloc(length + 1);
- if (!buffer) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to allocate buffer for message", ASR_LOG_TAG);
- return;
- }
-
- memcpy(buffer, data, length);
- buffer[length] = '\0';
-
-
- bool continue_connection = true;
-
- // 解析识别结果
- asr_recognition_result_t result = {0};
- ai_service_error_t ret = asr_server_parse_recognition_result(asr_context, buffer, &result);
- if (ret == AI_SERVICE_OK) {
- asr_context->total_results_received++;
-
- // 调用用户回调
- if (asr_context->on_recognition_result) {
- asr_context->on_recognition_result(asr_context, &result);
- }
-
- // 释放结果内存
- asr_server_free_recognition_result(&result);
- }
-
- free(buffer);
-
- // 如果 asr_api_result_analysis 返回 false,表示需要断开连接
- if (!continue_connection) {
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] ASR analysis indicates disconnection needed", ASR_LOG_TAG);
- ai_service_stop(&asr_context->base);
- }
-
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "[%s] Received message: %.*s",
- ASR_LOG_TAG, (int)length, data);
-}
-
-static void asr_server_on_error(void *context, int error_code, const char *error_msg)
-{
- asr_server_context_t *asr_context = (asr_server_context_t *)ai_service_get_user_data((ai_service_context_t *)context);
- if (!asr_context) {
- return;
- }
-
- // 发生错误时关闭录音数据上传
- g_audio_upload_enabled = false;
-
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] ASR server error: %d - %s",
- ASR_LOG_TAG, error_code, error_msg ? error_msg : "Unknown");
-}
-
-static ai_service_error_t asr_server_parse_recognition_result(asr_server_context_t *context,
- const char *json_data,
- asr_recognition_result_t *result)
-{
- if (!context || !json_data || !result) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- if (asr_api_result_analysis(json_data,result))
- {
- return AI_SERVICE_OK;
- }
- else
- {
- return AI_SERVICE_ERROR_INTERNAL;
- }
-
-}
-
-
-/* AI Media 录音回调函数实现 */
-static void asr_audio_record_callback(uint8_t *data, uint32_t size)
-{
- if (!g_asr_context || !data || size == 0) {
- return;
- }
-
- // 只有在上传标识位开启时才处理录音数据
- if (!g_audio_upload_enabled) {
- return;
- }
-
- // 发送录音数据到ASR服务器
- asr_server_send_audio_stream(g_asr_context, (const char*)data, size, false);
-}
-
-
-
-/****************************************************************************************** */
-/***
- * // 处理事件类型
- if (event_str) {
- if (strcmp(event_str, "TranscriptionStarted") == 0) { // 可以对话了,切换到聆听界面
- // 查询结果
- startAudioCaptureTask();
-
- bool state = true;
- SendMsgToUIService(UI_AI_JUMP_TO_LISTENING_VIEW, 0, &state, sizeof(bool));
- }
- else if (strcmp(event_str, "TranscriptionCompleted") == 0) { // asr 结束
- cJSON_Delete(root);
- return true; // 返回true asr不断连
- }
- else if (strcmp(event_str, "Failed") == 0) {
- stop_AudioCaptureProcess_AI();
- cJSON_Delete(root);
- return false;
- }
- }
- */
-/**
- * @brief ASR结果分析函数
- * @param buf 接收到的JSON字符串缓冲区
- * @param result 输出的识别结果结构体
- * @return bool true表示解析成功,false表示解析失败
- * @note 解析ASR服务器返回的JSON响应,提取识别结果和相关信息
- *
- *
- */
-/*
-
-asr result
-
-{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"TranscriptionStarted"}
-{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"Changed","result":{"result":"我,","is_end":false,"sentence_id":"","start_time":0,"end_time":0}}
-{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"SentenceEnd","result":{"result":"给我讲讲。","is_end":true,"sentence_id":"","start_time":0,"end_time":0}}
-{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"Changed","result":{"result":"没,","is_end":false,"sentence_id":"","start_time":0,"end_time":0}}
-{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"Changed","result":{"result":"今","is_end":false,"sentence_id":"","start_time":0,"end_time":0}}
-{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"Changed","result":{"result":"今天打算","is_end":false,"sentence_id":"","start_time":0,"end_time":0}}
-{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"Changed","result":{"result":"今天早上有你可能","is_end":false,"sentence_id":"","start_time":0,"end_time":0}}
-{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"Changed","result":{"result":"今天早上我去可能去温","is_end":false,"sentence_id":"","start_time":0,"end_time":0}}
-{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"SentenceEnd","result":{"result":"今天早上有没有什么趣味?","is_end":true,"sentence_id":"","start_time":0,"end_time":0}}
-{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"TranscriptionCompleted"}
-
-
-{
- "status" : 20000000,
- "msg" : "success",
- "task_id" : "ff5809f9a303aa133542df23e171dfc7",
- "event" : "SentenceEnd",
- "result": {
- "result" : "今天早上有没有什么趣味?",
- "is_end" : true,
- "sentence_id" : "",
- "start_time" : 0,
- "end_time" : 0
- }
-}
-
-*/
-
-bool asr_api_result_analysis(char *buf, asr_recognition_result_t *result)
-{
- // 参数检查
- if (!buf || !result) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid parameters for asr_api_result_analysis");
- return false;
- }
-
- // 解析JSON响应
- cJSON* root = cJSON_Parse((const char *)buf);
- if (root == NULL) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "解析失败 %s\n", buf);
- return false;
- }
-
- // 初始化解析变量
- char *result_str = NULL;
- int start_time_int = 0;
- int end_time_int = 0;
- bool is_end_bool = false;
- char *event_str = NULL;
-
- // 解析事件类型
- cJSON* event = cJSON_GetObjectItem(root, "event");
- if (event && cJSON_IsString(event)) {
- event_str = event->valuestring;
- }
-
- // 解析识别结果 - 修复变量名冲突
- cJSON* result_json = cJSON_GetObjectItem(root, "result");
- if (result_json) {
- // 获取识别文本
- cJSON* result_ = cJSON_GetObjectItem(result_json, "result");
- if (result_ && cJSON_IsString(result_)) {
- result_str = result_->valuestring;
- }
-
- // 获取开始时间
- cJSON* start_time = cJSON_GetObjectItem(result_json, "start_time");
- if (start_time && cJSON_IsNumber(start_time)) {
- start_time_int = start_time->valueint;
- }
-
- // 获取结束时间
- cJSON* end_time = cJSON_GetObjectItem(result_json, "end_time");
- if (end_time && cJSON_IsNumber(end_time)) {
- end_time_int = end_time->valueint;
- }
-
- // 获取是否结束标志
- cJSON* is_end = cJSON_GetObjectItem(result_json, "is_end");
- if (is_end && cJSON_IsBool(is_end)) {
- is_end_bool = is_end->valueint;
- }
- }
-
- // 安全的日志输出,避免空指针
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"str %s start %d end %d is end %d\n",
- result_str ? result_str : "NULL", start_time_int, end_time_int, is_end_bool);
-
- // 只有在最终结果且有有效文本时才填充 result 结构体
- if (is_end_bool == true) {
-
- // *** 关键修复:释放之前可能存在的内存,避免内存泄露 ***
- if (result->text) {
- free(result->text);
- result->text = NULL;
- }
- if (result->session_id) {
- free(result->session_id);
- result->session_id = NULL;
- }
-
- if(result_str)
- {
- // 安全分配内存并复制文本
- size_t text_len = strlen(result_str);
- result->text = (char *)malloc(text_len + 1);
- if (!result->text) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to allocate memory for result text");
- cJSON_Delete(root);
- return false;
- }
- strcpy(result->text, result_str);
- }
- // 设置其他字段
- result->start_time_ms = start_time_int;
- result->end_time_ms = end_time_int;
- result->is_final = is_end_bool;
- result->confidence = 1.0f; // 默认置信度
-
- // 安全分配并复制会话ID(使用事件类型作为会话标识)
- if (event_str) {
- size_t event_len = strlen(event_str);
- result->session_id = (char *)malloc(event_len + 1);
- if (!result->session_id) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to allocate memory for session_id");
- // 清理已分配的内存
- free(result->text);
- result->text = NULL;
- cJSON_Delete(root);
- return false;
- }
- strcpy(result->session_id, event_str);
- }
- }
-
- cJSON_Delete(root);
- return true;
-
-}
-
-/**
- * @brief 启动ASR(语音识别)服务
- * @param context ASR服务上下文
- * @note 查询是否可以对话,启动语音识别功能
- */
-void asr_api_start_asr(asr_server_context_t *context)
-{
- if (!context) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Invalid context for asr_api_start_asr", ASR_LOG_TAG);
- return;
- }
-
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "查询asr_api_start_asr是否可用\n");
-
- // 构建ASR启动转录的JSON消息
- char *jsonString = "{\"header\":{\"event\":\"StartTranscription\",\"trace_id\": \
- \"3fa6b9e6a30b407ea38ad7ae69e6c291\"},\"payload\":{\"format\":\"MP3\",\"sample_rate\":16000}}";
-
- // 使用 ai_service_send_text 发送启动转录消息到ASR服务器
- ai_service_error_t ret = ai_service_send_text(&context->base, jsonString);
- if (ret == AI_SERVICE_OK) {
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "asr_api_start_asr send message success\n");
- // 开启录音数据上传标识位
- g_audio_upload_enabled = true;
- } else {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "asr_api_start_asr send message error: %d\n", ret);
- }
-}
-
-/**
- * @brief 停止ASR(语音识别)服务
- * @param context ASR服务上下文
- * @note 发送停止转录消息到ASR服务器
- */
-void asr_api_stop_asr(asr_server_context_t *context)
-{
- if (!context) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Invalid context for asr_api_stop_asr", ASR_LOG_TAG);
- return;
- }
-
- // 关闭录音数据上传标识位
- g_audio_upload_enabled = false;
-
- // 构建ASR停止转录的JSON消息
- char *jsonString = "{\"header\":{\"event\":\"StopTranscription\",\"trace_id\":\"3fa6b9e6a30b407ea38ad7ae69e6c291\"}}";
-
- // 使用 ai_service_send_text 发送停止转录消息到ASR服务器
- ai_service_error_t ret = ai_service_send_text(&context->base, jsonString);
- if (ret == AI_SERVICE_OK) {
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "asr_api_stop_asr send message success\n");
- } else {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "asr_api_stop_asr send message error: %d\n", ret);
- }
-}
-
-
-
-bool asr_api_send_ai_bin(asr_server_context_t *context,uint8_t *buf,uint32_t len)
-{
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_ai_bin %d\n",len);
- // voice_chat_client
- ai_service_error_t ret = ai_service_send_binary(&context->base, buf, len);
- if(ret == AI_SERVICE_OK)
- {
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_websocket_message succ 0\n");
- msleep(100);
- return true;
- }
- else
- {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"send_websocket_message fail 0\n");
- return false;
- }
-}
-
-#ifdef __cplusplus
-}
-#endif
\ No newline at end of file
--- /dev/null
+/*
+ * ASR (Automatic Speech Recognition) 服务实现
+ * 负责建立与ASR服务器的WebSocket连接管理,上传录音数据,接收识别结果
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "asr_server.h"
+#include "ai_media.h" // 添加 AI Media 接口
+#include "../../../../application/wearable/ohos_deps/wearable_log.h"
+#include "../../../../../open_source/openharmony/third_party/cJSON/cJSON.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 内部宏定义 */
+#define ASR_LOG_TAG "ASR_SERVER"
+
+/*
+ * @brief 正式服务器URL
+ */
+#define WS_SERVER_URL "ws://amp.raisound.com/asr/ws"
+/**
+ * @brief 测试服务器URL
+ */
+#define WS_TEST_SERVER_URL "ws://118.145.158.207:22080/asr/ws";
+
+/**
+ * @brief Snicker测试服务器URL
+ */
+#define WS_SNICKER_TEST_SERVER_URL "ws://110.42.224.129:8910/asr/ws";
+
+
+/**
+ * @brief 初始化ASR WebSocket URL
+ * @param put_buf 输出缓冲区,存储构建的URL
+ * @return bool true表示成功,false表示失败
+ * @note 从设备令牌构建完整的ASR WebSocket URL
+ * 格式:ws://amp.raisound.com/asr/ws?dt={token}&platform=aliyun
+ */
+bool asr_api_ws_url_init(char *put_buf)
+{
+ char token[64] = {0};
+ if (read_dev_token(token)) {
+ sprintf(put_buf, "ws://amp.raisound.com/asr/ws?dt=%s&platform=aliyun", token);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+
+/****************************************************************************************** */
+/***
+ * // 处理事件类型
+ if (event_str) {
+ if (strcmp(event_str, "TranscriptionStarted") == 0) { // 可以对话了,切换到聆听界面
+ // 查询结果
+ startAudioCaptureTask();
+
+ bool state = true;
+ SendMsgToUIService(UI_AI_JUMP_TO_LISTENING_VIEW, 0, &state, sizeof(bool));
+ }
+ else if (strcmp(event_str, "TranscriptionCompleted") == 0) { // asr 结束
+ cJSON_Delete(root);
+ return true; // 返回true asr不断连
+ }
+ else if (strcmp(event_str, "Failed") == 0) {
+ stop_AudioCaptureProcess_AI();
+ cJSON_Delete(root);
+ return false;
+ }
+ }
+ */
+/**
+ * @brief ASR结果分析函数
+ * @param buf 接收到的JSON字符串缓冲区
+ * @param result 输出的识别结果结构体
+ * @return bool true表示解析成功,false表示解析失败
+ * @note 解析ASR服务器返回的JSON响应,提取识别结果和相关信息
+ *
+ *
+ */
+/*
+
+asr result
+
+{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"TranscriptionStarted"}
+{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"Changed","result":{"result":"我,","is_end":false,"sentence_id":"","start_time":0,"end_time":0}}
+{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"SentenceEnd","result":{"result":"给我讲讲。","is_end":true,"sentence_id":"","start_time":0,"end_time":0}}
+{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"Changed","result":{"result":"没,","is_end":false,"sentence_id":"","start_time":0,"end_time":0}}
+{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"Changed","result":{"result":"今","is_end":false,"sentence_id":"","start_time":0,"end_time":0}}
+{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"Changed","result":{"result":"今天打算","is_end":false,"sentence_id":"","start_time":0,"end_time":0}}
+{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"Changed","result":{"result":"今天早上有你可能","is_end":false,"sentence_id":"","start_time":0,"end_time":0}}
+{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"Changed","result":{"result":"今天早上我去可能去温","is_end":false,"sentence_id":"","start_time":0,"end_time":0}}
+{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"SentenceEnd","result":{"result":"今天早上有没有什么趣味?","is_end":true,"sentence_id":"","start_time":0,"end_time":0}}
+{"status":20000000,"msg":"success","task_id":"ff5809f9a303aa133542df23e171dfc7","event":"TranscriptionCompleted"}
+
+
+{
+ "status" : 20000000,
+ "msg" : "success",
+ "task_id" : "ff5809f9a303aa133542df23e171dfc7",
+ "event" : "SentenceEnd",
+ "result": {
+ "result" : "今天早上有没有什么趣味?",
+ "is_end" : true,
+ "sentence_id" : "",
+ "start_time" : 0,
+ "end_time" : 0
+ }
+}
+
+*/
+
+bool asr_api_result_analysis(char *buf, asr_recognition_result_t *result)
+{
+ // 参数检查
+ if (!buf || !result) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid parameters for asr_api_result_analysis");
+ return false;
+ }
+
+ // 解析JSON响应
+ cJSON* root = cJSON_Parse((const char *)buf);
+ if (root == NULL) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "解析失败 %s\n", buf);
+ return false;
+ }
+
+ // 初始化解析变量
+ char *result_str = NULL;
+ int start_time_int = 0;
+ int end_time_int = 0;
+ bool is_end_bool = false;
+ char *event_str = NULL;
+
+ // 解析事件类型
+ cJSON* event = cJSON_GetObjectItem(root, "event");
+ if (event && cJSON_IsString(event)) {
+ event_str = event->valuestring;
+ }
+
+ // 解析识别结果 - 修复变量名冲突
+ cJSON* result_json = cJSON_GetObjectItem(root, "result");
+ if (result_json) {
+ // 获取识别文本
+ cJSON* result_ = cJSON_GetObjectItem(result_json, "result");
+ if (result_ && cJSON_IsString(result_)) {
+ result_str = result_->valuestring;
+ }
+
+ // 获取开始时间
+ cJSON* start_time = cJSON_GetObjectItem(result_json, "start_time");
+ if (start_time && cJSON_IsNumber(start_time)) {
+ start_time_int = start_time->valueint;
+ }
+
+ // 获取结束时间
+ cJSON* end_time = cJSON_GetObjectItem(result_json, "end_time");
+ if (end_time && cJSON_IsNumber(end_time)) {
+ end_time_int = end_time->valueint;
+ }
+
+ // 获取是否结束标志
+ cJSON* is_end = cJSON_GetObjectItem(result_json, "is_end");
+ if (is_end && cJSON_IsBool(is_end)) {
+ is_end_bool = is_end->valueint;
+ }
+ }
+
+ // 安全的日志输出,避免空指针
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"str %s start %d end %d is end %d\n",
+ result_str ? result_str : "NULL", start_time_int, end_time_int, is_end_bool);
+
+ // 只有在最终结果且有有效文本时才填充 result 结构体
+ if (is_end_bool == true) {
+
+ // *** 关键修复:释放之前可能存在的内存,避免内存泄露 ***
+ if (result->text) {
+ free(result->text);
+ result->text = NULL;
+ }
+ if (result->session_id) {
+ free(result->session_id);
+ result->session_id = NULL;
+ }
+
+ if(result_str)
+ {
+ // 安全分配内存并复制文本
+ size_t text_len = strlen(result_str);
+ result->text = (char *)malloc(text_len + 1);
+ if (!result->text) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to allocate memory for result text");
+ cJSON_Delete(root);
+ return false;
+ }
+ strcpy(result->text, result_str);
+ }
+ // 设置其他字段
+ result->start_time_ms = start_time_int;
+ result->end_time_ms = end_time_int;
+ result->is_final = is_end_bool;
+ result->confidence = 1.0f; // 默认置信度
+
+ // 安全分配并复制会话ID(使用事件类型作为会话标识)
+ if (event_str) {
+ size_t event_len = strlen(event_str);
+ result->session_id = (char *)malloc(event_len + 1);
+ if (!result->session_id) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to allocate memory for session_id");
+ // 清理已分配的内存
+ free(result->text);
+ result->text = NULL;
+ cJSON_Delete(root);
+ return false;
+ }
+ strcpy(result->session_id, event_str);
+ }
+ }
+
+ cJSON_Delete(root);
+ return true;
+
+}
+
+/**
+ * @brief 启动ASR(语音识别)服务
+ * @param context ASR服务上下文
+ * @note 查询是否可以对话,启动语音识别功能
+ */
+void asr_api_start_asr(asr_server_context_t *context)
+{
+ if (!context) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Invalid context for asr_api_start_asr", ASR_LOG_TAG);
+ return;
+ }
+
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "查询asr_api_start_asr是否可用\n");
+
+ // 构建ASR启动转录的JSON消息
+ char *jsonString = "{\"header\":{\"event\":\"StartTranscription\",\"trace_id\": \
+ \"3fa6b9e6a30b407ea38ad7ae69e6c291\"},\"payload\":{\"format\":\"MP3\",\"sample_rate\":16000}}";
+
+ // 使用 ai_service_send_text 发送启动转录消息到ASR服务器
+ ai_service_error_t ret = ai_service_send_text(&context->base, jsonString);
+ if (ret == AI_SERVICE_OK) {
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "asr_api_start_asr send message success\n");
+ // 开启录音数据上传标识位
+ g_audio_upload_enabled = true;
+ } else {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "asr_api_start_asr send message error: %d\n", ret);
+ }
+}
+
+/**
+ * @brief 停止ASR(语音识别)服务
+ * @param context ASR服务上下文
+ * @note 发送停止转录消息到ASR服务器
+ */
+void asr_api_stop_asr(asr_server_context_t *context)
+{
+ if (!context) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Invalid context for asr_api_stop_asr", ASR_LOG_TAG);
+ return;
+ }
+
+ // 关闭录音数据上传标识位
+ g_audio_upload_enabled = false;
+
+ // 构建ASR停止转录的JSON消息
+ char *jsonString = "{\"header\":{\"event\":\"StopTranscription\",\"trace_id\":\"3fa6b9e6a30b407ea38ad7ae69e6c291\"}}";
+
+ // 使用 ai_service_send_text 发送停止转录消息到ASR服务器
+ ai_service_error_t ret = ai_service_send_text(&context->base, jsonString);
+ if (ret == AI_SERVICE_OK) {
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "asr_api_stop_asr send message success\n");
+ } else {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "asr_api_stop_asr send message error: %d\n", ret);
+ }
+}
+
+
+
+bool asr_api_send_ai_bin(asr_server_context_t *context,uint8_t *buf,uint32_t len)
+{
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_ai_bin %d\n",len);
+ // voice_chat_client
+ ai_service_error_t ret = ai_service_send_binary(&context->base, buf, len);
+ if(ret == AI_SERVICE_OK)
+ {
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_websocket_message succ 0\n");
+ msleep(100);
+ return true;
+ }
+ else
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"send_websocket_message fail 0\n");
+ return false;
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
\ No newline at end of file
+++ /dev/null
-/*
- * Chat 大模型服务实现
- * 负责建立与Chat大模型服务器的WebSocket连接管理,上传文本,接收回复并转发给TTS
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "chat_server.h"
-#include "../../../../application/wearable/ohos_deps/wearable_log.h"
-#include "../../../../../open_source/openharmony/third_party/cJSON/cJSON.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* 内部宏定义 */
-#define CHAT_LOG_TAG "CHAT_SERVER"
-#define CHAT_MAX_CONVERSATIONS 10
-
-/* 内部函数声明 */
-static void chat_server_on_connected(void *context);
-static void chat_server_on_disconnected(void *context);
-static void chat_server_on_message_received(void *context, const char *data, size_t length);
-static void chat_server_on_error(void *context, int error_code, const char *error_msg);
-static ai_service_error_t chat_server_parse_response(chat_server_context_t *context,
- const char *json_data,
- chat_response_t *response);
-static ai_service_error_t chat_server_create_request_message(chat_server_context_t *context,
- const chat_request_t *request,
- char *output, size_t max_len);
-static chat_conversation_t* chat_server_find_conversation(chat_server_context_t *context,
- const char *session_id);
-static chat_conversation_t* chat_server_create_conversation(chat_server_context_t *context,
- const char *session_id);
-static ai_service_error_t chat_server_add_message_to_conversation(chat_server_context_t *context,
- const char *session_id,
- chat_role_t role,
- const char *content);
-
-/* 公共接口实现 */
-
-ai_service_error_t chat_server_init(chat_server_context_t *context,
- const char *server_url,
- const chat_model_config_t *model_config)
-{
- if (!context || !server_url || !model_config) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- // 清零上下文
- memset(context, 0, sizeof(chat_server_context_t));
-
- // 创建基础服务配置
- ai_service_config_t base_config = {0};
- strncpy(base_config.server_url, server_url, sizeof(base_config.server_url) - 1);
- base_config.server_port = 80;
- strncpy(base_config.protocol, "chat-protocol", sizeof(base_config.protocol) - 1);
- base_config.connect_timeout_ms = AI_CONNECT_TIMEOUT_MS;
- base_config.receive_timeout_ms = AI_RECEIVE_TIMEOUT_MS;
- base_config.reconnect_interval_ms = AI_RECONNECT_INTERVAL_MS;
- base_config.heartbeat_interval_ms = AI_HEARTBEAT_INTERVAL_MS;
- base_config.max_retry_count = AI_MAX_RETRY_COUNT;
- base_config.auto_reconnect = true;
-
- // 初始化基础服务
- ai_service_error_t ret = ai_service_init(&context->base, "CHAT_SERVER", &base_config);
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to init base service: %d", CHAT_LOG_TAG, ret);
- return ret;
- }
-
- // 复制Chat特定配置
- memcpy(&context->model_config, model_config, sizeof(chat_model_config_t));
- context->response_mode = CHAT_RESPONSE_MODE_COMPLETE;
-
- // 初始化会话管理
- context->max_conversations = CHAT_MAX_CONVERSATIONS;
- context->conversations = (chat_conversation_t *)malloc(sizeof(chat_conversation_t) * context->max_conversations);
- if (!context->conversations) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to allocate conversations", CHAT_LOG_TAG);
- ai_service_destroy(&context->base);
- return AI_SERVICE_ERROR_MEMORY_ALLOC;
- }
-
- // 初始化所有会话
- for (size_t i = 0; i < context->max_conversations; i++) {
- memset(&context->conversations[i], 0, sizeof(chat_conversation_t));
- }
-
- context->conversation_count = 0;
-
- // 创建会话互斥锁
- context->conversation_mutex = osMutexNew(NULL);
- if (!context->conversation_mutex) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to create conversation mutex", CHAT_LOG_TAG);
- free(context->conversations);
- ai_service_destroy(&context->base);
- return AI_SERVICE_ERROR_INTERNAL;
- }
-
- // 初始化统计信息
- memset(&context->chat_stats, 0, sizeof(chat_stats_t));
-
- // 设置基础服务回调
- ai_service_set_callbacks(&context->base,
- chat_server_on_connected,
- chat_server_on_disconnected,
- chat_server_on_message_received,
- chat_server_on_error);
-
- // 设置用户数据指向Chat上下文
- ai_service_set_user_data(&context->base, context);
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Chat server initialized", CHAT_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t chat_server_destroy(chat_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- // 停止服务
- chat_server_stop(context);
-
- // 清理所有会话
- if (context->conversations) {
- for (size_t i = 0; i < context->max_conversations; i++) {
- chat_conversation_free(&context->conversations[i]);
- }
- free(context->conversations);
- context->conversations = NULL;
- }
-
- // 删除会话互斥锁
- if (context->conversation_mutex) {
- osMutexDelete(context->conversation_mutex);
- context->conversation_mutex = NULL;
- }
-
- // 销毁基础服务
- ai_service_destroy(&context->base);
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Chat server destroyed", CHAT_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t chat_server_start(chat_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- ai_service_error_t ret = ai_service_start(&context->base);
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to start Chat server: %d", CHAT_LOG_TAG, ret);
- return ret;
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Chat server started", CHAT_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t chat_server_stop(chat_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- ai_service_error_t ret = ai_service_stop(&context->base);
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to stop Chat server: %d", CHAT_LOG_TAG, ret);
- return ret;
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Chat server stopped", CHAT_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t chat_server_send_message(chat_server_context_t *context,
- const char *message,
- const char *session_id)
-{
- if (!context || !message) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- chat_request_t request = {0};
- request.message = (char *)message;
- request.message_type = CHAT_MESSAGE_TYPE_TEXT;
- request.response_mode = context->response_mode;
- request.model_config = context->model_config;
- request.include_history = context->model_config.enable_history;
-
- if (session_id && strlen(session_id) > 0) {
- strncpy(request.session_id, session_id, sizeof(request.session_id) - 1);
- } else {
- ai_service_generate_uuid(request.session_id, sizeof(request.session_id));
- }
-
- return chat_server_send_request(context, &request);
-}
-
-ai_service_error_t chat_server_send_request(chat_server_context_t *context,
- const chat_request_t *request)
-{
- if (!context || !request) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- if (!ai_service_is_connected(&context->base)) {
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[%s] Chat server is not connected", CHAT_LOG_TAG);
- return AI_SERVICE_ERROR_NOT_CONNECTED;
- }
-
- // 添加用户消息到会话历史
- if (request->include_history) {
- chat_server_add_message_to_conversation(context, request->session_id,
- CHAT_ROLE_USER, request->message);
- }
-
- // 创建请求消息
- char *chat_message = (char *)malloc(CHAT_MAX_MESSAGE_LENGTH + CHAT_MAX_CONTEXT_LENGTH + 1024);
- if (!chat_message) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to allocate chat message buffer", CHAT_LOG_TAG);
- return AI_SERVICE_ERROR_MEMORY_ALLOC;
- }
-
- ai_service_error_t ret = chat_server_create_request_message(context, request,
- chat_message,
- CHAT_MAX_MESSAGE_LENGTH + CHAT_MAX_CONTEXT_LENGTH + 1024);
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to create chat message: %d", CHAT_LOG_TAG, ret);
- free(chat_message);
- return ret;
- }
-
- // 发送请求消息
- ret = ai_service_send_text(&context->base, chat_message);
- free(chat_message);
-
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to send chat message: %d", CHAT_LOG_TAG, ret);
- return ret;
- }
-
- // 更新当前会话ID
- strncpy(context->current_session_id, request->session_id, sizeof(context->current_session_id) - 1);
-
- // 更新统计信息
- context->chat_stats.total_requests++;
- if (request->message) {
- context->chat_stats.total_tokens_sent += strlen(request->message); // 简化的token计算
- }
-
- // 调用用户回调
- if (context->on_chat_start) {
- context->on_chat_start(context, request->session_id);
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Chat request sent, session: %s",
- CHAT_LOG_TAG, request->session_id);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t chat_server_create_session(chat_server_context_t *context,
- const char *session_id)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- char actual_session_id[64];
- if (session_id && strlen(session_id) > 0) {
- strncpy(actual_session_id, session_id, sizeof(actual_session_id) - 1);
- } else {
- ai_service_generate_uuid(actual_session_id, sizeof(actual_session_id));
- }
-
- chat_conversation_t *conversation = chat_server_create_conversation(context, actual_session_id);
- if (!conversation) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to create conversation", CHAT_LOG_TAG);
- return AI_SERVICE_ERROR_INTERNAL;
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Session created: %s", CHAT_LOG_TAG, actual_session_id);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t chat_server_delete_session(chat_server_context_t *context,
- const char *session_id)
-{
- if (!context || !session_id) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- osMutexAcquire(context->conversation_mutex, osWaitForever);
-
- for (size_t i = 0; i < context->max_conversations; i++) {
- if (strlen(context->conversations[i].session_id) > 0 &&
- strcmp(context->conversations[i].session_id, session_id) == 0) {
-
- chat_conversation_free(&context->conversations[i]);
- memset(&context->conversations[i], 0, sizeof(chat_conversation_t));
- context->conversation_count--;
-
- osMutexRelease(context->conversation_mutex);
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Session deleted: %s", CHAT_LOG_TAG, session_id);
- return AI_SERVICE_OK;
- }
- }
-
- osMutexRelease(context->conversation_mutex);
-
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[%s] Session not found: %s", CHAT_LOG_TAG, session_id);
- return AI_SERVICE_ERROR_INVALID_PARAM;
-}
-
-ai_service_error_t chat_server_clear_session_history(chat_server_context_t *context,
- const char *session_id)
-{
- if (!context || !session_id) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- chat_conversation_t *conversation = chat_server_find_conversation(context, session_id);
- if (!conversation) {
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[%s] Session not found: %s", CHAT_LOG_TAG, session_id);
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- ai_service_error_t ret = chat_conversation_clear_messages(conversation);
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to clear session history: %d", CHAT_LOG_TAG, ret);
- return ret;
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Session history cleared: %s", CHAT_LOG_TAG, session_id);
-
- return AI_SERVICE_OK;
-}
-
-const chat_conversation_t* chat_server_get_session_history(chat_server_context_t *context,
- const char *session_id)
-{
- if (!context || !session_id) {
- return NULL;
- }
-
- return chat_server_find_conversation(context, session_id);
-}
-
-ai_service_error_t chat_server_set_model_config(chat_server_context_t *context,
- const chat_model_config_t *model_config)
-{
- if (!context || !model_config) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- memcpy(&context->model_config, model_config, sizeof(chat_model_config_t));
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Model config updated", CHAT_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t chat_server_set_response_mode(chat_server_context_t *context,
- chat_response_mode_t response_mode)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- context->response_mode = response_mode;
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Response mode updated: %s",
- CHAT_LOG_TAG, chat_server_response_mode_to_string(response_mode));
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t chat_server_set_tts_interface(chat_server_context_t *context,
- ai_service_error_t (*tts_send_text)(const char *text, const char *session_id))
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- context->tts_send_text = tts_send_text;
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] TTS interface set", CHAT_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-const char* chat_server_get_current_session_id(chat_server_context_t *context)
-{
- if (!context || strlen(context->current_session_id) == 0) {
- return NULL;
- }
-
- return context->current_session_id;
-}
-
-size_t chat_server_get_session_count(chat_server_context_t *context)
-{
- return context ? context->conversation_count : 0;
-}
-
-void chat_server_set_callbacks(chat_server_context_t *context,
- void (*on_chat_start)(void *context, const char *session_id),
- void (*on_chat_response)(void *context, const chat_response_t *response),
- void (*on_chat_complete)(void *context, const char *session_id),
- void (*on_chat_streaming)(void *context, const char *session_id, const char *partial_content))
-{
- if (!context) {
- return;
- }
-
- context->on_chat_start = on_chat_start;
- context->on_chat_response = on_chat_response;
- context->on_chat_complete = on_chat_complete;
- context->on_chat_streaming = on_chat_streaming;
-}
-
-const chat_stats_t* chat_server_get_stats(chat_server_context_t *context)
-{
- return context ? &context->chat_stats : NULL;
-}
-
-/* 会话管理函数实现 */
-
-ai_service_error_t chat_conversation_add_message(chat_conversation_t *conversation,
- chat_role_t role,
- const char *content,
- chat_message_type_t message_type)
-{
- if (!conversation || !content) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- // 检查是否需要扩展消息数组
- if (conversation->message_count >= conversation->max_messages) {
- size_t new_max = conversation->max_messages == 0 ? 10 : conversation->max_messages * 2;
- chat_message_t *new_messages = (chat_message_t *)realloc(conversation->messages,
- sizeof(chat_message_t) * new_max);
- if (!new_messages) {
- return AI_SERVICE_ERROR_MEMORY_ALLOC;
- }
- conversation->messages = new_messages;
- conversation->max_messages = new_max;
- }
-
- // 添加新消息
- chat_message_t *message = &conversation->messages[conversation->message_count];
- memset(message, 0, sizeof(chat_message_t));
-
- message->role = role;
- message->type = message_type;
- message->content = strdup(content);
- message->content_length = strlen(content);
- message->timestamp = ai_service_get_timestamp();
-
- // 生成消息ID
- ai_service_generate_uuid(message->message_id, sizeof(message->message_id));
-
- conversation->message_count++;
- conversation->last_update_time = ai_service_get_timestamp();
-
- return AI_SERVICE_OK;
-}
-
-const chat_message_t* chat_conversation_get_last_message(const chat_conversation_t *conversation)
-{
- if (!conversation || conversation->message_count == 0) {
- return NULL;
- }
-
- return &conversation->messages[conversation->message_count - 1];
-}
-
-ai_service_error_t chat_conversation_clear_messages(chat_conversation_t *conversation)
-{
- if (!conversation) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- // 释放所有消息内容
- for (size_t i = 0; i < conversation->message_count; i++) {
- if (conversation->messages[i].content) {
- free(conversation->messages[i].content);
- conversation->messages[i].content = NULL;
- }
- }
-
- conversation->message_count = 0;
- conversation->last_update_time = ai_service_get_timestamp();
-
- return AI_SERVICE_OK;
-}
-
-void chat_conversation_free(chat_conversation_t *conversation)
-{
- if (!conversation) {
- return;
- }
-
- // 清空消息
- chat_conversation_clear_messages(conversation);
-
- // 释放消息数组
- if (conversation->messages) {
- free(conversation->messages);
- conversation->messages = NULL;
- }
-
- conversation->max_messages = 0;
-}
-
-/* 工具函数实现 */
-
-void chat_server_create_default_model_config(chat_model_config_t *config)
-{
- if (!config) {
- return;
- }
-
- strncpy(config->model_name, "gpt-3.5-turbo", sizeof(config->model_name) - 1);
- config->model_type = CHAT_MODEL_TYPE_GPT35;
- config->temperature = 0.7f;
- config->top_p = 0.9f;
- config->max_tokens = 2048;
- config->enable_history = true;
- config->max_history_count = CHAT_MAX_HISTORY_COUNT;
-}
-
-void chat_server_free_response(chat_response_t *response)
-{
- if (!response) {
- return;
- }
-
- if (response->content) {
- free(response->content);
- response->content = NULL;
- }
-}
-
-void chat_server_free_message(chat_message_t *message)
-{
- if (!message) {
- return;
- }
-
- if (message->content) {
- free(message->content);
- message->content = NULL;
- }
-}
-
-const char* chat_server_message_type_to_string(chat_message_type_t message_type)
-{
- switch (message_type) {
- case CHAT_MESSAGE_TYPE_TEXT: return "TEXT";
- case CHAT_MESSAGE_TYPE_IMAGE: return "IMAGE";
- case CHAT_MESSAGE_TYPE_AUDIO: return "AUDIO";
- case CHAT_MESSAGE_TYPE_VIDEO: return "VIDEO";
- case CHAT_MESSAGE_TYPE_SYSTEM: return "SYSTEM";
- default: return "UNKNOWN";
- }
-}
-
-const char* chat_server_role_to_string(chat_role_t role)
-{
- switch (role) {
- case CHAT_ROLE_USER: return "user";
- case CHAT_ROLE_ASSISTANT: return "assistant";
- case CHAT_ROLE_SYSTEM: return "system";
- default: return "unknown";
- }
-}
-
-const char* chat_server_model_type_to_string(chat_model_type_t model_type)
-{
- switch (model_type) {
- case CHAT_MODEL_TYPE_GPT35: return "GPT-3.5";
- case CHAT_MODEL_TYPE_GPT4: return "GPT-4";
- case CHAT_MODEL_TYPE_CLAUDE: return "Claude";
- case CHAT_MODEL_TYPE_LLAMA: return "LLaMA";
- case CHAT_MODEL_TYPE_QWEN: return "Qwen";
- case CHAT_MODEL_TYPE_BAICHUAN: return "Baichuan";
- default: return "UNKNOWN";
- }
-}
-
-const char* chat_server_response_mode_to_string(chat_response_mode_t response_mode)
-{
- switch (response_mode) {
- case CHAT_RESPONSE_MODE_COMPLETE: return "COMPLETE";
- case CHAT_RESPONSE_MODE_STREAMING: return "STREAMING";
- default: return "UNKNOWN";
- }
-}
-
-/* 内部函数实现 */
-
-static void chat_server_on_connected(void *context)
-{
- chat_server_context_t *chat_context = (chat_server_context_t *)ai_service_get_user_data((ai_service_context_t *)context);
- if (!chat_context) {
- return;
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Chat server connected", CHAT_LOG_TAG);
-}
-
-static void chat_server_on_disconnected(void *context)
-{
- chat_server_context_t *chat_context = (chat_server_context_t *)ai_service_get_user_data((ai_service_context_t *)context);
- if (!chat_context) {
- return;
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Chat server disconnected", CHAT_LOG_TAG);
-}
-
-static void chat_server_on_message_received(void *context, const char *data, size_t length)
-{
- chat_server_context_t *chat_context = (chat_server_context_t *)ai_service_get_user_data((ai_service_context_t *)context);
- if (!chat_context || !data || length == 0) {
- return;
- }
-
- // 解析聊天响应
- chat_response_t response = {0};
- ai_service_error_t ret = chat_server_parse_response(chat_context, data, &response);
- if (ret == AI_SERVICE_OK) {
- // 更新统计信息
- chat_context->chat_stats.total_responses++;
- chat_context->chat_stats.total_tokens_received += response.token_count;
-
- // 更新平均响应时间
- if (chat_context->chat_stats.total_responses > 0) {
- chat_context->chat_stats.average_response_time_ms =
- (chat_context->chat_stats.average_response_time_ms * (chat_context->chat_stats.total_responses - 1) +
- response.response_time_ms) / chat_context->chat_stats.total_responses;
- }
-
- // 添加助手消息到会话历史
- if (chat_context->model_config.enable_history && response.content) {
- chat_server_add_message_to_conversation(chat_context, response.session_id,
- CHAT_ROLE_ASSISTANT, response.content);
- }
-
- // 调用用户回调
- if (response.is_streaming && chat_context->on_chat_streaming) {
- chat_context->on_chat_streaming(chat_context, response.session_id, response.content);
- } else if (chat_context->on_chat_response) {
- chat_context->on_chat_response(chat_context, &response);
- }
-
- // 如果是最终响应,调用完成回调
- if (response.is_final && chat_context->on_chat_complete) {
- chat_context->on_chat_complete(chat_context, response.session_id);
- }
-
- // 转发给TTS服务
- if (chat_context->tts_send_text && response.content && response.is_final) {
- ai_service_error_t tts_ret = chat_context->tts_send_text(response.content, response.session_id);
- if (tts_ret != AI_SERVICE_OK) {
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[%s] Failed to send to TTS: %d", CHAT_LOG_TAG, tts_ret);
- }
- }
-
- // 释放响应内存
- chat_server_free_response(&response);
- }
-
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "[%s] Received message: %.*s",
- CHAT_LOG_TAG, (int)length, data);
-}
-
-static void chat_server_on_error(void *context, int error_code, const char *error_msg)
-{
- chat_server_context_t *chat_context = (chat_server_context_t *)ai_service_get_user_data((ai_service_context_t *)context);
- if (!chat_context) {
- return;
- }
-
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Chat server error: %d - %s",
- CHAT_LOG_TAG, error_code, error_msg ? error_msg : "Unknown");
-}
-
-static ai_service_error_t chat_server_parse_response(chat_server_context_t *context,
- const char *json_data,
- chat_response_t *response)
-{
- if (!context || !json_data || !response) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- cJSON *json = cJSON_Parse(json_data);
- if (!json) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to parse JSON", CHAT_LOG_TAG);
- return AI_SERVICE_ERROR_INTERNAL;
- }
-
- // 解析内容
- cJSON *content_item = cJSON_GetObjectItem(json, "content");
- if (content_item && cJSON_IsString(content_item)) {
- const char *content = cJSON_GetStringValue(content_item);
- if (content) {
- response->content = strdup(content);
- response->content_length = strlen(content);
- }
- }
-
- // 解析会话ID
- cJSON *session_id_item = cJSON_GetObjectItem(json, "session_id");
- if (session_id_item && cJSON_IsString(session_id_item)) {
- const char *session_id = cJSON_GetStringValue(session_id_item);
- if (session_id) {
- strncpy(response->session_id, session_id, sizeof(response->session_id) - 1);
- }
- }
-
- // 解析消息ID
- cJSON *message_id_item = cJSON_GetObjectItem(json, "message_id");
- if (message_id_item && cJSON_IsString(message_id_item)) {
- const char *message_id = cJSON_GetStringValue(message_id_item);
- if (message_id) {
- strncpy(response->message_id, message_id, sizeof(response->message_id) - 1);
- }
- }
-
- // 解析是否为最终结果
- cJSON *is_final_item = cJSON_GetObjectItem(json, "is_final");
- if (is_final_item && cJSON_IsBool(is_final_item)) {
- response->is_final = cJSON_IsTrue(is_final_item);
- }
-
- // 解析是否为流式响应
- cJSON *is_streaming_item = cJSON_GetObjectItem(json, "is_streaming");
- if (is_streaming_item && cJSON_IsBool(is_streaming_item)) {
- response->is_streaming = cJSON_IsTrue(is_streaming_item);
- }
-
- // 解析token数量
- cJSON *token_count_item = cJSON_GetObjectItem(json, "token_count");
- if (token_count_item && cJSON_IsNumber(token_count_item)) {
- response->token_count = (uint32_t)cJSON_GetNumberValue(token_count_item);
- }
-
- // 解析置信度
- cJSON *confidence_item = cJSON_GetObjectItem(json, "confidence");
- if (confidence_item && cJSON_IsNumber(confidence_item)) {
- response->confidence = (float)cJSON_GetNumberValue(confidence_item);
- }
-
- // 解析响应时间
- cJSON *response_time_item = cJSON_GetObjectItem(json, "response_time_ms");
- if (response_time_item && cJSON_IsNumber(response_time_item)) {
- response->response_time_ms = (uint32_t)cJSON_GetNumberValue(response_time_item);
- }
-
- cJSON_Delete(json);
-
- return AI_SERVICE_OK;
-}
-
-static ai_service_error_t chat_server_create_request_message(chat_server_context_t *context,
- const chat_request_t *request,
- char *output, size_t max_len)
-{
- if (!context || !request || !output || max_len == 0) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- cJSON *json = cJSON_CreateObject();
- if (!json) {
- return AI_SERVICE_ERROR_MEMORY_ALLOC;
- }
-
- cJSON_AddStringToObject(json, "type", "chat_request");
- cJSON_AddStringToObject(json, "session_id", request->session_id);
- cJSON_AddStringToObject(json, "message", request->message);
- cJSON_AddStringToObject(json, "message_type", chat_server_message_type_to_string(request->message_type));
- cJSON_AddStringToObject(json, "response_mode", chat_server_response_mode_to_string(request->response_mode));
-
- // 添加模型配置
- cJSON *model_config = cJSON_CreateObject();
- cJSON_AddStringToObject(model_config, "model_name", request->model_config.model_name);
- cJSON_AddStringToObject(model_config, "model_type", chat_server_model_type_to_string(request->model_config.model_type));
- cJSON_AddNumberToObject(model_config, "temperature", request->model_config.temperature);
- cJSON_AddNumberToObject(model_config, "top_p", request->model_config.top_p);
- cJSON_AddNumberToObject(model_config, "max_tokens", request->model_config.max_tokens);
- cJSON_AddBoolToObject(model_config, "enable_history", request->model_config.enable_history);
- cJSON_AddNumberToObject(model_config, "max_history_count", request->model_config.max_history_count);
- cJSON_AddItemToObject(json, "model_config", model_config);
-
- // 添加会话历史(如果启用)
- if (request->include_history) {
- chat_conversation_t *conversation = chat_server_find_conversation(context, request->session_id);
- if (conversation && conversation->message_count > 0) {
- cJSON *history = cJSON_CreateArray();
-
- size_t start_index = 0;
- if (conversation->message_count > request->model_config.max_history_count) {
- start_index = conversation->message_count - request->model_config.max_history_count;
- }
-
- for (size_t i = start_index; i < conversation->message_count; i++) {
- cJSON *msg = cJSON_CreateObject();
- cJSON_AddStringToObject(msg, "role", chat_server_role_to_string(conversation->messages[i].role));
- cJSON_AddStringToObject(msg, "content", conversation->messages[i].content);
- cJSON_AddNumberToObject(msg, "timestamp", conversation->messages[i].timestamp);
- cJSON_AddItemToArray(history, msg);
- }
-
- cJSON_AddItemToObject(json, "history", history);
- }
- }
-
- char *json_string = cJSON_Print(json);
- if (!json_string) {
- cJSON_Delete(json);
- return AI_SERVICE_ERROR_MEMORY_ALLOC;
- }
-
- if (strlen(json_string) >= max_len) {
- free(json_string);
- cJSON_Delete(json);
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- strcpy(output, json_string);
-
- free(json_string);
- cJSON_Delete(json);
-
- return AI_SERVICE_OK;
-}
-
-static chat_conversation_t* chat_server_find_conversation(chat_server_context_t *context,
- const char *session_id)
-{
- if (!context || !session_id) {
- return NULL;
- }
-
- osMutexAcquire(context->conversation_mutex, osWaitForever);
-
- for (size_t i = 0; i < context->max_conversations; i++) {
- if (strlen(context->conversations[i].session_id) > 0 &&
- strcmp(context->conversations[i].session_id, session_id) == 0) {
- osMutexRelease(context->conversation_mutex);
- return &context->conversations[i];
- }
- }
-
- osMutexRelease(context->conversation_mutex);
- return NULL;
-}
-
-static chat_conversation_t* chat_server_create_conversation(chat_server_context_t *context,
- const char *session_id)
-{
- if (!context || !session_id) {
- return NULL;
- }
-
- osMutexAcquire(context->conversation_mutex, osWaitForever);
-
- // 查找空闲的会话槽
- for (size_t i = 0; i < context->max_conversations; i++) {
- if (strlen(context->conversations[i].session_id) == 0) {
- strncpy(context->conversations[i].session_id, session_id,
- sizeof(context->conversations[i].session_id) - 1);
- context->conversations[i].created_time = ai_service_get_timestamp();
- context->conversations[i].last_update_time = context->conversations[i].created_time;
- context->conversation_count++;
- context->chat_stats.conversation_count++;
-
- osMutexRelease(context->conversation_mutex);
- return &context->conversations[i];
- }
- }
-
- osMutexRelease(context->conversation_mutex);
-
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[%s] No free conversation slots", CHAT_LOG_TAG);
- return NULL;
-}
-
-static ai_service_error_t chat_server_add_message_to_conversation(chat_server_context_t *context,
- const char *session_id,
- chat_role_t role,
- const char *content)
-{
- if (!context || !session_id || !content) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- chat_conversation_t *conversation = chat_server_find_conversation(context, session_id);
- if (!conversation) {
- conversation = chat_server_create_conversation(context, session_id);
- if (!conversation) {
- return AI_SERVICE_ERROR_INTERNAL;
- }
- }
-
- return chat_conversation_add_message(conversation, role, content, CHAT_MESSAGE_TYPE_TEXT);
-}
-
-
-
-/****************************************************************************************************** */
-
-
-
-// {"type":"middle","content":"我是","task_id":"","reasoning_content":""}
-// char content_str_chat[64]={0};
-/*
-
-chart result
-
-{"type":"start","content":null,"task_id":"","reasoning_content":""}
-{"type":"middle","content":"请","task_id":"","reasoning_content":""}
-{"type":"middle","content":"你","task_id":"","reasoning_content":""}
-{"type":"middle","content":"明确","task_id":"","reasoning_content":""}
-{"type":"middle","content":"一下","task_id":"","reasoning_content":""}
-{"type":"middle","content":"问题","task_id":"","reasoning_content":""}
-{"type":"end","content":null,"task_id":"","reasoning_content":""}
-
-*/
-bool chat_api_result_analysis(char *buf)
-{
- cJSON* root = cJSON_Parse((const char *)buf);
- if (root == NULL) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"解析失败\n");
- return false;
- }
- char *type_str=NULL;
- char *content_str=NULL;
-
- cJSON* type = cJSON_GetObjectItem(root, "type");
- if (type && cJSON_IsString(type)) {
-
- type_str= type->valuestring;
- }
- cJSON* content = cJSON_GetObjectItem(root, "content");
- if (content && cJSON_IsString(content)) {
- content_str = content->valuestring;
- }
- if(strcmp("middle",type_str)==0)
- {
- if(strlen(content_str)>0)
- {
- // memset_s(content_str_chat,64,0,64);
- // memcpy_s(content_str_chat,64,content_str,strlen(content_str));
-
-
- 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);
-
-
- // uapi_start_tts_single_txt(content_str_chat);
- // static uint8_t test=1;
- // if(test)
- // {
- // uapi_start_tts_single();
- // test=0;
-
- // }
- free(content_str_chat);
- }
- }
- if(strcmp("end",type_str)==0)
- {
- char end_str_chat[128]={0};
-
- if(strlen(content_str)>0)
- {
- memset_s(end_str_chat,128,0,128);
- memcpy_s(end_str_chat,128,end_str_chat,strlen(end_str_chat));
- ble_set_ai_Answer_str(end_str_chat,2);
- }
-
- }
-
-
- cJSON_Delete(root);
- return true;
-}
-// &device_id=222&product_id=222
-bool chat_api_ws_url_init(char * put_buf,uint8_t type)
-{
- char token[64]={0};
- if(read_dev_token(token))
- {
- if(type_ai==AI_TYPE_JIU)
- {
- sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=chinamobiledevice&bot_type=jiutian-lan",token);
- }
- else if(type_ai==AI_TYPE_DOU)
- {
- sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=huoshan",token);
- }
- else if(type_ai==AI_TYPE_WEN)
- {
- sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=baidu",token);
- }
- else if(type_ai==AI_TYPE_KIMI)
- {
- sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=moonshot",token);
- }
- else if(type_ai==AI_TYPE_DE)
- {
- sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=huoshan&model=ep-20250205103849-582m7",token);
- }
- else
- {
- sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=aliyun",token);
- }
- return true;
-
- }
- else
- {
- char * Service_url="118.145.158.207:22080";
-
- char device_id[128]={0};
- get_dev_id(device_id);
-
- char * product_id="1927646275585744898";
-
- if(type_ai==AI_TYPE_JIU)
- {
- sprintf(put_buf,"ws://%s/chat/ws?device_id=%s&product_id=%s&platform=chinamobiledevice&bot_type=jiutian-lan",Service_url,device_id,product_id);
- }
- else if(type_ai==AI_TYPE_DOU)
- {
- sprintf(put_buf,"ws://%s/chat/ws?platform=huoshan",Service_url);
- }
- else if(type_ai==AI_TYPE_WEN)
- {
- sprintf(put_buf,"ws://%s/chat/ws?platform=baidu",Service_url);
- }
- else if(type_ai==AI_TYPE_KIMI)
- {
- sprintf(put_buf,"ws://%s/chat/ws?platform=moonshot",Service_url);
- }
- else if(type_ai==AI_TYPE_DE)
- {
- sprintf(put_buf,"ws://%s/chat/ws?platform=huoshan&model=ep-20250205103849-582m7",Service_url);
- }
- else
- {
- sprintf(put_buf,"ws://%s/chat/ws?platform=aliyun",Service_url);
- }
- return false;
- }
-
-
-}
-
-bool chat_api_send_ai_txt(uint8_t type, char *msg)
-{
- cJSON *dataJSON = cJSON_CreateObject();
-
- if (dataJSON == NULL)
- {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error creating JSON object\n");
- return false;
- }
-
- cJSON_AddStringToObject(dataJSON, "type", "jiutian-lan");
-
- cJSON_AddStringToObject(dataJSON, "content", msg);
-
- char *jsonString = cJSON_PrintUnformatted(dataJSON);
-
- if (jsonString == NULL)
- {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error printing JSON to string\n");
- cJSON_Delete(dataJSON);
- return false;
- }
-
- uint32_t data_len = strlen(jsonString);
- cJSON_Delete(dataJSON);
-
- if (data_len == 0)
- {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error: JSON string length is 0\n");
- cJSON_free(jsonString);
- return false;
- }
-
- if (send_websocket_message(chat_client, (uint8_t *)jsonString, strlen(jsonString), WS_TEXT) == 0)
- {
- chat_reconnect = 0;
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "send_websocket_message succ 0\n");
- cJSON_free(jsonString);
- return true;
- }
-
- else
- {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "send_websocket_message fail\n");
- if (chat_client == NULL)
- {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "chat_client is NULL\n");
- }
- cJSON_free(jsonString);
- return false;
- }
-}
-
-#ifdef __cplusplus
-}
-#endif
\ No newline at end of file
--- /dev/null
+/*
+ * Chat 大模型服务实现
+ * 负责建立与Chat大模型服务器的WebSocket连接管理,上传文本,接收回复并转发给TTS
+ */
+
+/****************************************************************************************************** */
+
+
+
+// {"type":"middle","content":"我是","task_id":"","reasoning_content":""}
+// char content_str_chat[64]={0};
+/*
+
+chart result
+
+{"type":"start","content":null,"task_id":"","reasoning_content":""}
+{"type":"middle","content":"请","task_id":"","reasoning_content":""}
+{"type":"middle","content":"你","task_id":"","reasoning_content":""}
+{"type":"middle","content":"明确","task_id":"","reasoning_content":""}
+{"type":"middle","content":"一下","task_id":"","reasoning_content":""}
+{"type":"middle","content":"问题","task_id":"","reasoning_content":""}
+{"type":"end","content":null,"task_id":"","reasoning_content":""}
+
+*/
+bool chat_api_result_analysis(char *buf)
+{
+ cJSON* root = cJSON_Parse((const char *)buf);
+ if (root == NULL) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"解析失败\n");
+ return false;
+ }
+ char *type_str=NULL;
+ char *content_str=NULL;
+
+ cJSON* type = cJSON_GetObjectItem(root, "type");
+ if (type && cJSON_IsString(type)) {
+
+ type_str= type->valuestring;
+ }
+ cJSON* content = cJSON_GetObjectItem(root, "content");
+ if (content && cJSON_IsString(content)) {
+ content_str = content->valuestring;
+ }
+ if(strcmp("middle",type_str)==0)
+ {
+ if(strlen(content_str)>0)
+ {
+ // memset_s(content_str_chat,64,0,64);
+ // memcpy_s(content_str_chat,64,content_str,strlen(content_str));
+
+
+ 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);
+
+
+ // uapi_start_tts_single_txt(content_str_chat);
+ // static uint8_t test=1;
+ // if(test)
+ // {
+ // uapi_start_tts_single();
+ // test=0;
+
+ // }
+ free(content_str_chat);
+ }
+ }
+ if(strcmp("end",type_str)==0)
+ {
+ char end_str_chat[128]={0};
+
+ if(strlen(content_str)>0)
+ {
+ memset_s(end_str_chat,128,0,128);
+ memcpy_s(end_str_chat,128,end_str_chat,strlen(end_str_chat));
+ ble_set_ai_Answer_str(end_str_chat,2);
+ }
+
+ }
+
+
+ cJSON_Delete(root);
+ return true;
+}
+// &device_id=222&product_id=222
+bool chat_api_ws_url_init(char * put_buf,uint8_t type)
+{
+ char token[64]={0};
+ if(read_dev_token(token))
+ {
+ if(type_ai==AI_TYPE_JIU)
+ {
+ sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=chinamobiledevice&bot_type=jiutian-lan",token);
+ }
+ else if(type_ai==AI_TYPE_DOU)
+ {
+ sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=huoshan",token);
+ }
+ else if(type_ai==AI_TYPE_WEN)
+ {
+ sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=baidu",token);
+ }
+ else if(type_ai==AI_TYPE_KIMI)
+ {
+ sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=moonshot",token);
+ }
+ else if(type_ai==AI_TYPE_DE)
+ {
+ sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=huoshan&model=ep-20250205103849-582m7",token);
+ }
+ else
+ {
+ sprintf(put_buf,"ws://amp.raisound.com/chat/ws?dt=%s&platform=aliyun",token);
+ }
+ return true;
+
+ }
+ else
+ {
+ char * Service_url="118.145.158.207:22080";
+
+ char device_id[128]={0};
+ get_dev_id(device_id);
+
+ char * product_id="1927646275585744898";
+
+ if(type_ai==AI_TYPE_JIU)
+ {
+ sprintf(put_buf,"ws://%s/chat/ws?device_id=%s&product_id=%s&platform=chinamobiledevice&bot_type=jiutian-lan",Service_url,device_id,product_id);
+ }
+ else if(type_ai==AI_TYPE_DOU)
+ {
+ sprintf(put_buf,"ws://%s/chat/ws?platform=huoshan",Service_url);
+ }
+ else if(type_ai==AI_TYPE_WEN)
+ {
+ sprintf(put_buf,"ws://%s/chat/ws?platform=baidu",Service_url);
+ }
+ else if(type_ai==AI_TYPE_KIMI)
+ {
+ sprintf(put_buf,"ws://%s/chat/ws?platform=moonshot",Service_url);
+ }
+ else if(type_ai==AI_TYPE_DE)
+ {
+ sprintf(put_buf,"ws://%s/chat/ws?platform=huoshan&model=ep-20250205103849-582m7",Service_url);
+ }
+ else
+ {
+ sprintf(put_buf,"ws://%s/chat/ws?platform=aliyun",Service_url);
+ }
+ return false;
+ }
+
+
+}
+
+bool chat_api_send_ai_txt(uint8_t type, char *msg)
+{
+ cJSON *dataJSON = cJSON_CreateObject();
+
+ if (dataJSON == NULL)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error creating JSON object\n");
+ return false;
+ }
+
+ cJSON_AddStringToObject(dataJSON, "type", "jiutian-lan");
+
+ cJSON_AddStringToObject(dataJSON, "content", msg);
+
+ char *jsonString = cJSON_PrintUnformatted(dataJSON);
+
+ if (jsonString == NULL)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error printing JSON to string\n");
+ cJSON_Delete(dataJSON);
+ return false;
+ }
+
+ uint32_t data_len = strlen(jsonString);
+ cJSON_Delete(dataJSON);
+
+ if (data_len == 0)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error: JSON string length is 0\n");
+ cJSON_free(jsonString);
+ return false;
+ }
+
+ if (send_websocket_message(chat_client, (uint8_t *)jsonString, strlen(jsonString), WS_TEXT) == 0)
+ {
+ chat_reconnect = 0;
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "send_websocket_message succ 0\n");
+ cJSON_free(jsonString);
+ return true;
+ }
+
+ else
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "send_websocket_message fail\n");
+ if (chat_client == NULL)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "chat_client is NULL\n");
+ }
+ cJSON_free(jsonString);
+ return false;
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
\ No newline at end of file
-//设备鉴权\r
-\r
-#define AIC_THIS_FILE 0x888899\r
-// #include <aic_errno.h>\r
-// #include <aic_init.h>\r
-// #include <aic_osa_ex.h>\r
-// // #include <aos_thread.h>\r
-// #include "app_msg.h"\r
-// #include "aic_net_pdp_mgr.h"\r
-// #include "aic_network_pcap.h"\r
-\r
-#include "cJSON.h"\r
-// #include <serial_inc.h>\r
-// #include "aic_osa.h"\r
-// #include "AI_AMP_2_5.h"\r
-#include "mbedtls/base64.h"\r
-#include "mbedtls/md5.h"\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include "mbedtls/aes.h"\r
-#include "mbedtls/cipher.h"\r
-#include "dev_authentication.h"\r
-#include "bts_br_gap.h"\r
-#include "custom_utils.h"\r
-#include "wearable_log.h"\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif /* __cplusplus */\r
-\r
-void ase_encrypt_demo(void);\r
-\r
-// #include "aic_http_comm.h"\r
-\r
-// #define malloc malloc\r
-// #define free free\r
-// static char * dev_key = "uKLrChwrxA1LklgBc3VwawYjUkbT3BgX" ;\r
-// static char * dev_pid = "cqxJZi5CNgzjS3mX21Zw";\r
-int get_dev_pass_MAX_len(void)//获取设备密码最大长度,注意要防止内存越界\r
-{\r
- // return sizeof(vc_cfg.dev_pass);\r
-}\r
-void save_dev_pass(char *dev_pass)//保存设备密码,dev_pass字符串\r
-{\r
- // memset(vc_cfg.dev_pass,0,sizeof(vc_cfg.dev_pass));\r
- // strncpy(vc_cfg.dev_pass,dev_pass,get_dev_pass_MAX_len());\r
- // save_VC_cfg();\r
-}\r
-char *get_dev_pass(void)//获取设备密码,字符串的方式,返回字符串长度为0,即没密码\r
-{\r
-\r
- // return vc_cfg.dev_pass;\r
-}\r
-\r
-static char aut_token[50] ={0};\r
-int str_count(char *data,char type)\r
-{\r
- int ret = 0;\r
- //int count = 0;\r
- while(1)\r
- {\r
- if(data[ret] == type)\r
- break;\r
- ret++;\r
- if(ret>65532)\r
- return 0;\r
- }\r
- return ret;\r
-}\r
-void ase_encrypt_dome(void);\r
-//激活用的md5签名\r
-int active_md5_sign(const char *dev_id,const char *pid,const char *timestamp,const char *productSecret,char*md5_str)\r
-{\r
- if(strlen(dev_id)>256)\r
- return -1;\r
- if(strlen(pid)>256)\r
- return -2; \r
- if(strlen(productSecret)>256)\r
- return -3;\r
- if(strlen(timestamp)>256)\r
- return -4;\r
- char md5_buf[16]={0};\r
- char *sign_buf = (char *)malloc(1024);\r
- \r
- if(!sign_buf)\r
- return -10;\r
- memset(sign_buf,0,1024);\r
- int sign_len = 0;\r
- strcpy(sign_buf,dev_id);\r
- sign_len = strlen(sign_buf);\r
-\r
- strcpy(sign_buf+sign_len,pid);\r
- sign_len = strlen(sign_buf);\r
-\r
- strcpy(sign_buf+sign_len,timestamp);\r
- sign_len = strlen(sign_buf);\r
-\r
- strcpy(sign_buf+sign_len,productSecret);\r
- sign_len = strlen(sign_buf);\r
- printf("sign_buf:%s\r\n",sign_buf);\r
- \r
-\r
- mbedtls_md5_context ctx;\r
-\r
- // 初始化MD5上下文\r
- mbedtls_md5_init(&ctx);\r
-\r
- // 开始计算MD5哈希\r
- mbedtls_md5_starts(&ctx);\r
- // 更新要计算哈希的数据\r
- mbedtls_md5_update(&ctx, (const unsigned char *)sign_buf, sign_len);\r
-\r
- // 完成哈希计算\r
- mbedtls_md5_finish(&ctx, (unsigned char *)md5_buf);\r
-\r
- // printf("md5_buf\r\n");\r
- // for (int i = 0; i < 16; i++) {\r
- // printf("%02X\n", (uint8_t)md5_buf[i]);\r
- // }\r
- // printf("md5_buf end\r\n");\r
-\r
- // 清理MD5上下文\r
- mbedtls_md5_free(&ctx);\r
- for (int i = 0; i < 16; i++) {\r
- sprintf(&md5_str[i * 2], "%02x", (uint8_t)md5_buf[i]);\r
- }\r
- md5_str[32] = '\0';\r
- \r
- free(sign_buf);\r
- return 0;\r
-}\r
-\r
-void active_md5_sign_demo(void)\r
-{\r
- const char *dev_id ="1234567890";//imei号\r
- const char *timestamp = "1717752535000";//时间戳\r
- const char *pid = "Amg1HJ3dJkX3kLiLPNFg";//PID\r
- const char *productSecret = "productSecret";//密钥\r
- char md5_buf[33]={0};\r
- active_md5_sign(dev_id,pid,timestamp,productSecret,md5_buf);\r
- printf("md5_buf:%s",md5_buf);\r
- ase_encrypt_demo();\r
-}\r
-#define AES_BLOCK_SIZE 16\r
-// PKCS5填充\r
-void pkcs5_padding(unsigned char *data, size_t data_len, size_t block_size) {\r
- size_t padding_len = block_size - (data_len % block_size);\r
- for (size_t i = 0; i < padding_len; i++) {\r
- data[data_len + i] = (unsigned char)padding_len;\r
- }\r
-}\r
-// 移除PKCS5填充\r
-size_t pkcs5_unpadding(unsigned char *data, size_t data_len,size_t block_size) {\r
- size_t padding_len = data[data_len - 1];\r
- if (padding_len > 0 && padding_len <= block_size) {\r
- for (size_t i = 0; i < padding_len; i++) {\r
- if (data[data_len - 1 - i] != (unsigned char)padding_len) {\r
- return data_len;\r
- }\r
- }\r
- return data_len - padding_len;\r
- }\r
- return data_len;\r
-}\r
-\r
-//登录用的aes256加密\r
-int aes_cbc_pkcs5_encrypt(const char *input,int input_len,const char* str_key,const char* str_iv,char *Base64_output,int *Base64_output_len)\r
-{\r
-\r
- mbedtls_cipher_context_t ctx;\r
- int ret;\r
- unsigned char *aes_data =NULL;\r
- unsigned char *padded_plaintext=NULL;\r
- uint32_t aes_data_len = 0;\r
- uint32_t padded_len;\r
- // 初始化上下文\r
- mbedtls_cipher_init(&ctx);\r
-\r
- // 设置加密算法\r
- ret = mbedtls_cipher_setup(&ctx, mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_CBC));\r
- if (ret != 0) {\r
- printf("mbedtls_cipher_setup failed: -0x%04x\n", -ret);\r
- goto exit;\r
- }\r
-\r
- // 设置密钥和IV\r
- ret = mbedtls_cipher_setkey(&ctx, ( const unsigned char *)str_key, strlen(str_key) * 8, MBEDTLS_ENCRYPT);\r
- if (ret != 0) {\r
- printf("mbedtls_cipher_setkey failed: -0x%04x\n", -ret);\r
- goto exit;\r
- }\r
-\r
- ret = mbedtls_cipher_set_iv(&ctx, ( const unsigned char *)str_iv, strlen(str_iv));\r
- if (ret != 0) {\r
- printf("mbedtls_cipher_set_iv failed: -0x%04x\n", -ret);\r
- goto exit;\r
- }\r
- //printf("aes_cbc_pkcs5_encrypt2");\r
- // 计算填充后的长度\r
- padded_len = input_len;\r
- if (padded_len % AES_BLOCK_SIZE != 0) {\r
- padded_len += AES_BLOCK_SIZE - (padded_len % AES_BLOCK_SIZE);\r
- }else\r
- padded_len+=AES_BLOCK_SIZE;\r
- //printf("aes_cbc_pkcs5_encrypt3");\r
- // 复制明文并进行填充\r
- padded_plaintext = (unsigned char *)malloc(padded_len);\r
- if (padded_plaintext == NULL) {\r
- ret = MBEDTLS_ERR_CIPHER_ALLOC_FAILED;\r
- printf("Memory allocation failed\n");\r
- goto exit;\r
- }\r
- //printf("aes_cbc_pkcs5_encrypt4 padded_len :%d,input_len:%d",padded_len,input_len);\r
- aes_data = (unsigned char *)malloc(padded_len);\r
- if (aes_data == NULL) {\r
- ret = MBEDTLS_ERR_CIPHER_ALLOC_FAILED;\r
- printf("Memory allocation failed\n");\r
- goto exit;\r
- }\r
- //printf("aes_cbc_pkcs5_encrypt5");\r
- memcpy(padded_plaintext, input, input_len);\r
- pkcs5_padding(padded_plaintext, input_len, AES_BLOCK_SIZE);\r
- printf("aes_cbc_pkcs5_encrypt6");\r
- // 加密\r
- ret = mbedtls_cipher_update(&ctx, padded_plaintext, padded_len, aes_data, &aes_data_len);\r
- if (ret != 0) {\r
- printf("mbedtls_cipher_update failed: -0x%04x\n", -ret);\r
- \r
- goto exit;\r
- }\r
- printf("aes_cbc_pkcs5_encrypt7");\r
- mbedtls_base64_encode((unsigned char *)Base64_output, *Base64_output_len,(size_t *) Base64_output_len, aes_data, aes_data_len);\r
- Base64_output[*Base64_output_len] = 0;\r
- printf("aes_cbc_pkcs5_encrypt8.");\r
- free(padded_plaintext);\r
- printf("aes_cbc_pkcs5_encrypt9");\r
- free(aes_data);\r
- \r
- // 清理上下文\r
- mbedtls_cipher_free(&ctx);\r
- return 0;\r
-\r
-exit:\r
- mbedtls_cipher_free(&ctx);\r
- if(aes_data)\r
- free(aes_data);\r
- if(padded_plaintext)\r
- free(padded_plaintext);\r
- return ret;\r
-}\r
-\r
-// AES/CBC/PKCS5Padding解密\r
-int aes_cbc_pkcs5_decrypt(const char *Base64_str_input,const char* str_key,const char* str_iv,char *output,int *output_len)\r
- // const unsigned char *key, size_t key_len,\r
- // const unsigned char *iv, size_t iv_len,\r
- // const unsigned char *ciphertext, size_t ciphertext_len,\r
- // unsigned char *plaintext, size_t *plaintext_len) \r
-{\r
- mbedtls_aes_context ctx = {0};\r
- int ret;\r
- char *input_buf = NULL;\r
- size_t input_buf_len;\r
- char vi_tmp[16];\r
- // 初始化上下文\r
- mbedtls_aes_init(&ctx);\r
- //printf("aes_cbc_pkcs5_decrypt str_key:%s,str_iv:%s!!!!!!!!!!!!!!!!!!!!!!!!", str_key,str_iv);\r
- // // 设置加密算法\r
- // ret = mbedtls_cipher_setup(&ctx, mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_CBC));\r
- // if (ret != 0) {\r
- // printf("mbedtls_cipher_setup failed: -0x%04x\n", -ret);\r
- // goto exit;\r
- // }\r
- \r
- // 设置密钥和IV\r
- ret = mbedtls_aes_setkey_dec(&ctx, (const unsigned char*)str_key, strlen(str_key) * 8);\r
- if (ret != 0) {\r
- printf("mbedtls_cipher_setkey failed: -0x%04x\n", -ret);\r
- goto exit;\r
- }\r
-\r
- // ret = mbedtls_cipher_set_iv(&ctx, str_iv, strlen(str_iv));\r
- // if (ret != 0) {\r
- // printf("mbedtls_cipher_set_iv failed: -0x%04x\n", -ret);\r
- // goto exit;\r
- // }\r
- input_buf_len = strlen(Base64_str_input)+1;\r
- input_buf = (char *)malloc(input_buf_len);\r
- memset(input_buf,0,input_buf_len);\r
- //printf("mbedtls_base64_decode1:input_buf_len:%d,Base64_str_input:%s",input_buf_len,Base64_str_input);\r
- mbedtls_base64_decode((unsigned char *)input_buf, input_buf_len, &input_buf_len,( const unsigned char *) Base64_str_input, strlen(Base64_str_input));\r
- //printf("mbedtls_base64_decode2:input_buf_len:%d,output_len:%d",input_buf_len,*output_len);\r
- // bk_print_hex(input_buf,input_buf_len);\r
- // 解密\r
-\r
- \r
- memcpy(vi_tmp,str_iv,16);\r
- ret = mbedtls_aes_crypt_cbc(&ctx,MBEDTLS_AES_DECRYPT,input_buf_len,(unsigned char *) vi_tmp,( const unsigned char *)input_buf,( unsigned char *)output);\r
- *output_len = input_buf_len;\r
-\r
- if (ret != 0) {\r
- printf("mbedtls_cipher_update failed: -0x%04x\n", -ret);\r
- goto exit;\r
- }\r
-\r
- // 清理上下文\r
- mbedtls_aes_free(&ctx);\r
- //printf("aes_cbc_pkcs5_decrypt output_len:%d output:%s",*output_len,output);\r
- // 移除填充\r
- *output_len = pkcs5_unpadding((unsigned char *)output, *output_len,AES_BLOCK_SIZE);\r
- output[*output_len] = 0;\r
- if(input_buf)\r
- free(input_buf);\r
- return 0;\r
-\r
- exit:\r
- if(input_buf)\r
- free(input_buf);\r
- mbedtls_cipher_free((mbedtls_cipher_context_t *)&ctx);\r
- return ret;\r
-}\r
-void ase_encrypt_demo(void)\r
-{\r
- const char *data = "123456789123456789001234567890";\r
- size_t Base64_data_len = strlen(data)*3+32;\r
- char *Base64_data =(char *) malloc(Base64_data_len);\r
- memset(Base64_data,0,Base64_data_len);\r
- aes_cbc_pkcs5_encrypt(data,strlen(data),"uKLrChwrxA1LklgBc3VwawYjUkbT3BgX","5555555566666666",Base64_data,(int *)&Base64_data_len);\r
- printf("ase_encrypt_dome:aes_cbc_pkcs5_encrypt:len:%d,Base64_data:%s",Base64_data_len,Base64_data);\r
- char *decrypt_data = (char *)malloc(Base64_data_len);\r
- aes_cbc_pkcs5_decrypt(Base64_data,"uKLrChwrxA1LklgBc3VwawYjUkbT3BgX","5555555566666666",decrypt_data,(int *)&Base64_data_len);\r
- printf("ase_encrypt_dome:aes_cbc_pkcs5_decrypt:len:%d,decrypt_data:%s",Base64_data_len,decrypt_data);\r
- if(Base64_data)\r
- free(Base64_data);\r
- if(decrypt_data)\r
- free(decrypt_data);\r
-}\r
-\r
-/****************************************************************************** */\r
-int set_token(char *token)\r
-{\r
- if(strlen(token)>=sizeof(aut_token))\r
- {\r
- printf("ERROR token to0 long");\r
- return -1;\r
- }\r
- memset(aut_token,0,sizeof(aut_token));\r
- strcpy(aut_token,token);\r
- return 0;\r
- \r
-}\r
-int get_token(char *token)\r
-{\r
- return 0;\r
- // return aut_token; \r
-}\r
-\r
-\r
-//激活\r
-\r
-\r
-// 设备激活\r
-\r
-\r
-//激活->登录的密钥\r
-const char * key = "4EepovakpbqhZUnUDwH42KAADYGv4UUe" ;\r
-//每小时更新登录一次的更新定时器\r
-// static aos_timer_ptr LOGIN_1H_timer = NULL;\r
-\r
-bool aut_active(void)//设备激活\r
-{\r
- int ret;\r
- printf("aut_active");\r
- // AIC_HTTPS_CLIENT_INSTANCE *http_client;\r
- char dev_pass_base64[100] ={0};\r
- char enc_iv[65] = {0};\r
- // http创建客户端句柄\r
-\r
- char *json_string =NULL;\r
- cJSON *root = NULL;\r
-\r
-\r
- unsigned char deviceId[6] = {0};\r
- unsigned int len = 6;\r
-\r
-\r
- memset(deviceId,0,6); \r
- bluetooth_get_local_addr(&deviceId[0],len);\r
-\r
- char deviceId_temp[20] = {0};\r
-\r
- sprintf(deviceId_temp,"%02X%02x%02X%02x%02X%02x",deviceId[5],deviceId[4],deviceId[3],deviceId[2],deviceId[1],deviceId[0]);\r
-\r
-\r
- time_t timestamp;\r
- timestamp = time(NULL);\r
- printf("2时间戳: %ld\n", (long)timestamp);\r
- long long timestamp_ms = (long long)timestamp * 1000;\r
-\r
- char* timestamp_str_2=(char *)malloc(20);\r
- memset(timestamp_str_2,0,20);\r
-\r
- // 使用 sprintf 将 long long 类型的时间戳转换为字符串\r
- ret = sprintf(timestamp_str_2, "%lld", timestamp_ms);\r
- // 打印转换后的字符串形式的时间戳\r
-\r
-\r
- const char *dev_pid = "Y1DxRdBfnzVZQrXHdrNl";//PID\r
- // const char *dev_key = "4EepovakpbqhZUnUDwH42KAADYGv4UUe";//密钥\r
-\r
- char md5_buf[33]={0};\r
- active_md5_sign((char *)deviceId_temp,dev_pid,timestamp_str_2,key,md5_buf);\r
- printf("md5_buf:%s",md5_buf);\r
-\r
-\r
- const char *signMethod ="MD5";\r
-\r
- uint32_t response = 0;\r
- //创建客户端实例\r
-\r
- \r
- // 创建JSON对象\r
- root = cJSON_CreateObject();\r
- if (root == NULL) {\r
- printf( "Failed to create JSON object\n");\r
- return false ;\r
- }\r
-\r
- // 添加字段\r
- cJSON_AddStringToObject(root, "deviceId", (char *)deviceId_temp);\r
- cJSON_AddStringToObject(root, "pid", dev_pid);\r
- cJSON_AddStringToObject(root, "sign", md5_buf);\r
-\r
- printf("时间戳(ms 转换为字符串): %s\n", timestamp_str_2);\r
-\r
- cJSON_AddStringToObject(root, "timeStamp", timestamp_str_2);\r
-\r
- free(timestamp_str_2);\r
-\r
- cJSON_AddStringToObject(root, "signMethod", signMethod);\r
-\r
- // 生成JSON字符串\r
- json_string = cJSON_Print(root);\r
- if (json_string == NULL) {\r
- printf("Failed to print JSON\n");\r
- cJSON_Delete(root);\r
- return false;\r
- }\r
-\r
- // 输出JSON\r
- printf("JSON output: %s\n", json_string);\r
- extern uint32_t put_data_by_get_file(char *data,uint16_t data_len);\r
- \r
- if(200==put_data_by_get_file(json_string,strlen(json_string)))\r
- {\r
- cJSON_free(json_string);\r
- return true; \r
- }\r
- else\r
- {\r
- cJSON_free(json_string);\r
- return false;\r
- }\r
-\r
- \r
-\r
- \r
-\r
-}\r
-\r
-\r
-\r
-extern bool read_dev_pass(char *data_pass);\r
-extern uint32_t post_data_by_get_file(char *data,uint16_t data_len);\r
-bool read_dev_token(char *data_token);\r
-\r
-uint32_t aut_login_time=0;\r
-\r
-bool aut_login(void)//登录\r
-{\r
- time_t timestamp;\r
- timestamp = time(NULL);\r
-\r
- if(timestamp - aut_login_time < 60 * 60 )\r
- {\r
- return true;\r
- }\r
-\r
- char dev_pass[64]={0}; \r
- if(read_dev_pass(dev_pass)==false)\r
- {\r
- // return ;\r
- if(aut_active())\r
- {\r
- printf( "aut_active fail\n");\r
- return false;\r
- }\r
- else\r
- {\r
- read_dev_pass(dev_pass);\r
- }\r
- }\r
- \r
-\r
-\r
- printf("dev_sign_in 2");\r
- int count = 5;\r
- char *encrypt_data = NULL;\r
- char *response_data =NULL;\r
- int aut_login_http_handle = 0;\r
- char enc_iv[17]={0};\r
- \r
- // 随机生成16个字符串 设备生成做加密使用\r
- //char *random_string= generate_random_string(); // 随机的16个字符串\r
- // 设备端进行密码加密\r
- /**\r
- * password, productSecret, nonce utJMIAPRN1E81DzSDVigh/f0ZmHQdBgdAGZ/DhkPJ/s= uKLrChwrxA1LklgBc3VwawYjUkbT3BgX qgofeplofqeoadha\r
- */\r
- int encrypt_data_len = 512;\r
- encrypt_data = (char *)malloc(encrypt_data_len);\r
- \r
-\r
- // 登录数据\r
- unsigned char deviceId[20] = {0};\r
- //aic_srv_tele_radio_get_current_slot_imei_sync(deviceId);\r
- memset(deviceId,0,6); \r
- bluetooth_get_local_addr(&deviceId[0],6);\r
-\r
- char deviceId_temp[20] = {0};\r
-\r
- sprintf(deviceId_temp,"%02X%02x%02X%02x%02X%02x",deviceId[5],deviceId[4],deviceId[3],deviceId[2],deviceId[1],deviceId[0]);\r
-\r
- \r
- printf("2时间戳: %ld\n", (long)timestamp);\r
- long long timestamp_ms = (long long)timestamp * 1000;\r
- char timestamp_str[20] ={0};\r
-\r
- // 使用 sprintf 将 long long 类型的时间戳转换为字符串\r
- sprintf(timestamp_str, "%lld", timestamp_ms);\r
- memset(enc_iv,'1',16);\r
- memcpy(enc_iv,timestamp_str,strlen(timestamp_str));\r
-\r
- enc_iv[16] = 0;\r
- aes_cbc_pkcs5_encrypt(dev_pass, strlen(dev_pass), key, enc_iv,encrypt_data,&encrypt_data_len);//加密\r
- \r
- cJSON *root = cJSON_CreateObject();\r
- if (root == NULL) \r
- {\r
- return false;\r
- }\r
- // 添加字段\r
- cJSON_AddStringToObject(root, "deviceId", deviceId_temp);\r
- cJSON_AddStringToObject(root, "password", encrypt_data);\r
- cJSON_AddStringToObject(root, "nonce", enc_iv);\r
- // 生成JSON字符串\r
- char *json_string = cJSON_Print(root);\r
- if (json_string == NULL) \r
- {\r
- printf( "Failed to print JSON\n");\r
- cJSON_Delete(root);\r
- return false;\r
- }\r
- printf("json_string:%s",json_string);\r
-\r
- int ret= post_data_by_get_file(json_string,strlen(json_string));\r
-\r
- \r
-\r
- if(ret==200 )\r
- {\r
- cJSON_free(json_string);\r
- aut_login_time=timestamp;\r
- if(read_dev_token(NULL))\r
- {\r
- return true;\r
- }\r
- else\r
- {\r
- aut_login_time=0;\r
- return false;\r
- }\r
- \r
- }\r
- else\r
- {\r
- cJSON_free(json_string);\r
- return false;\r
- }\r
-}\r
-\r
-\r
-bool read_dev_pass(char *data_pass)\r
-{\r
- char buf[512]={0};\r
-\r
- FILE *fp=fopen(AUTH_ACTIVE,"rb+");\r
- int read_size;\r
-\r
- uint32_t pack=512;\r
-\r
- if(fp==NULL)\r
- {\r
- return false;\r
- }\r
- \r
- memset_s(buf,512,0,512);\r
- read_size=fread(buf,1,512,fp);\r
- if(read_size!=0)\r
- {\r
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "buf %d %s",read_size,buf); \r
- }\r
- fclose(fp);\r
-\r
- char *p=buf;\r
- while (*p!='{' && *p !='\0')\r
- {\r
- p++;\r
- }\r
-\r
- cJSON* root = cJSON_Parse((const char *)p);\r
- if (root == NULL) {\r
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"解析失败\n");\r
- return false;\r
- }\r
- char *password_str=NULL;\r
- char * nonce_str=0;\r
-\r
- cJSON* data = cJSON_GetObjectItem(root, "data");\r
- if (data)\r
- {\r
- cJSON* password = cJSON_GetObjectItem(data, "password");\r
- if (password && cJSON_IsString(password)) {\r
- password_str= password->valuestring;\r
- }\r
-\r
- cJSON* nonce = cJSON_GetObjectItem(data, "nonce");\r
- if (nonce && cJSON_IsString(nonce)) {\r
- nonce_str = nonce->valuestring;\r
- }\r
- \r
- }\r
-\r
- int dev_pass_len =64;\r
- char *dev_pass =(char *)malloc(dev_pass_len);\r
- if(dev_pass)\r
- {\r
- memset(dev_pass,0,dev_pass_len);\r
- if(strlen(nonce_str)>8 && strlen(password_str)>8)\r
- {\r
- aes_cbc_pkcs5_decrypt(password_str, "4EepovakpbqhZUnUDwH42KAADYGv4UUe", nonce_str,dev_pass,&dev_pass_len);//解密\r
- dev_pass[dev_pass_len] = 0;\r
- printf("dev_pass:%s dev_pass_len:%d\n",dev_pass,dev_pass_len);\r
- }\r
- \r
- }else\r
- {\r
- printf("dev_pass malloc error!!!!!!!!!!!");\r
- }\r
-\r
- \r
-\r
- if(strlen(password_str)>=0)\r
- {\r
- memcpy(data_pass,dev_pass,dev_pass_len);\r
- free(dev_pass);\r
- cJSON_Delete(data);\r
- return true;\r
- }\r
- free(dev_pass);\r
- cJSON_Delete(data);\r
- return false;\r
-}\r
-\r
-// {"success":true,"msg":"登录成功","code":20001,"data":{"deviceId":"28110601009b","token":"95fc6dcdf5a3e9a48df535453efd097c19"}}\r
-\r
-bool read_dev_token(char *data_token)\r
-{\r
- time_t timestamp;\r
- timestamp = time(NULL);\r
-\r
- if(timestamp - aut_login_time > 60 * 60 )\r
- {\r
- return false;\r
- }\r
-\r
- char buf[512]={0};\r
-\r
- FILE *fp=fopen(AUTH_SIGN_IN,"rb+");\r
- int read_size;\r
-\r
- uint32_t pack=512;\r
-\r
- if(fp==NULL)\r
- {\r
- return false;\r
- }\r
- \r
- memset_s(buf,512,0,512);\r
- read_size=fread(buf,1,512,fp);\r
- if(read_size!=0)\r
- {\r
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "buf %d %s",read_size,buf); \r
- }\r
- fclose(fp);\r
-\r
- char *p=buf;\r
- while (*p!='{' && *p !='\0')\r
- {\r
- p++;\r
- }\r
-\r
- cJSON* root = cJSON_Parse((const char *)p);\r
- if (root == NULL) {\r
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"解析失败\n");\r
- return false;\r
- }\r
- char *token_str=NULL;\r
-\r
- cJSON* data = cJSON_GetObjectItem(root, "data");\r
- if (data)\r
- {\r
- cJSON* token = cJSON_GetObjectItem(data, "token");\r
- if (token && cJSON_IsString(token)) \r
- {\r
- token_str= token->valuestring;\r
- }\r
- else\r
- {\r
- cJSON_Delete(data);\r
- return false; \r
- }\r
- }\r
- else\r
- {\r
- cJSON_Delete(data);\r
- return false;\r
- }\r
- \r
-\r
- if(strlen(token_str)>=0 && data_token!=NULL )\r
- {\r
- memcpy(data_token,token_str,strlen(token_str));\r
- cJSON_Delete(data);\r
- return true;\r
- }\r
- cJSON_Delete(data);\r
- \r
- return true;\r
-}\r
-\r
-void read_file_put(void )\r
-{\r
- char buf[1024]={0};\r
-\r
- FILE *fp=fopen(AUTH_SIGN_IN,"rb+");\r
- int read_size;\r
-\r
- uint32_t pack=1024;\r
-\r
- if(fp==NULL)\r
- {\r
- return;\r
- }\r
- do\r
- {\r
- memset_s(buf,1024,0,1024);\r
- read_size=fread(buf,1,1024,fp);\r
-\r
- if(read_size!=0)\r
- {\r
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "buf %d %s",read_size,buf); \r
- }\r
- \r
- } while (read_size==1024);\r
- fclose(fp);\r
-\r
-}\r
-\r
-\r
-int active_md5_buf(char *in_buf,char*md5_str)\r
-{\r
-\r
- char md5_buf[16]={0};\r
- char *sign_buf = (char *)malloc(1024);\r
- \r
- if(!sign_buf)\r
- return -10;\r
- memset(sign_buf,0,1024);\r
-\r
- int sign_len = 0;\r
- strcpy(sign_buf,in_buf);\r
-\r
- sign_len = strlen(in_buf);\r
-\r
-\r
- mbedtls_md5_context ctx;\r
-\r
- // 初始化MD5上下文\r
- mbedtls_md5_init(&ctx);\r
-\r
- // 开始计算MD5哈希\r
- mbedtls_md5_starts(&ctx);\r
- // 更新要计算哈希的数据\r
- mbedtls_md5_update(&ctx, (const unsigned char *)sign_buf, sign_len);\r
-\r
- // 完成哈希计算\r
- mbedtls_md5_finish(&ctx, (unsigned char *)md5_buf);\r
-\r
- // printf("md5_buf\r\n");\r
- // for (int i = 0; i < 16; i++) {\r
- // printf("%02X\n", (uint8_t)md5_buf[i]);\r
- // }\r
- // printf("md5_buf end\r\n");\r
-\r
- // 清理MD5上下文\r
- mbedtls_md5_free(&ctx);\r
- for (int i = 0; i < 16; i++) {\r
- sprintf(&md5_str[i * 2], "%02x", (uint8_t)md5_buf[i]);\r
- }\r
- md5_str[32] = '\0';\r
- \r
- free(sign_buf);\r
- return 0;\r
-}\r
-\r
-\r
-#ifdef __cplusplus\r
-}\r
+//设备鉴权
+
+#define AIC_THIS_FILE 0x888899
+// #include <aic_errno.h>
+// #include <aic_init.h>
+// #include <aic_osa_ex.h>
+// // #include <aos_thread.h>
+// #include "app_msg.h"
+// #include "aic_net_pdp_mgr.h"
+// #include "aic_network_pcap.h"
+
+#include "cJSON.h"
+// #include <serial_inc.h>
+// #include "aic_osa.h"
+// #include "AI_AMP_2_5.h"
+#include "mbedtls/base64.h"
+#include "mbedtls/md5.h"
+#include <stdio.h>
+#include <string.h>
+#include "mbedtls/aes.h"
+#include "mbedtls/cipher.h"
+#include "dev_authentication.h"
+#include "bts_br_gap.h"
+#include "custom_utils.h"
+#include "wearable_log.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void ase_encrypt_demo(void);
+
+// #include "aic_http_comm.h"
+
+// #define malloc malloc
+// #define free free
+// static char * dev_key = "uKLrChwrxA1LklgBc3VwawYjUkbT3BgX" ;
+// static char * dev_pid = "cqxJZi5CNgzjS3mX21Zw";
+int get_dev_pass_MAX_len(void)//获取设备密码最大长度,注意要防止内存越界
+{
+ // return sizeof(vc_cfg.dev_pass);
+}
+void save_dev_pass(char *dev_pass)//保存设备密码,dev_pass字符串
+{
+ // memset(vc_cfg.dev_pass,0,sizeof(vc_cfg.dev_pass));
+ // strncpy(vc_cfg.dev_pass,dev_pass,get_dev_pass_MAX_len());
+ // save_VC_cfg();
+}
+char *get_dev_pass(void)//获取设备密码,字符串的方式,返回字符串长度为0,即没密码
+{
+
+ // return vc_cfg.dev_pass;
+}
+
+static char aut_token[50] ={0};
+int str_count(char *data,char type)
+{
+ int ret = 0;
+ //int count = 0;
+ while(1)
+ {
+ if(data[ret] == type)
+ break;
+ ret++;
+ if(ret>65532)
+ return 0;
+ }
+ return ret;
+}
+void ase_encrypt_dome(void);
+//激活用的md5签名
+int active_md5_sign(const char *dev_id,const char *pid,const char *timestamp,const char *productSecret,char*md5_str)
+{
+ if(strlen(dev_id)>256)
+ return -1;
+ if(strlen(pid)>256)
+ return -2;
+ if(strlen(productSecret)>256)
+ return -3;
+ if(strlen(timestamp)>256)
+ return -4;
+ char md5_buf[16]={0};
+ char *sign_buf = (char *)malloc(1024);
+
+ if(!sign_buf)
+ return -10;
+ memset(sign_buf,0,1024);
+ int sign_len = 0;
+ strcpy(sign_buf,dev_id);
+ sign_len = strlen(sign_buf);
+
+ strcpy(sign_buf+sign_len,pid);
+ sign_len = strlen(sign_buf);
+
+ strcpy(sign_buf+sign_len,timestamp);
+ sign_len = strlen(sign_buf);
+
+ strcpy(sign_buf+sign_len,productSecret);
+ sign_len = strlen(sign_buf);
+ printf("sign_buf:%s\r\n",sign_buf);
+
+
+ mbedtls_md5_context ctx;
+
+ // 初始化MD5上下文
+ mbedtls_md5_init(&ctx);
+
+ // 开始计算MD5哈希
+ mbedtls_md5_starts(&ctx);
+ // 更新要计算哈希的数据
+ mbedtls_md5_update(&ctx, (const unsigned char *)sign_buf, sign_len);
+
+ // 完成哈希计算
+ mbedtls_md5_finish(&ctx, (unsigned char *)md5_buf);
+
+ // printf("md5_buf\r\n");
+ // for (int i = 0; i < 16; i++) {
+ // printf("%02X\n", (uint8_t)md5_buf[i]);
+ // }
+ // printf("md5_buf end\r\n");
+
+ // 清理MD5上下文
+ mbedtls_md5_free(&ctx);
+ for (int i = 0; i < 16; i++) {
+ sprintf(&md5_str[i * 2], "%02x", (uint8_t)md5_buf[i]);
+ }
+ md5_str[32] = '\0';
+
+ free(sign_buf);
+ return 0;
+}
+
+void active_md5_sign_demo(void)
+{
+ const char *dev_id ="1234567890";//imei号
+ const char *timestamp = "1717752535000";//时间戳
+ const char *pid = "Amg1HJ3dJkX3kLiLPNFg";//PID
+ const char *productSecret = "productSecret";//密钥
+ char md5_buf[33]={0};
+ active_md5_sign(dev_id,pid,timestamp,productSecret,md5_buf);
+ printf("md5_buf:%s",md5_buf);
+ ase_encrypt_demo();
+}
+#define AES_BLOCK_SIZE 16
+// PKCS5填充
+void pkcs5_padding(unsigned char *data, size_t data_len, size_t block_size) {
+ size_t padding_len = block_size - (data_len % block_size);
+ for (size_t i = 0; i < padding_len; i++) {
+ data[data_len + i] = (unsigned char)padding_len;
+ }
+}
+// 移除PKCS5填充
+size_t pkcs5_unpadding(unsigned char *data, size_t data_len,size_t block_size) {
+ size_t padding_len = data[data_len - 1];
+ if (padding_len > 0 && padding_len <= block_size) {
+ for (size_t i = 0; i < padding_len; i++) {
+ if (data[data_len - 1 - i] != (unsigned char)padding_len) {
+ return data_len;
+ }
+ }
+ return data_len - padding_len;
+ }
+ return data_len;
+}
+
+//登录用的aes256加密
+int aes_cbc_pkcs5_encrypt(const char *input,int input_len,const char* str_key,const char* str_iv,char *Base64_output,int *Base64_output_len)
+{
+
+ mbedtls_cipher_context_t ctx;
+ int ret;
+ unsigned char *aes_data =NULL;
+ unsigned char *padded_plaintext=NULL;
+ uint32_t aes_data_len = 0;
+ uint32_t padded_len;
+ // 初始化上下文
+ mbedtls_cipher_init(&ctx);
+
+ // 设置加密算法
+ ret = mbedtls_cipher_setup(&ctx, mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_CBC));
+ if (ret != 0) {
+ printf("mbedtls_cipher_setup failed: -0x%04x\n", -ret);
+ goto exit;
+ }
+
+ // 设置密钥和IV
+ ret = mbedtls_cipher_setkey(&ctx, ( const unsigned char *)str_key, strlen(str_key) * 8, MBEDTLS_ENCRYPT);
+ if (ret != 0) {
+ printf("mbedtls_cipher_setkey failed: -0x%04x\n", -ret);
+ goto exit;
+ }
+
+ ret = mbedtls_cipher_set_iv(&ctx, ( const unsigned char *)str_iv, strlen(str_iv));
+ if (ret != 0) {
+ printf("mbedtls_cipher_set_iv failed: -0x%04x\n", -ret);
+ goto exit;
+ }
+ //printf("aes_cbc_pkcs5_encrypt2");
+ // 计算填充后的长度
+ padded_len = input_len;
+ if (padded_len % AES_BLOCK_SIZE != 0) {
+ padded_len += AES_BLOCK_SIZE - (padded_len % AES_BLOCK_SIZE);
+ }else
+ padded_len+=AES_BLOCK_SIZE;
+ //printf("aes_cbc_pkcs5_encrypt3");
+ // 复制明文并进行填充
+ padded_plaintext = (unsigned char *)malloc(padded_len);
+ if (padded_plaintext == NULL) {
+ ret = MBEDTLS_ERR_CIPHER_ALLOC_FAILED;
+ printf("Memory allocation failed\n");
+ goto exit;
+ }
+ //printf("aes_cbc_pkcs5_encrypt4 padded_len :%d,input_len:%d",padded_len,input_len);
+ aes_data = (unsigned char *)malloc(padded_len);
+ if (aes_data == NULL) {
+ ret = MBEDTLS_ERR_CIPHER_ALLOC_FAILED;
+ printf("Memory allocation failed\n");
+ goto exit;
+ }
+ //printf("aes_cbc_pkcs5_encrypt5");
+ memcpy(padded_plaintext, input, input_len);
+ pkcs5_padding(padded_plaintext, input_len, AES_BLOCK_SIZE);
+ printf("aes_cbc_pkcs5_encrypt6");
+ // 加密
+ ret = mbedtls_cipher_update(&ctx, padded_plaintext, padded_len, aes_data, &aes_data_len);
+ if (ret != 0) {
+ printf("mbedtls_cipher_update failed: -0x%04x\n", -ret);
+
+ goto exit;
+ }
+ printf("aes_cbc_pkcs5_encrypt7");
+ mbedtls_base64_encode((unsigned char *)Base64_output, *Base64_output_len,(size_t *) Base64_output_len, aes_data, aes_data_len);
+ Base64_output[*Base64_output_len] = 0;
+ printf("aes_cbc_pkcs5_encrypt8.");
+ free(padded_plaintext);
+ printf("aes_cbc_pkcs5_encrypt9");
+ free(aes_data);
+
+ // 清理上下文
+ mbedtls_cipher_free(&ctx);
+ return 0;
+
+exit:
+ mbedtls_cipher_free(&ctx);
+ if(aes_data)
+ free(aes_data);
+ if(padded_plaintext)
+ free(padded_plaintext);
+ return ret;
+}
+
+// AES/CBC/PKCS5Padding解密
+int aes_cbc_pkcs5_decrypt(const char *Base64_str_input,const char* str_key,const char* str_iv,char *output,int *output_len)
+ // const unsigned char *key, size_t key_len,
+ // const unsigned char *iv, size_t iv_len,
+ // const unsigned char *ciphertext, size_t ciphertext_len,
+ // unsigned char *plaintext, size_t *plaintext_len)
+{
+ mbedtls_aes_context ctx = {0};
+ int ret;
+ char *input_buf = NULL;
+ size_t input_buf_len;
+ char vi_tmp[16];
+ // 初始化上下文
+ mbedtls_aes_init(&ctx);
+ //printf("aes_cbc_pkcs5_decrypt str_key:%s,str_iv:%s!!!!!!!!!!!!!!!!!!!!!!!!", str_key,str_iv);
+ // // 设置加密算法
+ // ret = mbedtls_cipher_setup(&ctx, mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_CBC));
+ // if (ret != 0) {
+ // printf("mbedtls_cipher_setup failed: -0x%04x\n", -ret);
+ // goto exit;
+ // }
+
+ // 设置密钥和IV
+ ret = mbedtls_aes_setkey_dec(&ctx, (const unsigned char*)str_key, strlen(str_key) * 8);
+ if (ret != 0) {
+ printf("mbedtls_cipher_setkey failed: -0x%04x\n", -ret);
+ goto exit;
+ }
+
+ // ret = mbedtls_cipher_set_iv(&ctx, str_iv, strlen(str_iv));
+ // if (ret != 0) {
+ // printf("mbedtls_cipher_set_iv failed: -0x%04x\n", -ret);
+ // goto exit;
+ // }
+ input_buf_len = strlen(Base64_str_input)+1;
+ input_buf = (char *)malloc(input_buf_len);
+ memset(input_buf,0,input_buf_len);
+ //printf("mbedtls_base64_decode1:input_buf_len:%d,Base64_str_input:%s",input_buf_len,Base64_str_input);
+ mbedtls_base64_decode((unsigned char *)input_buf, input_buf_len, &input_buf_len,( const unsigned char *) Base64_str_input, strlen(Base64_str_input));
+ //printf("mbedtls_base64_decode2:input_buf_len:%d,output_len:%d",input_buf_len,*output_len);
+ // bk_print_hex(input_buf,input_buf_len);
+ // 解密
+
+
+ memcpy(vi_tmp,str_iv,16);
+ ret = mbedtls_aes_crypt_cbc(&ctx,MBEDTLS_AES_DECRYPT,input_buf_len,(unsigned char *) vi_tmp,( const unsigned char *)input_buf,( unsigned char *)output);
+ *output_len = input_buf_len;
+
+ if (ret != 0) {
+ printf("mbedtls_cipher_update failed: -0x%04x\n", -ret);
+ goto exit;
+ }
+
+ // 清理上下文
+ mbedtls_aes_free(&ctx);
+ //printf("aes_cbc_pkcs5_decrypt output_len:%d output:%s",*output_len,output);
+ // 移除填充
+ *output_len = pkcs5_unpadding((unsigned char *)output, *output_len,AES_BLOCK_SIZE);
+ output[*output_len] = 0;
+ if(input_buf)
+ free(input_buf);
+ return 0;
+
+ exit:
+ if(input_buf)
+ free(input_buf);
+ mbedtls_cipher_free((mbedtls_cipher_context_t *)&ctx);
+ return ret;
+}
+void ase_encrypt_demo(void)
+{
+ const char *data = "123456789123456789001234567890";
+ size_t Base64_data_len = strlen(data)*3+32;
+ char *Base64_data =(char *) malloc(Base64_data_len);
+ memset(Base64_data,0,Base64_data_len);
+ aes_cbc_pkcs5_encrypt(data,strlen(data),"uKLrChwrxA1LklgBc3VwawYjUkbT3BgX","5555555566666666",Base64_data,(int *)&Base64_data_len);
+ printf("ase_encrypt_dome:aes_cbc_pkcs5_encrypt:len:%d,Base64_data:%s",Base64_data_len,Base64_data);
+ char *decrypt_data = (char *)malloc(Base64_data_len);
+ aes_cbc_pkcs5_decrypt(Base64_data,"uKLrChwrxA1LklgBc3VwawYjUkbT3BgX","5555555566666666",decrypt_data,(int *)&Base64_data_len);
+ printf("ase_encrypt_dome:aes_cbc_pkcs5_decrypt:len:%d,decrypt_data:%s",Base64_data_len,decrypt_data);
+ if(Base64_data)
+ free(Base64_data);
+ if(decrypt_data)
+ free(decrypt_data);
+}
+
+/****************************************************************************** */
+int set_token(char *token)
+{
+ if(strlen(token)>=sizeof(aut_token))
+ {
+ printf("ERROR token to0 long");
+ return -1;
+ }
+ memset(aut_token,0,sizeof(aut_token));
+ strcpy(aut_token,token);
+ return 0;
+
+}
+int get_token(char *token)
+{
+ return 0;
+ // return aut_token;
+}
+
+
+//激活
+
+
+// 设备激活
+
+
+//激活->登录的密钥
+const char * key = "4EepovakpbqhZUnUDwH42KAADYGv4UUe" ;
+//每小时更新登录一次的更新定时器
+// static aos_timer_ptr LOGIN_1H_timer = NULL;
+
+bool aut_active(void)//设备激活
+{
+ int ret;
+ printf("aut_active");
+ // AIC_HTTPS_CLIENT_INSTANCE *http_client;
+ char dev_pass_base64[100] ={0};
+ char enc_iv[65] = {0};
+ // http创建客户端句柄
+
+ char *json_string =NULL;
+ cJSON *root = NULL;
+
+
+ unsigned char deviceId[6] = {0};
+ unsigned int len = 6;
+
+
+ memset(deviceId,0,6);
+ bluetooth_get_local_addr(&deviceId[0],len);
+
+ char deviceId_temp[20] = {0};
+
+ sprintf(deviceId_temp,"%02X%02x%02X%02x%02X%02x",deviceId[5],deviceId[4],deviceId[3],deviceId[2],deviceId[1],deviceId[0]);
+
+
+ time_t timestamp;
+ timestamp = time(NULL);
+ printf("2时间戳: %ld\n", (long)timestamp);
+ long long timestamp_ms = (long long)timestamp * 1000;
+
+ char* timestamp_str_2=(char *)malloc(20);
+ memset(timestamp_str_2,0,20);
+
+ // 使用 sprintf 将 long long 类型的时间戳转换为字符串
+ ret = sprintf(timestamp_str_2, "%lld", timestamp_ms);
+ // 打印转换后的字符串形式的时间戳
+
+
+ const char *dev_pid = "Y1DxRdBfnzVZQrXHdrNl";//PID
+ // const char *dev_key = "4EepovakpbqhZUnUDwH42KAADYGv4UUe";//密钥
+
+ char md5_buf[33]={0};
+ active_md5_sign((char *)deviceId_temp,dev_pid,timestamp_str_2,key,md5_buf);
+ printf("md5_buf:%s",md5_buf);
+
+
+ const char *signMethod ="MD5";
+
+ uint32_t response = 0;
+ //创建客户端实例
+
+
+ // 创建JSON对象
+ root = cJSON_CreateObject();
+ if (root == NULL) {
+ printf( "Failed to create JSON object\n");
+ return false ;
+ }
+
+ // 添加字段
+ cJSON_AddStringToObject(root, "deviceId", (char *)deviceId_temp);
+ cJSON_AddStringToObject(root, "pid", dev_pid);
+ cJSON_AddStringToObject(root, "sign", md5_buf);
+
+ printf("时间戳(ms 转换为字符串): %s\n", timestamp_str_2);
+
+ cJSON_AddStringToObject(root, "timeStamp", timestamp_str_2);
+
+ free(timestamp_str_2);
+
+ cJSON_AddStringToObject(root, "signMethod", signMethod);
+
+ // 生成JSON字符串
+ json_string = cJSON_Print(root);
+ if (json_string == NULL) {
+ printf("Failed to print JSON\n");
+ cJSON_Delete(root);
+ return false;
+ }
+
+ // 输出JSON
+ printf("JSON output: %s\n", json_string);
+ extern uint32_t put_data_by_get_file(char *data,uint16_t data_len);
+
+ if(200==put_data_by_get_file(json_string,strlen(json_string)))
+ {
+ cJSON_free(json_string);
+ return true;
+ }
+ else
+ {
+ cJSON_free(json_string);
+ return false;
+ }
+
+
+
+
+
+}
+
+
+
+extern bool read_dev_pass(char *data_pass);
+extern uint32_t post_data_by_get_file(char *data,uint16_t data_len);
+bool read_dev_token(char *data_token);
+
+uint32_t aut_login_time=0;
+
+bool aut_login(void)//登录
+{
+ time_t timestamp;
+ timestamp = time(NULL);
+
+ if(timestamp - aut_login_time < 60 * 60 )
+ {
+ return true;
+ }
+
+ char dev_pass[64]={0};
+ if(read_dev_pass(dev_pass)==false)
+ {
+ // return ;
+ if(aut_active())
+ {
+ printf( "aut_active fail\n");
+ return false;
+ }
+ else
+ {
+ read_dev_pass(dev_pass);
+ }
+ }
+
+
+
+ printf("dev_sign_in 2");
+ int count = 5;
+ char *encrypt_data = NULL;
+ char *response_data =NULL;
+ int aut_login_http_handle = 0;
+ char enc_iv[17]={0};
+
+ // 随机生成16个字符串 设备生成做加密使用
+ //char *random_string= generate_random_string(); // 随机的16个字符串
+ // 设备端进行密码加密
+ /**
+ * password, productSecret, nonce utJMIAPRN1E81DzSDVigh/f0ZmHQdBgdAGZ/DhkPJ/s= uKLrChwrxA1LklgBc3VwawYjUkbT3BgX qgofeplofqeoadha
+ */
+ int encrypt_data_len = 512;
+ encrypt_data = (char *)malloc(encrypt_data_len);
+
+
+ // 登录数据
+ unsigned char deviceId[20] = {0};
+ //aic_srv_tele_radio_get_current_slot_imei_sync(deviceId);
+ memset(deviceId,0,6);
+ bluetooth_get_local_addr(&deviceId[0],6);
+
+ char deviceId_temp[20] = {0};
+
+ sprintf(deviceId_temp,"%02X%02x%02X%02x%02X%02x",deviceId[5],deviceId[4],deviceId[3],deviceId[2],deviceId[1],deviceId[0]);
+
+
+ printf("2时间戳: %ld\n", (long)timestamp);
+ long long timestamp_ms = (long long)timestamp * 1000;
+ char timestamp_str[20] ={0};
+
+ // 使用 sprintf 将 long long 类型的时间戳转换为字符串
+ sprintf(timestamp_str, "%lld", timestamp_ms);
+ memset(enc_iv,'1',16);
+ memcpy(enc_iv,timestamp_str,strlen(timestamp_str));
+
+ enc_iv[16] = 0;
+ aes_cbc_pkcs5_encrypt(dev_pass, strlen(dev_pass), key, enc_iv,encrypt_data,&encrypt_data_len);//加密
+
+ cJSON *root = cJSON_CreateObject();
+ if (root == NULL)
+ {
+ return false;
+ }
+ // 添加字段
+ cJSON_AddStringToObject(root, "deviceId", deviceId_temp);
+ cJSON_AddStringToObject(root, "password", encrypt_data);
+ cJSON_AddStringToObject(root, "nonce", enc_iv);
+ // 生成JSON字符串
+ char *json_string = cJSON_Print(root);
+ if (json_string == NULL)
+ {
+ printf( "Failed to print JSON\n");
+ cJSON_Delete(root);
+ return false;
+ }
+ printf("json_string:%s",json_string);
+
+ int ret= post_data_by_get_file(json_string,strlen(json_string));
+
+
+
+ if(ret==200 )
+ {
+ cJSON_free(json_string);
+ aut_login_time=timestamp;
+ if(read_dev_token(NULL))
+ {
+ return true;
+ }
+ else
+ {
+ aut_login_time=0;
+ return false;
+ }
+
+ }
+ else
+ {
+ cJSON_free(json_string);
+ return false;
+ }
+}
+
+
+bool read_dev_pass(char *data_pass)
+{
+ char buf[512]={0};
+
+ FILE *fp=fopen(AUTH_ACTIVE,"rb+");
+ int read_size;
+
+ uint32_t pack=512;
+
+ if(fp==NULL)
+ {
+ return false;
+ }
+
+ memset_s(buf,512,0,512);
+ read_size=fread(buf,1,512,fp);
+ if(read_size!=0)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "buf %d %s",read_size,buf);
+ }
+ fclose(fp);
+
+ char *p=buf;
+ while (*p!='{' && *p !='\0')
+ {
+ p++;
+ }
+
+ cJSON* root = cJSON_Parse((const char *)p);
+ if (root == NULL) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"解析失败\n");
+ return false;
+ }
+ char *password_str=NULL;
+ char * nonce_str=0;
+
+ cJSON* data = cJSON_GetObjectItem(root, "data");
+ if (data)
+ {
+ cJSON* password = cJSON_GetObjectItem(data, "password");
+ if (password && cJSON_IsString(password)) {
+ password_str= password->valuestring;
+ }
+
+ cJSON* nonce = cJSON_GetObjectItem(data, "nonce");
+ if (nonce && cJSON_IsString(nonce)) {
+ nonce_str = nonce->valuestring;
+ }
+
+ }
+
+ int dev_pass_len =64;
+ char *dev_pass =(char *)malloc(dev_pass_len);
+ if(dev_pass)
+ {
+ memset(dev_pass,0,dev_pass_len);
+ if(strlen(nonce_str)>8 && strlen(password_str)>8)
+ {
+ aes_cbc_pkcs5_decrypt(password_str, "4EepovakpbqhZUnUDwH42KAADYGv4UUe", nonce_str,dev_pass,&dev_pass_len);//解密
+ dev_pass[dev_pass_len] = 0;
+ printf("dev_pass:%s dev_pass_len:%d\n",dev_pass,dev_pass_len);
+ }
+
+ }else
+ {
+ printf("dev_pass malloc error!!!!!!!!!!!");
+ }
+
+
+
+ if(strlen(password_str)>=0)
+ {
+ memcpy(data_pass,dev_pass,dev_pass_len);
+ free(dev_pass);
+ cJSON_Delete(data);
+ return true;
+ }
+ free(dev_pass);
+ cJSON_Delete(data);
+ return false;
+}
+
+// {"success":true,"msg":"登录成功","code":20001,"data":{"deviceId":"28110601009b","token":"95fc6dcdf5a3e9a48df535453efd097c19"}}
+
+bool read_dev_token(char *data_token)
+{
+ time_t timestamp;
+ timestamp = time(NULL);
+
+ if(timestamp - aut_login_time > 60 * 60 )
+ {
+ return false;
+ }
+
+ char buf[512]={0};
+
+ FILE *fp=fopen(AUTH_SIGN_IN,"rb+");
+ int read_size;
+
+ uint32_t pack=512;
+
+ if(fp==NULL)
+ {
+ return false;
+ }
+
+ memset_s(buf,512,0,512);
+ read_size=fread(buf,1,512,fp);
+ if(read_size!=0)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "buf %d %s",read_size,buf);
+ }
+ fclose(fp);
+
+ char *p=buf;
+ while (*p!='{' && *p !='\0')
+ {
+ p++;
+ }
+
+ cJSON* root = cJSON_Parse((const char *)p);
+ if (root == NULL) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"解析失败\n");
+ return false;
+ }
+ char *token_str=NULL;
+
+ cJSON* data = cJSON_GetObjectItem(root, "data");
+ if (data)
+ {
+ cJSON* token = cJSON_GetObjectItem(data, "token");
+ if (token && cJSON_IsString(token))
+ {
+ token_str= token->valuestring;
+ }
+ else
+ {
+ cJSON_Delete(data);
+ return false;
+ }
+ }
+ else
+ {
+ cJSON_Delete(data);
+ return false;
+ }
+
+
+ if(strlen(token_str)>=0 && data_token!=NULL )
+ {
+ memcpy(data_token,token_str,strlen(token_str));
+ cJSON_Delete(data);
+ return true;
+ }
+ cJSON_Delete(data);
+
+ return true;
+}
+
+void read_file_put(void )
+{
+ char buf[1024]={0};
+
+ FILE *fp=fopen(AUTH_SIGN_IN,"rb+");
+ int read_size;
+
+ uint32_t pack=1024;
+
+ if(fp==NULL)
+ {
+ return;
+ }
+ do
+ {
+ memset_s(buf,1024,0,1024);
+ read_size=fread(buf,1,1024,fp);
+
+ if(read_size!=0)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "buf %d %s",read_size,buf);
+ }
+
+ } while (read_size==1024);
+ fclose(fp);
+
+}
+
+
+int active_md5_buf(char *in_buf,char*md5_str)
+{
+
+ char md5_buf[16]={0};
+ char *sign_buf = (char *)malloc(1024);
+
+ if(!sign_buf)
+ return -10;
+ memset(sign_buf,0,1024);
+
+ int sign_len = 0;
+ strcpy(sign_buf,in_buf);
+
+ sign_len = strlen(in_buf);
+
+
+ mbedtls_md5_context ctx;
+
+ // 初始化MD5上下文
+ mbedtls_md5_init(&ctx);
+
+ // 开始计算MD5哈希
+ mbedtls_md5_starts(&ctx);
+ // 更新要计算哈希的数据
+ mbedtls_md5_update(&ctx, (const unsigned char *)sign_buf, sign_len);
+
+ // 完成哈希计算
+ mbedtls_md5_finish(&ctx, (unsigned char *)md5_buf);
+
+ // printf("md5_buf\r\n");
+ // for (int i = 0; i < 16; i++) {
+ // printf("%02X\n", (uint8_t)md5_buf[i]);
+ // }
+ // printf("md5_buf end\r\n");
+
+ // 清理MD5上下文
+ mbedtls_md5_free(&ctx);
+ for (int i = 0; i < 16; i++) {
+ sprintf(&md5_str[i * 2], "%02x", (uint8_t)md5_buf[i]);
+ }
+ md5_str[32] = '\0';
+
+ free(sign_buf);
+ return 0;
+}
+
+bool pre_AI_init(void)
+{
+ if(read_dev_token(NULL)==false)
+ {
+ return aut_login();
+ }
+}
+
+#ifdef __cplusplus
+}
#endif /* __cplusplus */
\ No newline at end of file
+++ /dev/null
-/*
- * TTS (Text-to-Speech) 服务实现
- * 负责建立与TTS服务器的WebSocket连接管理,上传文本,接收音频流并播放
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "tts_server.h"
-#include "../../../../application/wearable/ohos_deps/wearable_log.h"
-#include "../../../../../open_source/openharmony/third_party/cJSON/cJSON.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* 内部宏定义 */
-#define TTS_LOG_TAG "TTS_SERVER"
-#define TTS_PLAYBACK_THREAD_STACK_SIZE 4096
-
-/* 内部函数声明 */
-static void tts_server_on_connected(void *context);
-static void tts_server_on_disconnected(void *context);
-static void tts_server_on_message_received(void *context, const char *data, size_t length);
-static void tts_server_on_error(void *context, int error_code, const char *error_msg);
-static void tts_server_playback_thread(void *arg);
-static ai_service_error_t tts_server_parse_synthesis_result(tts_server_context_t *context,
- const char *json_data,
- tts_synthesis_result_t *result);
-static ai_service_error_t tts_server_create_synthesis_message(tts_server_context_t *context,
- const tts_synthesis_request_t *request,
- char *output, size_t max_len);
-static ai_service_error_t tts_server_create_stop_message(tts_server_context_t *context,
- char *output, size_t max_len);
-static ai_service_error_t tts_server_play_audio_data(tts_server_context_t *context,
- const char *audio_data, size_t data_length);
-static ai_service_error_t tts_server_decode_audio_data(const char *encoded_data,
- char **decoded_data, size_t *decoded_length);
-
-/* 公共接口实现 */
-
-ai_service_error_t tts_server_init(tts_server_context_t *context,
- const char *server_url,
- const tts_audio_config_t *audio_config,
- const tts_voice_config_t *voice_config)
-{
- if (!context || !server_url || !audio_config || !voice_config) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- // 清零上下文
- memset(context, 0, sizeof(tts_server_context_t));
-
- // 创建基础服务配置
- ai_service_config_t base_config = {0};
- strncpy(base_config.server_url, server_url, sizeof(base_config.server_url) - 1);
- base_config.server_port = 80;
- strncpy(base_config.protocol, "tts-protocol", sizeof(base_config.protocol) - 1);
- base_config.connect_timeout_ms = AI_CONNECT_TIMEOUT_MS;
- base_config.receive_timeout_ms = AI_RECEIVE_TIMEOUT_MS;
- base_config.reconnect_interval_ms = AI_RECONNECT_INTERVAL_MS;
- base_config.heartbeat_interval_ms = AI_HEARTBEAT_INTERVAL_MS;
- base_config.max_retry_count = AI_MAX_RETRY_COUNT;
- base_config.auto_reconnect = true;
-
- // 初始化基础服务
- ai_service_error_t ret = ai_service_init(&context->base, "TTS_SERVER", &base_config);
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to init base service: %d", TTS_LOG_TAG, ret);
- return ret;
- }
-
- // 复制TTS特定配置
- memcpy(&context->audio_config, audio_config, sizeof(tts_audio_config_t));
- memcpy(&context->voice_config, voice_config, sizeof(tts_voice_config_t));
-
- // 分配音频缓冲区
- context->audio_buffer_size = TTS_MAX_AUDIO_BUFFER_SIZE;
- context->audio_buffer = (char *)malloc(context->audio_buffer_size);
- if (!context->audio_buffer) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to allocate audio buffer", TTS_LOG_TAG);
- ai_service_destroy(&context->base);
- return AI_SERVICE_ERROR_MEMORY_ALLOC;
- }
-
- context->audio_buffer_used = 0;
-
- // 创建音频缓冲区互斥锁
- context->audio_buffer_mutex = osMutexNew(NULL);
- if (!context->audio_buffer_mutex) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to create audio buffer mutex", TTS_LOG_TAG);
- free(context->audio_buffer);
- ai_service_destroy(&context->base);
- return AI_SERVICE_ERROR_INTERNAL;
- }
-
- // 创建播放信号量
- context->playback_sem = osSemaphoreNew(1, 0, NULL);
- if (!context->playback_sem) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to create playback semaphore", TTS_LOG_TAG);
- osMutexDelete(context->audio_buffer_mutex);
- free(context->audio_buffer);
- ai_service_destroy(&context->base);
- return AI_SERVICE_ERROR_INTERNAL;
- }
-
- // 初始化播放状态
- context->playback_state = TTS_PLAYBACK_STATE_IDLE;
- context->synthesis_active = false;
- context->current_sequence = 0;
- memset(context->current_session_id, 0, sizeof(context->current_session_id));
-
- // 设置基础服务回调
- ai_service_set_callbacks(&context->base,
- tts_server_on_connected,
- tts_server_on_disconnected,
- tts_server_on_message_received,
- tts_server_on_error);
-
- // 设置用户数据指向TTS上下文
- ai_service_set_user_data(&context->base, context);
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] TTS server initialized", TTS_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t tts_server_destroy(tts_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- // 停止服务
- tts_server_stop(context);
-
- // 删除播放信号量
- if (context->playback_sem) {
- osSemaphoreDelete(context->playback_sem);
- context->playback_sem = NULL;
- }
-
- // 删除音频缓冲区互斥锁
- if (context->audio_buffer_mutex) {
- osMutexDelete(context->audio_buffer_mutex);
- context->audio_buffer_mutex = NULL;
- }
-
- // 释放音频缓冲区
- if (context->audio_buffer) {
- free(context->audio_buffer);
- context->audio_buffer = NULL;
- }
-
- // 销毁基础服务
- ai_service_destroy(&context->base);
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] TTS server destroyed", TTS_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t tts_server_start(tts_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- ai_service_error_t ret = ai_service_start(&context->base);
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to start TTS server: %d", TTS_LOG_TAG, ret);
- return ret;
- }
-
- // 创建播放线程
- osThreadAttr_t thread_attr = {0};
- thread_attr.name = "TTS_Playback";
- thread_attr.stack_size = TTS_PLAYBACK_THREAD_STACK_SIZE;
- thread_attr.priority = osPriorityNormal;
-
- context->playback_thread = osThreadNew(tts_server_playback_thread, context, &thread_attr);
- if (!context->playback_thread) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to create playback thread", TTS_LOG_TAG);
- ai_service_stop(&context->base);
- return AI_SERVICE_ERROR_INTERNAL;
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] TTS server started", TTS_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t tts_server_stop(tts_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- // 停止当前合成
- if (context->synthesis_active) {
- tts_server_stop_synthesis(context);
- }
-
- // 停止播放
- tts_server_stop_playback(context);
-
- // 等待播放线程结束
- if (context->playback_thread) {
- osThreadTerminate(context->playback_thread);
- context->playback_thread = NULL;
- }
-
- ai_service_error_t ret = ai_service_stop(&context->base);
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to stop TTS server: %d", TTS_LOG_TAG, ret);
- return ret;
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] TTS server stopped", TTS_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t tts_server_synthesize_text(tts_server_context_t *context,
- const char *text,
- const char *session_id)
-{
- if (!context || !text) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- tts_synthesis_request_t request = {0};
- request.text = (char *)text;
- request.use_ssml = false;
- request.voice_config = context->voice_config;
-
- if (session_id && strlen(session_id) > 0) {
- strncpy(request.session_id, session_id, sizeof(request.session_id) - 1);
- } else {
- ai_service_generate_uuid(request.session_id, sizeof(request.session_id));
- }
-
- return tts_server_synthesize_request(context, &request);
-}
-
-ai_service_error_t tts_server_synthesize_ssml(tts_server_context_t *context,
- const char *ssml,
- const char *session_id)
-{
- if (!context || !ssml) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- tts_synthesis_request_t request = {0};
- request.ssml = (char *)ssml;
- request.use_ssml = true;
- request.voice_config = context->voice_config;
-
- if (session_id && strlen(session_id) > 0) {
- strncpy(request.session_id, session_id, sizeof(request.session_id) - 1);
- } else {
- ai_service_generate_uuid(request.session_id, sizeof(request.session_id));
- }
-
- return tts_server_synthesize_request(context, &request);
-}
-
-ai_service_error_t tts_server_synthesize_request(tts_server_context_t *context,
- const tts_synthesis_request_t *request)
-{
- if (!context || !request) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- if (!ai_service_is_connected(&context->base)) {
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[%s] TTS server is not connected", TTS_LOG_TAG);
- return AI_SERVICE_ERROR_NOT_CONNECTED;
- }
-
- if (context->synthesis_active) {
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[%s] Synthesis is already active", TTS_LOG_TAG);
- return AI_SERVICE_ERROR_ALREADY_CONNECTED;
- }
-
- // 复制会话ID
- strncpy(context->current_session_id, request->session_id, sizeof(context->current_session_id) - 1);
-
- // 创建合成消息
- char *synthesis_message = (char *)malloc(TTS_MAX_TEXT_LENGTH + TTS_MAX_SSML_LENGTH + 1024);
- if (!synthesis_message) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to allocate synthesis message buffer", TTS_LOG_TAG);
- return AI_SERVICE_ERROR_MEMORY_ALLOC;
- }
-
- ai_service_error_t ret = tts_server_create_synthesis_message(context, request,
- synthesis_message,
- TTS_MAX_TEXT_LENGTH + TTS_MAX_SSML_LENGTH + 1024);
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to create synthesis message: %d", TTS_LOG_TAG, ret);
- free(synthesis_message);
- return ret;
- }
-
- // 发送合成消息
- ret = ai_service_send_text(&context->base, synthesis_message);
- free(synthesis_message);
-
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to send synthesis message: %d", TTS_LOG_TAG, ret);
- return ret;
- }
-
- context->synthesis_active = true;
- context->current_sequence = 0;
- context->synthesis_sessions++;
-
- // 统计发送的文本长度
- if (request->use_ssml && request->ssml) {
- context->total_text_sent += strlen(request->ssml);
- } else if (request->text) {
- context->total_text_sent += strlen(request->text);
- }
-
- // 调用用户回调
- if (context->on_synthesis_start) {
- context->on_synthesis_start(context, context->current_session_id);
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Synthesis started, session: %s",
- TTS_LOG_TAG, context->current_session_id);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t tts_server_stop_synthesis(tts_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- if (!context->synthesis_active) {
- return AI_SERVICE_OK;
- }
-
- // 创建停止合成消息
- char stop_message[512];
- ai_service_error_t ret = tts_server_create_stop_message(context, stop_message, sizeof(stop_message));
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to create stop message: %d", TTS_LOG_TAG, ret);
- } else {
- // 发送停止消息
- ret = ai_service_send_text(&context->base, stop_message);
- if (ret != AI_SERVICE_OK) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to send stop message: %d", TTS_LOG_TAG, ret);
- }
- }
-
- // 调用用户回调
- if (context->on_synthesis_complete) {
- context->on_synthesis_complete(context, context->current_session_id);
- }
-
- context->synthesis_active = false;
- memset(context->current_session_id, 0, sizeof(context->current_session_id));
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Synthesis stopped", TTS_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t tts_server_start_playback(tts_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- if (context->playback_state == TTS_PLAYBACK_STATE_PLAYING) {
- return AI_SERVICE_OK;
- }
-
- context->playback_state = TTS_PLAYBACK_STATE_PLAYING;
- context->playback_sessions++;
-
- // 通知播放线程开始播放
- osSemaphoreRelease(context->playback_sem);
-
- // 调用用户回调
- if (context->on_playback_start) {
- context->on_playback_start(context);
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Playback started", TTS_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t tts_server_pause_playback(tts_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- if (context->playback_state != TTS_PLAYBACK_STATE_PLAYING) {
- return AI_SERVICE_OK;
- }
-
- context->playback_state = TTS_PLAYBACK_STATE_PAUSED;
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Playback paused", TTS_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t tts_server_resume_playback(tts_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- if (context->playback_state != TTS_PLAYBACK_STATE_PAUSED) {
- return AI_SERVICE_OK;
- }
-
- context->playback_state = TTS_PLAYBACK_STATE_PLAYING;
-
- // 通知播放线程恢复播放
- osSemaphoreRelease(context->playback_sem);
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Playback resumed", TTS_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t tts_server_stop_playback(tts_server_context_t *context)
-{
- if (!context) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- if (context->playback_state == TTS_PLAYBACK_STATE_IDLE ||
- context->playback_state == TTS_PLAYBACK_STATE_STOPPED) {
- return AI_SERVICE_OK;
- }
-
- context->playback_state = TTS_PLAYBACK_STATE_STOPPED;
-
- // 清空音频缓冲区
- osMutexAcquire(context->audio_buffer_mutex, osWaitForever);
- context->audio_buffer_used = 0;
- osMutexRelease(context->audio_buffer_mutex);
-
- // 调用用户回调
- if (context->on_playback_complete) {
- context->on_playback_complete(context);
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Playback stopped", TTS_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t tts_server_set_audio_config(tts_server_context_t *context,
- const tts_audio_config_t *audio_config)
-{
- if (!context || !audio_config) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- memcpy(&context->audio_config, audio_config, sizeof(tts_audio_config_t));
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Audio config updated", TTS_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-ai_service_error_t tts_server_set_voice_config(tts_server_context_t *context,
- const tts_voice_config_t *voice_config)
-{
- if (!context || !voice_config) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- memcpy(&context->voice_config, voice_config, sizeof(tts_voice_config_t));
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Voice config updated", TTS_LOG_TAG);
-
- return AI_SERVICE_OK;
-}
-
-const char* tts_server_get_current_session_id(tts_server_context_t *context)
-{
- if (!context || !context->synthesis_active) {
- return NULL;
- }
-
- return context->current_session_id;
-}
-
-bool tts_server_is_synthesis_active(tts_server_context_t *context)
-{
- return context ? context->synthesis_active : false;
-}
-
-tts_playback_state_t tts_server_get_playback_state(tts_server_context_t *context)
-{
- return context ? context->playback_state : TTS_PLAYBACK_STATE_ERROR;
-}
-
-void tts_server_set_callbacks(tts_server_context_t *context,
- void (*on_synthesis_start)(void *context, const char *session_id),
- void (*on_synthesis_result)(void *context, const tts_synthesis_result_t *result),
- void (*on_synthesis_complete)(void *context, const char *session_id),
- void (*on_playback_start)(void *context),
- void (*on_playback_complete)(void *context),
- void (*on_playback_error)(void *context, int error_code))
-{
- if (!context) {
- return;
- }
-
- context->on_synthesis_start = on_synthesis_start;
- context->on_synthesis_result = on_synthesis_result;
- context->on_synthesis_complete = on_synthesis_complete;
- context->on_playback_start = on_playback_start;
- context->on_playback_complete = on_playback_complete;
- context->on_playback_error = on_playback_error;
-}
-
-void tts_server_get_stats(tts_server_context_t *context,
- uint32_t *total_text_sent,
- uint32_t *total_audio_received,
- uint32_t *synthesis_sessions,
- uint32_t *playback_sessions)
-{
- if (!context) {
- return;
- }
-
- if (total_text_sent) {
- *total_text_sent = context->total_text_sent;
- }
-
- if (total_audio_received) {
- *total_audio_received = context->total_audio_received;
- }
-
- if (synthesis_sessions) {
- *synthesis_sessions = context->synthesis_sessions;
- }
-
- if (playback_sessions) {
- *playback_sessions = context->playback_sessions;
- }
-}
-
-/* 工具函数实现 */
-
-void tts_server_create_default_audio_config(tts_audio_config_t *config)
-{
- if (!config) {
- return;
- }
-
- config->format = TTS_AUDIO_FORMAT_PCM;
- config->sample_rate = 16000;
- config->channels = 1;
- config->bits_per_sample = 16;
- config->bitrate = 128000;
-}
-
-void tts_server_create_default_voice_config(tts_voice_config_t *config)
-{
- if (!config) {
- return;
- }
-
- strncpy(config->voice_name, "default", sizeof(config->voice_name) - 1);
- config->voice_type = TTS_VOICE_TYPE_FEMALE;
- config->language = TTS_LANGUAGE_ZH_CN;
- config->emotion = TTS_EMOTION_NEUTRAL;
- config->speed = 1.0f;
- config->pitch = 1.0f;
- config->volume = 0.8f;
-}
-
-void tts_server_free_synthesis_result(tts_synthesis_result_t *result)
-{
- if (!result) {
- return;
- }
-
- if (result->audio_data) {
- free(result->audio_data);
- result->audio_data = NULL;
- }
-}
-
-const char* tts_server_audio_format_to_string(tts_audio_format_t format)
-{
- switch (format) {
- case TTS_AUDIO_FORMAT_PCM: return "PCM";
- case TTS_AUDIO_FORMAT_WAV: return "WAV";
- case TTS_AUDIO_FORMAT_MP3: return "MP3";
- case TTS_AUDIO_FORMAT_AAC: return "AAC";
- case TTS_AUDIO_FORMAT_OGG: return "OGG";
- default: return "UNKNOWN";
- }
-}
-
-const char* tts_server_voice_type_to_string(tts_voice_type_t voice_type)
-{
- switch (voice_type) {
- case TTS_VOICE_TYPE_MALE: return "MALE";
- case TTS_VOICE_TYPE_FEMALE: return "FEMALE";
- case TTS_VOICE_TYPE_CHILD: return "CHILD";
- case TTS_VOICE_TYPE_ELDERLY: return "ELDERLY";
- default: return "UNKNOWN";
- }
-}
-
-const char* tts_server_language_to_string(tts_language_t language)
-{
- switch (language) {
- case TTS_LANGUAGE_ZH_CN: return "zh-CN";
- case TTS_LANGUAGE_EN_US: return "en-US";
- case TTS_LANGUAGE_JA_JP: return "ja-JP";
- case TTS_LANGUAGE_KO_KR: return "ko-KR";
- default: return "unknown";
- }
-}
-
-const char* tts_server_emotion_to_string(tts_emotion_t emotion)
-{
- switch (emotion) {
- case TTS_EMOTION_NEUTRAL: return "NEUTRAL";
- case TTS_EMOTION_HAPPY: return "HAPPY";
- case TTS_EMOTION_SAD: return "SAD";
- case TTS_EMOTION_ANGRY: return "ANGRY";
- case TTS_EMOTION_EXCITED: return "EXCITED";
- case TTS_EMOTION_CALM: return "CALM";
- default: return "UNKNOWN";
- }
-}
-
-const char* tts_server_playback_state_to_string(tts_playback_state_t state)
-{
- switch (state) {
- case TTS_PLAYBACK_STATE_IDLE: return "IDLE";
- case TTS_PLAYBACK_STATE_PLAYING: return "PLAYING";
- case TTS_PLAYBACK_STATE_PAUSED: return "PAUSED";
- case TTS_PLAYBACK_STATE_STOPPED: return "STOPPED";
- case TTS_PLAYBACK_STATE_ERROR: return "ERROR";
- default: return "UNKNOWN";
- }
-}
-
-/* 内部函数实现 */
-
-static void tts_server_on_connected(void *context)
-{
- tts_server_context_t *tts_context = (tts_server_context_t *)ai_service_get_user_data((ai_service_context_t *)context);
- if (!tts_context) {
- return;
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] TTS server connected", TTS_LOG_TAG);
-}
-
-static void tts_server_on_disconnected(void *context)
-{
- tts_server_context_t *tts_context = (tts_server_context_t *)ai_service_get_user_data((ai_service_context_t *)context);
- if (!tts_context) {
- return;
- }
-
- // 停止当前合成
- if (tts_context->synthesis_active) {
- tts_context->synthesis_active = false;
- if (tts_context->on_synthesis_complete) {
- tts_context->on_synthesis_complete(tts_context, tts_context->current_session_id);
- }
- }
-
- // 停止播放
- tts_server_stop_playback(tts_context);
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] TTS server disconnected", TTS_LOG_TAG);
-}
-
-static void tts_server_on_message_received(void *context, const char *data, size_t length)
-{
- tts_server_context_t *tts_context = (tts_server_context_t *)ai_service_get_user_data((ai_service_context_t *)context);
- if (!tts_context || !data || length == 0) {
- return;
- }
-
- // 解析合成结果
- tts_synthesis_result_t result = {0};
- ai_service_error_t ret = tts_server_parse_synthesis_result(tts_context, data, &result);
- if (ret == AI_SERVICE_OK) {
- tts_context->total_audio_received += result.audio_length;
-
- // 调用用户回调
- if (tts_context->on_synthesis_result) {
- tts_context->on_synthesis_result(tts_context, &result);
- }
-
- // 播放音频数据
- if (result.audio_data && result.audio_length > 0) {
- tts_server_play_audio_data(tts_context, result.audio_data, result.audio_length);
- }
-
- // 检查是否为最终结果
- if (result.is_final) {
- tts_context->synthesis_active = false;
- if (tts_context->on_synthesis_complete) {
- tts_context->on_synthesis_complete(tts_context, result.session_id);
- }
- }
-
- // 释放结果内存
- tts_server_free_synthesis_result(&result);
- }
-
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "[%s] Received message: %.*s",
- TTS_LOG_TAG, (int)length, data);
-}
-
-static void tts_server_on_error(void *context, int error_code, const char *error_msg)
-{
- tts_server_context_t *tts_context = (tts_server_context_t *)ai_service_get_user_data((ai_service_context_t *)context);
- if (!tts_context) {
- return;
- }
-
- // 调用用户回调
- if (tts_context->on_playback_error) {
- tts_context->on_playback_error(tts_context, error_code);
- }
-
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] TTS server error: %d - %s",
- TTS_LOG_TAG, error_code, error_msg ? error_msg : "Unknown");
-}
-
-static void tts_server_playback_thread(void *arg)
-{
- tts_server_context_t *context = (tts_server_context_t *)arg;
- if (!context) {
- return;
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Playback thread started", TTS_LOG_TAG);
-
- while (ai_service_get_state(&context->base) != AI_SERVICE_STATE_IDLE) {
- // 等待播放信号
- osStatus_t status = osSemaphoreAcquire(context->playback_sem, 1000);
- if (status != osOK) {
- continue;
- }
-
- // 播放音频缓冲区中的数据
- osMutexAcquire(context->audio_buffer_mutex, osWaitForever);
-
- if (context->audio_buffer_used > 0 && context->playback_state == TTS_PLAYBACK_STATE_PLAYING) {
- // 这里应该调用实际的音频播放接口
- // 为了演示,我们只是简单地清空缓冲区
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "[%s] Playing %zu bytes of audio",
- TTS_LOG_TAG, context->audio_buffer_used);
-
- context->audio_buffer_used = 0;
-
- // 播放完成后检查是否还有更多数据
- if (context->audio_buffer_used == 0 && !context->synthesis_active) {
- context->playback_state = TTS_PLAYBACK_STATE_IDLE;
- if (context->on_playback_complete) {
- context->on_playback_complete(context);
- }
- }
- }
-
- osMutexRelease(context->audio_buffer_mutex);
-
- osDelay(10); // 短暂延迟
- }
-
- WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] Playback thread stopped", TTS_LOG_TAG);
-}
-
-static ai_service_error_t tts_server_parse_synthesis_result(tts_server_context_t *context,
- const char *json_data,
- tts_synthesis_result_t *result)
-{
- if (!context || !json_data || !result) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- cJSON *json = cJSON_Parse(json_data);
- if (!json) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] Failed to parse JSON", TTS_LOG_TAG);
- return AI_SERVICE_ERROR_INTERNAL;
- }
-
- // 解析音频数据
- cJSON *audio_data_item = cJSON_GetObjectItem(json, "audio_data");
- if (audio_data_item && cJSON_IsString(audio_data_item)) {
- const char *encoded_data = cJSON_GetStringValue(audio_data_item);
- if (encoded_data) {
- ai_service_error_t ret = tts_server_decode_audio_data(encoded_data,
- &result->audio_data,
- &result->audio_length);
- if (ret != AI_SERVICE_OK) {
- cJSON_Delete(json);
- return ret;
- }
- }
- }
-
- // 解析会话ID
- cJSON *session_id_item = cJSON_GetObjectItem(json, "session_id");
- if (session_id_item && cJSON_IsString(session_id_item)) {
- const char *session_id = cJSON_GetStringValue(session_id_item);
- if (session_id) {
- strncpy(result->session_id, session_id, sizeof(result->session_id) - 1);
- }
- }
-
- // 解析是否为最终结果
- cJSON *is_final_item = cJSON_GetObjectItem(json, "is_final");
- if (is_final_item && cJSON_IsBool(is_final_item)) {
- result->is_final = cJSON_IsTrue(is_final_item);
- }
-
- // 解析序列号
- cJSON *sequence_item = cJSON_GetObjectItem(json, "sequence_number");
- if (sequence_item && cJSON_IsNumber(sequence_item)) {
- result->sequence_number = (uint32_t)cJSON_GetNumberValue(sequence_item);
- }
-
- cJSON_Delete(json);
-
- return AI_SERVICE_OK;
-}
-
-static ai_service_error_t tts_server_create_synthesis_message(tts_server_context_t *context,
- const tts_synthesis_request_t *request,
- char *output, size_t max_len)
-{
- if (!context || !request || !output || max_len == 0) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- cJSON *json = cJSON_CreateObject();
- if (!json) {
- return AI_SERVICE_ERROR_MEMORY_ALLOC;
- }
-
- cJSON_AddStringToObject(json, "type", "synthesize");
- cJSON_AddStringToObject(json, "session_id", request->session_id);
-
- if (request->use_ssml && request->ssml) {
- cJSON_AddStringToObject(json, "ssml", request->ssml);
- cJSON_AddBoolToObject(json, "use_ssml", true);
- } else if (request->text) {
- cJSON_AddStringToObject(json, "text", request->text);
- cJSON_AddBoolToObject(json, "use_ssml", false);
- }
-
- // 添加音频配置
- cJSON *audio_config = cJSON_CreateObject();
- cJSON_AddStringToObject(audio_config, "format", tts_server_audio_format_to_string(context->audio_config.format));
- cJSON_AddNumberToObject(audio_config, "sample_rate", context->audio_config.sample_rate);
- cJSON_AddNumberToObject(audio_config, "channels", context->audio_config.channels);
- cJSON_AddNumberToObject(audio_config, "bits_per_sample", context->audio_config.bits_per_sample);
- cJSON_AddNumberToObject(audio_config, "bitrate", context->audio_config.bitrate);
- cJSON_AddItemToObject(json, "audio_config", audio_config);
-
- // 添加语音配置
- cJSON *voice_config = cJSON_CreateObject();
- cJSON_AddStringToObject(voice_config, "voice_name", request->voice_config.voice_name);
- cJSON_AddStringToObject(voice_config, "voice_type", tts_server_voice_type_to_string(request->voice_config.voice_type));
- cJSON_AddStringToObject(voice_config, "language", tts_server_language_to_string(request->voice_config.language));
- cJSON_AddStringToObject(voice_config, "emotion", tts_server_emotion_to_string(request->voice_config.emotion));
- cJSON_AddNumberToObject(voice_config, "speed", request->voice_config.speed);
- cJSON_AddNumberToObject(voice_config, "pitch", request->voice_config.pitch);
- cJSON_AddNumberToObject(voice_config, "volume", request->voice_config.volume);
- cJSON_AddItemToObject(json, "voice_config", voice_config);
-
- char *json_string = cJSON_Print(json);
- if (!json_string) {
- cJSON_Delete(json);
- return AI_SERVICE_ERROR_MEMORY_ALLOC;
- }
-
- if (strlen(json_string) >= max_len) {
- free(json_string);
- cJSON_Delete(json);
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- strcpy(output, json_string);
-
- free(json_string);
- cJSON_Delete(json);
-
- return AI_SERVICE_OK;
-}
-
-static ai_service_error_t tts_server_create_stop_message(tts_server_context_t *context,
- char *output, size_t max_len)
-{
- if (!context || !output || max_len == 0) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- cJSON *json = cJSON_CreateObject();
- if (!json) {
- return AI_SERVICE_ERROR_MEMORY_ALLOC;
- }
-
- cJSON_AddStringToObject(json, "type", "stop_synthesis");
- cJSON_AddStringToObject(json, "session_id", context->current_session_id);
- cJSON_AddNumberToObject(json, "timestamp", ai_service_get_timestamp());
-
- char *json_string = cJSON_Print(json);
- if (!json_string) {
- cJSON_Delete(json);
- return AI_SERVICE_ERROR_MEMORY_ALLOC;
- }
-
- if (strlen(json_string) >= max_len) {
- free(json_string);
- cJSON_Delete(json);
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- strcpy(output, json_string);
-
- free(json_string);
- cJSON_Delete(json);
-
- return AI_SERVICE_OK;
-}
-
-static ai_service_error_t tts_server_play_audio_data(tts_server_context_t *context,
- const char *audio_data, size_t data_length)
-{
- if (!context || !audio_data || data_length == 0) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- osMutexAcquire(context->audio_buffer_mutex, osWaitForever);
-
- // 检查缓冲区空间
- if (context->audio_buffer_used + data_length > context->audio_buffer_size) {
- // 缓冲区不足,扩展或清空
- if (data_length > context->audio_buffer_size) {
- // 数据太大,重新分配缓冲区
- char *new_buffer = (char *)realloc(context->audio_buffer, data_length * 2);
- if (!new_buffer) {
- osMutexRelease(context->audio_buffer_mutex);
- return AI_SERVICE_ERROR_MEMORY_ALLOC;
- }
- context->audio_buffer = new_buffer;
- context->audio_buffer_size = data_length * 2;
- context->audio_buffer_used = 0;
- } else {
- // 清空缓冲区为新数据腾出空间
- context->audio_buffer_used = 0;
- }
- }
-
- // 复制音频数据到缓冲区
- memcpy(context->audio_buffer + context->audio_buffer_used, audio_data, data_length);
- context->audio_buffer_used += data_length;
-
- osMutexRelease(context->audio_buffer_mutex);
-
- // 如果当前没有播放,开始播放
- if (context->playback_state == TTS_PLAYBACK_STATE_IDLE) {
- tts_server_start_playback(context);
- } else if (context->playback_state == TTS_PLAYBACK_STATE_PLAYING) {
- // 通知播放线程有新数据
- osSemaphoreRelease(context->playback_sem);
- }
-
- return AI_SERVICE_OK;
-}
-
-static ai_service_error_t tts_server_decode_audio_data(const char *encoded_data,
- char **decoded_data, size_t *decoded_length)
-{
- if (!encoded_data || !decoded_data || !decoded_length) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- // 简单的十六进制解码(与ASR服务中的编码对应)
- size_t encoded_len = strlen(encoded_data);
- if (encoded_len % 2 != 0) {
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
-
- size_t decoded_len = encoded_len / 2;
- char *decoded = (char *)malloc(decoded_len);
- if (!decoded) {
- return AI_SERVICE_ERROR_MEMORY_ALLOC;
- }
-
- for (size_t i = 0; i < decoded_len; i++) {
- unsigned int byte_val;
- if (sscanf(&encoded_data[i * 2], "%2x", &byte_val) != 1) {
- free(decoded);
- return AI_SERVICE_ERROR_INVALID_PARAM;
- }
- decoded[i] = (char)byte_val;
- }
-
- *decoded_data = decoded;
- *decoded_length = decoded_len;
-
- return AI_SERVICE_OK;
-}
-/********************************************************************************************************************* */
-
-/*
- * @brief 启动TTS服务
- * @note 通过自定义命令消息启动TTS任务
- */
-void tts_api_start_tts(void)
-{
- char *jsonString =
- "{\"header\": \
- { \"event\": \"StartSynthesis\",\
- \"trace_id\": \"\"},\
- \"payload\": \
- {\"voice\":\"xiaoyun\",\
- \"format\":\"mp3\",\
- \"sample_rate\":16000,\
- \"volume\":80,\
- \"speech_rate\":0}\
- }";
-
- printf("uapi_start_tts :%s\r\n",jsonString);
-
-
- if (send_websocket_message(tts_client,( uint8_t *)jsonString,strlen(jsonString),WS_TEXT)==0)
- {
- memset_s(tts_task_id_buf,128,0,128);
- tts_is_ready=0;
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_websocket_message succ 0\n");
- }
-
-}
-
-/*
- * @brief 停止TTS服务
- * @note 通过自定义命令消息停止TTS任务
- */
-void tts_api_stop_tts(void)
-{
- char *jsonString =
- " { \
- \"header\": { \
- \"event\": \"StopSynthesis\", \
- \"trace_id\": \"\" \
- } \
- } ";
-
- printf("uapi_start_tts : %s\r\n",jsonString);
-
- if (send_websocket_message(tts_client,( uint8_t *)jsonString,strlen(jsonString),WS_TEXT)==0)
- {
- tts_is_ready=0;
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_websocket_message succ 0\n");
- }
-
-}
-
-/*
- * @brief 初始化TTS服务URL
- * @note 根据设备token初始化TTS服务URL
- */
-bool tts_api_ws_url_init(char * put_buf)
-{
- // 测试用例
- // tts_client = init_websocket_client("ws://118.145.158.207:22080/tts/stream?audio_buffer_size=512", NULL, 0);
-
- char token[64]={0};
- if(read_dev_token(token))
- {
- // /tts/stream?audio_buffer_size=1024
- sprintf(put_buf,"ws://amp.raisound.com/tts/stream?dt=%s&platform=aliyun&noCache=1",token);
- return true;
- }
- else
- {
- return false;
- }
-
-}
-
-/*
- * @brief 启动TTS单次任务
- * @note 通过自定义命令消息启动TTS单次任务 测试用例
- */
-void tts_api_start_tts_single(void)
-{
-
- char *jsonString =
- " { \"header\": { \
- \"event\": \"LongTextStream\",\
- \"trace_id\": \"3fa6b9e6a30b407ea38ad7ae69e6c291\" \
- }, \
- \"payload\": { \
- \"voice\":\"xiaoyun\", \
- \"format\":\"pcm\", \
- \"sample_rate\":16000, \
- \"volume\":50, \
- \"speech_rate\":0, \
- \"text\":\"深圳市北科瑞声科技股份有限公司,是由国家重大人才计划特聘专家刘轶博士创办的国内人 \
- 工智能音频领军企业,专注于行业智能音频交互技术,拥有全链条核心自主知识产权,汇集世界一流的研发运营团队。\" \
- } } ";
-
- printf("uapi_start_tts : %s\r\n",jsonString);
-
- if (send_websocket_message(tts_client,(uint8_t *)jsonString,strlen(jsonString),WS_TEXT)==0)
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_websocket_message succ 0\n");
-}
-
-/*
- * @brief 启动TTS单次任务
- * @param buf 文本内容
- * @note 通过自定义命令消息启动TTS单次任务
- */
-bool tts_api_start_tts_single_txt(char *buf)
-{
-
-
- if (tts_is_ready != 1) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "uapi_start_tts_single_txt no tts_is_ready \n");
- return false;
- }
- // 创建根JSON对象
- cJSON* dataJSON = cJSON_CreateObject();
- if (dataJSON == NULL) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error creating root JSON object\n");
- return false;
- }
-
- // 创建header对象并添加字段
- cJSON* header = cJSON_CreateObject();
- if (header == NULL) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error creating header JSON object\n");
- cJSON_Delete(dataJSON); // 释放已分配的内存
- return false;
- }
- cJSON_AddStringToObject(header, "event", "RunSynthesis");
- cJSON_AddStringToObject(header, "trace_id", tts_task_id_buf);
-
- // 创建payload对象并添加字段
- cJSON* payload = cJSON_CreateObject();
- if (payload == NULL) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error creating payload JSON object\n");
- cJSON_Delete(header); // 释放已分配的内存
- cJSON_Delete(dataJSON);
- return false;
- }
- cJSON_AddStringToObject(payload, "text", buf);
-
- // 将header和payload添加到根对象dataJSON中
- cJSON_AddItemToObject(dataJSON, "header", header);
- cJSON_AddItemToObject(dataJSON, "payload", payload);
-
- // 将JSON对象转换为字符串
- char* jsonString = cJSON_PrintUnformatted(dataJSON);
- if (jsonString == NULL) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error converting JSON to string\n");
- cJSON_Delete(dataJSON); // 释放JSON对象
- return false;
- }
-
- // 发送WebSocket消息
- bool result = false;
- if (send_websocket_message(tts_client, (uint8_t*)jsonString, strlen(jsonString), WS_TEXT) == 0) {
- tts_reconnect = 0;
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "send_websocket_message succ 0\n");
- result = true;
- }
- else
- {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "send_websocket_message fail -1\n");
- }
-
- // 释放资源
- cJSON_Delete(dataJSON); // 释放JSON对象(会自动释放header和payload)
- free(jsonString); // 释放cJSON_Print生成的字符串
- return result;
-}
-
-// char *tts_txt_str=
-
-
-/*
- * @brief 发送TTS文本
- * @param msg 文本内容
- * @note 通过自定义命令消息启动TTS单次任务 测试用例
- */
-void tts_api_send_tts_txt(char *msg)
-{
- char *jsonString =
- "{ \
- \"header\": { \
- \"event\": \"RunSynthesis\", \
- \"trace_id\": \"3fa6b9e6a30b407ea38ad7ae69e6c291\"\
- }, \
- \"payload\": { \
- \"text\":\"深圳市北科瑞声科技股份有限公司,是由国家重大人才计划特聘专家刘轶博士创办的国内人工智能音频领军企业,\
- 专注于行业智能音频交互技术,拥有全链条核心自主知识产权,汇集世界一流的研发运营团队。\" \
- }\
- }";
-
-
- if (send_websocket_message(tts_client,( uint8_t *)jsonString,strlen(jsonString),WS_TEXT)==0)
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_websocket_message succ 0\n");
- else
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"send_websocket_message fail 1\n");
-}
-
-// {"header":{"event":"StartedSynthesis","msg":"success","status":20000000,"task_id":"8e8996f9148b66738309602ec3219412"}}
-/*
- * @brief 解析TTS响应
- * @param buf 响应内容
- * @note 解析TTS响应
- */
-bool tts_api_msg_analysis(char *buf)
-{
- cJSON* root = cJSON_Parse((const char *)buf);
- if (root == NULL) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"解析失败\n");
- return false;
- }
- 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;
-
- if(strcmp("StartedSynthesis",event_str)==0 && strcmp("success",msg_str)==0)
- {
- tts_is_ready=1;
- }
- }
-
- 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));
- }
- }
- cJSON_Delete(root);
- return true;
-}
-
-#ifdef __cplusplus
-}
-#endif
\ No newline at end of file
--- /dev/null
+/*
+ * TTS (Text-to-Speech) 服务实现
+ * 负责建立与TTS服务器的WebSocket连接管理,上传文本,接收音频流并播放
+ */
+
+/********************************************************************************************************************* */
+
+/*
+ * @brief 启动TTS服务
+ * @note 通过自定义命令消息启动TTS任务
+ */
+void tts_api_start_tts(void)
+{
+ char *jsonString =
+ "{\"header\": \
+ { \"event\": \"StartSynthesis\",\
+ \"trace_id\": \"\"},\
+ \"payload\": \
+ {\"voice\":\"xiaoyun\",\
+ \"format\":\"mp3\",\
+ \"sample_rate\":16000,\
+ \"volume\":80,\
+ \"speech_rate\":0}\
+ }";
+
+ printf("uapi_start_tts :%s\r\n",jsonString);
+
+
+ if (send_websocket_message(tts_client,( uint8_t *)jsonString,strlen(jsonString),WS_TEXT)==0)
+ {
+ memset_s(tts_task_id_buf,128,0,128);
+ tts_is_ready=0;
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_websocket_message succ 0\n");
+ }
+
+}
+
+/*
+ * @brief 停止TTS服务
+ * @note 通过自定义命令消息停止TTS任务
+ */
+void tts_api_stop_tts(void)
+{
+ char *jsonString =
+ " { \
+ \"header\": { \
+ \"event\": \"StopSynthesis\", \
+ \"trace_id\": \"\" \
+ } \
+ } ";
+
+ printf("uapi_start_tts : %s\r\n",jsonString);
+
+ if (send_websocket_message(tts_client,( uint8_t *)jsonString,strlen(jsonString),WS_TEXT)==0)
+ {
+ tts_is_ready=0;
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_websocket_message succ 0\n");
+ }
+
+}
+
+/*
+ * @brief 初始化TTS服务URL
+ * @note 根据设备token初始化TTS服务URL
+ */
+bool tts_api_ws_url_init(char * put_buf)
+{
+ // 测试用例
+ // tts_client = init_websocket_client("ws://118.145.158.207:22080/tts/stream?audio_buffer_size=512", NULL, 0);
+
+ char token[64]={0};
+ if(read_dev_token(token))
+ {
+ // /tts/stream?audio_buffer_size=1024
+ sprintf(put_buf,"ws://amp.raisound.com/tts/stream?dt=%s&platform=aliyun&noCache=1",token);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+}
+
+/*
+ * @brief 启动TTS单次任务
+ * @note 通过自定义命令消息启动TTS单次任务 测试用例
+ */
+void tts_api_start_tts_single(void)
+{
+
+ char *jsonString =
+ " { \"header\": { \
+ \"event\": \"LongTextStream\",\
+ \"trace_id\": \"3fa6b9e6a30b407ea38ad7ae69e6c291\" \
+ }, \
+ \"payload\": { \
+ \"voice\":\"xiaoyun\", \
+ \"format\":\"pcm\", \
+ \"sample_rate\":16000, \
+ \"volume\":50, \
+ \"speech_rate\":0, \
+ \"text\":\"深圳市北科瑞声科技股份有限公司,是由国家重大人才计划特聘专家刘轶博士创办的国内人 \
+ 工智能音频领军企业,专注于行业智能音频交互技术,拥有全链条核心自主知识产权,汇集世界一流的研发运营团队。\" \
+ } } ";
+
+ printf("uapi_start_tts : %s\r\n",jsonString);
+
+ if (send_websocket_message(tts_client,(uint8_t *)jsonString,strlen(jsonString),WS_TEXT)==0)
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_websocket_message succ 0\n");
+}
+
+/*
+ * @brief 启动TTS单次任务
+ * @param buf 文本内容
+ * @note 通过自定义命令消息启动TTS单次任务
+ */
+bool tts_api_start_tts_single_txt(char *buf)
+{
+
+
+ if (tts_is_ready != 1) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "uapi_start_tts_single_txt no tts_is_ready \n");
+ return false;
+ }
+ // 创建根JSON对象
+ cJSON* dataJSON = cJSON_CreateObject();
+ if (dataJSON == NULL) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error creating root JSON object\n");
+ return false;
+ }
+
+ // 创建header对象并添加字段
+ cJSON* header = cJSON_CreateObject();
+ if (header == NULL) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error creating header JSON object\n");
+ cJSON_Delete(dataJSON); // 释放已分配的内存
+ return false;
+ }
+ cJSON_AddStringToObject(header, "event", "RunSynthesis");
+ cJSON_AddStringToObject(header, "trace_id", tts_task_id_buf);
+
+ // 创建payload对象并添加字段
+ cJSON* payload = cJSON_CreateObject();
+ if (payload == NULL) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error creating payload JSON object\n");
+ cJSON_Delete(header); // 释放已分配的内存
+ cJSON_Delete(dataJSON);
+ return false;
+ }
+ cJSON_AddStringToObject(payload, "text", buf);
+
+ // 将header和payload添加到根对象dataJSON中
+ cJSON_AddItemToObject(dataJSON, "header", header);
+ cJSON_AddItemToObject(dataJSON, "payload", payload);
+
+ // 将JSON对象转换为字符串
+ char* jsonString = cJSON_PrintUnformatted(dataJSON);
+ if (jsonString == NULL) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error converting JSON to string\n");
+ cJSON_Delete(dataJSON); // 释放JSON对象
+ return false;
+ }
+
+ // 发送WebSocket消息
+ bool result = false;
+ if (send_websocket_message(tts_client, (uint8_t*)jsonString, strlen(jsonString), WS_TEXT) == 0) {
+ tts_reconnect = 0;
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "send_websocket_message succ 0\n");
+ result = true;
+ }
+ else
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "send_websocket_message fail -1\n");
+ }
+
+ // 释放资源
+ cJSON_Delete(dataJSON); // 释放JSON对象(会自动释放header和payload)
+ free(jsonString); // 释放cJSON_Print生成的字符串
+ return result;
+}
+
+// char *tts_txt_str=
+
+
+/*
+ * @brief 发送TTS文本
+ * @param msg 文本内容
+ * @note 通过自定义命令消息启动TTS单次任务 测试用例
+ */
+void tts_api_send_tts_txt(char *msg)
+{
+ char *jsonString =
+ "{ \
+ \"header\": { \
+ \"event\": \"RunSynthesis\", \
+ \"trace_id\": \"3fa6b9e6a30b407ea38ad7ae69e6c291\"\
+ }, \
+ \"payload\": { \
+ \"text\":\"深圳市北科瑞声科技股份有限公司,是由国家重大人才计划特聘专家刘轶博士创办的国内人工智能音频领军企业,\
+ 专注于行业智能音频交互技术,拥有全链条核心自主知识产权,汇集世界一流的研发运营团队。\" \
+ }\
+ }";
+
+
+ if (send_websocket_message(tts_client,( uint8_t *)jsonString,strlen(jsonString),WS_TEXT)==0)
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_websocket_message succ 0\n");
+ else
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"send_websocket_message fail 1\n");
+}
+
+// {"header":{"event":"StartedSynthesis","msg":"success","status":20000000,"task_id":"8e8996f9148b66738309602ec3219412"}}
+/*
+ * @brief 解析TTS响应
+ * @param buf 响应内容
+ * @note 解析TTS响应
+ */
+bool tts_api_msg_analysis(char *buf)
+{
+ cJSON* root = cJSON_Parse((const char *)buf);
+ if (root == NULL) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"解析失败\n");
+ return false;
+ }
+ 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;
+
+ if(strcmp("StartedSynthesis",event_str)==0 && strcmp("success",msg_str)==0)
+ {
+ tts_is_ready=1;
+ }
+ }
+
+ 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));
+ }
+ }
+ cJSON_Delete(root);
+ return true;
+}
+
+#ifdef __cplusplus
+}
+#endif
\ No newline at end of file