Skip to content

Commit

Permalink
fix(connectivity) Force restart client after 3 failed ICE restarts
Browse files Browse the repository at this point in the history
  • Loading branch information
jallamsetty1 committed Feb 4, 2025
1 parent 2a5d7fc commit efbc00c
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 8 deletions.
15 changes: 14 additions & 1 deletion JitsiConference.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,21 @@ import RTCEvents from './service/RTC/RTCEvents';
import { SignalingEvents } from './service/RTC/SignalingEvents';
import { getMediaTypeFromSourceName, getSourceNameForJitsiTrack } from './service/RTC/SignalingLayer';
import { VideoType } from './service/RTC/VideoType';
import { MAX_CONNECTION_RETRIES } from './service/connectivity/Constants';
import {
ACTION_JINGLE_RESTART,
ACTION_JINGLE_SI_RECEIVED,
ACTION_JINGLE_SI_TIMEOUT,
ACTION_JINGLE_TERMINATE,
ACTION_JVB_ICE_FAILED,
ACTION_P2P_DECLINED,
ACTION_P2P_ESTABLISHED,
ACTION_P2P_FAILED,
ACTION_P2P_SWITCH_TO_JVB,
ICE_ESTABLISHMENT_DURATION_DIFF,
createConferenceEvent,
createJingleEvent,
createJvbIceFailedEvent,
createP2PEvent
} from './service/statistics/AnalyticsEvents';
import { XMPPEvents } from './service/xmpp/XMPPEvents';
Expand Down Expand Up @@ -2917,7 +2920,7 @@ JitsiConference.prototype._onIceConnectionFailed = function(session) {
reason: 'connectivity-error',
reasonDescription: 'ICE FAILED'
});
} else if (session && this.jvbJingleSession === session) {
} else if (session && this.jvbJingleSession === session && this._iceRestarts < MAX_CONNECTION_RETRIES) {
// Use an exponential backoff timer for ICE restarts.
const jitterDelay = getJitterDelay(this._iceRestarts, 1000 /* min. delay */);

Expand All @@ -2927,6 +2930,16 @@ JitsiConference.prototype._onIceConnectionFailed = function(session) {
this._delayedIceFailed.start(session);
this._iceRestarts++;
}, jitterDelay);
} else if (this.jvbJingleSession === session) {
logger.warn('ICE failed, force reloading the conference after failed attempts to re-establish ICE');
Statistics.sendAnalyticsAndLog(
createJvbIceFailedEvent(
ACTION_JVB_ICE_FAILED,
{
participantId: this.myUserId(),
userRegion: this.options.config.deploymentInfo?.userRegion
}));
this.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED, JitsiConferenceErrors.ICE_FAILED);
}
};

Expand Down
10 changes: 3 additions & 7 deletions modules/xmpp/XmppConnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { getLogger } from '@jitsi/logger';
import { $pres, Strophe } from 'strophe.js';
import 'strophejs-plugin-stream-management';

import { MAX_CONNECTION_RETRIES } from '../../service/connectivity/Constants';
import Listenable from '../util/Listenable';

import ResumeTask from './ResumeTask';
Expand All @@ -10,11 +11,6 @@ import PingConnectionPlugin from './strophe.ping';

const logger = getLogger(__filename);

/**
* Maximum number of tries to resume.
*/
const MAX_RESUME_TRIES = 3;

/**
* The lib-jitsi-meet layer for {@link Strophe.Connection}.
*/
Expand Down Expand Up @@ -649,10 +645,10 @@ export default class XmppConnection extends Listenable {
if (resumeToken) {
this._resumeTask.schedule();

const r = this._resumeTask.retryCount <= MAX_RESUME_TRIES;
const r = this._resumeTask.retryCount <= MAX_CONNECTION_RETRIES;

if (!r) {
logger.warn(`Maximum resume tries reached (${MAX_RESUME_TRIES}), giving up.`);
logger.warn(`Maximum resume tries reached (${MAX_CONNECTION_RETRIES}), giving up.`);
}

return r;
Expand Down
2 changes: 2 additions & 0 deletions service/connectivity/Constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Number of times the client attempts to reconnect to the XMPP server or JVB (in case of an ICE failure).
export const MAX_CONNECTION_RETRIES = 3;
5 changes: 5 additions & 0 deletions service/statistics/AnalyticsEvents.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ describe( "/service/statistics/AnalyticsEvents members", () => {
ACTION_JINGLE_SI_RECEIVED,
ACTION_JINGLE_SI_TIMEOUT,
ACTION_JINGLE_TERMINATE,
ACTION_JVB_ICE_FAILED,
ACTION_P2P_DECLINED,
ACTION_P2P_ESTABLISHED,
ACTION_P2P_FAILED,
Expand All @@ -33,6 +34,7 @@ describe( "/service/statistics/AnalyticsEvents members", () => {
createE2eRttEvent,
createFocusLeftEvent,
createGetUserMediaEvent,
createJvbIceFailedEvent,
createParticipantConnectionStatusEvent,
createTrackStreamingStatusEvent,
createJingleEvent,
Expand All @@ -59,6 +61,7 @@ describe( "/service/statistics/AnalyticsEvents members", () => {
expect( ACTION_JINGLE_SI_RECEIVED ).toBe( 'session-initiate.received' );
expect( ACTION_JINGLE_SI_TIMEOUT ).toBe( 'session-initiate.timeout' );
expect( ACTION_JINGLE_TERMINATE ).toBe( 'terminate' );
expect( ACTION_JVB_ICE_FAILED ).toBe( 'jvb.ice.failed' );
expect( ACTION_P2P_DECLINED ).toBe( 'decline' );
expect( ACTION_P2P_ESTABLISHED ).toBe( 'established' );
expect( ACTION_P2P_FAILED ).toBe( 'failed' );
Expand All @@ -84,6 +87,7 @@ describe( "/service/statistics/AnalyticsEvents members", () => {
expect( AnalyticsEvents.ACTION_JINGLE_SI_RECEIVED ).toBe( 'session-initiate.received' );
expect( AnalyticsEvents.ACTION_JINGLE_SI_TIMEOUT ).toBe( 'session-initiate.timeout' );
expect( AnalyticsEvents.ACTION_JINGLE_TERMINATE ).toBe( 'terminate' );
expect( AnalyticsEvents.ACTION_JVB_ICE_FAILED ).toBe( 'jvb.ice.failed' );
expect( AnalyticsEvents.ACTION_P2P_DECLINED ).toBe( 'decline' );
expect( AnalyticsEvents.ACTION_P2P_ESTABLISHED ).toBe( 'established' );
expect( AnalyticsEvents.ACTION_P2P_FAILED ).toBe( 'failed' );
Expand All @@ -104,6 +108,7 @@ describe( "/service/statistics/AnalyticsEvents members", () => {
expect( typeof ( createE2eRttEvent ) ).toBe( 'function' );
expect( typeof ( createFocusLeftEvent ) ).toBe( 'function' );
expect( typeof ( createGetUserMediaEvent ) ).toBe( 'function' );
expect( typeof ( createJvbIceFailedEvent ) ).toBe( 'function' );
expect( typeof ( createParticipantConnectionStatusEvent ) ).toBe( 'function' );
expect( typeof ( createTrackStreamingStatusEvent ) ).toBe( 'function' );
expect( typeof ( createJingleEvent ) ).toBe( 'function' );
Expand Down
19 changes: 19 additions & 0 deletions service/statistics/AnalyticsEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ export enum AnalyticsEvents {
*/
ACTION_JINGLE_TERMINATE = 'terminate',

/**
* The "action" value for JVB events which indicates that the ICE connection has failed after 3 restart attempts
*/
ACTION_JVB_ICE_FAILED = 'jvb.ice.failed',

/**
* The "action" value for P2P events which indicates that P2P session initiate message has been rejected by the client
* because the mandatory requirements were not met.
Expand Down Expand Up @@ -221,6 +226,7 @@ export const ACTION_JINGLE_SA_TIMEOUT = AnalyticsEvents.ACTION_JINGLE_SA_TIMEOUT
export const ACTION_JINGLE_SI_RECEIVED = AnalyticsEvents.ACTION_JINGLE_SI_RECEIVED;
export const ACTION_JINGLE_SI_TIMEOUT = AnalyticsEvents.ACTION_JINGLE_SI_TIMEOUT;
export const ACTION_JINGLE_TERMINATE = AnalyticsEvents.ACTION_JINGLE_TERMINATE;
export const ACTION_JVB_ICE_FAILED = AnalyticsEvents.ACTION_JVB_ICE_FAILED;
export const ACTION_P2P_DECLINED = AnalyticsEvents.ACTION_P2P_DECLINED;
export const ACTION_P2P_ESTABLISHED = AnalyticsEvents.ACTION_P2P_ESTABLISHED;
export const ACTION_P2P_FAILED = AnalyticsEvents.ACTION_P2P_FAILED;
Expand Down Expand Up @@ -333,6 +339,19 @@ export const createGetUserMediaEvent = ( action: 'error' | 'success' | 'warning'
attributes
} );

/**
* Creates an event which indicates that the JVB ICE connection has failed event after 3 retries.
*
* @param action - The action type of the event.
* @param attributes - The attributes to be added to the event.
* @returns - The event object.
*/
export const createJvbIceFailedEvent = ( action: unknown, attributes: object = {} ) => ( {
action,
attributes,
type: AnalyticsEvents.TYPE_OPERATIONAL,
} );

/**
* Creates an event related to remote participant connection status changes.
*
Expand Down

0 comments on commit efbc00c

Please sign in to comment.