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.
Browser Compatibility
lib-jitsi-meet uses the BrowserCapabilities class for browser detection and feature support checking, along with webrtc-adapter for polyfills.
BrowserCapabilities Class
Extends BrowserDetection from @jitsi/js-utils with lib-jitsi-meet-specific capabilities.
import BrowserDetection from '@jitsi/js-utils/browser-detection/BrowserDetection';
export default class BrowserCapabilities extends BrowserDetection {
// lib-jitsi-meet specific methods
}
Source: modules/browser/BrowserCapabilities.ts:1, 22
Minimum Browser Versions
const MIN_REQUIRED_CHROME_VERSION = 72;
const MIN_REQUIRED_FIREFOX_VERSION = 91;
const MIN_REQUIRED_SAFARI_VERSION = 14;
const MIN_REQUIRED_IOS_VERSION = 14;
Source: modules/browser/BrowserCapabilities.ts:4-7
Version Detection
Safari Version
_getSafariVersion(): number {
if (this.isSafari()) {
return Number.parseInt(this.getVersion(), 10);
}
return -1;
}
Source: modules/browser/BrowserCapabilities.ts:41-47
iOS Version
_getIOSVersion(): number {
if (this.isWebKitBased()) {
return Number.parseInt(this.getOSVersion(), 10);
}
return -1;
}
Source: modules/browser/BrowserCapabilities.ts:28-34
Browser Support Checks
Overall Support
isSupported(): boolean {
// Check for WebRTC APIs (some security extensions disable them)
if (typeof RTCPeerConnection === 'undefined'
|| !navigator?.mediaDevices?.enumerateDevices
|| !navigator?.mediaDevices?.getUserMedia) {
return false;
}
if (this.isSafari() && this._getSafariVersion() < MIN_REQUIRED_SAFARI_VERSION) {
return false;
}
return (this.isChromiumBased() && this.isEngineVersionGreaterThan(MIN_REQUIRED_CHROME_VERSION - 1))
|| (this.isFirefox() && this.isVersionGreaterThan(MIN_REQUIRED_FIREFOX_VERSION - 1))
|| this.isReactNative()
|| this.isWebKitBased();
}
Source: modules/browser/BrowserCapabilities.ts:101-116
Android
isSupportedAndroidBrowser(): boolean {
return this.isChromiumBased() || this.isFirefox();
}
Source: modules/browser/BrowserCapabilities.ts:123-125
iOS
isSupportedIOSBrowser(): boolean {
// After iPadOS 13, UA string conceals version and pretends to be macOS 10.15.7
if (!this.isSafari() && this.isWebKitBased() && this.getOSVersion() === FROZEN_MACOS_VERSION) {
return true;
}
return this._getSafariVersion() >= MIN_REQUIRED_IOS_VERSION
|| this._getIOSVersion() >= MIN_REQUIRED_IOS_VERSION;
}
The iPad detection workaround is necessary because iPadOS 13+ masquerades as macOS in the user agent.
Source: modules/browser/BrowserCapabilities.ts:10-11, 132-140
Mobile Detection
isMobileDevice(): boolean {
return this.isAndroidBrowser() || this.isIosBrowser() || this.isReactNative();
}
isAndroidBrowser(): boolean {
return !this.isReactNative() && this.getOS() === 'Android';
}
isIosBrowser(): boolean {
return !this.isReactNative() && this.getOS() === 'iOS';
}
Source: modules/browser/BrowserCapabilities.ts:83-85, 65-67, 74-76
Trusted Web App Detection
isTwa(): boolean {
return 'matchMedia' in window && window.matchMedia('(display-mode:standalone)').matches;
}
Detects if running as a Trusted Web App (Android).
Source: modules/browser/BrowserCapabilities.ts:92-94
Codec Support
setCodecPreferences API
supportsCodecPreferences(): boolean {
return Boolean('setCodecPreferences' in window.RTCRtpTransceiver?.prototype
&& typeof window.RTCRtpReceiver?.getCapabilities !== 'undefined')
// Safari bug: https://bugs.webkit.org/show_bug.cgi?id=215567
&& !this.isWebKitBased()
// Firefox freeze bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1917800
&& !this.isFirefox();
}
Source: modules/browser/BrowserCapabilities.ts:178-189
Codec Selection API
supportsCodecSelectionAPI(): boolean {
return this.isChromiumBased() && this.isEngineVersionGreaterThan(125);
}
Chrome 126+ supports changing codecs on encodings without renegotiation.
Source: modules/browser/BrowserCapabilities.ts:199-201
VP9 Support
supportsVP9(): boolean {
// Disabled on Firefox (simulcast disabled by default)
// Disabled on Safari (decoder/encoder issues)
return !(this.isWebKitBased() || this.isFirefox());
}
See: https://bugs.webkit.org/show_bug.cgi?id=231074
Source: modules/browser/BrowserCapabilities.ts:276-281
SVC Support
supportsSVC(): boolean {
return !this.isFirefox();
}
Scalable Video Coding is supported on all browsers except Firefox.
Source: modules/browser/BrowserCapabilities.ts:288-290
Simulcast
SDP Munging for Simulcast
usesSdpMungingForSimulcast(): boolean {
return this.isChromiumBased() || this.isReactNative() || this.isWebKitBased();
}
Chrome, Safari, and React Native use SDP munging. Firefox uses RIDs/MIDs.
Source: modules/browser/BrowserCapabilities.ts:297-299
RIDs for Simulcast
usesRidsForSimulcast(): boolean {
return false; // Currently unused
}
Source: modules/browser/BrowserCapabilities.ts:307-309
Scalability Mode API
supportsScalabilityModeAPI(): boolean {
return this.isChromiumBased() && this.isEngineVersionGreaterThan(112);
}
Chrome 113+ supports the Scalability Mode API for VP9/AV1 simulcast and full SVC.
Source: modules/browser/BrowserCapabilities.ts:255-257
E2EE Support
Insertable Streams
supportsInsertableStreams(): boolean {
if (!window.RTCRtpSender?.prototype.createEncodedStreams) {
return false;
}
// Feature-detect transferable streams (needed for worker)
const stream = new ReadableStream();
try {
window.postMessage(stream, '*', [ stream ]);
return true;
} catch {
return false;
}
}
Source: modules/browser/BrowserCapabilities.ts:340-357
supportsEncodedTransform(): boolean {
return Boolean(window.RTCRtpScriptTransform);
}
Alternative to insertable streams, currently Safari/WebKit behind a flag.
Source: modules/browser/BrowserCapabilities.ts:331-333
supportsAudioRed(): boolean {
return Boolean(
window.RTCRtpSender?.getCapabilities('audio')?.codecs
.some(codec => codec.mimeType === 'audio/red')
&& window.RTCRtpReceiver?.getCapabilities('audio')?.codecs
.some(codec => codec.mimeType === 'audio/red')
);
}
Source: modules/browser/BrowserCapabilities.ts:364-367
Statistics Support
Bandwidth Statistics
supportsBandwidthStatistics(): boolean {
// Not implemented for Firefox or Safari on lib-jitsi-meet side
return !this.isFirefox() && !this.isWebKitBased();
}
Source: modules/browser/BrowserCapabilities.ts:167-171
RTT Statistics
supportsRTTStatistics(): boolean {
// Firefox doesn't report RTT for ICE candidate pairs
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1241066
return !this.isFirefox();
}
Source: modules/browser/BrowserCapabilities.ts:236-246
Receiver Stats
supportsReceiverStats(): boolean {
return typeof window.RTCRtpReceiver !== 'undefined'
&& Object.keys(RTCRtpReceiver.prototype).indexOf('getSynchronizationSources') > -1;
}
Source: modules/browser/BrowserCapabilities.ts:226-229
Track-Based Stats
supportsTrackBasedStats(): boolean {
return this.isChromiumBased() && this.isEngineVersionLessThan(112);
}
Older Chrome versions (< 112) support track-based statistics for resolution/framerate.
Source: modules/browser/BrowserCapabilities.ts:265-267
supportsGetDisplayMedia(): boolean {
return typeof navigator.getDisplayMedia !== 'undefined'
|| (typeof navigator.mediaDevices?.getDisplayMedia !== 'undefined');
}
Source: modules/browser/BrowserCapabilities.ts:316-320
Device Change Events
supportsDeviceChangeEvent(): boolean {
return typeof navigator.mediaDevices?.ondevicechange !== 'undefined'
&& typeof navigator.mediaDevices?.addEventListener !== 'undefined';
}
Source: modules/browser/BrowserCapabilities.ts:216-219
Video Mute Strategy
doesVideoMuteByStreamRemove(): boolean {
return this.isChromiumBased() || this.isWebKitBased() || this.isFirefox();
}
On Firefox, the MediaStream is removed from PeerConnection on mute to turn off camera. See: https://bugzilla.mozilla.org/show_bug.cgi?id=1735951
Source: modules/browser/BrowserCapabilities.ts:56-58
Video Mute Events
supportsVideoMuteOnConnInterrupted(): any | boolean {
return this.isChromiumBased() || this.isReactNative();
}
Chrome and React Native fire ‘onmute’/‘onunmute’ events when connection is interrupted.
Source: modules/browser/BrowserCapabilities.ts:158-160
Browser-Specific Features
User Interaction for Unmute
isUserInteractionRequiredForUnmute(): boolean {
return this.isFirefox() && this.isVersionLessThan(68);
}
Older Firefox versions require user interaction before unmute.
Source: modules/browser/BrowserCapabilities.ts:148-150
RTX Support
supportsRTX(): boolean {
// Disable RTX on Firefox < 96 (prefer simulcast)
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1738504
return !(this.isFirefox() && this.isVersionLessThan(96));
}
Source: modules/browser/BrowserCapabilities.ts:383-387
supportsDDExtHeaders(): boolean {
return !(this.isFirefox() && this.isVersionLessThan(136));
}
Firefox 136+ supports Dependency Descriptor RTP header extension.
Source: modules/browser/BrowserCapabilities.ts:208-210
Voice Activity Detection
supportsVADDetection(): boolean {
return this.isChromiumBased();
}
VADAudioAnalyser service is only supported on Chromium-based browsers.
Source: modules/browser/BrowserCapabilities.ts:374-376
webrtc-adapter Integration
lib-jitsi-meet uses webrtc-adapter for WebRTC API polyfills:
This provides:
- Unified WebRTC API across browsers
- getUserMedia polyfill
- RTCPeerConnection shims
- Browser compatibility fixes
Source: modules/RTC/RTCUtils.js:3, CLAUDE.md:53
Usage Pattern
import browser from '../browser';
// Check feature support
if (browser.supportsCodecPreferences()) {
// Use setCodecPreferences API
transceiver.setCodecPreferences(capabilities);
} else {
// Fallback to SDP munging
mungedSdp = mungeCodecOrder(sdp);
}
// Platform-specific logic
if (browser.isMobileDevice()) {
// Use mobile-optimized settings
codecOrder = MOBILE_VIDEO_CODEC_ORDER;
} else {
codecOrder = DESKTOP_VIDEO_CODEC_ORDER;
}
// Browser-specific workarounds
if (browser.isWebKitBased()) {
// Safari bug workaround
constraints.video.height = { ideal: height };
constraints.video.width = { ideal: width };
}
Common Compatibility Checks
Before Using APIs
// Codec selection
if (browser.supportsCodecPreferences() && !browser.isWebKitBased()) {
// Chrome/Edge only
}
if (browser.supportsCodecSelectionAPI()) {
// Chrome 126+ only
}
// E2EE
if (browser.supportsInsertableStreams() || browser.supportsEncodedTransform()) {
// Enable E2EE
}
// Screen sharing
if (browser.supportsGetDisplayMedia()) {
// Use getDisplayMedia
} else {
// Fallback to extension or error
}
// Statistics
if (browser.supportsReceiverStats()) {
receiver.getSynchronizationSources();
}
if (browser.isMobileDevice()) {
if (browser.isAndroidBrowser()) {
// Android-specific
if (browser.isSupportedAndroidBrowser()) {
// Chrome or Firefox on Android
}
} else if (browser.isIosBrowser()) {
// iOS-specific
if (browser.isSupportedIOSBrowser()) {
// iOS 14+ Safari or WKWebView
}
}
}
iPad Detection IssueStarting with iPadOS 13, Safari pretends to be macOS 10.15.7 in the user agent:const FROZEN_MACOS_VERSION = '10.15.7';
if (!this.isSafari() && this.isWebKitBased()
&& this.getOSVersion() === FROZEN_MACOS_VERSION) {
// Likely an iPad
return true;
}
This workaround is necessary for proper iPad detection.Source: modules/browser/BrowserCapabilities.ts:10-11, 134-136
Best Practices
-
Always check feature support: Don’t assume APIs exist
if (browser.supportsCodecPreferences()) {
// Use API
}
-
Use platform detection for optimization: Different defaults for mobile
const codecOrder = browser.isMobileDevice()
? MOBILE_VIDEO_CODEC_ORDER
: DESKTOP_VIDEO_CODEC_ORDER;
-
Handle browser bugs: Apply workarounds where necessary
if (browser.isWebKitBased()) {
// Safari-specific workaround
}
-
Graceful degradation: Provide fallbacks for unsupported features
if (!browser.supportsGetDisplayMedia()) {
// Show extension installation prompt or disable screenshare
}
-
Check minimum versions: Block unsupported browsers early
if (!browser.isSupported()) {
// Show unsupported browser message
}
Next Steps