|
|
|
@ -16,6 +16,8 @@ import java.text.SimpleDateFormat |
|
|
|
import java.util.* |
|
|
|
import com.yunqiinnovation.azure_speech.AzureAsrHelper |
|
|
|
import com.yunqiinnovation.azure_speech.AzureTtsHelper |
|
|
|
import com.yunqiinnovation.jl_opus.JlOpusPlugin |
|
|
|
|
|
|
|
/** |
|
|
|
* BLE服务类,提供核心蓝牙功能 |
|
|
|
*/ |
|
|
|
@ -65,6 +67,9 @@ class BleService(private val context: Context) { |
|
|
|
// Azure服务 |
|
|
|
private var azureAsrHelper: AzureAsrHelper? = null |
|
|
|
private var azureTtsHelper: AzureTtsHelper? = null |
|
|
|
|
|
|
|
// 获取插件实例 |
|
|
|
private val opusPlugin = JlOpusPlugin() |
|
|
|
// 蓝牙管理器和适配器 |
|
|
|
private val bluetoothManager = |
|
|
|
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager |
|
|
|
@ -158,10 +163,10 @@ class BleService(private val context: Context) { |
|
|
|
val deviceAddress = device.address |
|
|
|
val rssi = result.rssi |
|
|
|
val scanRecord = result.scanRecord |
|
|
|
// if (!deviceName.contains("sanag") && !deviceName.contains("Ola Friend")) { |
|
|
|
// return |
|
|
|
// } |
|
|
|
//Log.d(TAG, "============发现设备: $deviceName [$deviceAddress], RSSI: $rssi") |
|
|
|
if (!deviceName.contains("zxd")) { |
|
|
|
return |
|
|
|
} |
|
|
|
Log.d(TAG, "============发现设备: $deviceName [$deviceAddress], RSSI: $rssi") |
|
|
|
|
|
|
|
// 打印所有发现的UUID以便调试 |
|
|
|
val serviceUuids = scanRecord?.serviceUuids |
|
|
|
@ -175,20 +180,20 @@ class BleService(private val context: Context) { |
|
|
|
for (i in 0 until 65535) { |
|
|
|
val manufacturerData = scanRecord?.getManufacturerSpecificData(i) |
|
|
|
if (manufacturerData != null) { |
|
|
|
// Log.d(TAG, "发现厂商ID: $i, 数据长度: ${manufacturerData.size}") |
|
|
|
// Log.d(TAG, "发现厂商ID: $i, 数据长度: ${manufacturerData.size}") |
|
|
|
// 这里可以根据已知的厂商ID和格式解析数据 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 避免重复添加 |
|
|
|
|
|
|
|
|
|
|
|
val existingIndex = scanResults.indexOfFirst { it.device.address == deviceAddress } |
|
|
|
|
|
|
|
|
|
|
|
if (existingIndex >= 0) { |
|
|
|
|
|
|
|
|
|
|
|
scanResults[existingIndex] = result |
|
|
|
} else { |
|
|
|
Log.d(TAG, "扫描回调A, scanResults[existingIndex]ADD") |
|
|
|
Log.d(TAG, "扫描回调A, scanResults[existingIndex]ADD") |
|
|
|
scanResults.add(result) |
|
|
|
} |
|
|
|
|
|
|
|
@ -333,6 +338,7 @@ class BleService(private val context: Context) { |
|
|
|
updateConnectionState(STATE_ERROR) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 添加扩展函数(在文件顶部声明) |
|
|
|
fun List<Byte>.toByteArray(): ByteArray { |
|
|
|
return ByteArray(this.size) { this[it] } |
|
|
|
@ -345,6 +351,12 @@ class BleService(private val context: Context) { |
|
|
|
val characteristicUuid = characteristic.uuid.toString() |
|
|
|
Log.d(TAG, "收到特征变化通知: $characteristicUuid") |
|
|
|
|
|
|
|
opusPlugin?.startOpusDecodeStream(false, 1, 16000, 40, object : |
|
|
|
JlOpusPlugin.Callback1 { |
|
|
|
override fun onAudioDataReceived1(pcmData: ByteArray) { |
|
|
|
Log.i(TAG, "收到解码控制通知: ${pcmData.contentToString()}") |
|
|
|
// 处理解码后的 PCM 数据(如播放或写入文件) |
|
|
|
}}) |
|
|
|
when (characteristicUuid) { |
|
|
|
// NOTIFY_CHAR_UUID -> { |
|
|
|
// // 收到音频数据 |
|
|
|
@ -362,11 +374,12 @@ class BleService(private val context: Context) { |
|
|
|
if (value.isNotEmpty() && (value[0].toInt() and 0xFF == 0x4b || value[0].toInt() and 0xFF == 0x48)) { |
|
|
|
// 处理设备返回的协议数据 |
|
|
|
fos?.write(value) |
|
|
|
// 方法1:手动转换 |
|
|
|
val byteArray = ByteArray(value.size) { index -> value[index] } |
|
|
|
|
|
|
|
// 或者直接使用现有 |
|
|
|
azureAsrHelper?.pushAudioData(byteArray) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
opusPlugin?.handleDecodeRequest(value) |
|
|
|
|
|
|
|
//callback?.onAudioDataReceived(value) |
|
|
|
} |
|
|
|
// 判断是否是协议格式响应 |
|
|
|
if (value.isNotEmpty() && value[0].toInt() and 0xFF == 0xA5) { |
|
|
|
@ -508,7 +521,8 @@ val byteArray = ByteArray(value.size) { index -> value[index] } |
|
|
|
writeChar?.value = commandData |
|
|
|
// 获取外部存储目录路径 |
|
|
|
// 生成带时间戳的文件名(格式:yyyyMMdd_HHmmss_audio.opus) |
|
|
|
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date()) |
|
|
|
val timeStamp = |
|
|
|
SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date()) |
|
|
|
val fileName = "${timeStamp}_audio.opus" |
|
|
|
val externalDir = context.getExternalFilesDir(null) |
|
|
|
outputFile = File(externalDir, fileName) |
|
|
|
@ -519,10 +533,10 @@ val byteArray = ByteArray(value.size) { index -> value[index] } |
|
|
|
// val subscriptionKey = call.argument<String>("subscriptionKey") ?: "" |
|
|
|
// val region = call.argument<String>("region") ?: "" |
|
|
|
// val supportedLanguages = call.argument<List<String>>("supportedLanguages") ?: listOf("zh-CN") |
|
|
|
|
|
|
|
|
|
|
|
// val success = azureAsrHelper.initialize(subscriptionKey, region, supportedLanguages.toTypedArray()) |
|
|
|
// result.success(success) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val success = bluetoothGatt?.writeCharacteristic(writeChar) ?: false |
|
|
|
|
|
|
|
@ -599,7 +613,8 @@ val byteArray = ByteArray(value.size) { index -> value[index] } |
|
|
|
(volumeData.toInt() and 0xFF)) and 0xFF |
|
|
|
|
|
|
|
// 创建完整命令 |
|
|
|
val commandData = byteArrayOf(header, fieldType, dataLen, volumeData, checksum.toByte()) |
|
|
|
val commandData = |
|
|
|
byteArrayOf(header, fieldType, dataLen, volumeData, checksum.toByte()) |
|
|
|
|
|
|
|
// 写入特征 |
|
|
|
writeChar?.value = commandData |
|
|
|
@ -646,4 +661,4 @@ val byteArray = ByteArray(value.size) { index -> value[index] } |
|
|
|
notifyChar = null |
|
|
|
writeChar = null |
|
|
|
} |
|
|
|
} |
|
|
|
} |