Documentation Index
Fetch the complete documentation index at: https://mintlify.com/jitsi/lib-jitsi-meet/llms.txt
Use this file to discover all available pages before exploring further.
WebRTC Internals
lib-jitsi-meet provides enhanced WebRTC functionality through TraceablePeerConnection and RTCUtils, offering debugging capabilities, browser compatibility, and SDP manipulation.
TraceablePeerConnection
The TraceablePeerConnection class extends the standard RTCPeerConnection with enhanced debugging, logging, and state management.
Core Features
Enhanced Debugging
- Detailed trace logging for all peer connection events
- SDP dumping with
TraceablePeerConnection.dumpSDP()
- Stats collection and history tracking
- Update log for all state changes
Media Management
- Local and remote track lifecycle management
- SSRC mapping and tracking
- Simulcast and SVC support
- Codec preference handling
Creating a Peer Connection
const tpc = new TraceablePeerConnection(
rtc, // RTC service instance
id, // Peer connection ID
signalingLayer, // Signaling layer
pcConfig, // RTCConfiguration
constraints, // WebRTC constraints
isP2P, // P2P or JVB connection
options // TPC options
);
Source: modules/RTC/TraceablePeerConnection.ts:233-241
Configuration Options
interface ITPCOptions {
audioQuality: IAudioQuality; // Audio quality settings
capScreenshareBitrate: boolean; // Limit screenshare bitrate
codecSettings: ICodecSettings; // Codec preferences
disableRtx: boolean; // Disable RTX
disableSimulcast: boolean; // Disable simulcast
maxstats: number; // Stats history limit
startSilent: boolean; // Start without audio
usesCodecSelectionAPI: boolean; // Use codec selection API
videoQuality: IVideoQuality; // Video quality settings
}
Source: modules/RTC/TraceablePeerConnection.ts:85-95
Track Management
Local Tracks
- Stored in
localTracks Map indexed by rtcId
- SSRC info maintained in
localSSRCs Map
- Transceiver mapping via
localTrackTransceiverMids
Remote Tracks
- Indexed by SSRC in
remoteTracksBySsrc Map
- Organized by endpoint and media type in
remoteTracks Map
- Source name mapping in
remoteSources Map
Source: modules/RTC/TraceablePeerConnection.ts:314-364
SDP Handling
lib-jitsi-meet performs extensive SDP manipulation for simulcast, codec preferences, and browser compatibility.
SDP Munging
private _mungeDescription(description: RTCSessionDescription): RTCSessionDescription {
let mungedSdp = transform.parse(description?.sdp);
mungedSdp = this.tpcUtils.mungeOpus(mungedSdp); // Opus settings
mungedSdp = this.tpcUtils.mungeCodecOrder(mungedSdp); // Codec order
mungedSdp = this.tpcUtils.setMaxBitrates(mungedSdp); // Bitrate limits
return new RTCSessionDescription({
sdp: transform.write(mungedSdp),
type: description.type
});
}
Source: modules/RTC/TraceablePeerConnection.ts:877-892
Simulcast SDP Munging
For browsers using SDP-based simulcast (Chrome, Safari):
if (this.isSpatialScalabilityOn() && browser.usesSdpMungingForSimulcast()) {
resultSdp = this.simulcast.mungeLocalDescription(resultSdp);
}
Source: modules/RTC/TraceablePeerConnection.ts:1075-1080
RTX SSRC Modification
if (!this.options.disableRtx && browser.usesSdpMungingForSimulcast()) {
resultSdp = new RTCSessionDescription({
sdp: this.rtxModifier.modifyRtxSsrcs(resultSdp?.sdp),
type: resultSdp.type
});
}
Source: modules/RTC/TraceablePeerConnection.ts:1082-1088
Encoding Parameters
lib-jitsi-meet configures RTCRtpEncodingParameters for simulcast and quality control.
Configure Sender Encodings
private async _configureSenderEncodings(localTrack: JitsiLocalTrack): Promise<void> {
const transceiver = this.peerconnection.getTransceivers()
.find(t => t.sender?.track?.id === localTrack.getTrackId());
const parameters = transceiver?.sender?.getParameters();
if (!parameters?.encodings?.length) {
return;
}
parameters.encodings = this.tpcUtils.getStreamEncodings(localTrack);
await transceiver.sender.setParameters(parameters);
}
Source: modules/RTC/TraceablePeerConnection.ts:669-685
Video Sender Configuration
Dynamically adjust resolution, bitrate, and codec per encoding:
private _updateVideoSenderEncodings(
frameHeight: number,
localVideoTrack: JitsiLocalTrack,
preferredCodec: CodecMimeType
): Promise<void> {
const parameters = videoSender.getParameters();
// Calculate active state, bitrates, scale factors
const activeState = this.tpcUtils.calculateEncodingsActiveState(...);
const bitrates = this.tpcUtils.calculateEncodingsBitrates(...);
const scalabilityModes = this.tpcUtils.calculateEncodingsScalabilityMode(...);
const scaleFactors = this.tpcUtils.calculateEncodingsScaleFactor(...);
// Apply to encodings
for (const encoding of parameters.encodings) {
encoding.active = activeState[idx];
encoding.maxBitrate = bitrates[idx];
encoding.scaleResolutionDownBy = scaleFactors[idx];
encoding.scalabilityMode = scalabilityModes[idx];
// Codec selection API (Chrome 126+)
if (this.usesCodecSelectionAPI()) {
encoding.codec = matchingCodec;
}
}
return videoSender.setParameters(parameters);
}
Source: modules/RTC/TraceablePeerConnection.ts:923-1036
Chrome resets the transaction ID after setParameters(). Chain video sender updates to avoid conflicts:private _updateVideoSenderParameters(nextFunction: () => void): Promise<void> {
const nextPromise = this._lastVideoSenderUpdatePromise.finally(nextFunction);
this._lastVideoSenderUpdatePromise = nextPromise;
return nextPromise;
}
Source: modules/RTC/TraceablePeerConnection.ts:905-912
Codec Preferences
Using setCodecPreferences API
For browsers that support RTCRtpTransceiver.setCodecPreferences() (Chrome, Edge):
if (browser.supportsCodecPreferences() && this.codecSettings) {
const { codecList, mediaType } = this.codecSettings;
const transceivers = this.peerconnection.getTransceivers()
.filter(t => t.receiver?.track?.kind === mediaType);
let capabilities = RTCRtpReceiver.getCapabilities(mediaType)?.codecs;
// Rearrange codec list per preference order
for (const codec of codecList.slice().reverse()) {
capabilities.sort(caps =>
caps.mimeType.toLowerCase() === `${mediaType}/${codec}` ? -1 : 1
);
}
// Apply to all transceivers
for (const transceiver of transceivers) {
transceiver.setCodecPreferences(capabilities);
}
}
Source: modules/RTC/TraceablePeerConnection.ts:1116-1144
Codec Selection API (Chrome 126+)
Set codec per encoding without renegotiation:
if (this.usesCodecSelectionAPI()) {
const expectedPattern = `${MediaType.VIDEO}/${codec.toUpperCase()}`;
const matchingCodec = parameters.codecs.find(pt => pt.mimeType === expectedPattern);
encoding.codec = matchingCodec;
}
Source: modules/RTC/TraceablePeerConnection.ts:1007-1023
RTCUtils
The RTCUtils singleton handles browser compatibility, device enumeration, and media stream acquisition.
Initialization
RTCUtils.init({
disableAEC: false, // Acoustic Echo Cancellation
disableNS: false, // Noise Suppression
disableAGC: false, // Automatic Gain Control
disableAP: false, // All audio processing
audioQuality: {
stereo: false // Enable stereo audio
}
});
Source: modules/RTC/RTCUtils.js:274-294
Default Constraints
const DEFAULT_CONSTRAINTS = {
video: {
frameRate: { max: 30, min: 15 },
height: { ideal: 720, max: 720, min: 180 },
width: { ideal: 1280, max: 1280, min: 320 }
}
};
Source: modules/RTC/RTCUtils.js:28-45
Constraint Building
function getConstraints(um = [], options = {}) {
const constraints = cloneDeep(options.constraints || DEFAULT_CONSTRAINTS);
if (um.indexOf('video') >= 0) {
// Apply resolution shortcuts
if (Resolutions[options.resolution]) {
const r = Resolutions[options.resolution];
constraints.video.height = { ideal: r.height };
constraints.video.width = { ideal: r.width };
}
// WebKit workaround - use only ideal constraints
if (browser.isWebKitBased()) {
constraints.video.height = { ideal: constraints.video.height.ideal };
constraints.video.width = { ideal: constraints.video.width.ideal };
}
// Device selection
if (options.cameraDeviceId) {
constraints.video.deviceId = { exact: options.cameraDeviceId };
} else if (browser.isMobileDevice()) {
constraints.video.facingMode = options.facingMode || CameraFacingMode.USER;
}
}
// Audio constraints with processing flags
if (um.indexOf('audio') >= 0) {
constraints.audio = {
autoGainControl: !disableAGC && !disableAP,
echoCancellation: !disableAEC && !disableAP,
noiseSuppression: !disableNS && !disableAP
};
if (stereo) {
Object.assign(constraints.audio, { channelCount: 2 });
}
}
return constraints;
}
Source: modules/RTC/RTCUtils.js:95-183
Device Management
Device Enumeration
enumerateDevices(callback) {
navigator.mediaDevices.enumerateDevices()
.then(devices => {
this._updateKnownDevices(devices);
callback(devices);
})
.catch(error => {
logger.warn(`Failed to enumerate devices. ${error}`);
this._updateKnownDevices([]);
callback([]);
});
}
Source: modules/RTC/RTCUtils.js:372-383
Device Change Detection
- Modern browsers:
devicechange event listener
- Legacy browsers: 3-second polling interval
Source: modules/RTC/RTCUtils.js:318-328
_getUserMedia(umDevices, constraints = {}, timeout = 0) {
return new Promise((resolve, reject) => {
let gumTimeout, timeoutExpired = false;
if (isValidNumber(timeout) && timeout > 0) {
gumTimeout = setTimeout(() => {
timeoutExpired = true;
reject(new JitsiTrackError(JitsiTrackErrors.TIMEOUT));
}, timeout);
}
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => {
this._updateGrantedPermissions(umDevices, stream);
if (!timeoutExpired) {
clearTimeout(gumTimeout);
resolve(stream);
}
})
.catch(error => {
const jitsiError = new JitsiTrackError(error, constraints, umDevices);
if (!timeoutExpired) {
clearTimeout(gumTimeout);
reject(jitsiError);
}
});
});
}
Source: modules/RTC/RTCUtils.js:394-433
Audio Output Selection
setAudioOutputDevice(deviceId) {
if (!this.isDeviceChangeAvailable('output')) {
return Promise.reject(
new Error('Audio output device change is not supported')
);
}
return featureDetectionAudioEl.setSinkId(deviceId)
.then(() => {
audioOutputDeviceId = deviceId;
audioOutputChanged = true;
this.eventEmitter.emit(RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED, deviceId);
});
}
Source: modules/RTC/RTCUtils.js:836-852
Browser Compatibility
lib-jitsi-meet uses webrtc-adapter for cross-browser compatibility:
Source: modules/RTC/RTCUtils.js:3
Safari WebKit Bug WorkaroundOn macOS versions before Big Sur, Safari fails to start the camera if min/max constraints are specified. lib-jitsi-meet removes these constraints on WebKit-based browsers:if (browser.isWebKitBased()) {
if (constraints.video.height && constraints.video.height.ideal) {
constraints.video.height = { ideal: constraints.video.height.ideal };
}
if (constraints.video.width && constraints.video.width.ideal) {
constraints.video.width = { ideal: constraints.video.width.ideal };
}
}
See: https://bugs.webkit.org/show_bug.cgi?id=210932Source: modules/RTC/RTCUtils.js:120-131
Statistics Collection
TraceablePeerConnection maintains stats history for debugging.
Stats Interval
if (this.maxstats) {
this.statsinterval = window.setInterval(() => {
this.getStats().then((stats: StatsResponse) => {
// Process legacy or modern stats format
if (typeof (stats as ILegacyStatsResponse)?.result === 'function') {
const results = (stats as ILegacyStatsResponse).result();
for (const res of results) {
res.names().forEach(name => {
this._processStat(res, name, res.stat(name));
});
}
} else {
(stats as RTCStatsReport).forEach(r => this._processStat(r, '', r));
}
});
}, 1000);
}
Source: modules/RTC/TraceablePeerConnection.ts:587-605
Stat Processing
_processStat(report: RTCStats, name: string, statValue: any): void {
const id = `${report.id}-${name}`;
let s = this.stats[id];
const now = new Date();
if (!s) {
this.stats[id] = s = {
endTime: now,
startTime: now,
times: [],
values: []
};
}
s.values.push(statValue);
s.times.push(now.getTime());
if (s.values.length > this.maxstats) {
s.values.shift();
s.times.shift();
}
s.endTime = now;
}
Source: modules/RTC/TraceablePeerConnection.ts:1223-1243
Next Steps