bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx
Mario Jr 06c7edbb0b fix(audio): prevent mute notification to be triggered when mic is locked
When mic is locked, user is not able to talk so it doesn't make sense
to alert the user about unmuting (mute button is also disabled when mic
is locked).

Closes #12048
2021-07-06 11:59:42 -03:00

228 lines
6.2 KiB
JavaScript
Executable File

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import { defineMessages, injectIntl } from 'react-intl';
import deviceInfo from '/imports/utils/deviceInfo';
import Button from '/imports/ui/components/button/component';
import getFromUserSettings from '/imports/ui/services/users-settings';
import withShortcutHelper from '/imports/ui/components/shortcut-help/service';
import InputStreamLiveSelectorContainer from './input-stream-live-selector/container';
import MutedAlert from '/imports/ui/components/muted-alert/component';
import { styles } from './styles';
const intlMessages = defineMessages({
joinAudio: {
id: 'app.audio.joinAudio',
description: 'Join audio button label',
},
leaveAudio: {
id: 'app.audio.leaveAudio',
description: 'Leave audio button label',
},
muteAudio: {
id: 'app.actionsBar.muteLabel',
description: 'Mute audio button label',
},
unmuteAudio: {
id: 'app.actionsBar.unmuteLabel',
description: 'Unmute audio button label',
},
});
const propTypes = {
shortcuts: PropTypes.objectOf(PropTypes.string).isRequired,
processToggleMuteFromOutside: PropTypes.func.isRequired,
handleToggleMuteMicrophone: PropTypes.func.isRequired,
handleJoinAudio: PropTypes.func.isRequired,
handleLeaveAudio: PropTypes.func.isRequired,
disable: PropTypes.bool.isRequired,
muted: PropTypes.bool.isRequired,
showMute: PropTypes.bool.isRequired,
inAudio: PropTypes.bool.isRequired,
listenOnly: PropTypes.bool.isRequired,
intl: PropTypes.shape({
formatMessage: PropTypes.func.isRequired,
}).isRequired,
talking: PropTypes.bool.isRequired,
};
class AudioControls extends PureComponent {
constructor(props) {
super(props);
this.renderLeaveButtonWithoutLiveStreamSelector = this
.renderLeaveButtonWithoutLiveStreamSelector.bind(this);
this.renderJoinLeaveButton = this.renderJoinLeaveButton.bind(this);
}
componentDidMount() {
const { processToggleMuteFromOutside } = this.props;
if (Meteor.settings.public.allowOutsideCommands.toggleSelfVoice
|| getFromUserSettings('bbb_outside_toggle_self_voice', false)) {
window.addEventListener('message', processToggleMuteFromOutside);
}
}
renderJoinButton() {
const {
handleJoinAudio,
disable,
intl,
shortcuts,
} = this.props;
return (
<Button
className={styles.btn}
onClick={handleJoinAudio}
disabled={disable}
hideLabel
aria-label={intl.formatMessage(intlMessages.joinAudio)}
label={intl.formatMessage(intlMessages.joinAudio)}
color="default"
ghost
icon="audio_off"
size="lg"
circle
accessKey={shortcuts.joinaudio}
/>
);
}
static renderLeaveButtonWithLiveStreamSelector(props) {
const { handleLeaveAudio } = props;
return (
<InputStreamLiveSelectorContainer {...{ handleLeaveAudio }} />
);
}
renderLeaveButtonWithoutLiveStreamSelector() {
const {
handleJoinAudio,
handleLeaveAudio,
disable,
inAudio,
listenOnly,
intl,
shortcuts,
} = this.props;
let joinIcon = 'audio_off';
if (inAudio) {
if (listenOnly) {
joinIcon = 'listen';
} else {
joinIcon = 'audio_on';
}
}
return (
<Button
className={cx(inAudio || styles.btn)}
onClick={inAudio ? handleLeaveAudio : handleJoinAudio}
disabled={disable}
data-test={inAudio ? 'leaveAudio' : 'joinAudio'}
hideLabel
aria-label={inAudio ? intl.formatMessage(intlMessages.leaveAudio)
: intl.formatMessage(intlMessages.joinAudio)}
label={inAudio ? intl.formatMessage(intlMessages.leaveAudio)
: intl.formatMessage(intlMessages.joinAudio)}
color={inAudio ? 'primary' : 'default'}
ghost={!inAudio}
icon={joinIcon}
size="lg"
circle
accessKey={inAudio ? shortcuts.leaveaudio : shortcuts.joinaudio}
/>
);
}
renderJoinLeaveButton() {
const {
inAudio,
} = this.props;
const { isMobile } = deviceInfo;
let { enableDynamicAudioDeviceSelection } = Meteor.settings.public.app;
if (typeof enableDynamicAudioDeviceSelection === 'undefined') {
enableDynamicAudioDeviceSelection = true;
}
const _enableDynamicDeviceSelection = enableDynamicAudioDeviceSelection
&& !isMobile;
if (inAudio) {
if (_enableDynamicDeviceSelection) {
return AudioControls.renderLeaveButtonWithLiveStreamSelector(this
.props);
}
return this.renderLeaveButtonWithoutLiveStreamSelector();
}
return this.renderJoinButton();
}
render() {
const {
handleToggleMuteMicrophone,
showMute,
muted,
disable,
talking,
intl,
shortcuts,
isVoiceUser,
listenOnly,
inputStream,
isViewer,
isPresenter,
} = this.props;
const label = muted ? intl.formatMessage(intlMessages.unmuteAudio)
: intl.formatMessage(intlMessages.muteAudio);
const toggleMuteBtn = (
<Button
className={cx(styles.muteToggle, !talking || styles.glow, !muted || styles.btn)}
onClick={handleToggleMuteMicrophone}
disabled={disable}
hideLabel
label={label}
aria-label={label}
color={!muted ? 'primary' : 'default'}
ghost={muted}
icon={muted ? 'mute' : 'unmute'}
size="lg"
circle
accessKey={shortcuts.togglemute}
/>
);
const MUTE_ALERT_CONFIG = Meteor.settings.public.app.mutedAlert;
const { enabled: muteAlertEnabled } = MUTE_ALERT_CONFIG;
return (
<span className={styles.container}>
{isVoiceUser && inputStream && muteAlertEnabled && !listenOnly && muted && showMute ? (
<MutedAlert {...{
muted, inputStream, isViewer, isPresenter,
}}
/>
) : null}
{showMute && isVoiceUser ? toggleMuteBtn : null}
{
this.renderJoinLeaveButton()
}
</span>
);
}
}
AudioControls.propTypes = propTypes;
export default withShortcutHelper(injectIntl(AudioControls), ['joinAudio',
'leaveAudio', 'toggleMute']);