屏蔽静音帧的使用,改为使用蓝牙状态设置函数,AirPods Pro已经成功出声 3019/2 3019/head 3027/target/1
authorhcj <1224667075@qq.com>
Tue, 6 Jan 2026 10:25:40 +0000 (18:25 +0800)
committerhcj <1224667075@qq.com>
Tue, 6 Jan 2026 10:25:40 +0000 (18:25 +0800)
code/sdk/application/wearable/ln/nativeapp/nativeui/bluetooth/src/Ln_Bluetooth_apiC.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/include/bluetooth/Ln_Bluetooth_apiC.h
code/sdk/zhihui/ai/media/ai_media_service_ext.cpp
code/sdk/zhihui/leiniao/imsl_ln/CMakeLists.txt
code/sdk/zhihui/leiniao/imsl_ln/ln_api_websocket.c

index 1775da7..f5827bb 100644 (file)
@@ -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)
     {
index 9c69ccf..2fe968d 100644 (file)
@@ -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
index 8eae31e..8d7c0fa 100644 (file)
@@ -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;
index 9b26583..4719195 100644 (file)
@@ -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}/
 )
 
 # 私有宏定义(可选)
index 9895dee..3f6b253 100644 (file)
 #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; // 播放已完成
     }