From f35fdda7a24f31f05435c3c6a325e2d596d1cfb6 Mon Sep 17 00:00:00 2001 From: pavel Date: Tue, 24 Feb 2026 00:55:49 +0100 Subject: [PATCH] m --- static/app.js | 56 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/static/app.js b/static/app.js index fca5265..5d5deb4 100644 --- a/static/app.js +++ b/static/app.js @@ -675,9 +675,7 @@ function ensurePeerConnection(peerId) { pc.onnegotiationneeded = async () => { try { - if (shouldInitiateOffer(peerId)) { - await sendOffer(peerId); - } + await sendOffer(peerId); } catch (err) { console.error("negotiation failed", err); } @@ -701,25 +699,43 @@ async function sendOffer(peerId) { async function handleSignal(fromPeerId, kind, data) { const pc = ensurePeerConnection(fromPeerId); + const polite = !shouldInitiateOffer(fromPeerId); - if (kind === "offer") { - await pc.setRemoteDescription(new RTCSessionDescription(data)); - const answer = await pc.createAnswer(); - await pc.setLocalDescription(answer); - state.voice.ws.send(JSON.stringify({ - type: "signal", - to_user_id: fromPeerId, - kind: "answer", - data: answer, - })); - } else if (kind === "answer") { - await pc.setRemoteDescription(new RTCSessionDescription(data)); - } else if (kind === "ice") { - try { - await pc.addIceCandidate(data ? new RTCIceCandidate(data) : null); - } catch (err) { - console.warn("failed to add ice candidate", err); + try { + if (kind === "offer") { + const offerCollision = (pc.signalingState !== "stable"); + if (offerCollision) { + if (!polite) return; + await Promise.all([ + pc.setLocalDescription({ type: "rollback" }), + pc.setRemoteDescription(new RTCSessionDescription(data)) + ]); + } else { + await pc.setRemoteDescription(new RTCSessionDescription(data)); + } + const answer = await pc.createAnswer(); + await pc.setLocalDescription(answer); + state.voice.ws.send(JSON.stringify({ + type: "signal", + to_user_id: fromPeerId, + kind: "answer", + data: answer, + })); + } else if (kind === "answer") { + await pc.setRemoteDescription(new RTCSessionDescription(data)); + } else if (kind === "ice") { + try { + await pc.addIceCandidate(data ? new RTCIceCandidate(data) : null); + } catch (err) { + if (pc.signalingState !== "stable") { + // Ignore ICE candidates during negotiation + } else { + console.warn("failed to add ice candidate", err); + } + } } + } catch (err) { + console.error("handleSignal failed", err); } }