Merge branch 'feat-audio-settings' into develop
commit
0f053d0282
|
|
@ -50,6 +50,7 @@ var config =
|
|||
autoGainControl : true,
|
||||
echoCancellation : true,
|
||||
noiseSuppression : true,
|
||||
voiceActivityMute : false,
|
||||
sampleSize : 16
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -1003,37 +1003,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) =>
|
||||
this._hark = hark(this._harkStream,
|
||||
{
|
||||
// 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;
|
||||
play : false,
|
||||
interval : 5,
|
||||
threshold : store.getState().settings.noiseThreshold,
|
||||
history : 30
|
||||
});
|
||||
this._hark.lastVolume = -100;
|
||||
|
||||
this._hark.on('volume_change', (volume) =>
|
||||
{
|
||||
volume = Math.round(volume);
|
||||
|
||||
if (this._micProducer && volume !== this._micProducer.volume)
|
||||
if (this._micProducer && volume !== Math.round(this._hark.lastVolume))
|
||||
{
|
||||
this._micProducer.volume = volume;
|
||||
|
||||
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));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1962,23 +1975,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 +2033,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)
|
||||
|
|
@ -3888,6 +3879,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()');
|
||||
|
|
|
|||
|
|
@ -110,3 +110,9 @@ export const setIsSpeaking = (flag) =>
|
|||
type : 'SET_IS_SPEAKING',
|
||||
payload : { flag }
|
||||
});
|
||||
|
||||
export const setAutoMuted = (flag) =>
|
||||
({
|
||||
type : 'SET_AUTO_MUTED',
|
||||
payload : { flag }
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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' ?
|
||||
<MicIcon />
|
||||
<MicIcon
|
||||
color={me.isAutoMuted ? 'secondary' : 'primary'}
|
||||
style={{ opacity: noiseVolume }}
|
||||
/>
|
||||
:
|
||||
<MicOffIcon />
|
||||
}
|
||||
|
|
@ -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' ?
|
||||
<MicIcon />
|
||||
<MicIcon
|
||||
color={me.isAutoMuted ? 'secondary' : 'primary'}
|
||||
style={me.isAutoMuted ? { opacity: noiseVolume }
|
||||
: { opacity: 1 }}
|
||||
/>
|
||||
:
|
||||
<MicOffIcon />
|
||||
}
|
||||
|
|
@ -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) /
|
||||
state.settings.noiseThreshold) / 2;
|
||||
}
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -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' },
|
||||
|
|
@ -148,10 +148,17 @@ Volume.propTypes =
|
|||
const makeMapStateToProps = (initialState, props) =>
|
||||
{
|
||||
const mapStateToProps = (state) =>
|
||||
{
|
||||
if (state.peerVolumes[props.id]>state.settings.noiseThreshold)
|
||||
{
|
||||
return {
|
||||
volume : state.peerVolumes[props.id]
|
||||
volume : Math.round((state.peerVolumes[props.id]+100) / 10)
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return { volume: 0 };
|
||||
}
|
||||
};
|
||||
|
||||
return mapStateToProps;
|
||||
|
|
|
|||
|
|
@ -6,19 +6,52 @@ import { withRoomContext } from '../../RoomContext';
|
|||
import * as settingsActions from '../../actions/settingsActions';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl, FormattedMessage } from 'react-intl';
|
||||
import classnames from 'classnames';
|
||||
import MenuItem from '@material-ui/core/MenuItem';
|
||||
import FormHelperText from '@material-ui/core/FormHelperText';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||
import Select from '@material-ui/core/Select';
|
||||
import Checkbox from '@material-ui/core/Checkbox';
|
||||
import Slider from '@material-ui/core/Slider';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
const styles = (theme) =>
|
||||
({
|
||||
const NoiseSlider = withStyles(
|
||||
{
|
||||
root :
|
||||
{
|
||||
color : '#3880ff',
|
||||
height : 2,
|
||||
padding : '15px 0'
|
||||
},
|
||||
track : {
|
||||
height : 2
|
||||
},
|
||||
rail : {
|
||||
height : 2,
|
||||
opacity : 0.2,
|
||||
},
|
||||
mark : {
|
||||
backgroundColor : '#bfbfbf',
|
||||
height : 10,
|
||||
width : 3,
|
||||
marginTop : -3
|
||||
},
|
||||
markActive : {
|
||||
opacity : 1,
|
||||
backgroundColor : 'currentColor'
|
||||
}
|
||||
})(Slider);
|
||||
|
||||
const styles = (theme) => ({
|
||||
setting :
|
||||
{
|
||||
padding : theme.spacing(2)
|
||||
},
|
||||
margin :
|
||||
{
|
||||
height : theme.spacing(3),
|
||||
},
|
||||
formControl :
|
||||
{
|
||||
display : 'flex'
|
||||
|
|
@ -29,8 +62,10 @@ const MediaSettings = ({
|
|||
setEchoCancellation,
|
||||
setAutoGainControl,
|
||||
setNoiseSuppression,
|
||||
setVoiceActivatedUnmute,
|
||||
roomClient,
|
||||
me,
|
||||
volume,
|
||||
settings,
|
||||
classes
|
||||
}) =>
|
||||
|
|
@ -135,6 +170,32 @@ const MediaSettings = ({
|
|||
}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
<FormControl className={classes.formControl}>
|
||||
<Select
|
||||
value={settings.resolution || ''}
|
||||
onChange={(event) => {
|
||||
if (event.target.value)
|
||||
roomClient.changeVideoResolution(event.target.value);
|
||||
}}
|
||||
name='Video resolution'
|
||||
autoWidth
|
||||
className={classes.selectEmpty}
|
||||
>
|
||||
{resolutions.map((resolution, index) => {
|
||||
return (
|
||||
<MenuItem key={index} value={resolution.value}>
|
||||
{resolution.label}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
<FormattedMessage
|
||||
id='settings.resolution'
|
||||
defaultMessage='Select your video resolution'
|
||||
/>
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</form>
|
||||
<form className={classes.setting} autoComplete='off'>
|
||||
<FormControl className={classes.formControl}>
|
||||
|
|
@ -148,7 +209,7 @@ const MediaSettings = ({
|
|||
displayEmpty
|
||||
name={intl.formatMessage({
|
||||
id : 'settings.audio',
|
||||
defaultMessage : 'Audio device'
|
||||
defaultMessage : 'Audio input device'
|
||||
})}
|
||||
autoWidth
|
||||
className={classes.selectEmpty}
|
||||
|
|
@ -165,12 +226,12 @@ const MediaSettings = ({
|
|||
{ audioDevices.length > 0 ?
|
||||
intl.formatMessage({
|
||||
id : 'settings.selectAudio',
|
||||
defaultMessage : 'Select audio device'
|
||||
defaultMessage : 'Select audio input device'
|
||||
})
|
||||
:
|
||||
intl.formatMessage({
|
||||
id : 'settings.cantSelectAudio',
|
||||
defaultMessage : 'Unable to select audio device'
|
||||
defaultMessage : 'Unable to select audio input device'
|
||||
})
|
||||
}
|
||||
</FormHelperText>
|
||||
|
|
@ -225,34 +286,6 @@ const MediaSettings = ({
|
|||
</form>
|
||||
}
|
||||
<form className={classes.setting} autoComplete='off'>
|
||||
<FormControl className={classes.formControl}>
|
||||
<Select
|
||||
value={settings.resolution || ''}
|
||||
onChange={(event) =>
|
||||
{
|
||||
if (event.target.value)
|
||||
roomClient.changeVideoResolution(event.target.value);
|
||||
}}
|
||||
name='Video resolution'
|
||||
autoWidth
|
||||
className={classes.selectEmpty}
|
||||
>
|
||||
{ resolutions.map((resolution, index) =>
|
||||
{
|
||||
return (
|
||||
<MenuItem key={index} value={resolution.value}>
|
||||
{resolution.label}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
<FormattedMessage
|
||||
id='settings.resolution'
|
||||
defaultMessage='Select your video resolution'
|
||||
/>
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
<FormControlLabel
|
||||
className={classes.setting}
|
||||
control={
|
||||
|
|
@ -298,6 +331,41 @@ const MediaSettings = ({
|
|||
defaultMessage : 'Noise suppression'
|
||||
})}
|
||||
/>
|
||||
<FormControlLabel
|
||||
className={classes.setting}
|
||||
control={
|
||||
<Checkbox checked={settings.voiceActivatedUnmute} onChange={
|
||||
(event) =>
|
||||
{
|
||||
setVoiceActivatedUnmute(event.target.checked);
|
||||
}}
|
||||
/>}
|
||||
label={intl.formatMessage({
|
||||
id : 'settings.voiceActivatedUnmute',
|
||||
defaultMessage : 'Voice activated unmute'
|
||||
})}
|
||||
/>
|
||||
<div className={classes.margin} />
|
||||
<Typography gutterBottom>
|
||||
{
|
||||
intl.formatMessage({
|
||||
id : 'settings.noiseThreshold',
|
||||
defaultMessage : 'Noise threshold'
|
||||
})
|
||||
}
|
||||
</Typography>
|
||||
<NoiseSlider className={classnames(classes.slider, classnames.setting)}
|
||||
key={'noise-threshold-slider'}
|
||||
min={-100}
|
||||
value={settings.noiseThreshold}
|
||||
max={0}
|
||||
onChange={
|
||||
(event, value) => {
|
||||
roomClient._setNoiseThreshold(value);
|
||||
}}
|
||||
marks={[{ value: volume, label: 'level' }]} valueLabelDisplay='on'
|
||||
/>
|
||||
<div className={classes.margin} />
|
||||
</form>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
|
@ -309,7 +377,9 @@ MediaSettings.propTypes =
|
|||
setEchoCancellation : PropTypes.func.isRequired,
|
||||
setAutoGainControl : PropTypes.func.isRequired,
|
||||
setNoiseSuppression : PropTypes.func.isRequired,
|
||||
setVoiceActivatedUnmute : PropTypes.func.isRequired,
|
||||
me : appPropTypes.Me.isRequired,
|
||||
volume : PropTypes.number,
|
||||
settings : PropTypes.object.isRequired,
|
||||
classes : PropTypes.object.isRequired
|
||||
};
|
||||
|
|
@ -318,6 +388,7 @@ const mapStateToProps = (state) =>
|
|||
{
|
||||
return {
|
||||
me : state.me,
|
||||
volume : state.peerVolumes[state.me.id],
|
||||
settings : state.settings
|
||||
};
|
||||
};
|
||||
|
|
@ -325,7 +396,8 @@ const mapStateToProps = (state) =>
|
|||
const mapDispatchToProps = {
|
||||
setEchoCancellation : settingsActions.setEchoCancellation,
|
||||
setAutoGainControl : settingsActions.toggleAutoGainControl,
|
||||
setNoiseSuppression : settingsActions.toggleNoiseSuppression
|
||||
setNoiseSuppression : settingsActions.toggleNoiseSuppression,
|
||||
setVoiceActivatedUnmute : settingsActions.setVoiceActivatedUnmute
|
||||
};
|
||||
|
||||
export default withRoomContext(connect(
|
||||
|
|
@ -337,7 +409,8 @@ export default withRoomContext(connect(
|
|||
{
|
||||
return (
|
||||
prev.me === next.me &&
|
||||
prev.settings === next.settings
|
||||
prev.settings === next.settings &&
|
||||
prev.peerVolumes[prev.me.id] === next[next.me.id]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ const initialState =
|
|||
raisedHand : false,
|
||||
raisedHandInProgress : false,
|
||||
loggedIn : false,
|
||||
isSpeaking : false
|
||||
isSpeaking : false,
|
||||
isAutoMuted : true
|
||||
};
|
||||
|
||||
const me = (state = initialState, action) =>
|
||||
|
|
@ -162,6 +163,13 @@ const me = (state = initialState, action) =>
|
|||
return { ...state, isSpeaking: flag };
|
||||
}
|
||||
|
||||
case 'SET_AUTO_MUTED':
|
||||
{
|
||||
const { flag } = action.payload;
|
||||
|
||||
return { ...state, isAutoMuted: flag };
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,9 +31,10 @@ const peerVolumes = (state = initialState, action) =>
|
|||
|
||||
case 'SET_PEER_VOLUME':
|
||||
{
|
||||
const { peerId, volume } = action.payload;
|
||||
const { peerId } = action.payload;
|
||||
const dBs = action.payload.volume < -100 ? -100 : action.payload.volume;
|
||||
|
||||
return { ...state, [peerId]: volume };
|
||||
return { ...state, [peerId]: Math.round(dBs) };
|
||||
}
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -7,9 +7,11 @@ const initialState =
|
|||
sampleRate : 48000,
|
||||
channelCount : 1,
|
||||
volume : 1.0,
|
||||
autoGainControl : true,
|
||||
autoGainControl : false,
|
||||
echoCancellation : true,
|
||||
noiseSuppression : true,
|
||||
voiceActivatedUnmute : false,
|
||||
noiseThreshold : -50,
|
||||
sampleSize : 16,
|
||||
// low, medium, high, veryhigh, ultra
|
||||
resolution : window.config.defaultResolution || 'medium',
|
||||
|
|
@ -99,6 +101,20 @@ const settings = (state = initialState, action) =>
|
|||
return { ...state, noiseSuppression };
|
||||
}
|
||||
|
||||
case 'SET_VOICE_ACTIVATED_UNMUTE':
|
||||
{
|
||||
const { voiceActivatedUnmute } = action.payload;
|
||||
|
||||
return { ...state, voiceActivatedUnmute };
|
||||
}
|
||||
|
||||
case 'SET_NOISE_THRESHOLD':
|
||||
{
|
||||
const { noiseThreshold } = action.payload;
|
||||
|
||||
return { ...state, noiseThreshold };
|
||||
}
|
||||
|
||||
case 'SET_DEFAULT_AUDIO':
|
||||
{
|
||||
const { audio } = action.payload;
|
||||
|
|
|
|||
Loading…
Reference in New Issue