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 cad58b834..1fa24991d 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 @@ -128,6 +128,11 @@ object BleService { private val MAX_RETRY_COUNT = 1 // 最大重试次数 private val RETRY_DELAY = 30L // 重试延迟时间(毫秒) + // MTU相关变量 + private var currentMtu = 23 // 默认MTU值 + private var maxMtu = 517 // 最大MTU值 (512 + 5字节头部) + private var isWaitingForWriteCallback = false // 是否正在等待写入回调 + // 初始化状态 private var isInitialized = false @@ -859,6 +864,9 @@ object BleService { // 设置主服务的通知 setupNotifications(g, notifyChar) + + // 在服务发现完成后,请求最大MTU + requestMaxMtu(g) } @@ -915,10 +923,10 @@ object BleService { override fun onCharacteristicWrite( g: BluetoothGatt, c: BluetoothGattCharacteristic, status: Int ) { - Log.i( - TAG, - "写入 ${if (status == BluetoothGatt.GATT_SUCCESS) "成功" else "失败"}" - ) + Log.i( + TAG, + "写入 ${if (status == BluetoothGatt.GATT_SUCCESS) "成功" else "失败"}" + ) } override fun onDescriptorWrite( @@ -927,6 +935,22 @@ object BleService { if (status == BluetoothGatt.GATT_SUCCESS) Log.i(TAG, "通知描述符写入成功: ${d.characteristic.uuid}") } + + /** + * MTU变化回调 - 处理MTU协商结果 + */ + override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) { + super.onMtuChanged(gatt, mtu, status) + if (status == BluetoothGatt.GATT_SUCCESS) { + currentMtu = mtu + Log.i(TAG, "MTU协商成功: $mtu 字节") + // 更新音频块大小,预留5字节的ATT头部 + val newChunkSize = (mtu - 5).coerceAtMost(512) + Log.i(TAG, "更新音频块大小为: $newChunkSize 字节") + } else { + Log.w(TAG, "MTU协商失败: status=$status,使用默认MTU: $currentMtu") + } + } } /** @@ -943,6 +967,23 @@ object BleService { desc?.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE g.writeDescriptor(desc) } + + /** + * 请求最大MTU值 + * @param gatt BluetoothGatt实例 + */ + private fun requestMaxMtu(gatt: BluetoothGatt) { + try { + val result = gatt.requestMtu(maxMtu) + if (result) { + Log.i(TAG, "请求MTU $maxMtu 成功") + } else { + Log.w(TAG, "请求MTU $maxMtu 失败") + } + } catch (e: Exception) { + Log.e(TAG, "请求MTU异常: ${e.message}", e) + } + } /** * 处理接收到的音频数据 @@ -1039,9 +1080,9 @@ object BleService { /** - * 启动音频数据发送线程 + * 启动音频数据发送线程(优化版本) */ - private fun startAudioSendThread() { + private fun startAudioSendThread() { if (audioSendThread?.isAlive == true) { Log.d(TAG, "音频发送线程已在运行") return @@ -1056,11 +1097,9 @@ object BleService { // 从队列中取出音频数据块 val audioChunk = audioSendQueue.poll(100, TimeUnit.MILLISECONDS) - if (audioChunk != null) { - // 发送音频数据块 - sendAudioChunk(audioChunk) - - // 控制发送频率,避免蓝牙缓冲区溢出 + if (audioChunk != null&&!isWaitingForWriteCallback) { + // 发送音频数据块并等待回调 + sendAudioChunkWithCallback(audioChunk) Thread.sleep(AUDIO_SEND_INTERVAL) } } catch (e: InterruptedException) { @@ -1088,96 +1127,133 @@ object BleService { Log.i(TAG, "音频发送线程已停止,队列和缓冲区已清空") } - /** - * 发送音频数据块到设备(带重发机制) + /** + * 发送音频数据块并等待写入回调(新方法) * @param chunk 要发送的音频数据块 - * @param retryCount 当前重试次数 */ - private fun sendAudioChunk(chunk: ByteArray, retryCount: Int = 0) { + private fun sendAudioChunkWithCallback(chunk: ByteArray) { try { if (callWriteChar == null || bluetoothGatt == null) { Log.e(TAG, "蓝牙连接或特征值未准备就绪") return } + // 检查数据块大小是否超过当前MTU限制 + val maxDataSize = currentMtu - 5 // 减去ATT头部5字节 + if (chunk.size > maxDataSize) { + Log.w(TAG, "数据块过大 (${chunk.size} > $maxDataSize),分片发送") + // 分片发送 + sendChunksInFragments(chunk, maxDataSize) + return + } + // 在主线程中执行蓝牙写入操作 audioSendHandler.post { try { - callWriteChar?.value = chunk - recordfile1?.saveAudioDataAsUtf8Hex(chunk, true) - val isSuccess = bluetoothGatt?.writeCharacteristic(callWriteChar) - - if (isSuccess == true) { - recordfile1?.saveAudioDataToWav("发送成功,大小: ${chunk.size} 字节") - // 累加发送成功的字节数 - bytesSentInCurrentSecond += chunk.size - Log.d(TAG, "成功发送音频数据块,大小: ${chunk.size} 字节") - } else { - recordfile1?.saveAudioDataToWav("发送失败,大小: ${chunk.size} 字节") - Log.e(TAG, "发送音频数据块失败,大小: ${chunk.size} 字节") - // 详细的失败原因分析 - val failureReason = StringBuilder("发送音频数据块失败,大小: ${chunk.size} 字节") + + isWaitingForWriteCallback = true - // 检查蓝牙连接状态 - if (bluetoothGatt == null) { - failureReason.append(" - 原因: BluetoothGatt为空") - } else { - // 检查连接状态 - val State = bluetoothManager.getConnectionState( - bluetoothGatt!!.device, - BluetoothProfile.GATT - ) - when (State) { - BluetoothProfile.STATE_DISCONNECTED -> { - failureReason.append(" -发送失败 原因: 设备已断开连接") - } - BluetoothProfile.STATE_CONNECTING -> { - failureReason.append(" -发送失败 原因: 设备正在连接中") - } - BluetoothProfile.STATE_DISCONNECTING -> { - failureReason.append(" -发送失败 原因: 设备正在断开连接") - } - BluetoothProfile.STATE_CONNECTED -> { - // 连接正常,检查其他原因 - if (callWriteChar == null) { - failureReason.append(" -发送失败 原因: 写入特征值为空") - } else { - // 检查特征值属性 - val properties = callWriteChar!!.properties - if ((properties and BluetoothGattCharacteristic.PROPERTY_WRITE) == 0 && - (properties and BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) { - failureReason.append(" -发送失败 原因: 特征值不支持写入操作") - } else if (chunk.size > 512) { // BLE MTU通常限制 - failureReason.append(" -发送失败 原因: 数据块过大 (${chunk.size} > 512字节)") - } else { - failureReason.append(" -发送失败 原因: 未知错误,可能是设备忙碌或缓冲区满") - } - } - } - else -> { - failureReason.append(" -发送失败 原因: 未知连接状态($connectionState)") - } - } - } + callWriteChar?.value = chunk + recordfile1?.saveAudioDataAsUtf8Hex(chunk, true) + val isSuccess = bluetoothGatt?.writeCharacteristic(callWriteChar) - // 检查蓝牙适配器状态 - if (bluetoothAdapter?.isEnabled != true) { - failureReason.append(" - 蓝牙适配器未启用") + if (isSuccess == true) { + isWaitingForWriteCallback = false + recordfile1?.saveAudioDataToWav("发送成功,大小: ${chunk.size} 字节") + bytesSentInCurrentSecond += chunk.size + Log.d(TAG, "成功发送音频数据块,大小: ${chunk.size} 字节,等待写入回调...") + } else { + isWaitingForWriteCallback = false + recordfile1?.saveAudioDataToWav("发送失败,大小: ${chunk.size} 字节") + Log.e(TAG, "发送音频数据块失败,大小: ${chunk.size} 字节") + analyzeWriteFailure(chunk) } - - Log.e(TAG, failureReason.toString()) - - - } + } catch (e: Exception) { - Log.e(TAG, "发送音频数据块异常: ${e.message}", e) + Log.e(TAG, "发送音频数据块异常: ${e.message}", e) } } } catch (e: Exception) { Log.e(TAG, "发送音频数据块异常: ${e.message}", e) } } + + /** + * 分片发送大数据块 + * @param data 原始数据 + * @param maxChunkSize 每片的最大大小 + */ + private fun sendChunksInFragments(data: ByteArray, maxChunkSize: Int) { + var offset = 0 + while (offset < data.size) { + val remainingSize = data.size - offset + val chunkSize = minOf(remainingSize, maxChunkSize) + val fragment = data.copyOfRange(offset, offset + chunkSize) + + // 递归调用发送单个片段 + sendAudioChunkWithCallback(fragment) + + offset += chunkSize + } + } + + /** + * 分析写入失败的原因(从原sendAudioChunk方法提取) + * @param chunk 失败的数据块 + */ + private fun analyzeWriteFailure(chunk: ByteArray) { + val failureReason = StringBuilder("发送音频数据块失败,大小: ${chunk.size} 字节") + + // 检查蓝牙连接状态 + if (bluetoothGatt == null) { + failureReason.append(" - 原因: BluetoothGatt为空") + } else { + // 检查连接状态 + val state = bluetoothManager.getConnectionState( + bluetoothGatt!!.device, + BluetoothProfile.GATT + ) + when (state) { + BluetoothProfile.STATE_DISCONNECTED -> { + failureReason.append(" -发送失败 原因: 设备已断开连接") + } + BluetoothProfile.STATE_CONNECTING -> { + failureReason.append(" -发送失败 原因: 设备正在连接中") + } + BluetoothProfile.STATE_DISCONNECTING -> { + failureReason.append(" -发送失败 原因: 设备正在断开连接") + } + BluetoothProfile.STATE_CONNECTED -> { + // 连接正常,检查其他原因 + if (callWriteChar == null) { + failureReason.append(" -发送失败 原因: 写入特征值为空") + } else { + // 检查特征值属性 + val properties = callWriteChar!!.properties + if ((properties and BluetoothGattCharacteristic.PROPERTY_WRITE) == 0 && + (properties and BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) { + failureReason.append(" -发送失败 原因: 特征值不支持写入操作") + } else if (chunk.size > currentMtu - 5) { + failureReason.append(" -发送失败 原因: 数据块过大 (${chunk.size} > ${currentMtu - 5}字节)") + } else { + failureReason.append(" -发送失败 原因: 未知错误,可能是设备忙碌或缓冲区满") + } + } + } + else -> { + failureReason.append(" -发送失败 原因: 未知连接状态($state)") + } + } + } + + // 检查蓝牙适配器状态 + if (bluetoothAdapter?.isEnabled != true) { + failureReason.append(" - 蓝牙适配器未启用") + } + + Log.e(TAG, failureReason.toString()) + } // ====================================================================================================== // 设备控制方法 - 使用新的指令发送器 // ====================================================================================================== @@ -1386,6 +1462,40 @@ object BleService { fun getBluetoothAdapter(): BluetoothAdapter? { return bluetoothAdapter } + + /** + * 获取当前MTU值 + * @return 当前MTU值 + */ + fun getCurrentMtu(): Int { + return currentMtu + } + + /** + * 获取可用的数据传输大小(MTU减去头部) + * @return 可用的数据传输大小 + */ + fun getAvailableDataSize(): Int { + return currentMtu - 5 // 减去ATT头部5字节 + } + + /** + * 手动请求MTU协商 + * @param mtu 请求的MTU值 + * @return 是否成功发起请求 + */ + fun requestMtu(mtu: Int): Boolean { + return bluetoothGatt?.let { gatt -> + try { + val result = gatt.requestMtu(mtu.coerceIn(23, 517)) + Log.i(TAG, "手动请求MTU $mtu: $result") + result + } catch (e: Exception) { + Log.e(TAG, "手动请求MTU异常: ${e.message}", e) + false + } + } ?: false + } // ======================================================================================================