import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:sefer_driver/print.dart'; class SignalingService { WebSocket? _socket; final String _url = "wss://calls.intaleqapp.com/ws"; // Callbacks Function(List iceServers)? onConnected; Function(String reason)? onDisconnected; Function(Map offer)? onOffer; Function(Map answer)? onAnswer; Function(Map candidate)? onIceCandidate; Function(String reason)? onCallEnded; Function()? onParticipantJoined; bool get isConnected => _socket != null && _socket!.readyState == WebSocket.open; Future connect(String sessionId, String userId) async { if (isConnected) return; try { Log.print("Signaling: Connecting to $_url"); _socket = await WebSocket.connect(_url) .timeout(const Duration(seconds: 8)); _socket!.listen( (data) { _handleMessage(data); }, onError: (err) { Log.print("Signaling socket error: $err"); disconnect("socket_error"); }, onDone: () { Log.print("Signaling socket closed by server"); disconnect("socket_closed"); }, cancelOnError: true, ); // Send the authenticate message as the first message send("authenticate", { "session_id": sessionId, "user_id": userId, }); } catch (e) { Log.print("Signaling connection failed: $e"); onDisconnected?.call("connection_failed"); } } void _handleMessage(dynamic data) { try { Log.print("Signaling received raw: $data"); final message = jsonDecode(data); if (message is! Map) return; final type = message['type']; switch (type) { case 'authenticated': final iceServers = message['ice_servers'] as List? ?? []; onConnected?.call(iceServers); break; case 'participant_joined': onParticipantJoined?.call(); break; case 'offer': if (message['sdp'] != null) { onOffer?.call(message['sdp']); } break; case 'answer': if (message['sdp'] != null) { onAnswer?.call(message['sdp']); } break; case 'ice_candidate': if (message['candidate'] != null) { onIceCandidate?.call(message['candidate']); } break; case 'call_ended': onCallEnded?.call(message['reason'] ?? 'normal'); break; } } catch (e) { Log.print("Error handling signaling message: $e"); } } void send(String type, Map data) { if (!isConnected) return; final msg = jsonEncode({ 'type': type, ...data, }); Log.print("Signaling sending: $msg"); _socket!.add(msg); } void disconnect([String reason = "user_hangup"]) { if (_socket != null) { _socket!.close(); _socket = null; onDisconnected?.call(reason); } } }