import 'dart:async'; import 'dart:typed_data'; import 'package:flutter/services.dart'; /// 实时语音服务异常 class RealtimeException implements Exception { final String message; RealtimeException(this.message); @override String toString() => 'RealtimeException: $message'; } /// 连接状态 enum ConnectionStatus { disconnected, connecting, connected, error, } /// 语音状态 enum VoiceStatus { idle, recording, processing, playing, } /// 实时语音事件 class RealtimeEvent { final String type; final dynamic data; RealtimeEvent({required this.type, this.data}); factory RealtimeEvent.fromMap(Map map) { return RealtimeEvent( type: map['type'] as String, data: map['data'], ); } } /// 实时语音聊天服务 class RealtimeService { static const MethodChannel _channel = MethodChannel('realtime/methods'); static const EventChannel _eventChannel = EventChannel('realtime/events'); StreamController? _eventStreamController; Stream? _eventStream; /// 获取事件流 Stream get eventStream { if (_eventStream == null) { _eventStreamController = StreamController.broadcast(); _eventStream = _eventStreamController!.stream; // 监听原生事件 _eventChannel.receiveBroadcastStream().listen( (dynamic event) { if (event is Map) { final eventMap = Map.from(event); final realtimeEvent = RealtimeEvent.fromMap(eventMap); _eventStreamController!.add(realtimeEvent); } }, onError: (error) { _eventStreamController!.addError(RealtimeException('事件流错误: $error')); }, ); } return _eventStream!; } /// 初始化实时语音服务 /// /// [serverUrl] WebSocket服务器地址 /// [sampleRate] 采样率,默认16000 /// [channels] 声道数,默认1(单声道) /// [bitsPerSample] 位深,默认16 Future initialize({ required String serverUrl, int sampleRate = 16000, int channels = 1, int bitsPerSample = 16, }) async { try { final result = await _channel.invokeMethod( 'initialize', { 'serverUrl': serverUrl, 'sampleRate': sampleRate, 'channels': channels, 'bitsPerSample': bitsPerSample, }, ); return result ?? false; } catch (e) { throw RealtimeException('初始化失败: $e'); } } /// 连接到服务器 Future connect() async { try { final result = await _channel.invokeMethod('connect'); return result ?? false; } catch (e) { throw RealtimeException('连接失败: $e'); } } /// 断开连接 Future disconnect() async { try { final result = await _channel.invokeMethod('disconnect'); return result ?? false; } catch (e) { throw RealtimeException('断开连接失败: $e'); } } /// 开始录音 Future startRecording() async { try { final result = await _channel.invokeMethod('startRecording'); return result ?? false; } catch (e) { throw RealtimeException('开始录音失败: $e'); } } /// 停止录音 Future stopRecording() async { try { final result = await _channel.invokeMethod('stopRecording'); return result ?? false; } catch (e) { throw RealtimeException('停止录音失败: $e'); } } /// 停止播放 Future stopPlaying() async { try { final result = await _channel.invokeMethod('stopPlaying'); return result ?? false; } catch (e) { throw RealtimeException('停止播放失败: $e'); } } /// 获取连接状态 Future getConnectionStatus() async { try { final result = await _channel.invokeMethod('getConnectionStatus'); switch (result) { case 'disconnected': return ConnectionStatus.disconnected; case 'connecting': return ConnectionStatus.connecting; case 'connected': return ConnectionStatus.connected; case 'error': return ConnectionStatus.error; default: return ConnectionStatus.disconnected; } } catch (e) { throw RealtimeException('获取连接状态失败: $e'); } } /// 获取语音状态 Future getVoiceStatus() async { try { final result = await _channel.invokeMethod('getVoiceStatus'); switch (result) { case 'idle': return VoiceStatus.idle; case 'recording': return VoiceStatus.recording; case 'processing': return VoiceStatus.processing; case 'playing': return VoiceStatus.playing; default: return VoiceStatus.idle; } } catch (e) { throw RealtimeException('获取语音状态失败: $e'); } } /// 发送文本消息 Future sendTextMessage(String message) async { try { final result = await _channel.invokeMethod( 'sendTextMessage', {'message': message}, ); return result ?? false; } catch (e) { throw RealtimeException('发送文本消息失败: $e'); } } /// 设置音频参数 Future setAudioConfig({ int? sampleRate, int? channels, int? bitsPerSample, }) async { try { final params = {}; if (sampleRate != null) params['sampleRate'] = sampleRate; if (channels != null) params['channels'] = channels; if (bitsPerSample != null) params['bitsPerSample'] = bitsPerSample; final result = await _channel.invokeMethod('setAudioConfig', params); return result ?? false; } catch (e) { throw RealtimeException('设置音频参数失败: $e'); } } /// 释放资源 Future dispose() async { try { await _channel.invokeMethod('dispose'); _eventStreamController?.close(); _eventStreamController = null; _eventStream = null; } catch (e) { throw RealtimeException('释放资源失败: $e'); } } }