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
+
+// 音频数据最近缓存(环形缓冲区,仅保留最近数据)
+#define AUDIO_CACHE_BUFFER_SIZE 1024 // 8KB缓存
+static uint8_t g_audio_cache_buffer[AUDIO_CACHE_BUFFER_SIZE];
+static uint32_t g_audio_cache_pos = 0; // 当前写入位置
+static uint32_t g_audio_cache_total = 0; // 总写入数据量
+static bool g_audio_cache_wrapped = false; // 是否已循环
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冷却持续时间(毫秒)
+static uint32_t g_vad_cooldown_duration_ms = 10000; // VAD冷却持续时间(毫秒)
// 音频时长记录循环数组
#define AUDIO_DURATION_BUFFER_SIZE 50
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);
+static void ln_ws_add_to_audio_cache(const uint8_t* data, uint32_t size);
+static uint32_t ln_ws_get_audio_cache(const uint8_t** buffer);
+static void ln_ws_reset_audio_cache(void);
+static uint32_t ln_ws_copy_from_ring_cache(uint32_t start_pos, uint32_t length, uint8_t* output);
+static int ln_ws_send_cached_audio_data(void);
// 重置录音上传状态
g_recording_upload_started = false;
+
const char *command_name = (command_type == LN_AUDIO_CHAT_VOICE_CHAT_REQUEST) ?
"VoiceChatRequest" : "ChooseStoryRequest";
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_cached_audio_data();
+ // ln_ws_reset_audio_cache();
}
+
// 使用新的音频发送接口
ln_ws_send_audio_data(data, size, false);
// AI_SendAudioDataToQueue(data, size);
}
}
+ else
+ {
+ if (data && size > 0) {
+ ln_ws_add_to_audio_cache(data, size);
+ }
+ }
LOS_Msleep(10);
}
// 记录接收数据的时间
g_last_binary_data_tick = osKernelGetTickCount();
- if (!is_chat_id_matched()) {
- LN_WS_WARN("Chat ID not matched\n");
- return;
- }
+ // if (!is_chat_id_matched()) {
+ // LN_WS_WARN("Chat ID not matched\n");
+ // return;
+ // }
if (!raw_data || data_len == 0) {
LN_WS_ERROR("Invalid binary data parameters\n");
return ret;
}
- //ln_ws_audio_init();
+ ln_ws_audio_init();
// 注册音频数据写入回调
AI_RegisterWriteAudioDataCallback(ln_ws_audio_write_callback);
return;
}
- // if(status==1)
- // {
- // // 检查是否在VAD冷却时间内
- // if(ln_ws_is_vad_cooldown_active())
- // {
- // LN_WS_INFO("VAD cooldown active, ignoring start request\n");
- // 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
+ ln_ws_start_audio_chat(LN_AUDIO_CHAT_VOICE_CHAT_REQUEST);
+ }
+ else
if (status==2)
{
ln_ws_end_audio_chat();
+ if(g_audio_chat_ctx.is_active)
+ {
+ ln_ws_start_vad_cooldown();
+ }
// 开始VAD冷却计时
- ln_ws_start_vad_cooldown();
}
g_vad_cooldown_active = true;
LN_WS_INFO("VAD cooldown started, duration: %u ms\n", g_vad_cooldown_duration_ms);
}
+
+// ===== 音频缓存管理函数 =====
+
+/**
+ * @brief 添加音频数据到缓存(环形缓冲区,逐步替换,仅保留最近的数据)
+ * @param data 音频数据指针
+ * @param size 音频数据大小
+ */
+static void ln_ws_add_to_audio_cache(const uint8_t* data, uint32_t size)
+{
+ if (!data || size == 0) {
+ return;
+ }
+
+ // 如果要写入的数据太大,截取部分数据
+ uint32_t write_size = size;
+ if (write_size > AUDIO_CACHE_BUFFER_SIZE) {
+ write_size = AUDIO_CACHE_BUFFER_SIZE;
+ LN_WS_WARN("Audio data too large (%u bytes), truncating to %u bytes\n", size, write_size);
+ }
+
+ // 写入数据到缓存缓冲区
+ for (uint32_t i = 0; i < write_size; i++) {
+ g_audio_cache_buffer[g_audio_cache_pos] = data[i];
+ g_audio_cache_pos = (g_audio_cache_pos + 1) % AUDIO_CACHE_BUFFER_SIZE;
+
+ // 如果到达缓冲区末尾,标记为已循环
+ if (g_audio_cache_pos == 0) {
+ g_audio_cache_wrapped = true;
+ }
+ }
+
+ // 累计总写入量,但在达到缓存大小时停止增长
+ if (g_audio_cache_total < AUDIO_CACHE_BUFFER_SIZE) {
+ uint32_t new_total = g_audio_cache_total + write_size;
+ if (new_total > AUDIO_CACHE_BUFFER_SIZE) {
+ g_audio_cache_total = AUDIO_CACHE_BUFFER_SIZE;
+ } else {
+ g_audio_cache_total = new_total;
+ }
+ }
+ // 如果已经达到最大数量,g_audio_cache_total 保持不变
+
+ // 调试日志(可选,避免日志过多):当写入位置回到0时打印
+ if (g_audio_cache_pos == 0 && g_audio_cache_wrapped) {
+ LN_WS_DEBUG("Audio cache: total=%u bytes, pos=%u, wrapped=%d\n",
+ g_audio_cache_total, g_audio_cache_pos, g_audio_cache_wrapped);
+ }
+}
+
+/**
+ * @brief 获取音频缓存数据
+ * @param buffer 输出参数,返回缓存数据的指针
+ * @return 返回缓存的有效数据长度(字节数)
+ * @note 如果缓存未循环,返回从开始到当前位置的数据长度
+ * @note 如果缓存已循环,返回完整的缓存大小
+ */
+static uint32_t ln_ws_get_audio_cache(const uint8_t** buffer)
+{
+ if (!buffer) {
+ return 0;
+ }
+
+ *buffer = g_audio_cache_buffer;
+
+ // 如果缓存已循环,返回完整缓冲区大小
+ if (g_audio_cache_wrapped) {
+ return AUDIO_CACHE_BUFFER_SIZE;
+ }
+
+ // 如果还未循环,返回当前位置
+ return g_audio_cache_pos;
+}
+
+/**
+ * @brief 重置音频缓存
+ */
+static void ln_ws_reset_audio_cache(void)
+{
+ g_audio_cache_pos = 0;
+ g_audio_cache_total = 0;
+ g_audio_cache_wrapped = false;
+
+ // 可选:清空缓冲区
+ memset(g_audio_cache_buffer, 0, AUDIO_CACHE_BUFFER_SIZE);
+
+ LN_WS_INFO("Audio cache reset\n");
+}
+
+/**
+ * @brief 从环形缓存中复制数据到输出缓冲区(考虑循环情况)
+ * @param start_pos 起始位置
+ * @param length 要复制的长度
+ * @param output 输出缓冲区
+ * @return 实际复制的字节数
+ */
+static uint32_t ln_ws_copy_from_ring_cache(uint32_t start_pos, uint32_t length, uint8_t* output)
+{
+ if (!output || length == 0) {
+ return 0;
+ }
+
+ uint32_t copied = 0;
+
+ // 处理环形缓冲区的情况
+ while (length > 0) {
+ // 计算从当前位置到缓冲区末尾的长度
+ uint32_t copy_len = AUDIO_CACHE_BUFFER_SIZE - start_pos;
+ if (copy_len > length) {
+ copy_len = length;
+ }
+
+ // 复制数据
+ memcpy(output + copied, g_audio_cache_buffer + start_pos, copy_len);
+ copied += copy_len;
+ length -= copy_len;
+ start_pos = (start_pos + copy_len) % AUDIO_CACHE_BUFFER_SIZE;
+ }
+
+ return copied;
+}
+
+/**
+ * @brief 获取缓存的音频数据并通过 ln_ws_send_audio_data 发送,发送完后清空缓存
+ * @return 成功返回0,失败返回-1
+ * @note 考虑环形缓冲区,进行数据分割发送
+ */
+static int ln_ws_send_cached_audio_data(void)
+{
+ // 如果缓存为空,直接返回
+ if (g_audio_cache_pos == 0 && !g_audio_cache_wrapped) {
+ LN_WS_DEBUG("No cached audio data to send\n");
+ return 0;
+ }
+
+ uint32_t total_size = g_audio_cache_wrapped ? AUDIO_CACHE_BUFFER_SIZE : g_audio_cache_pos;
+ uint32_t start_pos = g_audio_cache_wrapped ? g_audio_cache_pos : 0;
+
+ LN_WS_INFO("Sending cached audio data: %u bytes (wrapped=%d, start_pos=%u)\n",
+ total_size, g_audio_cache_wrapped, start_pos);
+
+ #define MAX_SEND_CHUNK_SIZE 512 // 每次最多发送4KB
+
+ int ret = 0;
+ uint32_t remaining = total_size;
+ uint32_t sent_offset = 0;
+ uint8_t send_buffer[MAX_SEND_CHUNK_SIZE];
+
+ while (remaining > 0 && ret == 0) {
+ // 计算本次发送的数据长度
+ uint32_t chunk_size = (remaining > MAX_SEND_CHUNK_SIZE) ? MAX_SEND_CHUNK_SIZE : remaining;
+
+ // 从环形缓存中复制数据到发送缓冲区
+ uint32_t copy_start = (start_pos + sent_offset) % AUDIO_CACHE_BUFFER_SIZE;
+ uint32_t actual_copied = ln_ws_copy_from_ring_cache(copy_start, chunk_size, send_buffer);
+
+ if (actual_copied != chunk_size) {
+ LN_WS_ERROR("Failed to copy data from cache, expected %u, got %u\n", chunk_size, actual_copied);
+ ret = -1;
+ break;
+ }
+
+ // 判断是否是最后一块
+ bool is_last = (remaining <= chunk_size);
+
+ // 发送数据
+ LN_WS_DEBUG("Sending chunk: size=%u, remaining=%u, is_last=%d\n",
+ chunk_size, remaining - chunk_size, is_last);
+
+ ret = ln_ws_send_audio_data(send_buffer, chunk_size, false);
+
+ sent_offset += chunk_size;
+ remaining -= chunk_size;
+ }
+
+ if (ret == 0) {
+ LN_WS_INFO("Cached audio data sent successfully, clearing cache\n");
+ // 发送成功,清空缓存
+ ln_ws_reset_audio_cache();
+ } else {
+ LN_WS_ERROR("Failed to send cached audio data, ret=%d\n", ret);
+ }
+
+ return ret;
+}