#include "mbedtls/base64.h"
#include "ai_media.h" // Added for AI_RegisterWriteAudioDataCallback
+// 功能开关宏定义
+#define ENABLE_BINARY_DATA_INTERRUPT_CHECK 1 // 启用二进制数据间隔检查
+
// 打印等级定义
typedef enum {
LN_WS_LOG_ERROR = 0, // 错误信息
#define WS_STATE_CONNECTING 1 // 连接中
#define WS_STATE_CONNECTED 2 // 连接成功
#define WS_STATE_SLEEP 3 // 休眠状态
+#define WS_STATE_RECONNECTING 4 // 重连执行中
/* WebSocket关闭状态枚举 */
typedef enum {
static void ln_ws_process_message_with_callback(const ws_data_msg_t *data_msg);
static int ln_ws_close_with_status(int client_fd);
static ws_close_status_t ln_ws_get_close_status(void);
+static int ln_ws_check_chat_id_match(const char *chat_id, cJSON *root);
+static int ln_ws_reconnect(void);
static void ln_ws_reset_close_status(void);
+static bool ln_ws_check_binary_data_interrupt(void);
+static void ln_ws_reconnect_success_callback(void);
+static int ln_ws_audio_buffer_init(void);
+static void ln_ws_audio_buffer_cleanup(void);
+static int ln_ws_audio_buffer_add(const uint8_t *audio_data, uint32_t audio_size, bool finished);
+static void ln_ws_audio_buffer_flush(void);
+static int ln_ws_send_audio_data_direct(const uint8_t *audio_data, uint32_t audio_size, bool finished);
const char* ln_ws_get_connection_state_string(void);
/* Base64缓存管理函数 */
// 音频聊天结束标志
static bool g_audio_chat_ending = false;
+// 音频数据缓存结构
+typedef struct {
+ uint8_t *data; // 音频数据
+ uint32_t size; // 数据大小
+ bool finished; // 是否结束
+ uint32_t timestamp; // 时间戳
+} audio_buffer_item_t;
+
+// 音频数据缓存
+static audio_buffer_item_t *g_audio_buffer = NULL;
+static uint32_t g_audio_buffer_count = 0;
+static uint32_t g_audio_buffer_capacity = 0;
+static bool g_audio_buffering_enabled = false;
// 当前对话匹配标志
static bool g_chat_id_matched = false; // 当前对话ID是否匹配
static uint32_t g_last_audio_write_tick = 0; // 最后一次音频写入的tick
static bool g_audio_playback_active = false; // 音频播放是否活跃
static uint32_t g_audio_timeout_ticks = 1500; // 音频超时tick数(默认1.5秒)
+static uint32_t g_last_binary_data_tick = 0; // 最后一次接收二进制数据的tick
// 函数声明
static void generate_chat_id(char *chat_id, size_t size);
return -1;
}
- if (g_ws_connected != WS_STATE_CONNECTED) {
+ // 检查连接状态
+ if (g_ws_connected == WS_STATE_RECONNECTING) {
+ // 重连中,缓存音频数据
+ LN_WS_INFO("Connection reconnecting, buffering audio data (size: %u)\n", audio_size);
+ return ln_ws_audio_buffer_add(audio_data, audio_size, finished);
+ } else if (g_ws_connected != WS_STATE_CONNECTED) {
LN_WS_WARN("Cannot send audio data, connection state: %d\n", g_ws_connected);
return -1;
}
+ // 如果连接正常且有缓存数据,先刷新缓存
+ if (g_audio_buffer_count > 0) {
+ LN_WS_INFO("Connection restored, flushing %u buffered audio data items\n", g_audio_buffer_count);
+ ln_ws_audio_buffer_flush();
+ }
+
// 如果聊天未开始,生成新的聊天ID
if (!g_audio_chat_ctx.is_active) {
generate_chat_id(g_audio_chat_ctx.chat_id, sizeof(g_audio_chat_ctx.chat_id));
// 增加消息计数器
g_audio_chat_ctx.message_counter++;
+ // 如果是第一条消息,触发录音开始事件
+ if (g_audio_chat_ctx.message_counter == 1) {
+ LN_WS_INFO("First audio message, triggering recording start event\n");
+
+ // 触发录音开始事件
+ if (g_ws_message_callback != NULL) {
+ g_ws_message_callback(NULL, WS_CMD_AUDIO_RECORDING_START);
+ }
+ }
+
// 生成消息ID
char message_id[128];
generate_message_id(message_id, sizeof(message_id), g_audio_chat_ctx.chat_id, g_audio_chat_ctx.message_counter);
// 发送JSON字符串
int ret = uapi_ws_send_text(json_string);
- LN_WS_DEBUG("Sent audio data: chatId=%s, messageId=%s, size=%u, finished=%s\n",
+ LN_WS_ERROR("Sent audio data: chatId=%s, messageId=%s, size=%u, finished=%s\n",
g_audio_chat_ctx.chat_id, message_id, audio_size, finished ? "true" : "false");
// 清理内存
{
LN_WS_DEBUG("Received binary message at %u, length: %d bytes\n", timestamp, data_len);
+ // 记录接收数据的时间
+ g_last_binary_data_tick = osKernelGetTickCount();
+
if (!is_chat_id_matched()) {
LN_WS_WARN("Chat ID not matched\n");
return;
g_ws_callbacks.heartbeat_callback = ln_ws_heartbeat_callback;
g_ws_callbacks.binary_callback = ai_binary_message_handler;
g_ws_callbacks.incomplete_callback= ln_ws_incomplete_callback;
+ g_ws_callbacks.reconnect_success_callback = ln_ws_reconnect_success_callback;
// 启动WebSocket服务
int ret = uapi_ws_start(&g_ws_callbacks);
if (ret != 0) {
return -1;
}
+ // 检查是否需要在1秒内有数据时触发重连
+ bool need_reconnect = ln_ws_check_binary_data_interrupt();
+
if (g_ws_connected != WS_STATE_CONNECTED) {
LN_WS_WARN("Cannot send voice chat interrupt, connection state: %d\n", g_ws_connected);
return -1;
if (ret == 0) {
LN_WS_DEBUG("VoiceChatInterrupt sent successfully\n");
+
+ if (need_reconnect) {
+ // 如果检测到频繁数据接收,直接重连
+ LN_WS_INFO("Triggering reconnection due to frequent binary data reception\n");
+ if (ln_ws_reconnect() != 0) {
+ LN_WS_ERROR("Failed to reconnect after frequent data reception\n");
+ }
+ }
} else {
LN_WS_ERROR("Failed to send VoiceChatInterrupt\n");
}
// 清理Base64缓存
ln_ws_base64_cache_cleanup();
+ // 清理音频缓存
+ ln_ws_audio_buffer_cleanup();
+
return ret;
}
return "连接成功";
case WS_STATE_SLEEP:
return "休眠状态";
+ case WS_STATE_RECONNECTING:
+ return "重连执行中";
default:
return "未知状态";
}
data_msg->chat_id[sizeof(data_msg->chat_id) - 1] = '\0';
// 检查对话ID是否匹配当前活跃对话
- if (strcmp(g_audio_chat_ctx.chat_id, data_msg->chat_id) == 0) {
- set_chat_id_matched();
- } else {
- LN_WS_ERROR("VoiceChatResponse from non-active chat %s, ignoring\n", data_msg->chat_id);
- cJSON_Delete(root);
- return -1; // 返回错误,不处理此消息
+ if (ln_ws_check_chat_id_match(data_msg->chat_id, root) != 0) {
+ return -1; // 不匹配,已清理JSON
}
}
data_msg->chat_id[sizeof(data_msg->chat_id) - 1] = '\0';
// 检查对话ID是否匹配当前活跃对话
- if (strcmp(g_audio_chat_ctx.chat_id, data_msg->chat_id) == 0) {
- set_chat_id_matched();
- } else {
- LN_WS_WARN("ChooseStoryResponse from non-active chat %s, ignoring\n", data_msg->chat_id);
- cJSON_Delete(root);
- return -1; // 返回错误,不处理此消息
+ if (ln_ws_check_chat_id_match(data_msg->chat_id, root) != 0) {
+ return -1; // 不匹配,已清理JSON
}
}
data_msg->chat_id[sizeof(data_msg->chat_id) - 1] = '\0';
// 检查对话ID是否匹配当前活跃对话
- if (strcmp(g_audio_chat_ctx.chat_id, data_msg->chat_id) == 0) {
- set_chat_id_matched();
- } else {
- LN_WS_WARN("RandomStoryResponse from non-active chat %s, ignoring\n", data_msg->chat_id);
- cJSON_Delete(root);
- return -1; // 返回错误,不处理此消息
+ if (ln_ws_check_chat_id_match(data_msg->chat_id, root) != 0) {
+ return -1; // 不匹配,已清理JSON
}
}
case WS_CMD_AUDIO_PLAYBACK_END:
LN_WS_DEBUG("Default: Processing Audio Playback End event\n");
break;
+ case WS_CMD_AUDIO_RECORDING_START:
+ LN_WS_DEBUG("Default: Processing Audio Recording Start event\n");
+ break;
case WS_CMD_PONG:
if (data_msg) {
LN_WS_DEBUG("Default: Processing Pong message\n");
// WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] download process finished,ret=%d", ret);
// return ret;
-// }
\ No newline at end of file
+// }
+
+/**
+ * WebSocket重连函数
+ * @return 0-重连成功,-1-重连失败
+ */
+static int ln_ws_reconnect(void)
+{
+ LN_WS_INFO("Starting WebSocket reconnection\n");
+
+ // 设置重连执行中状态
+ g_ws_connected = WS_STATE_RECONNECTING;
+
+ // 使用强制重连API
+ int ret = uapi_ws_force_reconnect();
+ if (ret != 0) {
+ LN_WS_ERROR("WebSocket force reconnection failed: %d\n", ret);
+ g_ws_connected = WS_STATE_DISCONNECTED;
+ return -1;
+ }
+
+ LN_WS_INFO("WebSocket force reconnection successful\n");
+ return 0;
+}
+
+/**
+ * 检查二进制数据接收间隔,在1秒内有数据时触发重连
+ * @return true-需要重连,false-不需要重连
+ */
+static bool ln_ws_check_binary_data_interrupt(void)
+{
+#if ENABLE_BINARY_DATA_INTERRUPT_CHECK
+ uint32_t current_tick = osKernelGetTickCount();
+
+ // 如果是第一次调用,记录时间但不检查
+ if (g_last_binary_data_tick == 0) {
+ return false;
+ }
+
+ // 计算时间间隔(1秒 = 1000ms)
+ uint32_t interval_ticks = current_tick - g_last_binary_data_tick;
+ uint32_t one_second_ticks = osKernelGetTickFreq(); // 1秒的tick数
+
+ // 如果间隔小于1秒,需要重连
+ if (interval_ticks < one_second_ticks) {
+ LN_WS_WARN("Binary data received within 1 second interval (%u ticks), need to reconnect\n", interval_ticks);
+ return true;
+ }
+
+ return false;
+#else
+ // 功能被禁用,直接返回false
+ return false;
+#endif
+}
+
+/**
+ * 重连成功回调函数
+ */
+static void ln_ws_reconnect_success_callback(void)
+{
+ LN_WS_INFO("WebSocket reconnection successful, triggering reconnect success event\n");
+
+ // 触发重连成功事件
+ // if (g_ws_message_callback != NULL) {
+ // g_ws_message_callback(NULL, WS_CMD_CONNECTED);
+ // }
+ g_ws_connected = WS_STATE_CONNECTED;
+
+ LN_WS_INFO("Reconnect success event triggered\n");
+}
+
+/**
+ * 检查对话ID是否匹配当前活跃对话
+ * @param chat_id 要检查的对话ID
+ * @param root JSON根对象(用于错误时清理)
+ * @return 0-匹配成功,-1-不匹配(已清理JSON并记录错误)
+ */
+static int ln_ws_check_chat_id_match(const char *chat_id, cJSON *root)
+{
+ if (!chat_id) {
+ LN_WS_ERROR("Invalid chat_id parameter\n");
+ return -1;
+ }
+
+ // 检查对话ID是否匹配当前活跃对话
+ if (strcmp(g_audio_chat_ctx.chat_id, chat_id) == 0) {
+ set_chat_id_matched();
+ return 0; // 匹配成功
+ } else {
+ LN_WS_ERROR("Message from non-active chat %s, triggering reconnection\n", chat_id);
+ cJSON_Delete(root);
+
+ return -1; // 不匹配,已清理JSON
+ }
+}
+
+/* ============================ 音频缓存管理函数 ============================ */
+
+/**
+ * 初始化音频缓存
+ * @return 0成功,-1失败
+ */
+static int ln_ws_audio_buffer_init(void)
+{
+ if (g_audio_buffer != NULL) {
+ return 0; // 已经初始化
+ }
+
+ g_audio_buffer_capacity = 50; // 初始容量50个音频包
+ g_audio_buffer = (audio_buffer_item_t*)malloc(sizeof(audio_buffer_item_t) * g_audio_buffer_capacity);
+
+ if (!g_audio_buffer) {
+ LN_WS_ERROR("Failed to allocate audio buffer memory\n");
+ g_audio_buffer_capacity = 0;
+ return -1;
+ }
+
+ g_audio_buffer_count = 0;
+ g_audio_buffering_enabled = true;
+ LN_WS_DEBUG("Audio buffer initialized with capacity: %u\n", g_audio_buffer_capacity);
+
+ return 0;
+}
+
+/**
+ * 清理音频缓存
+ */
+static void ln_ws_audio_buffer_cleanup(void)
+{
+ if (g_audio_buffer) {
+ // 释放每个缓存项的数据
+ for (uint32_t i = 0; i < g_audio_buffer_count; i++) {
+ if (g_audio_buffer[i].data) {
+ free(g_audio_buffer[i].data);
+ }
+ }
+
+ free(g_audio_buffer);
+ g_audio_buffer = NULL;
+ g_audio_buffer_count = 0;
+ g_audio_buffer_capacity = 0;
+ g_audio_buffering_enabled = false;
+
+ LN_WS_DEBUG("Audio buffer cleaned up\n");
+ }
+}
+
+/**
+ * 添加音频数据到缓存
+ * @param audio_data 音频数据
+ * @param audio_size 数据大小
+ * @param finished 是否结束
+ * @return 0成功,-1失败
+ */
+static int ln_ws_audio_buffer_add(const uint8_t *audio_data, uint32_t audio_size, bool finished)
+{
+ if (!g_audio_buffering_enabled) {
+ LN_WS_WARN("Audio buffering not enabled\n");
+ return -1;
+ }
+
+ // 确保缓存已初始化
+ if (g_audio_buffer == NULL) {
+ if (ln_ws_audio_buffer_init() != 0) {
+ return -1;
+ }
+ }
+
+ // 检查是否需要扩容
+ if (g_audio_buffer_count >= g_audio_buffer_capacity) {
+ uint32_t new_capacity = g_audio_buffer_capacity * 2;
+ audio_buffer_item_t *new_buffer = (audio_buffer_item_t*)realloc(g_audio_buffer,
+ sizeof(audio_buffer_item_t) * new_capacity);
+ if (!new_buffer) {
+ LN_WS_ERROR("Failed to expand audio buffer\n");
+ return -1;
+ }
+
+ g_audio_buffer = new_buffer;
+ g_audio_buffer_capacity = new_capacity;
+ LN_WS_DEBUG("Audio buffer expanded to capacity: %u\n", g_audio_buffer_capacity);
+ }
+
+ // 添加新的缓存项
+ audio_buffer_item_t *item = &g_audio_buffer[g_audio_buffer_count];
+
+ if (audio_size > 0) {
+ item->data = (uint8_t*)malloc(audio_size);
+ if (!item->data) {
+ LN_WS_ERROR("Failed to allocate memory for audio buffer item\n");
+ return -1;
+ }
+ memcpy(item->data, audio_data, audio_size);
+ } else {
+ item->data = NULL;
+ }
+
+ item->size = audio_size;
+ item->finished = finished;
+ item->timestamp = osKernelGetTickCount();
+
+ g_audio_buffer_count++;
+
+ LN_WS_DEBUG("Audio data buffered: size=%u, finished=%s, total=%u\n",
+ audio_size, finished ? "true" : "false", g_audio_buffer_count);
+
+ return 0;
+}
+
+/**
+ * 刷新缓存的音频数据
+ */
+static void ln_ws_audio_buffer_flush(void)
+{
+ if (!g_audio_buffer || g_audio_buffer_count == 0) {
+ return;
+ }
+
+ LN_WS_INFO("Flushing %u buffered audio data items\n", g_audio_buffer_count);
+
+ // 逐个发送缓存的数据
+ for (uint32_t i = 0; i < g_audio_buffer_count; i++) {
+ audio_buffer_item_t *item = &g_audio_buffer[i];
+
+ // 直接调用发送函数,跳过状态检查(因为已经连接成功)
+ int ret = ln_ws_send_audio_data_direct(item->data, item->size, item->finished);
+ if (ret != 0) {
+ LN_WS_ERROR("Failed to send buffered audio data item %u\n", i);
+ }
+
+ // 释放数据内存
+ if (item->data) {
+ free(item->data);
+ }
+ }
+
+ // 重置缓存
+ g_audio_buffer_count = 0;
+ LN_WS_INFO("Audio buffer flush completed\n");
+}
+
+/**
+ * 直接发送音频数据(跳过状态检查)
+ * @param audio_data 音频数据
+ * @param audio_size 数据大小
+ * @param finished 是否结束
+ * @return 0成功,-1失败
+ */
+static int ln_ws_send_audio_data_direct(const uint8_t *audio_data, uint32_t audio_size, bool finished)
+{
+ // 对于正常音频数据,必须有有效的数据
+ if (!finished && (!audio_data || audio_size == 0)) {
+ LN_WS_ERROR("Invalid audio data parameters\n");
+ return -1;
+ }
+
+ // 如果聊天未开始,生成新的聊天ID
+ if (!g_audio_chat_ctx.is_active) {
+ generate_chat_id(g_audio_chat_ctx.chat_id, sizeof(g_audio_chat_ctx.chat_id));
+ g_audio_chat_ctx.message_counter = 0;
+ g_audio_chat_ctx.is_active = true;
+ // 重置对话ID匹配标志
+ reset_chat_id_match();
+ LN_WS_DEBUG("New chat started: %s\n", g_audio_chat_ctx.chat_id);
+ }
+
+ // 增加消息计数器
+ g_audio_chat_ctx.message_counter++;
+
+ // 如果是第一条消息,触发录音开始事件
+ if (g_audio_chat_ctx.message_counter == 1) {
+ LN_WS_INFO("First audio message, triggering recording start event\n");
+
+ // 触发录音开始事件
+ if (g_ws_message_callback != NULL) {
+ g_ws_message_callback(NULL, WS_CMD_AUDIO_RECORDING_START);
+ }
+ }
+
+ // 生成消息ID
+ char message_id[128];
+ generate_message_id(message_id, sizeof(message_id), g_audio_chat_ctx.chat_id, g_audio_chat_ctx.message_counter);
+
+ // Base64编码音频数据(如果是结束消息,则使用空字符串)
+ char *audio_base64 = NULL;
+ if (audio_size == 0) {
+ // 结束消息,使用空字符串
+ audio_base64 = (char*)malloc(1);
+ if (!audio_base64) {
+ LN_WS_ERROR("Failed to allocate memory for base64 encoding\n");
+ return -1;
+ }
+ audio_base64[0] = '\0';
+ } else {
+ // 正常音频数据,进行Base64编码
+ size_t base64_size = audio_size * 2; //((audio_size + 2) / 3) * 4 + 1;
+ audio_base64 = (char*)malloc(base64_size);
+ if (!audio_base64) {
+ LN_WS_ERROR("Failed to allocate memory for base64 encoding\n");
+ return -1;
+ }
+
+ size_t output_len = 0;
+ int ret_encode = mbedtls_base64_encode((unsigned char*)audio_base64, base64_size - 1, &output_len,
+ audio_data, audio_size);
+ if (ret_encode != 0) {
+ LN_WS_DEBUG("Base64 encoding failed: %d\n", ret_encode);
+ free(audio_base64);
+ return -1;
+ }
+ audio_base64[output_len] = '\0';
+ }
+
+ // 获取当前时间戳
+ uint32_t timestamp;
+ uapi_get_timestampe_ss(×tamp);
+
+ // 创建JSON消息
+ cJSON *json = cJSON_CreateObject();
+ if (!json) {
+ LN_WS_ERROR("Failed to create JSON object\n");
+ free(audio_base64);
+ return -1;
+ }
+
+ // 添加基本字段
+ cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+ cJSON_AddNumberToObject(json, "timestamp", (double)timestamp);
+ cJSON_AddStringToObject(json, "messageId", message_id);
+
+ // 根据命令类型设置不同的command
+ const char *command_str = (g_audio_chat_command_type == LN_AUDIO_CHAT_VOICE_CHAT_REQUEST) ?
+ "VoiceChatRequest" : "ChooseStoryRequest";
+ cJSON_AddStringToObject(json, "command", command_str);
+
+ // 创建data对象
+ cJSON *data_obj = cJSON_CreateObject();
+ if (!data_obj) {
+ LN_WS_ERROR("Failed to create data object\n");
+ cJSON_Delete(json);
+ free(audio_base64);
+ return -1;
+ }
+
+ cJSON_AddStringToObject(data_obj, "audioBase64", audio_base64);
+ cJSON_AddStringToObject(data_obj, "chatId", g_audio_chat_ctx.chat_id);
+ cJSON_AddBoolToObject(data_obj, "finished", finished);
+
+ cJSON_AddItemToObject(json, "data", data_obj);
+
+ // 转换为字符串
+ char *json_string = cJSON_Print(json);
+ if (!json_string) {
+ LN_WS_ERROR("Failed to print JSON\n");
+ cJSON_Delete(json);
+ free(audio_base64);
+ return -1;
+ }
+
+ // 发送JSON字符串
+ int ret = uapi_ws_send_text(json_string);
+
+ LN_WS_ERROR("Sent audio data: chatId=%s, messageId=%s, size=%u, finished=%s\n",
+ g_audio_chat_ctx.chat_id, message_id, audio_size, finished ? "true" : "false");
+
+ // 清理内存
+ cJSON_free(json_string);
+ free(audio_base64);
+ cJSON_Delete(json);
+
+ // 如果音频结束,重置聊天上下文
+ if (finished) {
+ g_audio_chat_ctx.is_active = false;
+ LN_WS_DEBUG("Chat ended: %s\n", g_audio_chat_ctx.chat_id);
+ // 重置对话ID匹配标志
+ reset_chat_id_match();
+ }
+
+ return ret;
+}
\ No newline at end of file
#define WS_STATE_CONNECTING 1 // 连接中
#define WS_STATE_CONNECTED 2 // 连接成功
#define WS_STATE_SLEEP 3 // 休眠状态
+#define WS_STATE_RECONNECTING 4 // 重连执行中
/* WebSocket关闭状态枚举 */
typedef enum {
static osMessageQueueId_t g_ws_msg_queue = NULL;
static ws_call_backs_t g_ws_callbacks = {0}; /* WebSocket回调函数结构体 */
static volatile ws_close_status_t g_ws_close_status = WS_CLOSE_NOT_EXECUTED; /* WebSocket关闭状态标志位 */
+static volatile int g_ws_is_reconnecting = 0; /* 是否正在重连的标志位 */
/* 连接超时检测相关变量 */
static time_t g_ws_connect_start_time = 0; /* 连接开始时间 */
g_ws_connected = WS_STATE_CONNECTED;
uapi_ws_reset_close_status(); // 连接成功时重置关闭状态
uapi_ws_reset_connect_timer(); // 连接成功时重置超时计时器
- HAISI_WS_DEBUG("连接状态: 连接成功, 关闭状态已重置为 NOT_EXECUTED (%d)\n", g_ws_close_status);
+
+ HAISI_WS_INFO("连接状态: 连接成功, 关闭状态已重置为 NOT_EXECUTED (%d)\n", g_ws_close_status);
+
+ // 检查是否是从重连状态恢复的连接
+ if (g_ws_is_reconnecting) {
+ HAISI_WS_INFO("Reconnection successful, triggering reconnect success callback\n");
+ g_ws_is_reconnecting = 0; // 重置重连标志
+
+ // 触发重连成功回调
+ if (g_ws_callbacks.reconnect_success_callback != NULL) {
+ g_ws_callbacks.reconnect_success_callback();
+ } else {
+ HAISI_WS_DEBUG("No reconnect success callback registered\n");
+ }
+ }
}
/*
while (g_ws_running) {
// 处理队列消息(非阻塞)
- if (osMessageQueueGet(g_ws_msg_queue, &msg, NULL, 1000) == osOK) {
- HAISI_WS_DEBUG("osMessageQueueGet: g_ws_msg_queue\n");
- switch (msg->msg_type) {
- case WS_MSG_TYPE_SEND_TEXT:
- if (g_ws_connected == WS_STATE_CONNECTED && g_ws_client_fd >= 0) {
- // 对于文本消息,我们需要特殊处理,因为现在data是ws_data_msg_t类型
- // 这里需要重新设计文本消息的存储方式
- HAISI_WS_WARN("Text message type not supported in new structure\n");
- } else {
- HAISI_WS_WARN("Cannot send text, connection state: %d\n", g_ws_connected);
- }
- ws_msg_free(msg);
- break;
-
- case WS_MSG_TYPE_FORCE_RECONNECT:
- HAISI_WS_INFO("Force reconnect requested\n");
- if (g_ws_client_fd >= 0) {
- HAISI_WS_DEBUG("WebSocketClientClose\n");
- uapi_ws_close_with_status(g_ws_client_fd);
- g_ws_client_fd=-1;
- HAISI_WS_DEBUG("WebSocketClientClose end\n");
- }
- g_ws_connected = WS_STATE_DISCONNECTED;
- HAISI_WS_INFO("连接状态: 未连接(强制重连)\n");
- ws_msg_free(msg);
- break;
-
- case WS_MSG_TYPE_STOP:
- HAISI_WS_INFO("Stop requested from queue\n");
- g_ws_running = 0;
- ws_msg_free(msg);
- break;
-
- case WS_MSG_TYPE_RAW_MESSAGE:
- {
- HAISI_WS_DEBUG("Received raw message: %s, timestamp: %u, isBinary: %s\n",
- msg->raw_data, msg->timestamp, msg->isBinary ? "true" : "false");
+ if (g_ws_connected == WS_STATE_CONNECTED)
+ {
+ if (osMessageQueueGet(g_ws_msg_queue, &msg, NULL, 0) == osOK) {
+ HAISI_WS_DEBUG("osMessageQueueGet: g_ws_msg_queue\n");
+ switch (msg->msg_type) {
+ case WS_MSG_TYPE_SEND_TEXT:
+ if (g_ws_connected == WS_STATE_CONNECTED && g_ws_client_fd >= 0) {
+ // 对于文本消息,我们需要特殊处理,因为现在data是ws_data_msg_t类型
+ // 这里需要重新设计文本消息的存储方式
+ HAISI_WS_WARN("Text message type not supported in new structure\n");
+ } else {
+ HAISI_WS_WARN("Cannot send text, connection state: %d\n", g_ws_connected);
+ }
+ ws_msg_free(msg);
+ break;
- // 根据消息类型调用不同的回调函数
- if (!msg->isBinary) {
-
- // 文本消息
- if (g_ws_callbacks.message_callback != NULL) {
- g_ws_callbacks.message_callback(msg->raw_data, msg->timestamp);
- } else {
- HAISI_WS_WARN("No text message callback registered\n");
+ case WS_MSG_TYPE_FORCE_RECONNECT:
+ HAISI_WS_INFO("Force reconnect requested\n");
+ if (g_ws_client_fd >= 0) {
+ HAISI_WS_DEBUG("WebSocketClientClose\n");
+ uapi_ws_close_with_status(g_ws_client_fd);
+ g_ws_client_fd=-1;
+ HAISI_WS_DEBUG("WebSocketClientClose end\n");
+ }
+ g_ws_connected = WS_STATE_DISCONNECTED;
+ HAISI_WS_INFO("连接状态: 未连接(强制重连)\n");
+ ws_msg_free(msg);
+ break;
+
+ case WS_MSG_TYPE_STOP:
+ HAISI_WS_INFO("Stop requested from queue\n");
+ g_ws_running = 0;
+ ws_msg_free(msg);
+ break;
+
+ case WS_MSG_TYPE_RAW_MESSAGE:
+ {
+ HAISI_WS_DEBUG("Received raw message: %s, timestamp: %u, isBinary: %s\n",
+ msg->raw_data, msg->timestamp, msg->isBinary ? "true" : "false");
+
+ // 根据消息类型调用不同的回调函数
+ if (!msg->isBinary) {
+
+ // 文本消息
+ if (g_ws_callbacks.message_callback != NULL) {
+ g_ws_callbacks.message_callback(msg->raw_data, msg->timestamp);
+ } else {
+ HAISI_WS_WARN("No text message callback registered\n");
+ }
}
+ // 处理完消息后释放内存
+ ws_msg_free(msg);
}
- // 处理完消息后释放内存
+ break;
+
+ default:
+ HAISI_WS_WARN("Unknown message type: %d\n", msg->msg_type);
ws_msg_free(msg);
- }
- break;
-
- default:
- HAISI_WS_WARN("Unknown message type: %d\n", msg->msg_type);
- ws_msg_free(msg);
- break;
+ break;
+ }
+ }
+ else
+ {
+ // HAISI_WS_DEBUG("osMessageQueueGet timeout or failed\r\n");
}
- }
- else
- {
- // HAISI_WS_DEBUG("osMessageQueueGet timeout or failed\r\n");
}
// 检测连接状态变化并触发事件回调
continue;
}
+ if (g_ws_connected == WS_STATE_RECONNECTING) {
+ // 重连执行中状态:等待断开完成,然后开始重新连接
+ HAISI_WS_DEBUG("Reconnecting mode: waiting for disconnect completion\n");
+ if (g_ws_client_fd < 0) {
+ // 断开完成,开始重新连接
+ HAISI_WS_INFO("Disconnect completed, starting reconnection\n");
+ g_ws_connected = WS_STATE_DISCONNECTED;
+ } else {
+ // 等待断开完成
+ usleep(100 * 1000); // 等待100ms
+ }
+ continue;
+ }
+
if (g_ws_connected == WS_STATE_DISCONNECTED) {
if (g_ws_client_fd >= 0) {
{
g_ws_callbacks.url_callback(url, sizeof(url), header_buf, sizeof(header_buf));
}
- HAISI_WS_DEBUG("尝试连接WebSocket: %s\n", url);
+ HAISI_WS_INFO("尝试连接WebSocket: %s\n", url);
HAISI_WS_DEBUG("使用Header: %s\n", header_buf);
int ret=0;
if(strlen(header_buf)==0)
}
/* 1秒间隔 */
- if(g_ws_connected!=WS_STATE_CONNECTED)
+ // if(g_ws_connected!=WS_STATE_CONNECTED)
{
usleep(1000 * 1000);
int uapi_ws_force_reconnect(void)
{
if (!g_ws_running) return -1;
+
+ HAISI_WS_INFO("Starting WebSocket force reconnection\n");
- ws_msg_info_t *msg = ws_msg_create(0);
- if (msg == NULL) {
- HAISI_WS_ERROR("Failed to create force reconnect message\n");
- return -1;
+ // 设置重连执行中状态和重连标志
+ g_ws_connected = WS_STATE_RECONNECTING;
+ g_ws_is_reconnecting = 1; // 标记正在重连
+
+ if (g_ws_client_fd >= 0) {
+ HAISI_WS_DEBUG("Disconnecting uapi_ws_force_reconnect\n");
+ uapi_ws_close_with_status(g_ws_client_fd);
}
- msg->msg_type = WS_MSG_TYPE_FORCE_RECONNECT;
- msg->timestamp = 0; // 控制消息不需要时间戳
- msg->isBinary = false; // 控制消息不是二进制数据
-
- osStatus_t ret = osMessageQueuePut(g_ws_msg_queue, &msg, 0, 0);
- if (ret != osOK) {
- ws_msg_free(msg);
- return -1;
- }
+ HAISI_WS_INFO("WebSocket force reconnection initiated\n");
return 0;
}
return "连接成功";
case WS_STATE_SLEEP:
return "休眠状态";
+ case WS_STATE_RECONNECTING:
+ return "重连执行中";
default:
return "未知状态";
}
#endif
}
+/**
+ * @brief 注册重连成功回调函数(公共接口)
+ * @param callback 回调函数
+ */
+void uapi_ws_register_reconnect_success_callback(ws_reconnect_success_callback_t callback)
+{
+ g_ws_callbacks.reconnect_success_callback = callback;
+ if (callback != NULL) {
+ HAISI_WS_DEBUG("Reconnect success callback registered successfully\n");
+ } else {
+ HAISI_WS_DEBUG("Reconnect success callback unregistered\n");
+ }
+}
+
/**
* @brief 重置连接超时计时器
*/