Skip to content
Open
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"search.exclude": {
"**/node_modules": false
}
}
56 changes: 49 additions & 7 deletions src/renderer/Voice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import Grid from '@material-ui/core/Grid';
import makeStyles from '@material-ui/core/styles/makeStyles';
import SupportLink from './SupportLink';
import Divider from '@material-ui/core/Divider';
import { validateClientPeerConfig } from './validateClientPeerConfig';
// @ts-ignore
import reverbOgx from 'arraybuffer-loader!../../static/reverb.ogx';

Expand Down Expand Up @@ -79,6 +80,19 @@ interface SocketError {
message?: string;
}

interface ClientPeerConfig {
forceRelayOnly: boolean;
iceServers: RTCIceServer[];
}

const DEFAULT_ICE_CONFIG: RTCConfiguration = {
iceServers: [
{
urls: 'stun:stun.l.google.com:19302',
},
],
};

function calculateVoiceAudio(
state: AmongUsState,
settings: ISettings,
Expand Down Expand Up @@ -408,10 +422,44 @@ const Voice: React.FC<VoiceProps> = function ({
socket.on('connect', () => {
setConnected(true);
});

socket.on('disconnect', () => {
setConnected(false);
});

let iceConfig: RTCConfiguration = DEFAULT_ICE_CONFIG;
socket.on('clientPeerConfig', (clientPeerConfig: ClientPeerConfig) => {
if (!validateClientPeerConfig(clientPeerConfig)) {
let errorsFormatted = '';
if (validateClientPeerConfig.errors) {
errorsFormatted = validateClientPeerConfig.errors
.map((error) => error.dataPath + ' ' + error.message)
.join('\n');
}
alert(
`Server sent a malformed peer config. Default config will be used. See errors below:\n${errorsFormatted}`
);
return;
}

if (
clientPeerConfig.forceRelayOnly &&
!clientPeerConfig.iceServers.some((server) =>
server.urls.toString().includes('turn:')
)
) {
alert(
'Server has forced relay mode enabled but provides no relay servers. Default config will be used.'
);
return;
}

iceConfig = {
iceTransportPolicy: clientPeerConfig.forceRelayOnly ? 'relay' : 'all',
iceServers: clientPeerConfig.iceServers,
};
});

// Initialize variables
let audioListener: {
connect: () => void;
Expand Down Expand Up @@ -494,13 +542,7 @@ const Voice: React.FC<VoiceProps> = function ({
const connection = new Peer({
stream,
initiator,
config: {
iceServers: [
{
urls: 'stun:stun.l.google.com:19302',
},
],
},
config: iceConfig,
});
setPeerConnections((connections) => {
connections[peer] = connection;
Expand Down
34 changes: 34 additions & 0 deletions src/renderer/validateClientPeerConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Ajv from 'ajv';

export const validateClientPeerConfig = new Ajv({ format: 'full', allErrors: true }).compile({
type: 'object',
properties: {
forceRelayOnly: {
type: 'boolean'
},
iceServers: {
type: 'array',
items: {
type: 'object',
properties: {
urls: {
type: ['string', 'array'],
format: 'uri',
items: {
type: 'string',
format: 'uri'
}
},
username: {
type: 'string',
},
credential: {
type: 'string',
}
},
required: ['urls']
}
}
},
required: ['forceRelayOnly', 'iceServers']
});