Merge branch 'develop' into feat-network-indicator

auto_join_3.3
Roman Drozd 2020-05-20 16:47:02 +02:00
commit ddd8c36c67
62 changed files with 1100 additions and 483 deletions

2
app/.env 100644
View File

@ -0,0 +1,2 @@
REACT_APP_VERSION=$npm_package_version
REACT_APP_NAME=$npm_package_name

View File

@ -159,6 +159,12 @@
"no-inner-declarations": 2, "no-inner-declarations": 2,
"no-invalid-regexp": 2, "no-invalid-regexp": 2,
"no-irregular-whitespace": 2, "no-irregular-whitespace": 2,
"no-trailing-spaces": [
"error",
{
"ignoreComments": true
}
],
"no-lonely-if": 2, "no-lonely-if": 2,
"no-mixed-operators": 2, "no-mixed-operators": 2,
"no-mixed-spaces-and-tabs": 2, "no-mixed-spaces-and-tabs": 2,

View File

@ -5,6 +5,26 @@ var config =
developmentPort : 3443, developmentPort : 3443,
productionPort : 443, productionPort : 443,
/**
* Supported browsers version
* in bowser satisfy format.
* See more:
* https://www.npmjs.com/package/bowser#filtering-browsers
* Otherwise you got a unsupported browser page
*/
supportedBrowsers :
{
'windows' : {
'internet explorer' : '>12',
'microsoft edge' : '>18'
},
'safari' : '>12',
'firefox' : '>=60',
'chrome' : '>=74',
'opera' : '>=62',
'samsung internet for android' : '>=11.1.1.52'
},
/** /**
* If defaultResolution is set, it will override user settings when joining: * If defaultResolution is set, it will override user settings when joining:
* low ~ 320x240 * low ~ 320x240
@ -26,6 +46,15 @@ var config =
{ scaleResolutionDownBy: 1 } { scaleResolutionDownBy: 1 }
], ],
/**
* Alternative simulcast setting:
* [
* { maxBitRate: 50000 },
* { maxBitRate: 1000000 },
* { maxBitRate: 4800000 }
*],
**/
/** /**
* White listing browsers that support audio output device selection. * White listing browsers that support audio output device selection.
* It is not yet fully implemented in Firefox. * It is not yet fully implemented in Firefox.
@ -37,7 +66,8 @@ var config =
'opera' 'opera'
], ],
// Socket.io request timeout // Socket.io request timeout
requestTimeout : 10000, requestTimeout : 20000,
requestRetries : 3,
transportOptions : transportOptions :
{ {
tcp : true tcp : true
@ -55,10 +85,12 @@ var config =
}, },
/** /**
* Set the auto mute / Push To Talk threshold * Set max number participants in one room that join
* default value is 4 * unmuted. Next participant will join automatically muted
* Default value is 4
* *
* Set it to 0 to disable auto mute functionality, * Set it to 0 to auto mute all,
* Set it to negative (-1) to never automatically auto mute
* but use it with caution * but use it with caution
* full mesh audio strongly decrease room capacity! * full mesh audio strongly decrease room capacity!
*/ */
@ -75,9 +107,12 @@ var config =
notificationPosition : 'right', notificationPosition : 'right',
// Timeout for autohiding topbar and button control bar // Timeout for autohiding topbar and button control bar
hideTimeout : 3000, hideTimeout : 3000,
// max number of participant that will be visible in
// as speaker
lastN : 4, lastN : 4,
mobileLastN : 1, mobileLastN : 1,
// Highest number of speakers user can select // Highest number of lastN the user can select manually in
// userinteface
maxLastN : 5, maxLastN : 5,
// If truthy, users can NOT change number of speakers visible // If truthy, users can NOT change number of speakers visible
lockLastN : false, lockLastN : false,

View File

@ -16,6 +16,44 @@
<title>Multiparty Meeting</title> <title>Multiparty Meeting</title>
<script src='%PUBLIC_URL%/config/config.js' type='text/javascript'></script> <script src='%PUBLIC_URL%/config/config.js' type='text/javascript'></script>
<!-- Show an error page to IE browsers -->
<script type='text/javascript'>
var fallback = '<style type="text/css">body{margin:40px auto;max-width:650px;line-height:1.6;font-size:18px;color:#444;padding:0 10px}h1,h2,h3{line-height:1.2}</style><header><h1>Your browser is not supported</h1><aside>You need to change to a different browser.</aside></header><h3>Supported browsers</h3><ul><li>Google Chrome/Chromium 55 +</li><li>Microsoft Edge 18 +</li><li>Mozilla Firefox 60 +</li><li>Apple Safari 12 +</li><li>Opera 62 +</li><li>Samsung Internet 11.1.1.52 +</li></ul>';
var fallbackCall = function() {
document.body.innerHTML = fallback;
};
if(navigator.userAgent.indexOf('MSIE') !== -1)
{
document.attachEvent('onreadystatechange', function() {
if (document.readyState === 'complete')
{
document.detachEvent('onreadystatechange', arguments.callee);
fallbackCall();
}
});
}
if (navigator.appVersion.indexOf('Trident/') > -1)
{
if (
document.readyState === 'complete' ||
(document.readyState !== 'loading' && !document.documentElement.doScroll)
)
{
document.removeEventListener('DOMContentLoaded', fallbackCall);
fallbackCall();
}
else
{
document.addEventListener('DOMContentLoaded', fallbackCall);
}
}
</script>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>

View File

@ -1,6 +1,7 @@
import Logger from './Logger'; import Logger from './Logger';
import hark from 'hark'; import hark from 'hark';
import { getSignalingUrl } from './urlFactory'; import { getSignalingUrl } from './urlFactory';
import { SocketTimeoutError } from './utils';
import * as requestActions from './actions/requestActions'; import * as requestActions from './actions/requestActions';
import * as meActions from './actions/meActions'; import * as meActions from './actions/meActions';
import * as roomActions from './actions/roomActions'; import * as roomActions from './actions/roomActions';
@ -575,7 +576,7 @@ export default class RoomClient
if (called) if (called)
return; return;
called = true; called = true;
callback(new Error('Request timeout.')); callback(new SocketTimeoutError('Request timed out'));
}, },
ROOM_OPTIONS.requestTimeout ROOM_OPTIONS.requestTimeout
); );
@ -591,13 +592,13 @@ export default class RoomClient
}; };
} }
sendRequest(method, data) _sendRequest(method, data)
{ {
return new Promise((resolve, reject) => return new Promise((resolve, reject) =>
{ {
if (!this._signalingSocket) if (!this._signalingSocket)
{ {
reject('No socket connection.'); reject('No socket connection');
} }
else else
{ {
@ -607,13 +608,9 @@ export default class RoomClient
this.timeoutCallback((err, response) => this.timeoutCallback((err, response) =>
{ {
if (err) if (err)
{
reject(err); reject(err);
}
else else
{
resolve(response); resolve(response);
}
}) })
); );
} }
@ -650,6 +647,33 @@ export default class RoomClient
} }
} }
async sendRequest(method, data)
{
logger.debug('sendRequest() [method:"%s", data:"%o"]', method, data);
const {
requestRetries = 3
} = window.config;
for (let tries = 0; tries < requestRetries; tries++)
{
try
{
return await this._sendRequest(method, data);
}
catch (error)
{
if (
error instanceof SocketTimeoutError &&
tries < requestRetries
)
logger.warn('sendRequest() | timeout, retrying [attempt:"%s"]', tries);
else
throw error;
}
}
}
async changeDisplayName(displayName) async changeDisplayName(displayName)
{ {
logger.debug('changeDisplayName() [displayName:"%s"]', displayName); logger.debug('changeDisplayName() [displayName:"%s"]', displayName);
@ -1037,20 +1061,20 @@ export default class RoomClient
this._hark = hark(this._harkStream, this._hark = hark(this._harkStream,
{ {
play : false, play : false,
interval : 5, interval : 10,
threshold : store.getState().settings.noiseThreshold, threshold : store.getState().settings.noiseThreshold,
history : 30 history : 100
}); });
this._hark.lastVolume = -100; this._hark.lastVolume = -100;
this._hark.on('volume_change', (volume) => this._hark.on('volume_change', (volume) =>
{ {
volume = Math.round(volume); volume = Math.round(volume);
if (this._micProducer && volume !== Math.round(this._hark.lastVolume)) if (this._micProducer && (volume !== Math.round(this._hark.lastVolume)))
{ {
if (volume < this._hark.lastVolume * 1.02) if (volume < this._hark.lastVolume)
{ {
volume = this._hark.lastVolume * 1.02; volume = this._hark.lastVolume - Math.pow((volume - this._hark.lastVolume)/(100 + this._hark.lastVolume),4)*2;
} }
this._hark.lastVolume = volume; this._hark.lastVolume = volume;
store.dispatch(peerVolumeActions.setPeerVolume(this._peerId, volume)); store.dispatch(peerVolumeActions.setPeerVolume(this._peerId, volume));
@ -2690,7 +2714,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
text : intl.formatMessage({ text : intl.formatMessage({
id : 'moderator.muteScreenSharingModerator', id : 'moderator.stopScreenSharing',
defaultMessage : 'Moderator stopped your screen sharing' defaultMessage : 'Moderator stopped your screen sharing'
}) })
})); }));
@ -3053,9 +3077,13 @@ export default class RoomClient
if (!this._muted) if (!this._muted)
{ {
await this.enableMic(); await this.enableMic();
const { autoMuteThreshold } = store.getState().settings; let autoMuteThreshold = 4;
if (autoMuteThreshold && peers.length > autoMuteThreshold) if ('autoMuteThreshold' in window.config)
{
autoMuteThreshold = window.config.autoMuteThreshold;
}
if (autoMuteThreshold && peers.length >= autoMuteThreshold)
this.muteMic(); this.muteMic();
} }

View File

@ -89,21 +89,6 @@ export const setDefaultAudio = (audio) =>
payload : { audio } payload : { audio }
}); });
export const toggleEchoCancellation = () =>
({
type : 'TOGGLE_ECHO_CANCELLATION'
});
export const toggleAutoGainControl = () =>
({
type : 'TOGGLE_AUTO_GAIN_CONTROL'
});
export const toggleNoiseSuppression = () =>
({
type : 'TOGGLE_NOISE_SUPPRESSION'
});
export const toggleHiddenControls = () => export const toggleHiddenControls = () =>
({ ({
type : 'TOGGLE_HIDDEN_CONTROLS' type : 'TOGGLE_HIDDEN_CONTROLS'

View File

@ -509,8 +509,10 @@ const Me = (props) =>
> >
{ micState === 'on' ? { micState === 'on' ?
<MicIcon <MicIcon
color={me.isAutoMuted ? 'secondary' : 'primary'} color={me.isAutoMuted && settings.voiceActivatedUnmute ?
style={me.isAutoMuted ? { opacity: noiseVolume } 'secondary' : 'primary'}
style={me.isAutoMuted && settings.voiceActivatedUnmute ?
{ opacity: noiseVolume }
: { opacity: 1 }} : { opacity: 1 }}
/> />
: :

View File

@ -58,27 +58,27 @@ const styles = () =>
'&.level6' : '&.level6' :
{ {
height : '60%', height : '60%',
backgroundColor : 'rgba(255, 0, 0, 0.65)' backgroundColor : 'rgba(255, 165, 0, 0.65)'
}, },
'&.level7' : '&.level7' :
{ {
height : '70%', height : '70%',
backgroundColor : 'rgba(255, 0, 0, 0.65)' backgroundColor : 'rgba(255, 100, 0, 0.65)'
}, },
'&.level8' : '&.level8' :
{ {
height : '80%', height : '80%',
backgroundColor : 'rgba(0, 0, 0, 0.65)' backgroundColor : 'rgba(255, 60, 0, 0.65)'
}, },
'&.level9' : '&.level9' :
{ {
height : '90%', height : '90%',
backgroundColor : 'rgba(0, 0, 0, 0.65)' backgroundColor : 'rgba(255, 30, 0, 0.65)'
}, },
'&.level10' : '&.level10' :
{ {
height : '100%', height : '100%',
backgroundColor : 'rgba(0, 0, 0, 0.65)' backgroundColor : 'rgba(255, 0, 0, 0.65)'
} }
}, },
volumeSmall : volumeSmall :

View File

@ -43,7 +43,8 @@ const styles = (theme) =>
link : link :
{ {
display : 'block', display : 'block',
textAlign : 'center' textAlign : 'center',
marginBottom : theme.spacing(1)
} }
}); });
@ -68,15 +69,16 @@ const About = ({
/> />
</DialogTitle> </DialogTitle>
<DialogContent dividers='true'> <DialogContent dividers='true'>
<DialogContentText> <DialogContentText paragraph>
Contributions to this work were made on behalf of the GÉANT Contributions to this work were made on behalf of the GÉANT
project, a project that has received funding from the project, a project that has received funding from the
European Unions Horizon 2020 research and innovation European Unions Horizon 2020 research and innovation
programme under Grant Agreement No. 731122 (GN4-2). programme under Grant Agreement No. 731122 (GN4-2).
On behalf of GÉANT project, GÉANT Association is the sole On behalf of GÉANT project, GÉANT Association is the sole
owner of the copyright in all material which was developed owner of the copyright in all material which was developed
by a member of the GÉANT project.<br /> by a member of the GÉANT project.
<br /> </DialogContentText>
<DialogContentText paragraph>
GÉANT Vereniging (Association) is registered with the GÉANT Vereniging (Association) is registered with the
Chamber of Commerce in Amsterdam with registration number Chamber of Commerce in Amsterdam with registration number
40535155 and operates in the UK as a branch of GÉANT 40535155 and operates in the UK as a branch of GÉANT
@ -87,6 +89,13 @@ const About = ({
<Link href='https://edumeet.org' target='_blank' rel='noreferrer' color='secondary' variant='h6' className={classes.link}> <Link href='https://edumeet.org' target='_blank' rel='noreferrer' color='secondary' variant='h6' className={classes.link}>
https://edumeet.org https://edumeet.org
</Link> </Link>
<DialogContentText align='center' variant='h7'>
<FormattedMessage
id='label.version'
defaultMessage='Version'
/>
:{` ${process.env.REACT_APP_VERSION}`}
</DialogContentText>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
{ window.config.logo && <img alt='Logo' className={classes.logo} src={window.config.logo} /> } { window.config.logo && <img alt='Logo' className={classes.logo} src={window.config.logo} /> }

View File

@ -472,14 +472,6 @@ const TopBar = (props) =>
} }
</div> </div>
<div className={classes.sectionMobile}> <div className={classes.sectionMobile}>
<IconButton
aria-haspopup='true'
onClick={handleMobileMenuOpen}
color='inherit'
>
<MoreIcon />
</IconButton>
</div>
{ lobbyPeers.length > 0 && { lobbyPeers.length > 0 &&
<Tooltip <Tooltip
title={intl.formatMessage({ title={intl.formatMessage({
@ -508,6 +500,14 @@ const TopBar = (props) =>
</span> </span>
</Tooltip> </Tooltip>
} }
<IconButton
aria-haspopup='true'
onClick={handleMobileMenuOpen}
color='inherit'
>
<MoreIcon />
</IconButton>
</div>
<div className={classes.divider} /> <div className={classes.divider} />
<Button <Button
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
@ -697,33 +697,6 @@ const TopBar = (props) =>
/> />
</p> </p>
</MenuItem> </MenuItem>
{ lobbyPeers.length > 0 &&
<MenuItem
aria-label={intl.formatMessage({
id : 'tooltip.lobby',
defaultMessage : 'Show lobby'
})}
disabled={!canPromote}
onClick={() =>
{
handleMenuClose();
setLockDialogOpen(!room.lockDialogOpen);
}}
>
<PulsingBadge
color='secondary'
badgeContent={lobbyPeers.length}
>
<SecurityIcon />
</PulsingBadge>
<p className={classes.moreAction}>
<FormattedMessage
id='tooltip.lobby'
defaultMessage='Show lobby'
/>
</p>
</MenuItem>
}
<MenuItem <MenuItem
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
id : 'tooltip.participants', id : 'tooltip.participants',

View File

@ -4,13 +4,14 @@ import { withStyles } from '@material-ui/core/styles';
import { withRoomContext } from '../../RoomContext'; import { withRoomContext } from '../../RoomContext';
import * as settingsActions from '../../actions/settingsActions'; import * as settingsActions from '../../actions/settingsActions';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames';
import { useIntl, FormattedMessage } from 'react-intl'; import { useIntl, FormattedMessage } from 'react-intl';
import MenuItem from '@material-ui/core/MenuItem'; import MenuItem from '@material-ui/core/MenuItem';
import FormHelperText from '@material-ui/core/FormHelperText'; import FormHelperText from '@material-ui/core/FormHelperText';
import FormControl from '@material-ui/core/FormControl'; import FormControl from '@material-ui/core/FormControl';
import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormControlLabel from '@material-ui/core/FormControlLabel';
import Select from '@material-ui/core/Select'; import Select from '@material-ui/core/Select';
import Checkbox from '@material-ui/core/Checkbox'; import Switch from '@material-ui/core/Switch';
const styles = (theme) => const styles = (theme) =>
({ ({
@ -21,6 +22,13 @@ const styles = (theme) =>
formControl : formControl :
{ {
display : 'flex' display : 'flex'
},
switchLabel : {
justifyContent : 'space-between',
flex : 'auto',
display : 'flex',
padding : theme.spacing(1),
marginRight : 0
} }
}); });
@ -37,16 +45,18 @@ const AdvancedSettings = ({
return ( return (
<React.Fragment> <React.Fragment>
<FormControlLabel <FormControlLabel
className={classes.setting} className={classnames(classes.setting, classes.switchLabel)}
control={<Checkbox checked={settings.advancedMode} onChange={onToggleAdvancedMode} value='advancedMode' />} control={<Switch checked={settings.advancedMode} onChange={onToggleAdvancedMode} value='advancedMode' />}
labelPlacement='start'
label={intl.formatMessage({ label={intl.formatMessage({
id : 'settings.advancedMode', id : 'settings.advancedMode',
defaultMessage : 'Advanced mode' defaultMessage : 'Advanced mode'
})} })}
/> />
<FormControlLabel <FormControlLabel
className={classes.setting} className={classnames(classes.setting, classes.switchLabel)}
control={<Checkbox checked={settings.notificationSounds} onChange={onToggleNotificationSounds} value='notificationSounds' />} control={<Switch checked={settings.notificationSounds} onChange={onToggleNotificationSounds} value='notificationSounds' />}
labelPlacement='start'
label={intl.formatMessage({ label={intl.formatMessage({
id : 'settings.notificationSounds', id : 'settings.notificationSounds',
defaultMessage : 'Notification sounds' defaultMessage : 'Notification sounds'

View File

@ -4,6 +4,7 @@ import * as appPropTypes from '../appPropTypes';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import * as roomActions from '../../actions/roomActions'; import * as roomActions from '../../actions/roomActions';
import * as settingsActions from '../../actions/settingsActions'; import * as settingsActions from '../../actions/settingsActions';
import classnames from 'classnames';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useIntl, FormattedMessage } from 'react-intl'; import { useIntl, FormattedMessage } from 'react-intl';
import MenuItem from '@material-ui/core/MenuItem'; import MenuItem from '@material-ui/core/MenuItem';
@ -11,7 +12,7 @@ import FormHelperText from '@material-ui/core/FormHelperText';
import FormControl from '@material-ui/core/FormControl'; import FormControl from '@material-ui/core/FormControl';
import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormControlLabel from '@material-ui/core/FormControlLabel';
import Select from '@material-ui/core/Select'; import Select from '@material-ui/core/Select';
import Checkbox from '@material-ui/core/Checkbox'; import Switch from '@material-ui/core/Switch';
const styles = (theme) => const styles = (theme) =>
({ ({
@ -22,6 +23,13 @@ const styles = (theme) =>
formControl : formControl :
{ {
display : 'flex' display : 'flex'
},
switchLabel : {
justifyContent : 'space-between',
flex : 'auto',
display : 'flex',
padding : theme.spacing(1),
marginRight : 0
} }
}); });
@ -90,24 +98,28 @@ const AppearenceSettings = ({
</FormControl> </FormControl>
</form> </form>
<FormControlLabel <FormControlLabel
className={classes.setting} className={classnames(classes.setting, classes.switchLabel)}
control={<Checkbox checked={settings.permanentTopBar} onChange={onTogglePermanentTopBar} value='permanentTopBar' />} control={
<Switch checked={settings.permanentTopBar} onChange={onTogglePermanentTopBar} value='permanentTopBar' />}
labelPlacement='start'
label={intl.formatMessage({ label={intl.formatMessage({
id : 'settings.permanentTopBar', id : 'settings.permanentTopBar',
defaultMessage : 'Permanent top bar' defaultMessage : 'Permanent top bar'
})} })}
/> />
<FormControlLabel <FormControlLabel
className={classes.setting} className={classnames(classes.setting, classes.switchLabel)}
control={<Checkbox checked={settings.hiddenControls} onChange={onToggleHiddenControls} value='hiddenControls' />} control={<Switch checked={settings.hiddenControls} onChange={onToggleHiddenControls} value='hiddenControls' />}
labelPlacement='start'
label={intl.formatMessage({ label={intl.formatMessage({
id : 'settings.hiddenControls', id : 'settings.hiddenControls',
defaultMessage : 'Hidden media controls' defaultMessage : 'Hidden media controls'
})} })}
/> />
<FormControlLabel <FormControlLabel
className={classes.setting} className={classnames(classes.setting, classes.switchLabel)}
control={<Checkbox checked={settings.buttonControlBar} onChange={onToggleButtonControlBar} value='buttonControlBar' />} control={<Switch checked={settings.buttonControlBar} onChange={onToggleButtonControlBar} value='buttonControlBar' />}
labelPlacement='start'
label={intl.formatMessage({ label={intl.formatMessage({
id : 'settings.buttonControlBar', id : 'settings.buttonControlBar',
defaultMessage : 'Separate media controls' defaultMessage : 'Separate media controls'
@ -115,8 +127,9 @@ const AppearenceSettings = ({
/> />
{ !isMobile && { !isMobile &&
<FormControlLabel <FormControlLabel
className={classes.setting} className={classnames(classes.setting, classes.switchLabel)}
control={<Checkbox checked={settings.drawerOverlayed} onChange={onToggleDrawerOverlayed} value='drawerOverlayed' />} control={<Switch checked={settings.drawerOverlayed} onChange={onToggleDrawerOverlayed} value='drawerOverlayed' />}
labelPlacement='start'
label={intl.formatMessage({ label={intl.formatMessage({
id : 'settings.drawerOverlayed', id : 'settings.drawerOverlayed',
defaultMessage : 'Side drawer over content' defaultMessage : 'Side drawer over content'
@ -124,8 +137,9 @@ const AppearenceSettings = ({
/> />
} }
<FormControlLabel <FormControlLabel
className={classes.setting} className={classnames(classes.setting, classes.switchLabel)}
control={<Checkbox checked={settings.showNotifications} onChange={onToggleShowNotifications} value='showNotifications' />} control={<Switch checked={settings.showNotifications} onChange={onToggleShowNotifications} value='showNotifications' />}
labelPlacement='start'
label={intl.formatMessage({ label={intl.formatMessage({
id : 'settings.showNotifications', id : 'settings.showNotifications',
defaultMessage : 'Show notifications' defaultMessage : 'Show notifications'

View File

@ -12,9 +12,15 @@ import FormHelperText from '@material-ui/core/FormHelperText';
import FormControl from '@material-ui/core/FormControl'; import FormControl from '@material-ui/core/FormControl';
import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormControlLabel from '@material-ui/core/FormControlLabel';
import Select from '@material-ui/core/Select'; import Select from '@material-ui/core/Select';
import Checkbox from '@material-ui/core/Checkbox';
import Slider from '@material-ui/core/Slider'; import Slider from '@material-ui/core/Slider';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import Collapse from '@material-ui/core/Collapse';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import ExpandLess from '@material-ui/icons/ExpandLess';
import ExpandMore from '@material-ui/icons/ExpandMore';
import Switch from '@material-ui/core/Switch';
const NoiseSlider = withStyles( const NoiseSlider = withStyles(
{ {
@ -52,6 +58,23 @@ const styles = (theme) => ({
{ {
height : theme.spacing(3) height : theme.spacing(3)
}, },
root : {
width : '100%',
backgroundColor : theme.palette.background.paper
},
switchLabel : {
justifyContent : 'space-between',
flex : 'auto',
display : 'flex',
padding : theme.spacing(1)
},
nested : {
display : 'block',
paddingTop : 0,
paddingBottom : 0,
paddingLeft : '25px',
paddingRight : '25px'
},
formControl : formControl :
{ {
display : 'flex' display : 'flex'
@ -129,6 +152,13 @@ const MediaSettings = ({
else else
audioOutputDevices = []; audioOutputDevices = [];
const [ open, setOpen ] = React.useState(true);
const advancedAudioSettings = () =>
{
setOpen(!open);
};
return ( return (
<React.Fragment> <React.Fragment>
<form className={classes.setting} autoComplete='off'> <form className={classes.setting} autoComplete='off'>
@ -287,90 +317,120 @@ const MediaSettings = ({
</FormControl> </FormControl>
</form> </form>
} }
<form className={classes.setting} autoComplete='off'> <List className={classes.root} component='nav'>
<ListItem button onClick={advancedAudioSettings}>
<ListItemText primary={intl.formatMessage({
id : 'settings.showAdvancedAudio',
defaultMessage : 'Show advanced audio settings'
})}
/>
{open ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={!open} timeout='auto'>
<List component='div'>
<ListItem className={classes.nested}>
<FormControlLabel <FormControlLabel
className={classes.setting} className={classnames(classes.setting, classes.switchLabel)}
control={ control={
<Checkbox checked={settings.echoCancellation} onChange={ <Switch color='secondary'
checked={settings.echoCancellation}
onChange={
(event) => (event) =>
{ {
setEchoCancellation(event.target.checked); setEchoCancellation(event.target.checked);
roomClient.changeAudioDevice(settings.selectedAudioDevice); roomClient.changeAudioDevice(settings.selectedAudioDevice);
}} }}
/>} />}
labelPlacement='start'
label={intl.formatMessage({ label={intl.formatMessage({
id : 'settings.echoCancellation', id : 'settings.echoCancellation',
defaultMessage : 'Echo cancellation' defaultMessage : 'Echo cancellation'
})} })}
/> />
</ListItem>
<ListItem className={classes.nested}>
<FormControlLabel <FormControlLabel
className={classes.setting} className={classnames(classes.setting, classes.switchLabel)}
control={ control={
<Checkbox checked={settings.autoGainControl} onChange={ <Switch color='secondary'
checked={settings.autoGainControl} onChange={
(event) => (event) =>
{ {
setAutoGainControl(event.target.checked); setAutoGainControl(event.target.checked);
roomClient.changeAudioDevice(settings.selectedAudioDevice); roomClient.changeAudioDevice(settings.selectedAudioDevice);
}} }}
/>} />}
labelPlacement='start'
label={intl.formatMessage({ label={intl.formatMessage({
id : 'settings.autoGainControl', id : 'settings.autoGainControl',
defaultMessage : 'Auto gain control' defaultMessage : 'Auto gain control'
})} })}
/> />
</ListItem>
<ListItem className={classes.nested}>
<FormControlLabel <FormControlLabel
className={classes.setting} className={classnames(classes.setting, classes.switchLabel)}
control={ control={
<Checkbox checked={settings.noiseSuppression} onChange={ <Switch color='secondary'
checked={settings.noiseSuppression} onChange={
(event) => (event) =>
{ {
setNoiseSuppression(event.target.checked); setNoiseSuppression(event.target.checked);
roomClient.changeAudioDevice(settings.selectedAudioDevice); roomClient.changeAudioDevice(settings.selectedAudioDevice);
}} }}
/>} />}
labelPlacement='start'
label={intl.formatMessage({ label={intl.formatMessage({
id : 'settings.noiseSuppression', id : 'settings.noiseSuppression',
defaultMessage : 'Noise suppression' defaultMessage : 'Noise suppression'
})} })}
/> />
</ListItem>
<ListItem className={classes.nested}>
<FormControlLabel <FormControlLabel
className={classes.setting} className={classnames(classes.setting, classes.switchLabel)}
control={ control={
<Checkbox checked={settings.voiceActivatedUnmute} onChange={ <Switch color='secondary'
checked={settings.voiceActivatedUnmute} onChange={
(event) => (event) =>
{ {
setVoiceActivatedUnmute(event.target.checked); setVoiceActivatedUnmute(event.target.checked);
}} }}
/>} />}
labelPlacement='start'
label={intl.formatMessage({ label={intl.formatMessage({
id : 'settings.voiceActivatedUnmute', id : 'settings.voiceActivatedUnmute',
defaultMessage : 'Voice activated unmute' defaultMessage : 'Voice activated unmute'
})} })}
/> />
</ListItem>
<ListItem className={classes.nested}>
<div className={classes.margin} /> <div className={classes.margin} />
<Typography gutterBottom> <Typography gutterBottom>
{ {
intl.formatMessage({ intl.formatMessage({
id : 'settings.noiseThreshold', id : 'settings.noiseThreshold',
defaultMessage : 'Noise threshold:' defaultMessage : 'Noise threshold'
}) })
} }:
</Typography> </Typography>
<NoiseSlider className={classnames(classes.slider, classnames.setting)} <NoiseSlider className={classnames(classes.slider, classnames.setting)}
key={'noise-threshold-slider'} key={'noise-threshold-slider'}
min={-100} min={-100}
value={settings.noiseThreshold} value={settings.noiseThreshold}
max={0} max={0}
valueLabelDisplay={'off'} valueLabelDisplay={'auto'}
onChange={ onChange={
(event, value) => (event, value) =>
{ {
roomClient._setNoiseThreshold(value); roomClient._setNoiseThreshold(value);
}} }}
marks={[ { value: volume, label: 'level' } ]} marks={[ { value: volume, label: `${volume} dB` } ]}
/> />
<div className={classes.margin} /> </ListItem>
</form> </List>
</Collapse>
</List>
</React.Fragment> </React.Fragment>
); );
}; };
@ -399,8 +459,8 @@ const mapStateToProps = (state) =>
const mapDispatchToProps = { const mapDispatchToProps = {
setEchoCancellation : settingsActions.setEchoCancellation, setEchoCancellation : settingsActions.setEchoCancellation,
setAutoGainControl : settingsActions.toggleAutoGainControl, setAutoGainControl : settingsActions.setAutoGainControl,
setNoiseSuppression : settingsActions.toggleNoiseSuppression, setNoiseSuppression : settingsActions.setNoiseSuppression,
setVoiceActivatedUnmute : settingsActions.setVoiceActivatedUnmute setVoiceActivatedUnmute : settingsActions.setVoiceActivatedUnmute
}; };

View File

@ -0,0 +1,154 @@
import React from 'react';
import { withStyles } from '@material-ui/core/styles';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import Dialog from '@material-ui/core/Dialog';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContent from '@material-ui/core/DialogContent';
import Grid from '@material-ui/core/Grid';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import ListItemAvatar from '@material-ui/core/ListItemAvatar';
import Avatar from '@material-ui/core/Avatar';
import WebAssetIcon from '@material-ui/icons/WebAsset';
import ErrorIcon from '@material-ui/icons/Error';
import Hidden from '@material-ui/core/Hidden';
const styles = (theme) =>
({
dialogPaper :
{
width : '40vw',
[theme.breakpoints.down('lg')] :
{
width : '40vw'
},
[theme.breakpoints.down('md')] :
{
width : '50vw'
},
[theme.breakpoints.down('sm')] :
{
width : '70vw'
},
[theme.breakpoints.down('xs')] :
{
width : '90vw'
}
// display : 'flex',
// flexDirection : 'column'
},
list : {
backgroundColor : theme.palette.background.paper
},
errorAvatar : {
width : theme.spacing(20),
height : theme.spacing(20)
}
});
const open=true;
const dividers=true;
let dense=false;
const supportedBrowsers=[
{ name: 'Chrome/Chromium', version: '74', vendor: 'Google' },
{ name: 'Edge', version: '18', vendor: 'Microsoft' },
{ name: 'Firefox', version: '60', vendor: 'Mozilla' },
{ name: 'Safari', version: '12', vendor: 'Apple' },
{ name: 'Opera', version: '62', vendor: '' },
// { name: 'Brave', version: '1.5', vendor: '' },
// { name: 'Vivaldi', version: '3', vendor: '' },
{ name: 'Samsung Internet', version: '11.1.1.52', vendor: '' }
];
const UnsupportedBrowser = ({
platform,
webrtcUnavailable,
classes
}) =>
{
if (platform !== 'desktop')
{
dense=true;
}
return (
<Dialog
open={open}
scroll={'body'}
classes={{
paper : classes.dialogPaper
}}
>
<DialogTitle id='form-dialog-title'>
{!webrtcUnavailable &&
<FormattedMessage
id='unsupportedBrowser.titleUnsupportedBrowser'
defaultMessage='Detected unsupported browser!'
/>
}
{webrtcUnavailable &&
<FormattedMessage
id='unsupportedBrowser.titlewebrtcUnavailable'
defaultMessage='Required functionality not availble in your browser!'
/>
}
</DialogTitle>
<DialogContent dividers={dividers} >
<FormattedMessage
id='unsupportedBrowser.bodyText'
defaultMessage='This meeting service requires a
functionality that is not supported by your browser.
Please upgrade, or switch to a different browser, or
check your settings. Supported browsers:'
/>
<Grid container spacing={2} justify='center' alignItems='center'>
<Grid item xs={12} md={7}>
<div className={classes.list}>
<List dense={dense}>
{supportedBrowsers.map((browser, index) =>
{
const supportedBrowser = `${browser.vendor} ${browser.name}`;
const supportedVersion = `${browser.version}+`;
return (
<ListItem key={index}>
<ListItemAvatar>
<Avatar>
<WebAssetIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={supportedBrowser}
secondary={supportedVersion}
/>
</ListItem>
);
})}
</List>
</div>
</Grid>
<Grid item xs={12} md={5} align='center'>
<Hidden mdDown>
<ErrorIcon className={classes.errorAvatar} color='error'/>
</Hidden>
</Grid>
</Grid>
</DialogContent>
</Dialog>
);
};
UnsupportedBrowser.propTypes =
{
webrtcUnavailable : PropTypes.bool.isRequired,
platform : PropTypes.string.isRequired,
classes : PropTypes.object.isRequired
};
export default withStyles(styles)(UnsupportedBrowser);

View File

@ -12,6 +12,7 @@ import RoomClient from './RoomClient';
import RoomContext from './RoomContext'; import RoomContext from './RoomContext';
import deviceInfo from './deviceInfo'; import deviceInfo from './deviceInfo';
import * as meActions from './actions/meActions'; import * as meActions from './actions/meActions';
import UnsupportedBrowser from './components/UnsupportedBrowser';
import ChooseRoom from './components/ChooseRoom'; import ChooseRoom from './components/ChooseRoom';
import LoadingView from './components/LoadingView'; import LoadingView from './components/LoadingView';
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles'; import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
@ -20,7 +21,7 @@ import { persistor, store } from './store';
import { SnackbarProvider } from 'notistack'; import { SnackbarProvider } from 'notistack';
import * as serviceWorker from './serviceWorker'; import * as serviceWorker from './serviceWorker';
import { ReactLazyPreload } from './components/ReactLazyPreload'; import { ReactLazyPreload } from './components/ReactLazyPreload';
import { detectDevice } from 'mediasoup-client';
// import messagesEnglish from './translations/en'; // import messagesEnglish from './translations/en';
import messagesNorwegian from './translations/nb'; import messagesNorwegian from './translations/nb';
import messagesGerman from './translations/de'; import messagesGerman from './translations/de';
@ -70,6 +71,18 @@ const messages =
'lv' : messagesLatvian 'lv' : messagesLatvian
}; };
const supportedBrowsers={
'windows' : {
'internet explorer' : '>12',
'microsoft edge' : '>18'
},
'safari' : '>12',
'firefox' : '>=60',
'chrome' : '>=74',
'opera' : '>=62',
'samsung internet for android' : '>=11.1.1.52'
};
const browserLanguage = (navigator.language || navigator.browserLanguage).toLowerCase(); const browserLanguage = (navigator.language || navigator.browserLanguage).toLowerCase();
let locale = browserLanguage.split(/[-_]/)[0]; // language without region code let locale = browserLanguage.split(/[-_]/)[0]; // language without region code
@ -138,6 +151,58 @@ function run()
// Get current device. // Get current device.
const device = deviceInfo(); const device = deviceInfo();
let unsupportedBrowser=false;
let webrtcUnavailable=false;
if (detectDevice() === undefined)
{
logger.error('Unsupported browser detected by mediasoup client detectDevice! deviceInfo: %o', device);
unsupportedBrowser=true;
}
else
if (
navigator.mediaDevices === undefined ||
navigator.mediaDevices.getUserMedia === undefined ||
window.RTCPeerConnection === undefined
)
{
logger.error('WebRTC is unavialable in your browser! deviceInfo: %o', device);
webrtcUnavailable=true;
}
else
if (!device.bowser.satisfies(
window.config.supportedBrowsers ? window.config.supportedBrowsers : supportedBrowsers)
)
{
logger.error(
'Your browser is not on the supported list! Ask your server admin to add your browser to the supported list, if you think that your browser should be supported! deviceInfo: %o',
device
);
unsupportedBrowser=true;
}
else
{
logger.debug('Supported Browser! deviceInfo: %o', device);
}
if (unsupportedBrowser || webrtcUnavailable)
{
render(
<MuiThemeProvider theme={theme}>
<RawIntlProvider value={intl}>
<UnsupportedBrowser
webrtcUnavailable={webrtcUnavailable}
platform={device.platform}
/>
</RawIntlProvider>
</MuiThemeProvider>,
document.getElementById('multiparty-meeting')
);
return;
}
store.dispatch( store.dispatch(
meActions.setMe({ meActions.setMe({
peerId, peerId,

View File

@ -0,0 +1,42 @@
class AudioAnalyzer extends EventEmitter
{
constructor()
{
if (prefix)
{
this._debug = debug(`${APP_NAME}:${prefix}`);
this._warn = debug(`${APP_NAME}:WARN:${prefix}`);
this._error = debug(`${APP_NAME}:ERROR:${prefix}`);
}
else
{
this._debug = debug(APP_NAME);
this._warn = debug(`${APP_NAME}:WARN`);
this._error = debug(`${APP_NAME}:ERROR`);
}
/* eslint-disable no-console */
this._debug.log = console.info.bind(console);
this._warn.log = console.warn.bind(console);
this._error.log = console.error.bind(console);
/* eslint-enable no-console */
}
get debug()
{
return this._debug;
}
get warn()
{
return this._warn;
}
get error()
{
return this._error;
}
}

View File

@ -10,13 +10,13 @@ const peerVolumes = (state = initialState, action) =>
peerId peerId
} = action.payload; } = action.payload;
return { ...state, [peerId]: 0 }; return { ...state, [peerId]: -100 };
} }
case 'ADD_PEER': case 'ADD_PEER':
{ {
const { peer } = action.payload; const { peer } = action.payload;
return { ...state, [peer.id]: 0 }; return { ...state, [peer.id]: -100 };
} }
case 'REMOVE_PEER': case 'REMOVE_PEER':

View File

@ -22,7 +22,6 @@ const initialState =
notificationSounds : true, notificationSounds : true,
buttonControlBar : window.config.buttonControlBar || false, buttonControlBar : window.config.buttonControlBar || false,
drawerOverlayed : window.config.drawerOverlayed || true, drawerOverlayed : window.config.drawerOverlayed || true,
autoMuteThreshold : window.config.autoMuteThreshold || 4,
...window.config.defaultAudio ...window.config.defaultAudio
}; };
@ -122,27 +121,6 @@ const settings = (state = initialState, action) =>
return { ...state, audio }; return { ...state, audio };
} }
case 'TOGGLE_AUTO_GAIN_CONTROL':
{
const autoGainControl = !state.autoGainControl;
return { ...state, autoGainControl };
}
case 'TOGGLE_ECHO_CANCELLATION':
{
const echoCancellation = !state.echoCancellation;
return { ...state, echoCancellation };
}
case 'TOGGLE_NOISE_SUPPRESSION':
{
const noiseSuppression = !state.noiseSuppression;
return { ...state, noiseSuppression };
}
case 'SET_SAMPLE_SIZE': case 'SET_SAMPLE_SIZE':
{ {
const { sampleSize } = action.payload; const { sampleSize } = action.payload;

View File

@ -119,6 +119,7 @@
"label.addVideo": null, "label.addVideo": null,
"label.promoteAllPeers": null, "label.promoteAllPeers": null,
"label.moreActions": null, "label.moreActions": null,
"label.version": null,
"settings.settings": "设置", "settings.settings": "设置",
"settings.camera": "视频设备", "settings.camera": "视频设备",
@ -144,6 +145,8 @@
"settings.autoGainControl": null, "settings.autoGainControl": null,
"settings.noiseSuppression": null, "settings.noiseSuppression": null,
"settings.drawerOverlayed": null, "settings.drawerOverlayed": null,
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "无法保存文件", "filesharing.saveFileError": "无法保存文件",
"filesharing.startingFileShare": "正在尝试共享文件", "filesharing.startingFileShare": "正在尝试共享文件",
@ -189,5 +192,9 @@
"moderator.clearFiles": null, "moderator.clearFiles": null,
"moderator.muteAudio": null, "moderator.muteAudio": null,
"moderator.muteVideo": null, "moderator.muteVideo": null,
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -118,6 +118,7 @@
"label.addVideo": null, "label.addVideo": null,
"label.promoteAllPeers": null, "label.promoteAllPeers": null,
"label.moreActions": null, "label.moreActions": null,
"label.version": null,
"settings.settings": "Nastavení", "settings.settings": "Nastavení",
"settings.camera": "Kamera", "settings.camera": "Kamera",
@ -143,6 +144,8 @@
"settings.autoGainControl": null, "settings.autoGainControl": null,
"settings.noiseSuppression": null, "settings.noiseSuppression": null,
"settings.drawerOverlayed": null, "settings.drawerOverlayed": null,
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "Není možné uložit soubor", "filesharing.saveFileError": "Není možné uložit soubor",
"filesharing.startingFileShare": "Pokouším se sdílet soubor", "filesharing.startingFileShare": "Pokouším se sdílet soubor",
@ -188,5 +191,9 @@
"moderator.clearFiles": null, "moderator.clearFiles": null,
"moderator.muteAudio": null, "moderator.muteAudio": null,
"moderator.muteVideo": null, "moderator.muteVideo": null,
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -119,6 +119,7 @@
"label.addVideo": "Video hinzufügen", "label.addVideo": "Video hinzufügen",
"label.promoteAllPeers": "Alle Teilnehmer reinlassen", "label.promoteAllPeers": "Alle Teilnehmer reinlassen",
"label.moreActions": "Weitere Aktionen", "label.moreActions": "Weitere Aktionen",
"label.version": null,
"settings.settings": "Einstellungen", "settings.settings": "Einstellungen",
"settings.camera": "Kamera", "settings.camera": "Kamera",
@ -144,6 +145,8 @@
"settings.autoGainControl": "Automatische Pegelregelung (Audioeingang)", "settings.autoGainControl": "Automatische Pegelregelung (Audioeingang)",
"settings.noiseSuppression": "Rauschunterdrückung", "settings.noiseSuppression": "Rauschunterdrückung",
"settings.drawerOverlayed": "Seitenpanel verdeckt Hauptinhalt", "settings.drawerOverlayed": "Seitenpanel verdeckt Hauptinhalt",
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "Fehler beim Speichern der Datei", "filesharing.saveFileError": "Fehler beim Speichern der Datei",
"filesharing.startingFileShare": "Starte Teilen der Datei", "filesharing.startingFileShare": "Starte Teilen der Datei",
@ -189,5 +192,9 @@
"moderator.clearFiles": "Moderator hat geteilte Dateiliste gelöscht", "moderator.clearFiles": "Moderator hat geteilte Dateiliste gelöscht",
"moderator.muteAudio": "Moderator hat dich stummgeschaltet", "moderator.muteAudio": "Moderator hat dich stummgeschaltet",
"moderator.muteVideo": "Moderator hat dein Video gestoppt", "moderator.muteVideo": "Moderator hat dein Video gestoppt",
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -119,6 +119,7 @@
"label.addVideo": null, "label.addVideo": null,
"label.promoteAllPeers": null, "label.promoteAllPeers": null,
"label.moreActions": null, "label.moreActions": null,
"label.version": null,
"settings.settings": "Indstillinger", "settings.settings": "Indstillinger",
"settings.camera": "Kamera", "settings.camera": "Kamera",
@ -144,6 +145,8 @@
"settings.autoGainControl": null, "settings.autoGainControl": null,
"settings.noiseSuppression": null, "settings.noiseSuppression": null,
"settings.drawerOverlayed": null, "settings.drawerOverlayed": null,
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "Kan ikke gemme fil", "filesharing.saveFileError": "Kan ikke gemme fil",
"filesharing.startingFileShare": "Forsøger at dele filen", "filesharing.startingFileShare": "Forsøger at dele filen",
@ -189,5 +192,9 @@
"moderator.clearFiles": null, "moderator.clearFiles": null,
"moderator.muteAudio": null, "moderator.muteAudio": null,
"moderator.muteVideo": null, "moderator.muteVideo": null,
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -119,6 +119,7 @@
"label.addVideo": null, "label.addVideo": null,
"label.promoteAllPeers": null, "label.promoteAllPeers": null,
"label.moreActions": null, "label.moreActions": null,
"label.version": null,
"settings.settings": "Ρυθμίσεις", "settings.settings": "Ρυθμίσεις",
"settings.camera": "Κάμερα", "settings.camera": "Κάμερα",
@ -144,6 +145,8 @@
"settings.autoGainControl": null, "settings.autoGainControl": null,
"settings.noiseSuppression": null, "settings.noiseSuppression": null,
"settings.drawerOverlayed": null, "settings.drawerOverlayed": null,
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "Αδυναμία αποθήκευσης του αρχείου", "filesharing.saveFileError": "Αδυναμία αποθήκευσης του αρχείου",
"filesharing.startingFileShare": "Προσπάθεια διαμοιρασμού αρχείου", "filesharing.startingFileShare": "Προσπάθεια διαμοιρασμού αρχείου",
@ -189,5 +192,9 @@
"moderator.clearFiles": null, "moderator.clearFiles": null,
"moderator.muteAudio": null, "moderator.muteAudio": null,
"moderator.muteVideo": null, "moderator.muteVideo": null,
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -119,6 +119,7 @@
"label.addVideo": "Add video", "label.addVideo": "Add video",
"label.promoteAllPeers": "Promote all", "label.promoteAllPeers": "Promote all",
"label.moreActions": "More actions", "label.moreActions": "More actions",
"label.version": "Version",
"settings.settings": "Settings", "settings.settings": "Settings",
"settings.camera": "Camera", "settings.camera": "Camera",
@ -144,6 +145,8 @@
"settings.autoGainControl": "Auto gain control", "settings.autoGainControl": "Auto gain control",
"settings.noiseSuppression": "Noise suppression", "settings.noiseSuppression": "Noise suppression",
"settings.drawerOverlayed": "Side drawer over content", "settings.drawerOverlayed": "Side drawer over content",
"settings.voiceActivatedUnmute": "Voice activated unmute",
"settings.noiseThreshold": "Noise threshold",
"filesharing.saveFileError": "Unable to save file", "filesharing.saveFileError": "Unable to save file",
"filesharing.startingFileShare": "Attempting to share file", "filesharing.startingFileShare": "Attempting to share file",
@ -189,5 +192,9 @@
"moderator.clearFiles": "Moderator cleared the files", "moderator.clearFiles": "Moderator cleared the files",
"moderator.muteAudio": "Moderator muted your audio", "moderator.muteAudio": "Moderator muted your audio",
"moderator.muteVideo": "Moderator muted your video", "moderator.muteVideo": "Moderator muted your video",
"moderator.muteScreenSharing": "Moderator muted your screen sharing" "moderator.stopScreenSharing": "Moderator stopped your screen sharing",
"unsupportedBrowser.titleUsnsupportedBrowser": "Detected unsupported browser!",
"unsupportedBrowser.titlewebrtcUnavailable": "Required functionality not available in your browser!",
"unsupportedBrowser.bodyText": "This meeting service requires a functionality that is not supported by your browser. Please upgrade, or switch to a different browser, or check your settings. Supported browsers:"
} }

View File

@ -119,6 +119,7 @@
"label.addVideo": null, "label.addVideo": null,
"label.promoteAllPeers": null, "label.promoteAllPeers": null,
"label.moreActions": null, "label.moreActions": null,
"label.version": null,
"settings.settings": "Ajustes", "settings.settings": "Ajustes",
"settings.camera": "Cámara", "settings.camera": "Cámara",
@ -144,6 +145,8 @@
"settings.autoGainControl": null, "settings.autoGainControl": null,
"settings.noiseSuppression": null, "settings.noiseSuppression": null,
"settings.drawerOverlayed": null, "settings.drawerOverlayed": null,
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "No ha sido posible guardar el fichero", "filesharing.saveFileError": "No ha sido posible guardar el fichero",
"filesharing.startingFileShare": "Intentando compartir el fichero", "filesharing.startingFileShare": "Intentando compartir el fichero",
@ -189,5 +192,9 @@
"moderator.clearFiles": null, "moderator.clearFiles": null,
"moderator.muteAudio": null, "moderator.muteAudio": null,
"moderator.muteVideo": null, "moderator.muteVideo": null,
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -119,6 +119,7 @@
"label.addVideo": null, "label.addVideo": null,
"label.promoteAllPeers": null, "label.promoteAllPeers": null,
"label.moreActions": null, "label.moreActions": null,
"label.version": null,
"settings.settings": "Paramètres", "settings.settings": "Paramètres",
"settings.camera": "Caméra", "settings.camera": "Caméra",
@ -144,6 +145,8 @@
"settings.autoGainControl": null, "settings.autoGainControl": null,
"settings.noiseSuppression": null, "settings.noiseSuppression": null,
"settings.drawerOverlayed": null, "settings.drawerOverlayed": null,
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "Impossible d'enregistrer le fichier", "filesharing.saveFileError": "Impossible d'enregistrer le fichier",
"filesharing.startingFileShare": "Début du transfert de fichier", "filesharing.startingFileShare": "Début du transfert de fichier",
@ -188,5 +191,9 @@
"moderator.clearFiles": null, "moderator.clearFiles": null,
"moderator.muteAudio": null, "moderator.muteAudio": null,
"moderator.muteVideo": null, "moderator.muteVideo": null,
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -119,6 +119,7 @@
"label.addVideo": "Dodaj video", "label.addVideo": "Dodaj video",
"label.promoteAllPeers": "Promoviraj sve", "label.promoteAllPeers": "Promoviraj sve",
"label.moreActions": "Više akcija", "label.moreActions": "Više akcija",
"label.version": null,
"settings.settings": "Postavke", "settings.settings": "Postavke",
"settings.camera": "Kamera", "settings.camera": "Kamera",
@ -144,6 +145,8 @@
"settings.autoGainControl": "Automatsko upravljanje jačinom zvuka", "settings.autoGainControl": "Automatsko upravljanje jačinom zvuka",
"settings.noiseSuppression": "Poništavanje šuma", "settings.noiseSuppression": "Poništavanje šuma",
"settings.drawerOverlayed": "Bočni izbornik iznad sadržaja", "settings.drawerOverlayed": "Bočni izbornik iznad sadržaja",
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "Nije moguće spremiti datoteku", "filesharing.saveFileError": "Nije moguće spremiti datoteku",
"filesharing.startingFileShare": "Pokušaj dijeljenja datoteke", "filesharing.startingFileShare": "Pokušaj dijeljenja datoteke",
@ -189,5 +192,9 @@
"moderator.clearFiles": "Moderator je izbrisao datoteke", "moderator.clearFiles": "Moderator je izbrisao datoteke",
"moderator.muteAudio": "Moderator je utišao tvoj zvuk", "moderator.muteAudio": "Moderator je utišao tvoj zvuk",
"moderator.muteVideo": "Moderator je zaustavio tvoj video", "moderator.muteVideo": "Moderator je zaustavio tvoj video",
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -66,7 +66,7 @@
"room.browsePeersSpotlight": "Résztvevők böngészése", "room.browsePeersSpotlight": "Résztvevők böngészése",
"room.stopAllScreenSharing": "Összes képernyőmegosztás leállítása", "room.stopAllScreenSharing": "Összes képernyőmegosztás leállítása",
"me.mutedPTT": "Némítva vagy, ha beszélnél nyomd le a szóköz billentyűt", "me.mutedPTT": "Némítva vagy, ha beszélnél nyomd le a SZÓKÖZ billentyűt",
"roles.gotRole": "{role} szerepet kaptál", "roles.gotRole": "{role} szerepet kaptál",
"roles.lostRole": "Elvesztetted a {role} szerepet", "roles.lostRole": "Elvesztetted a {role} szerepet",
@ -86,9 +86,9 @@
"tooltip.muteParticipantVideo": "Résztvevő videóstreamének némítása", "tooltip.muteParticipantVideo": "Résztvevő videóstreamének némítása",
"tooltip.raisedHand": "Jelentkezés", "tooltip.raisedHand": "Jelentkezés",
"tooltip.muteScreenSharing": "Képernyőmegosztás szüneteltetése", "tooltip.muteScreenSharing": "Képernyőmegosztás szüneteltetése",
"tooltip.muteParticipantAudioModerator": "Résztvevő hangjának általános némítása", "tooltip.muteParticipantAudioModerator": "Résztvevő hangjának némítása mindenkinél",
"tooltip.muteParticipantVideoModerator": "Résztvevő videójának általános némítása", "tooltip.muteParticipantVideoModerator": "Résztvevő videójának némítása mindenkinél",
"tooltip.muteScreenSharingModerator": "Résztvevő képernyőmegosztásának általános némítása", "tooltip.muteScreenSharingModerator": "Résztvevő képernyőmegosztásának leállítása mindenkinél",
"label.roomName": "Konferencia", "label.roomName": "Konferencia",
"label.chooseRoomButton": "Tovább", "label.chooseRoomButton": "Tovább",
@ -119,6 +119,7 @@
"label.addVideo": "Videó hozzáadása", "label.addVideo": "Videó hozzáadása",
"label.promoteAllPeers": "Mindenkit beengedek", "label.promoteAllPeers": "Mindenkit beengedek",
"label.moreActions": "További műveletek", "label.moreActions": "További műveletek",
"label.version": "Verzió",
"settings.settings": "Beállítások", "settings.settings": "Beállítások",
"settings.camera": "Kamera", "settings.camera": "Kamera",
@ -144,6 +145,8 @@
"settings.autoGainControl": "Automatikus hangerő", "settings.autoGainControl": "Automatikus hangerő",
"settings.noiseSuppression": "Zajelnyomás", "settings.noiseSuppression": "Zajelnyomás",
"settings.drawerOverlayed": "Oldalsáv a tartalom felett", "settings.drawerOverlayed": "Oldalsáv a tartalom felett",
"settings.voiceActivatedUnmute": "Beszéd aktivált mikrofon némítás",
"settings.noiseThreshold": "Zajszint",
"filesharing.saveFileError": "A file-t nem sikerült elmenteni", "filesharing.saveFileError": "A file-t nem sikerült elmenteni",
"filesharing.startingFileShare": "Fájl megosztása", "filesharing.startingFileShare": "Fájl megosztása",
@ -189,5 +192,9 @@
"moderator.clearFiles": "A moderátor kiürítette a file megosztás történelmet", "moderator.clearFiles": "A moderátor kiürítette a file megosztás történelmet",
"moderator.muteAudio": "A moderátor elnémította a hangod", "moderator.muteAudio": "A moderátor elnémította a hangod",
"moderator.muteVideo": "A moderátor elnémította a videód", "moderator.muteVideo": "A moderátor elnémította a videód",
"moderator.muteScreenSharing": "A moderátor leállította képernyőmegosztásod" "moderator.stopScreenSharing": "A moderátor leállította a képernyőmegosztásod",
"unsupportedBrowser.titleUnsupportedBrowser": "A bőngésző verziód sajnos nem támogatott! :-(",
"unsupportedBrowser.titlewebrtcUnavailable": "A böngésződ egy szükséges funkciója nem elérhető!",
"unsupportedBrowser.bodyText": "Kérlek frissítsd a böngésződ, válts másik böngészőre, vagy ellenőrizd a böngésződ beállításait! Támogatott böngészők:"
} }

View File

@ -119,6 +119,7 @@
"label.addVideo": "Aggiungi video", "label.addVideo": "Aggiungi video",
"label.promoteAllPeers": "Promuovi tutti", "label.promoteAllPeers": "Promuovi tutti",
"label.moreActions": "Altre azioni", "label.moreActions": "Altre azioni",
"label.version": null,
"settings.settings": "Impostazioni", "settings.settings": "Impostazioni",
"settings.camera": "Videocamera", "settings.camera": "Videocamera",
@ -144,6 +145,8 @@
"settings.autoGainControl": "Controllo guadagno automatico", "settings.autoGainControl": "Controllo guadagno automatico",
"settings.noiseSuppression": "Riduzione del rumore", "settings.noiseSuppression": "Riduzione del rumore",
"settings.drawerOverlayed": "Barra laterale sovrapposta", "settings.drawerOverlayed": "Barra laterale sovrapposta",
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "Impossibile salvare file", "filesharing.saveFileError": "Impossibile salvare file",
"filesharing.startingFileShare": "Tentativo di condivisione file", "filesharing.startingFileShare": "Tentativo di condivisione file",
@ -189,5 +192,9 @@
"moderator.clearFiles": "Il moderatore ha pulito i file", "moderator.clearFiles": "Il moderatore ha pulito i file",
"moderator.muteAudio": "Il moderatore ha mutato il tuo audio", "moderator.muteAudio": "Il moderatore ha mutato il tuo audio",
"moderator.muteVideo": "Il moderatore ha fermato il tuo video", "moderator.muteVideo": "Il moderatore ha fermato il tuo video",
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -116,6 +116,7 @@
"label.advanced": "Advancēts", "label.advanced": "Advancēts",
"label.addVideo": "Pievienot video", "label.addVideo": "Pievienot video",
"label.moreActions": null, "label.moreActions": null,
"label.version": null,
"settings.settings": "Iestatījumi", "settings.settings": "Iestatījumi",
"settings.camera": "Kamera", "settings.camera": "Kamera",
@ -138,6 +139,8 @@
"settings.autoGainControl": null, "settings.autoGainControl": null,
"settings.noiseSuppression": null, "settings.noiseSuppression": null,
"settings.drawerOverlayed": null, "settings.drawerOverlayed": null,
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "Nav iespējams saglabāt failu", "filesharing.saveFileError": "Nav iespējams saglabāt failu",
"filesharing.startingFileShare": "Tiek mēģināts kopīgot failu", "filesharing.startingFileShare": "Tiek mēģināts kopīgot failu",
@ -183,5 +186,9 @@
"moderator.clearFiles": "Moderators notīrīja failus", "moderator.clearFiles": "Moderators notīrīja failus",
"moderator.muteAudio": "Moderators noklusināja jūsu mikrofonu", "moderator.muteAudio": "Moderators noklusināja jūsu mikrofonu",
"moderator.muteVideo": "Moderators atslēdza jūsu kameru", "moderator.muteVideo": "Moderators atslēdza jūsu kameru",
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -119,6 +119,7 @@
"label.addVideo": "Legg til video", "label.addVideo": "Legg til video",
"label.promoteAllPeers": "Slipp inn alle", "label.promoteAllPeers": "Slipp inn alle",
"label.moreActions": "Flere handlinger", "label.moreActions": "Flere handlinger",
"label.version": null,
"settings.settings": "Innstillinger", "settings.settings": "Innstillinger",
"settings.camera": "Kamera", "settings.camera": "Kamera",
@ -144,6 +145,8 @@
"settings.autoGainControl": "Auto gain kontroll", "settings.autoGainControl": "Auto gain kontroll",
"settings.noiseSuppression": "Støy reduksjon", "settings.noiseSuppression": "Støy reduksjon",
"settings.drawerOverlayed": "Sidemeny over innhold", "settings.drawerOverlayed": "Sidemeny over innhold",
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "Klarte ikke å lagre fil", "filesharing.saveFileError": "Klarte ikke å lagre fil",
"filesharing.startingFileShare": "Starter fildeling", "filesharing.startingFileShare": "Starter fildeling",
@ -189,5 +192,9 @@
"moderator.clearFiles": "Moderator fjernet filer", "moderator.clearFiles": "Moderator fjernet filer",
"moderator.muteAudio": "Moderator mutet lyden din", "moderator.muteAudio": "Moderator mutet lyden din",
"moderator.muteVideo": "Moderator mutet videoen din", "moderator.muteVideo": "Moderator mutet videoen din",
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -119,6 +119,7 @@
"label.addVideo": "Dodaj wideo", "label.addVideo": "Dodaj wideo",
"label.promoteAllPeers": "Wpuść wszystkich", "label.promoteAllPeers": "Wpuść wszystkich",
"label.moreActions": "Więcej akcji", "label.moreActions": "Więcej akcji",
"label.version": null,
"settings.settings": "Ustawienia", "settings.settings": "Ustawienia",
"settings.camera": "Kamera", "settings.camera": "Kamera",
@ -144,6 +145,8 @@
"settings.autoGainControl": "Auto korekta wzmocnienia", "settings.autoGainControl": "Auto korekta wzmocnienia",
"settings.noiseSuppression": "Wyciszenie szumów", "settings.noiseSuppression": "Wyciszenie szumów",
"settings.drawerOverlayed": "Szuflada nad zawartością", "settings.drawerOverlayed": "Szuflada nad zawartością",
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "Nie można zapisać pliku", "filesharing.saveFileError": "Nie można zapisać pliku",
"filesharing.startingFileShare": "Próba udostępnienia pliku", "filesharing.startingFileShare": "Próba udostępnienia pliku",
@ -189,5 +192,9 @@
"moderator.clearFiles": "Moderator wyczyścił pliki", "moderator.clearFiles": "Moderator wyczyścił pliki",
"moderator.muteAudio": "Moderator wyciszył audio", "moderator.muteAudio": "Moderator wyciszył audio",
"moderator.muteVideo": "Moderator wyciszył twoje video", "moderator.muteVideo": "Moderator wyciszył twoje video",
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -119,6 +119,7 @@
"label.addVideo": null, "label.addVideo": null,
"label.promoteAllPeers": null, "label.promoteAllPeers": null,
"label.moreActions": null, "label.moreActions": null,
"label.version": null,
"settings.settings": "Definições", "settings.settings": "Definições",
"settings.camera": "Camera", "settings.camera": "Camera",
@ -144,6 +145,8 @@
"settings.autoGainControl": null, "settings.autoGainControl": null,
"settings.noiseSuppression": null, "settings.noiseSuppression": null,
"settings.drawerOverlayed": null, "settings.drawerOverlayed": null,
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "Impossível de gravar o ficheiro", "filesharing.saveFileError": "Impossível de gravar o ficheiro",
"filesharing.startingFileShare": "Tentando partilha de ficheiro", "filesharing.startingFileShare": "Tentando partilha de ficheiro",
@ -189,5 +192,9 @@
"moderator.clearFiles": null, "moderator.clearFiles": null,
"moderator.muteAudio": null, "moderator.muteAudio": null,
"moderator.muteVideo": null, "moderator.muteVideo": null,
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -119,6 +119,7 @@
"label.addVideo": null, "label.addVideo": null,
"label.promoteAllPeers": null, "label.promoteAllPeers": null,
"label.moreActions": null, "label.moreActions": null,
"label.version": null,
"settings.settings": "Setări", "settings.settings": "Setări",
"settings.camera": "Cameră video", "settings.camera": "Cameră video",
@ -144,6 +145,8 @@
"settings.autoGainControl": null, "settings.autoGainControl": null,
"settings.noiseSuppression": null, "settings.noiseSuppression": null,
"settings.drawerOverlayed": null, "settings.drawerOverlayed": null,
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "Încercarea de a salva fișierul a eșuat", "filesharing.saveFileError": "Încercarea de a salva fișierul a eșuat",
"filesharing.startingFileShare": "Partajarea fișierului", "filesharing.startingFileShare": "Partajarea fișierului",
@ -189,5 +192,9 @@
"moderator.clearFiles": null, "moderator.clearFiles": null,
"moderator.muteAudio": null, "moderator.muteAudio": null,
"moderator.muteVideo": null, "moderator.muteVideo": null,
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -119,6 +119,7 @@
"label.addVideo": null, "label.addVideo": null,
"label.promoteAllPeers": null, "label.promoteAllPeers": null,
"label.moreActions": null, "label.moreActions": null,
"label.version": null,
"settings.settings": "Ayarlar", "settings.settings": "Ayarlar",
"settings.camera": "Kamera", "settings.camera": "Kamera",
@ -141,6 +142,8 @@
"settings.autoGainControl": null, "settings.autoGainControl": null,
"settings.noiseSuppression": null, "settings.noiseSuppression": null,
"settings.drawerOverlayed": null, "settings.drawerOverlayed": null,
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "Dosya kaydedilemiyor", "filesharing.saveFileError": "Dosya kaydedilemiyor",
"filesharing.startingFileShare": "Paylaşılan dosyaya erişiliyor", "filesharing.startingFileShare": "Paylaşılan dosyaya erişiliyor",
@ -181,5 +184,14 @@
"devices.cameraDisconnected": "Kamera bağlı değil", "devices.cameraDisconnected": "Kamera bağlı değil",
"devices.cameraError": "Kameranıza erişilirken bir hata oluştu", "devices.cameraError": "Kameranıza erişilirken bir hata oluştu",
"moderator.muteScreenSharing": null
"moderator.clearChat": null,
"moderator.clearFiles": null,
"moderator.muteAudio": null,
"moderator.muteVideo": null,
"moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -118,6 +118,7 @@
"label.addVideo": "新增視訊", "label.addVideo": "新增視訊",
"label.promoteAllPeers": "提升全部", "label.promoteAllPeers": "提升全部",
"label.moreActions": "更多", "label.moreActions": "更多",
"label.version": null,
"settings.settings": "設置", "settings.settings": "設置",
"settings.camera": "視訊來源", "settings.camera": "視訊來源",
@ -143,6 +144,8 @@
"settings.autoGainControl": "自動增益控制", "settings.autoGainControl": "自動增益控制",
"settings.noiseSuppression": "噪音消除", "settings.noiseSuppression": "噪音消除",
"settings.drawerOverlayed": "側邊欄覆蓋畫面", "settings.drawerOverlayed": "側邊欄覆蓋畫面",
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "無法保存文件", "filesharing.saveFileError": "無法保存文件",
"filesharing.startingFileShare": "開始分享文件", "filesharing.startingFileShare": "開始分享文件",
@ -188,5 +191,9 @@
"moderator.clearFiles": "管理員清除了所有檔案", "moderator.clearFiles": "管理員清除了所有檔案",
"moderator.muteAudio": "您已被管理員靜音", "moderator.muteAudio": "您已被管理員靜音",
"moderator.muteVideo": "您的視訊已被管理員關閉", "moderator.muteVideo": "您的視訊已被管理員關閉",
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -119,6 +119,7 @@
"label.addVideo": null, "label.addVideo": null,
"label.promoteAllPeers": null, "label.promoteAllPeers": null,
"label.moreActions": null, "label.moreActions": null,
"label.version": null,
"settings.settings": "Налаштування", "settings.settings": "Налаштування",
"settings.camera": "Камера", "settings.camera": "Камера",
@ -144,6 +145,8 @@
"settings.autoGainControl": null, "settings.autoGainControl": null,
"settings.noiseSuppression": null, "settings.noiseSuppression": null,
"settings.drawerOverlayed": null, "settings.drawerOverlayed": null,
"settings.voiceActivatedUnmute": null,
"settings.noiseThreshold": null,
"filesharing.saveFileError": "Неможливо зберегти файл", "filesharing.saveFileError": "Неможливо зберегти файл",
"filesharing.startingFileShare": "Спроба поділитися файлом", "filesharing.startingFileShare": "Спроба поділитися файлом",
@ -189,5 +192,9 @@
"moderator.clearFiles": null, "moderator.clearFiles": null,
"moderator.muteAudio": null, "moderator.muteAudio": null,
"moderator.muteVideo": null, "moderator.muteVideo": null,
"moderator.muteScreenSharing": null "moderator.stopScreenSharing": null,
"unsupportedBrowser.titleUnsupportedBrowser": null,
"unsupportedBrowser.titlewebrtcUnavailable": null,
"unsupportedBrowser.bodyText": null
} }

View File

@ -17,3 +17,21 @@ export const idle = (callback, delay) =>
handle = setTimeout(callback, delay); handle = setTimeout(callback, delay);
}; };
}; };
/**
* Error produced when a socket request has a timeout.
*/
export class SocketTimeoutError extends Error
{
constructor(message)
{
super(message);
this.name = 'SocketTimeoutError';
if (Error.hasOwnProperty('captureStackTrace')) // Just in V8.
Error.captureStackTrace(this, SocketTimeoutError);
else
this.stack = (new Error(message)).stack;
}
}

View File

@ -106,6 +106,12 @@
"no-invalid-regexp": 2, "no-invalid-regexp": 2,
"no-invalid-this": 2, "no-invalid-this": 2,
"no-irregular-whitespace": 2, "no-irregular-whitespace": 2,
"no-trailing-spaces": [
"error",
{
"ignoreComments": true
}
],
"no-lonely-if": 2, "no-lonely-if": 2,
"no-mixed-operators": 2, "no-mixed-operators": 2,
"no-mixed-spaces-and-tabs": 2, "no-mixed-spaces-and-tabs": 2,

View File

@ -276,6 +276,10 @@ module.exports =
// maxUsersPerRoom : 20, // maxUsersPerRoom : 20,
// Room size before spreading to new router // Room size before spreading to new router
routerScaleSize : 40, routerScaleSize : 40,
// Socket timout value
requestTimeout : 20000,
// Socket retries when timeout
requestRetries : 3,
// Mediasoup settings // Mediasoup settings
mediasoup : mediasoup :
{ {

View File

@ -3,6 +3,7 @@ const AwaitQueue = require('awaitqueue');
const axios = require('axios'); const axios = require('axios');
const Logger = require('./Logger'); const Logger = require('./Logger');
const Lobby = require('./Lobby'); const Lobby = require('./Lobby');
const { SocketTimeoutError } = require('./errors');
const { v4: uuidv4 } = require('uuid'); const { v4: uuidv4 } = require('uuid');
const jwt = require('jsonwebtoken'); const jwt = require('jsonwebtoken');
const userRoles = require('../userRoles'); const userRoles = require('../userRoles');
@ -1759,9 +1760,9 @@ class Room extends EventEmitter
if (called) if (called)
return; return;
called = true; called = true;
callback(new Error('Request timeout.')); callback(new SocketTimeoutError('Request timed out'));
}, },
10000 config.requestTimeout || 20000
); );
return (...args) => return (...args) =>
@ -1775,7 +1776,7 @@ class Room extends EventEmitter
}; };
} }
_request(socket, method, data = {}) _sendRequest(socket, method, data = {})
{ {
return new Promise((resolve, reject) => return new Promise((resolve, reject) =>
{ {
@ -1797,6 +1798,33 @@ class Room extends EventEmitter
}); });
} }
async _request(socket, method, data)
{
logger.debug('_request() [method:"%s", data:"%o"]', method, data);
const {
requestRetries = 3
} = config;
for (let tries = 0; tries < requestRetries; tries++)
{
try
{
return await this._sendRequest(socket, method, data);
}
catch (error)
{
if (
error instanceof SocketTimeoutError &&
tries < requestRetries
)
logger.warn('_request() | timeout, retrying [attempt:"%s"]', tries);
else
throw error;
}
}
}
_notification(socket, method, data = {}, broadcast = false, includeSender = false) _notification(socket, method, data = {}, broadcast = false, includeSender = false)
{ {
if (broadcast) if (broadcast)

View File

@ -0,0 +1,22 @@
/**
* Error produced when a socket request has a timeout.
*/
class SocketTimeoutError extends Error
{
constructor(message)
{
super(message);
this.name = 'SocketTimeoutError';
if (Error.hasOwnProperty('captureStackTrace')) // Just in V8.
Error.captureStackTrace(this, SocketTimeoutError);
else
this.stack = (new Error(message)).stack;
}
}
module.exports =
{
SocketTimeoutError
};