crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

commit b3aa640b6539c74cb19e1925dac81eda0fb3b608
parent c6e457af0c9f6a39bab6050cd8ad8ac5633e13ba
Author: Michael Camilleri <[email protected]>
Date:   Mon, 25 May 2026 23:27:56 +0900

Force engagements to use TURN server

Diffstat:
MCrossmate/Services/EngagementHost.html | 28+++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/Crossmate/Services/EngagementHost.html b/Crossmate/Services/EngagementHost.html @@ -45,7 +45,8 @@ closedEngagementIDs.delete(engagementID); const pc = new RTCPeerConnection({ - iceServers: iceServers(configuredIceServers) + iceServers: iceServers(configuredIceServers), + iceTransportPolicy: "relay" }); const peer = { pc, channel: null, closed: false }; peers.set(engagementID, peer); @@ -140,6 +141,29 @@ }; } + function candidateTypeCounts(sdp) { + const counts = { host: 0, srflx: 0, prflx: 0, relay: 0, other: 0 }; + for (const line of sdp.split(/\r?\n/)) { + if (!line.startsWith("a=candidate:")) continue; + const match = line.match(/ typ ([a-z]+)/); + const type = match ? match[1] : "other"; + counts[type] = (counts[type] || 0) + 1; + } + return counts; + } + + function postCandidateDiagnostic(engagementID, pc, role) { + const sdp = pc.localDescription ? pc.localDescription.sdp : ""; + const counts = candidateTypeCounts(sdp); + postDiagnostic( + engagementID, + "local candidates (" + role + ") host=" + counts.host + + " srflx=" + counts.srflx + + " relay=" + counts.relay + + " other=" + counts.other + ); + } + function candidatesFromSDP(sdp) { return sdp .split(/\r?\n/) @@ -200,6 +224,7 @@ attachChannel(engagementID, channel); await peer.pc.setLocalDescription(await peer.pc.createOffer()); await waitForIceComplete(peer.pc); + postCandidateDiagnostic(engagementID, peer.pc, "offer"); const signal = signalFromLocalDescription(peer.pc); post({ type: "onSignal", engagementID, signal }); return signal; @@ -215,6 +240,7 @@ await peer.pc.setRemoteDescription({ type: "offer", sdp: signal.sdp }); await peer.pc.setLocalDescription(await peer.pc.createAnswer()); await waitForIceComplete(peer.pc); + postCandidateDiagnostic(engagementID, peer.pc, "reply"); const reply = signalFromLocalDescription(peer.pc); post({ type: "onSignal", engagementID, signal: reply }); return reply;