增加vad 雷鸟对话,仅可自动结束 2604/2 2604/head
authorhcj <1224667075@qq.com>
Sat, 25 Oct 2025 09:08:12 +0000 (17:08 +0800)
committerhcj <1224667075@qq.com>
Sat, 25 Oct 2025 09:08:12 +0000 (17:08 +0800)
code/sdk/zhihui/leiniao/imsl_ln/ln_api.h
code/sdk/zhihui/leiniao/imsl_ln/ln_api_websocket.c

index 4b8dff6..242f0af 100644 (file)
@@ -381,6 +381,7 @@ typedef enum {
     WS_CMD_AUDIO_PLAYBACK_START,     /* 音频播放开始 */
     WS_CMD_AUDIO_PLAYBACK_END,       /* 音频播放结束 */
     WS_CMD_AUDIO_RECORDING_START,    /* 开始录音上传 */
+    WS_CMD_AUDIO_RECORDING_END,      /* 结束录音上传 */
     WS_CMD_SENTENCE_PLAYBACK_COMPLETE, /* 单句语音播放完成 */
     WS_CMD_MAX                       /* 最大命令 */
 } ws_command_t;
index bd1dfb9..6e84e58 100644 (file)
@@ -152,6 +152,9 @@ static audio_chat_context_t g_audio_chat_ctx = {0};
 // 音频聊天结束标志
 static bool g_audio_chat_ending = false;
 
+// 录音上传状态跟踪
+static bool g_recording_upload_started = false;
+
 // 音频数据缓存结构
 typedef struct {
     uint8_t *data;          // 音频数据
@@ -176,6 +179,11 @@ static uint32_t g_audio_timeout_ticks = 1500; // 音频超时tick数(默认1.5
 static uint32_t g_last_binary_data_tick = 0;  // 最后一次接收二进制数据的tick
 static uint32_t g_audio_playback_start_tick = 0;  // 音频播放开始时间tick
 
+// VAD冷却时间相关变量
+static uint32_t g_vad_cooldown_start_tick = 0;  // VAD冷却开始时间tick
+static bool g_vad_cooldown_active = false;       // VAD冷却是否激活
+static uint32_t g_vad_cooldown_duration_ms = 3000; // VAD冷却持续时间(毫秒)
+
 // 音频时长记录循环数组
 #define AUDIO_DURATION_BUFFER_SIZE 50
 
@@ -197,6 +205,8 @@ static void set_chat_id_matched(void);
 static bool is_chat_id_matched(void);
 static bool is_active_chat_response(const char *chat_id, const char *response_id);
 static void ln_ws_audio_write_callback(uint32_t size);
+static bool ln_ws_is_vad_cooldown_active(void);
+static void ln_ws_start_vad_cooldown(void);
 
 
 
@@ -667,6 +677,9 @@ int ln_ws_start_audio_chat(ln_audio_chat_command_t command_type)
     // 重置对话ID匹配标志
     reset_chat_id_match();
     
+    // 重置录音上传状态
+    g_recording_upload_started = false;
+    
     const char *command_name = (command_type == LN_AUDIO_CHAT_VOICE_CHAT_REQUEST) ? 
                               "VoiceChatRequest" : "ChooseStoryRequest";
     
@@ -690,6 +703,12 @@ int ln_ws_end_audio_chat(void)
     }
     LN_WS_DEBUG("Ending audio chat: %s, total messages: %u\n", 
            g_audio_chat_ctx.chat_id, g_audio_chat_ctx.message_counter);
+    
+    // 安全检查:如果录音上传状态异常,记录警告
+    if (!g_recording_upload_started) {
+        LN_WS_WARN("Recording upload was not started, but ending audio chat\n");
+    }
+    
     // 设置结束标志,等待下次AIVoiceDataCallback_ln调用时发送结束消息
     g_audio_chat_ending = true;
     
@@ -706,6 +725,12 @@ static void AIVoiceDataCallback_ln(const uint8_t* data, uint32_t size, void* use
 {
     (void)userData;
     
+    // 状态一致性检查:如果音频聊天未激活但录音上传状态为true,重置状态
+    if (!g_audio_chat_ctx.is_active && g_recording_upload_started) {
+        LN_WS_WARN("Audio chat not active but recording upload started, resetting state\n");
+        g_recording_upload_started = false;
+    }
+    
     // MEDIA_INFO_LOG("Received audio data: size=%u bytes", size);
     
     // ========== VAD 处理已移到 ln_ws_send_audio_data (录音接口层) ==========
@@ -719,8 +744,8 @@ static void AIVoiceDataCallback_ln(const uint8_t* data, uint32_t size, void* use
             if (ret != ERRCODE_SUCC) {
                 /* 静默失败,避免过多日志 */
             } else {
-                LN_WS_DEBUG("VAD: Sent %u bytes (format=%d, is_last=%d)\n", 
-                           size, format, false);
+                // LN_WS_DEBUG("VAD: Sent %u bytes (format=%d, is_last=%d)\n", 
+                        //    size, format, false);
             }
         }
         
@@ -729,6 +754,10 @@ static void AIVoiceDataCallback_ln(const uint8_t* data, uint32_t size, void* use
             LN_WS_INFO("VAD: Audio recording ended\n");
         }
     }
+    else
+    {
+         LN_WS_INFO("VAD: Audio g_vad_server_enabled g_vad_server_initialized vad_server_is_running\n");
+    }
     #endif
 
     
@@ -737,18 +766,45 @@ static void AIVoiceDataCallback_ln(const uint8_t* data, uint32_t size, void* use
     {
          if (g_audio_chat_ending) {
             LN_WS_DEBUG("Sending audio chat end message\n");
+            
+            // 触发结束录音上传事件
+            // 增加多重判断确保不会重复触发:
+            // 1. 录音上传状态已开始
+            // 2. 音频聊天上下文激活
+            // 3. 回调函数已注册
+            if (g_recording_upload_started && g_ws_message_callback != NULL) {
+                LN_WS_INFO("Triggering WS_CMD_AUDIO_RECORDING_END event\n");
+                g_ws_message_callback(NULL, WS_CMD_AUDIO_RECORDING_END);
+                g_recording_upload_started = false;
+            }
+            
             // 发送结束消息
             ln_ws_send_audio_data(data, size, true);
+            // AI_SendAudioDataToQueue(data, size);
             // 重置聊天上下文和结束标志
             g_audio_chat_ctx.is_active = false;
             g_audio_chat_ending = false;
         }
         else
         {
+            // 触发开始录音上传事件(仅在第一次发送时触发)
+            // 增加多重判断确保不会重复触发:
+            // 1. 录音上传状态未开始
+            // 2. 音频聊天上下文激活
+            // 3. 有有效的音频数据
+            // 4. 回调函数已注册
+            if (!g_recording_upload_started && g_ws_message_callback != NULL) {
+                LN_WS_INFO("Triggering WS_CMD_AUDIO_RECORDING_START event\n");
+                g_ws_message_callback(NULL, WS_CMD_AUDIO_RECORDING_START);
+                g_recording_upload_started = true;
+            }
+            
             // 使用新的音频发送接口
             ln_ws_send_audio_data(data, size, false);
+            // AI_SendAudioDataToQueue(data, size);
         }
     }
+    LOS_Msleep(10);
 }
 
 // "audioBase64":
@@ -972,6 +1028,38 @@ int ln_ws_start(ws_message_callback_t_ln callback, uint32_t audio_timeout_ticks)
     return 0;
 }
 
+void vad_status_callback_ln_ws(int status)
+{
+    LN_WS_INFO("Audio vad_status_callback_ln_ws %d\n",status);
+    if(g_audio_playback_active)
+    {
+        // ln_ws_start_vad_cooldown();
+         LN_WS_INFO("g_audio_playback_active %d\n",g_audio_playback_active);
+        return;
+    }
+
+    // if(status==1)
+    // {
+    //     // 检查是否在VAD冷却时间内
+    //     if(ln_ws_is_vad_cooldown_active())
+    //     {
+    //         LN_WS_INFO("VAD cooldown active, ignoring start request\n");
+    //         return;
+    //     }
+
+    //     ln_ws_start_audio_chat(LN_AUDIO_CHAT_VOICE_CHAT_REQUEST);
+    // }
+    // else
+    if (status==2)
+    {
+        ln_ws_end_audio_chat();
+        // 开始VAD冷却计时
+        ln_ws_start_vad_cooldown();
+    }
+    
+
+}
+
 void ln_ws_audio_init(void)
 {
     // 检查是否已经初始化
@@ -1007,9 +1095,11 @@ void ln_ws_audio_init(void)
     
 #if ENABLE_VAD_SERVER
     // 如果 VAD 服务器已启用,则初始化 VAD 服务器
+    ln_ws_enable_vad_server();
+
     if (g_vad_server_enabled && !g_vad_server_initialized) {
         LN_WS_INFO("Initializing VAD server...\n");
-        errcode_t ret = vad_server_init(NULL);  // 使用 NULL 回调,也可以传入自定义回调
+        errcode_t ret = vad_server_init(vad_status_callback_ln_ws);  // 使用 NULL 回调,也可以传入自定义回调
         if (ret == ERRCODE_SUCC) {
             g_vad_server_initialized = true;
             LN_WS_INFO("VAD server initialized successfully\n");
@@ -1081,7 +1171,7 @@ int ln_ws_enable_vad_server(void)
     
     // 如果音频已经初始化,立即初始化 VAD 服务器
     if (g_audio_initialized && !g_vad_server_initialized) {
-        errcode_t ret = vad_server_init(NULL);
+        errcode_t ret = vad_server_init(vad_status_callback_ln_ws);
         if (ret == ERRCODE_SUCC) {
             g_vad_server_initialized = true;
             LN_WS_INFO("VAD server initialized successfully\n");
@@ -2852,3 +2942,35 @@ static bool check_playback_completion_by_timeout(void)
     
     return false; // 播放未完成
 }
+
+// ===== VAD冷却时间管理函数 =====
+
+// 检查VAD冷却时间是否激活
+static bool ln_ws_is_vad_cooldown_active(void)
+{
+    if (!g_vad_cooldown_active) {
+        return false;
+    }
+    
+    uint32_t current_tick = osKernelGetTickCount();
+    uint32_t elapsed_ms = current_tick - g_vad_cooldown_start_tick;
+    
+    // 如果冷却时间已过,重置冷却状态
+    if (elapsed_ms >= g_vad_cooldown_duration_ms) {
+        g_vad_cooldown_active = false;
+        LN_WS_INFO("VAD cooldown period ended, elapsed: %u ms\n", elapsed_ms);
+        return false;
+    }
+    
+    LN_WS_DEBUG("VAD cooldown active, remaining: %u ms\n", 
+               g_vad_cooldown_duration_ms - elapsed_ms);
+    return true;
+}
+
+// 开始VAD冷却计时
+static void ln_ws_start_vad_cooldown(void)
+{
+    g_vad_cooldown_start_tick = osKernelGetTickCount();
+    g_vad_cooldown_active = true;
+    LN_WS_INFO("VAD cooldown started, duration: %u ms\n", g_vad_cooldown_duration_ms);
+}