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.

427 lines
13 KiB

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../data/services/asr_service.dart';
import '../../../data/services/tts_service.dart';
import '../../../data/services/speech_factory.dart';
import '../../../core/utils/logger.dart';
/// 语音测试控制器
class SpeechTestController extends GetxController {
// 语音服务工厂
final SpeechFactory _speechFactory = Get.find<SpeechFactory>();
// 当前使用的TTS服务
late TtsService _ttsService;
// 当前使用的ASR服务
late AsrService _asrService;
// 状态变量
final RxBool isInitialized = false.obs;
final RxBool isProcessing = false.obs;
final RxBool isListening = false.obs;
final RxBool isSpeaking = false.obs;
// 识别结果
final RxString intermediateResult = ''.obs; // 中间结果
final RxString finalResult = ''.obs; // 最终结果
final RxString recognitionStatus = '准备就绪'.obs;
final RxString detectedLanguage = ''.obs; // 检测到的语言
// TTS事件
final RxString ttsStatus = '准备就绪'.obs;
// 当前选择的语音服务类型
final Rx<SpeechServiceType> selectedServiceType = SpeechServiceType.azure.obs;
// 音频输入源
bool _audioSourceType = false;
// 连续识别结果流
StreamSubscription<RecognitionEvent>? _recognitionSubscription;
// TTS事件流
StreamSubscription<TtsEvent>? _ttsEventSubscription;
// 文本控制器
final TextEditingController textController = TextEditingController();
// 连续播放的测试句子
final List<String> testSentences = [
'这是第一句测试语音。',
'这是第二句测试语音,语音合成支持连续播放。',
'这是第三句测试语音,将在连续模式下播放完毕。'
];
@override
void onInit() {
super.onInit();
// 设置默认待播放文本
textController.text = '欢迎使用语音测试,这是一段默认的测试文本。您可以修改此文本,然后点击播放按钮测试语音合成效果。';
_initServices();
}
/// 初始化服务
Future<void> _initServices() async {
try {
isProcessing.value = true;
// 获取服务实例
_ttsService = _speechFactory.getTtsService();
_asrService = _speechFactory.getAsrService();
// 初始化服务
await _ttsService.initialize();
await _asrService.initialize();
// 监听TTS事件
_setupTtsEventListener();
// 获取识别事件流 - 这启动了异步识别过程
final stream = await _asrService.recognizeCallback();
// 设置事件监听 - 异步处理识别结果
_setupAsrEventListener(stream);
isInitialized.value = true;
ttsStatus.value = '准备就绪';
recognitionStatus.value = '准备就绪';
} catch (e) {
ttsStatus.value = '初始化失败';
recognitionStatus.value = '初始化失败';
Logger.error('语音测试初始化失败: ${e.toString()}');
} finally {
isProcessing.value = false;
}
}
/// 设置TTS事件监听
void _setupTtsEventListener() {
// 取消旧的订阅
_ttsEventSubscription?.cancel();
// 设置新的订阅
_ttsEventSubscription = _ttsService.onEvent.listen((event) {
switch (event.type) {
case TtsEventType.started:
isSpeaking.value = true;
ttsStatus.value = '正在播放...';
break;
case TtsEventType.completed:
isSpeaking.value = false;
ttsStatus.value = '播放完成';
break;
case TtsEventType.canceled:
isSpeaking.value = false;
ttsStatus.value = '播放已取消';
break;
case TtsEventType.error:
isSpeaking.value = false;
ttsStatus.value = '播放错误: ${event.error}';
break;
}
});
}
/// 设置ASR事件监听
void _setupAsrEventListener(Stream<RecognitionEvent> stream) {
// 取消旧的订阅
_recognitionSubscription?.cancel();
// 重置识别结果
intermediateResult.value = '';
finalResult.value = '';
detectedLanguage.value = '';
recognitionStatus.value = '正在等待语音输入...';
// 设置新的订阅
_recognitionSubscription = stream.listen((event) {
switch (event.type) {
case RecognitionEventType.sessionStarted:
isListening.value = true;
recognitionStatus.value = '开始聆听...';
break;
case RecognitionEventType.sessionStopped:
isListening.value = false;
recognitionStatus.value = '聆听已结束';
// 清空中间结果,保留最终结果
intermediateResult.value = '';
break;
case RecognitionEventType.intermediateResult:
// 更新中间结果,显示为斜体或不同颜色
intermediateResult.value = event.text;
if (event.detectedLanguage.isNotEmpty) {
detectedLanguage.value = event.detectedLanguage;
}
recognitionStatus.value = '正在识别...';
break;
case RecognitionEventType.finalResult:
// 更新最终结果,显示为正常文本
finalResult.value = event.text;
intermediateResult.value = ''; // 清空中间结果
if (event.detectedLanguage.isNotEmpty) {
detectedLanguage.value = event.detectedLanguage;
}
recognitionStatus.value = '识别完成';
break;
case RecognitionEventType.finalResult1:
// 更新最终结果,显示为正常文本
finalResult.value = event.text;
intermediateResult.value = ''; // 清空中间结果
if (event.detectedLanguage.isNotEmpty) {
detectedLanguage.value = event.detectedLanguage;
}
recognitionStatus.value = '识别完成';
break;
case RecognitionEventType.error:
isListening.value = false;
recognitionStatus.value = '识别错误: ${event.error}';
break;
case RecognitionEventType.canceled:
isListening.value = false;
recognitionStatus.value = '识别已取消';
// 清空中间结果
intermediateResult.value = '';
break;
case RecognitionEventType.onAudio:
// TODO: Handle this case.
break;
}
}, onError: (error) {
isListening.value = false;
recognitionStatus.value = '识别错误: $error';
intermediateResult.value = '';
});
}
/// 切换语音服务类型
void switchServiceType(SpeechServiceType type) async {
if (selectedServiceType.value == type) return;
try {
isProcessing.value = true;
// 停止当前的所有服务状态
await stopAll();
// 切换服务类型
_speechFactory.setServiceType(type);
selectedServiceType.value = type;
// 重新初始化服务
await _initServices();
} catch (e) {
Logger.error('切换语音服务类型失败: ${e.toString()}');
} finally {
isProcessing.value = false;
}
}
/// 停止所有活动
Future<void> stopAll() async {
// 停止ASR
if (isListening.value) {
await stopContinuousRecognition();
}
// 停止TTS
if (isSpeaking.value) {
await stopSpeaking();
}
// 取消所有订阅
await _recognitionSubscription?.cancel();
_recognitionSubscription = null;
}
/// 单次播放文本
Future<void> speakOnce() async {
if (!isInitialized.value || isProcessing.value) return;
final text = textController.text.trim();
if (text.isEmpty) {
ttsStatus.value = '请输入要播放的文本';
return;
}
try {
isProcessing.value = true;
ttsStatus.value = '准备播放...';
final result = await _ttsService.speakOnce(text);
if (!result) {
ttsStatus.value = '播放失败';
}
} catch (e) {
ttsStatus.value = '播放异常: $e';
Logger.error('单次播放异常: ${e.toString()}');
} finally {
isProcessing.value = false;
}
}
/// 连续播放测试
Future<void> speakContinuously() async {
if (!isInitialized.value || isProcessing.value) return;
try {
isProcessing.value = true;
ttsStatus.value = '准备连续播放...';
// 为避免阻塞,使用一个句子接一个句子的方式添加到队列
for (final sentence in testSentences) {
if (!await _ttsService.speakStream(sentence)) {
ttsStatus.value = '添加句子到队列失败';
break;
}
// 给前一个句子一点处理时间
await Future.delayed(const Duration(milliseconds: 50));
}
// 刷新队列,确保播放完成
await _ttsService.flushStream();
} catch (e) {
ttsStatus.value = '连续播放异常: $e';
Logger.error('连续播放异常: ${e.toString()}');
} finally {
isProcessing.value = false;
}
}
/// 停止播放
Future<void> stopSpeaking() async {
if (!isInitialized.value) return;
try {
await _ttsService.stop();
} catch (e) {
ttsStatus.value = '停止播放异常: $e';
Logger.error('停止播放异常: ${e.toString()}');
}
}
/// 一次性识别
Future<void> recognizeOnce() async {
if (!isInitialized.value || isProcessing.value || isListening.value) return;
try {
isProcessing.value = true;
recognitionStatus.value = '开始识别...';
// 清空之前的结果
intermediateResult.value = '';
finalResult.value = '';
detectedLanguage.value = '';
// 显示正在进行的状态
recognitionStatus.value = '正在聆听...';
// 执行一次性识别 - 这是同步等待结果的操作
final result = await _asrService.recognizeOnce();
if (result.isError) {
recognitionStatus.value = '识别错误: ${result.error}';
Logger.error('一次性识别错误: ${result.error}');
} else {
// 更新最终结果
finalResult.value = result.text;
// 更新语言信息
if (result.detectedLanguage.isNotEmpty) {
detectedLanguage.value = result.detectedLanguage;
Logger.debug('检测到语言: ${result.detectedLanguage}');
}
recognitionStatus.value = '识别完成';
}
} catch (e) {
recognitionStatus.value = '识别异常: $e';
Logger.error('一次性识别异常: ${e.toString()}');
} finally {
isProcessing.value = false;
}
}
/// 开始连续识别
Future<void> startContinuousRecognition() async {
if (!isInitialized.value || isProcessing.value || isListening.value) return;
try {
isProcessing.value = true;
// 清空之前的结果
intermediateResult.value = '';
finalResult.value = '';
detectedLanguage.value = '';
recognitionStatus.value = '准备连续识别...';
// 获取识别事件流 - 这启动了异步识别过程
final stream =
await _asrService.startContinuousRecognition(_audioSourceType);
} catch (e) {
recognitionStatus.value = '启动连续识别异常: $e';
Logger.error('启动连续识别异常: ${e.toString()}');
isListening.value = false;
intermediateResult.value = '';
finalResult.value = '';
} finally {
isProcessing.value = false;
}
}
/// 停止连续识别
Future<void> stopContinuousRecognition() async {
if (!isInitialized.value || !isListening.value) return;
try {
// 首先更新状态,防止重复调用
isListening.value = false;
recognitionStatus.value = '正在停止识别...';
// 停止识别过程
await _asrService.stopContinuousRecognition();
// 更新UI状态
recognitionStatus.value = '连续识别已停止';
intermediateResult.value = '';
} catch (e) {
recognitionStatus.value = '停止连续识别异常: $e';
Logger.error('停止连续识别异常: ${e.toString()}');
}
}
// 获取识别结果(用于UI显示)
String getDisplayResult() {
// 如果有最终结果,优先显示
String displayText = '';
if (finalResult.value.isNotEmpty) {
displayText = finalResult.value;
}
// 如果有中间结果,添加到最终结果后(可在UI中使用不同样式显示)
if (intermediateResult.value.isNotEmpty) {
if (displayText.isNotEmpty) {
displayText = '$displayText\n\n正在识别: ${intermediateResult.value}';
} else {
displayText = '正在识别: ${intermediateResult.value}';
}
}
return displayText;
}
@override
void onClose() {
// 取消所有订阅
_recognitionSubscription?.cancel();
_ttsEventSubscription?.cancel();
// 释放控制器
textController.dispose();
super.onClose();
}
}