chore: add forceRelayOnFirefox option (false by default)

- forceRelayOnFirefox: whether TURN/relay usage should be forced to work
around Firefox's lack of support for regular nomination when dealing with
ICE-litee peers (e.g.: mediasoup).
  * See: https://bugzilla.mozilla.org/show_bug.cgi?id=1034964
- iOS endpoints are ignored from the trigger because _all_ iOS browsers
  are either native WebKit or WKWebView based (so they shouldn't be affected)
This commit is contained in:
prlanzarin 2021-11-30 20:31:09 +00:00
parent f8034b8e04
commit da6ab02122
8 changed files with 52 additions and 11 deletions

View File

@ -8,6 +8,7 @@ import {
getMappedFallbackStun getMappedFallbackStun
} from '/imports/utils/fetchStunTurnServers'; } from '/imports/utils/fetchStunTurnServers';
import getFromMeetingSettings from '/imports/ui/services/meeting-settings'; import getFromMeetingSettings from '/imports/ui/services/meeting-settings';
import { shouldForceRelay } from '/imports/ui/services/bbb-webrtc-sfu/utils';
const SFU_URL = Meteor.settings.public.kurento.wsUrl; const SFU_URL = Meteor.settings.public.kurento.wsUrl;
const DEFAULT_LISTENONLY_MEDIA_SERVER = Meteor.settings.public.kurento.listenOnlyMediaServer; const DEFAULT_LISTENONLY_MEDIA_SERVER = Meteor.settings.public.kurento.listenOnlyMediaServer;
@ -267,6 +268,7 @@ export default class KurentoAudioBridge extends BaseAudioBridge {
offering: OFFERING, offering: OFFERING,
mediaServer: getMediaServerAdapter(), mediaServer: getMediaServerAdapter(),
signalCandidates: SIGNAL_CANDIDATES, signalCandidates: SIGNAL_CANDIDATES,
forceRelay: shouldForceRelay(),
}; };
this.broker = new ListenOnlyBroker( this.broker = new ListenOnlyBroker(

View File

@ -4,6 +4,7 @@ import BridgeService from './service';
import ScreenshareBroker from '/imports/ui/services/bbb-webrtc-sfu/screenshare-broker'; import ScreenshareBroker from '/imports/ui/services/bbb-webrtc-sfu/screenshare-broker';
import { setSharingScreen, screenShareEndAlert } from '/imports/ui/components/screenshare/service'; import { setSharingScreen, screenShareEndAlert } from '/imports/ui/components/screenshare/service';
import { SCREENSHARING_ERRORS } from './errors'; import { SCREENSHARING_ERRORS } from './errors';
import { shouldForceRelay } from '/imports/ui/services/bbb-webrtc-sfu/utils';
const SFU_CONFIG = Meteor.settings.public.kurento; const SFU_CONFIG = Meteor.settings.public.kurento;
const SFU_URL = SFU_CONFIG.wsUrl; const SFU_URL = SFU_CONFIG.wsUrl;
@ -227,6 +228,7 @@ export default class KurentoScreenshareBridge {
offering: OFFERING, offering: OFFERING,
mediaServer: BridgeService.getMediaServerAdapter(), mediaServer: BridgeService.getMediaServerAdapter(),
signalCandidates: SIGNAL_CANDIDATES, signalCandidates: SIGNAL_CANDIDATES,
forceRelay: shouldForceRelay(),
}; };
this.broker = new ScreenshareBroker( this.broker = new ScreenshareBroker(
@ -287,6 +289,7 @@ export default class KurentoScreenshareBridge {
offering: true, offering: true,
mediaServer: BridgeService.getMediaServerAdapter(), mediaServer: BridgeService.getMediaServerAdapter(),
signalCandidates: SIGNAL_CANDIDATES, signalCandidates: SIGNAL_CANDIDATES,
forceRelay: shouldForceRelay(),
}; };
this.broker = new ScreenshareBroker( this.broker = new ScreenshareBroker(

View File

@ -19,6 +19,7 @@ import {
getSessionVirtualBackgroundInfo, getSessionVirtualBackgroundInfo,
} from '/imports/ui/services/virtual-background/service'; } from '/imports/ui/services/virtual-background/service';
import { notify } from '/imports/ui/services/notification'; import { notify } from '/imports/ui/services/notification';
import { shouldForceRelay } from '/imports/ui/services/bbb-webrtc-sfu/utils';
// Default values and default empty object to be backwards compat with 2.2. // Default values and default empty object to be backwards compat with 2.2.
// FIXME Remove hardcoded defaults 2.3. // FIXME Remove hardcoded defaults 2.3.
@ -605,6 +606,9 @@ class VideoProvider extends Component {
video: constraints, video: constraints,
}, },
onicecandidate: this._getOnIceCandidateCallback(stream, isLocal), onicecandidate: this._getOnIceCandidateCallback(stream, isLocal),
configuration: {
iceTransportPolicy: shouldForceRelay() ? 'relay' : undefined,
}
}; };
try { try {
@ -623,7 +627,6 @@ class VideoProvider extends Component {
iceServers = getMappedFallbackStun(); iceServers = getMappedFallbackStun();
} finally { } finally {
if (iceServers.length > 0) { if (iceServers.length > 0) {
peerOptions.configuration = {};
peerOptions.configuration.iceServers = iceServers; peerOptions.configuration.iceServers = iceServers;
} }

View File

@ -34,10 +34,9 @@ class ListenOnlyBroker extends BaseBroker {
video: false, video: false,
}, },
onicecandidate: this.signalCandidates ? this.onIceCandidate.bind(this) : null, onicecandidate: this.signalCandidates ? this.onIceCandidate.bind(this) : null,
configuration: this.populatePeerConfiguration(),
}; };
this.addIceServers(options);
this.webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly(options, (error) => { this.webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly(options, (error) => {
if (error) { if (error) {
// 1305: "PEER_NEGOTIATION_FAILED", // 1305: "PEER_NEGOTIATION_FAILED",

View File

@ -157,9 +157,9 @@ class ScreenshareBroker extends BaseBroker {
const options = { const options = {
onicecandidate: this.signalCandidates ? this.onIceCandidate.bind(this) : null, onicecandidate: this.signalCandidates ? this.onIceCandidate.bind(this) : null,
videoStream: this.stream, videoStream: this.stream,
configuration: this.populatePeerConfiguration(),
}; };
this.addIceServers(options);
this.webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerSendonly(options, (error) => { this.webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerSendonly(options, (error) => {
if (error) { if (error) {
// 1305: "PEER_NEGOTIATION_FAILED", // 1305: "PEER_NEGOTIATION_FAILED",
@ -226,10 +226,9 @@ class ScreenshareBroker extends BaseBroker {
audio: !!this.hasAudio, audio: !!this.hasAudio,
}, },
onicecandidate: this.signalCandidates ? this.onIceCandidate.bind(this) : null, onicecandidate: this.signalCandidates ? this.onIceCandidate.bind(this) : null,
configuration: this.populatePeerConfiguration(),
}; };
this.addIceServers(options);
this.webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly(options, (error) => { this.webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly(options, (error) => {
if (error) { if (error) {
// 1305: "PEER_NEGOTIATION_FAILED", // 1305: "PEER_NEGOTIATION_FAILED",

View File

@ -25,6 +25,7 @@ class BaseBroker {
this.started = false; this.started = false;
this.signallingTransportOpen = false; this.signallingTransportOpen = false;
this.logCodePrefix = `${this.sfuComponent}_broker`; this.logCodePrefix = `${this.sfuComponent}_broker`;
this.peerConfiguration = {};
this.onbeforeunload = this.onbeforeunload.bind(this); this.onbeforeunload = this.onbeforeunload.bind(this);
window.addEventListener('beforeunload', this.onbeforeunload); window.addEventListener('beforeunload', this.onbeforeunload);
@ -168,13 +169,23 @@ class BaseBroker {
} }
} }
addIceServers (options) { populatePeerConfiguration () {
if (this.iceServers && this.iceServers.length > 0) { this.addIceServers();
options.configuration = {}; if (this.forceRelay) {
options.configuration.iceServers = this.iceServers; this.setRelayTransportPolicy();
} }
return options; return this.peerConfiguration;
}
addIceServers () {
if (this.iceServers && this.iceServers.length > 0) {
this.peerConfiguration.iceServers = this.iceServers;
}
}
setRelayTransportPolicy () {
this.peerConfiguration.iceTransportPolicy = 'relay';
} }
handleConnectionStateChange (eventIdentifier) { handleConnectionStateChange (eventIdentifier) {

View File

@ -0,0 +1,23 @@
import browserInfo from '/imports/utils/browserInfo';
import deviceInfo from '/imports/utils/deviceInfo';
const FORCE_RELAY_ON_FF = Meteor.settings.public.kurento.forceRelayOnFirefox;
/*
* Whether TURN/relay usage should be forced to work around Firefox's lack of
* support for regular nomination when dealing with ICE-litee peers (e.g.:
* mediasoup). See: https://bugzilla.mozilla.org/show_bug.cgi?id=1034964
*
* iOS endpoints are ignored from the trigger because _all_ iOS browsers
* are either native WebKit or WKWebView based (so they shouldn't be affected)
*/
const shouldForceRelay = () => {
const { isFirefox } = browserInfo;
const { isIos } = deviceInfo;
return (isFirefox && !isIos) && FORCE_RELAY_ON_FF;
};
export {
shouldForceRelay,
};

View File

@ -200,6 +200,7 @@ public:
# Experiment(al). Controls whether ICE candidates should be signaled. # Experiment(al). Controls whether ICE candidates should be signaled.
# Applies to webcams, listen only and screen sharing. True is "stable behavior". # Applies to webcams, listen only and screen sharing. True is "stable behavior".
signalCandidates: true signalCandidates: true
forceRelayOnFirefox: false
cameraTimeouts: cameraTimeouts:
# Base camera timeout: used as the camera *sharing* timeout and # Base camera timeout: used as the camera *sharing* timeout and
# as the minimum camera subscribe reconnection timeout # as the minimum camera subscribe reconnection timeout