Files
VibeCoding/webrtc_controller_flutter/lib/signaling/signaling_client.dart

89 lines
2.3 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:convert';
import 'package:web_socket_channel/web_socket_channel.dart';
import '../models/signal_message.dart';
/// 信令客户端,封装 WebSocket 连接与消息收发。
///
/// 连接成功后自动向服务器发送 REGISTER 注册为 CONTROLLER 设备,
/// 与 Android 端 WebSocketClient 行为一致。
class SignalingClient {
final String serverUrl;
final String deviceId;
WebSocketChannel? _channel;
/// 收到信令消息回调(已解析为 SignalMessage
void Function(SignalMessage message)? onMessage;
/// 连接成功回调。
void Function()? onConnected;
/// 连接断开回调。
void Function()? onDisconnected;
/// 连接错误回调。
void Function(String error)? onError;
SignalingClient({required this.serverUrl, required this.deviceId});
/// 建立 WebSocket 连接并注册设备。
void connect() {
try {
final uri = Uri.parse(serverUrl);
_channel = WebSocketChannel.connect(uri);
_channel!.stream.listen(
_onData,
onDone: () => onDisconnected?.call(),
onError: (Object e) => onError?.call(e.toString()),
cancelOnError: false,
);
// 连接建立后注册设备(与 Android 端 onOpen -> registerDevice 对应)。
_register();
} catch (e) {
onError?.call(e.toString());
}
}
void _onData(dynamic data) {
if (data is! String) return;
try {
final map = jsonDecode(data) as Map<String, dynamic>;
final message = SignalMessage.fromJson(map);
onMessage?.call(message);
} catch (_) {
// 忽略无法解析的消息。
}
}
void _register() {
final msg = SignalMessage(
type: 'REGISTER',
fromDeviceId: deviceId,
deviceType: 'CONTROLLER',
);
_send(msg);
// 通知上层已“连接”WebSocketChannel 会缓冲发送,直到底层连接就绪);
// 后续 OFFER 等消息会排在 REGISTER 之后发送,保证服务器先完成注册。
onConnected?.call();
}
/// 发送信令消息。
void send(SignalMessage message) => _send(message);
void _send(SignalMessage message) {
_channel?.sink.add(jsonEncode(message.toJson()));
}
/// 关闭连接。
void disconnect() {
_channel?.sink.close();
_channel = null;
}
bool get isConnected => _channel != null;
}