import 'dart:async'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import '../../core/utils/logger.dart'; /// 识别事件类型 enum RecognitionEventType { /// 最终识别结果 finalResult, /// 中间识别结果(实时反馈) recognizing, /// 会话开始 sessionStarted, /// 会话结束 sessionStopped, /// 识别取消 canceled, /// 无匹配结果 noMatch, /// 识别错误 error, } /// 识别事件 class RecognitionEvent { /// 事件类型 final RecognitionEventType type; /// 识别文本(仅在 finalResult 和 recognizing 类型中有效) final String text; /// 错误信息(仅在 error 和 canceled 类型中有效) final String? error; /// 取消原因(仅在 canceled 类型中有效) final String? reason; /// 错误详情(仅在 canceled 类型中有效) final String? errorDetails; RecognitionEvent({ required this.type, this.text = '', this.error, this.reason, this.errorDetails, }); /// 从原生事件映射创建识别事件 factory RecognitionEvent.fromMap(Map map) { final eventType = map['eventType'] as String; RecognitionEventType type; switch (eventType) { case 'recognizing': type = RecognitionEventType.recognizing; break; case 'finalResult': type = RecognitionEventType.finalResult; break; case 'sessionStarted': type = RecognitionEventType.sessionStarted; break; case 'sessionStopped': type = RecognitionEventType.sessionStopped; break; case 'canceled': type = RecognitionEventType.canceled; break; case 'noMatch': type = RecognitionEventType.noMatch; break; case 'error': type = RecognitionEventType.error; break; default: throw ArgumentError('Unknown event type: $eventType'); } return RecognitionEvent( type: type, text: map['text'] as String? ?? '', error: map['error'] as String?, reason: map['reason'] as String?, errorDetails: map['errorDetails'] as String?, ); } @override String toString() { return 'RecognitionEvent{type: $type, text: $text, error: $error, reason: $reason, errorDetails: $errorDetails}'; } } /// Azure 语音识别服务 class AzureAsrService extends GetxService { static AzureAsrService get to => Get.find(); // 方法通道 static const MethodChannel _methodChannel = MethodChannel('com.example.deep_voice/azure_asr'); // 事件通道 static const EventChannel _eventChannel = EventChannel('com.example.deep_voice/azure_asr_events'); // 是否已初始化 bool _isInitialized = false; // 连续识别相关 bool _isContinuousRecognitionActive = false; StreamController? _eventStreamController; StreamSubscription? _eventSubscription; // 公开的事件流 Stream? _recognitionStream; Stream? get recognitionStream => _recognitionStream; // 最新的识别结果 String _latestRecognizedText = ''; String get latestRecognizedText => _latestRecognizedText; /// 初始化 Azure 语音识别服务 /// /// [subscriptionKey] Azure 语音服务的订阅密钥 /// [serviceRegion] Azure 语音服务的区域 /// [language] 识别语言,默认为中文 Future initialize({ required String subscriptionKey, required String serviceRegion, String language = 'zh-CN', }) async { if (_isInitialized) return true; try { final result = await _methodChannel.invokeMethod( 'initialize', { 'subscriptionKey': subscriptionKey, 'serviceRegion': serviceRegion, 'language': language, }, ); _isInitialized = result ?? false; if (_isInitialized) { Logger.info('Azure 语音识别服务初始化成功'); } else { Logger.error('Azure 语音识别服务初始化失败'); } return _isInitialized; } catch (e) { Logger.error('初始化 Azure 语音识别服务失败', e); _isInitialized = false; return false; } } /// 重置识别器 /// 在切换识别模式前调用,确保资源被正确释放 Future _resetRecognizer() async { try { // 如果连续识别正在进行,先停止它 if (_isContinuousRecognitionActive) { await stopContinuousRecognition(); } // 清理事件流资源 _cleanupEventStream(); // 调用原生方法重置识别器 await _methodChannel.invokeMethod('resetRecognizer'); Logger.info('Azure 语音识别器已重置'); return true; } catch (e) { Logger.error('重置 Azure 语音识别器失败', e); return false; } } /// 执行一次性语音识别 Future recognizeOnce() async { _checkInitialized(); try { // 重置识别器,确保资源被正确释放 await _resetRecognizer(); final result = await _methodChannel.invokeMethod('recognizeOnce'); final text = result ?? ''; _latestRecognizedText = text; return text; } catch (e) { Logger.error('一次性语音识别失败', e); rethrow; } } /// 开始连续语音识别 /// /// 返回一个布尔值,表示是否成功启动连续识别 Future startContinuousRecognition() async { _checkInitialized(); if (_isContinuousRecognitionActive) { Logger.warning('连续识别已经在进行中'); return false; } try { // 重置识别器,确保资源被正确释放 await _resetRecognizer(); // 创建事件流控制器 _eventStreamController = StreamController.broadcast(); // 设置事件监听 _eventSubscription = _eventChannel .receiveBroadcastStream() .map((dynamic event) => RecognitionEvent.fromMap(event)) .listen( (event) { _handleRecognitionEvent(event); _eventStreamController?.add(event); }, onError: (error) { Logger.error('Azure 语音识别事件流错误', error); _eventStreamController?.addError(error); _cleanupEventStream(); }, ); // 开始连续识别 final result = await _methodChannel.invokeMethod('startContinuousRecognition'); _isContinuousRecognitionActive = result ?? false; // 设置公开的流 _recognitionStream = _eventStreamController?.stream; return _isContinuousRecognitionActive; } catch (e) { Logger.error('开始连续语音识别失败', e); _cleanupEventStream(); return false; } } /// 停止连续语音识别 Future stopContinuousRecognition() async { _checkInitialized(); if (!_isContinuousRecognitionActive) { Logger.warning('连续识别未在进行中'); return true; // 已经停止,直接返回成功 } try { final result = await _methodChannel.invokeMethod('stopContinuousRecognition'); final success = result ?? false; if (success) { _isContinuousRecognitionActive = false; // 不立即清理事件流,等待 sessionStopped 事件 } return success; } catch (e) { Logger.error('停止连续语音识别失败', e); return false; } } /// 设置识别语言 Future setRecognitionLanguage(String language) async { _checkInitialized(); try { final result = await _methodChannel.invokeMethod( 'setRecognitionLanguage', {'language': language}, ); return result ?? false; } catch (e) { Logger.error('设置识别语言失败', e); return false; } } /// 检查连续识别是否活跃 bool isContinuousRecognitionActive() { return _isContinuousRecognitionActive; } /// 处理来自原生端的识别事件 void _handleRecognitionEvent(RecognitionEvent event) { switch (event.type) { case RecognitionEventType.finalResult: _latestRecognizedText = event.text; break; case RecognitionEventType.sessionStopped: _isContinuousRecognitionActive = false; // 延迟清理事件流,确保所有事件都被处理 Future.delayed(Duration(milliseconds: 500), _cleanupEventStream); break; case RecognitionEventType.canceled: _isContinuousRecognitionActive = false; // 延迟清理事件流,确保所有事件都被处理 Future.delayed(Duration(milliseconds: 500), _cleanupEventStream); break; default: // 其他事件类型不需要特殊处理 break; } } /// 清理事件流资源 void _cleanupEventStream() { _eventSubscription?.cancel(); _eventSubscription = null; // 只有在控制器存在且未关闭时才关闭 if (_eventStreamController != null && !_eventStreamController!.isClosed) { _eventStreamController?.close(); } _eventStreamController = null; _recognitionStream = null; } /// 检查是否已初始化 void _checkInitialized() { if (!_isInitialized) { throw StateError('Azure 语音识别服务未初始化'); } } /// 释放资源 Future dispose() async { try { if (_isContinuousRecognitionActive) { await stopContinuousRecognition(); } await _eventSubscription?.cancel(); _eventSubscription = null; // 只有在控制器存在且未关闭时才关闭 if (_eventStreamController != null && !_eventStreamController!.isClosed) { await _eventStreamController?.close(); } _eventStreamController = null; _recognitionStream = null; await _methodChannel.invokeMethod('dispose'); _isInitialized = false; Logger.info('Azure 语音识别服务资源已释放'); } catch (e) { Logger.error('释放 Azure 语音识别服务资源失败', e); } } @override void onClose() { dispose(); super.onClose(); } }