Merge #2844 into sdk650pathc0423 from refs/changes/2844/head 2848/target/1
author胡传军 <1224667075@qq.com>
Wed, 3 Dec 2025 07:28:23 +0000 (07:28 +0000)
committersnickersun@163.com <accounts_62b90f7fcf51ade33b6f628e@mail.teambition.com>
Wed, 3 Dec 2025 07:28:23 +0000 (07:28 +0000)
Code review from 胡传军

* refs/changes/2844/head: (15 commits squashed)

  - 屏蔽VAD认证

  - Merge branch &#39;sdk650pathc0423&#39; of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk650pathc0423

  - 增加文件保存测试开关

  - Merge branch &#39;sdk650pathc0423&#39; of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk650pathc0423

  - Merge branch &#39;sdk650pathc0423&#39; of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk650pathc0423

  - 修改ai宏开关不生效的问题

  - Merge branch &#39;sdk650pathc0423&#39; of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk650pathc0423

  - cat1升级启动换位置

  - Merge branch &#39;sdk650pathc0423&#39; of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk650pathc0423

  - Merge branch &#39;sdk650pathc0423&#39; of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk650pathc0423

  - Merge branch &#39;sdk650pathc0423&#39; of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk650pathc0423

  - vad参数调整

  - Merge branch &#39;sdk650pathc0423&#39; of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk650pathc0423

  - 修改ln 蓝牙耳机相关

  - Merge branch &#39;sdk650pathc0423&#39; of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk650pathc0423

Signed-off-by: aliyun8003852482 <1224667075@qq.com>
Reviewed-by: snickersun@163.com <accounts_62b90f7fcf51ade33b6f628e@mail.teambition.com>
Merged-by: snickersun@163.com <accounts_62b90f7fcf51ade33b6f628e@mail.teambition.com>
link: https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230/change/2844
code/sdk/application/wearable/ln/nativeapp/nativeui/bluetooth/src/BluetoothModel.cpp
code/sdk/zhihui/ai/include/ai_media.h
code/sdk/zhihui/ai/media/ai_media_service_ext.cpp
code/sdk/zhihui/leiniao/imsl_ln/ln_api_websocket.c
code/sdk/zhihui/utils/custom_cmd_service.c
code/sdk/zhihui/utils/custom_utils.h

index 514c98b..c34c3e3 100644 (file)
@@ -46,6 +46,8 @@
 #include "thunderbird/include/ThunderBirdMainView.h"\r
 #include "thunderbird/include/ThunderBirdBlueView.h"\r
 #include <custom_utils.h>\r
+#include "ai_media.h"\r
+\r
 namespace OHOS {\r
 \r
 #define BT_SPP_TASK_STACK_SIZE 2048\r
@@ -1163,6 +1165,12 @@ static void A2dpSrcConnectstateChanged(bd_addr_t *bdAddr, int connState)
     if (connState == PROFILE_STATE_CONNECTED) {\r
         uint32_t ret = avrcp_ct_connect(bdAddr);\r
         WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "avrcp_ct_connect ret = 0x%x", ret);\r
+\r
+        if(AI_IsVoiceServiceRunning()){\r
+            ln_ws_audio_deinit();\r
+        }\r
+        \r
+        set_a2dp_is_connect(true);\r
         PhoneAudioManagerSetDeviceConnState(OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_CONNECTED);\r
         GraphicService::GetInstance()->PostGraphicEvent(std::bind(ACLConnectionSuss, *bdAddr));\r
         int earphoneConnectStatus = 1;\r
@@ -1170,7 +1178,15 @@ static void A2dpSrcConnectstateChanged(bd_addr_t *bdAddr, int connState)
     }\r
 \r
     if (connState == PROFILE_STATE_DISCONNECTED) {\r
+        if(AI_IsVoiceServiceRunning()){\r
+            ln_ws_audio_deinit();\r
+        }\r
+\r
+\r
         PhoneAudioManagerSetDeviceConnState(OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_DISCONNECTED);\r
+        set_a2dp_is_connect(false);\r
+\r
+ \r
         GraphicService::GetInstance()->PostGraphicEvent(std::bind(ACLConnectionFail, *bdAddr));\r
         int earphoneConnectStatus = 0;\r
         SendMsgToUIService(HAND_BLUETOOTH_EARPHONE_CONNECT_STATUS_NOTIFY, 0, &earphoneConnectStatus, sizeof(earphoneConnectStatus));\r
index cb4f7b5..f1d069e 100644 (file)
@@ -102,6 +102,7 @@ typedef struct {
 } AIVoiceAudioParams;
 
 
+
 int32_t old_Start_AIVoice(AIVoiceDataCallback dataCallback, void* userData, 
     const AIVoiceAudioParams* inputAudioParams,
     const AIVoiceAudioParams* outputAudioParams,
@@ -196,6 +197,24 @@ int32_t AI_GetSecondStreamInParams(AIVoiceAudioParams* audioParams);
  */
 bool AI_IsSecondStreamInEnabled(void);
 
+/*
+ * @brief 开启第二个音频上行流(初始化并启动)
+ * @return 0 成功,-1 失败
+ */
+int32_t AI_StartSecondStreamIn(void);
+
+/*
+ * @brief 关闭第二个音频上行流(停止并反初始化)
+ * @return 0 成功,-1 失败
+ */
+int32_t AI_StopSecondStreamIn(void);
+
+/*
+ * @brief 获取第二个音频上行流状态
+ * @return true 正在运行,false 未运行或未启用
+ */
+bool AI_GetSecondStreamInStatus(void);
+
 /*
  * @brief 从第二个音频上行流获取音频数据缓冲区
  * @param data 音频数据缓冲区指针
@@ -204,6 +223,12 @@ bool AI_IsSecondStreamInEnabled(void);
  */
 int32_t AI_SecondStreamInObtainBuffer(uint8_t *data, uint32_t *size);
 
+/*
+ * @brief 设置连接状态
+ * @param state 设置状态
+ */
+void set_a2dp_is_connect(bool state);
+
 #ifdef __cplusplus
 };
 #endif
index 14de8a8..cec5bd9 100644 (file)
@@ -882,6 +882,68 @@ static int32_t DeinitSecondAudioStreamInSafe(void)
     return ret;
 }
 
+/**
+ * @brief 初始化第二个音频上行流(线程安全版本,使用全局上下文)
+ * @return 0 成功,-1 失败
+ */
+static int32_t InitSecondAudioStreamInSafe(void)
+{
+    int32_t ret = 0;
+    MediaMutexHandle mutex = GetGlobalMutex();
+    if (mutex == nullptr) {
+        return -1;
+    }
+    
+    MediaMutexLock(mutex);
+    if (g_aiVoiceContext == nullptr) {
+        MEDIA_ERR_LOG("AI voice context is null, please start AI voice first");
+        MediaMutexUnLock(mutex);
+        return -1;
+    }
+    
+    if (!g_aiVoiceContext->useSecondStreamIn) {
+        MEDIA_ERR_LOG("Second audio stream in is not enabled");
+        MediaMutexUnLock(mutex);
+        return -1;
+    }
+    
+    ret = InitSecondAudioStreamIn(g_aiVoiceContext);
+    if (ret != 0) {
+        MEDIA_ERR_LOG("second audio stream in init failed");
+    }
+    
+    MediaMutexUnLock(mutex);
+    return ret;
+}
+
+/**
+ * @brief 启动第二个音频上行流(线程安全版本,使用全局上下文)
+ * @return 0 成功,-1 失败
+ */
+static int32_t StartSecondAudioStreamInSafe(void)
+{
+    int32_t ret = 0;
+    MediaMutexHandle mutex = GetGlobalMutex();
+    if (mutex == nullptr) {
+        return -1;
+    }
+    
+    MediaMutexLock(mutex);
+    if (g_aiVoiceContext == nullptr) {
+        MEDIA_ERR_LOG("AI voice context is null, please start AI voice first");
+        MediaMutexUnLock(mutex);
+        return -1;
+    }
+    
+    ret = StartSecondAudioStreamIn(g_aiVoiceContext);
+    if (ret != 0) {
+        MEDIA_ERR_LOG("second audio stream in start failed");
+    }
+    
+    MediaMutexUnLock(mutex);
+    return ret;
+}
+
 // 注意:g_aiVoiceContext 已在上方定义,这里不需要重复定义
 
 
@@ -999,6 +1061,12 @@ static bool InitAIVoiceResources(AIVoiceContext *context)
     context->bufferSize = AI_VOICE_BUFFER_SIZE;
     return true;
 }
+bool a2dp_is_connect=false;
+
+void set_a2dp_is_connect(bool state)
+{
+    a2dp_is_connect=state;
+}
 
 static int32_t LocalAIVoiceStart(AIVoiceContext *context)
 {
@@ -1047,7 +1115,7 @@ static int32_t LocalAIVoiceStart(AIVoiceContext *context)
     }
 
     // 初始化第二个上行流(如果启用)
-    if (context->useSecondStreamIn) {
+    if (context->useSecondStreamIn  && a2dp_is_connect==false) {
         ret = InitSecondAudioStreamIn(context);
         if (ret != 0) {
             MEDIA_ERR_LOG("Failed to init second audio stream in");
@@ -2296,6 +2364,90 @@ bool AI_IsSecondStreamInEnabled(void)
     return enabled;
 }
 
+/**
+ * @brief 开启第二个音频上行流(初始化并启动)
+ * @return 0 成功,-1 失败
+ */
+int32_t AI_StartSecondStreamIn(void)
+{
+    // 检查音频主服务是否已开启
+    MEDIA_ERR_LOG("AI_StartSecondStreamIn");
+
+    if (!AI_IsVoiceServiceRunning()) {
+        MEDIA_ERR_LOG("Audio main service is not running, please start AI voice service first");
+        return -1;
+    }
+    
+    // 先初始化
+    int32_t ret = InitSecondAudioStreamInSafe();
+    if (ret != 0) {
+        MEDIA_ERR_LOG("Failed to init second audio stream in");
+        return -1;
+    }
+    
+    // 再启动
+    ret = StartSecondAudioStreamInSafe();
+    if (ret != 0) {
+        MEDIA_ERR_LOG("Failed to start second audio stream in");
+        // 如果启动失败,尝试清理已初始化的资源
+        DeinitSecondAudioStreamInSafe();
+        return -1;
+    }
+    
+    MEDIA_INFO_LOG("Second audio stream in started successfully");
+    return 0;
+}
+
+/**
+ * @brief 关闭第二个音频上行流(停止并反初始化)
+ * @return 0 成功,-1 失败
+ */
+int32_t AI_StopSecondStreamIn(void)
+{
+    int32_t ret = 0;
+    
+    // 先停止
+    ret = StopSecondAudioStreamInSafe();
+    if (ret != 0) {
+        MEDIA_ERR_LOG("Failed to stop second audio stream in");
+        // 继续执行反初始化,即使停止失败
+    }
+    
+    // 再反初始化
+    ret = DeinitSecondAudioStreamInSafe();
+    if (ret != 0) {
+        MEDIA_ERR_LOG("Failed to deinit second audio stream in");
+        return -1;
+    }
+    
+    MEDIA_INFO_LOG("Second audio stream in stopped successfully");
+    return 0;
+}
+
+/**
+ * @brief 获取第二个音频上行流状态
+ * @return true 正在运行,false 未运行或未启用
+ */
+bool AI_GetSecondStreamInStatus(void)
+{
+    bool isRunning = false;
+    
+    MediaMutexHandle mutex = GetGlobalMutex();
+    if (mutex == nullptr) {
+        return false;
+    }
+    
+    MediaMutexLock(mutex);
+    if (g_aiVoiceContext != nullptr && 
+        g_aiVoiceContext->useSecondStreamIn && 
+        g_aiVoiceContext->secondStreamIn != nullptr) {
+        isRunning = true;
+    }
+    MediaMutexUnLock(mutex);
+    
+    return isRunning;
+}
+
 /**
  * @brief 从第二个音频上行流获取音频数据缓冲区
  * @param data 音频数据缓冲区指针
@@ -2346,6 +2498,10 @@ int32_t AI_SecondStreamInObtainBuffer(uint8_t *data, uint32_t *size)
     return 0;
 }
 
+
+
+
+
 #ifdef __cplusplus
 };
 #endif
index 83fbc2c..7aa5620 100644 (file)
@@ -794,25 +794,11 @@ static void AIVoiceDataCallback_ln(const uint8_t* data, uint32_t size, void* use
     #if ENABLE_VAD_SERVER
     if (g_vad_server_enabled && g_vad_server_initialized && vad_server_is_running()) {
 
-        #ifdef VAD_LOCAL_PM
-        vad_audio_format_t format = VAD_AUDIO_FORMAT_MP3;  // 默认 MP3
+     
+        if(AI_GetSecondStreamInStatus()==false){
+            vad_audio_format_t format = VAD_AUDIO_FORMAT_MP3;  // 默认 MP3
         
-errcode_t ret = vad_server_send_audio(format, data, size, false);
-
-        #else  
-        vad_audio_format_t format = VAD_AUDIO_FORMAT_PCM;  // 默认 MP3
-
-        if (data && size > 0) {
-            
-            uint8_t *pcm_data=(uint8_t *) malloc(1024*3);
-            uint32_t len=1024*3;
-
-           errcode_t ret= AI_SecondStreamInObtainBuffer(pcm_data,&len);
-
-            if(ret==0 && len>0)
-            {
-                ret = vad_server_send_audio(format, pcm_data, len, false);
-// AI_SendAudioDataToQueue(pcm_data, len);
+            errcode_t ret = vad_server_send_audio(format, data, size, false);
 
             if (ret != ERRCODE_SUCC) {
                 /* 静默失败,避免过多日志 */
@@ -820,13 +806,27 @@ errcode_t ret = vad_server_send_audio(format, data, size, false);
                 // LN_WS_DEBUG("VAD: Sent %u bytes (format=%d, is_last=%d)\n", 
                         //    size, format, false);
             }
-
         }
-        free(pcm_data);
-           
+        else{
+            vad_audio_format_t format = VAD_AUDIO_FORMAT_PCM;  // 默认 MP3
+  
+                uint8_t *pcm_data=(uint8_t *) malloc(1024*3);
+                uint32_t len=1024*3;
+    
+               errcode_t ret= AI_SecondStreamInObtainBuffer(pcm_data,&len);
+    
+                if(ret==0 && len>0)
+                {
+                    ret = vad_server_send_audio(format, pcm_data, len, false);
+                    if (ret != ERRCODE_SUCC) {
+                        /* 静默失败,避免过多日志 */
+                    } else {
+                        // LN_WS_DEBUG("VAD: Sent %u bytes (format=%d, is_last=%d)\n", 
+                                //    size, format, false);
+                    }
+                }
+                free(pcm_data);
         }
-        #endif
-        
         // 如果是结束标志,打印日志
         if (false) {
             LN_WS_INFO("VAD: Audio recording ended\n");
@@ -1122,7 +1122,7 @@ int ln_ws_start(ws_message_callback_t_ln callback, uint32_t audio_timeout_ticks)
 void vad_status_callback_ln_ws(int status)
 {
     LN_WS_INFO("Audio vad_status_callback_ln_ws %d\n",status);
-    
+
     // 检查VAD服务器是否被禁用(例如在哄睡模式下)
     if (!ln_ws_is_vad_server_enabled()) {
         LN_WS_INFO("VAD server is disabled, ignoring callback (status=%d)\n", status);
index 7d80b23..ae10dfc 100644 (file)
@@ -37,6 +37,7 @@
 
 #ifdef SUPPORT_AI_SERVICE
 #include "websocket_server_manager.h"
+#include "ai_media.h"
 #endif
 
 #ifdef FD230_650
@@ -484,6 +485,34 @@ case CUSTOM_CMD_MSG_START_AI_ASR:
             PRINT("VAD auth via custom cmd\n");
             ln_ws_vad_auth();
             break;
+        case CUSTOM_CMD_MSG_START_SECOND_STREAM_IN:
+#ifdef SUPPORT_AI_SERVICE
+            {
+                int32_t ret = AI_StartSecondStreamIn();
+                if (ret == 0) {
+                    PRINT("Second audio stream in started via custom cmd\n");
+                } else {
+                    PRINT("Failed to start second audio stream in via custom cmd, ret=%d\n", ret);
+                }
+            }
+#else
+            PRINT("AI service not supported\n");
+#endif
+            break;
+        case CUSTOM_CMD_MSG_STOP_SECOND_STREAM_IN:
+#ifdef SUPPORT_AI_SERVICE
+            {
+                int32_t ret = AI_StopSecondStreamIn();
+                if (ret == 0) {
+                    PRINT("Second audio stream in stopped via custom cmd\n");
+                } else {
+                    PRINT("Failed to stop second audio stream in via custom cmd, ret=%d\n", ret);
+                }
+            }
+#else
+            PRINT("AI service not supported\n");
+#endif
+            break;
 #endif
         break;
         case CUSTOM_CMD_MSG_ROTARY_OPEN:
@@ -616,5 +645,21 @@ void uapi_set_chat_ai_type(uint8_t ai_type)
 {
     set_chat_ai_type(ai_type);
 }
+
+/**
+ * @brief 启动第二个音频上行流
+ */
+void uapi_start_second_stream_in(void)
+{
+    do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_START_SECOND_STREAM_IN, NULL, 0);
+}
+
+/**
+ * @brief 停止第二个音频上行流
+ */
+void uapi_stop_second_stream_in(void)
+{
+    do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_STOP_SECOND_STREAM_IN, NULL, 0);
+}
 #endif
 #endif
\ No newline at end of file
index d204fc1..a868243 100644 (file)
@@ -265,6 +265,11 @@ uint32_t uapi_calendar_store_date(void);
 
 #define CUSTOM_CMD_MSG_ROTARY_OPEN 0x29
 
+#define CUSTOM_CMD_MSG_START_SECOND_STREAM_IN 0x30
+
+#define CUSTOM_CMD_MSG_STOP_SECOND_STREAM_IN 0x31
+
+
 typedef enum {
     BR_HFP_CONNECT=1,
     BR_HFP_DISCONNECT,
@@ -282,6 +287,8 @@ errcode_t do_custom_cmd_service_check_msg_head(int cmd, void *params, int paraml
 #ifdef SUPPORT_AI_SERVICE
 void uapi_start_AI_asr(void);
 void uapi_stop_AI_asr(void);
+void uapi_start_second_stream_in(void);
+void uapi_stop_second_stream_in(void);
 #endif
 
 #ifdef SUPPORT_AI_SERVICE