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.

243 lines
6.2 KiB

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<String, dynamic> 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<RealtimeEvent>? _eventStreamController;
Stream<RealtimeEvent>? _eventStream;
/// 获取事件流
Stream<RealtimeEvent> get eventStream {
if (_eventStream == null) {
_eventStreamController = StreamController<RealtimeEvent>.broadcast();
_eventStream = _eventStreamController!.stream;
// 监听原生事件
_eventChannel.receiveBroadcastStream().listen(
(dynamic event) {
if (event is Map<dynamic, dynamic>) {
final eventMap = Map<String, dynamic>.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<bool> initialize({
required String serverUrl,
int sampleRate = 16000,
int channels = 1,
int bitsPerSample = 16,
}) async {
try {
final result = await _channel.invokeMethod<bool>(
'initialize',
{
'serverUrl': serverUrl,
'sampleRate': sampleRate,
'channels': channels,
'bitsPerSample': bitsPerSample,
},
);
return result ?? false;
} catch (e) {
throw RealtimeException('初始化失败: $e');
}
}
/// 连接到服务器
Future<bool> connect() async {
try {
final result = await _channel.invokeMethod<bool>('connect');
return result ?? false;
} catch (e) {
throw RealtimeException('连接失败: $e');
}
}
/// 断开连接
Future<bool> disconnect() async {
try {
final result = await _channel.invokeMethod<bool>('disconnect');
return result ?? false;
} catch (e) {
throw RealtimeException('断开连接失败: $e');
}
}
/// 开始录音
Future<bool> startRecording() async {
try {
final result = await _channel.invokeMethod<bool>('startRecording');
return result ?? false;
} catch (e) {
throw RealtimeException('开始录音失败: $e');
}
}
/// 停止录音
Future<bool> stopRecording() async {
try {
final result = await _channel.invokeMethod<bool>('stopRecording');
return result ?? false;
} catch (e) {
throw RealtimeException('停止录音失败: $e');
}
}
/// 停止播放
Future<bool> stopPlaying() async {
try {
final result = await _channel.invokeMethod<bool>('stopPlaying');
return result ?? false;
} catch (e) {
throw RealtimeException('停止播放失败: $e');
}
}
/// 获取连接状态
Future<ConnectionStatus> getConnectionStatus() async {
try {
final result = await _channel.invokeMethod<String>('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<VoiceStatus> getVoiceStatus() async {
try {
final result = await _channel.invokeMethod<String>('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<bool> sendTextMessage(String message) async {
try {
final result = await _channel.invokeMethod<bool>(
'sendTextMessage',
{'message': message},
);
return result ?? false;
} catch (e) {
throw RealtimeException('发送文本消息失败: $e');
}
}
/// 设置音频参数
Future<bool> setAudioConfig({
int? sampleRate,
int? channels,
int? bitsPerSample,
}) async {
try {
final params = <String, dynamic>{};
if (sampleRate != null) params['sampleRate'] = sampleRate;
if (channels != null) params['channels'] = channels;
if (bitsPerSample != null) params['bitsPerSample'] = bitsPerSample;
final result = await _channel.invokeMethod<bool>('setAudioConfig', params);
return result ?? false;
} catch (e) {
throw RealtimeException('设置音频参数失败: $e');
}
}
/// 释放资源
Future<void> dispose() async {
try {
await _channel.invokeMethod<void>('dispose');
_eventStreamController?.close();
_eventStreamController = null;
_eventStream = null;
} catch (e) {
throw RealtimeException('释放资源失败: $e');
}
}
}