From 93e0481b0d56ad8918853272fe2066b41b147cfa Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E8=83=A1=E4=BC=A0=E5=86=9B?= <1224667075@qq.com> Date: Tue, 21 Apr 2026 05:05:40 +0000 Subject: [PATCH] Merge #3351 into ln from refs/changes/3351/head MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Code review from 胡传军 * refs/changes/3351/head: (7 commits squashed) - 关闭测试文件写入 - 修复因没有按照帧结构发送数据导致服务端有坏数据问题 - Merge branch 'ln' of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into ln - 适配极速模式下的文字返回 - 雷鸟音频卡顿优化 - Merge branch 'ln' of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into ln - 修改保底机制,防止首保过大 Signed-off-by: aliyun8003852482 <1224667075@qq.com> Merged-by: 薛文强 CR-link: https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230/change/3351 --- .../zhihui/ai/media/ai_media_service_ext.cpp | 29 ++++++- .../zhihui/leiniao/imsl_ln/ln_api_websocket.c | 77 ++++++++++++------- 2 files changed, 75 insertions(+), 31 deletions(-) diff --git a/code/sdk/zhihui/ai/media/ai_media_service_ext.cpp b/code/sdk/zhihui/ai/media/ai_media_service_ext.cpp index 1481f3fc9..e6550e4ed 100644 --- a/code/sdk/zhihui/ai/media/ai_media_service_ext.cpp +++ b/code/sdk/zhihui/ai/media/ai_media_service_ext.cpp @@ -50,10 +50,13 @@ extern "C" { #endif +// #define USE_SILENCE_AUDIO_288 // #define USE_SILENCE_AUDIO_288 // 静音音频数据定义 // 默认使用1100字节版本,定义 USE_SILENCE_AUDIO_288 可切换到288字节版本 #ifdef USE_SILENCE_AUDIO_288 +#define USE_SILENCE_AUDIO + // 288字节版本(纯MP3数据帧,无ID3标签) static const unsigned char silence_audio[288] = { 0xff, 0xf3, 0x88, 0xc4, 0x00, 0x44, 0xc0, 0x03, 0x48, 0x00, 0x00, 0x00, @@ -1898,7 +1901,7 @@ int32_t old_Start_AIVoice(AIVoiceDataCallback dataCallback, void* userData, task_cfg.create_queue_handle = CreateAIVoiceQueue; // 设置队列创建函数 task_cfg.attr.name = "AIVoiceThread"; - task_cfg.attr.priority = (osPriority_t)28; // 使用合适的优先级 + task_cfg.attr.priority = (osPriority_t)(28+2); // 使用合适的优先级 task_cfg.attr.stack_size = 0x2000; // 8KB栈空间 task_cfg.func = AIVoiceThread; task_cfg.use_mem = USE_EXTEND_MEM; @@ -2183,8 +2186,20 @@ int32_t AI_WriteAudioData(const uint8_t* data, uint32_t size) } MediaMutexUnLock(g_aiVoiceContextMutex); + // static uint32_t last_delay_us = 1; + int32_t ret=0; + #ifndef TIME_TICKS_TEST + ret = AudioStreamOutStreamWrite(data, size); + #else // 写入音频数据到输出流 - int32_t ret = AudioStreamOutStreamWrite(data, size); + uint32_t current_tick = osKernelGetTickCount(); + printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx AudioStreamOutStreamWrite current_tick: %u\n", current_tick); + ret = AudioStreamOutStreamWrite(data, size); + // printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx last_delay_us==1\r\n"); + current_tick = osKernelGetTickCount(); + printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx AudioStreamOutStreamWrite end current_tick: %u\n", current_tick); + // last_delay_us=0; + #endif if(g_aiVoiceContext->outputAudioFormat==MP3) { @@ -2192,8 +2207,14 @@ int32_t AI_WriteAudioData(const uint8_t* data, uint32_t size) // 延迟时间(微秒)= (数据大小(字节)* 8 * 1000000) / 比特率(bps) // 当比特率更高时,延迟时间更短 // 公式:延迟(微秒)= (size * 8 * 1000000) / bit_rate - uint32_t delay_us = (uint32_t)((uint64_t)(size-(size/10*5)) * 8 * 1000000ULL / g_tts_audio_bit_rate); + uint32_t delay_us = (uint32_t)((uint64_t)(size-(size/10*7)) * 8 * 1000000ULL / g_tts_audio_bit_rate); + #ifdef TIME_TICKS_TEST + printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx delay_ms %d\r\n",(uint32_t)((uint64_t)(size) * 8 * 1000000ULL / g_tts_audio_bit_rate)/1000); + MEDIA_DEBUG_LOG("delay_us %d\r\n",delay_us); + #endif + + // 确保延迟时间在合理范围内(最小10微秒) if (delay_us < 20) { @@ -2202,7 +2223,7 @@ int32_t AI_WriteAudioData(const uint8_t* data, uint32_t size) usleep(delay_us-20); if (ret != 0) { retry_count++; - // MEDIA_ERR_LOG("Failed to write audio data to output stream, ret=%d, retry %d/%d", ret, retry_count, MAX_RETRY_COUNT); + MEDIA_ERR_LOG("Failed to write audio data to output stream, ret=%d, retry %d/%d", ret, retry_count, MAX_RETRY_COUNT); usleep(delay_us*retry_count/10*5); goto AI_WRITE; } diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api_websocket.c b/code/sdk/zhihui/leiniao/imsl_ln/ln_api_websocket.c index 93b82f36c..6658fd7a8 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/ln_api_websocket.c +++ b/code/sdk/zhihui/leiniao/imsl_ln/ln_api_websocket.c @@ -250,7 +250,7 @@ static uint32_t g_audio_timeout_ticks = 1500; // 音频超时tick数(默认1.5 uint32_t g_last_binary_data_tick = 0; // 最后一次接收二进制数据的tick // 音频数据最近缓存(环形缓冲区,仅保留最近数据) -#define AUDIO_CACHE_BUFFER_SIZE (1024*3) // 8KB缓存 +#define AUDIO_CACHE_BUFFER_SIZE (72*6*5) // 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; // 总写入数据量 @@ -291,7 +291,7 @@ 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); - +#define TIME_TICKS_TEST 0 /* 握手成功回调:标记连接就绪 */ static void ln_ws_on_open(int client) @@ -347,7 +347,10 @@ static void ln_ws_message_callback(const char *raw_data, uint32_t timestamp) LN_WS_WARN("Invalid message\n"); } LN_WS_DEBUG("on_message: %s\n", buf); - +#if TIME_TICKS_TEST + uint32_t current_tick = osKernelGetTickCount(); + LN_WS_DEBUG("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx on_message current_tick: %u\n", current_tick); +#endif free(buf); } @@ -613,6 +616,12 @@ static void ln_ws_audio_write_callback(uint32_t size) { LN_WS_DEBUG("Audio data written successfully: %u bytes\n", size); +#if TIME_TICKS_TEST + uint32_t current_tick = osKernelGetTickCount(); + LN_WS_DEBUG("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx current_tick: %u\n", current_tick); +#endif + + // 更新最后一次音频写入tick g_last_audio_write_tick = osKernelGetTickCount(); g_audio_playback_active = true; @@ -723,7 +732,14 @@ int ln_ws_send_audio_data(const uint8_t *audio_data, uint32_t audio_size, bool f LN_WS_ERROR("Failed to allocate memory for base64 encoding\n"); return -1; } - + memset(audio_base64, 0, base64_size); + // LN_WS_DEBUG("audio_data before encode: \n"); + // for(int i = 0; i < 32; i++) + // { + // printf(" %02X",audio_data[i]); + // } + // LN_WS_DEBUG("audio_data end\n"); + size_t output_len = 0; int ret_encode = mbedtls_base64_encode((unsigned char*)audio_base64, base64_size - 1, &output_len, audio_data, audio_size); @@ -1153,7 +1169,11 @@ static void AIVoiceDataCallback_ln(const uint8_t* data, uint32_t size, void* use static void ai_binary_message_handler(const uint8_t *raw_data, uint32_t timestamp, uint32_t data_len) { LN_WS_INFO("Received binary message at %u, length: %d bytes\n", timestamp, data_len); - + +#if TIME_TICKS_TEST + uint32_t current_tick = osKernelGetTickCount(); + LN_WS_DEBUG("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ai_binary_message_handler current_tick: %u\n", current_tick); +#endif // 收到二进制消息时,清除 ping 超时检测 if (g_ping_timeout_active) { g_ping_timeout_active = false; @@ -1168,15 +1188,20 @@ static void ai_binary_message_handler(const uint8_t *raw_data, uint32_t timestam LN_WS_WARN("Chat ID not matched\n"); return; } + if(false==is_chat_id_matched() && g_audio_playback_active==false && g_audio_chat_ctx.finish_state == LN_CHAT_SENT_END_NO_REPLY) + { + LN_WS_DEBUG("Chat ID not matched, setting chat ID matched\n"); + set_chat_id_matched(); + } if (!raw_data || data_len == 0) { LN_WS_ERROR("Invalid binary data parameters\n"); return; } - const size_t CHUNK_SIZE = 1024; // 1K 分块大小 + const size_t CHUNK_SIZE = 1024*2; // 1K 分块大小 - if (data_len <= CHUNK_SIZE) { + if (data_len <= CHUNK_SIZE || (g_audio_playback_active==false && data_len<=1024*5)) { // 数据小于等于1K,直接发送 LN_WS_DEBUG("Sending data directly (size: %d bytes)\n", data_len); AI_SendAudioDataToQueue(raw_data, data_len); @@ -1198,32 +1223,30 @@ static void ai_binary_message_handler(const uint8_t *raw_data, uint32_t timestam remaining -= current_chunk_size; } + LN_WS_DEBUG("All %d chunks sent successfully\n", chunk_count); + } + // 更新最后一次音频写入tick // 如果音频播放从非活跃状态转为活跃状态,记录开始播放时间 - if (!g_audio_playback_active) { - g_audio_playback_start_tick = osKernelGetTickCount(); - LN_WS_INFO("Audio playback started at tick: %u\n", g_audio_playback_start_tick); - - // 触发音频播放开始事件 - if (g_ws_message_callback != NULL) { - g_ws_message_callback(NULL, WS_CMD_AUDIO_PLAYBACK_START); - } - extern bool a2dp_is_connect; - if(a2dp_is_connect) - { - int ret = a2dp_src_start_playing(ln_bt_get_last_conned_device_Addr()); // 设置耳机的状态为播放 + if (!g_audio_playback_active) { + g_audio_playback_start_tick = osKernelGetTickCount(); + LN_WS_INFO("Audio playback started at tick: %u\n", g_audio_playback_start_tick); + + // 触发音频播放开始事件 + if (g_ws_message_callback != NULL) { + g_ws_message_callback(NULL, WS_CMD_AUDIO_PLAYBACK_START); + } + extern bool a2dp_is_connect; + if(a2dp_is_connect) + { + int ret = a2dp_src_start_playing(ln_bt_get_last_conned_device_Addr()); // 设置耳机的状态为播放 + + LN_WS_DEBUG("a2dp_src_start_playing %d \n", ret); - LN_WS_DEBUG("a2dp_src_start_playing %d \n", ret); - - } - } g_audio_playback_active = true; - - - LN_WS_DEBUG("All %d chunks sent successfully\n", chunk_count); } } @@ -4093,7 +4116,7 @@ static int ln_ws_send_cached_audio_data(void) 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 + #define MAX_SEND_CHUNK_SIZE 72*6 // 每次最多发送4KB int ret = 0; uint32_t remaining = total_size; -- 2.17.1