From 68b9feffd54a32618195719692ee91269d5e79ed Mon Sep 17 00:00:00 2001 From: hcj <1224667075@qq.com> Date: Tue, 6 Jan 2026 18:25:40 +0800 Subject: [PATCH] =?utf8?q?=E5=B1=8F=E8=94=BD=E9=9D=99=E9=9F=B3=E5=B8=A7?= =?utf8?q?=E7=9A=84=E4=BD=BF=E7=94=A8=EF=BC=8C=E6=94=B9=E4=B8=BA=E4=BD=BF?= =?utf8?q?=E7=94=A8=E8=93=9D=E7=89=99=E7=8A=B6=E6=80=81=E8=AE=BE=E7=BD=AE?= =?utf8?q?=E5=87=BD=E6=95=B0=EF=BC=8CAirPods=20Pro=E5=B7=B2=E7=BB=8F?= =?utf8?q?=E6=88=90=E5=8A=9F=E5=87=BA=E5=A3=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../bluetooth/src/Ln_Bluetooth_apiC.cpp | 10 +++ .../include/bluetooth/Ln_Bluetooth_apiC.h | 7 +++ .../zhihui/ai/media/ai_media_service_ext.cpp | 63 ++++++++++++++++++- .../sdk/zhihui/leiniao/imsl_ln/CMakeLists.txt | 4 +- .../zhihui/leiniao/imsl_ln/ln_api_websocket.c | 45 ++++++++----- 5 files changed, 112 insertions(+), 17 deletions(-) diff --git a/code/sdk/application/wearable/ln/nativeapp/nativeui/bluetooth/src/Ln_Bluetooth_apiC.cpp b/code/sdk/application/wearable/ln/nativeapp/nativeui/bluetooth/src/Ln_Bluetooth_apiC.cpp index 1775da79a..f5827bb05 100644 --- a/code/sdk/application/wearable/ln/nativeapp/nativeui/bluetooth/src/Ln_Bluetooth_apiC.cpp +++ b/code/sdk/application/wearable/ln/nativeapp/nativeui/bluetooth/src/Ln_Bluetooth_apiC.cpp @@ -229,6 +229,16 @@ extern "C" return 0; } + bd_addr_t *ln_bt_get_last_conned_device_Addr(void) + { + bd_addr_t *lastAddr = OHOS::BluetoothModel::GetInstance()->GetLastConnedAddr(); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "LastDevice addr: %02x%02x%02x%02x%02x%02x is connected", + lastAddr->addr[5], lastAddr->addr[4], lastAddr->addr[3], + lastAddr->addr[2], lastAddr->addr[1], lastAddr->addr[0]); + return OHOS::BluetoothModel::GetInstance()->GetLastConnedAddr(); + } + + // 解绑远程设备 int ln_bt_unbind_remote_device(const char *addr) { diff --git a/code/sdk/application/wearable/ln/nativeapp/nativeui/include/bluetooth/Ln_Bluetooth_apiC.h b/code/sdk/application/wearable/ln/nativeapp/nativeui/include/bluetooth/Ln_Bluetooth_apiC.h index 9c69ccff4..2fe968dd2 100644 --- a/code/sdk/application/wearable/ln/nativeapp/nativeui/include/bluetooth/Ln_Bluetooth_apiC.h +++ b/code/sdk/application/wearable/ln/nativeapp/nativeui/include/bluetooth/Ln_Bluetooth_apiC.h @@ -1,6 +1,9 @@ #ifndef _LN_BLUETOOTH_API_C_H_ #define _LN_BLUETOOTH_API_C_H_ +#include "bts_def.h" + + #ifdef __cplusplus extern "C" { #endif @@ -48,6 +51,10 @@ int ln_bt_earphone_set_volume(int volume); // 获取当前耳机音量(返回值:0-100,对应0%-100%,-1表示获取失败) int ln_bt_earphone_get_volume(void); + +bd_addr_t *ln_bt_get_last_conned_device_Addr(void); + + #ifdef __cplusplus } #endif 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 8eae31e77..8d7c0fa07 100644 --- a/code/sdk/zhihui/ai/media/ai_media_service_ext.cpp +++ b/code/sdk/zhihui/ai/media/ai_media_service_ext.cpp @@ -49,6 +49,7 @@ #ifdef __cplusplus extern "C" { #endif + // #define USE_SILENCE_AUDIO_288 // 静音音频数据定义 // 默认使用1100字节版本,定义 USE_SILENCE_AUDIO_288 可切换到288字节版本 @@ -1451,6 +1452,32 @@ static int32_t RunAIVoice(AIVoiceContext *context) if (ret != 0) { return ret; } + #ifdef USE_SILENCE_AUDIO + if(a2dp_is_connect) + { + uint32_t queueSize=0, queueCapacity=0; + AI_GetQueueStatus(&queueSize, &queueCapacity); + if (queueSize==0) + { + // 使用静音音频数据(自动匹配大小) + AIVoiceQueueMessage cachedMsg; + cachedMsg.size = SILENCE_AUDIO_SIZE; + + cachedMsg.data = (uint8_t *)malloc(cachedMsg.size); + memcpy(cachedMsg.data, (void*)silence_audio, SILENCE_AUDIO_SIZE); + + osStatus_t queueStatus = osMessageQueuePut(context->inputQueue, &cachedMsg, 0, 0); + if (queueStatus == osOK) { + context->queueMsgCount++; + // MEDIA_INFO_LOG("Successfully restored %u bytes from cache to queue", cachedMsg.size); + } else { + MEDIA_ERR_LOG("Failed to restore cached data to queue: %d", queueStatus); + // 如果队列写入失败,释放内存 + free(cachedMsg.data); + } + } + } + #endif // Wait for stop signal and process queue data MEDIA_INFO_LOG("RunAIVoice: waiting for queue data..."); @@ -1477,14 +1504,16 @@ static int32_t RunAIVoice(AIVoiceContext *context) if (msg.data != nullptr && msg.size > 0) { // 写入音频数据到输出流 AI_WriteAudioData(msg.data,msg.size); + #ifdef USE_SILENCE_AUDIO if(msg.size==SILENCE_AUDIO_SIZE) { #ifdef USE_SILENCE_AUDIO_288 LOS_Msleep(20); #else - LOS_Msleep(1000); + LOS_Msleep(500); #endif } + #endif // struct timespec ts; // AudioStreamGetTimestamp(&ts); // printf("AudioStreamGetTimestamp %d\r\n",ts.tv_sec); @@ -1526,6 +1555,7 @@ static int32_t RunAIVoice(AIVoiceContext *context) } else { + #ifdef USE_SILENCE_AUDIO if(a2dp_is_connect) { uint32_t queueSize=0, queueCapacity=0; @@ -1535,6 +1565,7 @@ static int32_t RunAIVoice(AIVoiceContext *context) // 使用静音音频数据(自动匹配大小) AIVoiceQueueMessage cachedMsg; cachedMsg.size = SILENCE_AUDIO_SIZE; + cachedMsg.data = (uint8_t *)malloc(cachedMsg.size); memcpy(cachedMsg.data, (void*)silence_audio, SILENCE_AUDIO_SIZE); @@ -1550,11 +1581,39 @@ static int32_t RunAIVoice(AIVoiceContext *context) } } + #endif } } else if (status == osErrorTimeout) { + #ifdef USE_SILENCE_AUDIO + if(a2dp_is_connect) + { + uint32_t queueSize=0, queueCapacity=0; + AI_GetQueueStatus(&queueSize, &queueCapacity); + if (queueSize==0) + { + // 使用静音音频数据(自动匹配大小) + AIVoiceQueueMessage cachedMsg; + cachedMsg.size = SILENCE_AUDIO_SIZE; + + cachedMsg.data = (uint8_t *)malloc(cachedMsg.size); + memcpy(cachedMsg.data, (void*)silence_audio, SILENCE_AUDIO_SIZE); + + osStatus_t queueStatus = osMessageQueuePut(context->inputQueue, &cachedMsg, 0, 0); + if (queueStatus == osOK) { + context->queueMsgCount++; + // MEDIA_INFO_LOG("Successfully restored %u bytes from cache to queue", cachedMsg.size); + } else { + MEDIA_ERR_LOG("Failed to restore cached data to queue: %d", queueStatus); + // 如果队列写入失败,释放内存 + free(cachedMsg.data); + } + } + + } + #endif // 超时,继续循环检查停止标志 continue; } else { @@ -2499,6 +2558,7 @@ int32_t AI_ForceInterrupt(void) MEDIA_INFO_LOG("AI voice force interrupt completed"); + #ifdef USE_SILENCE_AUDIO if (a2dp_is_connect) { uint32_t queueSize = 0, queueCapacity = 0; @@ -2522,6 +2582,7 @@ int32_t AI_ForceInterrupt(void) } } } + #endif MediaMutexUnLock(mutex); return 0; diff --git a/code/sdk/zhihui/leiniao/imsl_ln/CMakeLists.txt b/code/sdk/zhihui/leiniao/imsl_ln/CMakeLists.txt index 9b2658360..471919500 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/CMakeLists.txt +++ b/code/sdk/zhihui/leiniao/imsl_ln/CMakeLists.txt @@ -24,7 +24,7 @@ set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ln_file_recv_task.c ${CMAKE_CURRENT_SOURCE_DIR}/ln_bluetooth_api.c ${CMAKE_CURRENT_SOURCE_DIR}/ln_websoket_api_ext.c - + ) # 公共头文件路径(供其他模块引用) @@ -36,6 +36,7 @@ set(PUBLIC_HEADER ${ROOT_DIR}/open_source/openharmony/third_party/cJSON/ ${ROOT_DIR}/open_source/openharmony/foundation/ace/ace_engine_lite/modules/netstack/websocket/include ${ROOT_DIR}/zhihui/websocket/os_ws + ${ROOT_DIR}/application/wearable/ln/nativeapp/nativeui/include/bluetooth ) # 公共宏定义(可选) @@ -48,6 +49,7 @@ set(PUBLIC_DEFINES # 私有头文件路径(仅当前组件内部使用) set(PRIVATE_HEADER # 如无特殊私有头文件,可留空 + ${CMAKE_CURRENT_SOURCE_DIR}/ ) # 私有宏定义(可选) 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 9895deed3..3f6b253e8 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/ln_api_websocket.c +++ b/code/sdk/zhihui/leiniao/imsl_ln/ln_api_websocket.c @@ -19,7 +19,11 @@ #include "vad_server.h" // Added for VAD processing #include "imsl_vad.h" // Added for AuthInfo and auth_vad #include "dmp_api.h" // Added for dmp_read_dev_token and dmp_aut_login +#include "bts_a2dp_source.h" + #endif +#include "Ln_Bluetooth_apiC.h" + // 功能开关宏定义 #define ENABLE_BINARY_DATA_INTERRUPT_CHECK 1 // 启用二进制数据间隔检查 #define ENABLE_AUDIO_FILE_WRITE 0 // 启用音频文件写入功能(根据chat_id生成文件) @@ -42,7 +46,7 @@ typedef enum { } ln_ws_log_level_t; // 当前日志等级(可通过配置修改) -static ln_ws_log_level_t g_log_level = LN_WS_LOG_INFO; +static ln_ws_log_level_t g_log_level = LN_WS_LOG_DEBUG; void ln_ws_set_log_level(uint8_t level) { @@ -530,22 +534,10 @@ static bool is_active_chat_response(const char *chat_id, const char *response_id static void ln_ws_audio_write_callback(uint32_t size) { LN_WS_DEBUG("Audio data written successfully: %u bytes\n", size); - + // 更新最后一次音频写入tick g_last_audio_write_tick = osKernelGetTickCount(); - - // 如果音频播放从非活跃状态转为活跃状态,记录开始播放时间 - if (!g_audio_playback_active) { - g_audio_playback_start_tick = g_last_audio_write_tick; - 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); - } - } - - g_audio_playback_active = true; + g_audio_playback_active = true; } // 发送音频数据到WebSocket @@ -1089,6 +1081,25 @@ static void ai_binary_message_handler(const uint8_t *raw_data, uint32_t timestam remaining -= current_chunk_size; } + // 更新最后一次音频写入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); + } + int ret = a2dp_src_start_playing(ln_bt_get_last_conned_device_Addr()); // 设置耳机的状态为播放 + + 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); } @@ -3627,6 +3638,10 @@ static bool check_playback_completion_by_timeout(void) if (g_ws_message_callback != NULL) { g_ws_message_callback(NULL, WS_CMD_AUDIO_PLAYBACK_END); } + + int ret = a2dp_src_suspend_playing(ln_bt_get_last_conned_device_Addr()); // 设置耳机的状态为播放 + + LN_WS_DEBUG("a2dp_src_suspend_playing %d \n", ret); return true; // 播放已完成 } -- 2.17.1