import 'dart:async'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:realtime/realtime.dart'; import '../../../core/utils/logger.dart'; class RealtimeController extends GetxController with GetTickerProviderStateMixin { // Realtime服务实例 final RealtimeService _realtimeService = RealtimeService(); // 连接状态 final RxBool isConnected = false.obs; final RxBool isConnecting = false.obs; // 语音状态 final RxBool isListening = false.obs; final RxBool isSpeaking = false.obs; // 状态和字幕显示 final RxString currentStatus = '正在初始化...'.obs; final RxString userSpeechText = ''.obs; final RxString aiResponseText = ''.obs; // 音频可视化数据 final RxList audioLevels = [].obs; final RxDouble userVoiceLevel = 0.0.obs; final RxDouble aiVoiceLevel = 0.0.obs; // 动画控制器 late AnimationController pulseAnimationController; late Animation pulseAnimation; // 状态监听 StreamSubscription? _eventSubscription; Timer? _audioUpdateTimer; @override void onInit() { super.onInit(); _initializeAnimations(); _initializeAudioLevels(); _setupEventListener(); Logger.info('Realtime模块初始化完成'); // 自动开始连接 WidgetsBinding.instance.addPostFrameCallback((_) { _autoConnect(); }); } @override void onClose() { _cleanup(); super.onClose(); } /// 初始化动画 void _initializeAnimations() { pulseAnimationController = AnimationController( duration: const Duration(milliseconds: 1000), vsync: this, ); pulseAnimation = Tween( begin: 0.8, end: 1.2, ).animate(CurvedAnimation( parent: pulseAnimationController, curve: Curves.easeInOut, )); } /// 初始化音频级别数据 void _initializeAudioLevels() { audioLevels.value = List.generate(20, (index) => 0.0); } /// 设置事件监听器 void _setupEventListener() { _eventSubscription = _realtimeService.eventStream.listen( (event) { _handleRealtimeEvent(event); }, onError: (error) { Logger.error('Realtime事件流错误: $error'); }, ); } /// 处理Realtime事件 void _handleRealtimeEvent(RealtimeEvent event) { switch (event.type) { case 'connectionStatusChanged': _handleConnectionStatusChanged(event.data); break; case 'voiceStatusChanged': _handleVoiceStatusChanged(event.data); break; case 'textReceived': _handleTextReceived(event.data); break; case 'error': _handleError(event.data); break; } } /// 自动连接 Future _autoConnect() async { currentStatus.value = '正在连接AI服务器...'; await connect(); } /// 处理连接状态变化 void _handleConnectionStatusChanged(String status) { switch (status) { case 'connected': isConnected.value = true; isConnecting.value = false; currentStatus.value = '已连接,正在开始录音...'; _startAudioUpdates(); Logger.info('已连接到Vocode服务器'); // 连接成功后自动开始录音 Timer(const Duration(milliseconds: 500), () { startListening(); }); break; case 'connecting': isConnecting.value = true; currentStatus.value = '正在连接AI服务器...'; Logger.info('正在连接Vocode服务器...'); break; case 'disconnected': isConnected.value = false; isConnecting.value = false; currentStatus.value = '已断开连接'; _resetState(); Logger.info('已断开Vocode服务器连接'); break; case 'error': isConnected.value = false; isConnecting.value = false; currentStatus.value = '连接失败,请检查网络'; _resetState(); Logger.error('Vocode服务器连接错误'); break; } } /// 处理语音状态变化 void _handleVoiceStatusChanged(String status) { switch (status) { case 'recording': isListening.value = true; isSpeaking.value = false; currentStatus.value = '正在聆听,请说话...'; pulseAnimationController.repeat(reverse: true); Logger.info('开始录音'); break; case 'processing': // 用户说话结束,等待AI回应 isListening.value = false; currentStatus.value = 'AI正在思考中...'; break; case 'playing': isListening.value = false; isSpeaking.value = true; currentStatus.value = 'AI正在回复...'; pulseAnimationController.repeat(reverse: true); Logger.info('AI开始说话'); break; case 'idle': isListening.value = false; isSpeaking.value = false; currentStatus.value = isConnected.value ? '等待用户说话...' : '已断开连接'; pulseAnimationController.stop(); Logger.info('语音状态空闲'); break; } } /// 处理收到的文本消息 void _handleTextReceived(String text) { Logger.info('收到文本消息: $text'); // 根据消息来源更新相应的文本 if (text.startsWith('[USER]')) { userSpeechText.value = text.replaceFirst('[USER]', '').trim(); } else if (text.startsWith('[AI]')) { aiResponseText.value = text.replaceFirst('[AI]', '').trim(); } else { // 默认认为是AI回复 aiResponseText.value = text; } } /// 处理错误 void _handleError(String error) { Logger.error('Realtime错误: $error'); // 可以显示错误提示 } /// 切换连接状态 Future toggleConnection() async { if (isConnected.value) { await disconnect(); } else { await connect(); } } /// 连接到AI服务 Future connect() async { if (isConnecting.value || isConnected.value) return; try { HapticFeedback.lightImpact(); // 初始化Realtime服务 final initialized = await _realtimeService.initialize( serverUrl: 'ws://192.168.1.11:8000/ws', // 本地开发服务器使用ws协议 sampleRate: 16000, channels: 1, bitsPerSample: 16, ); if (!initialized) { throw Exception('初始化Realtime服务失败'); } // 连接服务器 final connected = await _realtimeService.connect(); if (!connected) { throw Exception('连接Vocode服务器失败'); } } catch (e) { Logger.error('连接失败: $e'); isConnecting.value = false; _resetState(); } } /// 断开连接 Future disconnect() async { try { HapticFeedback.mediumImpact(); // 停止录音和播放 if (isListening.value) { await _realtimeService.stopRecording(); } await _realtimeService.stopPlaying(); // 断开连接 await _realtimeService.disconnect(); // 停止本地更新 _stopAudioUpdates(); pulseAnimationController.stop(); } catch (e) { Logger.error('断开连接失败: $e'); } } /// 开始/停止聆听 void toggleListening() { if (!isConnected.value) return; if (isListening.value) { stopListening(); } else { startListening(); } } /// 开始聆听 void startListening() { if (!isConnected.value || isListening.value) return; HapticFeedback.lightImpact(); _realtimeService.startRecording().then((success) { if (!success) { Logger.error('开始录音失败'); } }); } /// 停止聆听 void stopListening() { if (!isListening.value) return; _realtimeService.stopRecording().then((success) { if (!success) { Logger.error('停止录音失败'); } }); } /// 开始音频数据更新 void _startAudioUpdates() { _audioUpdateTimer = Timer.periodic(const Duration(milliseconds: 100), (timer) { if (!isConnected.value) { timer.cancel(); return; } _updateAudioLevels(); }); } /// 停止音频数据更新 void _stopAudioUpdates() { _audioUpdateTimer?.cancel(); _audioUpdateTimer = null; } /// 更新音频级别 void _updateAudioLevels() { final random = Random(); // 更新用户语音级别 if (isListening.value) { userVoiceLevel.value = 0.3 + random.nextDouble() * 0.7; } else { userVoiceLevel.value = userVoiceLevel.value * 0.8; // 衰减 } // 更新AI语音级别 if (isSpeaking.value) { aiVoiceLevel.value = 0.2 + random.nextDouble() * 0.8; } else { aiVoiceLevel.value = aiVoiceLevel.value * 0.9; // 衰减 } // 更新音频级别数组 final newLevels = List.generate(20, (index) { if (isListening.value || isSpeaking.value) { return random.nextDouble() * (isListening.value ? userVoiceLevel.value : aiVoiceLevel.value); } return audioLevels[index] * 0.95; // 衰减 }); audioLevels.value = newLevels; } /// 重置音频级别 void _resetAudioLevels() { userVoiceLevel.value = 0.0; aiVoiceLevel.value = 0.0; audioLevels.value = List.generate(20, (index) => 0.0); } /// 关闭并返回上一页 Future closeAndGoBack() async { // 立即返回上一页,避免阻塞UI Get.back(); // 之后异步进行清理,不阻塞页面切换 unawaited(_performShutdown()); } /// 实际执行关闭逻辑(后台) Future _performShutdown() async { try { currentStatus.value = '正在关闭连接...'; if (isListening.value) { await _realtimeService.stopRecording(); } await _realtimeService.stopPlaying(); await _realtimeService.disconnect(); _resetState(); Logger.info('实时语音连接已关闭'); } catch (e) { Logger.error('关闭连接失败: $e'); } } /// 重置状态 void _resetState() { isListening.value = false; isSpeaking.value = false; userSpeechText.value = ''; aiResponseText.value = ''; _resetAudioLevels(); pulseAnimationController.stop(); _stopAudioUpdates(); } /// 清理资源 void _cleanup() async { _eventSubscription?.cancel(); _stopAudioUpdates(); pulseAnimationController.dispose(); try { await _realtimeService.dispose(); } catch (e) { Logger.error('清理Realtime服务失败: $e'); } } }