Merge pull request #4 from havfo/develop

sync with upstream repo
auto_join_3.3
Saša Davidović 2020-05-07 12:53:09 +02:00 committed by GitHub
commit 99a9ec7d1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 1086 additions and 431 deletions

View File

@ -27,6 +27,7 @@
"react": "^16.10.2",
"react-cookie-consent": "^2.5.0",
"react-dom": "^16.10.2",
"react-flip-toolkit": "^7.0.9",
"react-intl": "^3.4.0",
"react-redux": "^7.1.1",
"react-router-dom": "^5.1.2",

View File

@ -42,6 +42,17 @@ var config =
{
tcp : true
},
defaultAudio :
{
sampleRate : 48000,
channelCount : 1,
volume : 1.0,
autoGainControl : true,
echoCancellation : true,
noiseSuppression : true,
sampleSize : 16
},
background : 'images/background.jpg',
defaultLayout : 'democratic', // democratic, filmstrip
lastN : 4,
mobileLastN : 1,
@ -49,7 +60,6 @@ var config =
maxLastN : 5,
// If truthy, users can NOT change number of speakers visible
lockLastN : false,
background : 'images/background.jpg',
// Add file and uncomment for adding logo to appbar
// logo : 'images/logo.svg',
title : 'Multiparty meeting',

View File

@ -475,9 +475,9 @@ export default class RoomClient
window.open(url, 'loginWindow');
}
logout()
logout(roomId = this._roomId)
{
window.open('/auth/logout', 'logoutWindow');
window.open(`/auth/logout?peerId=${this._peerId}&roomId=${roomId}`, 'logoutWindow');
}
receiveLoginChildWindow(data)
@ -953,20 +953,65 @@ export default class RoomClient
}
}
async getAudioTrack()
disconnectLocalHark()
{
await navigator.mediaDevices.getUserMedia(
{
audio : true, video : false
});
logger.debug('disconnectLocalHark() | Stopping harkStream.');
if (this._harkStream != null)
{
this._harkStream.getAudioTracks()[0].stop();
this._harkStream = null;
}
if (this._hark != null)
{
logger.debug('disconnectLocalHark() Stopping hark.');
this._hark.stop();
}
}
async getVideoTrack()
connectLocalHark(track)
{
await navigator.mediaDevices.getUserMedia(
logger.debug('connectLocalHark() | Track:%o', track);
this._harkStream = new MediaStream();
this._harkStream.addTrack(track.clone());
this._harkStream.getAudioTracks()[0].enabled = true;
if (!this._harkStream.getAudioTracks()[0])
throw new Error('getMicStream():something went wrong with hark');
this._hark = hark(this._harkStream, { play: false });
// eslint-disable-next-line no-unused-vars
this._hark.on('volume_change', (dBs, threshold) =>
{
// The exact formula to convert from dBs (-100..0) to linear (0..1) is:
// Math.pow(10, dBs / 20)
// However it does not produce a visually useful output, so let exagerate
// it a bit. Also, let convert it from 0..1 to 0..10 and avoid value 1 to
// minimize component renderings.
let volume = Math.round(Math.pow(10, dBs / 85) * 10);
if (volume === 1)
volume = 0;
volume = Math.round(volume);
if (this._micProducer && volume !== this._micProducer.volume)
{
audio : false, video : true
});
this._micProducer.volume = volume;
store.dispatch(peerVolumeActions.setPeerVolume(this._peerId, volume));
}
});
this._hark.on('speaking', function()
{
store.dispatch(meActions.setIsSpeaking(true));
});
this._hark.on('stopped_speaking', function()
{
store.dispatch(meActions.setIsSpeaking(false));
});
}
async changeAudioDevice(deviceId)
@ -977,7 +1022,7 @@ export default class RoomClient
meActions.setAudioInProgress(true));
try
{
{
const device = this._audioDevices[deviceId];
if (!device)
@ -987,29 +1032,30 @@ export default class RoomClient
'changeAudioDevice() | new selected webcam [device:%o]',
device);
if (this._hark != null)
this._hark.stop();
if (this._harkStream != null)
{
logger.debug('Stopping hark.');
this._harkStream.getAudioTracks()[0].stop();
this._harkStream = null;
}
this.disconnectLocalHark();
if (this._micProducer && this._micProducer.track)
this._micProducer.track.stop();
logger.debug('changeAudioDevice() | calling getUserMedia()');
logger.debug('changeAudioDevice() | calling getUserMedia() %o', store.getState().settings);
const stream = await navigator.mediaDevices.getUserMedia(
{
audio :
{
deviceId : { exact: device.deviceId }
deviceId : { ideal: device.deviceId },
sampleRate : store.getState().settings.sampleRate,
channelCount : store.getState().settings.channelCount,
volume : store.getState().settings.volume,
autoGainControl : store.getState().settings.autoGainControl,
echoCancellation : store.getState().settings.echoCancellation,
noiseSuppression : store.getState().settings.noiseSuppression,
sampleSize : store.getState().settings.sampleSize
}
});
}
);
logger.debug('Constraints: %o', stream.getAudioTracks()[0].getConstraints());
const track = stream.getAudioTracks()[0];
if (this._micProducer)
@ -1017,47 +1063,8 @@ export default class RoomClient
if (this._micProducer)
this._micProducer.volume = 0;
this.connectLocalHark(track);
this._harkStream = new MediaStream();
this._harkStream.addTrack(track.clone());
this._harkStream.getAudioTracks()[0].enabled = true;
if (!this._harkStream.getAudioTracks()[0])
throw new Error('changeAudioDevice(): given stream has no audio track');
this._hark = hark(this._harkStream, { play: false });
// eslint-disable-next-line no-unused-vars
this._hark.on('volume_change', (dBs, threshold) =>
{
// The exact formula to convert from dBs (-100..0) to linear (0..1) is:
// Math.pow(10, dBs / 20)
// However it does not produce a visually useful output, so let exaggerate
// it a bit. Also, let convert it from 0..1 to 0..10 and avoid value 1 to
// minimize component renderings.
let volume = Math.round(Math.pow(10, dBs / 85) * 10);
if (volume === 1)
volume = 0;
volume = Math.round(volume);
if (this._micProducer && volume !== this._micProducer.volume)
{
this._micProducer.volume = volume;
store.dispatch(peerVolumeActions.setPeerVolume(this._peerId, volume));
}
});
this._hark.on('speaking', function()
{
store.dispatch(meActions.setIsSpeaking(true));
});
this._hark.on('stopped_speaking', function()
{
store.dispatch(meActions.setIsSpeaking(false));
});
if (this._micProducer && this._micProducer.id)
store.dispatch(
producerActions.setProducerTrack(this._micProducer.id, track));
@ -1533,6 +1540,26 @@ export default class RoomClient
}
}
async lowerPeerHand(peerId)
{
logger.debug('lowerPeerHand() [peerId:"%s"]', peerId);
store.dispatch(
peerActions.setPeerRaisedHandInProgress(peerId, true));
try
{
await this.sendRequest('moderator:lowerHand', { peerId });
}
catch (error)
{
logger.error('lowerPeerHand() | [error:"%o"]', error);
}
store.dispatch(
peerActions.setPeerRaisedHandInProgress(peerId, false));
}
async setRaisedHand(raisedHand)
{
logger.debug('setRaisedHand: ', raisedHand);
@ -2534,6 +2561,13 @@ export default class RoomClient
break;
}
case 'moderator:lowerHand':
{
this.setRaisedHand(false);
break;
}
case 'gotRole':
{
const { peerId, role } = notification.data;
@ -2811,7 +2845,9 @@ export default class RoomClient
{
text : intl.formatMessage({
id : 'roles.gotRole',
defaultMessage : `You got the role: ${role}`
defaultMessage : 'You got the role: {role}'
}, {
role
})
}));
}
@ -3233,11 +3269,20 @@ export default class RoomClient
const stream = await navigator.mediaDevices.getUserMedia(
{
audio : {
deviceId : { ideal: deviceId }
deviceId : { ideal: device.deviceId },
sampleRate : store.getState().settings.sampleRate,
channelCount : store.getState().settings.channelCount,
volume : store.getState().settings.volume,
autoGainControl : store.getState().settings.autoGainControl,
echoCancellation : store.getState().settings.echoCancellation,
noiseSuppression : store.getState().settings.noiseSuppression,
sampleSize : store.getState().settings.sampleSize
}
}
);
logger.debug('Constraints: %o', stream.getAudioTracks()[0].getConstraints());
track = stream.getAudioTracks()[0];
this._micProducer = await this._sendTransport.produce(
@ -3291,51 +3336,8 @@ export default class RoomClient
this._micProducer.volume = 0;
if (this._hark != null)
this._hark.stop();
this.connectLocalHark(track);
if (this._harkStream != null)
this._harkStream.getAudioTracks()[0].stop();
this._harkStream = new MediaStream();
this._harkStream.addTrack(track.clone());
if (!this._harkStream.getAudioTracks()[0])
throw new Error('enableMic(): given stream has no audio track');
this._hark = hark(this._harkStream, { play: false });
// eslint-disable-next-line no-unused-vars
this._hark.on('volume_change', (dBs, threshold) =>
{
// The exact formula to convert from dBs (-100..0) to linear (0..1) is:
// Math.pow(10, dBs / 20)
// However it does not produce a visually useful output, so let exaggerate
// it a bit. Also, let convert it from 0..1 to 0..10 and avoid value 1 to
// minimize component renderings.
let volume = Math.round(Math.pow(10, dBs / 85) * 10);
if (volume === 1)
volume = 0;
volume = Math.round(volume);
if (this._micProducer && volume !== this._micProducer.volume)
{
this._micProducer.volume = volume;
store.dispatch(peerVolumeActions.setPeerVolume(this._peerId, volume));
}
});
this._hark.on('speaking', function()
{
store.dispatch(meActions.setIsSpeaking(true));
});
this._hark.on('stopped_speaking', function()
{
store.dispatch(meActions.setIsSpeaking(false));
});
}
catch (error)
{

View File

@ -40,6 +40,12 @@ export const setPeerRaisedHand = (peerId, raisedHand, raisedHandTimestamp) =>
payload : { peerId, raisedHand, raisedHandTimestamp }
});
export const setPeerRaisedHandInProgress = (peerId, flag) =>
({
type : 'SET_PEER_RAISED_HAND_IN_PROGRESS',
payload : { peerId, flag }
});
export const setPeerPicture = (peerId, picture) =>
({
type : 'SET_PEER_PICTURE',

View File

@ -38,6 +38,50 @@ export const togglePermanentTopBar = () =>
type : 'TOGGLE_PERMANENT_TOPBAR'
});
export const toggleShowNotifications = () =>
({
type : 'TOGGLE_SHOW_NOTIFICATIONS'
});
export const setEchoCancellation = (echoCancellation) =>
({
type : 'SET_ECHO_CANCELLATION',
payload : { echoCancellation }
});
export const setAutoGainControl = (autoGainControl) =>
({
type : 'SET_AUTO_GAIN_CONTROL',
payload : { autoGainControl }
});
export const setNoiseSuppression = (noiseSuppression) =>
({
type : 'SET_NOISE_SUPPRESSION',
payload : { noiseSuppression }
});
export const setDefaultAudio = (audio) =>
({
type : 'SET_DEFAULT_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 = () =>
({
type : 'TOGGLE_HIDDEN_CONTROLS'

View File

@ -16,11 +16,13 @@ import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import MenuItem from '@material-ui/core/MenuItem';
import Menu from '@material-ui/core/Menu';
import Popover from '@material-ui/core/Popover';
import Typography from '@material-ui/core/Typography';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';
import Avatar from '@material-ui/core/Avatar';
import Badge from '@material-ui/core/Badge';
import Paper from '@material-ui/core/Paper';
import ExtensionIcon from '@material-ui/icons/Extension';
import AccountCircle from '@material-ui/icons/AccountCircle';
import FullScreenIcon from '@material-ui/icons/Fullscreen';
@ -33,6 +35,7 @@ import LockOpenIcon from '@material-ui/icons/LockOpen';
import VideoCallIcon from '@material-ui/icons/VideoCall';
import Button from '@material-ui/core/Button';
import Tooltip from '@material-ui/core/Tooltip';
import MoreIcon from '@material-ui/icons/MoreVert';
const styles = (theme) =>
({
@ -77,9 +80,17 @@ const styles = (theme) =>
display : 'block'
}
},
actionButtons :
{
display : 'flex'
sectionDesktop : {
display : 'none',
[theme.breakpoints.up('md')] : {
display : 'flex'
}
},
sectionMobile : {
display : 'flex',
[theme.breakpoints.up('md')] : {
display : 'none'
}
},
actionButton :
{
@ -96,7 +107,7 @@ const styles = (theme) =>
},
moreAction :
{
margin : theme.spacing(0, 0, 0, 1)
margin : theme.spacing(0.5, 0, 0.5, 1.5)
}
});
@ -135,16 +146,36 @@ const TopBar = (props) =>
{
const intl = useIntl();
const [ moreActionsElement, setMoreActionsElement ] = useState(null);
const [ mobileMoreAnchorEl, setMobileMoreAnchorEl ] = useState(null);
const [ anchorEl, setAnchorEl ] = useState(null);
const [ currentMenu, setCurrentMenu ] = useState(null);
const handleMoreActionsOpen = (event) =>
const handleExited = () =>
{
setMoreActionsElement(event.currentTarget);
setCurrentMenu(null);
};
const handleMoreActionsClose = () =>
const handleMobileMenuOpen = (event) =>
{
setMoreActionsElement(null);
setMobileMoreAnchorEl(event.currentTarget);
};
const handleMobileMenuClose = () =>
{
setMobileMoreAnchorEl(null);
};
const handleMenuOpen = (event, menu) =>
{
setAnchorEl(event.currentTarget);
setCurrentMenu(menu);
};
const handleMenuClose = () =>
{
setAnchorEl(null);
handleMobileMenuClose();
};
const {
@ -171,7 +202,8 @@ const TopBar = (props) =>
classes
} = props;
const isMoreActionsMenuOpen = Boolean(moreActionsElement);
const isMenuOpen = Boolean(anchorEl);
const isMobileMenuOpen = Boolean(mobileMoreAnchorEl);
const lockTooltip = room.locked ?
intl.formatMessage({
@ -239,10 +271,15 @@ const TopBar = (props) =>
{ window.config.title ? window.config.title : 'Multiparty meeting' }
</Typography>
<div className={classes.grow} />
<div className={classes.actionButtons}>
<div className={classes.sectionDesktop}>
<IconButton
aria-owns={
isMenuOpen &&
currentMenu === 'moreActions' ?
'material-appbar' : undefined
}
aria-haspopup='true'
onClick={handleMoreActionsOpen}
onClick={(event) => handleMenuOpen(event, 'moreActions')}
color='inherit'
>
<ExtensionIcon />
@ -386,52 +423,253 @@ const TopBar = (props) =>
</IconButton>
</Tooltip>
}
<div className={classes.divider} />
<Button
aria-label={intl.formatMessage({
id : 'label.leave',
defaultMessage : 'Leave'
})}
className={classes.actionButton}
variant='contained'
color='secondary'
onClick={() => roomClient.close()}
>
<FormattedMessage
id='label.leave'
defaultMessage='Leave'
/>
</Button>
</div>
<div className={classes.sectionMobile}>
<IconButton
aria-haspopup='true'
onClick={handleMobileMenuOpen}
color='inherit'
>
<MoreIcon />
</IconButton>
</div>
<div className={classes.divider} />
<Button
aria-label={intl.formatMessage({
id : 'label.leave',
defaultMessage : 'Leave'
})}
className={classes.actionButton}
variant='contained'
color='secondary'
onClick={() => roomClient.close()}
>
<FormattedMessage
id='label.leave'
defaultMessage='Leave'
/>
</Button>
</Toolbar>
</AppBar>
<Menu
anchorEl={moreActionsElement}
<Popover
anchorEl={anchorEl}
anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
transformOrigin={{ vertical: 'top', horizontal: 'left' }}
open={isMoreActionsMenuOpen}
onClose={handleMoreActionsClose}
open={isMenuOpen}
onClose={handleMenuClose}
onExited={handleExited}
getContentAnchorEl={null}
>
{ currentMenu === 'moreActions' &&
<Paper>
<MenuItem
disabled={!canProduceExtraVideo}
onClick={() =>
{
handleMenuClose();
setExtraVideoOpen(!room.extraVideoOpen);
}}
>
<VideoCallIcon
aria-label={intl.formatMessage({
id : 'label.addVideo',
defaultMessage : 'Add video'
})}
/>
<p className={classes.moreAction}>
<FormattedMessage
id='label.addVideo'
defaultMessage='Add video'
/>
</p>
</MenuItem>
</Paper>
}
</Popover>
<Menu
anchorEl={mobileMoreAnchorEl}
anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
transformOrigin={{ vertical: 'bottom', horizontal: 'right' }}
open={isMobileMenuOpen}
onClose={handleMenuClose}
getContentAnchorEl={null}
>
{ loginEnabled &&
<MenuItem
aria-label={loginTooltip}
onClick={() =>
{
handleMenuClose();
loggedIn ? roomClient.logout() : roomClient.login();
}}
>
{ myPicture ?
<Avatar src={myPicture} />
:
<AccountCircle className={loggedIn ? classes.green : null} />
}
{ loggedIn ?
<p className={classes.moreAction}>
<FormattedMessage
id='tooltip.logout'
defaultMessage='Log out'
/>
</p>
:
<p className={classes.moreAction}>
<FormattedMessage
id='tooltip.login'
defaultMessage='Log in'
/>
</p>
}
</MenuItem>
}
<MenuItem
dense
disabled={!canProduceExtraVideo}
aria-label={lockTooltip}
disabled={!canLock}
onClick={() =>
{
handleMoreActionsClose();
setExtraVideoOpen(!room.extraVideoOpen);
handleMenuClose();
if (room.locked)
{
roomClient.unlockRoom();
}
else
{
roomClient.lockRoom();
}
}}
>
<VideoCallIcon
aria-label={intl.formatMessage({
id : 'label.addVideo',
defaultMessage : 'Add video'
})}
/>
{ room.locked ?
<LockIcon />
:
<LockOpenIcon />
}
{ room.locked ?
<p className={classes.moreAction}>
<FormattedMessage
id='tooltip.unLockRoom'
defaultMessage='Unlock room'
/>
</p>
:
<p className={classes.moreAction}>
<FormattedMessage
id='tooltip.lockRoom'
defaultMessage='Lock room'
/>
</p>
}
</MenuItem>
<MenuItem
aria-label={intl.formatMessage({
id : 'tooltip.settings',
defaultMessage : 'Show settings'
})}
onClick={() =>
{
handleMenuClose();
setSettingsOpen(!room.settingsOpen);
}}
>
<SettingsIcon />
<p className={classes.moreAction}>
<FormattedMessage
id='label.addVideo'
defaultMessage='Add video'
id='tooltip.settings'
defaultMessage='Show settings'
/>
</p>
</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
aria-label={intl.formatMessage({
id : 'tooltip.participants',
defaultMessage : 'Show participants'
})}
onClick={() =>
{
handleMenuClose();
openUsersTab();
}}
>
<Badge
color='primary'
badgeContent={peersLength + 1}
>
<PeopleIcon />
</Badge>
<p className={classes.moreAction}>
<FormattedMessage
id='tooltip.participants'
defaultMessage='Show participants'
/>
</p>
</MenuItem>
{ fullscreenEnabled &&
<MenuItem
aria-label={intl.formatMessage({
id : 'tooltip.enterFullscreen',
defaultMessage : 'Enter fullscreen'
})}
onClick={() =>
{
handleMenuClose();
onFullscreen();
}}
>
{ fullscreen ?
<FullScreenExitIcon />
:
<FullScreenIcon />
}
<p className={classes.moreAction}>
<FormattedMessage
id='tooltip.enterFullscreen'
defaultMessage='Enter fullscreen'
/>
</p>
</MenuItem>
}
<MenuItem
aria-label={intl.formatMessage({
id : 'label.moreActions',
defaultMessage : 'Add video'
})}
onClick={(event) => handleMenuOpen(event, 'moreActions')}
>
<ExtensionIcon />
<p className={classes.moreAction}>
<FormattedMessage
id='label.moreActions'
defaultMessage='More actions'
/>
</p>
</MenuItem>

View File

@ -224,7 +224,7 @@ const JoinDialog = ({
myPicture={myPicture}
onLogin={() =>
{
loggedIn ? roomClient.logout() : roomClient.login(roomId);
loggedIn ? roomClient.logout(roomId) : roomClient.login(roomId);
}}
loggedIn={loggedIn}
>

View File

@ -2,10 +2,12 @@ import React from 'react';
import { connect } from 'react-redux';
import { withStyles } from '@material-ui/core/styles';
import { withRoomContext } from '../../../RoomContext';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import * as appPropTypes from '../../appPropTypes';
import { useIntl } from 'react-intl';
import IconButton from '@material-ui/core/IconButton';
import Tooltip from '@material-ui/core/Tooltip';
import PanIcon from '@material-ui/icons/PanTool';
import EmptyAvatar from '../../../images/avatar-empty.jpeg';
@ -22,7 +24,7 @@ const styles = (theme) =>
{
borderRadius : '50%',
height : '2rem',
marginTop : theme.spacing(1)
marginTop : theme.spacing(0.5)
},
peerInfo :
{
@ -32,6 +34,10 @@ const styles = (theme) =>
flexGrow : 1,
alignItems : 'center'
},
buttons :
{
padding : theme.spacing(1)
},
green :
{
color : 'rgba(0, 153, 0, 1)'
@ -58,23 +64,33 @@ const ListMe = (props) =>
<div className={classes.peerInfo}>
{settings.displayName}
</div>
<IconButton
aria-label={intl.formatMessage({
<Tooltip
title={intl.formatMessage({
id : 'tooltip.raisedHand',
defaultMessage : 'Raise hand'
})}
className={me.raisedHand ? classes.green : null}
disabled={me.raisedHandInProgress}
color='primary'
onClick={(e) =>
{
e.stopPropagation();
roomClient.setRaisedHand(!me.raisedHand);
}}
placement='bottom'
>
<PanIcon />
</IconButton>
<IconButton
aria-label={intl.formatMessage({
id : 'tooltip.raisedHand',
defaultMessage : 'Raise hand'
})}
className={
classnames(me.raisedHand ? classes.green : null, classes.buttons)
}
disabled={me.raisedHandInProgress}
color='primary'
onClick={(e) =>
{
e.stopPropagation();
roomClient.setRaisedHand(!me.raisedHand);
}}
>
<PanIcon />
</IconButton>
</Tooltip>
</div>
);
};

View File

@ -6,7 +6,9 @@ import PropTypes from 'prop-types';
import * as appPropTypes from '../../appPropTypes';
import { withRoomContext } from '../../../RoomContext';
import { useIntl } from 'react-intl';
import { green } from '@material-ui/core/colors';
import IconButton from '@material-ui/core/IconButton';
import Tooltip from '@material-ui/core/Tooltip';
import VideocamIcon from '@material-ui/icons/Videocam';
import VideocamOffIcon from '@material-ui/icons/VideocamOff';
import VolumeUpIcon from '@material-ui/icons/VolumeUp';
@ -16,6 +18,7 @@ import ScreenOffIcon from '@material-ui/icons/StopScreenShare';
import ExitIcon from '@material-ui/icons/ExitToApp';
import EmptyAvatar from '../../../images/avatar-empty.jpeg';
import PanIcon from '@material-ui/icons/PanTool';
import RecordVoiceOverIcon from '@material-ui/icons/RecordVoiceOver';
const styles = (theme) =>
({
@ -30,7 +33,7 @@ const styles = (theme) =>
{
borderRadius : '50%',
height : '2rem',
marginTop : theme.spacing(1)
marginTop : theme.spacing(0.5)
},
peerInfo :
{
@ -43,11 +46,16 @@ const styles = (theme) =>
indicators :
{
display : 'flex',
padding : theme.spacing(1.5)
padding : theme.spacing(1)
},
buttons :
{
padding : theme.spacing(1)
},
green :
{
color : 'rgba(0, 153, 0, 1)'
color : 'rgba(0, 153, 0, 1)',
marginLeft : theme.spacing(2)
}
});
@ -58,6 +66,7 @@ const ListPeer = (props) =>
const {
roomClient,
isModerator,
spotlight,
peer,
micConsumer,
webcamConsumer,
@ -93,96 +102,151 @@ const ListPeer = (props) =>
<div className={classes.peerInfo}>
{peer.displayName}
</div>
<div className={classes.indicators}>
{ peer.raisedHand &&
<PanIcon className={classes.green} />
}
</div>
{ screenConsumer &&
{ peer.raisedHand &&
<IconButton
aria-label={intl.formatMessage({
className={classes.buttons}
style={{ color: green[500] }}
disabled={!isModerator || peer.raisedHandInProgress}
onClick={(e) =>
{
e.stopPropagation();
roomClient.lowerPeerHand(peer.id);
}}
>
<PanIcon />
</IconButton>
}
{ spotlight &&
<IconButton
className={classes.buttons}
style={{ color: green[500] }}
disabled
>
<RecordVoiceOverIcon />
</IconButton>
}
{ screenConsumer &&
<Tooltip
title={intl.formatMessage({
id : 'tooltip.muteScreenSharing',
defaultMessage : 'Mute participant share'
})}
color={screenVisible ? 'primary' : 'secondary'}
disabled={peer.peerScreenInProgress}
onClick={(e) =>
{
e.stopPropagation();
screenVisible ?
roomClient.modifyPeerConsumer(peer.id, 'screen', true) :
roomClient.modifyPeerConsumer(peer.id, 'screen', false);
}}
placement='bottom'
>
{ screenVisible ?
<ScreenIcon />
:
<ScreenOffIcon />
}
</IconButton>
<IconButton
aria-label={intl.formatMessage({
id : 'tooltip.muteScreenSharing',
defaultMessage : 'Mute participant share'
})}
color={screenVisible ? 'primary' : 'secondary'}
disabled={peer.peerScreenInProgress}
className={classes.buttons}
onClick={(e) =>
{
e.stopPropagation();
screenVisible ?
roomClient.modifyPeerConsumer(peer.id, 'screen', true) :
roomClient.modifyPeerConsumer(peer.id, 'screen', false);
}}
>
{ screenVisible ?
<ScreenIcon />
:
<ScreenOffIcon />
}
</IconButton>
</Tooltip>
}
<IconButton
aria-label={intl.formatMessage({
<Tooltip
title={intl.formatMessage({
id : 'tooltip.muteParticipantVideo',
defaultMessage : 'Mute participant video'
})}
color={webcamEnabled ? 'primary' : 'secondary'}
disabled={peer.peerVideoInProgress}
onClick={(e) =>
{
e.stopPropagation();
webcamEnabled ?
roomClient.modifyPeerConsumer(peer.id, 'webcam', true) :
roomClient.modifyPeerConsumer(peer.id, 'webcam', false);
}}
placement='bottom'
>
{ webcamEnabled ?
<VideocamIcon />
:
<VideocamOffIcon />
}
</IconButton>
<IconButton
aria-label={intl.formatMessage({
id : 'tooltip.muteParticipant',
defaultMessage : 'Mute participant'
})}
color={micEnabled ? 'primary' : 'secondary'}
disabled={peer.peerAudioInProgress}
onClick={(e) =>
{
e.stopPropagation();
micEnabled ?
roomClient.modifyPeerConsumer(peer.id, 'mic', true) :
roomClient.modifyPeerConsumer(peer.id, 'mic', false);
}}
>
{ micEnabled ?
<VolumeUpIcon />
:
<VolumeOffIcon />
}
</IconButton>
{ isModerator &&
<IconButton
aria-label={intl.formatMessage({
id : 'tooltip.kickParticipant',
defaultMessage : 'Kick out participant'
id : 'tooltip.muteParticipantVideo',
defaultMessage : 'Mute participant video'
})}
disabled={peer.peerKickInProgress}
color='secondary'
color={webcamEnabled ? 'primary' : 'secondary'}
disabled={peer.peerVideoInProgress}
className={classes.buttons}
onClick={(e) =>
{
e.stopPropagation();
roomClient.kickPeer(peer.id);
webcamEnabled ?
roomClient.modifyPeerConsumer(peer.id, 'webcam', true) :
roomClient.modifyPeerConsumer(peer.id, 'webcam', false);
}}
>
<ExitIcon />
{ webcamEnabled ?
<VideocamIcon />
:
<VideocamOffIcon />
}
</IconButton>
</Tooltip>
<Tooltip
title={intl.formatMessage({
id : 'tooltip.muteParticipant',
defaultMessage : 'Mute participant'
})}
placement='bottom'
>
<IconButton
aria-label={intl.formatMessage({
id : 'tooltip.muteParticipant',
defaultMessage : 'Mute participant'
})}
color={micEnabled ? 'primary' : 'secondary'}
disabled={peer.peerAudioInProgress}
className={classes.buttons}
onClick={(e) =>
{
e.stopPropagation();
micEnabled ?
roomClient.modifyPeerConsumer(peer.id, 'mic', true) :
roomClient.modifyPeerConsumer(peer.id, 'mic', false);
}}
>
{ micEnabled ?
<VolumeUpIcon />
:
<VolumeOffIcon />
}
</IconButton>
</Tooltip>
{ isModerator &&
<Tooltip
title={intl.formatMessage({
id : 'tooltip.kickParticipant',
defaultMessage : 'Kick out participant'
})}
placement='bottom'
>
<IconButton
aria-label={intl.formatMessage({
id : 'tooltip.kickParticipant',
defaultMessage : 'Kick out participant'
})}
disabled={peer.peerKickInProgress}
className={classes.buttons}
color='secondary'
onClick={(e) =>
{
e.stopPropagation();
roomClient.kickPeer(peer.id);
}}
>
<ExitIcon />
</IconButton>
</Tooltip>
}
{children}
</div>
@ -194,6 +258,7 @@ ListPeer.propTypes =
roomClient : PropTypes.any.isRequired,
advancedMode : PropTypes.bool,
isModerator : PropTypes.bool,
spotlight : PropTypes.bool,
peer : appPropTypes.Peer.isRequired,
micConsumer : appPropTypes.Consumer,
webcamConsumer : appPropTypes.Consumer,

View File

@ -1,13 +1,13 @@
import React from 'react';
import { connect } from 'react-redux';
import {
passivePeersSelector,
spotlightSortedPeersSelector
participantListSelector
} from '../../Selectors';
import classNames from 'classnames';
import classnames from 'classnames';
import { withStyles } from '@material-ui/core/styles';
import { withRoomContext } from '../../../RoomContext';
import PropTypes from 'prop-types';
import { Flipper, Flipped } from 'react-flip-toolkit';
import { FormattedMessage } from 'react-intl';
import ListPeer from './ListPeer';
import ListMe from './ListMe';
@ -76,9 +76,9 @@ class ParticipantList extends React.PureComponent
roomClient,
advancedMode,
isModerator,
passivePeers,
participants,
spotlights,
selectedPeerId,
spotlightPeers,
classes
} = this.props;
@ -107,50 +107,42 @@ class ParticipantList extends React.PureComponent
<ul className={classes.list}>
<li className={classes.listheader}>
<FormattedMessage
id='room.spotlights'
defaultMessage='Participants in Spotlight'
id='label.participants'
defaultMessage='Participants'
/>
</li>
{ spotlightPeers.map((peer) => (
<li
key={peer.id}
className={classNames(classes.listItem, {
selected : peer.id === selectedPeerId
})}
onClick={() => roomClient.setSelectedPeer(peer.id)}
>
<ListPeer
id={peer.id}
advancedMode={advancedMode}
isModerator={isModerator}
>
<Volume small id={peer.id} />
</ListPeer>
</li>
))}
</ul>
<ul className={classes.list}>
<li className={classes.listheader}>
<FormattedMessage
id='room.passive'
defaultMessage='Passive Participants'
/>
</li>
{ passivePeers.map((peer) => (
<li
key={peer.id}
className={classNames(classes.listItem, {
selected : peer.id === selectedPeerId
})}
onClick={() => roomClient.setSelectedPeer(peer.id)}
>
<ListPeer
id={peer.id}
advancedMode={advancedMode}
isModerator={isModerator}
/>
</li>
))}
<Flipper
flipKey={participants}
>
{ participants.map((peer) => (
<Flipped key={peer.id} flipId={peer.id}>
<li
key={peer.id}
className={classnames(classes.listItem, {
selected : peer.id === selectedPeerId
})}
onClick={() => roomClient.setSelectedPeer(peer.id)}
>
{ spotlights.includes(peer.id) ?
<ListPeer
id={peer.id}
advancedMode={advancedMode}
isModerator={isModerator}
spotlight
>
<Volume small id={peer.id} />
</ListPeer>
:
<ListPeer
id={peer.id}
advancedMode={advancedMode}
isModerator={isModerator}
/>
}
</li>
</Flipped>
))}
</Flipper>
</ul>
</div>
);
@ -162,9 +154,9 @@ ParticipantList.propTypes =
roomClient : PropTypes.any.isRequired,
advancedMode : PropTypes.bool,
isModerator : PropTypes.bool,
passivePeers : PropTypes.array,
participants : PropTypes.array,
spotlights : PropTypes.array,
selectedPeerId : PropTypes.string,
spotlightPeers : PropTypes.array,
classes : PropTypes.object.isRequired
};
@ -174,9 +166,9 @@ const mapStateToProps = (state) =>
isModerator :
state.me.roles.some((role) =>
state.room.permissionsFromRoles.MODERATE_ROOM.includes(role)),
passivePeers : passivePeersSelector(state),
selectedPeerId : state.room.selectedPeerId,
spotlightPeers : spotlightSortedPeersSelector(state)
participants : participantListSelector(state),
spotlights : state.room.spotlights,
selectedPeerId : state.room.selectedPeerId
};
};

View File

@ -142,6 +142,7 @@ class Room extends React.PureComponent
room,
browser,
advancedMode,
showNotifications,
toolAreaOpen,
toggleToolArea,
classes,
@ -178,7 +179,9 @@ class Room extends React.PureComponent
<AudioPeers />
<Notifications />
{ showNotifications &&
<Notifications />
}
<CssBaseline />
@ -232,6 +235,7 @@ Room.propTypes =
room : appPropTypes.Room.isRequired,
browser : PropTypes.object.isRequired,
advancedMode : PropTypes.bool.isRequired,
showNotifications : PropTypes.bool.isRequired,
toolAreaOpen : PropTypes.bool.isRequired,
setToolbarsVisible : PropTypes.func.isRequired,
toggleToolArea : PropTypes.func.isRequired,
@ -241,10 +245,11 @@ Room.propTypes =
const mapStateToProps = (state) =>
({
room : state.room,
browser : state.me.browser,
advancedMode : state.settings.advancedMode,
toolAreaOpen : state.toolarea.toolAreaOpen
room : state.room,
browser : state.me.browser,
advancedMode : state.settings.advancedMode,
showNotifications : state.settings.showNotifications,
toolAreaOpen : state.toolarea.toolAreaOpen
});
const mapDispatchToProps = (dispatch) =>
@ -270,6 +275,7 @@ export default connect(
prev.room === next.room &&
prev.me.browser === next.me.browser &&
prev.settings.advancedMode === next.settings.advancedMode &&
prev.settings.showNotifications === next.settings.showNotifications &&
prev.toolarea.toolAreaOpen === next.toolarea.toolAreaOpen
);
}

View File

@ -12,7 +12,8 @@ const peersKeySelector = createSelector(
peersSelector,
(peers) => Object.keys(peers)
);
const peersValueSelector = createSelector(
export const peersValueSelector = createSelector(
peersSelector,
(peers) => Object.values(peers)
);
@ -113,8 +114,31 @@ export const spotlightPeersSelector = createSelector(
export const spotlightSortedPeersSelector = createSelector(
spotlightsSelector,
peersValueSelector,
(spotlights, peers) => peers.filter((peer) => spotlights.includes(peer.id))
.sort((a, b) => String(a.displayName || '').localeCompare(String(b.displayName || '')))
(spotlights, peers) =>
peers.filter((peer) => spotlights.includes(peer.id) && !peer.raisedHand)
.sort((a, b) => String(a.displayName || '').localeCompare(String(b.displayName || '')))
);
const raisedHandSortedPeers = createSelector(
peersValueSelector,
(peers) => peers.filter((peer) => peer.raisedHand)
.sort((a, b) => a.raisedHandTimestamp - b.raisedHandTimestamp)
);
const peersSortedSelector = createSelector(
spotlightsSelector,
peersValueSelector,
(spotlights, peers) =>
peers.filter((peer) => !spotlights.includes(peer.id) && !peer.raisedHand)
.sort((a, b) => String(a.displayName || '').localeCompare(String(b.displayName || '')))
);
export const participantListSelector = createSelector(
raisedHandSortedPeers,
spotlightSortedPeersSelector,
peersSortedSelector,
(raisedHands, spotlights, peers) =>
[ ...raisedHands, ...spotlights, ...peers ]
);
export const peersLengthSelector = createSelector(

View File

@ -30,6 +30,7 @@ const AppearenceSettings = ({
settings,
onTogglePermanentTopBar,
onToggleHiddenControls,
onToggleShowNotifications,
handleChangeMode,
classes
}) =>
@ -101,18 +102,27 @@ const AppearenceSettings = ({
defaultMessage : 'Hidden media controls'
})}
/>
<FormControlLabel
className={classes.setting}
control={<Checkbox checked={settings.showNotifications} onChange={onToggleShowNotifications} value='showNotifications' />}
label={intl.formatMessage({
id : 'settings.showNotifications',
defaultMessage : 'Show notifications'
})}
/>
</React.Fragment>
);
};
AppearenceSettings.propTypes =
{
room : appPropTypes.Room.isRequired,
settings : PropTypes.object.isRequired,
onTogglePermanentTopBar : PropTypes.func.isRequired,
onToggleHiddenControls : PropTypes.func.isRequired,
handleChangeMode : PropTypes.func.isRequired,
classes : PropTypes.object.isRequired
room : appPropTypes.Room.isRequired,
settings : PropTypes.object.isRequired,
onTogglePermanentTopBar : PropTypes.func.isRequired,
onToggleHiddenControls : PropTypes.func.isRequired,
onToggleShowNotifications : PropTypes.func.isRequired,
handleChangeMode : PropTypes.func.isRequired,
classes : PropTypes.object.isRequired
};
const mapStateToProps = (state) =>
@ -122,9 +132,10 @@ const mapStateToProps = (state) =>
});
const mapDispatchToProps = {
onTogglePermanentTopBar : settingsActions.togglePermanentTopBar,
onToggleHiddenControls : settingsActions.toggleHiddenControls,
handleChangeMode : roomActions.setDisplayMode
onTogglePermanentTopBar : settingsActions.togglePermanentTopBar,
onToggleHiddenControls : settingsActions.toggleHiddenControls,
onToggleShowNotifications : settingsActions.toggleShowNotifications,
handleChangeMode : roomActions.setDisplayMode
};
export default connect(

View File

@ -3,12 +3,15 @@ import { connect } from 'react-redux';
import * as appPropTypes from '../appPropTypes';
import { withStyles } from '@material-ui/core/styles';
import { withRoomContext } from '../../RoomContext';
import * as settingsActions from '../../actions/settingsActions';
import PropTypes from 'prop-types';
import { useIntl, FormattedMessage } from 'react-intl';
import MenuItem from '@material-ui/core/MenuItem';
import FormHelperText from '@material-ui/core/FormHelperText';
import FormControl from '@material-ui/core/FormControl';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Select from '@material-ui/core/Select';
import Checkbox from '@material-ui/core/Checkbox';
const styles = (theme) =>
({
@ -23,6 +26,9 @@ const styles = (theme) =>
});
const MediaSettings = ({
setEchoCancellation,
setAutoGainControl,
setNoiseSuppression,
roomClient,
me,
settings,
@ -247,6 +253,51 @@ const MediaSettings = ({
/>
</FormHelperText>
</FormControl>
<FormControlLabel
className={classes.setting}
control={
<Checkbox checked={settings.echoCancellation} onChange={
(event) =>
{
setEchoCancellation(event.target.checked);
roomClient.changeAudioDevice(settings.selectedAudioDevice);
}}
/>}
label={intl.formatMessage({
id : 'settings.echoCancellation',
defaultMessage : 'Echo Cancellation'
})}
/>
<FormControlLabel
className={classes.setting}
control={
<Checkbox checked={settings.autoGainControl} onChange={
(event) =>
{
setAutoGainControl(event.target.checked);
roomClient.changeAudioDevice(settings.selectedAudioDevice);
}}
/>}
label={intl.formatMessage({
id : 'settings.autoGainControl',
defaultMessage : 'Auto Gain Control'
})}
/>
<FormControlLabel
className={classes.setting}
control={
<Checkbox checked={settings.noiseSuppression} onChange={
(event) =>
{
setNoiseSuppression(event.target.checked);
roomClient.changeAudioDevice(settings.selectedAudioDevice);
}}
/>}
label={intl.formatMessage({
id : 'settings.noiseSuppression',
defaultMessage : 'Noise Suppression'
})}
/>
</form>
</React.Fragment>
);
@ -254,10 +305,13 @@ const MediaSettings = ({
MediaSettings.propTypes =
{
roomClient : PropTypes.any.isRequired,
me : appPropTypes.Me.isRequired,
settings : PropTypes.object.isRequired,
classes : PropTypes.object.isRequired
roomClient : PropTypes.any.isRequired,
setEchoCancellation : PropTypes.func.isRequired,
setAutoGainControl : PropTypes.func.isRequired,
setNoiseSuppression : PropTypes.func.isRequired,
me : appPropTypes.Me.isRequired,
settings : PropTypes.object.isRequired,
classes : PropTypes.object.isRequired
};
const mapStateToProps = (state) =>
@ -268,9 +322,15 @@ const mapStateToProps = (state) =>
};
};
const mapDispatchToProps = {
setEchoCancellation : settingsActions.setEchoCancellation,
setAutoGainControl : settingsActions.toggleAutoGainControl,
setNoiseSuppression : settingsActions.toggleNoiseSuppression
};
export default withRoomContext(connect(
mapStateToProps,
null,
mapDispatchToProps,
null,
{
areStatesEqual : (next, prev) =>

View File

@ -4,13 +4,12 @@ import classnames from 'classnames';
import { withStyles } from '@material-ui/core/styles';
import EditableInput from '../Controls/EditableInput';
import Logger from '../../Logger';
import { green, yellow, orange, red } from '@material-ui/core/colors';
import { yellow, orange, red } from '@material-ui/core/colors';
import SignalCellularOffIcon from '@material-ui/icons/SignalCellularOff';
import SignalCellular0BarIcon from '@material-ui/icons/SignalCellular0Bar';
import SignalCellular1BarIcon from '@material-ui/icons/SignalCellular1Bar';
import SignalCellular2BarIcon from '@material-ui/icons/SignalCellular2Bar';
import SignalCellular3BarIcon from '@material-ui/icons/SignalCellular3Bar';
import SignalCellularAltIcon from '@material-ui/icons/SignalCellularAlt';
const logger = new Logger('VideoView');
@ -162,8 +161,6 @@ class VideoView extends React.PureComponent
videoMultiLayer,
audioScore,
videoScore,
// consumerSpatialLayers,
// consumerTemporalLayers,
consumerCurrentSpatialLayer,
consumerCurrentTemporalLayer,
consumerPreferredSpatialLayer,
@ -215,16 +212,16 @@ class VideoView extends React.PureComponent
case 7:
case 8:
case 9:
{
quality = <SignalCellular3BarIcon style={{ color: yellow[500] }}/>;
break;
}
case 9:
case 10:
{
quality = <SignalCellularAltIcon style={{ color: green[500] }}/>;
quality = null;
break;
}
@ -261,7 +258,7 @@ class VideoView extends React.PureComponent
<p>{videoWidth}x{videoHeight}</p>
}
</div>
{ !isMe &&
{ !isMe &&
<div className={classnames(classes.box, 'right')}>
{
quality

View File

@ -26,6 +26,12 @@ const peer = (state = {}, action) =>
raisedHand : action.payload.raisedHand,
raisedHandTimestamp : action.payload.raisedHandTimestamp
};
case 'SET_PEER_RAISED_HAND_IN_PROGRESS':
return {
...state,
raisedHandInProgress : action.payload.flag
};
case 'ADD_CONSUMER':
{
@ -91,6 +97,7 @@ const peers = (state = {}, action) =>
case 'SET_PEER_AUDIO_IN_PROGRESS':
case 'SET_PEER_SCREEN_IN_PROGRESS':
case 'SET_PEER_RAISED_HAND':
case 'SET_PEER_RAISED_HAND_IN_PROGRESS':
case 'SET_PEER_PICTURE':
case 'ADD_CONSUMER':
case 'ADD_PEER_ROLE':

View File

@ -4,12 +4,21 @@ const initialState =
selectedWebcam : null,
selectedAudioDevice : null,
advancedMode : false,
sampleRate : 48000,
channelCount : 1,
volume : 1.0,
autoGainControl : true,
echoCancellation : true,
noiseSuppression : true,
sampleSize : 16,
// low, medium, high, veryhigh, ultra
resolution : window.config.defaultResolution || 'medium',
lastN : 4,
permanentTopBar : true,
hiddenControls : false,
notificationSounds : true
showNotifications : true,
notificationSounds : true,
...window.config.defaultAudio
};
const settings = (state = initialState, action) =>
@ -45,6 +54,83 @@ const settings = (state = initialState, action) =>
return { ...state, advancedMode };
}
case 'SET_SAMPLE_RATE':
{
const { sampleRate } = action.payload;
return { ...state, sampleRate };
}
case 'SET_CHANNEL_COUNT':
{
const { channelCount } = action.payload;
return { ...state, channelCount };
}
case 'SET_VOLUME':
{
const { volume } = action.payload;
return { ...state, volume };
}
case 'SET_AUTO_GAIN_CONTROL':
{
const { autoGainControl } = action.payload;
return { ...state, autoGainControl };
}
case 'SET_ECHO_CANCELLATION':
{
const { echoCancellation } = action.payload;
return { ...state, echoCancellation };
}
case 'SET_NOISE_SUPPRESSION':
{
const { noiseSuppression } = action.payload;
return { ...state, noiseSuppression };
}
case 'SET_DEFAULT_AUDIO':
{
const { audio } = action.payload;
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':
{
const { sampleSize } = action.payload;
return { ...state, sampleSize };
}
case 'SET_LAST_N':
{
const { lastN } = action.payload;
@ -73,6 +159,13 @@ const settings = (state = initialState, action) =>
return { ...state, notificationSounds };
}
case 'TOGGLE_SHOW_NOTIFICATIONS':
{
const showNotifications = !state.showNotifications;
return { ...state, showNotifications };
}
case 'SET_VIDEO_RESOLUTION':
{
const { resolution } = action.payload;

View File

@ -80,6 +80,7 @@
"tooltip.muteParticipant": null,
"tooltip.muteParticipantVideo": null,
"tooltip.raisedHand": null,
"tooltip.muteScreenSharing": null,
"label.roomName": "房间名称",
"label.chooseRoomButton": "继续",
@ -109,6 +110,7 @@
"label.advanced": null,
"label.addVideo": null,
"label.promoteAllPeers": null,
"label.moreActions": null,
"settings.settings": "设置",
"settings.camera": "视频设备",
@ -128,6 +130,7 @@
"settings.lastn": "可见视频数量",
"settings.hiddenControls": null,
"settings.notificationSounds": null,
"settings.showNotifications": null,
"filesharing.saveFileError": "无法保存文件",
"filesharing.startingFileShare": "正在尝试共享文件",

View File

@ -79,6 +79,7 @@
"tooltip.muteParticipant": null,
"tooltip.muteParticipantVideo": null,
"tooltip.raisedHand": null,
"tooltip.muteScreenSharing": null,
"label.roomName": "Jméno místnosti",
"label.chooseRoomButton": "Pokračovat",
@ -108,6 +109,7 @@
"label.advanced": null,
"label.addVideo": null,
"label.promoteAllPeers": null,
"label.moreActions": null,
"settings.settings": "Nastavení",
"settings.camera": "Kamera",
@ -127,6 +129,7 @@
"settings.lastn": null,
"settings.hiddenControls": null,
"settings.notificationSounds": null,
"settings.showNotifications": null,
"filesharing.saveFileError": "Není možné uložit soubor",
"filesharing.startingFileShare": "Pokouším se sdílet soubor",

View File

@ -80,6 +80,7 @@
"tooltip.muteParticipant": null,
"tooltip.muteParticipantVideo": null,
"tooltip.raisedHand": null,
"tooltip.muteScreenSharing": null,
"label.roomName": "Name des Raums",
"label.chooseRoomButton": "Weiter",
@ -109,6 +110,7 @@
"label.advanced": null,
"label.addVideo": null,
"label.promoteAllPeers": null,
"label.moreActions": null,
"settings.settings": "Einstellungen",
"settings.camera": "Kamera",
@ -128,6 +130,7 @@
"settings.lastn": "Anzahl der sichtbaren Videos",
"settings.hiddenControls": null,
"settings.notificationSounds": null,
"settings.showNotifications": null,
"filesharing.saveFileError": "Fehler beim Speichern der Datei",
"filesharing.startingFileShare": "Starte Teilen der Datei",

View File

@ -80,6 +80,7 @@
"tooltip.muteParticipant": null,
"tooltip.muteParticipantVideo": null,
"tooltip.raisedHand": null,
"tooltip.muteScreenSharing": null,
"label.roomName": "Værelsesnavn",
"label.chooseRoomButton": "Fortsæt",
@ -109,6 +110,7 @@
"label.advanced": null,
"label.addVideo": null,
"label.promoteAllPeers": null,
"label.moreActions": null,
"settings.settings": "Indstillinger",
"settings.camera": "Kamera",
@ -128,6 +130,7 @@
"settings.lastn": "Antal synlige videoer",
"settings.hiddenControls": null,
"settings.notificationSounds": null,
"settings.showNotifications": null,
"filesharing.saveFileError": "Kan ikke gemme fil",
"filesharing.startingFileShare": "Forsøger at dele filen",

View File

@ -80,6 +80,7 @@
"tooltip.muteParticipant": null,
"tooltip.muteParticipantVideo": null,
"tooltip.raisedHand": null,
"tooltip.muteScreenSharing": null,
"label.roomName": "Όνομα δωματίου",
"label.chooseRoomButton": "Συνέχεια",
@ -109,6 +110,7 @@
"label.advanced": null,
"label.addVideo": null,
"label.promoteAllPeers": null,
"label.moreActions": null,
"settings.settings": "Ρυθμίσεις",
"settings.camera": "Κάμερα",
@ -128,6 +130,7 @@
"settings.lastn": "Αριθμός ορατών βίντεο",
"settings.hiddenControls": null,
"settings.notificationSounds": null,
"settings.showNotifications": null,
"filesharing.saveFileError": "Αδυναμία αποθήκευσης του αρχείου",
"filesharing.startingFileShare": "Προσπάθεια διαμοιρασμού αρχείου",

View File

@ -80,6 +80,7 @@
"tooltip.muteParticipant": "Mute participant",
"tooltip.muteParticipantVideo": "Mute participant video",
"tooltip.raisedHand": "Raise hand",
"tooltip.muteScreenSharing": "Mute participant share",
"label.roomName": "Room name",
"label.chooseRoomButton": "Continue",
@ -109,6 +110,7 @@
"label.advanced": "Advanced",
"label.addVideo": "Add video",
"label.promoteAllPeers": "Promote all",
"label.moreActions": "More actions",
"settings.settings": "Settings",
"settings.camera": "Camera",
@ -128,6 +130,7 @@
"settings.lastn": "Number of visible videos",
"settings.hiddenControls": "Hidden media controls",
"settings.notificationSounds": "Notification sounds",
"settings.showNotifications": "Show notifications",
"filesharing.saveFileError": "Unable to save file",
"filesharing.startingFileShare": "Attempting to share file",

View File

@ -80,6 +80,7 @@
"tooltip.muteParticipant": null,
"tooltip.muteParticipantVideo": null,
"tooltip.raisedHand": null,
"tooltip.muteScreenSharing": null,
"label.roomName": "Nombre de la sala",
"label.chooseRoomButton": "Continuar",
@ -109,6 +110,7 @@
"label.advanced": null,
"label.addVideo": null,
"label.promoteAllPeers": null,
"label.moreActions": null,
"settings.settings": "Ajustes",
"settings.camera": "Cámara",
@ -128,6 +130,7 @@
"settings.lastn": "Cantidad de videos visibles",
"settings.hiddenControls": null,
"settings.notificationSounds": null,
"settings.showNotifications": null,
"filesharing.saveFileError": "No ha sido posible guardar el fichero",
"filesharing.startingFileShare": "Intentando compartir el fichero",

View File

@ -80,6 +80,7 @@
"tooltip.muteParticipant": null,
"tooltip.muteParticipantVideo": null,
"tooltip.raisedHand": null,
"tooltip.muteScreenSharing": null,
"label.roomName": "Nom de la salle",
"label.chooseRoomButton": "Continuer",
@ -109,6 +110,7 @@
"label.advanced": null,
"label.addVideo": null,
"label.promoteAllPeers": null,
"label.moreActions": null,
"settings.settings": "Paramètres",
"settings.camera": "Caméra",
@ -128,6 +130,7 @@
"settings.lastn": "Nombre de vidéos visibles",
"settings.hiddenControls": null,
"settings.notificationSounds": null,
"settings.showNotifications": null,
"filesharing.saveFileError": "Impossible d'enregistrer le fichier",
"filesharing.startingFileShare": "Début du transfert de fichier",

View File

@ -80,6 +80,7 @@
"tooltip.muteParticipant": "Utišaj sudionika",
"tooltip.muteParticipantVideo": "Ne primaj video sudionika",
"tooltip.raisedHand": "Podigni ruku",
"tooltip.muteScreenSharing": null,
"label.roomName": "Naziv sobe",
"label.chooseRoomButton": "Nastavi",
@ -109,6 +110,7 @@
"label.advanced": "Napredno",
"label.addVideo": "Dodaj video",
"label.promoteAllPeers": "Promoviraj sve",
"label.moreActions": null,
"settings.settings": "Postavke",
"settings.camera": "Kamera",
@ -128,6 +130,7 @@
"settings.lastn": "Broj vidljivih videozapisa",
"settings.hiddenControls": "Skrivene kontrole medija",
"settings.notificationSounds": "Zvuk obavijesti",
"settings.showNotifications": null,
"filesharing.saveFileError": "Nije moguće spremiti datoteku",
"filesharing.startingFileShare": "Pokušaj dijeljenja datoteke",

View File

@ -1,24 +1,24 @@
{
"socket.disconnected": "A kapcsolat lebomlott",
"socket.reconnecting": "A kapcsolat lebomlott, újrapróbálkozás",
"socket.reconnected": "Sikeres újarkapcsolódás",
"socket.reconnected": "Sikeres újrakapcsolódás",
"socket.requestError": "Sikertelen szerver lekérés",
"room.chooseRoom": "Válaszd ki a konferenciaszobát",
"room.cookieConsent": "Ez a weblap a felhasználói élmény fokozása miatt sütiket használ",
"room.consentUnderstand": "Megértettem",
"room.joined": "Csatlakozátál a konferenciához",
"room.joined": "Csatlakoztál a konferenciához",
"room.cantJoin": "Sikertelen csatlakozás a konferenciához",
"room.youLocked": "A konferenciába való belépés letiltva",
"room.cantLock": "Sikertelen a konferenciaba való belépés letiltása",
"room.cantLock": "Sikertelen a konferenciába való belépés letiltása",
"room.youUnLocked": "A konferenciába való belépés engedélyezve",
"room.cantUnLock": "Sikertelen a konferenciába való belépés engedélyezése",
"room.locked": "A konferenciába való belépés letiltva",
"room.unlocked": "A konferenciába való belépés engedélyezve",
"room.newLobbyPeer": "Új részvevő lépett be a konferencia előszobájába",
"room.lobbyPeerLeft": "A konferencia előszobájából a részvevő távozott",
"room.lobbyPeerChangedDisplayName": "Az előszobai résztvevő meváltoztatta a nevét: {displayName}",
"room.lobbyPeerChangedPicture": "Az előszobai résztvevő meváltoztatta a képét",
"room.lobbyPeerChangedDisplayName": "Az előszobai résztvevő megváltoztatta a nevét: {displayName}",
"room.lobbyPeerChangedPicture": "Az előszobai résztvevő megváltoztatta a képét",
"room.setAccessCode": "A konferencia hozzáférési kódja megváltozott",
"room.accessCodeOn": "A konferencia hozzáférési kódja aktiválva",
"room.accessCodeOff": "A konferencia hozzáférési kódka deaktiválva",
@ -39,7 +39,7 @@
"room.audioOnly": "csak Hang",
"room.audioVideo": "Hang és Videó",
"room.youAreReady": "Ok, kész vagy",
"room.emptyRequireLogin": "A konferencia üres! Be kell lépned a konferecnia elkezdéséhez, vagy várnod kell amíg a házigazda becsatlakozik.",
"room.emptyRequireLogin": "A konferencia üres! Be kell lépned a konferencia elkezdéséhez, vagy várnod kell amíg a házigazda becsatlakozik.",
"room.locketWait": "Az automatikus belépés tiltva van - Várj amíg valaki beenged ...",
"room.lobbyAdministration": "Előszoba adminisztráció",
"room.peersInLobby": "Résztvevők az előszobában",
@ -54,7 +54,7 @@
"room.closeMeeting": "Konferencia lebontása",
"room.clearChat": "Chat történelem kiürítése",
"room.clearFileSharing": "File megosztás kiürítése",
"room.speechUnsupported": "A böngésződ nem támogatja a hangszint",
"room.speechUnsupported": "A böngésződ nem támogatja a hangfelismerést",
"room.moderatoractions": "Moderátor funkciók",
"room.raisedHand": "{displayName} jelentkezik",
"room.loweredHand": "{displayName} leeresztette a kezét",
@ -68,7 +68,7 @@
"tooltip.login": "Belépés",
"tooltip.logout": "Kilépés",
"tooltip.admitFromLobby": "Beenegdem az előszobából",
"tooltip.admitFromLobby": "Beengedem az előszobából",
"tooltip.lockRoom": "A konferenciába való belépés letiltása",
"tooltip.unLockRoom": "konferenciába való belépés engedélyezése",
"tooltip.enterFullscreen": "Teljes képernyős mód",
@ -78,8 +78,9 @@
"tooltip.participants": "Résztvevők",
"tooltip.kickParticipant": "Résztvevő kirúgása",
"tooltip.muteParticipant": "Résztvevő némítása",
"tooltip.muteParticipantVideo": "Résztvevő video némítása",
"tooltip.muteParticipantVideo": "Résztvevő videóstreamének némítása",
"tooltip.raisedHand": "Jelentkezés",
"tooltip.muteScreenSharing": "Képernyőmegosztás szüneteltetése",
"label.roomName": "Konferencia",
"label.chooseRoomButton": "Tovább",
@ -109,6 +110,7 @@
"label.advanced": "Részletek",
"label.addVideo": "Videó hozzáadása",
"label.promoteAllPeers": "Mindenkit beengedek",
"label.moreActions": "További műveletek",
"settings.settings": "Beállítások",
"settings.camera": "Kamera",
@ -127,12 +129,13 @@
"settings.permanentTopBar": "Állandó felső sáv",
"settings.lastn": "A látható videók száma",
"settings.hiddenControls": "Média Gombok automatikus elrejtése",
"settings.notificationSounds": "Értesítések hangjelzjéssel",
"settings.notificationSounds": "Értesítések hangjelzéssel",
"settings.showNotifications": null,
"filesharing.saveFileError": "A file-t nem sikerült elmenteni",
"filesharing.startingFileShare": "Fájl megosztása",
"filesharing.successfulFileShare": "A fájl sikeresen megosztva",
"filesharing.unableToShare": "Sikereteln fájl megosztás",
"filesharing.unableToShare": "Sikertelen fájl megosztás",
"filesharing.error": "Hiba a fájlmegosztás során",
"filesharing.finished": "A fájl letöltés befejeződött",
"filesharing.save": "Mentés",
@ -142,7 +145,7 @@
"devices.devicesChanged": "Az eszközei megváltoztak, konfiguráld őket be a beállítások menüben",
"device.audioUnsupported": "A hnag nem támogatott",
"device.audioUnsupported": "A hang nem támogatott",
"device.activateAudio": "Hang aktiválása",
"device.muteAudio": "Hang némítása",
"device.unMuteAudio": "Hang némítás kikapcsolása",
@ -153,9 +156,9 @@
"device.screenSharingUnsupported": "A képernyő megosztás nem támogatott",
"device.startScreenSharing": "Képernyőmegosztás indítása",
"device.stopScreenSharing": "Képernyőmegosztás leáłłítása",
"device.stopScreenSharing": "Képernyőmegosztás leállítása",
"devices.microphoneDisconnected": "Microphone kapcsolat bontva",
"devices.microphoneDisconnected": "Mikrofon kapcsolat bontva",
"devices.microphoneError": "Hiba történt a mikrofon hangeszköz elérése közben",
"devices.microphoneMute": "A mikrofon némítva lett",
"devices.microphoneUnMute": "A mikrofon némítása ki lett kapocsolva",

View File

@ -49,22 +49,22 @@
"room.spotlights": "Partecipanti in Evidenza",
"room.passive": "Participanti Passivi",
"room.videoPaused": "Il video è in pausa",
"room.muteAll": null,
"room.stopAllVideo": null,
"room.closeMeeting": null,
"room.clearChat": null,
"room.clearFileSharing": null,
"room.speechUnsupported": null,
"room.moderatoractions": null,
"room.raisedHand": null,
"room.loweredHand": null,
"room.extraVideo": null,
"room.muteAll": "Muta tutti",
"room.stopAllVideo": "Ferma tutti i video",
"room.closeMeeting": "Termina meeting",
"room.clearChat": "Pulisci chat",
"room.clearFileSharing": "Pulisci file sharing",
"room.speechUnsupported": "Il tuo browser non supporta il riconoscimento vocale",
"room.moderatoractions": "Azioni moderatore",
"room.raisedHand": "{displayName} ha alzato la mano",
"room.loweredHand": "{displayName} ha abbassato la mano",
"room.extraVideo": "Video extra",
"room.overRoomLimit": null,
"me.mutedPTT": null,
"me.mutedPTT": "Sei mutato, tieni premuto SPAZIO per parlare",
"roles.gotRole": null,
"roles.lostRole": null,
"roles.gotRole": "Hai ottenuto il ruolo: {role}",
"roles.lostRole": "Hai perso il ruolo: {role}",
"tooltip.login": "Log in",
"tooltip.logout": "Log out",
@ -76,9 +76,10 @@
"tooltip.lobby": "Mostra lobby",
"tooltip.settings": "Mostra impostazioni",
"tooltip.participants": "Mostra partecipanti",
"tooltip.muteParticipant": null,
"tooltip.muteParticipantVideo": null,
"tooltip.raisedHand": null,
"tooltip.muteParticipant": "Muta partecipante",
"tooltip.muteParticipantVideo": "Ferma video partecipante",
"tooltip.raisedHand": "Mano alzata",
"tooltip.muteScreenSharing": null,
"label.roomName": "Nome della stanza",
"label.chooseRoomButton": "Continua",
@ -103,11 +104,12 @@
"label.veryHigh": "Molto alta (FHD)",
"label.ultra": "Ultra (UHD)",
"label.close": "Chiudi",
"label.media": null,
"label.appearence": null,
"label.advanced": null,
"label.addVideo": null,
"label.promoteAllPeers": null,
"label.media": "Media",
"label.appearence": "Aspetto",
"label.advanced": "Avanzate",
"label.addVideo": "Aggiungi video",
"label.promoteAllPeers": "Promuovi tutti",
"label.moreActions": null,
"settings.settings": "Impostazioni",
"settings.camera": "Videocamera",
@ -125,8 +127,9 @@
"settings.advancedMode": "Modalità avanzata",
"settings.permanentTopBar": "Barra superiore permanente",
"settings.lastn": "Numero di video visibili",
"settings.hiddenControls": null,
"settings.notificationSounds": null,
"settings.hiddenControls": "Controlli media nascosti",
"settings.notificationSounds": "Suoni di notifica",
"settings.showNotifications": null,
"filesharing.saveFileError": "Impossibile salvare file",
"filesharing.startingFileShare": "Tentativo di condivisione file",
@ -168,8 +171,8 @@
"devices.cameraDisconnected": "Videocamera scollegata",
"devices.cameraError": "Errore con l'accesso alla videocamera",
"moderator.clearChat": null,
"moderator.clearFiles": null,
"moderator.muteAudio": null,
"moderator.muteVideo": null
"moderator.clearChat": "Il moderatore ha pulito la chat",
"moderator.clearFiles": "Il moderatore ha pulito i file",
"moderator.muteAudio": "Il moderatore ha mutato il tuo audio",
"moderator.muteVideo": "Il moderatore ha fermato il tuo video"
}

View File

@ -79,6 +79,7 @@
"tooltip.muteParticipant": "Noklusināt dalībnieku",
"tooltip.muteParticipantVideo": "Atslēgt dalībnieka video",
"tooltip.raisedHand": "Pacelt roku",
"tooltip.muteScreenSharing": null,
"label.roomName": "Sapulces telpas nosaukums (ID)",
"label.chooseRoomButton": "Turpināt",
@ -106,6 +107,7 @@
"label.appearence": "Izskats",
"label.advanced": "Advancēts",
"label.addVideo": "Pievienot video",
"label.moreActions": null,
"settings.settings": "Iestatījumi",
"settings.camera": "Kamera",
@ -122,6 +124,7 @@
"settings.lastn": "Jums redzamo video/kameru skaits",
"settings.hiddenControls": "Slēpto mediju vadība",
"settings.notificationSounds": "Paziņojumu skaņas",
"settings.showNotifications": null,
"filesharing.saveFileError": "Nav iespējams saglabāt failu",
"filesharing.startingFileShare": "Tiek mēģināts kopīgot failu",

View File

@ -80,6 +80,7 @@
"tooltip.muteParticipant": "Demp deltaker",
"tooltip.muteParticipantVideo": "Demp deltakervideo",
"tooltip.raisedHand": "Rekk opp hånden",
"tooltip.muteScreenSharing": "Demp deltaker skjermdeling",
"label.roomName": "Møtenavn",
"label.chooseRoomButton": "Fortsett",
@ -109,6 +110,7 @@
"label.advanced": "Avansert",
"label.addVideo": "Legg til video",
"label.promoteAllPeers": "Slipp inn alle",
"label.moreActions": "Flere handlinger",
"settings.settings": "Innstillinger",
"settings.camera": "Kamera",
@ -128,6 +130,7 @@
"settings.lastn": "Antall videoer synlig",
"settings.hiddenControls": "Skjul media knapper",
"settings.notificationSounds": "Varslingslyder",
"settings.showNotifications": "Vis varslinger",
"filesharing.saveFileError": "Klarte ikke å lagre fil",
"filesharing.startingFileShare": "Starter fildeling",

View File

@ -80,6 +80,7 @@
"tooltip.muteParticipant": null,
"tooltip.muteParticipantVideo": null,
"tooltip.raisedHand": null,
"tooltip.muteScreenSharing": null,
"label.roomName": "Nazwa konferencji",
"label.chooseRoomButton": "Kontynuuj",
@ -109,6 +110,7 @@
"label.advanced": null,
"label.addVideo": null,
"label.promoteAllPeers": null,
"label.moreActions": null,
"settings.settings": "Ustawienia",
"settings.camera": "Kamera",
@ -128,6 +130,7 @@
"settings.lastn": "Liczba widocznych uczestników (zdalnych)",
"settings.hiddenControls": null,
"settings.notificationSounds": null,
"settings.showNotifications": null,
"filesharing.saveFileError": "Nie można zapisać pliku",
"filesharing.startingFileShare": "Próba udostępnienia pliku",

View File

@ -80,6 +80,7 @@
"tooltip.muteParticipant": null,
"tooltip.muteParticipantVideo": null,
"tooltip.raisedHand": null,
"tooltip.muteScreenSharing": null,
"label.roomName": "Nome da sala",
"label.chooseRoomButton": "Continuar",
@ -109,6 +110,7 @@
"label.advanced": null,
"label.addVideo": null,
"label.promoteAllPeers": null,
"label.moreActions": null,
"settings.settings": "Definições",
"settings.camera": "Camera",
@ -128,6 +130,7 @@
"settings.lastn": "Número de vídeos visíveis",
"settings.hiddenControls": null,
"settings.notificationSounds": null,
"settings.showNotifications": null,
"filesharing.saveFileError": "Impossível de gravar o ficheiro",
"filesharing.startingFileShare": "Tentando partilha de ficheiro",

View File

@ -80,6 +80,7 @@
"tooltip.muteParticipant": null,
"tooltip.muteParticipantVideo": null,
"tooltip.raisedHand": null,
"tooltip.muteScreenSharing": null,
"label.roomName": "Numele camerei",
"label.chooseRoomButton": "Continuare",
@ -109,6 +110,7 @@
"label.advanced": null,
"label.addVideo": null,
"label.promoteAllPeers": null,
"label.moreActions": null,
"settings.settings": "Setări",
"settings.camera": "Cameră video",
@ -128,6 +130,7 @@
"settings.lastn": "Numărul de videoclipuri vizibile",
"settings.hiddenControls": null,
"settings.notificationSounds": null,
"settings.showNotifications": null,
"filesharing.saveFileError": "Încercarea de a salva fișierul a eșuat",
"filesharing.startingFileShare": "Partajarea fișierului",

View File

@ -80,6 +80,7 @@
"tooltip.muteParticipant": null,
"tooltip.muteParticipantVideo": null,
"tooltip.raisedHand": null,
"tooltip.muteScreenSharing": null,
"label.roomName": "Oda adı",
"label.chooseRoomButton": "Devam",
@ -109,6 +110,7 @@
"label.advanced": null,
"label.addVideo": null,
"label.promoteAllPeers": null,
"label.moreActions": null,
"settings.settings": "Ayarlar",
"settings.camera": "Kamera",
@ -125,6 +127,7 @@
"settings.lastn": "İzlenebilir video sayısı",
"settings.hiddenControls": null,
"settings.notificationSounds": null,
"settings.showNotifications": null,
"filesharing.saveFileError": "Dosya kaydedilemiyor",
"filesharing.startingFileShare": "Paylaşılan dosyaya erişiliyor",

View File

@ -80,6 +80,7 @@
"tooltip.muteParticipant": null,
"tooltip.muteParticipantVideo": null,
"tooltip.raisedHand": null,
"tooltip.muteScreenSharing": null,
"label.roomName": "Назва кімнати",
"label.chooseRoomButton": "Продовжити",
@ -109,6 +110,7 @@
"label.advanced": null,
"label.addVideo": null,
"label.promoteAllPeers": null,
"label.moreActions": null,
"settings.settings": "Налаштування",
"settings.camera": "Камера",
@ -128,6 +130,7 @@
"settings.lastn": "Кількість видимих ​​відео",
"settings.hiddenControls": null,
"settings.notificationSounds": null,
"settings.showNotifications": null,
"filesharing.saveFileError": "Неможливо зберегти файл",
"filesharing.startingFileShare": "Спроба поділитися файлом",

View File

@ -96,8 +96,8 @@ module.exports =
this._queue = new AwaitQueue();
}
// rooms: number of rooms
// peers: number of peers
// rooms: rooms object
// peers: peers object
// eslint-disable-next-line no-unused-vars
async log({ rooms, peers })
{
@ -106,9 +106,9 @@ module.exports =
// Do your logging in here, use queue to keep correct order
// eslint-disable-next-line no-console
console.log('Number of rooms: ', rooms);
console.log('Number of rooms: ', rooms.size);
// eslint-disable-next-line no-console
console.log('Number of peers: ', peers);
console.log('Number of peers: ', peers.size);
})
.catch((error) =>
{

View File

@ -117,6 +117,8 @@ class Room extends EventEmitter
this._peers = {};
this._selfDestructTimeout = null;
// Array of mediasoup Router instances.
this._mediasoupRouters = mediasoupRouters;
@ -146,6 +148,11 @@ class Room extends EventEmitter
this._closed = true;
if (this._selfDestructTimeout)
clearTimeout(this._selfDestructTimeout);
this._selfDestructTimeout = null;
this._chatHistory = null;
this._fileHistory = null;
@ -411,7 +418,10 @@ class Room extends EventEmitter
{
logger.debug('selfDestructCountdown() started');
setTimeout(() =>
if (this._selfDestructTimeout)
clearTimeout(this._selfDestructTimeout);
this._selfDestructTimeout = setTimeout(() =>
{
if (this._closed)
return;
@ -659,7 +669,14 @@ class Room extends EventEmitter
.filter((joinedPeer) => joinedPeer.id !== peer.id)
.map((joinedPeer) => (joinedPeer.peerInfo));
const lobbyPeers = this._lobby.peerList();
let lobbyPeers = [];
if ( // Allowed to promote peers, notify about lobbypeers
peer.roles.some((role) =>
permissionsFromRoles.PROMOTE_PEER.includes(role)
)
)
lobbyPeers = this._lobby.peerList();
cb(null, {
roles : peer.roles,
@ -1430,6 +1447,29 @@ class Room extends EventEmitter
break;
}
case 'moderator:lowerHand':
{
if (
!peer.roles.some(
(role) => permissionsFromRoles.MODERATE_ROOM.includes(role)
)
)
throw new Error('peer not authorized');
const { peerId } = request.data;
const lowerPeer = this._peers[peerId];
if (!lowerPeer)
throw new Error(`peer with id "${peerId}" not found`);
this._notification(lowerPeer.socket, 'moderator:lowerHand');
cb();
break;
}
default:
{
logger.error('unknown request.method "%s"', request.method);

View File

@ -7,7 +7,7 @@
"license": "MIT",
"main": "lib/index.js",
"scripts": {
"start": "DEBUG=${DEBUG:='*mediasoup* *INFO* *WARN* *ERROR*'} INTERACTIVE=${INTERACTIVE:='true'} node server.js",
"start": "node server.js",
"connect": "node connect.js",
"lint": "eslint -c .eslintrc.json --ext .js *.js lib/"
},

View File

@ -127,69 +127,58 @@ let oidcStrategy;
async function run()
{
// Open the interactive server.
await interactiveServer(rooms, peers);
// start Prometheus exporter
if (config.prometheus)
try
{
await promExporter(rooms, peers, config.prometheus);
}
// Open the interactive server.
await interactiveServer(rooms, peers);
if (typeof(config.auth) === 'undefined')
{
logger.warn('Auth is not configured properly!');
}
else
{
await setupAuth();
}
// Run a mediasoup Worker.
await runMediasoupWorkers();
// Run HTTPS server.
await runHttpsServer();
// Run WebSocketServer.
await runWebSocketServer();
// eslint-disable-next-line no-unused-vars
function errorHandler(err, req, res, next)
{
const trackingId = uuidv4();
res.status(500).send(
`<h1>Internal Server Error</h1>
<p>If you report this error, please also report this
<i>tracking ID</i> which makes it possible to locate your session
in the logs which are available to the system administrator:
<b>${trackingId}</b></p>`
);
logger.error(
'Express error handler dump with tracking ID: %s, error dump: %o',
trackingId, err);
}
app.use(errorHandler);
// Log rooms status every 30 seconds.
setInterval(() =>
{
for (const room of rooms.values())
// start Prometheus exporter
if (config.prometheus)
{
room.logStatus();
await promExporter(rooms, peers, config.prometheus);
}
}, 120000);
// check for deserted rooms
setInterval(() =>
{
for (const room of rooms.values())
if (typeof(config.auth) === 'undefined')
{
room.checkEmpty();
logger.warn('Auth is not configured properly!');
}
}, 10000);
else
{
await setupAuth();
}
// Run a mediasoup Worker.
await runMediasoupWorkers();
// Run HTTPS server.
await runHttpsServer();
// Run WebSocketServer.
await runWebSocketServer();
const errorHandler = (err, req, res, next) =>
{
const trackingId = uuidv4();
res.status(500).send(
`<h1>Internal Server Error</h1>
<p>If you report this error, please also report this
<i>tracking ID</i> which makes it possible to locate your session
in the logs which are available to the system administrator:
<b>${trackingId}</b></p>`
);
logger.error(
'Express error handler dump with tracking ID: %s, error dump: %o',
trackingId, err);
};
// eslint-disable-next-line no-unused-vars
app.use(errorHandler);
}
catch (error)
{
logger.error('run() [error:"%o"]', error);
}
}
function statusLog()
@ -197,8 +186,8 @@ function statusLog()
if (statusLogger)
{
statusLogger.log({
rooms : rooms.size,
peers : peers.size
rooms : rooms,
peers : peers
});
}
}