import 'dart:async'; import 'dart:io'; import 'dart:collection'; import 'package:get/get.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter/services.dart'; /// 火山语音服务异常 class VolcanoTtsException implements Exception { final String message; final dynamic originalError; VolcanoTtsException(this.message, [this.originalError]); @override String toString() => originalError != null ? '$message (原始错误: $originalError)' : message; } /// 火山语音合成服务 (极简版) /// /// 直接使用原生端 VolcanoTtsHelper 的功能,不处理状态回调 class VolcanoTtsService extends GetxService { // 平台通道 static const MethodChannel _channel = MethodChannel('com.example.deep_voice/volcano_tts'); // 配置参数 final String _appId; final String _token; final String _cluster; final String _voiceType; // 初始化状态 bool _isInitialized = false; bool _isDisposed = false; // 服务启用状态 final isEnabled = true.obs; // 默认启用 // 音频质量参数 final double _defaultVolume = 1.0; final double _defaultSpeed = 1.0; VolcanoTtsService() : _appId = dotenv.env['VOLCANO_TTS_APP_ID'] ?? '', _token = dotenv.env['VOLCANO_TTS_APP_TOKEN'] ?? '', _cluster = dotenv.env['VOLCANO_TTS_CLUSTER'] ?? '', _voiceType = dotenv.env['VOLCANO_TTS_VOICE_TYPE'] ?? '' { if (_appId.isEmpty || _token.isEmpty || _cluster.isEmpty) { throw VolcanoTtsException('火山语音配置信息不完整,请检查环境变量 VOLCANO_TTS_APP_ID, VOLCANO_TTS_APP_TOKEN 和 VOLCANO_TTS_CLUSTER'); } } @override Future onInit() async { super.onInit(); try { await _initializeTtsEngine(); } catch (e, stackTrace) { print('初始化TTS服务失败: $e'); print('Stack trace: $stackTrace'); } } /// 初始化TTS引擎 Future _initializeTtsEngine() async { try { print('开始初始化火山语音TTS引擎'); final result = await _channel.invokeMethod('initialize', { 'appId': _appId, 'token': _token, 'cluster': _cluster, }); _isInitialized = result ?? false; print('火山语音TTS引擎初始化${_isInitialized ? '成功' : '失败'}'); if (!_isInitialized) { throw VolcanoTtsException('TTS引擎初始化失败'); } // 设置默认音量和速度 await setVolume(_defaultVolume); await setSpeed(_defaultSpeed); } catch (e) { print('初始化火山语音TTS引擎失败: $e'); _isInitialized = false; throw VolcanoTtsException('初始化失败', e); } } /// 合成并播放文本 /// /// [text] 要合成的文本 /// [voiceType] 可选的语音类型,如果提供,将覆盖默认语音类型 /// /// 返回一个Future,表示是否成功开始播放 Future speak(String text, {String? voiceType}) async { if (text.trim().isEmpty) return false; if (!isEnabled.value) return false; if (!_isInitialized) { print('TTS引擎尚未初始化'); return false; } try { print('开始播放文本: "${text.length > 20 ? text.substring(0, 20) + '...' : text}"'); // 如果提供了语音类型,记录日志 if (voiceType != null && voiceType != _voiceType) { print('使用临时语音类型: $voiceType (默认: $_voiceType)'); } // 直接调用原生方法合成并播放语音 final success = await _channel.invokeMethod('speakText', { 'text': text, 'voiceType': voiceType ?? _voiceType, }); return success ?? false; } catch (e) { print('语音合成失败: $e'); return false; } } /// 停止播放 Future stop() async { if (!_isInitialized) { print('TTS引擎尚未初始化'); return false; } try { print('停止播放'); // 调用原生方法停止播放 final success = await _channel.invokeMethod('stopSpeaking'); print('已停止播放'); return success ?? false; } catch (e) { print('停止播放失败: $e'); return false; } } /// 切换TTS启用状态 void toggleEnabled() { isEnabled.toggle(); if (!isEnabled.value) { stop(); } } /// 设置播放速度 Future setSpeed(double speed) async { if (!_isInitialized) { print('TTS引擎尚未初始化'); return false; } if (speed < 0.5 || speed > 2.0) { throw VolcanoTtsException('播放速度必须在0.5到2.0之间'); } try { // 设置原生播放速度 final success = await _channel.invokeMethod('setSpeed', { 'speed': speed, }); return success ?? false; } catch (e) { print('设置播放速度失败: $e'); return false; } } /// 设置音量 Future setVolume(double volume) async { if (!_isInitialized) { print('TTS引擎尚未初始化'); return false; } if (volume < 0.0 || volume > 1.0) { throw VolcanoTtsException('音量必须在0.0到1.0之间'); } try { // 设置原生音量 final success = await _channel.invokeMethod('setVolume', { 'volume': volume, }); return success ?? false; } catch (e) { print('设置音量失败: $e'); return false; } } /// 清理资源 Future _cleanupResources() async { _isDisposed = true; await stop(); // 释放原生资源 try { await _channel.invokeMethod('dispose'); } catch (e) { print('释放原生TTS资源失败: $e'); } } @override void onClose() async { print('关闭TTS服务'); await _cleanupResources(); super.onClose(); } /// 获取当前语音类型 String getCurrentVoiceType() { return _voiceType; } /// 检查是否正在播放 bool get isPlaying => true; /// 检查是否正在合成(简化版,直接返回true) bool isActuallySynthesizing() { return true; } }