bigbluebutton-Github/bigbluebutton-html5/imports/utils/fetchStunTurnServers.js
prlanzarin 2cba85e866 html5: refactor STUN/TURN fetch, add fallback STUN, fix deadlock in audio join
Refactored STUN/TURN fetch to be done only once, when successful, per session and cache it in mem to avoid too many reqs. Current way is a bit dumb, this should increase reliability a bit more. The caching is configurable so folks who want to use very short lived TURN credentials can disable it

Add a fallback STUN config option to be used when the default STUN/TURN fetch fails

Clean the safari/no candidate generation pre flight check from 3rd party STUNs

Fix deadlock in audio join when STUN/TURN fetch failed
2020-05-21 04:35:17 +00:00

83 lines
2.2 KiB
JavaScript

import _ from 'lodash';
const MEDIA = Meteor.settings.public.media;
const STUN_TURN_FETCH_URL = MEDIA.stunTurnServersFetchAddress;
const CACHE_STUN_TURN = MEDIA.cacheStunTurnServers;
const FALLBACK_STUN_SERVER = MEDIA.fallbackStunServer;
let STUN_TURN_DICT;
let MAPPED_STUN_TURN_DICT;
const fetchStunTurnServers = function (sessionToken) {
if (STUN_TURN_DICT && CACHE_STUN_TURN) return Promise.resolve(STUN_TURN_DICT);
const handleStunTurnResponse = ({ stunServers, turnServers }) => {
if (!stunServers && !turnServers) {
return Promise.reject(new Error('Could not fetch STUN/TURN servers'));
}
const turnReply = [];
_.each(turnServers, (turnEntry) => {
const { password, url, username } = turnEntry;
turnReply.push({
urls: url,
password,
username,
});
});
const stDictionary = {
stun: stunServers.map(server => server.url),
turn: turnReply,
};
STUN_TURN_DICT = stDictionary;
return Promise.resolve(stDictionary);
};
const url = `${STUN_TURN_FETCH_URL}?sessionToken=${sessionToken}`;
return fetch(url, { credentials: 'same-origin' })
.then(res => res.json())
.then(handleStunTurnResponse)
};
const mapStunTurn = ({ stun, turn }) => {
const rtcStuns = stun.map(url => ({ urls: url }));
const rtcTurns = turn.map(t => ({ urls: t.urls, credential: t.password, username: t.username }));
return rtcStuns.concat(rtcTurns);
};
const getFallbackStun = () => {
const stun = FALLBACK_STUN_SERVER ? [FALLBACK_STUN_SERVER] : []
return { stun, turn: [] };
}
const getMappedFallbackStun = () => {
return FALLBACK_STUN_SERVER ? [{ urls: FALLBACK_STUN_SERVER }] : [];
}
const fetchWebRTCMappedStunTurnServers = function (sessionToken) {
return new Promise(async (resolve, reject) => {
try {
if (MAPPED_STUN_TURN_DICT && CACHE_STUN_TURN) {
return resolve(MAPPED_STUN_TURN_DICT);
}
const stDictionary = await fetchStunTurnServers(sessionToken);
MAPPED_STUN_TURN_DICT = mapStunTurn(stDictionary);
return resolve(MAPPED_STUN_TURN_DICT);
} catch (error) {
return reject(error);
}
});
};
export {
fetchStunTurnServers,
fetchWebRTCMappedStunTurnServers,
getFallbackStun,
getMappedFallbackStun,
};