diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx index 95d8be778e9711bc0fad60527f431a57d6d00f84..362fec5fa7ac87c18f7d8137a832a1099a7fc756 100755 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx @@ -52,11 +52,6 @@ if (TRANSLATION_SETTINGS) { } const intlMessages = defineMessages({ - translatorMicrophoneLabel: { - id: 'app.translation.translator.microphone', - description: 'Label for translator microphone button', - defaultMessage: 'Translator mic', - }, translatorSelectLanguageLabel: { id: 'app.translation.translator.selectLanguage', description: 'Label for translator select language button', @@ -181,18 +176,10 @@ class ActionsBar extends PureComponent { } handleMuteTranslator(){ - const muteKey = 'mute-button'; - - let isTranslatorMuted = AudioManager.isTranslatorMuted(muteKey); - - if(isTranslatorMuted) { - AudioManager.unmuteTranslator(muteKey); - } else { - AudioManager.muteTranslator(muteKey); - } - + AudioManager.toggleMuteTranslator(); this.forceUpdate(); } + handleLanguageSelection(language, onConnected) { this.state.translationLanguage = language AudioManager.openTranslationChannel(language.extension) @@ -235,14 +222,9 @@ class ActionsBar extends PureComponent { setEmojiStatus, currentUser, shortcuts, - hasBreakouts, - isTranslatorTalking, - isTranslatorMuted, hasLanguages, - showTranslatorMicButton } = this.props; - const amIAsTranslatorMuted = isTranslatorMuted(); return ( <div @@ -320,22 +302,7 @@ class ActionsBar extends PureComponent { ) : null } - { amIModerator && hasLanguages && showTranslatorMicButton ? - ( - <Button - className={[amIAsTranslatorMuted ? styles.btnmuted: "", styles.translatorBtn ].join(" ")} - onClick={this.handleMuteTranslator} - hideLabel - label={intl.formatMessage(intlMessages.translatorMicrophoneLabel)} - aria-label={intl.formatMessage(intlMessages.translatorMicrophoneLabel)} - color={!amIAsTranslatorMuted ? 'primary' : 'default'} - ghost={amIAsTranslatorMuted} - icon={amIAsTranslatorMuted ? 'mute' : AudioManager.$translatorSpeakingChanged.value ? "mute_filled": 'unmute'} - size="lg" - circle - /> - ) :null - } + { amIModerator && hasLanguages ? ( <div id={"translatorButton"}> diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/container.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/container.jsx index c023e99aa08fe8379607c603354a36a30a76f5a2..9530d97ac13c2b2bb6748cd72fe94c2dab733003 100644 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/actions-bar/container.jsx @@ -67,3 +67,5 @@ export default withTracker(() => ({ hasLanguages: Service.hasLanguages(), showTranslatorMicButton: Service.showTranslatorMicButton() }))(injectIntl(ActionsBarContainer)); + + diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/styles.scss b/bigbluebutton-html5/imports/ui/components/actions-bar/styles.scss index e979ce724fdb9bdcdbcc082eac6f3e2a37dd4078..1325888d87d4c6cca7c639eecf56cfa875f75fbe 100755 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/styles.scss +++ b/bigbluebutton-html5/imports/ui/components/actions-bar/styles.scss @@ -218,20 +218,9 @@ margin: 0; } -.btnmuted{ - span{ - border-color: white !important; - } -} - .translatorBtn{ span{ background-color: mediumpurple; } } -.translatorBtn:not(.btnmuted):focus{ - span{ - background-color: mediumpurple !important; - } -} diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx index c64971b3b8a7f03836821f19160ba9a9cc5e607d..7179d3a291ffc85a34371ac756842ef86b13d002 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx @@ -9,6 +9,7 @@ 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'; +import AudioManager from "../../../services/audio-manager"; const intlMessages = defineMessages({ joinAudio: { @@ -27,6 +28,11 @@ const intlMessages = defineMessages({ id: 'app.actionsBar.unmuteLabel', description: 'Unmute audio button label', }, + translatorMicrophoneLabel: { + id: 'app.translation.translator.microphone', + description: 'Label for translator microphone button', + defaultMessage: 'Translator mic', + }, }); const propTypes = { @@ -53,6 +59,8 @@ class AudioControls extends PureComponent { .renderLeaveButtonWithoutLiveStreamSelector.bind(this); this.renderJoinLeaveButton = this.renderJoinLeaveButton.bind(this); + this.handleMuteTranslator = this.handleMuteTranslator.bind(this) + } componentDidMount() { @@ -89,6 +97,11 @@ class AudioControls extends PureComponent { ); } + handleMuteTranslator(){ + AudioManager.toggleMuteTranslator(); + this.forceUpdate(); + } + static renderLeaveButtonWithLiveStreamSelector(props) { const { handleLeaveAudio } = props; return ( @@ -179,7 +192,13 @@ class AudioControls extends PureComponent { inputStream, isViewer, isPresenter, - translatorChannelOpen + translatorChannelOpen, + hasBreakouts, + isTranslatorTalking, + isTranslatorMuted, + showTranslatorMicButton, + amIModerator, + hasLanguages } = this.props; const label = "Floor " + muted ? intl.formatMessage(intlMessages.unmuteAudio) @@ -202,13 +221,31 @@ class AudioControls extends PureComponent { /> ); + const amIAsTranslatorMuted = isTranslatorMuted(); + + const translatorToggleMuteBtn = ( + <Button + className={cx(styles.muteToggle, [amIAsTranslatorMuted ? styles.btnmuted: "", styles.translatorBtn ].join(" "))} + onClick={this.handleMuteTranslator} + hideLabel + label={intl.formatMessage(intlMessages.translatorMicrophoneLabel)} + aria-label={intl.formatMessage(intlMessages.translatorMicrophoneLabel)} + color={!amIAsTranslatorMuted ? 'primary' : 'default'} + ghost={amIAsTranslatorMuted} + icon={amIAsTranslatorMuted ? 'mute' : AudioManager.$translatorSpeakingChanged.value ? "mute_filled": 'unmute'} + size="lg" + circle + /> + ); + const MUTE_ALERT_CONFIG = Meteor.settings.public.app.mutedAlert; const { enabled: muteAlertEnabled } = MUTE_ALERT_CONFIG; return ( <span className={styles.container}> {(showMute && isVoiceUser ) && ! translatorChannelOpen ? toggleMuteBtn : null} - { + { amIModerator && hasLanguages && showTranslatorMicButton ? translatorToggleMuteBtn : null } + { this.renderJoinLeaveButton() } </span> diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx index eed08ad4b4901cfafc3281d0d190ce8f437b31f3..8c93cd92cec04ba868a35af5a4bf672809065c03 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx @@ -11,6 +11,7 @@ import Storage from '/imports/ui/services/storage/session'; import getFromUserSettings from '/imports/ui/services/users-settings'; import AudioControls from './component'; import AudioModalContainer from '../audio-modal/container'; +import ActionsBarService from '/imports/ui/components/actions-bar/service'; import { setUserSelectedMicrophone, setUserSelectedListenOnly, @@ -113,6 +114,12 @@ export default withUsersConsumer(lockContextContainer(withModalMounter(withTrack inputStream: AudioManager.inputStream, isViewer, isPresenter, - translatorChannelOpen: AudioManager.translatorChannelOpen + translatorChannelOpen: AudioManager.translatorChannelOpen, + hasBreakouts: Service.hasBreakouts, + isTranslatorTalking: Service.isTranslatorTalking(), + isTranslatorMuted: Service.isTranslatorMuted, + showTranslatorMicButton: Service.showTranslatorMicButton(), + hasLanguages: Service.hasLanguages(), + amIModerator: ActionsBarService.amIModerator(), }); })(AudioControlsContainer)))); diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/styles.scss b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/styles.scss index c57487d6e85360284a088e9bfb5634f109f650c1..f0c5dc1213361e0a87c462a5690b8f3032f25388 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/styles.scss +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/styles.scss @@ -22,7 +22,7 @@ } } } - + > :last-child { margin-left: var(--sm-padding-x); margin-right: 0; @@ -50,7 +50,7 @@ .glow { border-radius: 50%; - + :global(.animationsEnabled) & { animation: pulse 1s infinite ease-in; } @@ -96,3 +96,21 @@ .selectedDevice { font-weight: bold; } + +.btnmuted{ + span{ + border-color: white !important; + } +} + +.translatorBtn{ + span{ + background-color: mediumpurple; + } +} + +.translatorBtn:not(.btnmuted):focus{ + span{ + background-color: mediumpurple !important; + } +} diff --git a/bigbluebutton-html5/imports/ui/components/audio/service.js b/bigbluebutton-html5/imports/ui/components/audio/service.js index 627973851d94cfc9c0251e9b185a2d3e24264fd9..d9390087df8a58219212c69ba3c6e387a2b357b3 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/service.js +++ b/bigbluebutton-html5/imports/ui/components/audio/service.js @@ -7,6 +7,7 @@ import { makeCall } from '/imports/ui/services/api'; import VoiceUsers from '/imports/api/voice-users'; import logger from '/imports/startup/client/logger'; import Storage from '../../services/storage/session'; +import Meeting from "../../services/meeting"; const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator; const TOGGLE_MUTE_THROTTLE_TIME = Meteor.settings.public.media.toggleMuteThrottleTime; @@ -66,6 +67,17 @@ const init = (messages, intl) => { AudioManager.init(userData, audioEventHandler); }; + + +const isTranslatorTalking = () => { + const translationLanguageExtension = AudioManager.translationLanguageExtension; + let isTranslatorTalking = false; + if(translationLanguageExtension >= 0) { + isTranslatorTalking = Meeting.isTranslatorSpeaking(translationLanguageExtension); + } + return isTranslatorTalking; +} + const isVoiceUser = () => { const voiceUser = VoiceUsers.findOne({ intId: Auth.userID }, { fields: { joined: 1 } }); @@ -136,4 +148,8 @@ export default { .setBreakoutAudioTransferStatus(status), getBreakoutAudioTransferStatus: () => AudioManager .getBreakoutAudioTransferStatus(), + isTranslatorTalking, + isTranslatorMuted: () => AudioManager.isTranslatorMuted(), + hasLanguages: () => Meeting.hasLanguages(), + showTranslatorMicButton: () => AudioManager.translatorChannelOpen && Meeting.hasLanguages(), }; diff --git a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js index 755322848fd1b5b29572c3b19a7e31116b33f200..8a5444fbcc1463fe0ceb54728d7e623ae12ec355 100755 --- a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js +++ b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js @@ -88,7 +88,12 @@ class AudioManager { this.BREAKOUT_AUDIO_TRANSFER_STATES = BREAKOUT_AUDIO_TRANSFER_STATES; - this.muteHandles = new Set(); + // this.muteHandles = new Set(); + this.$translatorMuted = new BehaviorSubject(true); + this.$translatorMuted.subscribe((val) => { + this.setSenderTrackEnabledTranslator(!val); + }) + this.muteStateCallbacks = new Set(); this.translationStateCallbacks = new Set(); this.translationState = null; @@ -900,28 +905,28 @@ class AudioManager { floorMediaElement.volume = volume; } - muteTranslator(muteHandle) { - this.setSenderTrackEnabledTranslator(false) - this.muteHandles.add(muteHandle); + muteTranslator() { + this.$translatorMuted.next(true); this.notifyMuteStateListener(); } - unmuteTranslator(muteHandle) { - this.muteHandles.delete(muteHandle); - if(this.muteHandles.size === 0) { - this.setSenderTrackEnabledTranslator(true); - } + unmuteTranslator() { + this.$translatorMuted.next(false); this.notifyMuteStateListener(); } - isTranslatorMuted(muteHandle = null) { - if(muteHandle === null) { - return this.muteHandles.size !== 0; + toggleMuteTranslator() { + if (this.isTranslatorMuted()) { + this.unmuteTranslator(); } else { - return this.muteHandles.has(muteHandle); + this.muteTranslator(); } } + isTranslatorMuted() { + return this.$translatorMuted.value; + } + registerMuteStateListener( callback ) { this.muteStateCallbacks.add(callback); }