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.
188 lines
5.3 KiB
188 lines
5.3 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';
|
|
}
|
|
|
|
/// 杰理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;
|
|
|
|
/// 事件流订阅
|
|
StreamSubscription? _eventSubscription;
|
|
|
|
/// 构造函数,初始化平台通道和事件监听
|
|
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) {
|
|
_audioController.add(data);
|
|
}
|
|
break;
|
|
case EventType.wakeupSignal:
|
|
if (data is bool) {
|
|
_wakeupController.add(data);
|
|
}
|
|
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();
|
|
}
|
|
|
|
/// 检查蓝牙是否已启用
|
|
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;
|
|
}
|
|
}
|