Spaces:
Runtime error
Runtime error
Stabilize ICE recovery loop and default relay mode for calls (v2.6.9)
Browse files- client.js +31 -5
- index.html +2 -2
- package.json +1 -1
- server.js +2 -1
client.js
CHANGED
|
@@ -30,6 +30,7 @@ let rtcConfigLoaded = false;
|
|
| 30 |
let activeIceServers = [];
|
| 31 |
let callIceFailureCount = 0;
|
| 32 |
let forceRelayOnly = false;
|
|
|
|
| 33 |
let hasUserInteractedWithPage = false;
|
| 34 |
let activeRoomSubscription = null;
|
| 35 |
let roomMessages = JSON.parse(localStorage.getItem('roomMessages') || '{}');
|
|
@@ -6288,9 +6289,6 @@ function createPeerConnection(peerId) {
|
|
| 6288 |
}
|
| 6289 |
if (peerConnection.connectionState === 'connecting') {
|
| 6290 |
showToast('📞 Connecting call...', 'info');
|
| 6291 |
-
} else if (peerConnection.connectionState === 'disconnected') {
|
| 6292 |
-
showCallWarningThrottled('⚠️ Connection unstable, trying to reconnect...');
|
| 6293 |
-
attemptIceRecovery(peerId);
|
| 6294 |
} else if (peerConnection.connectionState === 'connected') {
|
| 6295 |
callIceFailureCount = 0;
|
| 6296 |
showToast('📞 Call connected!', 'success');
|
|
@@ -6323,10 +6321,34 @@ function createPeerConnection(peerId) {
|
|
| 6323 |
|
| 6324 |
if (peerConnection.iceConnectionState === 'connected' || peerConnection.iceConnectionState === 'completed') {
|
| 6325 |
callIceFailureCount = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6326 |
return;
|
| 6327 |
}
|
| 6328 |
|
| 6329 |
-
if (peerConnection.iceConnectionState === '
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6330 |
attemptIceRecovery(peerId);
|
| 6331 |
}
|
| 6332 |
};
|
|
@@ -6397,7 +6419,7 @@ async function startCallSession(peerName, peerId, isCaller) {
|
|
| 6397 |
currentCallPeerId = peerId;
|
| 6398 |
currentCallPeerName = peerName;
|
| 6399 |
callIceFailureCount = 0;
|
| 6400 |
-
forceRelayOnly =
|
| 6401 |
|
| 6402 |
openCallDialog(peerName);
|
| 6403 |
await ensureRtcConfigLoaded();
|
|
@@ -6579,6 +6601,10 @@ function cleanupCallSession(keepDialogOpen = false) {
|
|
| 6579 |
callIceFailureCount = 0;
|
| 6580 |
forceRelayOnly = false;
|
| 6581 |
activeIceServers = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6582 |
|
| 6583 |
if (localCallStream) {
|
| 6584 |
localCallStream.getTracks().forEach((track) => track.stop());
|
|
|
|
| 30 |
let activeIceServers = [];
|
| 31 |
let callIceFailureCount = 0;
|
| 32 |
let forceRelayOnly = false;
|
| 33 |
+
let pendingIceRecoveryTimer = null;
|
| 34 |
let hasUserInteractedWithPage = false;
|
| 35 |
let activeRoomSubscription = null;
|
| 36 |
let roomMessages = JSON.parse(localStorage.getItem('roomMessages') || '{}');
|
|
|
|
| 6289 |
}
|
| 6290 |
if (peerConnection.connectionState === 'connecting') {
|
| 6291 |
showToast('📞 Connecting call...', 'info');
|
|
|
|
|
|
|
|
|
|
| 6292 |
} else if (peerConnection.connectionState === 'connected') {
|
| 6293 |
callIceFailureCount = 0;
|
| 6294 |
showToast('📞 Call connected!', 'success');
|
|
|
|
| 6321 |
|
| 6322 |
if (peerConnection.iceConnectionState === 'connected' || peerConnection.iceConnectionState === 'completed') {
|
| 6323 |
callIceFailureCount = 0;
|
| 6324 |
+
if (pendingIceRecoveryTimer) {
|
| 6325 |
+
clearTimeout(pendingIceRecoveryTimer);
|
| 6326 |
+
pendingIceRecoveryTimer = null;
|
| 6327 |
+
}
|
| 6328 |
return;
|
| 6329 |
}
|
| 6330 |
|
| 6331 |
+
if (peerConnection.iceConnectionState === 'disconnected') {
|
| 6332 |
+
if (pendingIceRecoveryTimer) {
|
| 6333 |
+
clearTimeout(pendingIceRecoveryTimer);
|
| 6334 |
+
}
|
| 6335 |
+
// 'disconnected' can be temporary on mobile networks; wait before forcing ICE restart.
|
| 6336 |
+
pendingIceRecoveryTimer = setTimeout(() => {
|
| 6337 |
+
pendingIceRecoveryTimer = null;
|
| 6338 |
+
if (!peerConnection) return;
|
| 6339 |
+
if (peerConnection.iceConnectionState === 'disconnected' || peerConnection.iceConnectionState === 'failed') {
|
| 6340 |
+
showCallWarningThrottled('⚠️ Connection unstable, trying to reconnect...');
|
| 6341 |
+
attemptIceRecovery(peerId);
|
| 6342 |
+
}
|
| 6343 |
+
}, 3000);
|
| 6344 |
+
return;
|
| 6345 |
+
}
|
| 6346 |
+
|
| 6347 |
+
if (peerConnection.iceConnectionState === 'failed') {
|
| 6348 |
+
if (pendingIceRecoveryTimer) {
|
| 6349 |
+
clearTimeout(pendingIceRecoveryTimer);
|
| 6350 |
+
pendingIceRecoveryTimer = null;
|
| 6351 |
+
}
|
| 6352 |
attemptIceRecovery(peerId);
|
| 6353 |
}
|
| 6354 |
};
|
|
|
|
| 6419 |
currentCallPeerId = peerId;
|
| 6420 |
currentCallPeerName = peerName;
|
| 6421 |
callIceFailureCount = 0;
|
| 6422 |
+
forceRelayOnly = rtcRuntimeConfig?.iceTransportPolicy === 'relay';
|
| 6423 |
|
| 6424 |
openCallDialog(peerName);
|
| 6425 |
await ensureRtcConfigLoaded();
|
|
|
|
| 6601 |
callIceFailureCount = 0;
|
| 6602 |
forceRelayOnly = false;
|
| 6603 |
activeIceServers = [];
|
| 6604 |
+
if (pendingIceRecoveryTimer) {
|
| 6605 |
+
clearTimeout(pendingIceRecoveryTimer);
|
| 6606 |
+
pendingIceRecoveryTimer = null;
|
| 6607 |
+
}
|
| 6608 |
|
| 6609 |
if (localCallStream) {
|
| 6610 |
localCallStream.getTracks().forEach((track) => track.stop());
|
index.html
CHANGED
|
@@ -3048,7 +3048,7 @@
|
|
| 3048 |
<div class="chat-header-title" id="chatTitle">💬 Select a friend to chat</div>
|
| 3049 |
</div>
|
| 3050 |
<div class="chat-header-actions">
|
| 3051 |
-
<span class="build-badge mobile-essential" id="buildVersionBadge" title="Frontend build version">v2.6.
|
| 3052 |
<button class="header-btn mobile-essential" onclick="toggleArchiveChat()" title="Archive chat">
|
| 3053 |
<i class="fas fa-archive"></i>
|
| 3054 |
</button>
|
|
@@ -3665,7 +3665,7 @@
|
|
| 3665 |
|
| 3666 |
<script src="/socket.io/socket.io.js"></script>
|
| 3667 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
|
| 3668 |
-
<script src="client.js?v=2.6.
|
| 3669 |
</body>
|
| 3670 |
</html>
|
| 3671 |
|
|
|
|
| 3048 |
<div class="chat-header-title" id="chatTitle">💬 Select a friend to chat</div>
|
| 3049 |
</div>
|
| 3050 |
<div class="chat-header-actions">
|
| 3051 |
+
<span class="build-badge mobile-essential" id="buildVersionBadge" title="Frontend build version">v2.6.9</span>
|
| 3052 |
<button class="header-btn mobile-essential" onclick="toggleArchiveChat()" title="Archive chat">
|
| 3053 |
<i class="fas fa-archive"></i>
|
| 3054 |
</button>
|
|
|
|
| 3665 |
|
| 3666 |
<script src="/socket.io/socket.io.js"></script>
|
| 3667 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
|
| 3668 |
+
<script src="client.js?v=2.6.9"></script>
|
| 3669 |
</body>
|
| 3670 |
</html>
|
| 3671 |
|
package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
{
|
| 2 |
"name": "discord-like-app",
|
| 3 |
-
"version": "2.6.
|
| 4 |
"main": "server.js",
|
| 5 |
"scripts": {
|
| 6 |
"dev": "nodemon server.js",
|
|
|
|
| 1 |
{
|
| 2 |
"name": "discord-like-app",
|
| 3 |
+
"version": "2.6.9",
|
| 4 |
"main": "server.js",
|
| 5 |
"scripts": {
|
| 6 |
"dev": "nodemon server.js",
|
server.js
CHANGED
|
@@ -98,7 +98,8 @@ app.get('/api/rtc-config', (req, res) => {
|
|
| 98 |
const turnUrlsRaw = process.env.TURN_URLS || '';
|
| 99 |
const turnUsername = process.env.TURN_USERNAME || '';
|
| 100 |
const turnCredential = process.env.TURN_CREDENTIAL || '';
|
| 101 |
-
const
|
|
|
|
| 102 |
|
| 103 |
let iceServers = [...defaultIceServers];
|
| 104 |
|
|
|
|
| 98 |
const turnUrlsRaw = process.env.TURN_URLS || '';
|
| 99 |
const turnUsername = process.env.TURN_USERNAME || '';
|
| 100 |
const turnCredential = process.env.TURN_CREDENTIAL || '';
|
| 101 |
+
const relayFlag = String(process.env.RTC_FORCE_RELAY || 'true').toLowerCase();
|
| 102 |
+
const forceRelay = relayFlag === 'true' || relayFlag === '1' || relayFlag === 'yes';
|
| 103 |
|
| 104 |
let iceServers = [...defaultIceServers];
|
| 105 |
|