Merge remote-tracking branch 'upstream/develop' into mm-exporter
commit
c61ebc8287
|
|
@ -62,14 +62,6 @@ OR
|
||||||
|
|
||||||
## Configure multiparty-meeting servers
|
## Configure multiparty-meeting servers
|
||||||
|
|
||||||
### App config
|
|
||||||
|
|
||||||
mm/configs/app/config.js
|
|
||||||
|
|
||||||
``` js
|
|
||||||
multipartyServer : 'meet.example.com',
|
|
||||||
```
|
|
||||||
|
|
||||||
### Server config
|
### Server config
|
||||||
|
|
||||||
mm/configs/server/config.js
|
mm/configs/server/config.js
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron": "^7.1.1",
|
"electron": "^7.1.1",
|
||||||
|
"eslint-plugin-react": "^7.19.0",
|
||||||
"foreman": "^3.0.1",
|
"foreman": "^3.0.1",
|
||||||
"redux-mock-store": "^1.5.3"
|
"redux-mock-store": "^1.5.3"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ var config =
|
||||||
{ scaleResolutionDownBy: 2 },
|
{ scaleResolutionDownBy: 2 },
|
||||||
{ scaleResolutionDownBy: 1 }
|
{ scaleResolutionDownBy: 1 }
|
||||||
],
|
],
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
|
|
@ -41,8 +42,13 @@ var config =
|
||||||
{
|
{
|
||||||
tcp : true
|
tcp : true
|
||||||
},
|
},
|
||||||
|
defaultLayout : 'democratic', // democratic, filmstrip
|
||||||
lastN : 4,
|
lastN : 4,
|
||||||
mobileLastN : 1,
|
mobileLastN : 1,
|
||||||
|
// Highest number of speakers user can select
|
||||||
|
maxLastN : 5,
|
||||||
|
// If truthy, users can NOT change number of speakers visible
|
||||||
|
lockLastN : false,
|
||||||
background : 'images/background.jpg',
|
background : 'images/background.jpg',
|
||||||
// Add file and uncomment for adding logo to appbar
|
// Add file and uncomment for adding logo to appbar
|
||||||
// logo : 'images/logo.svg',
|
// logo : 'images/logo.svg',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Pleaceholder for Privacy Statetment/Policy, AUP</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Privacy Statement</h1>
|
||||||
|
<h1>Privacy Policy</h1>
|
||||||
|
<h1>Acceptable use policy (AUP)</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -31,8 +31,7 @@ let Spotlights;
|
||||||
let requestTimeout,
|
let requestTimeout,
|
||||||
transportOptions,
|
transportOptions,
|
||||||
lastN,
|
lastN,
|
||||||
mobileLastN,
|
mobileLastN;
|
||||||
defaultResolution;
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'test')
|
if (process.env.NODE_ENV !== 'test')
|
||||||
{
|
{
|
||||||
|
|
@ -40,8 +39,7 @@ if (process.env.NODE_ENV !== 'test')
|
||||||
requestTimeout,
|
requestTimeout,
|
||||||
transportOptions,
|
transportOptions,
|
||||||
lastN,
|
lastN,
|
||||||
mobileLastN,
|
mobileLastN
|
||||||
defaultResolution
|
|
||||||
} = window.config);
|
} = window.config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,9 +203,6 @@ export default class RoomClient
|
||||||
// Our WebTorrent client
|
// Our WebTorrent client
|
||||||
this._webTorrent = null;
|
this._webTorrent = null;
|
||||||
|
|
||||||
if (defaultResolution)
|
|
||||||
store.dispatch(settingsActions.setVideoResolution(defaultResolution));
|
|
||||||
|
|
||||||
// Max spotlights
|
// Max spotlights
|
||||||
if (device.platform === 'desktop')
|
if (device.platform === 'desktop')
|
||||||
this._maxSpotlights = lastN;
|
this._maxSpotlights = lastN;
|
||||||
|
|
@ -470,9 +465,9 @@ export default class RoomClient
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
login()
|
login(roomId = this._roomId)
|
||||||
{
|
{
|
||||||
const url = `/auth/login?peerId=${this._peerId}&roomId=${this._roomId}`;
|
const url = `/auth/login?peerId=${this._peerId}&roomId=${roomId}`;
|
||||||
|
|
||||||
window.open(url, 'loginWindow');
|
window.open(url, 'loginWindow');
|
||||||
}
|
}
|
||||||
|
|
@ -534,11 +529,6 @@ export default class RoomClient
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notify(text)
|
|
||||||
{
|
|
||||||
store.dispatch(requestActions.notify({ text: text }));
|
|
||||||
}
|
|
||||||
|
|
||||||
timeoutCallback(callback)
|
timeoutCallback(callback)
|
||||||
{
|
{
|
||||||
let called = false;
|
let called = false;
|
||||||
|
|
@ -684,7 +674,7 @@ export default class RoomClient
|
||||||
{
|
{
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
return store.dispatch(requestActions.notify(
|
store.dispatch(requestActions.notify(
|
||||||
{
|
{
|
||||||
type : 'error',
|
type : 'error',
|
||||||
text : intl.formatMessage({
|
text : intl.formatMessage({
|
||||||
|
|
@ -692,6 +682,8 @@ export default class RoomClient
|
||||||
defaultMessage : 'Unable to save file'
|
defaultMessage : 'Unable to save file'
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveAs(blob, file.name);
|
saveAs(blob, file.name);
|
||||||
|
|
@ -708,7 +700,9 @@ export default class RoomClient
|
||||||
if (existingTorrent)
|
if (existingTorrent)
|
||||||
{
|
{
|
||||||
// Never add duplicate torrents, use the existing one instead.
|
// Never add duplicate torrents, use the existing one instead.
|
||||||
return this._handleTorrent(existingTorrent);
|
this._handleTorrent(existingTorrent);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._webTorrent.add(magnetUri, this._handleTorrent);
|
this._webTorrent.add(magnetUri, this._handleTorrent);
|
||||||
|
|
@ -720,11 +714,13 @@ export default class RoomClient
|
||||||
// same file was sent multiple times.
|
// same file was sent multiple times.
|
||||||
if (torrent.progress === 1)
|
if (torrent.progress === 1)
|
||||||
{
|
{
|
||||||
return store.dispatch(
|
store.dispatch(
|
||||||
fileActions.setFileDone(
|
fileActions.setFileDone(
|
||||||
torrent.magnetURI,
|
torrent.magnetURI,
|
||||||
torrent.files
|
torrent.files
|
||||||
));
|
));
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let lastMove = 0;
|
let lastMove = 0;
|
||||||
|
|
@ -767,7 +763,7 @@ export default class RoomClient
|
||||||
{
|
{
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
return store.dispatch(requestActions.notify(
|
store.dispatch(requestActions.notify(
|
||||||
{
|
{
|
||||||
type : 'error',
|
type : 'error',
|
||||||
text : intl.formatMessage({
|
text : intl.formatMessage({
|
||||||
|
|
@ -775,13 +771,30 @@ export default class RoomClient
|
||||||
defaultMessage : 'Unable to share file'
|
defaultMessage : 'Unable to share file'
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingTorrent = this._webTorrent.get(torrent);
|
const existingTorrent = this._webTorrent.get(torrent);
|
||||||
|
|
||||||
if (existingTorrent)
|
if (existingTorrent)
|
||||||
{
|
{
|
||||||
return this._sendFile(existingTorrent.magnetURI);
|
store.dispatch(requestActions.notify(
|
||||||
|
{
|
||||||
|
text : intl.formatMessage({
|
||||||
|
id : 'filesharing.successfulFileShare',
|
||||||
|
defaultMessage : 'File successfully shared'
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
|
||||||
|
store.dispatch(fileActions.addFile(
|
||||||
|
this._peerId,
|
||||||
|
existingTorrent.magnetURI
|
||||||
|
));
|
||||||
|
|
||||||
|
this._sendFile(existingTorrent.magnetURI);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._webTorrent.seed(
|
this._webTorrent.seed(
|
||||||
|
|
@ -873,7 +886,7 @@ export default class RoomClient
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
lobbyPeerActions.addLobbyPeer(peer.peerId));
|
lobbyPeerActions.addLobbyPeer(peer.peerId));
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
lobbyPeerActions.setLobbyPeerDisplayName(peer.displayName));
|
lobbyPeerActions.setLobbyPeerDisplayName(peer.displayName, peer.peerId));
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
lobbyPeerActions.setLobbyPeerPicture(peer.picture));
|
lobbyPeerActions.setLobbyPeerPicture(peer.picture));
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ const DialogTitle = withStyles(styles)((props) =>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MuiDialogTitle disableTypography className={classes.dialogTitle} {...other}>
|
<MuiDialogTitle disableTypography className={classes.dialogTitle} {...other}>
|
||||||
{ window.config && 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} /> }
|
||||||
<Typography variant='h5'>{children}</Typography>
|
<Typography variant='h5'>{children}</Typography>
|
||||||
</MuiDialogTitle>
|
</MuiDialogTitle>
|
||||||
);
|
);
|
||||||
|
|
@ -125,7 +125,7 @@ const ChooseRoom = ({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
{ window.config && window.config.title ? window.config.title : 'Multiparty meeting' }
|
{ window.config.title ? window.config.title : 'Multiparty meeting' }
|
||||||
<hr />
|
<hr />
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ import { useIntl, FormattedMessage } from 'react-intl';
|
||||||
import VideoView from '../VideoContainers/VideoView';
|
import VideoView from '../VideoContainers/VideoView';
|
||||||
import Tooltip from '@material-ui/core/Tooltip';
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
import Fab from '@material-ui/core/Fab';
|
import Fab from '@material-ui/core/Fab';
|
||||||
import MicIcon from '@material-ui/icons/Mic';
|
import VolumeUpIcon from '@material-ui/icons/VolumeUp';
|
||||||
import MicOffIcon from '@material-ui/icons/MicOff';
|
import VolumeOffIcon from '@material-ui/icons/VolumeOff';
|
||||||
import NewWindowIcon from '@material-ui/icons/OpenInNew';
|
import NewWindowIcon from '@material-ui/icons/OpenInNew';
|
||||||
import FullScreenIcon from '@material-ui/icons/Fullscreen';
|
import FullScreenIcon from '@material-ui/icons/Fullscreen';
|
||||||
import Volume from './Volume';
|
import Volume from './Volume';
|
||||||
|
|
@ -252,9 +252,9 @@ const Peer = (props) =>
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{ micEnabled ?
|
{ micEnabled ?
|
||||||
<MicIcon />
|
<VolumeUpIcon />
|
||||||
:
|
:
|
||||||
<MicOffIcon />
|
<VolumeOffIcon />
|
||||||
}
|
}
|
||||||
</Fab>
|
</Fab>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -340,6 +340,7 @@ const Peer = (props) =>
|
||||||
videoMultiLayer={webcamConsumer && webcamConsumer.type !== 'simple'}
|
videoMultiLayer={webcamConsumer && webcamConsumer.type !== 'simple'}
|
||||||
videoTrack={webcamConsumer && webcamConsumer.track}
|
videoTrack={webcamConsumer && webcamConsumer.track}
|
||||||
videoVisible={videoVisible}
|
videoVisible={videoVisible}
|
||||||
|
audioTrack={micConsumer && micConsumer.track}
|
||||||
audioCodec={micConsumer && micConsumer.codec}
|
audioCodec={micConsumer && micConsumer.codec}
|
||||||
videoCodec={webcamConsumer && webcamConsumer.codec}
|
videoCodec={webcamConsumer && webcamConsumer.codec}
|
||||||
audioScore={micConsumer ? micConsumer.score : null}
|
audioScore={micConsumer ? micConsumer.score : null}
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,10 @@ const styles = (theme) =>
|
||||||
{
|
{
|
||||||
margin : theme.spacing(1, 0),
|
margin : theme.spacing(1, 0),
|
||||||
padding : theme.spacing(0, 1)
|
padding : theme.spacing(0, 1)
|
||||||
|
},
|
||||||
|
green :
|
||||||
|
{
|
||||||
|
color : 'rgba(0, 153, 0, 1)'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -136,6 +140,7 @@ const TopBar = (props) =>
|
||||||
openUsersTab,
|
openUsersTab,
|
||||||
unread,
|
unread,
|
||||||
canLock,
|
canLock,
|
||||||
|
canPromote,
|
||||||
classes
|
classes
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
|
@ -194,14 +199,14 @@ const TopBar = (props) =>
|
||||||
<MenuIcon />
|
<MenuIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</PulsingBadge>
|
</PulsingBadge>
|
||||||
{ window.config && 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} /> }
|
||||||
<Typography
|
<Typography
|
||||||
className={classes.title}
|
className={classes.title}
|
||||||
variant='h6'
|
variant='h6'
|
||||||
color='inherit'
|
color='inherit'
|
||||||
noWrap
|
noWrap
|
||||||
>
|
>
|
||||||
{ window.config && window.config.title ? window.config.title : 'Multiparty meeting' }
|
{ window.config.title ? window.config.title : 'Multiparty meeting' }
|
||||||
</Typography>
|
</Typography>
|
||||||
<div className={classes.grow} />
|
<div className={classes.grow} />
|
||||||
<div className={classes.actionButtons}>
|
<div className={classes.actionButtons}>
|
||||||
|
|
@ -305,6 +310,7 @@ const TopBar = (props) =>
|
||||||
defaultMessage : 'Show lobby'
|
defaultMessage : 'Show lobby'
|
||||||
})}
|
})}
|
||||||
color='inherit'
|
color='inherit'
|
||||||
|
disabled={!canPromote}
|
||||||
onClick={() => setLockDialogOpen(!room.lockDialogOpen)}
|
onClick={() => setLockDialogOpen(!room.lockDialogOpen)}
|
||||||
>
|
>
|
||||||
<PulsingBadge
|
<PulsingBadge
|
||||||
|
|
@ -333,7 +339,7 @@ const TopBar = (props) =>
|
||||||
{ myPicture ?
|
{ myPicture ?
|
||||||
<Avatar src={myPicture} />
|
<Avatar src={myPicture} />
|
||||||
:
|
:
|
||||||
<AccountCircle />
|
<AccountCircle className={loggedIn && classes.green} />
|
||||||
}
|
}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
@ -380,6 +386,7 @@ TopBar.propTypes =
|
||||||
openUsersTab : PropTypes.func.isRequired,
|
openUsersTab : PropTypes.func.isRequired,
|
||||||
unread : PropTypes.number.isRequired,
|
unread : PropTypes.number.isRequired,
|
||||||
canLock : PropTypes.bool.isRequired,
|
canLock : PropTypes.bool.isRequired,
|
||||||
|
canPromote : PropTypes.bool.isRequired,
|
||||||
classes : PropTypes.object.isRequired,
|
classes : PropTypes.object.isRequired,
|
||||||
theme : PropTypes.object.isRequired
|
theme : PropTypes.object.isRequired
|
||||||
};
|
};
|
||||||
|
|
@ -397,7 +404,10 @@ const mapStateToProps = (state) =>
|
||||||
state.toolarea.unreadFiles,
|
state.toolarea.unreadFiles,
|
||||||
canLock :
|
canLock :
|
||||||
state.me.roles.some((role) =>
|
state.me.roles.some((role) =>
|
||||||
state.room.permissionsFromRoles.CHANGE_ROOM_LOCK.includes(role))
|
state.room.permissionsFromRoles.CHANGE_ROOM_LOCK.includes(role)),
|
||||||
|
canPromote :
|
||||||
|
state.me.roles.some((role) =>
|
||||||
|
state.room.permissionsFromRoles.PROMOTE_PEER.includes(role))
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) =>
|
const mapDispatchToProps = (dispatch) =>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import { withRoomContext } from '../RoomContext';
|
import { withRoomContext } from '../RoomContext';
|
||||||
|
import classnames from 'classnames';
|
||||||
import isElectron from 'is-electron';
|
import isElectron from 'is-electron';
|
||||||
import * as settingsActions from '../actions/settingsActions';
|
import * as settingsActions from '../actions/settingsActions';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
@ -128,9 +129,9 @@ const DialogTitle = withStyles(styles)((props) =>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MuiDialogTitle disableTypography className={classes.dialogTitle} {...other}>
|
<MuiDialogTitle disableTypography className={classes.dialogTitle} {...other}>
|
||||||
{ window.config && 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} /> }
|
||||||
<Typography variant='h5'>{children}</Typography>
|
<Typography variant='h5'>{children}</Typography>
|
||||||
{ window.config && window.config.loginEnabled &&
|
{ window.config.loginEnabled &&
|
||||||
<Tooltip
|
<Tooltip
|
||||||
onClose={handleTooltipClose}
|
onClose={handleTooltipClose}
|
||||||
onOpen={handleTooltipOpen}
|
onOpen={handleTooltipOpen}
|
||||||
|
|
@ -147,7 +148,9 @@ const DialogTitle = withStyles(styles)((props) =>
|
||||||
{ myPicture ?
|
{ myPicture ?
|
||||||
<Avatar src={myPicture} className={classes.largeAvatar} />
|
<Avatar src={myPicture} className={classes.largeAvatar} />
|
||||||
:
|
:
|
||||||
<AccountCircle className={classes.largeIcon} />
|
<AccountCircle
|
||||||
|
className={classnames(classes.largeIcon, loggedIn && classes.green)}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
@ -217,11 +220,11 @@ const JoinDialog = ({
|
||||||
myPicture={myPicture}
|
myPicture={myPicture}
|
||||||
onLogin={() =>
|
onLogin={() =>
|
||||||
{
|
{
|
||||||
loggedIn ? roomClient.logout() : roomClient.login();
|
loggedIn ? roomClient.logout() : roomClient.login(roomId);
|
||||||
}}
|
}}
|
||||||
loggedIn={loggedIn}
|
loggedIn={loggedIn}
|
||||||
>
|
>
|
||||||
{ window.config && window.config.title ? window.config.title : 'Multiparty meeting' }
|
{ window.config.title ? window.config.title : 'Multiparty meeting' }
|
||||||
<hr />
|
<hr />
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
|
|
@ -316,6 +319,7 @@ const JoinDialog = ({
|
||||||
className={classes.green}
|
className={classes.green}
|
||||||
gutterBottom
|
gutterBottom
|
||||||
variant='h6'
|
variant='h6'
|
||||||
|
style={{ fontWeight: '600' }}
|
||||||
align='center'
|
align='center'
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
|
@ -324,7 +328,11 @@ const JoinDialog = ({
|
||||||
/>
|
/>
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
{ room.signInRequired ?
|
{ room.signInRequired ?
|
||||||
<DialogContentText gutterBottom>
|
<DialogContentText
|
||||||
|
gutterBottom
|
||||||
|
variant='h5'
|
||||||
|
style={{ fontWeight: '600' }}
|
||||||
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='room.emptyRequireLogin'
|
id='room.emptyRequireLogin'
|
||||||
defaultMessage={
|
defaultMessage={
|
||||||
|
|
@ -334,7 +342,11 @@ const JoinDialog = ({
|
||||||
/>
|
/>
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
:
|
:
|
||||||
<DialogContentText gutterBottom>
|
<DialogContentText
|
||||||
|
gutterBottom
|
||||||
|
variant='h5'
|
||||||
|
style={{ fontWeight: '600' }}
|
||||||
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='room.locketWait'
|
id='room.locketWait'
|
||||||
defaultMessage='The room is locked - hang on until somebody lets you in ...'
|
defaultMessage='The room is locked - hang on until somebody lets you in ...'
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ const FileSharing = (props) =>
|
||||||
{
|
{
|
||||||
if (event.target.files.length > 0)
|
if (event.target.files.length > 0)
|
||||||
{
|
{
|
||||||
props.roomClient.shareFiles(event.target.files);
|
await props.roomClient.shareFiles(event.target.files);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -65,6 +65,8 @@ const FileSharing = (props) =>
|
||||||
type='file'
|
type='file'
|
||||||
disabled={!canShare}
|
disabled={!canShare}
|
||||||
onChange={handleFileChange}
|
onChange={handleFileChange}
|
||||||
|
// Need to reset to be able to share same file twice
|
||||||
|
onClick={(e) => (e.target.value = null)}
|
||||||
id='share-files-button'
|
id='share-files-button'
|
||||||
/>
|
/>
|
||||||
<label htmlFor='share-files-button'>
|
<label htmlFor='share-files-button'>
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,10 @@ import * as appPropTypes from '../../appPropTypes';
|
||||||
import { withRoomContext } from '../../../RoomContext';
|
import { withRoomContext } from '../../../RoomContext';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import IconButton from '@material-ui/core/IconButton';
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
import MicIcon from '@material-ui/icons/Mic';
|
import VideocamIcon from '@material-ui/icons/Videocam';
|
||||||
import MicOffIcon from '@material-ui/icons/MicOff';
|
import VideocamOffIcon from '@material-ui/icons/VideocamOff';
|
||||||
|
import VolumeUpIcon from '@material-ui/icons/VolumeUp';
|
||||||
|
import VolumeOffIcon from '@material-ui/icons/VolumeOff';
|
||||||
import ScreenIcon from '@material-ui/icons/ScreenShare';
|
import ScreenIcon from '@material-ui/icons/ScreenShare';
|
||||||
import ScreenOffIcon from '@material-ui/icons/StopScreenShare';
|
import ScreenOffIcon from '@material-ui/icons/StopScreenShare';
|
||||||
import ExitIcon from '@material-ui/icons/ExitToApp';
|
import ExitIcon from '@material-ui/icons/ExitToApp';
|
||||||
|
|
@ -104,11 +106,18 @@ const ListPeer = (props) =>
|
||||||
isModerator,
|
isModerator,
|
||||||
peer,
|
peer,
|
||||||
micConsumer,
|
micConsumer,
|
||||||
|
webcamConsumer,
|
||||||
screenConsumer,
|
screenConsumer,
|
||||||
children,
|
children,
|
||||||
classes
|
classes
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
const webcamEnabled = (
|
||||||
|
Boolean(webcamConsumer) &&
|
||||||
|
!webcamConsumer.locallyPaused &&
|
||||||
|
!webcamConsumer.remotelyPaused
|
||||||
|
);
|
||||||
|
|
||||||
const micEnabled = (
|
const micEnabled = (
|
||||||
Boolean(micConsumer) &&
|
Boolean(micConsumer) &&
|
||||||
!micConsumer.locallyPaused &&
|
!micConsumer.locallyPaused &&
|
||||||
|
|
@ -153,8 +162,10 @@ const ListPeer = (props) =>
|
||||||
})}
|
})}
|
||||||
color={screenVisible ? 'primary' : 'secondary'}
|
color={screenVisible ? 'primary' : 'secondary'}
|
||||||
disabled={peer.peerScreenInProgress}
|
disabled={peer.peerScreenInProgress}
|
||||||
onClick={() =>
|
onClick={(e) =>
|
||||||
{
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
screenVisible ?
|
screenVisible ?
|
||||||
roomClient.modifyPeerConsumer(peer.id, 'screen', true) :
|
roomClient.modifyPeerConsumer(peer.id, 'screen', true) :
|
||||||
roomClient.modifyPeerConsumer(peer.id, 'screen', false);
|
roomClient.modifyPeerConsumer(peer.id, 'screen', false);
|
||||||
|
|
@ -167,6 +178,28 @@ const ListPeer = (props) =>
|
||||||
}
|
}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
}
|
}
|
||||||
|
<IconButton
|
||||||
|
aria-label={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);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ webcamEnabled ?
|
||||||
|
<VideocamIcon />
|
||||||
|
:
|
||||||
|
<VideocamOffIcon />
|
||||||
|
}
|
||||||
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label={intl.formatMessage({
|
aria-label={intl.formatMessage({
|
||||||
id : 'tooltip.muteParticipant',
|
id : 'tooltip.muteParticipant',
|
||||||
|
|
@ -174,17 +207,19 @@ const ListPeer = (props) =>
|
||||||
})}
|
})}
|
||||||
color={micEnabled ? 'primary' : 'secondary'}
|
color={micEnabled ? 'primary' : 'secondary'}
|
||||||
disabled={peer.peerAudioInProgress}
|
disabled={peer.peerAudioInProgress}
|
||||||
onClick={() =>
|
onClick={(e) =>
|
||||||
{
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
micEnabled ?
|
micEnabled ?
|
||||||
roomClient.modifyPeerConsumer(peer.id, 'mic', true) :
|
roomClient.modifyPeerConsumer(peer.id, 'mic', true) :
|
||||||
roomClient.modifyPeerConsumer(peer.id, 'mic', false);
|
roomClient.modifyPeerConsumer(peer.id, 'mic', false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{ micEnabled ?
|
{ micEnabled ?
|
||||||
<MicIcon />
|
<VolumeUpIcon />
|
||||||
:
|
:
|
||||||
<MicOffIcon />
|
<VolumeOffIcon />
|
||||||
}
|
}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
{ isModerator &&
|
{ isModerator &&
|
||||||
|
|
@ -194,8 +229,10 @@ const ListPeer = (props) =>
|
||||||
defaultMessage : 'Kick out participant'
|
defaultMessage : 'Kick out participant'
|
||||||
})}
|
})}
|
||||||
disabled={peer.peerKickInProgress}
|
disabled={peer.peerKickInProgress}
|
||||||
onClick={() =>
|
onClick={(e) =>
|
||||||
{
|
{
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
roomClient.kickPeer(peer.id);
|
roomClient.kickPeer(peer.id);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { micConsumerSelector } from '../Selectors';
|
import { passiveMicConsumerSelector } from '../Selectors';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import PeerAudio from './PeerAudio';
|
import PeerAudio from './PeerAudio';
|
||||||
|
|
||||||
|
|
@ -37,7 +37,7 @@ AudioPeers.propTypes =
|
||||||
|
|
||||||
const mapStateToProps = (state) =>
|
const mapStateToProps = (state) =>
|
||||||
({
|
({
|
||||||
micConsumers : micConsumerSelector(state),
|
micConsumers : passiveMicConsumerSelector(state),
|
||||||
audioOutputDevice : state.settings.selectedAudioOutputDevice
|
audioOutputDevice : state.settings.selectedAudioOutputDevice
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -50,7 +50,9 @@ const AudioPeersContainer = connect(
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
prev.consumers === next.consumers &&
|
prev.consumers === next.consumers &&
|
||||||
prev.settings.selectedAudioOutputDevice === next.settings.selectedAudioOutputDevice
|
prev.room.spotlights === next.room.spotlights &&
|
||||||
|
prev.settings.selectedAudioOutputDevice ===
|
||||||
|
next.settings.selectedAudioOutputDevice
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,15 @@ export const screenConsumerSelector = createSelector(
|
||||||
(consumers) => Object.values(consumers).filter((consumer) => consumer.source === 'screen')
|
(consumers) => Object.values(consumers).filter((consumer) => consumer.source === 'screen')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const passiveMicConsumerSelector = createSelector(
|
||||||
|
spotlightsSelector,
|
||||||
|
consumersSelect,
|
||||||
|
(spotlights, consumers) =>
|
||||||
|
Object.values(consumers).filter(
|
||||||
|
(consumer) => consumer.source === 'mic' && !spotlights.includes(consumer.peerId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
export const spotlightsLengthSelector = createSelector(
|
export const spotlightsLengthSelector = createSelector(
|
||||||
spotlightsSelector,
|
spotlightsSelector,
|
||||||
(spotlights) => spotlights.length
|
(spotlights) => spotlights.length
|
||||||
|
|
|
||||||
|
|
@ -233,8 +233,7 @@ const Settings = ({
|
||||||
</FormHelperText>
|
</FormHelperText>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</form>
|
</form>
|
||||||
{
|
{ 'audioOutputSupportedBrowsers' in window.config &&
|
||||||
'audioOutputSupportedBrowsers' in window.config &&
|
|
||||||
window.config.audioOutputSupportedBrowsers.includes(me.browser.name) &&
|
window.config.audioOutputSupportedBrowsers.includes(me.browser.name) &&
|
||||||
<form className={classes.setting} autoComplete='off'>
|
<form className={classes.setting} autoComplete='off'>
|
||||||
<FormControl className={classes.formControl}>
|
<FormControl className={classes.formControl}>
|
||||||
|
|
@ -355,6 +354,7 @@ const Settings = ({
|
||||||
/>
|
/>
|
||||||
{ settings.advancedMode &&
|
{ settings.advancedMode &&
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
{ !window.config.lockLastN &&
|
||||||
<form className={classes.setting} autoComplete='off'>
|
<form className={classes.setting} autoComplete='off'>
|
||||||
<FormControl className={classes.formControl}>
|
<FormControl className={classes.formControl}>
|
||||||
<Select
|
<Select
|
||||||
|
|
@ -368,7 +368,10 @@ const Settings = ({
|
||||||
autoWidth
|
autoWidth
|
||||||
className={classes.selectEmpty}
|
className={classes.selectEmpty}
|
||||||
>
|
>
|
||||||
{ [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ].map((lastN) =>
|
{ Array.from(
|
||||||
|
{ length: window.config.maxLastN || 10 },
|
||||||
|
(_, i) => i + 1
|
||||||
|
).map((lastN) =>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<MenuItem key={lastN} value={lastN}>
|
<MenuItem key={lastN} value={lastN}>
|
||||||
|
|
@ -385,6 +388,7 @@ const Settings = ({
|
||||||
</FormHelperText>
|
</FormHelperText>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</form>
|
</form>
|
||||||
|
}
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
className={classes.setting}
|
className={classes.setting}
|
||||||
control={<Checkbox checked={settings.permanentTopBar} onChange={onTogglePermanentTopBar} value='permanentTopBar' />}
|
control={<Checkbox checked={settings.permanentTopBar} onChange={onTogglePermanentTopBar} value='permanentTopBar' />}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import EditableInput from '../Controls/EditableInput';
|
import EditableInput from '../Controls/EditableInput';
|
||||||
|
import Logger from '../../Logger';
|
||||||
import { green, yellow, orange, red } from '@material-ui/core/colors';
|
import { green, yellow, orange, red } from '@material-ui/core/colors';
|
||||||
import SignalCellularOffIcon from '@material-ui/icons/SignalCellularOff';
|
import SignalCellularOffIcon from '@material-ui/icons/SignalCellularOff';
|
||||||
import SignalCellular0BarIcon from '@material-ui/icons/SignalCellular0Bar';
|
import SignalCellular0BarIcon from '@material-ui/icons/SignalCellular0Bar';
|
||||||
|
|
@ -11,6 +12,8 @@ import SignalCellular2BarIcon from '@material-ui/icons/SignalCellular2Bar';
|
||||||
import SignalCellular3BarIcon from '@material-ui/icons/SignalCellular3Bar';
|
import SignalCellular3BarIcon from '@material-ui/icons/SignalCellular3Bar';
|
||||||
import SignalCellularAltIcon from '@material-ui/icons/SignalCellularAlt';
|
import SignalCellularAltIcon from '@material-ui/icons/SignalCellularAlt';
|
||||||
|
|
||||||
|
const logger = new Logger('VideoView');
|
||||||
|
|
||||||
const styles = (theme) =>
|
const styles = (theme) =>
|
||||||
({
|
({
|
||||||
root :
|
root :
|
||||||
|
|
@ -134,6 +137,10 @@ class VideoView extends React.PureComponent
|
||||||
videoHeight : null
|
videoHeight : null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Latest received audio track
|
||||||
|
// @type {MediaStreamTrack}
|
||||||
|
this._audioTrack = null;
|
||||||
|
|
||||||
// Latest received video track.
|
// Latest received video track.
|
||||||
// @type {MediaStreamTrack}
|
// @type {MediaStreamTrack}
|
||||||
this._videoTrack = null;
|
this._videoTrack = null;
|
||||||
|
|
@ -292,7 +299,7 @@ class VideoView extends React.PureComponent
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<video
|
<video
|
||||||
ref='video'
|
ref='videoElement'
|
||||||
className={classnames(classes.video, {
|
className={classnames(classes.video, {
|
||||||
hidden : !videoVisible,
|
hidden : !videoVisible,
|
||||||
'isMe' : isMe && !isScreen,
|
'isMe' : isMe && !isScreen,
|
||||||
|
|
@ -300,6 +307,16 @@ class VideoView extends React.PureComponent
|
||||||
})}
|
})}
|
||||||
autoPlay
|
autoPlay
|
||||||
playsInline
|
playsInline
|
||||||
|
muted
|
||||||
|
controls={false}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<audio
|
||||||
|
ref='audioElement'
|
||||||
|
autoPlay
|
||||||
|
playsInline
|
||||||
|
muted={isMe}
|
||||||
|
controls={false}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{children}
|
{children}
|
||||||
|
|
@ -309,52 +326,84 @@ class VideoView extends React.PureComponent
|
||||||
|
|
||||||
componentDidMount()
|
componentDidMount()
|
||||||
{
|
{
|
||||||
const { videoTrack } = this.props;
|
const { videoTrack, audioTrack } = this.props;
|
||||||
|
|
||||||
this._setTracks(videoTrack);
|
this._setTracks(videoTrack, audioTrack);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount()
|
componentWillUnmount()
|
||||||
{
|
{
|
||||||
clearInterval(this._videoResolutionTimer);
|
clearInterval(this._videoResolutionTimer);
|
||||||
|
|
||||||
|
const { videoElement } = this.refs;
|
||||||
|
|
||||||
|
if (videoElement)
|
||||||
|
{
|
||||||
|
videoElement.oncanplay = null;
|
||||||
|
videoElement.onplay = null;
|
||||||
|
videoElement.onpause = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
componentWillUpdate()
|
||||||
UNSAFE_componentWillReceiveProps(nextProps)
|
|
||||||
{
|
{
|
||||||
const { videoTrack } = nextProps;
|
const { videoTrack, audioTrack } = this.props;
|
||||||
|
|
||||||
this._setTracks(videoTrack);
|
|
||||||
|
|
||||||
|
this._setTracks(videoTrack, audioTrack);
|
||||||
}
|
}
|
||||||
|
|
||||||
_setTracks(videoTrack)
|
_setTracks(videoTrack, audioTrack)
|
||||||
{
|
{
|
||||||
if (this._videoTrack === videoTrack)
|
if (this._videoTrack === videoTrack && this._audioTrack === audioTrack)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._videoTrack = videoTrack;
|
this._videoTrack = videoTrack;
|
||||||
|
this._audioTrack = audioTrack;
|
||||||
|
|
||||||
clearInterval(this._videoResolutionTimer);
|
clearInterval(this._videoResolutionTimer);
|
||||||
this._hideVideoResolution();
|
this._hideVideoResolution();
|
||||||
|
|
||||||
const { video } = this.refs;
|
const { videoElement, audioElement } = this.refs;
|
||||||
|
|
||||||
if (videoTrack)
|
if (videoTrack)
|
||||||
{
|
{
|
||||||
const stream = new MediaStream();
|
const stream = new MediaStream();
|
||||||
|
|
||||||
if (videoTrack)
|
|
||||||
stream.addTrack(videoTrack);
|
stream.addTrack(videoTrack);
|
||||||
|
|
||||||
video.srcObject = stream;
|
videoElement.srcObject = stream;
|
||||||
|
|
||||||
|
videoElement.oncanplay = () => this.setState({ videoCanPlay: true });
|
||||||
|
|
||||||
|
videoElement.onplay = () =>
|
||||||
|
{
|
||||||
|
audioElement.play()
|
||||||
|
.catch((error) => logger.warn('audioElement.play() [error:"%o]', error));
|
||||||
|
};
|
||||||
|
|
||||||
|
videoElement.play()
|
||||||
|
.catch((error) => logger.warn('videoElement.play() [error:"%o]', error));
|
||||||
|
|
||||||
if (videoTrack)
|
|
||||||
this._showVideoResolution();
|
this._showVideoResolution();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
video.srcObject = null;
|
videoElement.srcObject = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audioTrack)
|
||||||
|
{
|
||||||
|
const stream = new MediaStream();
|
||||||
|
|
||||||
|
stream.addTrack(audioTrack);
|
||||||
|
audioElement.srcObject = stream;
|
||||||
|
|
||||||
|
audioElement.play()
|
||||||
|
.catch((error) => logger.warn('audioElement.play() [error:"%o]', error));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
audioElement.srcObject = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -363,16 +412,19 @@ class VideoView extends React.PureComponent
|
||||||
this._videoResolutionTimer = setInterval(() =>
|
this._videoResolutionTimer = setInterval(() =>
|
||||||
{
|
{
|
||||||
const { videoWidth, videoHeight } = this.state;
|
const { videoWidth, videoHeight } = this.state;
|
||||||
const { video } = this.refs;
|
const { videoElement } = this.refs;
|
||||||
|
|
||||||
// Don't re-render if nothing changed.
|
// Don't re-render if nothing changed.
|
||||||
if (video.videoWidth === videoWidth && video.videoHeight === videoHeight)
|
if (
|
||||||
|
videoElement.videoWidth === videoWidth &&
|
||||||
|
videoElement.videoHeight === videoHeight
|
||||||
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
videoWidth : video.videoWidth,
|
videoWidth : videoElement.videoWidth,
|
||||||
videoHeight : video.videoHeight
|
videoHeight : videoElement.videoHeight
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
@ -392,6 +444,7 @@ VideoView.propTypes =
|
||||||
videoContain : PropTypes.bool,
|
videoContain : PropTypes.bool,
|
||||||
advancedMode : PropTypes.bool,
|
advancedMode : PropTypes.bool,
|
||||||
videoTrack : PropTypes.any,
|
videoTrack : PropTypes.any,
|
||||||
|
audioTrack : PropTypes.any,
|
||||||
videoVisible : PropTypes.bool.isRequired,
|
videoVisible : PropTypes.bool.isRequired,
|
||||||
consumerSpatialLayers : PropTypes.number,
|
consumerSpatialLayers : PropTypes.number,
|
||||||
consumerTemporalLayers : PropTypes.number,
|
consumerTemporalLayers : PropTypes.number,
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import messagesCroatian from './translations/hr';
|
||||||
import messagesCzech from './translations/cs';
|
import messagesCzech from './translations/cs';
|
||||||
import messagesItalian from './translations/it';
|
import messagesItalian from './translations/it';
|
||||||
import messagesUkrainian from './translations/uk';
|
import messagesUkrainian from './translations/uk';
|
||||||
|
import messagesTurkish from './translations/tr';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
|
|
@ -61,7 +62,8 @@ const messages =
|
||||||
'hr' : messagesCroatian,
|
'hr' : messagesCroatian,
|
||||||
'cs' : messagesCzech,
|
'cs' : messagesCzech,
|
||||||
'it' : messagesItalian,
|
'it' : messagesItalian,
|
||||||
'uk' : messagesUkrainian
|
'uk' : messagesUkrainian,
|
||||||
|
'tr' : messagesTurkish
|
||||||
};
|
};
|
||||||
|
|
||||||
const locale = navigator.language.split(/[-_]/)[0]; // language without region code
|
const locale = navigator.language.split(/[-_]/)[0]; // language without region code
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,22 @@
|
||||||
const initialState =
|
const initialState =
|
||||||
{
|
{
|
||||||
name : '',
|
name : '',
|
||||||
state : 'new', // new/connecting/connected/disconnected/closed,
|
// new/connecting/connected/disconnected/closed,
|
||||||
|
state : 'new',
|
||||||
locked : false,
|
locked : false,
|
||||||
inLobby : false,
|
inLobby : false,
|
||||||
signInRequired : false,
|
signInRequired : false,
|
||||||
accessCode : '', // access code to the room if locked and joinByAccessCode == true
|
// access code to the room if locked and joinByAccessCode == true
|
||||||
joinByAccessCode : true, // if true: accessCode is a possibility to open the room
|
accessCode : '',
|
||||||
|
// if true: accessCode is a possibility to open the room
|
||||||
|
joinByAccessCode : true,
|
||||||
activeSpeakerId : null,
|
activeSpeakerId : null,
|
||||||
torrentSupport : false,
|
torrentSupport : false,
|
||||||
showSettings : false,
|
showSettings : false,
|
||||||
fullScreenConsumer : null, // ConsumerID
|
fullScreenConsumer : null, // ConsumerID
|
||||||
windowConsumer : null, // ConsumerID
|
windowConsumer : null, // ConsumerID
|
||||||
toolbarsVisible : true,
|
toolbarsVisible : true,
|
||||||
mode : 'democratic',
|
mode : window.config.defaultLayout || 'democratic',
|
||||||
selectedPeerId : null,
|
selectedPeerId : null,
|
||||||
spotlights : [],
|
spotlights : [],
|
||||||
settingsOpen : false,
|
settingsOpen : false,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ const initialState =
|
||||||
selectedWebcam : null,
|
selectedWebcam : null,
|
||||||
selectedAudioDevice : null,
|
selectedAudioDevice : null,
|
||||||
advancedMode : false,
|
advancedMode : false,
|
||||||
resolution : 'medium', // low, medium, high, veryhigh, ultra
|
// low, medium, high, veryhigh, ultra
|
||||||
|
resolution : window.config.defaultResolution || 'medium',
|
||||||
lastN : 4,
|
lastN : 4,
|
||||||
permanentTopBar : true
|
permanentTopBar : true
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": null,
|
"room.clearChat": null,
|
||||||
"room.clearFileSharing": null,
|
"room.clearFileSharing": null,
|
||||||
"room.speechUnsupported": null,
|
"room.speechUnsupported": null,
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
"me.mutedPTT": null,
|
"me.mutedPTT": null,
|
||||||
|
|
||||||
|
|
@ -69,6 +70,8 @@
|
||||||
"tooltip.settings": "显示设置",
|
"tooltip.settings": "显示设置",
|
||||||
"tooltip.participants": "显示参加者",
|
"tooltip.participants": "显示参加者",
|
||||||
"tooltip.kickParticipant": null,
|
"tooltip.kickParticipant": null,
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
"label.roomName": "房间名称",
|
"label.roomName": "房间名称",
|
||||||
"label.chooseRoomButton": "继续",
|
"label.chooseRoomButton": "继续",
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@
|
||||||
"room.clearChat": null,
|
"room.clearChat": null,
|
||||||
"room.clearFileSharing": null,
|
"room.clearFileSharing": null,
|
||||||
"room.speechUnsupported": null,
|
"room.speechUnsupported": null,
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
"me.mutedPTT": null,
|
"me.mutedPTT": null,
|
||||||
|
|
||||||
|
|
@ -66,6 +67,10 @@
|
||||||
"tooltip.leaveFullscreen": "Vypnout režim celé obrazovky (fullscreen)",
|
"tooltip.leaveFullscreen": "Vypnout režim celé obrazovky (fullscreen)",
|
||||||
"tooltip.lobby": "Ukázat Přijímací místnost",
|
"tooltip.lobby": "Ukázat Přijímací místnost",
|
||||||
"tooltip.settings": "Zobrazit nastavení",
|
"tooltip.settings": "Zobrazit nastavení",
|
||||||
|
"tooltip.participants": null,
|
||||||
|
"tooltip.kickParticipant": null,
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
"label.roomName": "Jméno místnosti",
|
"label.roomName": "Jméno místnosti",
|
||||||
"label.chooseRoomButton": "Pokračovat",
|
"label.chooseRoomButton": "Pokračovat",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": null,
|
"room.clearChat": null,
|
||||||
"room.clearFileSharing": null,
|
"room.clearFileSharing": null,
|
||||||
"room.speechUnsupported": "Dein Browser unterstützt keine Spracherkennung",
|
"room.speechUnsupported": "Dein Browser unterstützt keine Spracherkennung",
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
"me.mutedPTT": "Du bist stummgeschalted, Halte die SPACE-Taste um zu sprechen",
|
"me.mutedPTT": "Du bist stummgeschalted, Halte die SPACE-Taste um zu sprechen",
|
||||||
|
|
||||||
|
|
@ -69,6 +70,8 @@
|
||||||
"tooltip.settings": "Einstellungen",
|
"tooltip.settings": "Einstellungen",
|
||||||
"tooltip.participants": "Teilnehmer",
|
"tooltip.participants": "Teilnehmer",
|
||||||
"tooltip.kickParticipant": "Teilnehmer rauswerfen",
|
"tooltip.kickParticipant": "Teilnehmer rauswerfen",
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
"label.roomName": "Name des Raums",
|
"label.roomName": "Name des Raums",
|
||||||
"label.chooseRoomButton": "Weiter",
|
"label.chooseRoomButton": "Weiter",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": null,
|
"room.clearChat": null,
|
||||||
"room.clearFileSharing": null,
|
"room.clearFileSharing": null,
|
||||||
"room.speechUnsupported": null,
|
"room.speechUnsupported": null,
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
"me.mutedPTT": null,
|
"me.mutedPTT": null,
|
||||||
|
|
||||||
|
|
@ -69,6 +70,8 @@
|
||||||
"tooltip.settings": "Vis indstillinger",
|
"tooltip.settings": "Vis indstillinger",
|
||||||
"tooltip.participants": "Vis deltagere",
|
"tooltip.participants": "Vis deltagere",
|
||||||
"tooltip.kickParticipant": null,
|
"tooltip.kickParticipant": null,
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
"label.roomName": "Værelsesnavn",
|
"label.roomName": "Værelsesnavn",
|
||||||
"label.chooseRoomButton": "Fortsæt",
|
"label.chooseRoomButton": "Fortsæt",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": null,
|
"room.clearChat": null,
|
||||||
"room.clearFileSharing": null,
|
"room.clearFileSharing": null,
|
||||||
"room.speechUnsupported": null,
|
"room.speechUnsupported": null,
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
"me.mutedPTT": null,
|
"me.mutedPTT": null,
|
||||||
|
|
||||||
|
|
@ -69,6 +70,8 @@
|
||||||
"tooltip.settings": "Εμφάνιση ρυθμίσεων",
|
"tooltip.settings": "Εμφάνιση ρυθμίσεων",
|
||||||
"tooltip.participants": "Εμφάνιση συμμετεχόντων",
|
"tooltip.participants": "Εμφάνιση συμμετεχόντων",
|
||||||
"tooltip.kickParticipant": null,
|
"tooltip.kickParticipant": null,
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
"label.roomName": "Όνομα δωματίου",
|
"label.roomName": "Όνομα δωματίου",
|
||||||
"label.chooseRoomButton": "Συνέχεια",
|
"label.chooseRoomButton": "Συνέχεια",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": "Clear chat",
|
"room.clearChat": "Clear chat",
|
||||||
"room.clearFileSharing": "Clear files",
|
"room.clearFileSharing": "Clear files",
|
||||||
"room.speechUnsupported": "Your browser does not support speech recognition",
|
"room.speechUnsupported": "Your browser does not support speech recognition",
|
||||||
|
"room.moderatoractions": "Moderator actions",
|
||||||
|
|
||||||
"me.mutedPTT": "You are muted, hold down SPACE-BAR to talk",
|
"me.mutedPTT": "You are muted, hold down SPACE-BAR to talk",
|
||||||
|
|
||||||
|
|
@ -69,6 +70,8 @@
|
||||||
"tooltip.settings": "Show settings",
|
"tooltip.settings": "Show settings",
|
||||||
"tooltip.participants": "Show participants",
|
"tooltip.participants": "Show participants",
|
||||||
"tooltip.kickParticipant": "Kick out participant",
|
"tooltip.kickParticipant": "Kick out participant",
|
||||||
|
"tooltip.muteParticipant": "Mute participant",
|
||||||
|
"tooltip.muteParticipantVideo": "Mute participant video",
|
||||||
|
|
||||||
"label.roomName": "Room name",
|
"label.roomName": "Room name",
|
||||||
"label.chooseRoomButton": "Continue",
|
"label.chooseRoomButton": "Continue",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": null,
|
"room.clearChat": null,
|
||||||
"room.clearFileSharing": null,
|
"room.clearFileSharing": null,
|
||||||
"room.speechUnsupported": null,
|
"room.speechUnsupported": null,
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
"me.mutedPTT": null,
|
"me.mutedPTT": null,
|
||||||
|
|
||||||
|
|
@ -69,6 +70,8 @@
|
||||||
"tooltip.settings": "Mostrar ajustes",
|
"tooltip.settings": "Mostrar ajustes",
|
||||||
"tooltip.participants": "Mostrar participantes",
|
"tooltip.participants": "Mostrar participantes",
|
||||||
"tooltip.kickParticipant": null,
|
"tooltip.kickParticipant": null,
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
"label.roomName": "Nombre de la sala",
|
"label.roomName": "Nombre de la sala",
|
||||||
"label.chooseRoomButton": "Continuar",
|
"label.chooseRoomButton": "Continuar",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": null,
|
"room.clearChat": null,
|
||||||
"room.clearFileSharing": null,
|
"room.clearFileSharing": null,
|
||||||
"room.speechUnsupported": null,
|
"room.speechUnsupported": null,
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
"me.mutedPTT": null,
|
"me.mutedPTT": null,
|
||||||
|
|
||||||
|
|
@ -69,6 +70,8 @@
|
||||||
"tooltip.settings": "Afficher les paramètres",
|
"tooltip.settings": "Afficher les paramètres",
|
||||||
"tooltip.participants": "Afficher les participants",
|
"tooltip.participants": "Afficher les participants",
|
||||||
"tooltip.kickParticipant": null,
|
"tooltip.kickParticipant": null,
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
"label.roomName": "Nom de la salle",
|
"label.roomName": "Nom de la salle",
|
||||||
"label.chooseRoomButton": "Continuer",
|
"label.chooseRoomButton": "Continuer",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": null,
|
"room.clearChat": null,
|
||||||
"room.clearFileSharing": null,
|
"room.clearFileSharing": null,
|
||||||
"room.speechUnsupported": "Vaš preglednik ne podržava prepoznavanje govora",
|
"room.speechUnsupported": "Vaš preglednik ne podržava prepoznavanje govora",
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
"me.mutedPTT": "Utišani ste, pritisnite i držite SPACE tipku za razgovor",
|
"me.mutedPTT": "Utišani ste, pritisnite i držite SPACE tipku za razgovor",
|
||||||
|
|
||||||
|
|
@ -69,6 +70,8 @@
|
||||||
"tooltip.settings": "Prikaži postavke",
|
"tooltip.settings": "Prikaži postavke",
|
||||||
"tooltip.participants": "Pokažite sudionike",
|
"tooltip.participants": "Pokažite sudionike",
|
||||||
"tooltip.kickParticipant": "Izbaci sudionika",
|
"tooltip.kickParticipant": "Izbaci sudionika",
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
"label.roomName": "Naziv sobe",
|
"label.roomName": "Naziv sobe",
|
||||||
"label.chooseRoomButton": "Nastavi",
|
"label.chooseRoomButton": "Nastavi",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": null,
|
"room.clearChat": null,
|
||||||
"room.clearFileSharing": null,
|
"room.clearFileSharing": null,
|
||||||
"room.speechUnsupported": null,
|
"room.speechUnsupported": null,
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
"me.mutedPTT": null,
|
"me.mutedPTT": null,
|
||||||
|
|
||||||
|
|
@ -69,6 +70,8 @@
|
||||||
"tooltip.settings": "Beállítások",
|
"tooltip.settings": "Beállítások",
|
||||||
"tooltip.participants": "Résztvevők",
|
"tooltip.participants": "Résztvevők",
|
||||||
"tooltip.kickParticipant": null,
|
"tooltip.kickParticipant": null,
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
"label.roomName": "Konferencia",
|
"label.roomName": "Konferencia",
|
||||||
"label.chooseRoomButton": "Tovább",
|
"label.chooseRoomButton": "Tovább",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": null,
|
"room.clearChat": null,
|
||||||
"room.clearFileSharing": null,
|
"room.clearFileSharing": null,
|
||||||
"room.speechUnsupported": null,
|
"room.speechUnsupported": null,
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
"me.mutedPTT": null,
|
"me.mutedPTT": null,
|
||||||
|
|
||||||
|
|
@ -68,6 +69,8 @@
|
||||||
"tooltip.lobby": "Mostra lobby",
|
"tooltip.lobby": "Mostra lobby",
|
||||||
"tooltip.settings": "Mostra impostazioni",
|
"tooltip.settings": "Mostra impostazioni",
|
||||||
"tooltip.participants": "Mostra partecipanti",
|
"tooltip.participants": "Mostra partecipanti",
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
"label.roomName": "Nome della stanza",
|
"label.roomName": "Nome della stanza",
|
||||||
"label.chooseRoomButton": "Continua",
|
"label.chooseRoomButton": "Continua",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": "Tøm chat",
|
"room.clearChat": "Tøm chat",
|
||||||
"room.clearFileSharing": "Fjern filer",
|
"room.clearFileSharing": "Fjern filer",
|
||||||
"room.speechUnsupported": "Din nettleser støtter ikke stemmegjenkjenning",
|
"room.speechUnsupported": "Din nettleser støtter ikke stemmegjenkjenning",
|
||||||
|
"room.moderatoractions": "Moderatorhandlinger",
|
||||||
|
|
||||||
"me.mutedPTT": "Du er dempet, hold nede SPACE for å snakke",
|
"me.mutedPTT": "Du er dempet, hold nede SPACE for å snakke",
|
||||||
|
|
||||||
|
|
@ -69,6 +70,8 @@
|
||||||
"tooltip.settings": "Vis innstillinger",
|
"tooltip.settings": "Vis innstillinger",
|
||||||
"tooltip.participants": "Vis deltakere",
|
"tooltip.participants": "Vis deltakere",
|
||||||
"tooltip.kickParticipant": "Spark ut deltaker",
|
"tooltip.kickParticipant": "Spark ut deltaker",
|
||||||
|
"tooltip.muteParticipant": "Demp deltaker",
|
||||||
|
"tooltip.muteParticipantVideo": "Demp deltakervideo",
|
||||||
|
|
||||||
"label.roomName": "Møtenavn",
|
"label.roomName": "Møtenavn",
|
||||||
"label.chooseRoomButton": "Fortsett",
|
"label.chooseRoomButton": "Fortsett",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": null,
|
"room.clearChat": null,
|
||||||
"room.clearFileSharing": null,
|
"room.clearFileSharing": null,
|
||||||
"room.speechUnsupported": null,
|
"room.speechUnsupported": null,
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
"me.mutedPTT": null,
|
"me.mutedPTT": null,
|
||||||
|
|
||||||
|
|
@ -69,6 +70,8 @@
|
||||||
"tooltip.settings": "Pokaż ustawienia",
|
"tooltip.settings": "Pokaż ustawienia",
|
||||||
"tooltip.participants": "Pokaż uczestników",
|
"tooltip.participants": "Pokaż uczestników",
|
||||||
"tooltip.kickParticipant": null,
|
"tooltip.kickParticipant": null,
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
"label.roomName": "Nazwa konferencji",
|
"label.roomName": "Nazwa konferencji",
|
||||||
"label.chooseRoomButton": "Kontynuuj",
|
"label.chooseRoomButton": "Kontynuuj",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": null,
|
"room.clearChat": null,
|
||||||
"room.clearFileSharing": null,
|
"room.clearFileSharing": null,
|
||||||
"room.speechUnsupported": null,
|
"room.speechUnsupported": null,
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
"me.mutedPTT": null,
|
"me.mutedPTT": null,
|
||||||
|
|
||||||
|
|
@ -69,6 +70,8 @@
|
||||||
"tooltip.settings": "Apresentar definições",
|
"tooltip.settings": "Apresentar definições",
|
||||||
"tooltip.participants": "Apresentar participantes",
|
"tooltip.participants": "Apresentar participantes",
|
||||||
"tooltip.kickParticipant": null,
|
"tooltip.kickParticipant": null,
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
"label.roomName": "Nome da sala",
|
"label.roomName": "Nome da sala",
|
||||||
"label.chooseRoomButton": "Continuar",
|
"label.chooseRoomButton": "Continuar",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": null,
|
"room.clearChat": null,
|
||||||
"room.clearFileSharing": null,
|
"room.clearFileSharing": null,
|
||||||
"room.speechUnsupported": null,
|
"room.speechUnsupported": null,
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
"me.mutedPTT": null,
|
"me.mutedPTT": null,
|
||||||
|
|
||||||
|
|
@ -69,6 +70,8 @@
|
||||||
"tooltip.settings": "Arată setăile",
|
"tooltip.settings": "Arată setăile",
|
||||||
"tooltip.participants": null,
|
"tooltip.participants": null,
|
||||||
"tooltip.kickParticipant": null,
|
"tooltip.kickParticipant": null,
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
"label.roomName": "Numele camerei",
|
"label.roomName": "Numele camerei",
|
||||||
"label.chooseRoomButton": "Continuare",
|
"label.chooseRoomButton": "Continuare",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
{
|
||||||
|
"socket.disconnected": "Bağlantınız Kesildi",
|
||||||
|
"socket.reconnecting": "Bağlantınız kesildi, yeniden bağlanmaya çalışılıyor",
|
||||||
|
"socket.reconnected": "Yeniden bağlandınız",
|
||||||
|
"socket.requestError": "Sunucu isteğinde hata",
|
||||||
|
|
||||||
|
"room.chooseRoom": "Katılmak istediğiniz odanın adını seçin",
|
||||||
|
"room.cookieConsent": "Bu web sayfası kullanıcı deneyimini geliştirmek için çerezleri kullanmaktadır",
|
||||||
|
"room.consentUnderstand": "Anladım",
|
||||||
|
"room.joined": "Odaya katıldın",
|
||||||
|
"room.cantJoin": "Odaya katılamadın",
|
||||||
|
"room.youLocked": "Odayı kilitledin",
|
||||||
|
"room.cantLock": "Oda kilitlenemiyor",
|
||||||
|
"room.youUnLocked": "Odanın kilidini açtın",
|
||||||
|
"room.cantUnLock": "Odanın kilidi açılamıyor",
|
||||||
|
"room.locked": "Oda kilitlendi",
|
||||||
|
"room.unlocked": "Oda kilidi açıldı",
|
||||||
|
"room.newLobbyPeer": "Lobiye yeni katılımcı girdi",
|
||||||
|
"room.lobbyPeerLeft": "Lobiden katılımcı ayrıldı",
|
||||||
|
"room.lobbyPeerChangedDisplayName": "Lobideki katılımcı adını {displayName} olarak değiştirdi",
|
||||||
|
"room.lobbyPeerChangedPicture": "Lobideki katılımcı resim değiştirdi",
|
||||||
|
"room.setAccessCode": "Oda için erişim kodu güncellendi",
|
||||||
|
"room.accessCodeOn": "Oda erişim kodu etkinleştirildi",
|
||||||
|
"room.accessCodeOff": "Oda erişim kodu devre dışı",
|
||||||
|
"room.peerChangedDisplayName": "{oldDisplayName}, {displayName} olarak değiştirildi",
|
||||||
|
"room.newPeer": "{displayName} odaya katıldı",
|
||||||
|
"room.newFile": "Yeni dosya mevcut",
|
||||||
|
"room.toggleAdvancedMode": "Gelişmiş moda geçiş",
|
||||||
|
"room.setDemocraticView": "Demokratik görünüme geçtiniz",
|
||||||
|
"room.setFilmStripView": "Filmşeridi görünümüne geçtiniz",
|
||||||
|
"room.loggedIn": "Giriş yaptınız",
|
||||||
|
"room.loggedOut": "Çıkış yaptınız",
|
||||||
|
"room.changedDisplayName": "Adınız {displayName} olarak değiştirildi",
|
||||||
|
"room.changeDisplayNameError": "Adınız değiştirilirken bir hata oluştu",
|
||||||
|
"room.chatError": "Sohbet mesajı gönderilemiyor",
|
||||||
|
"room.aboutToJoin": "Toplantıya katılmak üzeresiniz",
|
||||||
|
"room.roomId": "Oda ID: {roomName}",
|
||||||
|
"room.setYourName": "Katılım için adınızı belirleyin ve nasıl katılmak istediğinizi seçin:",
|
||||||
|
"room.audioOnly": "Sadece ses",
|
||||||
|
"room.audioVideo": "Ses ve Video",
|
||||||
|
"room.youAreReady": "Tamam, hazırsın",
|
||||||
|
"room.emptyRequireLogin": "Oda boş! Toplantıyı başlatmak için oturum açabilirsiniz veya toplantı sahibi katılana kadar bekleyebilirsiniz",
|
||||||
|
"room.locketWait": "Oda kilitli - birisi içeri alana kadar bekleyiniz ...",
|
||||||
|
"room.lobbyAdministration": "Lobi Yöneticisi",
|
||||||
|
"room.peersInLobby": "Lobideki katılımcılar",
|
||||||
|
"room.lobbyEmpty": "Lobide katılımcı yok",
|
||||||
|
"room.hiddenPeers": "{hiddenPeersCount, plural, one {participant} other {participants}}",
|
||||||
|
"room.me": "Ben",
|
||||||
|
"room.spotlights": "Gündemdeki Katılımcılar",
|
||||||
|
"room.passive": "Pasif Katılımcılar",
|
||||||
|
"room.videoPaused": "Video duraklatıldı",
|
||||||
|
"room.muteAll": null,
|
||||||
|
"room.stopAllVideo": null,
|
||||||
|
"room.closeMeeting": null,
|
||||||
|
"room.clearChat": null,
|
||||||
|
"room.clearFileSharing": null,
|
||||||
|
"room.speechUnsupported": null,
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
|
"tooltip.login": "Giriş",
|
||||||
|
"tooltip.logout": "Çıkış",
|
||||||
|
"tooltip.admitFromLobby": "Lobiden içeri al",
|
||||||
|
"tooltip.lockRoom": "Oda kilitle",
|
||||||
|
"tooltip.unLockRoom": "Oda kilidini aç",
|
||||||
|
"tooltip.enterFullscreen": "Tam Ekrana Geç",
|
||||||
|
"tooltip.leaveFullscreen": "Tam Ekrandan Çık",
|
||||||
|
"tooltip.lobby": "Lobiyi göster",
|
||||||
|
"tooltip.settings": "Ayarları göster",
|
||||||
|
"tooltip.participants": "Katılımcıları göster",
|
||||||
|
"tooltip.kickParticipant": null,
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
|
"label.roomName": "Oda adı",
|
||||||
|
"label.chooseRoomButton": "Devam",
|
||||||
|
"label.yourName": "Adınız",
|
||||||
|
"label.newWindow": "Yeni pencere",
|
||||||
|
"label.fullscreen": "Tam Ekran",
|
||||||
|
"label.openDrawer": "Çiziciyi aç",
|
||||||
|
"label.leave": "Ayrıl",
|
||||||
|
"label.chatInput": "Sohbet mesajı gir...",
|
||||||
|
"label.chat": "Sohbet",
|
||||||
|
"label.filesharing": "Dosya paylaşım",
|
||||||
|
"label.participants": "Katılımcı",
|
||||||
|
"label.shareFile": "Dosya paylaş",
|
||||||
|
"label.fileSharingUnsupported": "Dosya paylaşımı desteklenmiyor",
|
||||||
|
"label.unknown": "Bilinmeyen",
|
||||||
|
"label.democratic": "Demokratik görünüm",
|
||||||
|
"label.filmstrip": "Filmşeridi görünüm",
|
||||||
|
"label.low": "Düşük",
|
||||||
|
"label.medium": "Orta",
|
||||||
|
"label.high": "Yüksek (HD)",
|
||||||
|
"label.veryHigh": "Çok Yüksek (FHD)",
|
||||||
|
"label.ultra": "Ultra (UHD)",
|
||||||
|
"label.close": "Kapat",
|
||||||
|
|
||||||
|
"settings.settings": "Ayarlar",
|
||||||
|
"settings.camera": "Kamera",
|
||||||
|
"settings.selectCamera": "Video aygıtını seç",
|
||||||
|
"settings.cantSelectCamera": "Video aygıtı seçilemiyor",
|
||||||
|
"settings.audio": "Ses aygıtı",
|
||||||
|
"settings.selectAudio": "Ses aygıtını seç",
|
||||||
|
"settings.cantSelectAudio": "Ses aygıtı seçilemiyor",
|
||||||
|
"settings.resolution": "Video çözünürlüğü ayarla",
|
||||||
|
"settings.layout": "Oda düzeni",
|
||||||
|
"settings.selectRoomLayout": "Oda düzeni seç",
|
||||||
|
"settings.advancedMode": "Detaylı mod",
|
||||||
|
"settings.permanentTopBar": "Üst barı kalıcı yap",
|
||||||
|
"settings.lastn": "İzlenebilir video sayısı",
|
||||||
|
|
||||||
|
"filesharing.saveFileError": "Dosya kaydedilemiyor",
|
||||||
|
"filesharing.startingFileShare": "Paylaşılan dosyaya erişiliyor",
|
||||||
|
"filesharing.successfulFileShare": "Dosya başarıyla paylaşıldı",
|
||||||
|
"filesharing.unableToShare": "Dosya paylaşılamıyor",
|
||||||
|
"filesharing.error": "Dosya paylaşım hatası",
|
||||||
|
"filesharing.finished": "Dosya indirilmesi tamamlandı",
|
||||||
|
"filesharing.save": "Kaydet",
|
||||||
|
"filesharing.sharedFile": "{displayName} bir dosya paylaştı",
|
||||||
|
"filesharing.download": "İndir",
|
||||||
|
"filesharing.missingSeeds": "İşlem uzun zaman alıyorsa, bu torrent'i paylaşan kimse olmayabilir. İlgili dosyayı yeniden yüklemesini isteyin.",
|
||||||
|
|
||||||
|
"devices.devicesChanged": "Cihazlarınız değişti, ayarlar kutusundan cihazlarınızı yapılandırın",
|
||||||
|
|
||||||
|
"device.audioUnsupported": "Ses desteklenmiyor",
|
||||||
|
"device.activateAudio": "Sesi aktif et",
|
||||||
|
"device.muteAudio": "Sesi kıs",
|
||||||
|
"device.unMuteAudio": "Sesi aç",
|
||||||
|
|
||||||
|
"device.videoUnsupported": "Video desteklenmiyor",
|
||||||
|
"device.startVideo": "Video başlat",
|
||||||
|
"device.stopVideo": "Video durdur",
|
||||||
|
|
||||||
|
"device.screenSharingUnsupported": "Ekran paylaşımı desteklenmiyor",
|
||||||
|
"device.startScreenSharing": "Ekran paylaşımını başlat",
|
||||||
|
"device.stopScreenSharing": "Ekran paylaşımını durdur",
|
||||||
|
|
||||||
|
"devices.microphoneDisconnected": "Mikrofon bağlı değil",
|
||||||
|
"devices.microphoneError": "Mikrofononuza erişilirken bir hata oluştu",
|
||||||
|
"devices.microPhoneMute": "Mikrofonumu kıs",
|
||||||
|
"devices.micophoneUnMute": "Mikrofonumu aç",
|
||||||
|
"devices.microphoneEnable": "Mikrofonumu aktif et",
|
||||||
|
"devices.microphoneMuteError": "Mikrofonunuz kısılamıyor",
|
||||||
|
"devices.microphoneUnMuteError": "Mikrofonunuz açılamıyor",
|
||||||
|
|
||||||
|
"devices.screenSharingDisconnected" : "Ekran paylaşımı bağlı değil",
|
||||||
|
"devices.screenSharingError": "Ekranınıza erişilirken bir hata oluştu",
|
||||||
|
|
||||||
|
"devices.cameraDisconnected": "Kamera bağlı değil",
|
||||||
|
"devices.cameraError": "Kameranıza erişilirken bir hata oluştu"
|
||||||
|
}
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
"room.clearChat": null,
|
"room.clearChat": null,
|
||||||
"room.clearFileSharing": null,
|
"room.clearFileSharing": null,
|
||||||
"room.speechUnsupported": null,
|
"room.speechUnsupported": null,
|
||||||
|
"room.moderatoractions": null,
|
||||||
|
|
||||||
"tooltip.login": "Увійти",
|
"tooltip.login": "Увійти",
|
||||||
"tooltip.logout": "Вихід",
|
"tooltip.logout": "Вихід",
|
||||||
|
|
@ -66,6 +67,9 @@
|
||||||
"tooltip.lobby": "Показати зал очікувань",
|
"tooltip.lobby": "Показати зал очікувань",
|
||||||
"tooltip.settings": "Показати налаштування",
|
"tooltip.settings": "Показати налаштування",
|
||||||
"tooltip.participants": "Показати учасників",
|
"tooltip.participants": "Показати учасників",
|
||||||
|
"tooltip.kickParticipant": null,
|
||||||
|
"tooltip.muteParticipant": null,
|
||||||
|
"tooltip.muteParticipantVideo": null,
|
||||||
|
|
||||||
"label.roomName": "Назва кімнати",
|
"label.roomName": "Назва кімнати",
|
||||||
"label.chooseRoomButton": "Продовжити",
|
"label.chooseRoomButton": "Продовжити",
|
||||||
|
|
|
||||||
|
|
@ -60,14 +60,16 @@ module.exports =
|
||||||
// session cookie secret
|
// session cookie secret
|
||||||
cookieSecret : 'T0P-S3cR3t_cook!e',
|
cookieSecret : 'T0P-S3cR3t_cook!e',
|
||||||
cookieName : 'multiparty-meeting.sid',
|
cookieName : 'multiparty-meeting.sid',
|
||||||
|
// if you use encrypted private key the set the passphrase
|
||||||
tls :
|
tls :
|
||||||
{
|
{
|
||||||
cert : `${__dirname}/../certs/mediasoup-demo.localhost.cert.pem`,
|
cert : `${__dirname}/../certs/mediasoup-demo.localhost.cert.pem`,
|
||||||
|
// passphrase: 'key_password'
|
||||||
key : `${__dirname}/../certs/mediasoup-demo.localhost.key.pem`
|
key : `${__dirname}/../certs/mediasoup-demo.localhost.key.pem`
|
||||||
},
|
},
|
||||||
// listening Host or IP
|
// listening Host or IP
|
||||||
// If omitted listens on every IP. ("0.0.0.0" and "::")
|
// If omitted listens on every IP. ("0.0.0.0" and "::")
|
||||||
//listeningHost: 'localhost',
|
// listeningHost: 'localhost',
|
||||||
// Listening port for https server.
|
// Listening port for https server.
|
||||||
listeningPort : 443,
|
listeningPort : 443,
|
||||||
// Any http request is redirected to https.
|
// Any http request is redirected to https.
|
||||||
|
|
@ -77,6 +79,12 @@ module.exports =
|
||||||
// listeningRedirectPort disabled
|
// listeningRedirectPort disabled
|
||||||
// use case: loadbalancer backend
|
// use case: loadbalancer backend
|
||||||
httpOnly : false,
|
httpOnly : false,
|
||||||
|
// WebServer/Express trust proxy config for httpOnly mode
|
||||||
|
// You can find more info:
|
||||||
|
// - https://expressjs.com/en/guide/behind-proxies.html
|
||||||
|
// - https://www.npmjs.com/package/proxy-addr
|
||||||
|
// use case: loadbalancer backend
|
||||||
|
trustProxy : '',
|
||||||
// This logger class will have the log function
|
// This logger class will have the log function
|
||||||
// called every time there is a room created or destroyed,
|
// called every time there is a room created or destroyed,
|
||||||
// or peer created or destroyed. This would then be able
|
// or peer created or destroyed. This would then be able
|
||||||
|
|
@ -109,12 +117,6 @@ module.exports =
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, */
|
}, */
|
||||||
// WebServer/Express trust proxy config for httpOnly mode
|
|
||||||
// You can find more info:
|
|
||||||
// - https://expressjs.com/en/guide/behind-proxies.html
|
|
||||||
// - https://www.npmjs.com/package/proxy-addr
|
|
||||||
// use case: loadbalancer backend
|
|
||||||
trustProxy : '',
|
|
||||||
// This function will be called on successful login through oidc.
|
// This function will be called on successful login through oidc.
|
||||||
// Use this function to map your oidc userinfo to the Peer object.
|
// Use this function to map your oidc userinfo to the Peer object.
|
||||||
// The roomId is equal to the room name.
|
// The roomId is equal to the room name.
|
||||||
|
|
@ -325,11 +327,12 @@ module.exports =
|
||||||
{
|
{
|
||||||
listenIps :
|
listenIps :
|
||||||
[
|
[
|
||||||
// change ip to your servers IP address!
|
// change 192.0.2.1 IPv4 to your server's IPv4 address!!
|
||||||
{ ip: '0.0.0.0', announcedIp: null }
|
{ ip: '192.0.2.1', announcedIp: null }
|
||||||
|
|
||||||
// Can have multiple listening interfaces
|
// Can have multiple listening interfaces
|
||||||
// { ip: '::/0', announcedIp: null }
|
// change 2001:DB8::1 IPv6 to your server's IPv6 address!!
|
||||||
|
// { ip: '2001:DB8::1', announcedIp: null }
|
||||||
],
|
],
|
||||||
initialAvailableOutgoingBitrate : 1000000,
|
initialAvailableOutgoingBitrate : 1000000,
|
||||||
minimumAvailableOutgoingBitrate : 600000,
|
minimumAvailableOutgoingBitrate : 600000,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,27 @@ const config = require('../config/config');
|
||||||
|
|
||||||
const logger = new Logger('Room');
|
const logger = new Logger('Room');
|
||||||
|
|
||||||
|
// In case they are not configured properly
|
||||||
|
const accessFromRoles =
|
||||||
|
{
|
||||||
|
BYPASS_ROOM_LOCK : [ userRoles.ADMIN ],
|
||||||
|
BYPASS_LOBBY : [ userRoles.NORMAL ],
|
||||||
|
...config.accessFromRoles
|
||||||
|
};
|
||||||
|
|
||||||
|
const permissionsFromRoles =
|
||||||
|
{
|
||||||
|
CHANGE_ROOM_LOCK : [ userRoles.NORMAL ],
|
||||||
|
PROMOTE_PEER : [ userRoles.NORMAL ],
|
||||||
|
SEND_CHAT : [ userRoles.NORMAL ],
|
||||||
|
MODERATE_CHAT : [ userRoles.MODERATOR ],
|
||||||
|
SHARE_SCREEN : [ userRoles.NORMAL ],
|
||||||
|
SHARE_FILE : [ userRoles.NORMAL ],
|
||||||
|
MODERATE_FILES : [ userRoles.MODERATOR ],
|
||||||
|
MODERATE_ROOM : [ userRoles.MODERATOR ],
|
||||||
|
...config.permissionsFromRoles
|
||||||
|
};
|
||||||
|
|
||||||
class Room extends EventEmitter
|
class Room extends EventEmitter
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
@ -152,7 +173,7 @@ class Room extends EventEmitter
|
||||||
if (returning)
|
if (returning)
|
||||||
this._peerJoining(peer, true);
|
this._peerJoining(peer, true);
|
||||||
else if ( // Has a role that is allowed to bypass room lock
|
else if ( // Has a role that is allowed to bypass room lock
|
||||||
peer.roles.some((role) => config.accessFromRoles.BYPASS_ROOM_LOCK.includes(role))
|
peer.roles.some((role) => accessFromRoles.BYPASS_ROOM_LOCK.includes(role))
|
||||||
)
|
)
|
||||||
this._peerJoining(peer);
|
this._peerJoining(peer);
|
||||||
else if (this._locked)
|
else if (this._locked)
|
||||||
|
|
@ -160,7 +181,7 @@ class Room extends EventEmitter
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Has a role that is allowed to bypass lobby
|
// Has a role that is allowed to bypass lobby
|
||||||
peer.roles.some((role) => config.accessFromRoles.BYPASS_LOBBY.includes(role)) ?
|
peer.roles.some((role) => accessFromRoles.BYPASS_LOBBY.includes(role)) ?
|
||||||
this._peerJoining(peer) :
|
this._peerJoining(peer) :
|
||||||
this._handleGuest(peer);
|
this._handleGuest(peer);
|
||||||
}
|
}
|
||||||
|
|
@ -187,7 +208,11 @@ class Room extends EventEmitter
|
||||||
|
|
||||||
this._peerJoining(promotedPeer);
|
this._peerJoining(promotedPeer);
|
||||||
|
|
||||||
for (const peer of this._getJoinedPeers())
|
for (
|
||||||
|
const peer of this._getPeersWithPermission({
|
||||||
|
permission : permissionsFromRoles.PROMOTE_PEER
|
||||||
|
})
|
||||||
|
)
|
||||||
{
|
{
|
||||||
this._notification(peer.socket, 'lobby:promotedPeer', { peerId: id });
|
this._notification(peer.socket, 'lobby:promotedPeer', { peerId: id });
|
||||||
}
|
}
|
||||||
|
|
@ -196,7 +221,7 @@ class Room extends EventEmitter
|
||||||
this._lobby.on('peerRolesChanged', (peer) =>
|
this._lobby.on('peerRolesChanged', (peer) =>
|
||||||
{
|
{
|
||||||
if ( // Has a role that is allowed to bypass room lock
|
if ( // Has a role that is allowed to bypass room lock
|
||||||
peer.roles.some((role) => config.accessFromRoles.BYPASS_ROOM_LOCK.includes(role))
|
peer.roles.some((role) => accessFromRoles.BYPASS_ROOM_LOCK.includes(role))
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this._lobby.promotePeer(peer.id);
|
this._lobby.promotePeer(peer.id);
|
||||||
|
|
@ -206,7 +231,7 @@ class Room extends EventEmitter
|
||||||
|
|
||||||
if ( // Has a role that is allowed to bypass lobby
|
if ( // Has a role that is allowed to bypass lobby
|
||||||
!this._locked &&
|
!this._locked &&
|
||||||
peer.roles.some((role) => config.accessFromRoles.BYPASS_LOBBY.includes(role))
|
peer.roles.some((role) => accessFromRoles.BYPASS_LOBBY.includes(role))
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this._lobby.promotePeer(peer.id);
|
this._lobby.promotePeer(peer.id);
|
||||||
|
|
@ -219,7 +244,11 @@ class Room extends EventEmitter
|
||||||
{
|
{
|
||||||
const { id, displayName } = changedPeer;
|
const { id, displayName } = changedPeer;
|
||||||
|
|
||||||
for (const peer of this._getJoinedPeers())
|
for (
|
||||||
|
const peer of this._getPeersWithPermission({
|
||||||
|
permission : permissionsFromRoles.PROMOTE_PEER
|
||||||
|
})
|
||||||
|
)
|
||||||
{
|
{
|
||||||
this._notification(peer.socket, 'lobby:changeDisplayName', { peerId: id, displayName });
|
this._notification(peer.socket, 'lobby:changeDisplayName', { peerId: id, displayName });
|
||||||
}
|
}
|
||||||
|
|
@ -229,7 +258,11 @@ class Room extends EventEmitter
|
||||||
{
|
{
|
||||||
const { id, picture } = changedPeer;
|
const { id, picture } = changedPeer;
|
||||||
|
|
||||||
for (const peer of this._getJoinedPeers())
|
for (
|
||||||
|
const peer of this._getPeersWithPermission({
|
||||||
|
permission : permissionsFromRoles.PROMOTE_PEER
|
||||||
|
})
|
||||||
|
)
|
||||||
{
|
{
|
||||||
this._notification(peer.socket, 'lobby:changePicture', { peerId: id, picture });
|
this._notification(peer.socket, 'lobby:changePicture', { peerId: id, picture });
|
||||||
}
|
}
|
||||||
|
|
@ -241,7 +274,11 @@ class Room extends EventEmitter
|
||||||
|
|
||||||
const { id } = closedPeer;
|
const { id } = closedPeer;
|
||||||
|
|
||||||
for (const peer of this._getJoinedPeers())
|
for (
|
||||||
|
const peer of this._getPeersWithPermission({
|
||||||
|
permission : permissionsFromRoles.PROMOTE_PEER
|
||||||
|
})
|
||||||
|
)
|
||||||
{
|
{
|
||||||
this._notification(peer.socket, 'lobby:peerClosed', { peerId: id });
|
this._notification(peer.socket, 'lobby:peerClosed', { peerId: id });
|
||||||
}
|
}
|
||||||
|
|
@ -344,7 +381,11 @@ class Room extends EventEmitter
|
||||||
{
|
{
|
||||||
this._lobby.parkPeer(parkPeer);
|
this._lobby.parkPeer(parkPeer);
|
||||||
|
|
||||||
for (const peer of this._getJoinedPeers())
|
for (
|
||||||
|
const peer of this._getPeersWithPermission({
|
||||||
|
permission : permissionsFromRoles.PROMOTE_PEER
|
||||||
|
})
|
||||||
|
)
|
||||||
{
|
{
|
||||||
this._notification(peer.socket, 'parkedPeer', { peerId: parkPeer.id });
|
this._notification(peer.socket, 'parkedPeer', { peerId: parkPeer.id });
|
||||||
}
|
}
|
||||||
|
|
@ -550,7 +591,7 @@ class Room extends EventEmitter
|
||||||
peers : peerInfos,
|
peers : peerInfos,
|
||||||
tracker : config.fileTracker,
|
tracker : config.fileTracker,
|
||||||
authenticated : peer.authenticated,
|
authenticated : peer.authenticated,
|
||||||
permissionsFromRoles : config.permissionsFromRoles,
|
permissionsFromRoles : permissionsFromRoles,
|
||||||
userRoles : userRoles
|
userRoles : userRoles
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -682,7 +723,8 @@ class Room extends EventEmitter
|
||||||
|
|
||||||
if (
|
if (
|
||||||
appData.source === 'screen' &&
|
appData.source === 'screen' &&
|
||||||
!peer.roles.some((role) => config.permissionsFromRoles.SHARE_SCREEN.includes(role))
|
!peer.roles.some(
|
||||||
|
(role) => permissionsFromRoles.SHARE_SCREEN.includes(role))
|
||||||
)
|
)
|
||||||
throw new Error('peer not authorized');
|
throw new Error('peer not authorized');
|
||||||
|
|
||||||
|
|
@ -985,7 +1027,7 @@ class Room extends EventEmitter
|
||||||
case 'chatMessage':
|
case 'chatMessage':
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!peer.roles.some((role) => config.permissionsFromRoles.SEND_CHAT.includes(role))
|
!peer.roles.some((role) => permissionsFromRoles.SEND_CHAT.includes(role))
|
||||||
)
|
)
|
||||||
throw new Error('peer not authorized');
|
throw new Error('peer not authorized');
|
||||||
|
|
||||||
|
|
@ -1008,7 +1050,9 @@ class Room extends EventEmitter
|
||||||
case 'moderator:clearChat':
|
case 'moderator:clearChat':
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!peer.roles.some((role) => config.permissionsFromRoles.MODERATE_CHAT.includes(role))
|
!peer.roles.some(
|
||||||
|
(role) => permissionsFromRoles.MODERATE_CHAT.includes(role)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
throw new Error('peer not authorized');
|
throw new Error('peer not authorized');
|
||||||
|
|
||||||
|
|
@ -1046,7 +1090,9 @@ class Room extends EventEmitter
|
||||||
case 'lockRoom':
|
case 'lockRoom':
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!peer.roles.some((role) => config.permissionsFromRoles.CHANGE_ROOM_LOCK.includes(role))
|
!peer.roles.some(
|
||||||
|
(role) => permissionsFromRoles.CHANGE_ROOM_LOCK.includes(role)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
throw new Error('peer not authorized');
|
throw new Error('peer not authorized');
|
||||||
|
|
||||||
|
|
@ -1066,7 +1112,9 @@ class Room extends EventEmitter
|
||||||
case 'unlockRoom':
|
case 'unlockRoom':
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!peer.roles.some((role) => config.permissionsFromRoles.CHANGE_ROOM_LOCK.includes(role))
|
!peer.roles.some(
|
||||||
|
(role) => permissionsFromRoles.CHANGE_ROOM_LOCK.includes(role)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
throw new Error('peer not authorized');
|
throw new Error('peer not authorized');
|
||||||
|
|
||||||
|
|
@ -1126,7 +1174,9 @@ class Room extends EventEmitter
|
||||||
case 'promotePeer':
|
case 'promotePeer':
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!peer.roles.some((role) => config.permissionsFromRoles.PROMOTE_PEER.includes(role))
|
!peer.roles.some(
|
||||||
|
(role) => permissionsFromRoles.PROMOTE_PEER.includes(role)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
throw new Error('peer not authorized');
|
throw new Error('peer not authorized');
|
||||||
|
|
||||||
|
|
@ -1143,7 +1193,9 @@ class Room extends EventEmitter
|
||||||
case 'promoteAllPeers':
|
case 'promoteAllPeers':
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!peer.roles.some((role) => config.permissionsFromRoles.PROMOTE_PEER.includes(role))
|
!peer.roles.some(
|
||||||
|
(role) => permissionsFromRoles.PROMOTE_PEER.includes(role)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
throw new Error('peer not authorized');
|
throw new Error('peer not authorized');
|
||||||
|
|
||||||
|
|
@ -1158,7 +1210,9 @@ class Room extends EventEmitter
|
||||||
case 'sendFile':
|
case 'sendFile':
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!peer.roles.some((role) => config.permissionsFromRoles.SHARE_FILE.includes(role))
|
!peer.roles.some(
|
||||||
|
(role) => permissionsFromRoles.SHARE_FILE.includes(role)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
throw new Error('peer not authorized');
|
throw new Error('peer not authorized');
|
||||||
|
|
||||||
|
|
@ -1181,7 +1235,9 @@ class Room extends EventEmitter
|
||||||
case 'moderator:clearFileSharing':
|
case 'moderator:clearFileSharing':
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!peer.roles.some((role) => config.permissionsFromRoles.MODERATE_FILES.includes(role))
|
!peer.roles.some(
|
||||||
|
(role) => permissionsFromRoles.MODERATE_FILES.includes(role)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
throw new Error('peer not authorized');
|
throw new Error('peer not authorized');
|
||||||
|
|
||||||
|
|
@ -1217,7 +1273,9 @@ class Room extends EventEmitter
|
||||||
case 'moderator:muteAll':
|
case 'moderator:muteAll':
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!peer.roles.some((role) => config.permissionsFromRoles.MODERATE_ROOM.includes(role))
|
!peer.roles.some(
|
||||||
|
(role) => permissionsFromRoles.MODERATE_ROOM.includes(role)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
throw new Error('peer not authorized');
|
throw new Error('peer not authorized');
|
||||||
|
|
||||||
|
|
@ -1232,7 +1290,9 @@ class Room extends EventEmitter
|
||||||
case 'moderator:stopAllVideo':
|
case 'moderator:stopAllVideo':
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!peer.roles.some((role) => config.permissionsFromRoles.MODERATE_ROOM.includes(role))
|
!peer.roles.some(
|
||||||
|
(role) => permissionsFromRoles.MODERATE_ROOM.includes(role)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
throw new Error('peer not authorized');
|
throw new Error('peer not authorized');
|
||||||
|
|
||||||
|
|
@ -1247,7 +1307,9 @@ class Room extends EventEmitter
|
||||||
case 'moderator:closeMeeting':
|
case 'moderator:closeMeeting':
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!peer.roles.some((role) => config.permissionsFromRoles.MODERATE_ROOM.includes(role))
|
!peer.roles.some(
|
||||||
|
(role) => permissionsFromRoles.MODERATE_ROOM.includes(role)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
throw new Error('peer not authorized');
|
throw new Error('peer not authorized');
|
||||||
|
|
||||||
|
|
@ -1264,7 +1326,9 @@ class Room extends EventEmitter
|
||||||
case 'moderator:kickPeer':
|
case 'moderator:kickPeer':
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!peer.roles.some((role) => config.permissionsFromRoles.MODERATE_ROOM.includes(role))
|
!peer.roles.some(
|
||||||
|
(role) => permissionsFromRoles.MODERATE_ROOM.includes(role)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
throw new Error('peer not authorized');
|
throw new Error('peer not authorized');
|
||||||
|
|
||||||
|
|
@ -1452,6 +1516,19 @@ class Room extends EventEmitter
|
||||||
.filter((peer) => peer.joined && peer !== excludePeer);
|
.filter((peer) => peer.joined && peer !== excludePeer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getPeersWithPermission({ permission = null, excludePeer = undefined, joined = true })
|
||||||
|
{
|
||||||
|
return Object.values(this._peers)
|
||||||
|
.filter(
|
||||||
|
(peer) =>
|
||||||
|
peer.joined === joined &&
|
||||||
|
peer !== excludePeer &&
|
||||||
|
peer.roles.some(
|
||||||
|
(role) => permission.includes(role)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
_timeoutCallback(callback)
|
_timeoutCallback(callback)
|
||||||
{
|
{
|
||||||
let called = false;
|
let called = false;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "DEBUG=${DEBUG:='*mediasoup* *INFO* *WARN* *ERROR*'} INTERACTIVE=${INTERACTIVE:='true'} node server.js",
|
"start": "DEBUG=${DEBUG:='*mediasoup* *INFO* *WARN* *ERROR*'} INTERACTIVE=${INTERACTIVE:='true'} node server.js",
|
||||||
"connect": "node connect.js"
|
"connect": "node connect.js",
|
||||||
|
"lint": "eslint -c .eslintrc.json --ext .js *.js lib/"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"awaitqueue": "^1.0.0",
|
"awaitqueue": "^1.0.0",
|
||||||
|
|
@ -36,5 +37,8 @@
|
||||||
"socket.io": "^2.3.0",
|
"socket.io": "^2.3.0",
|
||||||
"spdy": "^4.0.1",
|
"spdy": "^4.0.1",
|
||||||
"uuid": "^7.0.2"
|
"uuid": "^7.0.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint": "6.8.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,7 @@ function setupLTI(ltiConfig)
|
||||||
if (lti.user_id && lti.custom_room)
|
if (lti.user_id && lti.custom_room)
|
||||||
{
|
{
|
||||||
user.id = lti.user_id;
|
user.id = lti.user_id;
|
||||||
user._userinfo = { "lti" : lti };
|
user._userinfo = { 'lti': lti };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lti.custom_room)
|
if (lti.custom_room)
|
||||||
|
|
@ -244,7 +244,18 @@ function setupOIDC(oidcIssuer)
|
||||||
// redirect_uri defaults to client.redirect_uris[0]
|
// redirect_uri defaults to client.redirect_uris[0]
|
||||||
// response type defaults to client.response_types[0], then 'code'
|
// response type defaults to client.response_types[0], then 'code'
|
||||||
// scope defaults to 'openid'
|
// scope defaults to 'openid'
|
||||||
const params = config.auth.oidc.clientOptions;
|
|
||||||
|
/* eslint-disable camelcase */
|
||||||
|
const params = (({
|
||||||
|
client_id,
|
||||||
|
redirect_uri,
|
||||||
|
scope
|
||||||
|
}) => ({
|
||||||
|
client_id,
|
||||||
|
redirect_uri,
|
||||||
|
scope
|
||||||
|
}))(config.auth.oidc.clientOptions);
|
||||||
|
/* eslint-enable camelcase */
|
||||||
|
|
||||||
// optional, defaults to false, when true req is passed as a first
|
// optional, defaults to false, when true req is passed as a first
|
||||||
// argument to verify fn
|
// argument to verify fn
|
||||||
|
|
@ -259,7 +270,9 @@ function setupOIDC(oidcIssuer)
|
||||||
{ client: oidcClient, params, passReqToCallback, usePKCE },
|
{ client: oidcClient, params, passReqToCallback, usePKCE },
|
||||||
(tokenset, userinfo, done) =>
|
(tokenset, userinfo, done) =>
|
||||||
{
|
{
|
||||||
if (userinfo && tokenset) {
|
if (userinfo && tokenset)
|
||||||
|
{
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
userinfo._tokenset_claims = tokenset.claims();
|
userinfo._tokenset_claims = tokenset.claims();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -434,14 +447,14 @@ async function runHttpsServer()
|
||||||
// http
|
// http
|
||||||
const redirectListener = http.createServer(app);
|
const redirectListener = http.createServer(app);
|
||||||
|
|
||||||
if(config.listeningHost)
|
if (config.listeningHost)
|
||||||
redirectListener.listen(config.listeningRedirectPort, config.listeningHost);
|
redirectListener.listen(config.listeningRedirectPort, config.listeningHost);
|
||||||
else
|
else
|
||||||
redirectListener.listen(config.listeningRedirectPort);
|
redirectListener.listen(config.listeningRedirectPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https or http
|
// https or http
|
||||||
if(config.listeningHost)
|
if (config.listeningHost)
|
||||||
mainListener.listen(config.listeningPort, config.listeningHost);
|
mainListener.listen(config.listeningPort, config.listeningHost);
|
||||||
else
|
else
|
||||||
mainListener.listen(config.listeningPort);
|
mainListener.listen(config.listeningPort);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue