diff --git a/.gitignore b/.gitignore index d8f0b11274f787754546a06a55e6cb9f1a924c8d..42d6d13a7b5a058591c0e2dddf7775726f1fb3fa 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ clients/flash/**/.gradle **/.idea/* *.iml *~ +**/node_modules/ diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx index f5ab6664d3795e89c280f63f16ebac935deeacd9..95d8be778e9711bc0fad60527f431a57d6d00f84 100755 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx @@ -330,7 +330,7 @@ class ActionsBar extends PureComponent { aria-label={intl.formatMessage(intlMessages.translatorMicrophoneLabel)} color={!amIAsTranslatorMuted ? 'primary' : 'default'} ghost={amIAsTranslatorMuted} - icon={amIAsTranslatorMuted ? 'mute' : 'unmute'} + icon={amIAsTranslatorMuted ? 'mute' : AudioManager.$translatorSpeakingChanged.value ? "mute_filled": 'unmute'} size="lg" circle /> diff --git a/bigbluebutton-html5/imports/ui/components/translations/component.jsx b/bigbluebutton-html5/imports/ui/components/translations/component.jsx index 26ddd2ef5602cca6fa8a28971606bc1dd99174bf..35534823d27169cceb70ccd168198662221de124 100644 --- a/bigbluebutton-html5/imports/ui/components/translations/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/translations/component.jsx @@ -39,6 +39,11 @@ const intlMessages = defineMessages({ description: 'Label for end translation button', defaultMessage: 'End Translation', }, + speechDetectionThreshold: { + id: 'app.translation.speechDetectionThreshold', + description: 'Translator speech detection threshold', + defaultMessage: 'Translator speech detection threshold', + }, }); class Translations extends Component{ @@ -106,12 +111,25 @@ class Translations extends Component{ languages: [], active: false, warning: null, + speechDetectionThreshold: AudioManager.$translatorSpeechDetectionThresholdChanged.value } componentWillUnmount() { window.dispatchEvent(new Event('panelChanged')); } + updateThreshold() { + AudioManager.$translatorSpeechDetectionThresholdChanged.next(this.state.speechDetectionThreshold); + } + + setThreshold(pEvent) { + this.setState({speechDetectionThreshold: pEvent.target.value}); + } + + handleSubmit(pEvent) { + pEvent.preventDefault(); + } + render() { const { intl, @@ -167,6 +185,11 @@ class Translations extends Component{ : null } </p> + <div>{intl.formatMessage(intlMessages.speechDetectionThreshold)}:</div> + <form onSubmit={this.handleSubmit}> + <input id="speechDetectionThreshold" type="number" value={this.state.speechDetectionThreshold} onChange={this.setThreshold.bind(this)} /> + <input type="submit" onClick={ this.updateThreshold.bind(this) } value="Set" /> + </form> </div> ); } diff --git a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js index ebae532b4b81cffec767020281bade0f73d82c59..69b64724008047a9476d586d194a7dbed06878c0 100755 --- a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js +++ b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js @@ -15,6 +15,7 @@ import { monitorAudioConnection } from '/imports/utils/stats'; import AudioErrors from './error-codes'; import {Meteor} from "meteor/meteor"; import {makeCall} from "../api"; +import { BehaviorSubject } from "rxjs"; const STATS = Meteor.settings.public.stats; const MEDIA = Meteor.settings.public.media; @@ -24,7 +25,7 @@ const MAX_LISTEN_ONLY_RETRIES = 1; const LISTEN_ONLY_CALL_TIMEOUT_MS = MEDIA.listenOnlyCallTimeout || 25000; const DEFAULT_INPUT_DEVICE_ID = 'default'; const DEFAULT_OUTPUT_DEVICE_ID = 'default'; -const TRANSLATOR_SPEAK_DETECTION_THRESHOLD = MEDIA.translation.translator.speakDetection.threshold || -70; +const TRANSLATOR_SPEECH_DETECTION_THRESHOLD = MEDIA.translation.translator.speakDetection.threshold || -70; const CALL_STATES = { STARTED: 'started', @@ -53,7 +54,12 @@ class AudioManager { status: BREAKOUT_AUDIO_TRANSFER_STATES.DISCONNECTED, breakoutMeetingId: null, }; - this.translatorStream = null + this.translatorStream = null; + this.translatorSpeechEvents = null; + + this.$translatorSpeechDetectionThresholdChanged = new BehaviorSubject(TRANSLATOR_SPEECH_DETECTION_THRESHOLD) + this.$translatorSpeakingChanged = new BehaviorSubject(false) + this.defineProperties({ isMuted: false, isConnected: false, @@ -69,7 +75,7 @@ class AudioManager { isReconnecting: false, listeningTranslation: ORIGINAL_TRANSLATION, translatorChannelOpen:false, - translationChannelOpen:false + translationChannelOpen:false, }); this.useKurento = Meteor.settings.public.kurento.enableListenOnly; @@ -86,6 +92,12 @@ class AudioManager { this.muteStateCallbacks = new Set(); this.translationStateCallbacks = new Set(); this.translationState = null; + this.$translatorSpeechDetectionThresholdChanged.subscribe((val) => { + if(this.translatorSpeechEvents && this.translatorSpeechEvents.hasOwnProperty("setThreshold")) { + this.translatorSpeechEvents.setThreshold(val); + } + }); + } init(userData, audioEventHandler) { @@ -828,29 +840,28 @@ class AudioManager { let success = function (inputStream) { let speechEventsOptions = { interval: 200, - threshold: TRANSLATOR_SPEAK_DETECTION_THRESHOLD, + threshold: this.$translatorSpeechDetectionThresholdChanged.value, play: false, }; let hark = window.hark; this.translatorStream = inputStream this.translatorSpeechEvents = hark(inputStream, speechEventsOptions); this.translatorSpeechEvents.on('speaking', () => { - console.log("Speaking") + this.$translatorSpeakingChanged.next(true); Meeting.changeTranslatorSpeackState(languageExtension, true); }); this.translatorSpeechEvents.on('volume_change', () => { const translatorIsSpeaking = this.translatorSpeechEvents.speaking; if (translatorIsSpeaking && (!this.translatorSpeechEvents.lastTimestamp || Date.now() - this.translatorSpeechEvents.lastTimestamp > 2000)) { - console.log("Check is translator speaking"); this.translatorSpeechEvents.lastTimestamp = Date.now(); Meeting.changeTranslatorSpeackState(languageExtension, translatorIsSpeaking); } }); this.translatorSpeechEvents.on('stopped_speaking', () => { + this.$translatorSpeakingChanged.next(false); Meeting.changeTranslatorSpeackState(languageExtension, false); - console.log("stopped speaking") }); const callOptions = { diff --git a/bigbluebutton-html5/public/locales/de.json b/bigbluebutton-html5/public/locales/de.json index 4c455a82a07ead58db24274aed3e4340cd0e1d58..575c0d9b266a248017920e01a285273f8c06d4ba 100644 --- a/bigbluebutton-html5/public/locales/de.json +++ b/bigbluebutton-html5/public/locales/de.json @@ -819,6 +819,7 @@ "app.translation.language.connection.established": "✓", "app.translation.language.connection.settingUp": "...", "app.translation.filterMarker.languageListening": "hören", - "app.translation.filterMarker.languageTranslating": "sprechen" + "app.translation.filterMarker.languageTranslating": "sprechen", + "app.translation.speechDetectionThreshold": "Sprachschwellenwert f. Übersetzer" } diff --git a/bigbluebutton-html5/public/locales/en.json b/bigbluebutton-html5/public/locales/en.json index ffcaa860f4d811742a2f87a8811b35e3be270c2d..1e1bee5d2b9a52983089dd7a927db940bcc474c4 100755 --- a/bigbluebutton-html5/public/locales/en.json +++ b/bigbluebutton-html5/public/locales/en.json @@ -830,6 +830,7 @@ "app.translation.language.connection.established": "✓", "app.translation.language.connection.settingUp": "...", "app.translation.filterMarker.languageListening": "listening", - "app.translation.filterMarker.languageTranslating": "speaking" + "app.translation.filterMarker.languageTranslating": "speaking", + "app.translation.speechDetectionThreshold": "Translator speech detection threshold" } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..2e36ecbc697921d1f6f3cb58e9104ef0c448fdd2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,19 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "rxjs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.1.0.tgz", + "integrity": "sha512-gCFO5iHIbRPwznl6hAYuwNFld8W4S2shtSJIqG27ReWXo9IWrCyEICxUA+6vJHwSR/OakoenC4QsDxq50tzYmw==", + "requires": { + "tslib": "~2.1.0" + } + }, + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + } + } +}