feat: 添加唤醒功能

This commit is contained in:
2025-09-28 18:42:56 +08:00
parent c6765ab29c
commit 5be50b4dbb
18 changed files with 746 additions and 28 deletions

View File

@@ -1,8 +1,8 @@
// 导出核心管理类
export 'src/vosk_wakeword_manager.dart';
import 'src/interface/flutter_vosk_wakeword_platform_interface.dart';
// 导出错误定义
export 'src/vosk_wakeword_error.dart';
class FlutterVoskWakeword {
Future<String?> getPlatformVersion() {
return FlutterVoskWakewordPlatform.instance.getPlatformVersion();
}
}
// 导出数据模型
export 'src/model/recognition_event.dart';

View File

@@ -26,4 +26,7 @@ abstract class FlutterVoskWakewordPlatform extends PlatformInterface {
Future<String?> getPlatformVersion() {
throw UnimplementedError('platformVersion() has not been implemented.');
}
}

View File

@@ -0,0 +1,39 @@
// recognition event type
enum RecognitionEventType {
// partial
partial,
// final result
finalResult,
// wakeword
wakeword,
// error
error
}
// recognition event
class RecognitionEvent {
final RecognitionEventType type;
final String? text;
RecognitionEvent({required this.type, this.text});
factory RecognitionEvent.fromJson(Map<String, dynamic> json) {
return RecognitionEvent(
type: RecognitionEventType.values.firstWhere((e) => e.name == json['type']),
text: json['text'],
);
}
Map<String, dynamic> toJson() {
return {
'type': type.name,
'text': text,
};
}
@override
String toString() {
return 'RecognitionEvent{type: $type, text: $text}';
}
}

View File

@@ -0,0 +1,51 @@
/// Vosk 插件的基础异常类
class VoskWakewordException implements Exception {
final String? message;
VoskWakewordException([this.message]);
@override
String toString() => '$runtimeType: $message';
}
/// 当原生代码无法分配内存时抛出
class VoskWakewordMemoryException extends VoskWakewordException {
VoskWakewordMemoryException(super.message);
}
/// 当模型文件或IO操作失败时抛出
class VoskWakewordIOException extends VoskWakewordException {
VoskWakewordIOException(super.message);
}
/// 当传入无效参数时抛出
class VoskWakewordInvalidArgumentException extends VoskWakewordException {
VoskWakewordInvalidArgumentException(super.message);
}
/// 当状态不正确例如未初始化就调用start时抛出
class VoskWakewordInvalidStateException extends VoskWakewordException {
VoskWakewordInvalidStateException(super.message);
}
/// 当发生未预期的运行时错误时抛出
class VoskWakewordRuntimeException extends VoskWakewordException {
VoskWakewordRuntimeException(super.message);
}
/// 将原生端返回的错误码转换为对应的 Exception
Exception voskStatusToException(String code, String? message) {
switch (code) {
case 'VoskWakewordMemoryException':
return VoskWakewordMemoryException(message);
case 'VoskWakewordIOException':
return VoskWakewordIOException(message);
case 'VoskWakewordInvalidArgumentException':
return VoskWakewordInvalidArgumentException(message);
case 'VoskWakewordInvalidStateException':
return VoskWakewordInvalidStateException(message);
case 'VoskWakewordRuntimeException':
return VoskWakewordRuntimeException(message);
default:
return VoskWakewordException("Unexpected error: $code, message: $message");
}
}

View File

@@ -0,0 +1,77 @@
import 'dart:async';
import 'package:flutter/services.dart';
import 'vosk_wakeword_error.dart';
import 'model/recognition_event.dart';
/// Vosk 唤醒词插件的主接口 (单例模式)
///
/// 这个类负责向原生代码发送指令,并通过 Stream 接收识别事件。
/// 所有的音频采集和处理都在原生端完成。
class FlutterVoskWakeword {
// 私有构造函数
FlutterVoskWakeword._internal();
// 获取唯一实例
static FlutterVoskWakeword get instance => _instance;
// 静态、唯一的实例
static final FlutterVoskWakeword _instance = FlutterVoskWakeword._internal();
// Factory 构造函数返回唯一实例
factory FlutterVoskWakeword() => _instance;
static const MethodChannel _methodChannel = MethodChannel('flutter_vosk_wakeword/methods');
static const EventChannel _eventChannel = EventChannel('flutter_vosk_wakeword/events');
Stream<RecognitionEvent>? _recognitionStream;
/// 监听识别事件的流
Stream<RecognitionEvent> get recognitionStream {
_recognitionStream ??= _eventChannel
.receiveBroadcastStream()
.map((event) => RecognitionEvent.fromJson(Map<String, dynamic>.from(event)));
return _recognitionStream!;
}
/// 初始化 Vosk 引擎和模型
Future<bool> initialize({
// required String modelPath,
required List<String> wakeWords,
}) async {
try {
final result = await _methodChannel.invokeMethod<bool>('initialize', {
// 'modelPath': modelPath,
'wakeWords': wakeWords,
});
return result ?? false;
} on PlatformException catch (e) {
throw voskStatusToException(e.code, e.message);
}
}
/// 开始监听
Future<bool> start() async {
try {
return await _methodChannel.invokeMethod<bool>('start') ?? false;
} on PlatformException catch (e) {
throw voskStatusToException(e.code, e.message);
}
}
/// 停止监听
Future<bool> stop() async {
try {
return await _methodChannel.invokeMethod<bool>('stop') ?? false;
} on PlatformException catch (e) {
throw voskStatusToException(e.code, e.message);
}
}
/// 释放所有原生资源
Future<bool> dispose() async {
try {
return await _methodChannel.invokeMethod<bool>('dispose') ?? false;
} on PlatformException catch (e) {
throw voskStatusToException(e.code, e.message);
}
}
}