From 77013a1352e6d55a0bb9243883dac6b5a2e3b527 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Fri, 26 Jun 2026 10:32:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20ble=20uuid=20=E6=B3=A8?= =?UTF-8?q?=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yunqiinnovation/ble_service/BleService.kt | 69 +++++++++++-------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt index c34d01daf..9b1a95e03 100644 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt +++ b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt @@ -979,43 +979,54 @@ object BleService { val callAudioSvc = g.getService(BleConst.CALL_AUDIO_SERVICE_UUID) callWriteChar = callAudioSvc?.getCharacteristic(BleConst.CALL_WRITE_AUDIO_CHAR_UUID) callAudioChar = callAudioSvc?.getCharacteristic(BleConst.CALL_RECEIVE_AUDIO_CHAR_UUID) - if (callWriteChar == null) { - Log.e(TAG, "未找到通话音频主服务所需特征") - updateConnectionState(BleConst.STATE_ERROR) - return + // 通话音频写特征仅用于发送翻译音频,缺失只影响发送能力,不再中断整个服务发现流程 + if (callWriteChar != null) { + Log.d(TAG, "找到通话音频写特征") + callWriteChar?.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE + } else { + Log.w(TAG, "未找到通话音频写特征,通话音频发送不可用") } - Log.d(TAG, "找到通话音频服务所需特征") startBytesStatistics() writeChar?.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE - callWriteChar?.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE - // 串行注册通知:等待上一个通道成功后再注册下一个 + + // 获取唤醒词OTA主服务特征(其通知通道与下面几路一起串行注册) + val wakeupVoicesSvc = g.getService(BleConst.WakeupVoices_PRIMARY_SERVICE_UUID) + wakeupVoicesNotifyChar = wakeupVoicesSvc?.getCharacteristic(BleConst.WakeupVoices_NOTIFY_UUID) + wakeupVoicesWriteChar = wakeupVoicesSvc?.getCharacteristic(BleConst.WakeupVoices_WRITE_UUID) + wakeupVoicesWriteChar?.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE + + // 串行注册所有通知通道:逐个写入 CCCD,等上一个 onDescriptorWrite 回调后再写下一个。 + // Android 同一时刻只允许一个 GATT 操作,连发 writeDescriptor 会相互覆盖/失败, + // 必须经由 notificationSetupQueue + processNextNotificationDescriptor 串行驱动。 notificationSetupQueue.clear() isDescriptorWriteInProgress = false - notificationTargetsTotal = 0 notificationTargetsSucceeded = 0 - if (callAudioChar != null && audioChar != null) { - setupNotifications(g, callAudioChar) - setupNotifications(g, audioChar) - Log.i(TAG, "通话音频服务特征找到并设置通知") - Handler(Looper.getMainLooper()).postDelayed({ - getDeviceWakeupVersion() - }, 1000) // 延迟3秒再请求版本,确保通知描述符写入完成 - } else { - Log.w(TAG, "通话音频服务特征未完整找到") - } - setupNotifications(g, notifyChar) + // 各特征独立判空入队,互不影响:某一路缺失只跳过该路,其余照常注册 + val notifyTargets = listOf( + "通话接收音频" to callAudioChar, + "AI音频" to audioChar, + "命令通知" to notifyChar, + "唤醒词OTA通知" to wakeupVoicesNotifyChar + ) + for ((name, ch) in notifyTargets) { + if (ch != null) { + notificationSetupQueue.addLast(ch) + } else { + Log.w(TAG, "未找到${name}特征,跳过其通知注册") + } + } - // 获取唤醒词OTA主服务特征 - val wakeupVoicesSvc = g.getService(BleConst.WakeupVoices_PRIMARY_SERVICE_UUID) - wakeupVoicesNotifyChar = wakeupVoicesSvc?.getCharacteristic(BleConst.WakeupVoices_NOTIFY_UUID) - wakeupVoicesWriteChar = wakeupVoicesSvc?.getCharacteristic(BleConst.WakeupVoices_WRITE_UUID) - if (wakeupVoicesNotifyChar != null && wakeupVoicesWriteChar != null) { - wakeupVoicesWriteChar?.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE - setupWakeupVoicesNotifications(g, wakeupVoicesNotifyChar) - Log.i(TAG, "liwei------- 唤醒词OTA服务特征已找到") - }else{ - Log.w(TAG, "liwei------- 唤醒词OTA服务特征未找到") + notificationTargetsTotal = notificationSetupQueue.size + if (notificationTargetsTotal > 0) { + Log.i(TAG, "开始串行注册 $notificationTargetsTotal 路通知通道") + processNextNotificationDescriptor(g) + // 延迟请求唤醒词版本,确保命令通道通知描述符已写入完成 + Handler(Looper.getMainLooper()).postDelayed({ + getDeviceWakeupVersion() + }, 1000) + } else { + Log.w(TAG, "没有可注册通知的特征") } // 在服务发现完成后,请求最大MTU //requestMaxMtu(g)