Spaces:
Runtime error
Runtime error
Fix calls fully: remove bad default TURN, conditional relay fallback, mobile control bindings (v2.8.3)
Browse files- client.js +57 -2
- index.html +6 -6
- package.json +1 -1
- server.js +1 -20
client.js
CHANGED
|
@@ -100,6 +100,13 @@ function getDefaultIceServers() {
|
|
| 100 |
];
|
| 101 |
}
|
| 102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
async function ensureRtcConfigLoaded() {
|
| 104 |
if (rtcConfigLoaded) return;
|
| 105 |
rtcConfigLoaded = true;
|
|
@@ -343,6 +350,50 @@ function ensureRemoteMediaPlayback(videoEl) {
|
|
| 343 |
setTimeout(tryPlay, 900);
|
| 344 |
}
|
| 345 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 346 |
|
| 347 |
|
| 348 |
function toggleAuthMode() {
|
|
@@ -5718,6 +5769,7 @@ function showToastClickable(message, type = 'success', chatContext = null) {
|
|
| 5718 |
window.addEventListener('DOMContentLoaded', () => {
|
| 5719 |
loadTheme();
|
| 5720 |
applySettingsToUI();
|
|
|
|
| 5721 |
pinnedChats = JSON.parse(localStorage.getItem('pinnedChats') || '[]');
|
| 5722 |
joinedCommunities = JSON.parse(localStorage.getItem('joinedCommunities') || '[]');
|
| 5723 |
joinedGroups = JSON.parse(localStorage.getItem('joinedGroups') || '[]');
|
|
@@ -6206,6 +6258,7 @@ function createPeerConnection(peerId) {
|
|
| 6206 |
const runtimeIceServers = Array.isArray(rtcRuntimeConfig?.iceServers) && rtcRuntimeConfig.iceServers.length
|
| 6207 |
? rtcRuntimeConfig.iceServers
|
| 6208 |
: getDefaultIceServers();
|
|
|
|
| 6209 |
activeIceServers = runtimeIceServers;
|
| 6210 |
|
| 6211 |
peerConnection = new RTCPeerConnection({
|
|
@@ -6400,13 +6453,15 @@ function createPeerConnection(peerId) {
|
|
| 6400 |
callIceFailureCount += 1;
|
| 6401 |
|
| 6402 |
try {
|
| 6403 |
-
if (callIceFailureCount >= 2 && !forceRelayOnly) {
|
| 6404 |
forceRelayOnly = true;
|
| 6405 |
peerConnection.setConfiguration({
|
| 6406 |
iceServers: activeIceServers,
|
| 6407 |
iceTransportPolicy: 'relay'
|
| 6408 |
});
|
| 6409 |
showToast('Switching call to relay mode for network compatibility...', 'warning');
|
|
|
|
|
|
|
| 6410 |
}
|
| 6411 |
|
| 6412 |
peerConnection.restartIce?.();
|
|
@@ -6478,7 +6533,7 @@ async function startCallSession(peerName, peerId, isCaller) {
|
|
| 6478 |
const localVideo = document.getElementById('localCallVideo');
|
| 6479 |
if (localVideo && localCallStream) {
|
| 6480 |
localVideo.srcObject = localCallStream;
|
| 6481 |
-
|
| 6482 |
} else if (localVideo) {
|
| 6483 |
localVideo.srcObject = null;
|
| 6484 |
}
|
|
|
|
| 100 |
];
|
| 101 |
}
|
| 102 |
|
| 103 |
+
function hasTurnServerConfigured(iceServers = []) {
|
| 104 |
+
return iceServers.some((server) => {
|
| 105 |
+
const urls = Array.isArray(server?.urls) ? server.urls : [server?.urls];
|
| 106 |
+
return urls.some((url) => typeof url === 'string' && /^turns?:/i.test(url));
|
| 107 |
+
});
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
async function ensureRtcConfigLoaded() {
|
| 111 |
if (rtcConfigLoaded) return;
|
| 112 |
rtcConfigLoaded = true;
|
|
|
|
| 350 |
setTimeout(tryPlay, 900);
|
| 351 |
}
|
| 352 |
|
| 353 |
+
function ensureLocalPreviewPlayback(videoEl) {
|
| 354 |
+
if (!videoEl || !videoEl.srcObject) return;
|
| 355 |
+
|
| 356 |
+
videoEl.muted = true;
|
| 357 |
+
videoEl.autoplay = true;
|
| 358 |
+
videoEl.playsInline = true;
|
| 359 |
+
|
| 360 |
+
const tryPlay = () => {
|
| 361 |
+
videoEl.play().catch(() => {});
|
| 362 |
+
};
|
| 363 |
+
|
| 364 |
+
tryPlay();
|
| 365 |
+
setTimeout(tryPlay, 120);
|
| 366 |
+
setTimeout(tryPlay, 500);
|
| 367 |
+
}
|
| 368 |
+
|
| 369 |
+
let callControlBindingsDone = false;
|
| 370 |
+
function bindCallControlButtons() {
|
| 371 |
+
if (callControlBindingsDone) return;
|
| 372 |
+
|
| 373 |
+
const bindings = [
|
| 374 |
+
['muteBtn', toggleLocalMute],
|
| 375 |
+
['cameraBtn', toggleCallCamera],
|
| 376 |
+
['endCallBtn', endVideoCall],
|
| 377 |
+
['callDebugBtn', toggleCallDebug]
|
| 378 |
+
];
|
| 379 |
+
|
| 380 |
+
bindings.forEach(([id, action]) => {
|
| 381 |
+
const button = document.getElementById(id);
|
| 382 |
+
if (!button) return;
|
| 383 |
+
|
| 384 |
+
const handlePress = (event) => {
|
| 385 |
+
event.preventDefault();
|
| 386 |
+
action();
|
| 387 |
+
};
|
| 388 |
+
|
| 389 |
+
button.addEventListener('click', handlePress);
|
| 390 |
+
button.addEventListener('touchend', handlePress, { passive: false });
|
| 391 |
+
button.style.pointerEvents = 'auto';
|
| 392 |
+
});
|
| 393 |
+
|
| 394 |
+
callControlBindingsDone = true;
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
|
| 398 |
|
| 399 |
function toggleAuthMode() {
|
|
|
|
| 5769 |
window.addEventListener('DOMContentLoaded', () => {
|
| 5770 |
loadTheme();
|
| 5771 |
applySettingsToUI();
|
| 5772 |
+
bindCallControlButtons();
|
| 5773 |
pinnedChats = JSON.parse(localStorage.getItem('pinnedChats') || '[]');
|
| 5774 |
joinedCommunities = JSON.parse(localStorage.getItem('joinedCommunities') || '[]');
|
| 5775 |
joinedGroups = JSON.parse(localStorage.getItem('joinedGroups') || '[]');
|
|
|
|
| 6258 |
const runtimeIceServers = Array.isArray(rtcRuntimeConfig?.iceServers) && rtcRuntimeConfig.iceServers.length
|
| 6259 |
? rtcRuntimeConfig.iceServers
|
| 6260 |
: getDefaultIceServers();
|
| 6261 |
+
const hasTurnServersConfigured = hasTurnServerConfigured(runtimeIceServers);
|
| 6262 |
activeIceServers = runtimeIceServers;
|
| 6263 |
|
| 6264 |
peerConnection = new RTCPeerConnection({
|
|
|
|
| 6453 |
callIceFailureCount += 1;
|
| 6454 |
|
| 6455 |
try {
|
| 6456 |
+
if (callIceFailureCount >= 2 && !forceRelayOnly && hasTurnServersConfigured) {
|
| 6457 |
forceRelayOnly = true;
|
| 6458 |
peerConnection.setConfiguration({
|
| 6459 |
iceServers: activeIceServers,
|
| 6460 |
iceTransportPolicy: 'relay'
|
| 6461 |
});
|
| 6462 |
showToast('Switching call to relay mode for network compatibility...', 'warning');
|
| 6463 |
+
} else if (callIceFailureCount >= 2 && !hasTurnServersConfigured) {
|
| 6464 |
+
showToast('Retrying call without relay fallback...', 'warning');
|
| 6465 |
}
|
| 6466 |
|
| 6467 |
peerConnection.restartIce?.();
|
|
|
|
| 6533 |
const localVideo = document.getElementById('localCallVideo');
|
| 6534 |
if (localVideo && localCallStream) {
|
| 6535 |
localVideo.srcObject = localCallStream;
|
| 6536 |
+
ensureLocalPreviewPlayback(localVideo);
|
| 6537 |
} else if (localVideo) {
|
| 6538 |
localVideo.srcObject = null;
|
| 6539 |
}
|
index.html
CHANGED
|
@@ -3098,7 +3098,7 @@
|
|
| 3098 |
<div class="chat-header-title" id="chatTitle">π¬ Select a friend to chat</div>
|
| 3099 |
</div>
|
| 3100 |
<div class="chat-header-actions">
|
| 3101 |
-
<span class="build-badge mobile-essential" id="buildVersionBadge" title="Frontend build version">v2.8.
|
| 3102 |
<button class="header-btn mobile-essential" onclick="toggleArchiveChat()" title="Archive chat">
|
| 3103 |
<i class="fas fa-archive"></i>
|
| 3104 |
</button>
|
|
@@ -3688,15 +3688,15 @@
|
|
| 3688 |
<div id="callOverlayPeerName" style="color:#fff; font-size:18px; font-weight:700;"></div>
|
| 3689 |
<div id="callTimerLabel" style="color:rgba(255,255,255,0.7); font-size:13px; margin-top:4px;">00:00:00</div>
|
| 3690 |
</div>
|
| 3691 |
-
<button
|
| 3692 |
</div>
|
| 3693 |
|
| 3694 |
<div id="callDebugPanel"></div>
|
| 3695 |
|
| 3696 |
<div class="call-overlay-controls">
|
| 3697 |
-
<button id="muteBtn" class="call-ctrl-btn"
|
| 3698 |
-
<button id="cameraBtn" class="call-ctrl-btn"
|
| 3699 |
-
<button class="call-end-btn"
|
| 3700 |
</div>
|
| 3701 |
</div>
|
| 3702 |
</div>
|
|
@@ -3717,7 +3717,7 @@
|
|
| 3717 |
|
| 3718 |
<script src="/socket.io/socket.io.js"></script>
|
| 3719 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
|
| 3720 |
-
<script src="client.js?v=2.8.
|
| 3721 |
</body>
|
| 3722 |
</html>
|
| 3723 |
|
|
|
|
| 3098 |
<div class="chat-header-title" id="chatTitle">π¬ Select a friend to chat</div>
|
| 3099 |
</div>
|
| 3100 |
<div class="chat-header-actions">
|
| 3101 |
+
<span class="build-badge mobile-essential" id="buildVersionBadge" title="Frontend build version">v2.8.3</span>
|
| 3102 |
<button class="header-btn mobile-essential" onclick="toggleArchiveChat()" title="Archive chat">
|
| 3103 |
<i class="fas fa-archive"></i>
|
| 3104 |
</button>
|
|
|
|
| 3688 |
<div id="callOverlayPeerName" style="color:#fff; font-size:18px; font-weight:700;"></div>
|
| 3689 |
<div id="callTimerLabel" style="color:rgba(255,255,255,0.7); font-size:13px; margin-top:4px;">00:00:00</div>
|
| 3690 |
</div>
|
| 3691 |
+
<button id="callDebugBtn" style="background:rgba(255,255,255,0.18); border:none; color:white; padding:7px 13px; border-radius:8px; cursor:pointer; font-size:12px; font-weight:600;">π§ Debug</button>
|
| 3692 |
</div>
|
| 3693 |
|
| 3694 |
<div id="callDebugPanel"></div>
|
| 3695 |
|
| 3696 |
<div class="call-overlay-controls">
|
| 3697 |
+
<button id="muteBtn" class="call-ctrl-btn" title="Mute/Unmute">π€</button>
|
| 3698 |
+
<button id="cameraBtn" class="call-ctrl-btn" title="Camera on/off">π·</button>
|
| 3699 |
+
<button id="endCallBtn" class="call-end-btn" title="End Call">π΅</button>
|
| 3700 |
</div>
|
| 3701 |
</div>
|
| 3702 |
</div>
|
|
|
|
| 3717 |
|
| 3718 |
<script src="/socket.io/socket.io.js"></script>
|
| 3719 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
|
| 3720 |
+
<script src="client.js?v=2.8.3"></script>
|
| 3721 |
</body>
|
| 3722 |
</html>
|
| 3723 |
|
package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
{
|
| 2 |
"name": "discord-like-app",
|
| 3 |
-
"version": "2.8.
|
| 4 |
"main": "server.js",
|
| 5 |
"scripts": {
|
| 6 |
"dev": "nodemon server.js",
|
|
|
|
| 1 |
{
|
| 2 |
"name": "discord-like-app",
|
| 3 |
+
"version": "2.8.3",
|
| 4 |
"main": "server.js",
|
| 5 |
"scripts": {
|
| 6 |
"dev": "nodemon server.js",
|
server.js
CHANGED
|
@@ -73,26 +73,7 @@ app.get('/api/rtc-config', (req, res) => {
|
|
| 73 |
{ urls: 'stun:stun2.l.google.com:19302' },
|
| 74 |
{ urls: 'stun:stun3.l.google.com:19302' },
|
| 75 |
{ urls: 'stun:stun4.l.google.com:19302' },
|
| 76 |
-
{ urls: 'stun:stun.cloudflare.com:3478' }
|
| 77 |
-
{
|
| 78 |
-
urls: [
|
| 79 |
-
'turn:a.relay.metered.ca:80',
|
| 80 |
-
'turn:a.relay.metered.ca:80?transport=tcp',
|
| 81 |
-
'turn:a.relay.metered.ca:443',
|
| 82 |
-
'turns:a.relay.metered.ca:443?transport=tcp'
|
| 83 |
-
],
|
| 84 |
-
username: 'openrelayproject',
|
| 85 |
-
credential: 'openrelayproject'
|
| 86 |
-
},
|
| 87 |
-
{
|
| 88 |
-
urls: [
|
| 89 |
-
'turn:openrelay.metered.ca:80',
|
| 90 |
-
'turn:openrelay.metered.ca:443',
|
| 91 |
-
'turn:openrelay.metered.ca:443?transport=tcp'
|
| 92 |
-
],
|
| 93 |
-
username: 'openrelayproject',
|
| 94 |
-
credential: 'openrelayproject'
|
| 95 |
-
}
|
| 96 |
];
|
| 97 |
|
| 98 |
const turnUrlsRaw = process.env.TURN_URLS || '';
|
|
|
|
| 73 |
{ urls: 'stun:stun2.l.google.com:19302' },
|
| 74 |
{ urls: 'stun:stun3.l.google.com:19302' },
|
| 75 |
{ urls: 'stun:stun4.l.google.com:19302' },
|
| 76 |
+
{ urls: 'stun:stun.cloudflare.com:3478' }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
];
|
| 78 |
|
| 79 |
const turnUrlsRaw = process.env.TURN_URLS || '';
|