You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
323 lines
8.6 KiB
323 lines
8.6 KiB
import 'dart:async';
|
|
import 'dart:typed_data';
|
|
import 'package:flutter/material.dart' hide ConnectionState;
|
|
import 'package:get/get.dart';
|
|
import 'package:jieli/jieli.dart';
|
|
|
|
/// 杰理测试控制器
|
|
class JieliTestController extends GetxController {
|
|
// Jieli插件实例
|
|
late Jieli jieli;
|
|
|
|
// 状态变量
|
|
var isScanning = false.obs;
|
|
var deviceInfo = '未获取'.obs;
|
|
var connectStatus = '未连接'.obs;
|
|
var currentDevice = Rx<BleDevice?>(null);
|
|
var scannedDevices = RxList<BleDevice>([]);
|
|
var wakeupReceived = false.obs;
|
|
var audioDataSize = 0.obs;
|
|
var receivedFrames = 0.obs;
|
|
var audioDataReceiving = false.obs;
|
|
var volumeCommandResult = ''.obs;
|
|
|
|
// 事件订阅
|
|
StreamSubscription? _scanSubscription;
|
|
StreamSubscription? _connectionSubscription;
|
|
StreamSubscription? _wakeupSubscription;
|
|
StreamSubscription? _audioSubscription;
|
|
StreamSubscription? _commandResultSubscription;
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
_initializeJieli();
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
_cancelAllSubscriptions();
|
|
_disposeJieli();
|
|
super.onClose();
|
|
}
|
|
|
|
/// 取消所有订阅
|
|
void _cancelAllSubscriptions() {
|
|
_scanSubscription?.cancel();
|
|
_connectionSubscription?.cancel();
|
|
_wakeupSubscription?.cancel();
|
|
_audioSubscription?.cancel();
|
|
_commandResultSubscription?.cancel();
|
|
}
|
|
|
|
/// 初始化杰理SDK
|
|
void _initializeJieli() {
|
|
try {
|
|
jieli = Jieli();
|
|
_setupEventListeners();
|
|
} catch (e) {
|
|
// 初始化错误处理
|
|
}
|
|
}
|
|
|
|
/// 设置事件监听器
|
|
void _setupEventListeners() {
|
|
// 监听扫描结果
|
|
_scanSubscription = jieli.scanResults.listen((devices) {
|
|
scannedDevices.assignAll(devices);
|
|
});
|
|
|
|
// 监听连接状态
|
|
_connectionSubscription = jieli.connectionState.listen((state) {
|
|
switch (state) {
|
|
case ConnectionState.connected:
|
|
connectStatus.value = '已连接';
|
|
break;
|
|
case ConnectionState.disconnected:
|
|
connectStatus.value = '已断开';
|
|
currentDevice.value = null;
|
|
break;
|
|
case ConnectionState.connecting:
|
|
connectStatus.value = '连接中...';
|
|
break;
|
|
case ConnectionState.disconnecting:
|
|
connectStatus.value = '断开中...';
|
|
break;
|
|
case ConnectionState.error:
|
|
connectStatus.value = '连接错误';
|
|
break;
|
|
}
|
|
});
|
|
|
|
// 监听唤醒信号
|
|
_wakeupSubscription = jieli.wakeupStream.listen((wakeup) {
|
|
wakeupReceived.value = true;
|
|
Get.snackbar('收到唤醒信号', '耳机发送了唤醒信号');
|
|
});
|
|
|
|
// 监听音频数据
|
|
_audioSubscription = jieli.audioDataStream.listen((data) {
|
|
// 更新音频数据统计
|
|
audioDataSize.value += data.length;
|
|
receivedFrames.value++;
|
|
audioDataReceiving.value = true;
|
|
});
|
|
|
|
// 监听命令结果
|
|
_commandResultSubscription = jieli.commandResultStream.listen((result) {
|
|
// 处理音量调整命令结果
|
|
if (result.commandType == Jieli.commandTypeVolume) {
|
|
volumeCommandResult.value = result.success ? '音量调整成功' : '音量调整失败';
|
|
Get.snackbar(
|
|
result.success ? '音量调整成功' : '音量调整失败',
|
|
result.success ? '设备已更新音量' : '设备未能更新音量',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: result.success ? Colors.green.withOpacity(0.7) : Colors.red.withOpacity(0.7),
|
|
colorText: Colors.white,
|
|
duration: Duration(seconds: 2),
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
/// 检查蓝牙状态
|
|
Future<bool> checkBluetoothStatus() async {
|
|
try {
|
|
final isEnabled = await jieli.isBluetoothEnabled();
|
|
if (!isEnabled) {
|
|
return await jieli.requestBluetoothEnable();
|
|
}
|
|
return true;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 开始扫描设备
|
|
Future<void> startScan() async {
|
|
if (isScanning.value) return;
|
|
|
|
final bluetoothReady = await checkBluetoothStatus();
|
|
if (!bluetoothReady) {
|
|
Get.snackbar('蓝牙未启用', '请启用蓝牙后再试');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
isScanning.value = true;
|
|
|
|
// 清空之前的设备列表
|
|
scannedDevices.clear();
|
|
|
|
// 开始扫描,10秒后自动停止
|
|
final success = await jieli.startScan(scanTimeout: 10000);
|
|
|
|
if (!success) {
|
|
isScanning.value = false;
|
|
Get.snackbar('扫描失败', '启动扫描设备失败,请检查蓝牙权限');
|
|
}
|
|
|
|
// 10秒后自动更新UI状态
|
|
Future.delayed(Duration(milliseconds: 10000), () {
|
|
isScanning.value = false;
|
|
});
|
|
|
|
} catch (e) {
|
|
isScanning.value = false;
|
|
Get.snackbar('扫描错误', e.toString());
|
|
}
|
|
}
|
|
|
|
/// 停止扫描
|
|
Future<void> stopScan() async {
|
|
if (!isScanning.value) return;
|
|
|
|
try {
|
|
await jieli.stopScan();
|
|
isScanning.value = false;
|
|
} catch (e) {
|
|
// 停止扫描错误处理
|
|
}
|
|
}
|
|
|
|
/// 连接到指定设备
|
|
Future<void> connectToDevice(BleDevice device) async {
|
|
try {
|
|
// 先断开当前连接
|
|
if (currentDevice.value != null) {
|
|
await disconnectDevice();
|
|
}
|
|
|
|
// 更新UI状态
|
|
connectStatus.value = '连接中...';
|
|
|
|
// 重置音频和唤醒相关的状态
|
|
wakeupReceived.value = false;
|
|
audioDataSize.value = 0;
|
|
receivedFrames.value = 0;
|
|
audioDataReceiving.value = false;
|
|
|
|
// 连接设备
|
|
final success = await jieli.connect(device.id);
|
|
|
|
if (success) {
|
|
// 连接成功,更新当前设备
|
|
currentDevice.value = device;
|
|
deviceInfo.value = '设备名称: ${device.name}\n设备ID: ${device.id}\nRSSI: ${device.rssi} dBm';
|
|
} else {
|
|
deviceInfo.value = '连接失败';
|
|
}
|
|
} catch (e) {
|
|
deviceInfo.value = '连接错误: ${e.toString()}';
|
|
}
|
|
}
|
|
|
|
/// 断开设备连接
|
|
Future<void> disconnectDevice() async {
|
|
if (currentDevice.value == null) return;
|
|
|
|
try {
|
|
connectStatus.value = '断开中...';
|
|
|
|
final success = await jieli.disconnect();
|
|
|
|
if (success) {
|
|
deviceInfo.value = '未连接设备';
|
|
}
|
|
|
|
} catch (e) {
|
|
// 断开连接错误处理
|
|
}
|
|
}
|
|
|
|
/// 发送开始录音命令
|
|
Future<void> sendStartRecordingCommand() async {
|
|
if (currentDevice.value == null) {
|
|
Get.snackbar('操作失败', '未连接设备');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
final success = await jieli.sendStartRecordingCommand();
|
|
|
|
if (success) {
|
|
Get.snackbar('命令已发送', '已发送开始录音命令');
|
|
} else {
|
|
Get.snackbar('命令发送失败', '发送开始录音命令失败');
|
|
}
|
|
} catch (e) {
|
|
Get.snackbar('命令错误', e.toString());
|
|
}
|
|
}
|
|
|
|
/// 发送停止录音命令
|
|
Future<void> sendStopRecordingCommand() async {
|
|
if (currentDevice.value == null) {
|
|
Get.snackbar('操作失败', '未连接设备');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
final success = await jieli.sendStopRecordingCommand();
|
|
|
|
if (success) {
|
|
Get.snackbar('命令已发送', '已发送停止录音命令');
|
|
} else {
|
|
Get.snackbar('命令发送失败', '发送停止录音命令失败');
|
|
}
|
|
} catch (e) {
|
|
Get.snackbar('命令错误', e.toString());
|
|
}
|
|
}
|
|
|
|
/// 增加音量
|
|
Future<void> increaseVolume() async {
|
|
if (currentDevice.value == null) {
|
|
Get.snackbar('操作失败', '未连接设备');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
volumeCommandResult.value = '发送中...';
|
|
final success = await jieli.increaseVolume();
|
|
|
|
if (!success) {
|
|
Get.snackbar('命令发送失败', '发送增加音量命令失败');
|
|
volumeCommandResult.value = '发送失败';
|
|
}
|
|
} catch (e) {
|
|
Get.snackbar('命令错误', e.toString());
|
|
volumeCommandResult.value = '发送出错';
|
|
}
|
|
}
|
|
|
|
/// 减小音量
|
|
Future<void> decreaseVolume() async {
|
|
if (currentDevice.value == null) {
|
|
Get.snackbar('操作失败', '未连接设备');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
volumeCommandResult.value = '发送中...';
|
|
final success = await jieli.decreaseVolume();
|
|
|
|
if (!success) {
|
|
Get.snackbar('命令发送失败', '发送减小音量命令失败');
|
|
volumeCommandResult.value = '发送失败';
|
|
}
|
|
} catch (e) {
|
|
Get.snackbar('命令错误', e.toString());
|
|
volumeCommandResult.value = '发送出错';
|
|
}
|
|
}
|
|
|
|
/// 清理资源
|
|
void _disposeJieli() {
|
|
try {
|
|
jieli.dispose();
|
|
} catch (e) {
|
|
// 释放资源错误处理
|
|
}
|
|
}
|
|
}
|