/* 回调函数结构体 */
static ws_call_backs_t g_ws_callbacks = {0};
+/* Ping 超时检测相关变量 */
+static uint32_t g_ping_send_tick = 0; /* Ping 发送时间(tick) */
+static bool g_ping_timeout_active = false; /* Ping 超时检测是否激活 */
+#define LN_WS_PING_TIMEOUT_MS 3000 /* Ping 超时时间(毫秒),默认3秒 */
+
static void ln_ws_build_url(char *out, size_t out_size);
int ln_ws_send_ping(void);
static ws_command_t ln_ws_parse_command_string(const char *command_str);
(void)client;
LN_WS_DEBUG("WebSocketClientConstructor ln_ws_on_open\r\n");
g_ws_connected = WS_STATE_CONNECTED;
+ // 重置 ping 超时状态
+ g_ping_timeout_active = false;
+ g_ping_send_tick = 0;
LN_WS_DEBUG("连接状态: 连接成功\n");
}
(void)timestamp;
if (raw_data == NULL) return;
+ // 收到任何消息时,清除 ping 超时检测
+ if (g_ping_timeout_active) {
+ g_ping_timeout_active = false;
+ LN_WS_DEBUG("Ping timeout detection cancelled due to received message\n");
+ }
+
size_t length = strlen(raw_data);
char *buf = (char *)malloc(length + 1);
if (!buf) return;
case WS_EVENT_CONNECTED:
LN_WS_INFO("Event: Connected\n");
g_ws_connected = WS_STATE_CONNECTED;
+ // 重置 ping 超时状态
+ g_ping_timeout_active = false;
+ g_ping_send_tick = 0;
// 触发连接成功事件
if (g_ws_message_callback != NULL) {
case WS_EVENT_DISCONNECTED:
LN_WS_INFO("Event: Disconnected\n");
g_ws_connected = WS_STATE_DISCONNECTED;
+ // 重置 ping 超时状态
+ g_ping_timeout_active = false;
+ g_ping_send_tick = 0;
// 触发断连事件
if (g_ws_message_callback != NULL) {
check_playback_completion_by_timeout();
}
+ // 检查检活 ping 超时(仅在检活接口调用后检查)
+ if (g_ping_timeout_active && g_ws_connected == WS_STATE_CONNECTED) {
+ uint32_t current_tick = osKernelGetTickCount();
+ uint32_t elapsed_ticks = current_tick - g_ping_send_tick;
+ uint32_t tick_freq = osKernelGetTickFreq(); // 获取 tick 频率(tick/秒)
+ uint32_t timeout_ticks = (LN_WS_PING_TIMEOUT_MS * tick_freq) / 1000; // 将毫秒转换为 tick 数
+
+ if (elapsed_ticks >= timeout_ticks) {
+ uint32_t elapsed_ms = (elapsed_ticks * 1000) / tick_freq; // 转换为毫秒用于日志
+ LN_WS_ERROR("Keepalive ping timeout detected: elapsed %u ms (timeout: %u ms), triggering reconnection\n",
+ elapsed_ms, LN_WS_PING_TIMEOUT_MS);
+
+ // 清除超时状态
+ g_ping_timeout_active = false;
+ g_ping_send_tick = 0;
+
+ // 触发重连
+ if (ln_ws_reconnect() != 0) {
+ LN_WS_ERROR("Failed to reconnect after keepalive ping timeout\n");
+ }
+ }
+ }
+
if (heartbeat_counter >= LN_WS_HEARTBEAT_COUNTER_THRESHOLD) { // 30秒心跳间隔
heartbeat_counter = 0;
LN_WS_DEBUG("Sending heartbeat (interval: %u ms, threshold: %u)\n",
}
+/**
+ * @brief 发送ping并启动检活超时检测
+ * @return 0成功,-1失败
+ * @note 调用此接口后,如果超时(默认3秒)未收到任何消息,将触发重连
+ */
int ln_ws_send_ping(void)
{
if (g_ws_connected != WS_STATE_CONNECTED) {
// 发送 JSON 字符串
int ret = uapi_ws_send_text(json_string);
- LN_WS_DEBUG("Sent ping: %s\n", json_string);
+ if (ret == 0) {
+ // 发送成功,记录发送时间并启动超时检测
+ g_ping_send_tick = osKernelGetTickCount();
+ g_ping_timeout_active = true;
+ LN_WS_DEBUG("Sent ping: %s, keepalive timeout detection activated (timeout: %u ms)\n",
+ json_string, LN_WS_PING_TIMEOUT_MS);
+ } else {
+ LN_WS_ERROR("Failed to send ping: %s\n", json_string);
+ }
// 清理内存
cJSON_free(json_string);
{
LN_WS_INFO("Received binary message at %u, length: %d bytes\n", timestamp, data_len);
+ // 收到二进制消息时,清除 ping 超时检测
+ if (g_ping_timeout_active) {
+ g_ping_timeout_active = false;
+ LN_WS_DEBUG("Ping timeout detection cancelled due to received binary message\n");
+ }
+
// 记录接收数据的时间
g_last_binary_data_tick = osKernelGetTickCount();
g_vad_cooldown_active = false;
void ln_ws_audio_init(bool is_vad_server_enabled)
{
+ // is_vad_server_enabled=false;
// 检查是否已经初始化
if (g_audio_initialized) {
LN_WS_WARN("Audio already initialized, skipping duplicate initialization\n");
LN_WS_INFO("WebSocket reconnection successful, triggering reconnect success event\n");
g_ws_connected = WS_STATE_CONNECTED;
+ // 重置 ping 超时状态
+ g_ping_timeout_active = false;
+ g_ping_send_tick = 0;
if(strlen(story_theme_cache)>3)
{
last_error.errorMessage=NULL;
}
last_error.errorCode=error.errorCode;
- last_error.errorMessage=malloc(strlen(error.errorMessage));
- memcpy(last_error.errorMessage,error.errorMessage,strlen(error.errorMessage));
-
+ last_error.errorMessage=malloc(strlen(error.errorMessage) + 1);
+ memcpy(last_error.errorMessage, error.errorMessage, strlen(error.errorMessage));
HAISI_WS_ERROR("WebSocketClientConstructor error: code=%d msg=%s\n", error.errorCode, error.errorMessage);
+
+ // 触发错误回调
+ if (g_ws_callbacks.error_callback != NULL) {
+ g_ws_callbacks.error_callback(error.errorCode, error.errorMessage);
+ } else {
+ HAISI_WS_DEBUG("No error callback registered\n");
+ }
}
/* 断开回调:标记为未连接。是否自动重连交由上层决定 */
{
ret= WebSocketClientConnect(g_ws_client_fd, url, header_buf);
}
+
+
// int ret = WebSocketClientConnect(g_ws_client_fd,"ws://118.145.158.207:22080/chat/ws?platform=huoshan");
else
{
g_ws_connected = WS_STATE_CONNECTING;
+ g_ws_close_status = WS_CLOSE_NOT_EXECUTED;
}
/* 连接请求已发送,等待握手完成 */
HAISI_WS_DEBUG("连接请求已发送,等待握手完成...\n");
} else {
HAISI_WS_WARN("No event callback registered\n");
}
+
+ if (g_ws_callbacks.error_callback != NULL) {
+ HAISI_WS_DEBUG("Error callback registered\n");
+ } else {
+ HAISI_WS_DEBUG("No error callback registered\n");
+ }
} else {
memset(&g_ws_callbacks, 0, sizeof(ws_call_backs_t));
HAISI_WS_DEBUG("No callbacks provided, using defaults\n");
}
}
+/**
+ * @brief 注册错误回调函数(公共接口)
+ * @param callback 回调函数
+ */
+void uapi_ws_register_error_callback(ws_error_callback_t callback)
+{
+ g_ws_callbacks.error_callback = callback;
+ if (callback != NULL) {
+ HAISI_WS_DEBUG("Error callback registered successfully\n");
+ } else {
+ HAISI_WS_DEBUG("Error callback unregistered\n");
+ }
+}
+
/**
* @brief 获取主线程循环间隔时长(公共接口)
* @return 当前间隔时长(毫秒)