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.

364 lines
9.4 KiB

import 'dart:io';
import 'package:flutter_tts/flutter_tts.dart';
import 'package:get/get.dart';
import '../../core/utils/logger.dart';
/// Flutter TTS服务,负责本地文本转语音功能
class FlutterTtsService extends GetxService {
late FlutterTts _flutterTts;
// 当前TTS状态
TtsState _ttsState = TtsState.stopped;
TtsState get ttsState => _ttsState;
// 可用的语音
List<Map<String, String>> _voices = [];
List<Map<String, String>> get voices => _voices;
// 当前选择的语音
String _currentVoice = '';
String get currentVoice => _currentVoice;
set currentVoice(String voice) => _currentVoice = voice;
// 语速 (0.1-2.0)
double _rate = 0.5;
double get rate => _rate;
set rate(double value) => _rate = value;
// 音量 (0.0-1.0)
double _volume = 1.0;
double get volume => _volume;
set volume(double value) => _volume = value;
// 音调 (0.5-2.0)
double _pitch = 1.0;
double get pitch => _pitch;
set pitch(double value) => _pitch = value;
// 文本队列 - 仅包含待播放的文本
List<String> _textQueue = [];
List<String> get textQueue => _textQueue;
// 当前正在播放的文本
String _currentText = '';
String get currentText => _currentText;
// 是否正在处理队列
bool _isProcessingQueue = false;
@override
void onInit() {
super.onInit();
_initTts();
}
/// 初始化TTS引擎
Future<void> _initTts() async {
_flutterTts = FlutterTts();
// 设置完成回调
_flutterTts.setCompletionHandler(() {
Logger.info('TTS播放完成: "$_currentText"');
// 清空当前播放文本
_currentText = '';
// 处理队列中的下一条文本
_processNextInQueue();
// 只有当队列为空且不再处理队列时才设置为stopped状态
if (_textQueue.isEmpty && !_isProcessingQueue) {
_ttsState = TtsState.stopped;
Logger.info('TTS队列播放完成,设置为stopped状态');
}
});
// 设置错误回调
_flutterTts.setErrorHandler((error) {
Logger.error('Flutter TTS错误: $error');
// 清空当前播放文本
_currentText = '';
// 尝试播放下一条文本
_processNextInQueue();
// 只有当队列为空且不再处理队列时才设置为stopped状态
if (_textQueue.isEmpty && !_isProcessingQueue) {
_ttsState = TtsState.stopped;
Logger.info('TTS队列播放出错且为空,设置为stopped状态');
}
});
// 设置开始回调
_flutterTts.setStartHandler(() {
_ttsState = TtsState.playing;
});
// 设置取消回调
_flutterTts.setCancelHandler(() {
// 清空当前播放文本
_currentText = '';
_isProcessingQueue = false;
_ttsState = TtsState.stopped;
Logger.info('TTS播放被取消,设置为stopped状态');
});
// 设置暂停回调
_flutterTts.setPauseHandler(() {
_ttsState = TtsState.paused;
});
// 设置继续回调
_flutterTts.setContinueHandler(() {
_ttsState = TtsState.playing;
});
// 加载可用语音
await _loadVoices();
Logger.info('Flutter TTS服务已初始化');
}
/// 加载可用的语音
Future<void> _loadVoices() async {
try {
if (Platform.isAndroid || Platform.isIOS) {
final voices = await _flutterTts.getVoices;
if (voices != null) {
_voices = [];
for (var voice in voices) {
if (voice is Map) {
final Map<String, String> voiceMap = {};
voice.forEach((key, value) {
if (key is String && value is String) {
voiceMap[key] = value;
} else if (key is String) {
voiceMap[key] = value.toString();
}
});
if (voiceMap.containsKey('name')) {
_voices.add(voiceMap);
}
}
}
// 如果有可用语音,设置第一个为默认
if (_voices.isNotEmpty) {
_currentVoice = _voices[0]['name'] ?? '';
await _flutterTts.setVoice({"name": _currentVoice});
}
}
}
} catch (e) {
Logger.error('加载TTS语音失败', e);
}
}
/// 设置语音
Future<void> setVoice(String voiceName) async {
try {
_currentVoice = voiceName;
await _flutterTts.setVoice({"name": voiceName});
} catch (e) {
Logger.error('设置TTS语音失败', e);
}
}
/// 设置语速
Future<void> setRate(double rate) async {
try {
_rate = rate;
await _flutterTts.setSpeechRate(rate);
} catch (e) {
Logger.error('设置TTS语速失败', e);
}
}
/// 设置音量
Future<void> setVolume(double volume) async {
try {
_volume = volume;
await _flutterTts.setVolume(volume);
} catch (e) {
Logger.error('设置TTS音量失败', e);
}
}
/// 设置音调
Future<void> setPitch(double pitch) async {
try {
_pitch = pitch;
await _flutterTts.setPitch(pitch);
} catch (e) {
Logger.error('设置TTS音调失败', e);
}
}
/// 设置语言
Future<void> setLanguage(String language) async {
try {
await _flutterTts.setLanguage(language);
} catch (e) {
Logger.error('设置TTS语言失败', e);
}
}
/// 添加文本到队列并开始处理队列(如果尚未开始)
Future<void> speak(String text) async {
if (text.isEmpty) return;
// 添加到队列
_addToQueue(text);
// 开始处理队列(如果尚未开始)
_startQueueProcessingIfNeeded();
}
/// 添加多条文本到队列并开始处理队列(如果尚未开始)
Future<void> speakTexts(List<String> texts) async {
if (texts.isEmpty) return;
// 添加所有非空文本到队列
int addedCount = 0;
for (final text in texts) {
if (text.isNotEmpty) {
_textQueue.add(text);
addedCount++;
}
}
if (addedCount > 0) {
Logger.info('已添加$addedCount条文本到TTS队列');
// 开始处理队列(如果尚未开始)
_startQueueProcessingIfNeeded();
}
}
/// 添加文本到队列
void _addToQueue(String text) {
if (text.isEmpty) return;
_textQueue.add(text);
Logger.info('已添加文本到TTS队列: "${text.length > 20 ? "${text.substring(0, 20)}..." : text}"');
}
/// 开始处理队列(如果尚未开始)
void _startQueueProcessingIfNeeded() {
// 如果队列为空,不需要处理
if (_textQueue.isEmpty) return;
// 如果已经在处理队列或正在播放,不需要重新开始
if (_isProcessingQueue || _ttsState == TtsState.playing) return;
// 开始处理队列
_isProcessingQueue = true;
_processNextInQueue();
}
/// 处理队列中的下一条文本
void _processNextInQueue() {
// 如果队列为空,结束处理但不立即设置stopped状态
if (_textQueue.isEmpty) {
_currentText = '';
_isProcessingQueue = false;
// 只有当当前没有文本在播放时才设置为stopped状态
if (_currentText.isEmpty) {
_ttsState = TtsState.stopped;
Logger.info('TTS队列为空,设置为stopped状态');
}
return;
}
// 获取队列中的第一条文本并播放
_speakNextText();
}
/// 播放队列中的下一条文本
Future<void> _speakNextText() async {
if (_textQueue.isEmpty) {
_isProcessingQueue = false;
// 只有当当前没有文本在播放时才设置为stopped状态
if (_currentText.isEmpty) {
_ttsState = TtsState.stopped;
Logger.info('TTS队列播放完成,设置为stopped状态');
}
return;
}
// 获取队列中的第一条文本
final text = _textQueue.removeAt(0);
_currentText = text;
try {
// 设置TTS参数
await _flutterTts.setSpeechRate(_rate);
await _flutterTts.setVolume(_volume);
await _flutterTts.setPitch(_pitch);
if (_currentVoice.isNotEmpty) {
await _flutterTts.setVoice({"name": _currentVoice});
}
// 播放文本
await _flutterTts.speak(text);
Logger.info('正在播放文本,队列中还有${_textQueue.length}条待播放');
} catch (e) {
Logger.error('TTS播放文本失败', e);
// 清空当前文本
_currentText = '';
// 尝试播放下一个
_processNextInQueue();
}
}
/// 停止播放并清空队列
Future<void> stop() async {
try {
await _flutterTts.stop();
// 重置队列处理状态
_textQueue.clear();
_currentText = '';
_isProcessingQueue = false;
_ttsState = TtsState.stopped;
Logger.info('已停止TTS播放并清空队列');
} catch (e) {
Logger.error('停止TTS播放失败', e);
}
}
/// 暂停播放
Future<void> pause() async {
try {
await _flutterTts.pause();
_ttsState = TtsState.paused;
} catch (e) {
Logger.error('暂停TTS播放失败', e);
}
}
/// 清空队列并停止播放
Future<void> clearQueue() async {
_textQueue.clear();
await stop();
Logger.info('已清空TTS队列');
}
@override
void onClose() {
_flutterTts.stop();
super.onClose();
}
}
/// TTS状态枚举
enum TtsState {
playing,
stopped,
paused,
}