♻️ Proper singaling
This commit is contained in:
@@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||
import 'package:island/models/account.dart';
|
||||
import 'package:island/pods/chat/webrtc_signaling.dart';
|
||||
import 'package:island/pods/userinfo.dart';
|
||||
import 'package:island/talker.dart';
|
||||
|
||||
class WebRTCParticipant {
|
||||
@@ -11,6 +12,7 @@ class WebRTCParticipant {
|
||||
final SnAccount userinfo;
|
||||
RTCPeerConnection? peerConnection;
|
||||
MediaStream? remoteStream;
|
||||
List<RTCIceCandidate> remoteCandidates = [];
|
||||
bool isAudioEnabled = true;
|
||||
bool isVideoEnabled = false;
|
||||
bool isConnected = false;
|
||||
@@ -20,6 +22,8 @@ class WebRTCParticipant {
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.userinfo,
|
||||
this.isAudioEnabled = true,
|
||||
this.isVideoEnabled = false,
|
||||
this.isLocal = false,
|
||||
});
|
||||
}
|
||||
@@ -48,6 +52,10 @@ class WebRTCManager {
|
||||
}
|
||||
|
||||
Future<void> initialize(Ref ref) async {
|
||||
final user = ref.watch(userInfoProvider).value!;
|
||||
_signaling.userId = user.id;
|
||||
_signaling.userName = user.name;
|
||||
_signaling.user = user;
|
||||
await _initializeLocalStream();
|
||||
_setupSignalingListeners();
|
||||
await _signaling.connect(ref);
|
||||
@@ -60,6 +68,19 @@ class WebRTCManager {
|
||||
'video': true,
|
||||
});
|
||||
talker.info('[WebRTC] Local stream initialized');
|
||||
|
||||
// Add local participant
|
||||
bool videoEnabled = _localStream!.getVideoTracks().isNotEmpty;
|
||||
WebRTCParticipant localParticipant = WebRTCParticipant(
|
||||
id: _signaling.userId,
|
||||
name: _signaling.userName,
|
||||
userinfo: _signaling.user,
|
||||
isLocal: true,
|
||||
isAudioEnabled: true,
|
||||
isVideoEnabled: videoEnabled,
|
||||
);
|
||||
_participants[_signaling.userId] = localParticipant;
|
||||
_participantController.add(localParticipant);
|
||||
} catch (e) {
|
||||
talker.error('[WebRTC] Failed to initialize local stream: $e');
|
||||
rethrow;
|
||||
@@ -156,6 +177,7 @@ class WebRTCManager {
|
||||
|
||||
final peerConnection = await createPeerConnection(configuration);
|
||||
_peerConnections[participantId] = peerConnection;
|
||||
_participants[participantId]!.peerConnection = peerConnection;
|
||||
|
||||
if (_localStream != null) {
|
||||
for (final track in _localStream!.getTracks()) {
|
||||
@@ -233,6 +255,15 @@ class WebRTCManager {
|
||||
await peerConnection.setLocalDescription(answer);
|
||||
// CHANGED: Send answer to the specific participant
|
||||
_signaling.sendAnswer(participantId, answer);
|
||||
|
||||
// Process any queued ICE candidates
|
||||
final participant = _participants[participantId];
|
||||
if (participant != null) {
|
||||
for (final candidate in participant.remoteCandidates) {
|
||||
await peerConnection.addCandidate(candidate);
|
||||
}
|
||||
participant.remoteCandidates.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleAnswer(String from, Map<String, dynamic> data) async {
|
||||
@@ -243,6 +274,15 @@ class WebRTCManager {
|
||||
final peerConnection = _peerConnections[participantId];
|
||||
if (peerConnection != null) {
|
||||
await peerConnection.setRemoteDescription(answer);
|
||||
|
||||
// Process any queued ICE candidates
|
||||
final participant = _participants[participantId];
|
||||
if (participant != null) {
|
||||
for (final candidate in participant.remoteCandidates) {
|
||||
await peerConnection.addCandidate(candidate);
|
||||
}
|
||||
participant.remoteCandidates.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,11 +297,14 @@ class WebRTCManager {
|
||||
data['sdpMLineIndex'],
|
||||
);
|
||||
|
||||
final peerConnection = _peerConnections[participantId];
|
||||
if (peerConnection != null) {
|
||||
// It's possible for candidates to arrive before the remote description is set.
|
||||
// A robust implementation might queue them, but for now, we'll just add them.
|
||||
await peerConnection.addCandidate(candidate);
|
||||
final participant = _participants[participantId];
|
||||
if (participant != null) {
|
||||
final pc = participant.peerConnection;
|
||||
if (pc != null) {
|
||||
await pc.addCandidate(candidate);
|
||||
} else {
|
||||
participant.remoteCandidates.add(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,7 +316,7 @@ class WebRTCManager {
|
||||
}
|
||||
}
|
||||
|
||||
_participants.values.where((e) => e.isLocal).firstOrNull?.isAudioEnabled = true;
|
||||
_participants[_signaling.userId]?.isAudioEnabled = enabled;
|
||||
}
|
||||
|
||||
Future<void> toggleCamera(bool enabled) async {
|
||||
@@ -283,7 +326,7 @@ class WebRTCManager {
|
||||
});
|
||||
}
|
||||
|
||||
_participants.values.where((e) => e.isLocal).firstOrNull?.isVideoEnabled = true;
|
||||
_participants[_signaling.userId]?.isVideoEnabled = enabled;
|
||||
}
|
||||
|
||||
List<WebRTCParticipant> get participants => _participants.values.toList();
|
||||
@@ -294,6 +337,7 @@ class WebRTCManager {
|
||||
pc.close();
|
||||
}
|
||||
_peerConnections.clear();
|
||||
_participants.values.forEach((p) => p.remoteCandidates.clear());
|
||||
_participants.clear();
|
||||
_localStream?.dispose();
|
||||
_participantController.close();
|
||||
|
||||
Reference in New Issue
Block a user