Skip to main content

Network Optimization

lib-jitsi-meet implements robust network handling including ICE connection management, network quality monitoring, and automatic recovery mechanisms.

ICE Failed Handling

The IceFailedHandling class manages recovery from ICE connection failures on the JVB media session.

Architecture

export default class IceFailedHandling {
    private _conference: JitsiConference;
    private _canceled: boolean = false;
    private _iceFailedTimeout?: number;
    
    constructor(conference: JitsiConference) {
        this._conference = conference;
    }
}
Source: modules/connectivity/IceFailedHandling.ts:16-27

Recovery Strategy

When ICE fails, lib-jitsi-meet:
  1. Pings XMPP server to verify internet connectivity (65s timeout)
  2. Waits 2 seconds for ICE to recover
  3. If still failed, sends session-terminate to Jicofo
  4. Jicofo re-invites the participant to recreate the session
Source: modules/connectivity/IceFailedHandling.ts:10-14

Implementation

Starting Recovery
start(): void {
    // Using xmpp.ping handles both XMPP disconnection and internet offline cases.
    // sendIQ2 waits patiently for reconnection.
    // 
    // 65 second timeout: no chance for XMPP to recover after 65s of no communication.
    // Resume attempts will fail with 'item-not-found' error.
    this._conference.xmpp.ping(65000).then(
        () => {
            if (!this._canceled) {
                // Wait 2 seconds for ICE to recover after internet comes back
                this._iceFailedTimeout = window.setTimeout(() => {
                    this._iceFailedTimeout = undefined;
                    this._actOnIceFailed();
                }, 2000);
            }
        },
        error => {
            logger.error('PING error/timeout - not sending ICE failed', error);
        }
    );
}
Source: modules/connectivity/IceFailedHandling.ts:63-85 Taking Action on Failure
private _actOnIceFailed(): void {
    if (!this._conference.room) {
        return;
    }
    
    const jvbConnection = this._conference.jvbJingleSession;
    const jvbConnIceState = jvbConnection?.getIceConnectionState();
    
    if (!jvbConnection) {
        logger.warn('Not sending ICE failed - no JVB connection');
    } else if (jvbConnIceState === 'connected') {
        logger.info('ICE connection restored - not sending ICE failed');
    } else {
        logger.info(`Sending ICE failed - connection did not recover, ICE state: ${jvbConnIceState}`);
        RTCStats.sendStatsEntry(RTCStatsEvents.JVB_ICE_RESTARTED_EVENT);
        this._conference._stopJvbSession({
            reason: 'connectivity-error',
            reasonDescription: 'ICE FAILED',
            requestRestart: true,
            sendSessionTerminate: true
        });
    }
}
Source: modules/connectivity/IceFailedHandling.ts:35-57 Canceling Recovery
cancel(): void {
    this._canceled = true;
    window.clearTimeout(this._iceFailedTimeout);
}
Source: modules/connectivity/IceFailedHandling.ts:91-94
65 Second XMPP TimeoutThe 65-second ping timeout is intentional. XMPP cannot recover after 65 seconds without server communication - the server will reject resume attempts with item-not-found error.Do not reduce this timeout or recovery may fail.Source: modules/connectivity/IceFailedHandling.ts:70-72

Network Info Module

The NetworkInfo module tracks online/offline internet status.

Architecture

export interface ICurrentNetworkInfo {
    isOnline: boolean;
}

export class NetworkInfo extends Listenable {
    private _current: ICurrentNetworkInfo;
    
    constructor() {
        super();
        this._current = {
            isOnline: true  // Default to online
        };
    }
}
Source: modules/connectivity/NetworkInfo.ts:9-31

Usage

Updating Network Status
updateNetworkInfo({ isOnline }: { isOnline: boolean; }): void {
    logger.debug('updateNetworkInfo', { isOnline });
    this._current = {
        isOnline: isOnline === true
    };
    this.eventEmitter.emit(NETWORK_INFO_EVENT, this._current);
}
Source: modules/connectivity/NetworkInfo.ts:40-46 Checking Online Status
isOnline(): boolean {
    return this._current.isOnline === true;
}
Source: modules/connectivity/NetworkInfo.ts:55-57

Integration

Applications using lib-jitsi-meet should wire network status:
import { JitsiMeetJS } from 'lib-jitsi-meet';

// Browser API
window.addEventListener('online', () => {
    JitsiMeetJS.setNetworkInfo({ isOnline: true });
});

window.addEventListener('offline', () => {
    JitsiMeetJS.setNetworkInfo({ isOnline: false });
});

// React Native NetInfo
import NetInfo from '@react-native-community/netinfo';

NetInfo.addEventListener(state => {
    JitsiMeetJS.setNetworkInfo({ isOnline: state.isConnected });
});
Source: modules/connectivity/NetworkInfo.ts:14-18
Default is OnlineBy default, lib-jitsi-meet assumes the network is online:
this._current = {
    isOnline: true
};
Applications must wire the network status for lib-jitsi-meet to properly handle offline scenarios. Without this, operations will fail gracefully but without optimization.Source: modules/connectivity/NetworkInfo.ts:28-30, 48-56

Connection Quality

The ConnectionQuality module monitors connection quality based on RTCStats.

Module Structure

Source: modules/connectivity/ directory Available Modules:
  • IceFailedHandling.ts - ICE failure recovery
  • NetworkInfo.ts - Online/offline tracking
  • ConnectionQuality.ts - Quality monitoring
  • TrackStreamingStatus.ts - Track streaming state

ICE Connection States

lib-jitsi-meet normalizes ICE connection states across browsers:
getConnectionState(): RTCIceConnectionState {
    const state = this.peerconnection.iceConnectionState;
    
    // Normalize 'completed' to 'connected'
    if (state === 'completed') {
        return 'connected';
    }
    
    return state;
}
The P2P connection may report “completed” state, but this is normalized to “connected” for consistency. Source: modules/RTC/TraceablePeerConnection.ts:1254-1262

ICE State Transitions

new → checking → connected → completed

             failed → disconnected → closed
Key States:
  • new: ICE agent gathering addresses
  • checking: ICE agent checking pairs
  • connected: ICE agent found working connection
  • completed: ICE agent finished (normalized to connected)
  • failed: ICE agent exhausted all candidates
  • disconnected: ICE agent lost connection
  • closed: ICE agent shut down

DTLS Transport

lib-jitsi-meet monitors the DTLS transport for the peer connection:
private _initializeDtlsTransport(): void {
    // Assume single bundled transport
    if (!this.peerconnection.getSenders || this._dtlsTransport) {
        return;
    }
    
    const senders = this.peerconnection.getSenders();
    
    if (senders.length !== 0 && senders[0].transport) {
        this._dtlsTransport = senders[0].transport;
        
        this._dtlsTransport.onerror = error => {
            logger.error(`${this} DtlsTransport error: ${error}`);
        };
        
        this._dtlsTransport.onstatechange = () => {
            this.trace('dtlsTransport.onstatechange', this._dtlsTransport.state);
        };
    }
}
All streams are bundled on a single transport for efficiency. Source: modules/RTC/TraceablePeerConnection.ts:834-853

ICE Configuration

lib-jitsi-meet supports separate ICE configurations for JVB and P2P:
const iceConfig = {
    jvb: {
        iceServers: [
            { urls: 'stun:stun.example.com:3478' },
            {
                urls: 'turn:turn.example.com:3478',
                username: 'user',
                credential: 'pass'
            }
        ],
        iceTransportPolicy: 'all'  // or 'relay' to force TURN
    },
    p2p: {
        iceServers: [
            { urls: 'stun:stun.example.com:3478' }
        ],
        iceTransportPolicy: 'all'
    }
};
Source: CLAUDE.md:94

Force TURN Relay

const options = {
    // ...
    forceTurnRelay: true  // Generate only relay candidates
};
When enabled, the browser will only generate relay (TURN) candidates, ensuring all traffic goes through the TURN server. Source: modules/RTC/TraceablePeerConnection.ts:223

Network Resilience Best Practices

1. Monitor ICE State

pc.peerconnection.oniceconnectionstatechange = event => {
    const state = pc.getConnectionState();
    logger.info('ICE connection state:', state);
    
    if (state === 'failed') {
        // Start recovery process
        iceFailedHandling.start();
    } else if (state === 'connected') {
        // Cancel recovery if recovering
        iceFailedHandling.cancel();
    }
};

2. Wire Network Status

// Browser
window.addEventListener('online', () => {
    JitsiMeetJS.setNetworkInfo({ isOnline: true });
});

window.addEventListener('offline', () => {
    JitsiMeetJS.setNetworkInfo({ isOnline: false });
    
    // Pause operations while offline
    conference.pauseParticipantStats();
});

3. Handle Reconnection

room.on(JitsiConferenceEvents.CONNECTION_RESTORED, () => {
    logger.info('Connection restored');
    // Resume operations
});

room.on(JitsiConferenceEvents.CONNECTION_INTERRUPTED, () => {
    logger.warn('Connection interrupted');
    // Show warning to user
});

4. Use Adaptive Bitrate

// Let lib-jitsi-meet adapt to network conditions
conference.setReceiverConstraints({
    lastN: 5,          // Receive video from 5 participants
    selectedSources: [], // Auto-select based on quality
    onStageEndpoints: ['endpoint1'],
    defaultConstraints: { maxHeight: 720 },
    constraints: {
        'endpoint1': { maxHeight: 1080 }  // High quality for on-stage
    }
});

5. Monitor Statistics

conference.on(JitsiConferenceEvents.CONNECTION_STATS, stats => {
    const { bitrate, packetLoss, jitter } = stats;
    
    if (packetLoss.upload > 10) {
        logger.warn('High packet loss:', packetLoss.upload);
        // Reduce quality or notify user
    }
    
    if (bitrate.download < 500000) {
        logger.warn('Low bandwidth:', bitrate.download);
        // Reduce lastN or resolution
    }
});

RTCStats Integration

lib-jitsi-meet sends analytics events to rtcstats:
RTCStats.sendStatsEntry(RTCStatsEvents.JVB_ICE_RESTARTED_EVENT);
This tracks ICE restarts for monitoring and debugging. Source: modules/connectivity/IceFailedHandling.ts:4-5, 49

Connectivity Modules

Other connectivity-related modules:

TrackStreamingStatus

Monitors whether tracks are actively streaming:
  • Tracks interruptions
  • Detects playback issues
  • Manages buffer state

ConnectionQuality

Calculates connection quality score:
  • Based on RTCStats metrics
  • Packet loss, jitter, RTT
  • Audio/video quality indicators
Source: modules/connectivity/ directory

Network Diagnostics

Enable Detailed Logging

import { setLogLevel } from '@jitsi/logger';

setLogLevel('connectivity:IceFailedHandling', 'debug');
setLogLevel('connectivity:NetworkInfo', 'debug');

Trace ICE Candidates

pc.peerconnection.onicecandidate = event => {
    if (event.candidate) {
        logger.debug('ICE candidate:', event.candidate.candidate);
    } else {
        logger.debug('ICE gathering complete');
    }
};

Monitor DTLS State

if (pc._dtlsTransport) {
    pc._dtlsTransport.onstatechange = () => {
        logger.debug('DTLS state:', pc._dtlsTransport.state);
    };
}

Performance Optimization

Reduce Signaling Overhead

  • Use JSON message encoding for large conferences
  • Batch source updates
  • Minimize presence updates

Optimize ICE Gathering

const pcConfig = {
    iceServers: [...],
    iceCandidatePoolSize: 10,  // Pre-gather candidates
    bundlePolicy: 'max-bundle', // Bundle all media
    rtcpMuxPolicy: 'require'    // Multiplex RTCP
};

Enable ICE Restart

conference.on(JitsiConferenceEvents.ICE_CONNECTION_STATE_CHANGED, (state) => {
    if (state === 'failed') {
        // Automatic restart via IceFailedHandling
        // Or manual restart:
        // conference.restartJvbSession();
    }
});

Next Steps

Build docs developers (and LLMs) love