diff --git a/app/.env b/app/.env
new file mode 100644
index 0000000..86c714e
--- /dev/null
+++ b/app/.env
@@ -0,0 +1,2 @@
+REACT_APP_VERSION=$npm_package_version
+REACT_APP_NAME=$npm_package_name
\ No newline at end of file
diff --git a/app/public/config/config.example.js b/app/public/config/config.example.js
index 4c7f249..bbd9a03 100644
--- a/app/public/config/config.example.js
+++ b/app/public/config/config.example.js
@@ -37,20 +37,22 @@ var config =
'opera'
],
// Socket.io request timeout
- requestTimeout : 10000,
+ requestTimeout : 20000,
+ requestRetries : 3,
transportOptions :
{
tcp : true
},
defaultAudio :
{
- sampleRate : 48000,
- channelCount : 1,
- volume : 1.0,
- autoGainControl : true,
- echoCancellation : true,
- noiseSuppression : true,
- sampleSize : 16
+ sampleRate : 48000,
+ channelCount : 1,
+ volume : 1.0,
+ autoGainControl : true,
+ echoCancellation : true,
+ noiseSuppression : true,
+ voiceActivityMute : false,
+ sampleSize : 16
},
/**
diff --git a/app/src/RoomClient.js b/app/src/RoomClient.js
index a936a14..7d7336c 100644
--- a/app/src/RoomClient.js
+++ b/app/src/RoomClient.js
@@ -1,6 +1,7 @@
import Logger from './Logger';
import hark from 'hark';
import { getSignalingUrl } from './urlFactory';
+import { SocketTimeoutError } from './utils';
import * as requestActions from './actions/requestActions';
import * as meActions from './actions/meActions';
import * as roomActions from './actions/roomActions';
@@ -314,7 +315,7 @@ export default class RoomClient
{
const newPeerId = this._spotlights.getNextAsSelected(
store.getState().room.selectedPeerId);
-
+
if (newPeerId) this.setSelectedPeer(newPeerId);
break;
}
@@ -574,7 +575,7 @@ export default class RoomClient
if (called)
return;
called = true;
- callback(new Error('Request timeout.'));
+ callback(new SocketTimeoutError('Request timed out'));
},
ROOM_OPTIONS.requestTimeout
);
@@ -590,13 +591,13 @@ export default class RoomClient
};
}
- sendRequest(method, data)
+ _sendRequest(method, data)
{
return new Promise((resolve, reject) =>
{
if (!this._signalingSocket)
{
- reject('No socket connection.');
+ reject('No socket connection');
}
else
{
@@ -606,19 +607,42 @@ export default class RoomClient
this.timeoutCallback((err, response) =>
{
if (err)
- {
reject(err);
- }
else
- {
resolve(response);
- }
})
);
}
});
}
+ async sendRequest(method, data)
+ {
+ logger.debug('sendRequest() [method:"%s", data:"%o"]', method, data);
+
+ const {
+ requestRetries = 3
+ } = window.config;
+
+ for (let tries = 0; tries < requestRetries; tries++)
+ {
+ try
+ {
+ return await this._sendRequest(method, data);
+ }
+ catch (error)
+ {
+ if (
+ error instanceof SocketTimeoutError &&
+ tries < requestRetries
+ )
+ logger.warn('sendRequest() | timeout, retrying [attempt:"%s"]', tries);
+ else
+ throw error;
+ }
+ }
+ }
+
async changeDisplayName(displayName)
{
logger.debug('changeDisplayName() [displayName:"%s"]', displayName);
@@ -774,7 +798,7 @@ export default class RoomClient
}
});
- torrent.on('done', () =>
+ torrent.on('done', () =>
{
store.dispatch(
fileActions.setFileDone(
@@ -924,7 +948,7 @@ export default class RoomClient
{
await this.sendRequest(
'resumeProducer', { producerId: this._micProducer.id });
-
+
store.dispatch(
producerActions.setProducerResumed(this._micProducer.id));
}
@@ -976,23 +1000,23 @@ export default class RoomClient
}
}
- disconnectLocalHark()
+ disconnectLocalHark()
{
logger.debug('disconnectLocalHark() | Stopping harkStream.');
- if (this._harkStream != null)
+ if (this._harkStream != null)
{
this._harkStream.getAudioTracks()[0].stop();
this._harkStream = null;
}
- if (this._hark != null)
+ if (this._hark != null)
{
logger.debug('disconnectLocalHark() Stopping hark.');
this._hark.stop();
}
}
- connectLocalHark(track)
+ connectLocalHark(track)
{
logger.debug('connectLocalHark() | Track:%o', track);
this._harkStream = new MediaStream();
@@ -1003,37 +1027,50 @@ export default class RoomClient
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)
+ this._hark = hark(this._harkStream,
{
- this._micProducer.volume = volume;
+ play : false,
+ interval : 5,
+ threshold : store.getState().settings.noiseThreshold,
+ history : 300
+ });
+ this._hark.lastVolume = -100;
+ this._hark.on('volume_change', (volume) =>
+ {
+ volume = Math.round(volume);
+ if (this._micProducer && volume !== Math.round(this._hark.lastVolume))
+ {
+ if (volume < this._hark.lastVolume * 1.02)
+ {
+ volume = this._hark.lastVolume * 1.02;
+ }
+ this._hark.lastVolume = volume;
store.dispatch(peerVolumeActions.setPeerVolume(this._peerId, volume));
}
});
- this._hark.on('speaking', function()
+ this._hark.on('speaking', () =>
{
store.dispatch(meActions.setIsSpeaking(true));
+ if ((store.getState().settings.voiceActivatedUnmute ||
+ store.getState().me.isAutoMuted) &&
+ this._micProducer &&
+ this._micProducer.paused)
+ {
+ this._micProducer.resume();
+ }
+ store.dispatch(meActions.setAutoMuted(false)); // sanity action
});
- this._hark.on('stopped_speaking', function()
+ this._hark.on('stopped_speaking', () =>
{
store.dispatch(meActions.setIsSpeaking(false));
+ if (store.getState().settings.voiceActivatedUnmute &&
+ this._micProducer &&
+ !this._micProducer.paused)
+ {
+ this._micProducer.pause();
+ store.dispatch(meActions.setAutoMuted(true));
+ }
});
}
@@ -1045,7 +1082,7 @@ export default class RoomClient
meActions.setAudioInProgress(true));
try
- {
+ {
const device = this._audioDevices[deviceId];
if (!device)
@@ -1164,7 +1201,7 @@ export default class RoomClient
...VIDEO_CONSTRAINS[resolution]
}
});
-
+
if (stream)
{
const track = stream.getVideoTracks()[0];
@@ -1175,15 +1212,15 @@ export default class RoomClient
{
await this._webcamProducer.replaceTrack({ track });
}
- else
+ else
{
this._webcamProducer = await this._sendTransport.produce({
track,
- appData :
+ appData :
{
source : 'webcam'
}
- });
+ });
}
store.dispatch(
@@ -1193,7 +1230,7 @@ export default class RoomClient
{
logger.warn('getVideoTracks Error: First Video Track is null');
}
-
+
}
else
{
@@ -1227,7 +1264,7 @@ export default class RoomClient
if (!device)
throw new Error('no webcam devices');
-
+
logger.debug(
'changeWebcam() | new selected webcam [device:%o]',
device);
@@ -1255,17 +1292,17 @@ export default class RoomClient
{
await this._webcamProducer.replaceTrack({ track });
}
- else
+ else
{
this._webcamProducer = await this._sendTransport.produce({
track,
- appData :
+ appData :
{
source : 'webcam'
}
- });
+ });
}
-
+
store.dispatch(
producerActions.setProducerTrack(this._webcamProducer.id, track));
@@ -1274,7 +1311,7 @@ export default class RoomClient
{
logger.warn('getVideoTracks Error: First Video Track is null');
}
-
+
}
else
{
@@ -1962,23 +1999,12 @@ export default class RoomClient
producerPaused
} = request.data;
- let codecOptions;
-
- if (kind === 'audio')
- {
- codecOptions =
- {
- opusStereo : 1
- };
- }
-
const consumer = await this._recvTransport.consume(
{
id,
producerId,
kind,
rtpParameters,
- codecOptions,
appData : { ...appData, peerId } // Trick.
});
@@ -2031,19 +2057,8 @@ export default class RoomClient
consumer.hark = hark(stream, { play: false });
- // eslint-disable-next-line no-unused-vars
- consumer.hark.on('volume_change', (dBs, threshold) =>
+ consumer.hark.on('volume_change', (volume) =>
{
- // 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 (consumer && volume !== consumer.volume)
@@ -2083,7 +2098,7 @@ export default class RoomClient
const { displayName } = store.getState().settings;
const { picture } = store.getState().me;
-
+
await this.sendRequest('changeDisplayName', { displayName });
await this.sendRequest('changePicture', { picture });
break;
@@ -2092,10 +2107,10 @@ export default class RoomClient
case 'signInRequired':
{
store.dispatch(roomActions.setSignInRequired(true));
-
+
break;
}
-
+
case 'overRoomLimit':
{
store.dispatch(roomActions.setOverRoomLimit(true));
@@ -2111,24 +2126,24 @@ export default class RoomClient
store.dispatch(roomActions.toggleJoined());
store.dispatch(roomActions.setInLobby(false));
-
+
await this._joinRoom({ joinVideo });
-
+
break;
}
case 'roomBack':
{
await this._joinRoom({ joinVideo });
-
+
break;
}
-
+
case 'lockRoom':
{
store.dispatch(
roomActions.setRoomLocked());
-
+
store.dispatch(requestActions.notify(
{
text : intl.formatMessage({
@@ -2136,15 +2151,15 @@ export default class RoomClient
defaultMessage : 'Room is now locked'
})
}));
-
+
break;
}
-
+
case 'unlockRoom':
{
store.dispatch(
roomActions.setRoomUnLocked());
-
+
store.dispatch(requestActions.notify(
{
text : intl.formatMessage({
@@ -2152,21 +2167,21 @@ export default class RoomClient
defaultMessage : 'Room is now unlocked'
})
}));
-
+
break;
}
-
+
case 'parkedPeer':
{
const { peerId } = notification.data;
-
+
store.dispatch(
lobbyPeerActions.addLobbyPeer(peerId));
store.dispatch(
roomActions.setToolbarsVisible(true));
this._soundNotification();
-
+
store.dispatch(requestActions.notify(
{
text : intl.formatMessage({
@@ -2174,7 +2189,7 @@ export default class RoomClient
defaultMessage : 'New participant entered the lobby'
})
}));
-
+
break;
}
@@ -2203,7 +2218,7 @@ export default class RoomClient
)
);
});
-
+
store.dispatch(
roomActions.setToolbarsVisible(true));
@@ -2220,14 +2235,14 @@ export default class RoomClient
break;
}
-
+
case 'lobby:peerClosed':
{
const { peerId } = notification.data;
-
+
store.dispatch(
lobbyPeerActions.removeLobbyPeer(peerId));
-
+
store.dispatch(requestActions.notify(
{
text : intl.formatMessage({
@@ -2235,10 +2250,10 @@ export default class RoomClient
defaultMessage : 'Participant in lobby left'
})
}));
-
+
break;
}
-
+
case 'lobby:promotedPeer':
{
const { peerId } = notification.data;
@@ -2248,7 +2263,7 @@ export default class RoomClient
break;
}
-
+
case 'lobby:changeDisplayName':
{
const { peerId, displayName } = notification.data;
@@ -2268,11 +2283,11 @@ export default class RoomClient
break;
}
-
+
case 'lobby:changePicture':
{
const { peerId, picture } = notification.data;
-
+
store.dispatch(
lobbyPeerActions.setLobbyPeerPicture(picture, peerId));
@@ -2290,7 +2305,7 @@ export default class RoomClient
case 'setAccessCode':
{
const { accessCode } = notification.data;
-
+
store.dispatch(
roomActions.setAccessCode(accessCode));
@@ -2304,14 +2319,14 @@ export default class RoomClient
break;
}
-
+
case 'setJoinByAccessCode':
{
const { joinByAccessCode } = notification.data;
-
+
store.dispatch(
roomActions.setJoinByAccessCode(joinByAccessCode));
-
+
if (joinByAccessCode)
{
store.dispatch(requestActions.notify(
@@ -2322,7 +2337,7 @@ export default class RoomClient
})
}));
}
- else
+ else
{
store.dispatch(requestActions.notify(
{
@@ -2335,20 +2350,20 @@ export default class RoomClient
break;
}
-
+
case 'activeSpeaker':
{
const { peerId } = notification.data;
-
+
store.dispatch(
roomActions.setRoomActiveSpeaker(peerId));
if (peerId && peerId !== this._peerId)
this._spotlights.handleActiveSpeaker(peerId);
-
+
break;
}
-
+
case 'changeDisplayName':
{
const { peerId, displayName, oldDisplayName } = notification.data;
@@ -2556,74 +2571,74 @@ export default class RoomClient
{
const { consumerId } = notification.data;
const consumer = this._consumers.get(consumerId);
-
+
if (!consumer)
break;
-
+
consumer.close();
-
+
if (consumer.hark != null)
consumer.hark.stop();
-
+
this._consumers.delete(consumerId);
-
+
const { peerId } = consumer.appData;
-
+
store.dispatch(
consumerActions.removeConsumer(consumerId, peerId));
-
+
break;
}
-
+
case 'consumerPaused':
{
const { consumerId } = notification.data;
const consumer = this._consumers.get(consumerId);
-
+
if (!consumer)
break;
-
+
store.dispatch(
consumerActions.setConsumerPaused(consumerId, 'remote'));
break;
}
-
+
case 'consumerResumed':
{
const { consumerId } = notification.data;
const consumer = this._consumers.get(consumerId);
-
+
if (!consumer)
break;
-
+
store.dispatch(
consumerActions.setConsumerResumed(consumerId, 'remote'));
-
+
break;
}
-
+
case 'consumerLayersChanged':
{
const { consumerId, spatialLayer, temporalLayer } = notification.data;
const consumer = this._consumers.get(consumerId);
-
+
if (!consumer)
break;
-
+
store.dispatch(consumerActions.setConsumerCurrentLayers(
consumerId, spatialLayer, temporalLayer));
-
+
break;
}
-
+
case 'consumerScore':
{
const { consumerId, score } = notification.data;
-
+
store.dispatch(
consumerActions.setConsumerScore(consumerId, score));
-
+
break;
}
@@ -2667,7 +2682,7 @@ export default class RoomClient
store.dispatch(requestActions.notify(
{
text : intl.formatMessage({
- id : 'moderator.muteScreenSharingModerator',
+ id : 'moderator.stopScreenSharing',
defaultMessage : 'Moderator stopped your screen sharing'
})
}));
@@ -2737,7 +2752,7 @@ export default class RoomClient
break;
}
-
+
default:
{
logger.error(
@@ -2784,7 +2799,7 @@ export default class RoomClient
this._webTorrent.on('error', (error) =>
{
logger.error('Filesharing [error:"%o"]', error);
-
+
store.dispatch(requestActions.notify(
{
type : 'error',
@@ -3006,7 +3021,7 @@ export default class RoomClient
);
}
- locked ?
+ locked ?
store.dispatch(roomActions.setRoomLocked()) :
store.dispatch(roomActions.setRoomUnLocked());
@@ -3032,14 +3047,14 @@ export default class RoomClient
await this.enableMic();
const { autoMuteThreshold } = store.getState().settings;
- if (autoMuteThreshold && peers.length > autoMuteThreshold)
+ if (autoMuteThreshold && peers.length > autoMuteThreshold)
this.muteMic();
}
if (joinVideo && this._mediasoupDevice.canProduce('video'))
this.enableWebcam();
}
-
+
await this._updateAudioOutputDevices();
const { selectedAudioOutputDevice } = store.getState().settings;
@@ -3052,7 +3067,7 @@ export default class RoomClient
)
);
}
-
+
store.dispatch(roomActions.setRoomState('connected'));
// Clean all the existing notifications.
@@ -3236,7 +3251,7 @@ export default class RoomClient
if (!device)
throw new Error('no webcam devices');
-
+
logger.debug(
'addExtraVideo() | new selected webcam [device:%o]',
device);
@@ -3281,7 +3296,7 @@ export default class RoomClient
{
videoGoogleStartBitrate : 1000
},
- appData :
+ appData :
{
source : 'extravideo'
}
@@ -3291,7 +3306,7 @@ export default class RoomClient
{
producer = await this._sendTransport.produce({
track,
- appData :
+ appData :
{
source : 'extravideo'
}
@@ -3385,7 +3400,7 @@ export default class RoomClient
if (!device)
throw new Error('no audio devices');
-
+
logger.debug(
'enableMic() | new selected audio device [device:%o]',
device);
@@ -3422,7 +3437,7 @@ export default class RoomClient
opusPtime : '3',
opusMaxPlaybackRate : 48000
},
- appData :
+ appData :
{ source: 'mic' }
});
@@ -3582,7 +3597,7 @@ export default class RoomClient
{
videoGoogleStartBitrate : 1000
},
- appData :
+ appData :
{
source : 'screen'
}
@@ -3592,7 +3607,7 @@ export default class RoomClient
{
this._screenSharingProducer = await this._sendTransport.produce({
track,
- appData :
+ appData :
{
source : 'screen'
}
@@ -3710,7 +3725,7 @@ export default class RoomClient
if (!device)
throw new Error('no webcam devices');
-
+
logger.debug(
'_setWebcamProducer() | new selected webcam [device:%o]',
device);
@@ -3753,7 +3768,7 @@ export default class RoomClient
{
videoGoogleStartBitrate : 1000
},
- appData :
+ appData :
{
source : 'webcam'
}
@@ -3763,7 +3778,7 @@ export default class RoomClient
{
this._webcamProducer = await this._sendTransport.produce({
track,
- appData :
+ appData :
{
source : 'webcam'
}
@@ -3888,6 +3903,14 @@ export default class RoomClient
store.dispatch(meActions.setWebcamInProgress(false));
}
+ async _setNoiseThreshold(threshold)
+ {
+ logger.debug('_setNoiseThreshold:%s', threshold);
+ this._hark.setThreshold(threshold);
+ store.dispatch(
+ settingsActions.setNoiseThreshold(threshold));
+ }
+
async _updateAudioDevices()
{
logger.debug('_updateAudioDevices()');
diff --git a/app/src/actions/meActions.js b/app/src/actions/meActions.js
index 7fb34ea..be7c1ee 100644
--- a/app/src/actions/meActions.js
+++ b/app/src/actions/meActions.js
@@ -110,3 +110,9 @@ export const setIsSpeaking = (flag) =>
type : 'SET_IS_SPEAKING',
payload : { flag }
});
+
+export const setAutoMuted = (flag) =>
+ ({
+ type : 'SET_AUTO_MUTED',
+ payload : { flag }
+ });
diff --git a/app/src/actions/settingsActions.js b/app/src/actions/settingsActions.js
index 21ff2fd..90b019a 100644
--- a/app/src/actions/settingsActions.js
+++ b/app/src/actions/settingsActions.js
@@ -71,6 +71,18 @@ export const setNoiseSuppression = (noiseSuppression) =>
payload : { noiseSuppression }
});
+export const setVoiceActivatedUnmute = (voiceActivatedUnmute) =>
+ ({
+ type: 'SET_VOICE_ACTIVATED_UNMUTE',
+ payload: { voiceActivatedUnmute }
+ });
+
+export const setNoiseThreshold = (noiseThreshold) =>
+ ({
+ type: 'SET_NOISE_THRESHOLD',
+ payload: { noiseThreshold }
+ });
+
export const setDefaultAudio = (audio) =>
({
type : 'SET_DEFAULT_AUDIO',
diff --git a/app/src/components/Containers/Me.js b/app/src/components/Containers/Me.js
index 8e0eb8e..85b2ca9 100644
--- a/app/src/components/Containers/Me.js
+++ b/app/src/components/Containers/Me.js
@@ -137,10 +137,10 @@ const styles = (theme) =>
transform : 'translate(-50%, 0%)',
color : 'rgba(255, 255, 255, 0.7)',
fontSize : '1.3em',
- backgroundColor : 'rgba(255, 0, 0, 0.9)',
+ backgroundColor : 'rgba(245, 0, 87, 0.70)',
margin : '4px',
padding : theme.spacing(2),
- zIndex : 31,
+ zIndex : 1200,
borderRadius : '20px',
textAlign : 'center',
opacity : 0,
@@ -176,6 +176,7 @@ const Me = (props) =>
screenProducer,
extraVideoProducers,
canShareScreen,
+ noiseVolume,
classes
} = props;
@@ -440,7 +441,12 @@ const Me = (props) =>
})}
className={classes.smallContainer}
disabled={!me.canSendMic || me.audioInProgress}
- color={micState === 'on' ? 'primary' : 'secondary'}
+ color={
+ micState === 'on' ?
+ settings.voiceActivatedUnmute && !me.isAutoMuted ?
+ 'primary'
+ : 'default'
+ : 'secondary'}
size='small'
onClick={() =>
{
@@ -453,7 +459,10 @@ const Me = (props) =>
}}
>
{ micState === 'on' ?
-
+
:
}
@@ -468,7 +477,10 @@ const Me = (props) =>
})}
className={classes.fab}
disabled={!me.canSendMic || me.audioInProgress}
- color={micState === 'on' ? 'default' : 'secondary'}
+ color={micState === 'on' ?
+ settings.voiceActivatedUnmute && !me.isAutoMuted? 'primary'
+ : 'default'
+ : 'secondary'}
size='large'
onClick={() =>
{
@@ -481,7 +493,11 @@ const Me = (props) =>
}}
>
{ micState === 'on' ?
-
+
:
}
@@ -868,6 +884,7 @@ Me.propTypes =
style : PropTypes.object,
smallContainer : PropTypes.bool,
canShareScreen : PropTypes.bool.isRequired,
+ noiseVolume : PropTypes.number,
classes : PropTypes.object.isRequired,
theme : PropTypes.object.isRequired
};
@@ -878,12 +895,26 @@ const makeMapStateToProps = () =>
const mapStateToProps = (state) =>
{
+ let volume;
+
+ // noiseVolume under threshold
+ if (state.peerVolumes[state.me.id] < state.settings.noiseThreshold)
+ {
+ // noiseVolume mapped to range 0.5 ... 1 (threshold switch)
+ volume = 1 + ((Math.abs(state.peerVolumes[state.me.id] -
+ state.settings.noiseThreshold) / (-120 -
+ state.settings.noiseThreshold)));
+ }
+ // noiseVolume over threshold: no noise but voice
+ else { volume = 0; }
+
return {
me : state.me,
...meProducersSelector(state),
settings : state.settings,
activeSpeaker : state.me.id === state.room.activeSpeakerId,
- canShareScreen : hasPermission(state)
+ canShareScreen : hasPermission(state),
+ noiseVolume : volume
};
};
@@ -900,6 +931,8 @@ export default withRoomContext(connect(
return (
prev.room === next.room &&
prev.me === next.me &&
+ Math.round(prev.peerVolumes[prev.me.id]) ===
+ Math.round(next.peerVolumes[next.me.id]) &&
prev.peers === next.peers &&
prev.producers === next.producers &&
prev.settings === next.settings
diff --git a/app/src/components/Containers/Volume.js b/app/src/components/Containers/Volume.js
index 3c13a39..81a050b 100644
--- a/app/src/components/Containers/Volume.js
+++ b/app/src/components/Containers/Volume.js
@@ -94,17 +94,17 @@ const styles = () =>
smallBar :
{
flex : '0 0 auto',
- margin : '0.3rem',
backgroundSize : '75%',
backgroundRepeat : 'no-repeat',
backgroundColor : 'rgba(0, 0, 0, 1)',
cursor : 'pointer',
transitionProperty : 'opacity, background-color',
width : 3,
- borderRadius : 6,
+ borderRadius : 2,
transitionDuration : '0.25s',
position : 'absolute',
- bottom : 0,
+ top : '50%',
+ transform : 'translateY(-50%)',
'&.level0' : { height: 0 },
'&.level1' : { height: '0.2vh' },
'&.level2' : { height: '0.4vh' },
@@ -149,9 +149,16 @@ const makeMapStateToProps = (initialState, props) =>
{
const mapStateToProps = (state) =>
{
- return {
- volume : state.peerVolumes[props.id]
- };
+ if (state.peerVolumes[props.id]>state.settings.noiseThreshold)
+ {
+ return {
+ volume : Math.round((state.peerVolumes[props.id]+100) / 10)
+ };
+ }
+ else
+ {
+ return { volume: 0 };
+ }
};
return mapStateToProps;
diff --git a/app/src/components/Controls/About.js b/app/src/components/Controls/About.js
index d361a8c..c462549 100644
--- a/app/src/components/Controls/About.js
+++ b/app/src/components/Controls/About.js
@@ -42,8 +42,9 @@ const styles = (theme) =>
},
link :
{
- display : 'block',
- textAlign : 'center'
+ display : 'block',
+ textAlign : 'center',
+ marginBottom : theme.spacing(1)
}
});
@@ -68,15 +69,16 @@ const About = ({
/>
-
+
Contributions to this work were made on behalf of the GÉANT
project, a project that has received funding from the
European Union’s Horizon 2020 research and innovation
programme under Grant Agreement No. 731122 (GN4-2).
On behalf of GÉANT project, GÉANT Association is the sole
owner of the copyright in all material which was developed
- by a member of the GÉANT project.
-
+ by a member of the GÉANT project.
+
+
GÉANT Vereniging (Association) is registered with the
Chamber of Commerce in Amsterdam with registration number
40535155 and operates in the UK as a branch of GÉANT
@@ -87,6 +89,13 @@ const About = ({
https://edumeet.org
+
+
+ :{` ${process.env.REACT_APP_VERSION}`}
+
{ window.config.logo &&
}
diff --git a/app/src/components/Controls/TopBar.js b/app/src/components/Controls/TopBar.js
index 148f4a7..55bb849 100644
--- a/app/src/components/Controls/TopBar.js
+++ b/app/src/components/Controls/TopBar.js
@@ -312,7 +312,7 @@ const TopBar = (props) =>
-
}
-
{ lobbyPeers.length > 0 &&
-
})}
className={classes.actionButton}
color='inherit'
- onClick={() =>
+ onClick={() =>
{
loggedIn ? roomClient.logout() : roomClient.login();
}}
@@ -472,6 +472,34 @@ const TopBar = (props) =>
}
+ { lobbyPeers.length > 0 &&
+
+
+ setLockDialogOpen(!room.lockDialogOpen)}
+ >
+
+
+
+
+
+
+ }
- { lobbyPeers.length > 0 &&
-
-
- setLockDialogOpen(!room.lockDialogOpen)}
- >
-
-
-
-
-
-
- }
-