// 音频聊天结束标志
static bool g_audio_chat_ending = false;
+// 录音上传状态跟踪
+static bool g_recording_upload_started = false;
+
// 音频数据缓存结构
typedef struct {
uint8_t *data; // 音频数据
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
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);
// 重置对话ID匹配标志
reset_chat_id_match();
+ // 重置录音上传状态
+ g_recording_upload_started = false;
+
const char *command_name = (command_type == LN_AUDIO_CHAT_VOICE_CHAT_REQUEST) ?
"VoiceChatRequest" : "ChooseStoryRequest";
}
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;
{
(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 (录音接口层) ==========
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);
}
}
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
{
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":
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)
{
// 检查是否已经初始化
#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");
// 如果音频已经初始化,立即初始化 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");
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);
+}