Browse Source

暂存

newdev_shunjiawei
fdp 1 year ago
parent
commit
953ab67fb7
  1. 2
      local_plugins/jieli/android/build.gradle.kts
  2. 35
      local_plugins/jieli/android/src/main/kotlin/com/yunqiinnovation/jieli/BleService.kt
  3. 2
      local_plugins/jieli/android/src/main/kotlin/com/yunqiinnovation/jieli/JieliPlugin.kt
  4. 92
      local_plugins/jl_opus/android/src/main/kotlin/com/yunqiinnovation/jl_opus/JlOpusPlugin.kt
  5. 17
      local_plugins/jl_opus/lib/jl_opus.dart

2
local_plugins/jieli/android/build.gradle.kts

@ -53,4 +53,6 @@ dependencies {
implementation("androidx.lifecycle:lifecycle-service:2.4.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2")
implementation(project(":azure_speech"))
implementation(project(":jl_opus"))
implementation(project(":jl_opus"))
}

35
local_plugins/jieli/android/src/main/kotlin/com/yunqiinnovation/jieli/BleService.kt

@ -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
@ -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)
@ -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

2
local_plugins/jieli/android/src/main/kotlin/com/yunqiinnovation/jieli/JieliPlugin.kt

@ -6,6 +6,7 @@ import android.bluetooth.BluetoothManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.util.Log
import androidx.annotation.NonNull
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
@ -91,6 +92,7 @@ class JieliPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, EventChannel
override fun onAudioDataReceived(data: ByteArray) {
pluginScope.launch(Dispatchers.Main) {
Log.d("","数据流onAudioDataReceived${data}")
sendEvent(EVENT_TYPE_AUDIO_DATA, data)
}
}

92
local_plugins/jl_opus/android/src/main/kotlin/com/yunqiinnovation/jl_opus/JlOpusPlugin.kt

@ -25,22 +25,35 @@ class JlOpusPlugin: FlutterPlugin, MethodCallHandler {
private lateinit var context: Context
private var opusManager: OpusManager? = null
private var streamSink: EventChannel.EventSink? = null
// 修正1:正确的主构造函数写法
constructor() {
opusManager = OpusManager()
Log.d(TAG, "OpusManager初始化成功")
}
// 添加主线程Handler用于确保在主线程回调
private val mainHandler = Handler(Looper.getMainLooper())
interface Callback1 {
fun onAudioDataReceived1(data: ByteArray)
}
companion object {
private const val TAG = "JlOpusPlugin"
private const val CHANNEL_NAME = "com.yunqiinnovation.jl_opus"
private const val EVENT_CHANNEL_NAME = "com.yunqiinnovation.jl_opus/events"
}
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
context = flutterPluginBinding.applicationContext
channel = MethodChannel(flutterPluginBinding.binaryMessenger, CHANNEL_NAME)
channel.setMethodCallHandler(this)
eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, EVENT_CHANNEL_NAME)
eventChannel.setStreamHandler(object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
streamSink = events
@ -269,9 +282,88 @@ class JlOpusPlugin: FlutterPlugin, MethodCallHandler {
result.notImplemented()
}
}
}
fun handleDecodeRequest(opusdata: ByteArray) {
Log.d(TAG, "handleDecodeRequest${opusdata}")
if (opusdata == null) {
return
}
if (opusManager?.isDecodeStream == true) {
opusManager?.writeAudioStream(opusdata)
} else {
}
}
fun startOpusDecodeStream(
hasHeader: Boolean,
channel: Int,
sampleRate: Int,
packetSize: Int,
callback: Callback1
) {
Log.d(TAG, "开始解码数据流,startOpusDecodeStream: $opusManager")
// 如果已经在解码流,先停止
if (opusManager?.isDecodeStream == true) {
opusManager?.stopDecodeStream()
}
// 创建解码参数
val option = OpusOption()
.setHasHead(hasHeader)
.setChannel(channel)
.setSampleRate(sampleRate)
.setPacketSize(packetSize)
Log.d(TAG, "开始解码数据流, 参数: $option")
opusManager?.startDecodeStream(option, object : OnDecodeStreamCallback {
override fun onDecodeStream(data: ByteArray?) {
if (data != null) {
Log.d(TAG, "onDecodeStream${data}")
callback.onAudioDataReceived1(data)
sendEventOnMainThread(mapOf(
"event" to "onDecodeStream",
"data" to data
))
}
}
override fun onStart() {
Log.d(TAG, "数据流解码开始")
sendEventOnMainThread(mapOf(
"event" to "onStart",
"type" to "stream"
))
}
override fun onComplete(outPath: String?) {
Log.d(TAG, "数据流解码完成: $outPath")
sendEventOnMainThread(mapOf(
"event" to "onComplete",
"type" to "stream"
))
}
override fun onError(code: Int, message: String?) {
Log.e(TAG, "数据流解码错误: [$code] $message")
sendEventOnMainThread(mapOf(
"event" to "onError",
"type" to "stream",
"code" to code,
"message" to message
))
}
})
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
eventChannel.setStreamHandler(null)
opusManager?.let {

17
local_plugins/jl_opus/lib/jl_opus.dart

@ -80,8 +80,12 @@ class OpusEvent {
/// 杰理OPUS编解码插件
class JlOpus {
static const MethodChannel _methodChannel = MethodChannel('com.yunqiinnovation.jl_opus');
static const EventChannel _eventChannel = EventChannel('com.yunqiinnovation.jl_opus/events');
static const MethodChannel _methodChannel =
MethodChannel('com.yunqiinnovation.jl_opus');
static const EventChannel _eventChannel =
EventChannel('com.yunqiinnovation.jl_opus/events');
static const EventChannel _eventChannel1 =
EventChannel('com.yunqiinnovation.jl_opus/events1');
/// 事件流
Stream<OpusEvent>? _eventStream;
@ -101,7 +105,8 @@ class JlOpus {
}
/// 解码后的数据流
final StreamController<Uint8List> _decodedDataController = StreamController<Uint8List>.broadcast();
final StreamController<Uint8List> _decodedDataController =
StreamController<Uint8List>.broadcast();
/// 获取解码数据流
Stream<Uint8List> get decodedDataStream => _decodedDataController.stream;
@ -135,7 +140,8 @@ class JlOpus {
/// [inPath] 输入文件路径
/// [outPath] 输出文件路径
/// [option] 解码参数
Future<String?> decodeOpusFile(String inPath, String outPath, OpusOption option) async {
Future<String?> decodeOpusFile(
String inPath, String outPath, OpusOption option) async {
try {
final result = await _methodChannel.invokeMethod<String>(
'decodeOpusFile',
@ -169,7 +175,8 @@ class JlOpus {
/// 停止解码OPUS数据流
Future<bool> stopDecodeStream() async {
try {
final result = await _methodChannel.invokeMethod<bool>('stopDecodeStream');
final result =
await _methodChannel.invokeMethod<bool>('stopDecodeStream');
return result ?? false;
} catch (e) {
return false;

Loading…
Cancel
Save