From 99f3b40a5def933ce9215091651749c99c5ecf42 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Wed, 6 May 2026 20:54:37 +0200 Subject: [PATCH] [mirotalksfu] - refactor: improve ICE candidate queueing and co-locate related handlers --- public/js/client.js | 66 ++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/public/js/client.js b/public/js/client.js index 3303fb2f..8a6a2f48 100644 --- a/public/js/client.js +++ b/public/js/client.js @@ -624,33 +624,7 @@ let peerConnections = {}; // keep track of our peer connections, indexed by peer let chatDataChannels = {}; // keep track of our peer chat data channels let fileDataChannels = {}; // keep track of our peer file sharing data channels let allPeers = {}; // keep track of all peers in the room, indexed by peer_id == socket.io id - - -let pendingIceCandidates = {}; - -function queueIceCandidate(peer_id, ice_candidate) { - if (!peer_id || !ice_candidate) return; - if (!pendingIceCandidates[peer_id]) pendingIceCandidates[peer_id] = []; - pendingIceCandidates[peer_id].push(ice_candidate); -} - -async function flushIceCandidates(peer_id) { - const pc = peerConnections[peer_id]; - const queued = pendingIceCandidates[peer_id]; - - if (!pc || !queued || queued.length === 0) return; - if (!pc.remoteDescription || !pc.remoteDescription.type) return; - - delete pendingIceCandidates[peer_id]; - - for (const ice of queued) { - try { - await pc.addIceCandidate(new RTCIceCandidate(ice)); - } catch (err) { - console.error('[Error] addIceCandidate (queued)', err); - } - } -} +let pendingIceCandidates = {}; // keep track of pending ICE candidates before the peer connection is ready, indexed by peer_id == socket.io id let lastStats = null; @@ -2742,9 +2716,6 @@ async function handleAddPeer(config) { const peerConnection = new RTCPeerConnection({ iceServers: iceServers }); peerConnections[peer_id] = peerConnection; - // If ICE arrived before we processed addPeer, keep it and flush when ready. - flushIceCandidates(peer_id).catch((err) => console.error('[Error] flushIceCandidates', err)); - allPeers = peers; // Ensure extras object exists for every peer to avoid undefined checks later try { @@ -3223,6 +3194,41 @@ function handleIceCandidate(config) { }); } +/** + * If addIceCandidate is called before setRemoteDescription, it can fail and the candidate will be lost. To prevent this, we queue candidates until setRemoteDescription is called. + * @param {string} peer_id socket.id + * @param {object} ice_candidate RTCIceCandidateInit + * @returns {void} + */ +function queueIceCandidate(peer_id, ice_candidate) { + if (!peer_id || !ice_candidate) return; + if (!pendingIceCandidates[peer_id]) pendingIceCandidates[peer_id] = []; + pendingIceCandidates[peer_id].push(ice_candidate); +} + +/** + * When setRemoteDescription is called, we can flush any queued ICE candidates for that peer. + * @param {string} peer_id socket.id + * @returns {Promise} + */ +async function flushIceCandidates(peer_id) { + const pc = peerConnections[peer_id]; + const queued = pendingIceCandidates[peer_id]; + + if (!pc || !queued || queued.length === 0) return; + if (!pc.remoteDescription || !pc.remoteDescription.type) return; + + delete pendingIceCandidates[peer_id]; + + for (const ice of queued) { + try { + await pc.addIceCandidate(new RTCIceCandidate(ice)); + } catch (err) { + console.error('[Error] addIceCandidate (queued)', err); + } + } +} + /** * Disconnected from Signaling Server. * Tear down all of our peer connections and remove all the media divs.