diff --git a/app/package.json b/app/package.json index b58d66a..d7cff17 100644 --- a/app/package.json +++ b/app/package.json @@ -11,6 +11,7 @@ "@material-ui/core": "^4.5.1", "@material-ui/icons": "^4.5.1", "bowser": "^2.7.0", + "classnames": "^2.2.6", "dompurify": "^2.0.7", "domready": "^1.0.8", "end-of-stream": "1.4.0", diff --git a/app/public/config/config.example.js b/app/public/config/config.example.js index 9aaff4b..f64b139 100644 --- a/app/public/config/config.example.js +++ b/app/public/config/config.example.js @@ -31,9 +31,19 @@ var config = { tcp : true }, - lastN : 4, - mobileLastN : 1, - background : 'images/background.jpg', + lastN : 4, + mobileLastN : 1, + defaultAudio : + { + sampleRate : 48000, + channelCount : 1, + volume : 1.0, + autoGainControl : true, + echoCancellation : true, + noiseSuppression : true, + sampleSize : 16 + }, + background : 'images/background.jpg', // Add file and uncomment for adding logo to appbar // logo : 'images/logo.svg', title : 'Multiparty meeting', diff --git a/app/src/RoomClient.js b/app/src/RoomClient.js index 0d0bd3a..de3e177 100644 --- a/app/src/RoomClient.js +++ b/app/src/RoomClient.js @@ -30,6 +30,7 @@ let requestTimeout, transportOptions, lastN, mobileLastN, + defaultAudio, defaultResolution; if (process.env.NODE_ENV !== 'test') @@ -39,6 +40,7 @@ if (process.env.NODE_ENV !== 'test') transportOptions, lastN, mobileLastN, + defaultAudio, defaultResolution } = window.config); } @@ -203,6 +205,9 @@ export default class RoomClient if (defaultResolution) store.dispatch(settingsActions.setVideoResolution(defaultResolution)); + if (defaultAudio) + store.dispatch(settingsActions.setDefaultAudio(defaultAudio)); + // Max spotlights if (device.bowser.getPlatformType() === 'desktop') this._maxSpotlights = lastN; @@ -1036,23 +1041,24 @@ export default class RoomClient if (this._micProducer && this._micProducer.track) this._micProducer.track.stop(); - logger.debug('changeAudioDevice() | calling getUserMedia()'); + logger.debug('changeAudioDevice() | calling getUserMedia() %o', store.getState().settings); const stream = await navigator.mediaDevices.getUserMedia( { audio : { - deviceId : { exact: device.deviceId }, - sampleRate : 48000, - channelCount : 1, - volume : 1.0, - autoGainControl : true, - echoCancellation : false, - noiseSuppression : false, - sampleSize : 16 + deviceId : { exact: device.deviceId }, + sampleRate : store.getState().settings.sampleRate, + channelCount : store.getState().settings.channelCount, + volume : store.getState().settings.volume, + autoGainControl : store.getState().settings.autoGainControl, + echoCancellation : store.getState().settings.echoCancellation, + noiseSuppression : store.getState().settings.noiseSuppression, + sampleSize : store.getState().settings.sampleSize } } ); + logger.debug('Constraints: %o', stream.getAudioTracks()[0].getConstraints()); const track = stream.getAudioTracks()[0]; @@ -2697,6 +2703,7 @@ export default class RoomClient } } ); + logger.debug('Constraints: %o', stream.getAudioTracks()[0].getConstraints()); track = stream.getAudioTracks()[0]; diff --git a/app/src/actions/settingsActions.js b/app/src/actions/settingsActions.js index 79b5ef2..68b4257 100644 --- a/app/src/actions/settingsActions.js +++ b/app/src/actions/settingsActions.js @@ -32,6 +32,45 @@ export const togglePermanentTopBar = () => type : 'TOGGLE_PERMANENT_TOPBAR' }); +export const setEchoCancellation = (echoCancellation) => + ({ + type : 'SET_ECHO_CANCELLATION', + payload : { echoCancellation } + }); + +export const setAutoGainControl = (autoGainControl) => + ({ + type : 'SET_AUTO_GAIN_CONTROL', + payload : { autoGainControl } + }); + +export const setNoiseSuppression = (noiseSuppression) => + ({ + type : 'SET_NOISE_SUPPRESSION', + payload : { noiseSuppression } + }); + +export const setDefaultAudio = (defaultAudio) => + ({ + type : 'SET_DEFAULT_AUDIO', + payload : { defaultAudio } + }); + +export const toggleEchoCancellation = () => + ({ + type : 'TOGGLE_ECHO_CANCELLATION' + }); + +export const toggleAutoGainControl = () => + ({ + type : 'TOGGLE_AUTO_GAIN_CONTROL' + }); + +export const toggleNoiseSuppression = () => + ({ + type : 'TOGGLE_NOISE_SUPPRESSION' + }); + export const setLastN = (lastN) => ({ type : 'SET_LAST_N', diff --git a/app/src/components/Settings/Settings.js b/app/src/components/Settings/Settings.js index 91ba0db..3c56be4 100644 --- a/app/src/components/Settings/Settings.js +++ b/app/src/components/Settings/Settings.js @@ -60,6 +60,9 @@ const Settings = ({ settings, onToggleAdvancedMode, onTogglePermanentTopBar, + setEchoCancellation, + setAutoGainControl, + setNoiseSuppression, handleCloseSettings, handleChangeMode, classes @@ -329,6 +332,49 @@ const Settings = ({ + + { + setEchoCancellation(event.target.checked); + roomClient.changeAudioDevice(settings.selectedAudioDevice); + }} + />} + label={intl.formatMessage({ + id : 'settings.echoCancellation', + defaultMessage : 'Echo Cancellation' + })} + /> + { + setAutoGainControl(event.target.checked); + roomClient.changeAudioDevice(settings.selectedAudioDevice); + }} + />} + label={intl.formatMessage({ + id: 'settings.autoGainControl', + defaultMessage: 'Auto Gain Control' + })} + /> + { + setNoiseSuppression(event.target.checked); + roomClient.changeAudioDevice(settings.selectedAudioDevice); + }} + />} + label={intl.formatMessage({ + id: 'settings.noiseSuppression', + defaultMessage: 'Noise Suppression' + })} + /> } @@ -359,6 +405,9 @@ Settings.propTypes = settings : PropTypes.object.isRequired, onToggleAdvancedMode : PropTypes.func.isRequired, onTogglePermanentTopBar : PropTypes.func.isRequired, + setEchoCancellation : PropTypes.func.isRequired, + setAutoGainControl : PropTypes.func.isRequired, + setNoiseSuppression : PropTypes.func.isRequired, handleChangeMode : PropTypes.func.isRequired, handleCloseSettings : PropTypes.func.isRequired, classes : PropTypes.object.isRequired @@ -376,6 +425,9 @@ const mapStateToProps = (state) => const mapDispatchToProps = { onToggleAdvancedMode : settingsActions.toggleAdvancedMode, onTogglePermanentTopBar : settingsActions.togglePermanentTopBar, + setEchoCancellation : settingsActions.setEchoCancellation, + setAutoGainControl : settingsActions.toggleAutoGainControl, + setNoiseSuppression : settingsActions.toggleNoiseSuppression, handleChangeMode : roomActions.setDisplayMode, handleCloseSettings : roomActions.setSettingsOpen }; diff --git a/app/src/reducers/settings.js b/app/src/reducers/settings.js index 21d59db..60f05fd 100644 --- a/app/src/reducers/settings.js +++ b/app/src/reducers/settings.js @@ -4,6 +4,13 @@ const initialState = selectedWebcam : null, selectedAudioDevice : null, advancedMode : false, + sampleRate : 48000, + channelCount : 1, + volume : 1.0, + autoGainControl : true, + echoCancellation : true, + noiseSuppression : true, + sampleSize : 16, resolution : 'medium', // low, medium, high, veryhigh, ultra lastN : 4, permanentTopBar : true @@ -37,6 +44,76 @@ const settings = (state = initialState, action) => return { ...state, advancedMode }; } + case 'SET_SAMPLE_RATE': + { + const { sampleRate } = action.payload; + + return { ...state, sampleRate }; + } + + case 'SET_CHANNEL_COUNT': + { + const { channelCount } = action.payload; + + return { ...state, channelCount }; + } + + case 'SET_VOLUME': + { + const { volume } = action.payload; + + return { ...state, volume }; + } + + case 'SET_AUTO_GAIN_CONTROL': + { + const { autoGainControl } = action.payload; + + return { ...state, autoGainControl }; + } + + case 'SET_ECHO_CANCELLATION': + { + const { echoCancellation } = action.payload; + + return { ...state, echoCancellation }; + } + + case 'SET_NOISE_SUPPRESSION': + { + const { noiseSuppression } = action.payload; + + return { ...state, noiseSuppression }; + } + + case 'TOGGLE_AUTO_GAIN_CONTROL': + { + const autoGainControl = !state.autoGainControl; + + return { ...state, autoGainControl }; + } + + case 'TOGGLE_ECHO_CANCELLATION': + { + const echoCancellation = !state.echoCancellation; + + return { ...state, echoCancellation }; + } + + case 'TOGGLE_NOISE_SUPPRESSION': + { + const noiseSuppression = !state.noiseSuppression; + + return { ...state, noiseSuppression }; + } + + case 'SET_SAMPLE_SIZE': + { + const { sampleSize } = action.payload; + + return { ...state, sampleSize }; + } + case 'SET_LAST_N': { const { lastN } = action.payload;