bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/muted-alert/component.jsx

157 lines
4.0 KiB
React
Raw Normal View History

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import hark from 'hark';
2022-02-15 22:51:51 +08:00
import Icon from '/imports/ui/components/common/icon/component';
2021-10-28 01:07:09 +08:00
import Styled from './styles';
2021-04-29 20:55:01 +08:00
import { defineMessages, injectIntl } from 'react-intl';
import { notify } from '/imports/ui/services/notification';
import TooltipContainer from '/imports/ui/components/common/tooltip/container';
const propTypes = {
inputStream: PropTypes.objectOf(PropTypes.any).isRequired,
isPresenter: PropTypes.bool.isRequired,
isViewer: PropTypes.bool.isRequired,
muted: PropTypes.bool.isRequired,
};
2021-04-29 20:55:01 +08:00
const intlMessages = defineMessages({
disableMessage: {
id: 'app.muteWarning.disableMessage',
description: 'Message used when mute alerts has been disabled',
},
tooltip: {
id: 'app.muteWarning.tooltip',
description: 'Tooltip message',
},
warningLabel: {
id: 'app.muteWarning.label',
description: 'Warning when someone speaks while muted',
},
});
class MutedAlert extends Component {
constructor(props) {
super(props);
this.state = {
visible: false,
};
this.inputStream = null;
this.speechEvents = null;
this.timer = null;
this.cloneMediaStream = this.cloneMediaStream.bind(this);
this.resetTimer = this.resetTimer.bind(this);
2021-04-29 20:55:01 +08:00
this.closeAlert = this.closeAlert.bind(this);
}
componentDidMount() {
const MUTE_ALERT_CONFIG = window.meetingClientSettings.public.app.mutedAlert;
this._isMounted = true;
if (!this.hasValidInputStream()) return;
this.cloneMediaStream();
if (this.inputStream) {
const { interval, threshold, duration } = MUTE_ALERT_CONFIG;
this.speechEvents = hark(this.inputStream, { interval, threshold });
this.speechEvents.on('speaking', () => {
this.resetTimer();
if (this._isMounted) this.setState({ visible: true });
});
this.speechEvents.on('stopped_speaking', () => {
if (this._isMounted) {
this.timer = setTimeout(() => this.setState(
{ visible: false },
), duration);
}
});
}
}
componentDidUpdate() {
this.cloneMediaStream();
}
componentWillUnmount() {
this._isMounted = false;
if (this.speechEvents) this.speechEvents.stop();
if (this.inputStream) {
fix: mic selection (firefox/all browsers) and muted alert when mic is changed This commit contains three fixes: one already reported and two detected during the investigation of the solution. This started as a fix for firefox (#12023), but i also fixed the muted alert/banner when device changes: the banner wasn't detecting device changes, unless audio was deactived/actived. There's another fix for the microphone stream: we now keep sender's track disabled if it was already disabled for the sender's track of the previous selected device. Also did small refactor for eslint checking. Some technical information: in sip bridge (bridge/sip.js), setInputStream and liveChangeInputDevice function were both fully turned into promises, which guarantees we have everything ready when it resolves to the respective values. This helps AudioManager (audio-manager/index.js) to sequentially sets and tracks the state of the current microphone stream (inputStream), when calling liveChangeInputDevice function: we first set the current stream to null, creats a new one and then set it to the newly created value - this is needed because MutedAlert (muted-alert/component.jsx) can then gracefully allocate/deallocate the cloned stream when it is set to a non-null/null value (the cloned stream is used for speech detection with hark). In MutedAlert we also make sure to enable the cloned stream's audio tracks, just in case the user change the device when muted (audio track is disabled in this case), which also leaves the cloned stream muted (we then enable the track to allow speech detection). Closes #12023
2021-04-16 21:45:40 +08:00
this.inputStream.getTracks().forEach((t) => t.stop());
}
this.resetTimer();
}
cloneMediaStream() {
if (this.inputStream) return;
fix: mic selection (firefox/all browsers) and muted alert when mic is changed This commit contains three fixes: one already reported and two detected during the investigation of the solution. This started as a fix for firefox (#12023), but i also fixed the muted alert/banner when device changes: the banner wasn't detecting device changes, unless audio was deactived/actived. There's another fix for the microphone stream: we now keep sender's track disabled if it was already disabled for the sender's track of the previous selected device. Also did small refactor for eslint checking. Some technical information: in sip bridge (bridge/sip.js), setInputStream and liveChangeInputDevice function were both fully turned into promises, which guarantees we have everything ready when it resolves to the respective values. This helps AudioManager (audio-manager/index.js) to sequentially sets and tracks the state of the current microphone stream (inputStream), when calling liveChangeInputDevice function: we first set the current stream to null, creats a new one and then set it to the newly created value - this is needed because MutedAlert (muted-alert/component.jsx) can then gracefully allocate/deallocate the cloned stream when it is set to a non-null/null value (the cloned stream is used for speech detection with hark). In MutedAlert we also make sure to enable the cloned stream's audio tracks, just in case the user change the device when muted (audio track is disabled in this case), which also leaves the cloned stream muted (we then enable the track to allow speech detection). Closes #12023
2021-04-16 21:45:40 +08:00
const { inputStream } = this.props;
if (inputStream) {
this.inputStream = inputStream.clone();
this.enableInputStreamAudioTracks(this.inputStream);
}
}
/* eslint-disable no-param-reassign */
fix: mic selection (firefox/all browsers) and muted alert when mic is changed This commit contains three fixes: one already reported and two detected during the investigation of the solution. This started as a fix for firefox (#12023), but i also fixed the muted alert/banner when device changes: the banner wasn't detecting device changes, unless audio was deactived/actived. There's another fix for the microphone stream: we now keep sender's track disabled if it was already disabled for the sender's track of the previous selected device. Also did small refactor for eslint checking. Some technical information: in sip bridge (bridge/sip.js), setInputStream and liveChangeInputDevice function were both fully turned into promises, which guarantees we have everything ready when it resolves to the respective values. This helps AudioManager (audio-manager/index.js) to sequentially sets and tracks the state of the current microphone stream (inputStream), when calling liveChangeInputDevice function: we first set the current stream to null, creats a new one and then set it to the newly created value - this is needed because MutedAlert (muted-alert/component.jsx) can then gracefully allocate/deallocate the cloned stream when it is set to a non-null/null value (the cloned stream is used for speech detection with hark). In MutedAlert we also make sure to enable the cloned stream's audio tracks, just in case the user change the device when muted (audio track is disabled in this case), which also leaves the cloned stream muted (we then enable the track to allow speech detection). Closes #12023
2021-04-16 21:45:40 +08:00
enableInputStreamAudioTracks() {
if (!this.inputStream) return;
this.inputStream.getAudioTracks().forEach((t) => { t.enabled = true; });
}
/* eslint-enable no-param-reassign */
resetTimer() {
if (this.timer) clearTimeout(this.timer);
this.timer = null;
}
hasValidInputStream() {
const { inputStream } = this.props;
if (inputStream
&& (typeof inputStream.getAudioTracks === 'function')
&& (inputStream.getAudioTracks().length > 0)
) return true;
return false;
}
2021-04-29 20:55:01 +08:00
closeAlert() {
const { intl } = this.props;
this.setState({ visible: false });
this.speechEvents.stop();
notify(intl.formatMessage(intlMessages.disableMessage), 'info', 'mute');
}
render() {
2021-04-29 20:55:01 +08:00
const {
isViewer, isPresenter, muted, intl,
} = this.props;
const { visible } = this.state;
return visible && muted ? (
2021-04-29 20:55:01 +08:00
<TooltipContainer
title={intl.formatMessage(intlMessages.tooltip)}
position="top"
>
2021-10-28 01:07:09 +08:00
<Styled.MuteWarning
alignForMod={!isViewer || isPresenter}
alignForViewer={isViewer}
2021-04-29 20:55:01 +08:00
onClick={() => this.closeAlert()}
>
<span>
{intl.formatMessage(intlMessages.warningLabel, { 0: <Icon iconName="mute" /> })}
</span>
2021-10-28 01:07:09 +08:00
</Styled.MuteWarning>
2021-04-29 20:55:01 +08:00
</TooltipContainer>
) : null;
}
}
MutedAlert.propTypes = propTypes;
2021-04-29 20:55:01 +08:00
export default injectIntl(MutedAlert);