|
|
|
@ -134,6 +134,12 @@ object BleService { |
|
|
|
private var maxMtu = 517 // 最大MTU值 (512 + 5字节头部) |
|
|
|
private var isWaitingForWriteCallback = false // 是否正在等待写入回调 |
|
|
|
|
|
|
|
// 通知注册串行化相关变量 |
|
|
|
private val notificationSetupQueue: ArrayDeque<BluetoothGattCharacteristic> = ArrayDeque() |
|
|
|
private var isDescriptorWriteInProgress = false |
|
|
|
private var notificationTargetsTotal = 0 |
|
|
|
private var notificationTargetsSucceeded = 0 |
|
|
|
|
|
|
|
// 初始化状态 |
|
|
|
private var isInitialized = false |
|
|
|
|
|
|
|
@ -743,33 +749,6 @@ object BleService { |
|
|
|
updateConnectionState(BleConst.STATE_CONNECTED) |
|
|
|
Log.d(TAG, "成功连接Ble蓝牙设备:${g.device.name}") |
|
|
|
companionManager?.unregisterBackgroundScan() |
|
|
|
// 设置PHY值为2M以提高传输速度 |
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
|
|
|
try { |
|
|
|
// 首先尝试读取当前PHY状态 |
|
|
|
val readResult = g.readPhy() |
|
|
|
Log.d(TAG, "读取PHY状态请求结果: $readResult") |
|
|
|
|
|
|
|
// 延迟一段时间后再设置PHY,确保readPhy完成 |
|
|
|
Handler(Looper.getMainLooper()).postDelayed({ |
|
|
|
try { |
|
|
|
val setResult = g.setPreferredPhy( |
|
|
|
BluetoothDevice.PHY_LE_2M_MASK, // TX PHY: 2M |
|
|
|
BluetoothDevice.PHY_LE_2M_MASK, // RX PHY: 2M |
|
|
|
BluetoothDevice.PHY_OPTION_NO_PREFERRED |
|
|
|
) |
|
|
|
Log.d(TAG, "设置PHY为2M请求结果: $setResult") |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "设置PHY失败: ${e.message}") |
|
|
|
} |
|
|
|
}, 500) // 延迟500ms |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "读取PHY失败: ${e.message},将使用默认1M PHY") |
|
|
|
} |
|
|
|
} else { |
|
|
|
Log.w(TAG, "当前Android版本不支持PHY设置(需要API 26+),使用默认1M PHY") |
|
|
|
} |
|
|
|
|
|
|
|
g.discoverServices() |
|
|
|
} |
|
|
|
|
|
|
|
@ -861,20 +840,23 @@ object BleService { |
|
|
|
startBytesStatistics() |
|
|
|
writeChar?.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE |
|
|
|
callWriteChar?.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE |
|
|
|
//要先设置音频服务的通知,否则接收不到 |
|
|
|
// 设置音频服务的通知(如果存在) |
|
|
|
// 串行注册通知:等待上一个通道成功后再注册下一个 |
|
|
|
notificationSetupQueue.clear() |
|
|
|
isDescriptorWriteInProgress = false |
|
|
|
notificationTargetsTotal = 0 |
|
|
|
notificationTargetsSucceeded = 0 |
|
|
|
if (callAudioChar != null && audioChar != null) { |
|
|
|
setupNotifications(g, callAudioChar) |
|
|
|
setupNotifications(g, audioChar) |
|
|
|
|
|
|
|
|
|
|
|
Log.i(TAG, "通话音频服务特征找到并设置通知") |
|
|
|
|
|
|
|
notificationSetupQueue.add(callAudioChar!!) |
|
|
|
notificationSetupQueue.add(audioChar!!) |
|
|
|
Log.i(TAG, "通话音频服务特征找到,准备串行开启通知") |
|
|
|
} else { |
|
|
|
Log.w(TAG, "通话音频服务特征未找到") |
|
|
|
Log.w(TAG, "通话音频服务特征未完整找到") |
|
|
|
} |
|
|
|
|
|
|
|
setupNotifications(g, notifyChar) |
|
|
|
// 将命令通知通道也纳入串行队列,避免并发写入描述符 |
|
|
|
notifyChar?.let { notificationSetupQueue.add(it) } |
|
|
|
notificationTargetsTotal = notificationSetupQueue.size |
|
|
|
// 启动处理队列 |
|
|
|
processNextNotificationDescriptor(g) |
|
|
|
|
|
|
|
// 在服务发现完成后,请求最大MTU |
|
|
|
//requestMaxMtu(g) |
|
|
|
@ -951,8 +933,27 @@ object BleService { |
|
|
|
override fun onDescriptorWrite( |
|
|
|
g: BluetoothGatt, d: BluetoothGattDescriptor, status: Int |
|
|
|
) { |
|
|
|
if (status == BluetoothGatt.GATT_SUCCESS) |
|
|
|
Log.i(TAG, "通知描述符写入成功: ${d.characteristic.uuid}") |
|
|
|
if (d.uuid == BleConst.CLIENT_CHAR_CONFIG_UUID) { |
|
|
|
val charUuid = d.characteristic.uuid |
|
|
|
if (status == BluetoothGatt.GATT_SUCCESS) { |
|
|
|
Log.i(TAG, "通知描述符写入成功: ${charUuid}") |
|
|
|
notificationTargetsSucceeded++ |
|
|
|
} else { |
|
|
|
Log.e(TAG, "通知描述符写入失败: ${charUuid}, status=${status}") |
|
|
|
} |
|
|
|
|
|
|
|
// 当前一次写入完成,移除队首并继续处理下一个 |
|
|
|
if (notificationSetupQueue.isNotEmpty() && notificationSetupQueue.first().uuid == charUuid) { |
|
|
|
notificationSetupQueue.removeFirst() |
|
|
|
} |
|
|
|
isDescriptorWriteInProgress = false |
|
|
|
// 如果所有通知已处理完毕,且全部成功,则设置PHY |
|
|
|
if (notificationSetupQueue.isEmpty()) { |
|
|
|
onAllNotificationsProcessed(g) |
|
|
|
} else { |
|
|
|
processNextNotificationDescriptor(g) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
@ -1010,6 +1011,66 @@ object BleService { |
|
|
|
} |
|
|
|
return true |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 串行处理通知描述符写入队列 |
|
|
|
* 功能:遵循Android BLE单操作约束,确保按顺序开启各通道通知 |
|
|
|
* @param g BluetoothGatt实例 |
|
|
|
*/ |
|
|
|
private fun processNextNotificationDescriptor(g: BluetoothGatt) { |
|
|
|
if (isDescriptorWriteInProgress) return |
|
|
|
val next = notificationSetupQueue.firstOrNull() ?: run { |
|
|
|
onAllNotificationsProcessed(g) |
|
|
|
return |
|
|
|
} |
|
|
|
val started = setupNotifications(g, next) |
|
|
|
if (started) { |
|
|
|
isDescriptorWriteInProgress = true |
|
|
|
} else { |
|
|
|
// 当前特征无法启动通知,跳过并尝试下一个 |
|
|
|
notificationSetupQueue.removeFirst() |
|
|
|
processNextNotificationDescriptor(g) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 所有通知通道处理完成后的回调:在全部成功时设置PHY |
|
|
|
*/ |
|
|
|
private fun onAllNotificationsProcessed(g: BluetoothGatt) { |
|
|
|
if (notificationTargetsTotal > 0 && notificationTargetsSucceeded == notificationTargetsTotal) { |
|
|
|
applyPreferredPhy(g) |
|
|
|
} else { |
|
|
|
Log.w(TAG, "通知通道未全部注册成功(${notificationTargetsSucceeded}/${notificationTargetsTotal}),跳过PHY设置") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 读取并设置首选PHY为2M(仅API 26+) |
|
|
|
*/ |
|
|
|
private fun applyPreferredPhy(g: BluetoothGatt) { |
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
|
|
|
try { |
|
|
|
val readResult = g.readPhy() |
|
|
|
Log.d(TAG, "读取PHY状态请求结果: $readResult") |
|
|
|
Handler(Looper.getMainLooper()).postDelayed({ |
|
|
|
try { |
|
|
|
val setResult = g.setPreferredPhy( |
|
|
|
BluetoothDevice.PHY_LE_2M_MASK, |
|
|
|
BluetoothDevice.PHY_LE_2M_MASK, |
|
|
|
BluetoothDevice.PHY_OPTION_NO_PREFERRED |
|
|
|
) |
|
|
|
Log.d(TAG, "设置PHY为2M请求结果: $setResult") |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "设置PHY失败: ${e.message}") |
|
|
|
} |
|
|
|
}, 500) |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "读取PHY失败: ${e.message},将使用默认1M PHY") |
|
|
|
} |
|
|
|
} else { |
|
|
|
Log.w(TAG, "当前Android版本不支持PHY设置(需要API 26+),使用默认1M PHY") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 请求最大MTU值 |
|
|
|
@ -1033,6 +1094,7 @@ object BleService { |
|
|
|
* @param data 音频数据 (Opus编码) |
|
|
|
*/ |
|
|
|
private fun processAudioData(data: ByteArray) { |
|
|
|
recordfile?.saveAudioDataToWav(data) |
|
|
|
// 委托给Opus音频管理器处理 |
|
|
|
opusAudioManager.processAudioData(data) |
|
|
|
} |
|
|
|
@ -1344,6 +1406,8 @@ object BleService { |
|
|
|
*/ |
|
|
|
fun closeCodec(): Boolean { |
|
|
|
Log.i(TAG, "关闭编解码...") |
|
|
|
recordfile?.closeFile() |
|
|
|
recordfile1?.closeFile() |
|
|
|
val cmdData = byteArrayOf( |
|
|
|
BleConst.CODEC_CONTROL_CLOSE.toByte(), |
|
|
|
BleConst.AUDIO_CHANNEL_STEREO.toByte() |
|
|
|
@ -1688,5 +1752,3 @@ object BleService { |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|