Browse Source

opus日记打印

newdev_shunjiawei
fdp 1 year ago
parent
commit
177ce47bde
  1. 2
      lib/modules/opus_test/controllers/opus_test_controller.dart
  2. 44
      lib/modules/settings/views/settings_view.dart
  3. 68
      local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt

2
lib/modules/opus_test/controllers/opus_test_controller.dart

@ -140,7 +140,7 @@ class OpusTestController extends GetxController {
for (var entity in files) { for (var entity in files) {
if (entity is File) { if (entity is File) {
final path = entity.path.toLowerCase(); final path = entity.path.toLowerCase();
if (path.endsWith('.opus')) { if (path.endsWith('.opus') || path.endsWith('.txt')) {
final fileSize = await entity.length(); final fileSize = await entity.length();
externalFiles.add(PlatformFile( externalFiles.add(PlatformFile(
name: entity.path.split('/').last, name: entity.path.split('/').last,

44
lib/modules/settings/views/settings_view.dart

@ -514,28 +514,28 @@ class SettingsView extends GetView<SettingsController> {
// color: isDarkMode // color: isDarkMode
// ? Colors.white.withOpacity(0.1) // ? Colors.white.withOpacity(0.1)
// : Colors.grey[200]), // : Colors.grey[200]),
// //BLE测试 //BLE测试
// _buildSimpleNavigationSetting( _buildSimpleNavigationSetting(
// title: 'opus解码测试', title: 'opus解码测试',
// subtitle: '测试opus解码', subtitle: '测试opus解码',
// icon: Icons.bluetooth_searching, icon: Icons.bluetooth_searching,
// iconBgColor: isDarkMode iconBgColor: isDarkMode
// ? Colors.green[900]!.withOpacity(0.3) ? Colors.green[900]!.withOpacity(0.3)
// : Colors.green[100]!, : Colors.green[100]!,
// iconColor: iconColor:
// isDarkMode ? Colors.green[300]! : Colors.green[600]!, isDarkMode ? Colors.green[300]! : Colors.green[600]!,
// titleColor: isDarkMode ? Colors.white : null, titleColor: isDarkMode ? Colors.white : null,
// subtitleColor: isDarkMode ? Colors.white70 : null, subtitleColor: isDarkMode ? Colors.white70 : null,
// onTap: () { onTap: () {
// Get.toNamed(Routes.opusTest); Get.toNamed(Routes.opusTest);
// }, },
// isDarkMode: isDarkMode, isDarkMode: isDarkMode,
// ), ),
// Divider( Divider(
// height: 1, height: 1,
// color: isDarkMode color: isDarkMode
// ? Colors.white.withOpacity(0.1) ? Colors.white.withOpacity(0.1)
// : Colors.grey[200]), : Colors.grey[200]),
// BLE测试 // BLE测试
// _buildSimpleNavigationSetting( // _buildSimpleNavigationSetting(

68
local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt

@ -1360,7 +1360,7 @@ startBytesStatistics()
if (data != null) { if (data != null) {
// 编码完成的数据处理: // 编码完成的数据处理:
// 1. 保存到WAV文件 // 1. 保存到WAV文件
recordfile1?.saveAudioDataToWav(data)
// 2. 将编码后的数据加入发送队列进行分块发送 // 2. 将编码后的数据加入发送队列进行分块发送
addAudioDataToSendQueue(data) addAudioDataToSendQueue(data)
} else { } else {
@ -1493,13 +1493,16 @@ startBytesStatistics()
audioSendHandler.post { audioSendHandler.post {
try { try {
callWriteChar?.value = chunk callWriteChar?.value = chunk
recordfile1?.saveAudioDataAsUtf8Hex(chunk, true)
val isSuccess = bluetoothGatt?.writeCharacteristic(callWriteChar) val isSuccess = bluetoothGatt?.writeCharacteristic(callWriteChar)
if (isSuccess == true) { if (isSuccess == true) {
recordfile1?.saveAudioDataToWav("发送成功,大小: ${chunk.size} 字节")
// 累加发送成功的字节数 // 累加发送成功的字节数
bytesSentInCurrentSecond += chunk.size bytesSentInCurrentSecond += chunk.size
Log.d(TAG, "成功发送音频数据块,大小: ${chunk.size} 字节") Log.d(TAG, "成功发送音频数据块,大小: ${chunk.size} 字节")
} else { } else {
recordfile1?.saveAudioDataToWav("发送失败,大小: ${chunk.size} 字节")
Log.e(TAG, "发送音频数据块失败,大小: ${chunk.size} 字节") Log.e(TAG, "发送音频数据块失败,大小: ${chunk.size} 字节")
// 详细的失败原因分析 // 详细的失败原因分析
val failureReason = StringBuilder("发送音频数据块失败,大小: ${chunk.size} 字节") val failureReason = StringBuilder("发送音频数据块失败,大小: ${chunk.size} 字节")
@ -1636,7 +1639,6 @@ startBytesStatistics()
*/ */
fun closeCodec(): Boolean { fun closeCodec(): Boolean {
Log.i(TAG, "关闭编解码...") Log.i(TAG, "关闭编解码...")
return sendCommand( return sendCommand(
BleConst.CMD_CONTROL_CODEC.toByte(), BleConst.CMD_CONTROL_CODEC.toByte(),
byteArrayOf( byteArrayOf(
@ -1646,12 +1648,7 @@ startBytesStatistics()
) // 或其他默认声道 ) // 或其他默认声道
) )
} }
fun closeCodec1(): Boolean {
recordfile1!!.closeFile()
recordfile!!.closeFile()
return true
}
/** /**
* 控制编解码 - 打开解码 * 控制编解码 - 打开解码
*/ */
@ -1682,6 +1679,7 @@ startBytesStatistics()
*/ */
fun openA2DPDecoder(): Boolean { fun openA2DPDecoder(): Boolean {
Log.i(TAG, "打开编码 0xA2") Log.i(TAG, "打开编码 0xA2")
startOpusEncodeStream() startOpusEncodeStream()
//双声道 80字节 //双声道 80字节
startOpusStreamDecoding(false, 2, 16000, 80) startOpusStreamDecoding(false, 2, 16000, 80)
@ -1724,10 +1722,7 @@ startBytesStatistics()
*/ */
fun openEncoder(): Boolean { fun openEncoder(): Boolean {
Log.i(TAG, "打开编码0xB1") Log.i(TAG, "打开编码0xB1")
recordfile1!!.closeFile()
recordfile1!!.creatingFiles()
recordfile!!.closeFile()
recordfile!!.creatingFiles()
startOpusStreamDecoding(false, 1, 16000, 40) startOpusStreamDecoding(false, 1, 16000, 40)
// // 目前仅发送命令通知设备开始编码。 // // 目前仅发送命令通知设备开始编码。
// return sendCommand( // return sendCommand(
@ -2096,7 +2091,7 @@ class RecordingFile(private val context: Context) {
val timestamp = dateFormat.format(Date()) val timestamp = dateFormat.format(Date())
val filePath = val filePath =
File(context.getExternalFilesDir(null), "${fileName}_${timestamp}.opus").absolutePath File(context.getExternalFilesDir(null), "${fileName}_${timestamp}.txt").absolutePath
currentAudioFile = File(filePath) currentAudioFile = File(filePath)
currentAudioFile?.createNewFile() currentAudioFile?.createNewFile()
// 追加音频数据到文件 // 追加音频数据到文件
@ -2124,11 +2119,12 @@ class RecordingFile(private val context: Context) {
/** /**
* 保存音频数据到 opus 文件(异步) * 保存音频数据到 opus 文件(异步)
* @param buffer 音频数据字节数组
*/ */
internal fun saveAudioDataToWav(buffer: ByteArray) { internal fun saveAudioDataToWav(buffer: ByteArray) {
if (fos == null || currentAudioFile == null) return if (fos == null || currentAudioFile == null) return
// 放入队列,由写线程写入 // 放入队列,由写线程写入
// 1. 将字节数据转换为十六进制字符串 // // 1. 将字节数据转换为十六进制字符串
// val hexData = buildString { // val hexData = buildString {
// buffer.forEachIndexed { index, byte -> // buffer.forEachIndexed { index, byte ->
// append("%02X".format(byte)) // append("%02X".format(byte))
@ -2142,6 +2138,52 @@ class RecordingFile(private val context: Context) {
totalBytesWritten += buffer.size totalBytesWritten += buffer.size
} }
/**
* 保存日志信息到文件(重载方法)
* 使用UTF-8编码处理字符串
* @param logMessage 日志消息字符串
*/
internal fun saveAudioDataToWav(logMessage: String) {
if (fos == null || currentAudioFile == null) return
try {
// 使用UTF-8编码将字符串转换为字节数组,并添加换行符
val logBytes = (logMessage + "\n").toByteArray(Charsets.UTF_8)
writeQueue.offer(logBytes)
totalBytesWritten += logBytes.size
Log.d("RecordingFile", "保存日志信息: ${logMessage.length} 字符, ${logBytes.size} 字节 (UTF-8)")
} catch (e: Exception) {
Log.e("RecordingFile", "UTF-8编码转换失败: ${e.message}")
}
}
/**
* 将音频数据转换为UTF-8编码的十六进制字符串格式并保存
* @param buffer 音频数据字节数组
* @param addTimestamp 是否添加时间戳,默认为true
*/
internal fun saveAudioDataAsUtf8Hex(buffer: ByteArray, addTimestamp: Boolean = true) {
if (fos == null || currentAudioFile == null) return
try {
val timestamp = if (addTimestamp) {
"[${SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault()).format(Date())}] "
} else ""
// 将字节数组转换为十六进制字符串
val hexString = buffer.joinToString(" ") { "%02X".format(it) }
val dataLine = "${timestamp}音频数据 (${buffer.size} 字节): $hexString\n"
// 使用UTF-8编码转换为字节数组
val utf8Bytes = dataLine.toByteArray(Charsets.UTF_8)
writeQueue.offer(utf8Bytes)
totalBytesWritten += utf8Bytes.size
Log.d("RecordingFile", "保存UTF-8格式音频数据: ${buffer.size} 字节 -> ${utf8Bytes.size} UTF-8字节")
} catch (e: Exception) {
Log.e("RecordingFile", "UTF-8格式保存失败: ${e.message}")
}
}
internal fun closeFile() { internal fun closeFile() {
try { try {

Loading…
Cancel
Save