feat: display noise detection notification (#4952)

* feat: display noise detection notification

* address code review p1

* Address code review p2

* bump lib-jitsi-meet version
This commit is contained in:
Andrei Gavrilescu 2020-01-20 20:00:12 +02:00 committed by Hristo Terezov
parent a18ed3a779
commit d2c2919aef
14 changed files with 135 additions and 16 deletions

View File

@ -76,7 +76,13 @@ var config = {
// Enabling this will run the lib-jitsi-meet no audio detection module which // Enabling this will run the lib-jitsi-meet no audio detection module which
// will notify the user if the current selected microphone has no audio // will notify the user if the current selected microphone has no audio
// input and will suggest another valid device if one is present. // input and will suggest another valid device if one is present.
// enableNoAudioDetection: false enableNoAudioDetection: true,
// Enabling this will run the lib-jitsi-meet noise detection module which will
// notify the user if there is noise, other than voice, coming from the current
// selected microphone. The purpose it to let the user know that the input could
// be potentially unpleasant for other meeting participants.
enableNoisyMicDetection: true,
// Start the conference in audio only mode (no video is being received nor // Start the conference in audio only mode (no video is being received nor
// sent). // sent).

View File

@ -634,6 +634,8 @@
"noAudioSignalTitle": "There is no input coming from your mic!", "noAudioSignalTitle": "There is no input coming from your mic!",
"noAudioSignalDesc": "If you did not purposely mute it from system settings or hardware, consider changing the device.", "noAudioSignalDesc": "If you did not purposely mute it from system settings or hardware, consider changing the device.",
"noAudioSignalDescSuggestion": "If you did not purposely mute it from system settings or hardware, consider using the following device:", "noAudioSignalDescSuggestion": "If you did not purposely mute it from system settings or hardware, consider using the following device:",
"noisyAudioInputTitle": "Your microphone appears to be noisy!",
"noisyAudioInputDesc": "Jitsi has detected noise coming from your microphone, please consider muting or changing the device.",
"openChat": "Open chat", "openChat": "Open chat",
"pip": "Enter Picture-in-Picture mode", "pip": "Enter Picture-in-Picture mode",
"privateMessage": "Send private message", "privateMessage": "Send private message",

4
package-lock.json generated
View File

@ -10869,8 +10869,8 @@
} }
}, },
"lib-jitsi-meet": { "lib-jitsi-meet": {
"version": "github:jitsi/lib-jitsi-meet#8deeaf6bd2b233ab163303e42febfee87201b2d9", "version": "github:jitsi/lib-jitsi-meet#e4b523d0fab83a1cf1408abbf41f5d0ca1169900",
"from": "github:jitsi/lib-jitsi-meet#8deeaf6bd2b233ab163303e42febfee87201b2d9", "from": "github:jitsi/lib-jitsi-meet#e4b523d0fab83a1cf1408abbf41f5d0ca1169900",
"requires": { "requires": {
"@jitsi/sdp-interop": "0.1.14", "@jitsi/sdp-interop": "0.1.14",
"@jitsi/sdp-simulcast": "0.2.2", "@jitsi/sdp-simulcast": "0.2.2",

View File

@ -56,7 +56,7 @@
"js-utils": "github:jitsi/js-utils#400ce825d3565019946ee75d86ed773c6f21e117", "js-utils": "github:jitsi/js-utils#400ce825d3565019946ee75d86ed773c6f21e117",
"jsrsasign": "8.0.12", "jsrsasign": "8.0.12",
"jwt-decode": "2.2.0", "jwt-decode": "2.2.0",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#8deeaf6bd2b233ab163303e42febfee87201b2d9", "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#e4b523d0fab83a1cf1408abbf41f5d0ca1169900",
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d", "libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.13", "lodash": "4.17.13",
"moment": "2.19.4", "moment": "2.19.4",

View File

@ -8,6 +8,7 @@ import '../../base/user-interaction';
import '../../chat'; import '../../chat';
import '../../external-api'; import '../../external-api';
import '../../no-audio-signal'; import '../../no-audio-signal';
import '../../noise-detection';
import '../../power-monitor'; import '../../power-monitor';
import '../../room-lock'; import '../../room-lock';
import '../../talk-while-muted'; import '../../talk-while-muted';

View File

@ -48,13 +48,10 @@ MiddlewareRegistry.register(store => next => async action => {
async function _handleNoAudioSignalNotification({ dispatch, getState }, action) { async function _handleNoAudioSignalNotification({ dispatch, getState }, action) {
const { conference } = action; const { conference } = action;
let confAudioInputState;
conference.on(JitsiConferenceEvents.AUDIO_INPUT_STATE_CHANGE, hasAudioInput => { conference.on(JitsiConferenceEvents.AUDIO_INPUT_STATE_CHANGE, hasAudioInput => {
const { noAudioSignalNotificationUid } = getState()['features/no-audio-signal']; const { noAudioSignalNotificationUid } = getState()['features/no-audio-signal'];
confAudioInputState = hasAudioInput;
// In case the notification is displayed but the conference detected audio input signal we hide it. // In case the notification is displayed but the conference detected audio input signal we hide it.
if (noAudioSignalNotificationUid && hasAudioInput) { if (noAudioSignalNotificationUid && hasAudioInput) {
dispatch(hideNotification(noAudioSignalNotificationUid)); dispatch(hideNotification(noAudioSignalNotificationUid));
@ -71,17 +68,8 @@ async function _handleNoAudioSignalNotification({ dispatch, getState }, action)
return; return;
} }
// Force the flag to false in case AUDIO_INPUT_STATE_CHANGE is received after the notification is displayed,
// possibly preventing the notification from displaying because of an outdated state.
confAudioInputState = false;
const activeDevice = await JitsiMeetJS.getActiveAudioDevice(); const activeDevice = await JitsiMeetJS.getActiveAudioDevice();
if (confAudioInputState) {
return;
}
// In case there is a previous notification displayed just hide it. // In case there is a previous notification displayed just hide it.
const { noAudioSignalNotificationUid } = getState()['features/no-audio-signal']; const { noAudioSignalNotificationUid } = getState()['features/no-audio-signal'];

View File

@ -0,0 +1,11 @@
/**
* The type of Redux action which sets the pending notification UID
* to use it when hiding the notification is necessary, or unset it when
* undefined (or no param) is passed.
*
* {
* type: SET_NOISY_AUDIO_INPUT_NOTIFICATION_UID
* uid: ?number
* }
*/
export const SET_NOISY_AUDIO_INPUT_NOTIFICATION_UID = 'SET_NOISY_AUDIO_INPUT_NOTIFICATION_UID';

View File

@ -0,0 +1,21 @@
// @flow
import { SET_NOISY_AUDIO_INPUT_NOTIFICATION_UID } from './actionTypes';
/**
* Sets UID of the the pending notification to use it when hiding
* the notification is necessary, or unset it when undefined (or no param) is
* passed.
*
* @param {?number} uid - The UID of the notification.
* @returns {{
* type: SET_NOISY_AUDIO_INPUT_NOTIFICATION_UID,
* uid: number
* }}
*/
export function setNoisyAudioInputNotificationUid(uid: ?number) {
return {
type: SET_NOISY_AUDIO_INPUT_NOTIFICATION_UID,
uid
};
}

View File

@ -0,0 +1,6 @@
/**
* The identifier of the sound to be played when we display a you are noisy notification.
*
* @type {string}
*/
export const NOISY_AUDIO_INPUT_SOUND_ID = 'NOISY_AUDIO_INPUT_SOUND_ID';

View File

@ -0,0 +1,4 @@
// @flow
import './middleware';
import './reducer';

View File

@ -0,0 +1,57 @@
// @flow
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
import { CONFERENCE_JOINED } from '../base/conference';
import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
import { MiddlewareRegistry } from '../base/redux';
import { playSound, registerSound, unregisterSound } from '../base/sounds';
import { hideNotification, showNotification } from '../notifications';
import { setNoisyAudioInputNotificationUid } from './actions';
import { NOISY_AUDIO_INPUT_SOUND_ID } from './constants';
import { NOISY_AUDIO_INPUT_SOUND_FILE } from './sounds';
MiddlewareRegistry.register(store => next => action => {
const result = next(action);
switch (action.type) {
case APP_WILL_MOUNT:
store.dispatch(registerSound(NOISY_AUDIO_INPUT_SOUND_ID, NOISY_AUDIO_INPUT_SOUND_FILE));
break;
case APP_WILL_UNMOUNT:
store.dispatch(unregisterSound(NOISY_AUDIO_INPUT_SOUND_ID));
break;
case CONFERENCE_JOINED: {
const { dispatch, getState } = store;
const { conference } = action;
conference.on(
JitsiConferenceEvents.TRACK_MUTE_CHANGED,
track => {
const { noisyAudioInputNotificationUid } = getState()['features/noise-detection'];
// Hide the notification in case the user mutes the microphone
if (noisyAudioInputNotificationUid && track.isAudioTrack() && track.isLocal() && track.isMuted()) {
dispatch(hideNotification(noisyAudioInputNotificationUid));
dispatch(setNoisyAudioInputNotificationUid());
}
});
conference.on(
JitsiConferenceEvents.NOISY_MIC, () => {
const notification = showNotification({
titleKey: 'toolbar.noisyAudioInputTitle',
descriptionKey: 'toolbar.noisyAudioInputDesc'
});
dispatch(notification);
dispatch(playSound(NOISY_AUDIO_INPUT_SOUND_ID));
// we store the last notification id so we can hide it if the mic is muted
dispatch(setNoisyAudioInputNotificationUid(notification.uid));
});
break;
}
}
return result;
});

View File

@ -0,0 +1,17 @@
// @flow
import { ReducerRegistry, set } from '../base/redux';
import { SET_NOISY_AUDIO_INPUT_NOTIFICATION_UID } from './actionTypes';
/**
* Reduces the redux actions of noise detection feature
*/
ReducerRegistry.register('features/noise-detection', (state = {}, action) => {
switch (action.type) {
case SET_NOISY_AUDIO_INPUT_NOTIFICATION_UID:
return set(state, 'noisyAudioInputNotificationUid', action.uid);
}
return state;
});

View File

@ -0,0 +1,6 @@
/**
* The file used for the noisy audio input notification.
*
* @type {string}
*/
export const NOISY_AUDIO_INPUT_SOUND_FILE = 'noisyAudioInput.mp3';

BIN
sounds/noisyAudioInput.mp3 Normal file

Binary file not shown.