Dhurgh commited on
Commit
6409906
·
1 Parent(s): e1fb3aa

Fix call signaling glare and duplicate sockets (v2.6.5)

Browse files
Files changed (3) hide show
  1. client.js +43 -10
  2. index.html +1 -1
  3. package.json +1 -1
client.js CHANGED
@@ -24,6 +24,7 @@ let remoteCallPlaybackRetryBound = false;
24
  let remoteCallPlaybackStarted = false;
25
  let isStartingCallSession = false;
26
  let pendingSignalOffer = null;
 
27
  let hasUserInteractedWithPage = false;
28
  let activeRoomSubscription = null;
29
  let roomMessages = JSON.parse(localStorage.getItem('roomMessages') || '{}');
@@ -548,6 +549,16 @@ function switchAccount() {
548
 
549
 
550
  function connectSocket() {
 
 
 
 
 
 
 
 
 
 
551
  socket = io(SERVER_URL, {
552
  reconnection: true,
553
  reconnectionDelay: 1000,
@@ -947,6 +958,22 @@ function connectSocket() {
947
 
948
  try {
949
  if (signal.type === 'offer') {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
950
  if (!activeCallState) {
951
  activeCallState = { callId: payload?.callId || null, peerId: fromId, direction: 'incoming' };
952
  }
@@ -6356,16 +6383,21 @@ async function startCallSession(peerName, peerId, isCaller) {
6356
  createPeerConnection(peerId);
6357
 
6358
  if (isCaller && peerConnection) {
6359
- const offer = await peerConnection.createOffer({
6360
- offerToReceiveAudio: true,
6361
- offerToReceiveVideo: true
6362
- });
6363
- await peerConnection.setLocalDescription(offer);
6364
- socket.emit('video signal', {
6365
- toId: peerId,
6366
- callId: activeCallState?.callId,
6367
- signal: { type: 'offer', offer }
6368
- });
 
 
 
 
 
6369
  }
6370
 
6371
  // Handle an offer that arrived while this session was being set up
@@ -6514,6 +6546,7 @@ function cleanupCallSession(keepDialogOpen = false) {
6514
  lastCallWarningAt = 0;
6515
  isStartingCallSession = false;
6516
  pendingSignalOffer = null;
 
6517
 
6518
  if (localCallStream) {
6519
  localCallStream.getTracks().forEach((track) => track.stop());
 
24
  let remoteCallPlaybackStarted = false;
25
  let isStartingCallSession = false;
26
  let pendingSignalOffer = null;
27
+ let makingOffer = false;
28
  let hasUserInteractedWithPage = false;
29
  let activeRoomSubscription = null;
30
  let roomMessages = JSON.parse(localStorage.getItem('roomMessages') || '{}');
 
549
 
550
 
551
  function connectSocket() {
552
+ // Prevent multiple active socket connections/listeners that can duplicate signaling events.
553
+ if (socket) {
554
+ try {
555
+ socket.removeAllListeners();
556
+ socket.disconnect();
557
+ } catch (socketCleanupError) {
558
+ console.warn('Previous socket cleanup failed:', socketCleanupError);
559
+ }
560
+ }
561
+
562
  socket = io(SERVER_URL, {
563
  reconnection: true,
564
  reconnectionDelay: 1000,
 
958
 
959
  try {
960
  if (signal.type === 'offer') {
961
+ const isPolitePeer = String(currentUser?.id || '') > String(fromId || '');
962
+ const hasPeer = !!peerConnection;
963
+ const offerCollision = hasPeer && (makingOffer || peerConnection.signalingState !== 'stable');
964
+
965
+ if (offerCollision) {
966
+ if (!isPolitePeer) {
967
+ console.warn('Ignoring offer collision (impolite peer)');
968
+ return;
969
+ }
970
+
971
+ // Polite peer: rollback local offer so remote offer can be accepted.
972
+ if (peerConnection.signalingState === 'have-local-offer') {
973
+ await peerConnection.setLocalDescription({ type: 'rollback' });
974
+ }
975
+ }
976
+
977
  if (!activeCallState) {
978
  activeCallState = { callId: payload?.callId || null, peerId: fromId, direction: 'incoming' };
979
  }
 
6383
  createPeerConnection(peerId);
6384
 
6385
  if (isCaller && peerConnection) {
6386
+ makingOffer = true;
6387
+ try {
6388
+ const offer = await peerConnection.createOffer({
6389
+ offerToReceiveAudio: true,
6390
+ offerToReceiveVideo: true
6391
+ });
6392
+ await peerConnection.setLocalDescription(offer);
6393
+ socket.emit('video signal', {
6394
+ toId: peerId,
6395
+ callId: activeCallState?.callId,
6396
+ signal: { type: 'offer', offer }
6397
+ });
6398
+ } finally {
6399
+ makingOffer = false;
6400
+ }
6401
  }
6402
 
6403
  // Handle an offer that arrived while this session was being set up
 
6546
  lastCallWarningAt = 0;
6547
  isStartingCallSession = false;
6548
  pendingSignalOffer = null;
6549
+ makingOffer = false;
6550
 
6551
  if (localCallStream) {
6552
  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.4</span>
3052
  <button class="header-btn mobile-essential" onclick="toggleArchiveChat()" title="Archive chat">
3053
  <i class="fas fa-archive"></i>
3054
  </button>
 
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.5</span>
3052
  <button class="header-btn mobile-essential" onclick="toggleArchiveChat()" title="Archive chat">
3053
  <i class="fas fa-archive"></i>
3054
  </button>
package.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "discord-like-app",
3
- "version": "2.6.4",
4
  "main": "server.js",
5
  "scripts": {
6
  "dev": "nodemon server.js",
 
1
  {
2
  "name": "discord-like-app",
3
+ "version": "2.6.5",
4
  "main": "server.js",
5
  "scripts": {
6
  "dev": "nodemon server.js",