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.

283 lines
7.6 KiB

import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/services.dart';
/// 设备类,代表一个BLE设备
class BleDevice {
final String id;
final String name;
final int rssi;
BleDevice({required this.id, required this.name, required this.rssi});
factory BleDevice.fromJson(Map<String, dynamic> json) {
return BleDevice(
id: json['id'] as String,
name: json['name'] as String? ?? 'Unknown Device',
rssi: json['rssi'] as int? ?? 0,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'rssi': rssi,
};
}
@override
String toString() => 'BleDevice(id: $id, name: $name, rssi: $rssi)';
}
/// 连接状态
enum ConnectionState {
disconnected,
connecting,
connected,
disconnecting,
error
}
/// 事件类型
class EventType {
static const String audioData = 'audio_data';
static const String connectionState = 'connection_state';
static const String scanResult = 'scan_result';
static const String wakeupSignal = 'wakeup_signal';
static const String commandResult = 'command_result';
}
/// 杰理BLE插件主类
class Jieli {
static const MethodChannel _methodChannel =
MethodChannel('com.yunqiinnovation.jieli');
static const EventChannel _eventChannel =
EventChannel('com.yunqiinnovation.jieli/events');
/// 扫描结果流
static final StreamController<List<BleDevice>> _scanController =
StreamController<List<BleDevice>>.broadcast();
Stream<List<BleDevice>> get scanResults => _scanController.stream;
/// 连接状态变化流
static final StreamController<ConnectionState> _connectionController =
StreamController<ConnectionState>.broadcast();
Stream<ConnectionState> get connectionState => _connectionController.stream;
/// 音频数据流
static final StreamController<Uint8List> _audioController =
StreamController<Uint8List>.broadcast();
Stream<Uint8List> get audioDataStream => _audioController.stream;
/// 唤醒信号流
static final StreamController<bool> _wakeupController =
StreamController<bool>.broadcast();
Stream<bool> get wakeupStream => _wakeupController.stream;
/// 命令结果流
static final StreamController<CommandResult> _commandResultController =
StreamController<CommandResult>.broadcast();
Stream<CommandResult> get commandResultStream =>
_commandResultController.stream;
/// 原始事件流
Stream<Map<String, dynamic>>? _eventStream;
/// 事件流订阅
StreamSubscription? _eventSubscription;
/// 命令类型常量
static const int commandTypeVolume = 1;
/// 构造函数,初始化平台通道和事件监听
Jieli() {
_setupEventListener();
}
/// 设置事件监听器
void _setupEventListener() {
_eventSubscription =
_eventChannel.receiveBroadcastStream().listen(_handleEvent);
}
/// 处理来自原生平台的事件
void _handleEvent(dynamic event) {
if (event is! Map<dynamic, dynamic>) return;
final eventData = Map<String, dynamic>.from(event);
final String eventType = eventData['type'] as String;
final dynamic data = eventData['data'];
switch (eventType) {
case EventType.scanResult:
if (data is List<dynamic>) {
final deviceList = data
.map(
(item) => BleDevice.fromJson(Map<String, dynamic>.from(item)))
.toList();
_scanController.add(deviceList);
}
break;
case EventType.connectionState:
if (data is int && data >= 0 && data < ConnectionState.values.length) {
_connectionController.add(ConnectionState.values[data]);
}
break;
case EventType.audioData:
if (data is Uint8List) {
//print('收到ble通道消息: $data');
_audioController.add(data);
}
break;
case EventType.wakeupSignal:
if (data is bool) {
_wakeupController.add(data);
}
break;
case EventType.commandResult:
if (data is Map<dynamic, dynamic>) {
final commandType = data['commandType'] as int;
final success = data['success'] as bool;
_commandResultController.add(CommandResult(
commandType: commandType,
success: success,
));
}
break;
}
}
/// 开始扫描BLE设备
Future<bool> startScan({int scanTimeout = 10000}) async {
final result = await _methodChannel.invokeMethod<bool>(
'startScan',
{'scanTimeout': scanTimeout},
);
return result ?? false;
}
/// 停止扫描BLE设备
Future<bool> stopScan() async {
final result = await _methodChannel.invokeMethod<bool>('stopScan');
return result ?? false;
}
/// 连接到指定设备
Future<bool> connect(String deviceId) async {
final result = await _methodChannel.invokeMethod<bool>(
'connect',
{'deviceId': deviceId},
);
return result ?? false;
}
/// 断开连接
Future<bool> disconnect() async {
final result = await _methodChannel.invokeMethod<bool>('disconnect');
return result ?? false;
}
/// 发送开始录音命令
Future<bool> sendStartRecordingCommand() async {
final result =
await _methodChannel.invokeMethod<bool>('sendStartRecordingCommand');
return result ?? false;
}
/// 发送停止录音命令
Future<bool> sendStopRecordingCommand() async {
final result =
await _methodChannel.invokeMethod<bool>('sendStopRecordingCommand');
return result ?? false;
}
/// 关闭插件,释放资源
Future<void> dispose() async {
await stopScan();
// await disconnect();
// _eventSubscription?.cancel();
// _scanController.close();
// _connectionController.close();
// _audioController.close();
// _wakeupController.close();
// _commandResultController.close();
}
/// 检查蓝牙是否已启用
Future<bool> isBluetoothEnabled() async {
final result =
await _methodChannel.invokeMethod<bool>('isBluetoothEnabled');
return result ?? false;
}
/// 请求打开蓝牙
Future<bool> requestBluetoothEnable() async {
final result =
await _methodChannel.invokeMethod<bool>('requestBluetoothEnable');
return result ?? false;
}
/// 调整音量
/// [volume] 音量值,范围0-16
Future<bool> adjustVolume(int volume) async {
try {
final result = await _methodChannel.invokeMethod<bool>(
'adjustVolume',
{'volume': volume},
);
return result ?? false;
} catch (e) {
print('调整音量失败: $e');
return false;
}
}
/// 增加音量
Future<bool> increaseVolume() async {
try {
final result = await _methodChannel.invokeMethod<bool>('increaseVolume');
return result ?? false;
} catch (e) {
print('增加音量失败: $e');
return false;
}
}
/// 减小音量
Future<bool> decreaseVolume() async {
try {
final result = await _methodChannel.invokeMethod<bool>('decreaseVolume');
return result ?? false;
} catch (e) {
print('减小音量失败: $e');
return false;
}
}
/// 命令结果回调
Stream<CommandResult> get onCommandResult => commandResultStream
.where((event) => event.commandType == commandTypeVolume)
.map((event) => event);
}
/// 蓝牙设备模型
class BluetoothDevice {
// ... existing code ...
}
/// 命令结果
class CommandResult {
final int commandType;
final bool success;
CommandResult({
required this.commandType,
required this.success,
});
@override
String toString() =>
'CommandResult{commandType: $commandType, success: $success}';
}