|
|
|
@ -12,6 +12,7 @@ import java.util.concurrent.CopyOnWriteArrayList |
|
|
|
// Import Jieli Opus SDK classes |
|
|
|
import com.jieli.jl_audio_decode.opus.model.OpusOption |
|
|
|
import com.jieli.jl_audio_decode.callback.OnDecodeStreamCallback |
|
|
|
import com.jieli.jl_audio_decode.callback.OnEncodeStreamCallback |
|
|
|
import com.jieli.jl_audio_decode.opus.OpusManager |
|
|
|
import com.jieli.jl_audio_decode.exceptions.OpusException |
|
|
|
|
|
|
|
@ -78,6 +79,7 @@ object BleService { |
|
|
|
private var audioChar: BluetoothGattCharacteristic? = null |
|
|
|
private var writeChar1: BluetoothGattCharacteristic? = null |
|
|
|
var recordfile: RecordingFile? = null |
|
|
|
var recordfile1: RecordingFile? = null |
|
|
|
// 扫描相关 |
|
|
|
private lateinit var scanHandler: Handler |
|
|
|
private val scanResults = ArrayList<ScanResult>() |
|
|
|
@ -173,6 +175,7 @@ object BleService { |
|
|
|
try { |
|
|
|
opusManager = OpusManager() |
|
|
|
startOpusStreamDecoding() |
|
|
|
startEncodeStream() |
|
|
|
Log.d(TAG, "OpusManager初始化成功") |
|
|
|
} catch (e: OpusException) { |
|
|
|
Log.e(TAG, "OpusManager初始化失败: ${e.message}", e) |
|
|
|
@ -180,6 +183,9 @@ object BleService { |
|
|
|
} |
|
|
|
recordfile = RecordingFile(this.context) |
|
|
|
recordfile!!.fileName = "不拆分" |
|
|
|
|
|
|
|
recordfile1 = RecordingFile(this.context) |
|
|
|
recordfile1!!.fileName = "重新压缩" |
|
|
|
isInitialized = true |
|
|
|
Log.d(TAG, "BLE服务初始化成功") |
|
|
|
return true |
|
|
|
@ -953,11 +959,13 @@ object BleService { |
|
|
|
codecStatus == BleConst.CODEC_CONTROL_A2DP_PLAY || |
|
|
|
codecStatus == BleConst.CODEC_CONTROL_ENCODE_ON |
|
|
|
) { |
|
|
|
|
|
|
|
recordfile1!!.closeFile() |
|
|
|
recordfile1!!.creatingFiles() |
|
|
|
recordfile!!.closeFile() |
|
|
|
recordfile!!.creatingFiles() |
|
|
|
} else if (codecStatus == BleConst.CODEC_CONTROL_CLOSE) { |
|
|
|
recordfile!!.closeFile() |
|
|
|
recordfile1!!.closeFile() |
|
|
|
} |
|
|
|
// 声道模式描述 |
|
|
|
val channelDesc = when (channelMode) { |
|
|
|
@ -1152,7 +1160,31 @@ object BleService { |
|
|
|
override fun onDecodeStream(data: ByteArray?) { |
|
|
|
if (data != null) { |
|
|
|
// Log.d(TAG, "Opus解码数据: ${data.size} bytes") |
|
|
|
notifyAudioDataReceived(data) |
|
|
|
//解码数据再重新编码回去 |
|
|
|
val sampleCount = data.size / 4 // 每个样本4字节(左右声道各2字节) |
|
|
|
val leftBuffer = ByteArray(sampleCount * 2) // 左声道缓冲区 |
|
|
|
val rightBuffer = ByteArray(sampleCount * 2) // 右声道缓冲区 |
|
|
|
|
|
|
|
// 拆分交错的左右声道数据 |
|
|
|
for (i in 0 until sampleCount) { |
|
|
|
val stereoIndex = i * 4 |
|
|
|
val monoIndex = i * 2 |
|
|
|
|
|
|
|
// 左声道(低位字节在前,高位字节在后) |
|
|
|
leftBuffer[monoIndex] = data[stereoIndex] |
|
|
|
leftBuffer[monoIndex + 1] = data[stereoIndex + 1] |
|
|
|
|
|
|
|
// 右声道 |
|
|
|
rightBuffer[monoIndex] = data[stereoIndex + 2] |
|
|
|
rightBuffer[monoIndex + 1] = data[stereoIndex + 3] |
|
|
|
} |
|
|
|
|
|
|
|
// // 将左右声道数据分别放入队列 |
|
|
|
// leftChannelQueue.offer(leftBuffer) |
|
|
|
// rightChannelQueue.offer(rightBuffer) |
|
|
|
opusManager?.writeEncodeStream(rightBuffer) |
|
|
|
|
|
|
|
notifyAudioDataReceived(rightBuffer) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -1194,7 +1226,60 @@ object BleService { |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
// ====================================================================================================== |
|
|
|
// Opus 编码相关 |
|
|
|
// ====================================================================================================== |
|
|
|
|
|
|
|
private fun startEncodeStream( |
|
|
|
hasHeader: Boolean = false, // 通常BLE传输的Opus没有文件头 |
|
|
|
channel: Int = 1, |
|
|
|
sampleRate: Int = 16000, // 确认设备端Opus编码采样率 |
|
|
|
packetSize: Int = 40 // 确认设备端Opus编码帧长,必须与iOS版本frameSize保持一致 |
|
|
|
): Boolean { |
|
|
|
if (opusManager == null) { |
|
|
|
Log.e(TAG, "OpusManager未初始化,无法开始编码") |
|
|
|
return false |
|
|
|
} |
|
|
|
// 如果已经在解码流,先停止 |
|
|
|
if (opusManager?.isEncodeStream == true) { |
|
|
|
opusManager?.stopEncodeStream() |
|
|
|
Log.d(TAG, "已停止正在进行的Opus编码流") |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var streamStartedSuccessfully = false |
|
|
|
opusManager?.startEncodeStream(object : OnEncodeStreamCallback { |
|
|
|
override fun onEncodeStream(data: ByteArray?) { |
|
|
|
if (data != null) { |
|
|
|
// Log.d(TAG, "Opus解码数据: ${data.size} bytes") |
|
|
|
//notifyAudioDataReceived(data) |
|
|
|
writeChar1!!.value=data |
|
|
|
recordfile1!!.saveAudioDataToWav(data) |
|
|
|
val isSuccess = bluetoothGatt?.writeCharacteristic(writeChar1) |
|
|
|
if (isSuccess == true) { |
|
|
|
|
|
|
|
Log.d(TAG, "发送opus数据") |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
override fun onStart() { |
|
|
|
streamStartedSuccessfully = true |
|
|
|
Log.i(TAG, "Opus数据流编码已开始") |
|
|
|
// 可以通过回调通知上层解码已开始 |
|
|
|
} |
|
|
|
|
|
|
|
override fun onComplete(outPath: String?) { |
|
|
|
Log.i(TAG, "Opus数据流编码完成: $outPath (通常流式编码不会调用此方法)") |
|
|
|
} |
|
|
|
|
|
|
|
override fun onError(code: Int, message: String?) { |
|
|
|
Log.e(TAG, "Opus数据流编码错误: [$code] $message") |
|
|
|
// 可以通过回调通知上层解码错误 |
|
|
|
} |
|
|
|
}) |
|
|
|
return true // 暂定为调用即成功 |
|
|
|
} |
|
|
|
// ====================================================================================================== |
|
|
|
// 公开的命令接口 |
|
|
|
// ====================================================================================================== |
|
|
|
|