feat(conference) Implement audio/video mute disable when sender limit is reached.
* feat(conference) Impl audio/video mute disable when sender limit is reached. Jicofo sends a presence when the audio/video sender limit is reached in the conference. The client can then proceed to disable the audio and video mute buttons when this occurs. * squash: use a different action type and show notification.
This commit is contained in:
parent
d8487c25b2
commit
c7765cc1b7
|
@ -76,12 +76,16 @@ import {
|
||||||
import {
|
import {
|
||||||
getStartWithAudioMuted,
|
getStartWithAudioMuted,
|
||||||
getStartWithVideoMuted,
|
getStartWithVideoMuted,
|
||||||
|
isAudioMuted,
|
||||||
|
isVideoMuted,
|
||||||
isVideoMutedByUser,
|
isVideoMutedByUser,
|
||||||
MEDIA_TYPE,
|
MEDIA_TYPE,
|
||||||
setAudioAvailable,
|
setAudioAvailable,
|
||||||
setAudioMuted,
|
setAudioMuted,
|
||||||
|
setAudioUnmutePermissions,
|
||||||
setVideoAvailable,
|
setVideoAvailable,
|
||||||
setVideoMuted
|
setVideoMuted,
|
||||||
|
setVideoUnmutePermissions
|
||||||
} from './react/features/base/media';
|
} from './react/features/base/media';
|
||||||
import {
|
import {
|
||||||
dominantSpeakerChanged,
|
dominantSpeakerChanged,
|
||||||
|
@ -2257,6 +2261,27 @@ export default {
|
||||||
APP.store.dispatch(suspendDetected());
|
APP.store.dispatch(suspendDetected());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
room.on(
|
||||||
|
JitsiConferenceEvents.AUDIO_UNMUTE_PERMISSIONS_CHANGED,
|
||||||
|
disableAudioMuteChange => {
|
||||||
|
const muted = isAudioMuted(APP.store.getState());
|
||||||
|
|
||||||
|
// Disable the mute button only if its muted.
|
||||||
|
if (!disableAudioMuteChange || (disableAudioMuteChange && muted)) {
|
||||||
|
APP.store.dispatch(setAudioUnmutePermissions(disableAudioMuteChange));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
room.on(
|
||||||
|
JitsiConferenceEvents.VIDEO_UNMUTE_PERMISSIONS_CHANGED,
|
||||||
|
disableVideoMuteChange => {
|
||||||
|
const muted = isVideoMuted(APP.store.getState());
|
||||||
|
|
||||||
|
// Disable the mute button only if its muted.
|
||||||
|
if (!disableVideoMuteChange || (disableVideoMuteChange && muted)) {
|
||||||
|
APP.store.dispatch(setVideoUnmutePermissions(disableVideoMuteChange));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
APP.UI.addListener(UIEvents.AUDIO_MUTED, muted => {
|
APP.UI.addListener(UIEvents.AUDIO_MUTED, muted => {
|
||||||
this.muteAudio(muted);
|
this.muteAudio(muted);
|
||||||
});
|
});
|
||||||
|
|
|
@ -572,6 +572,8 @@
|
||||||
"notify": {
|
"notify": {
|
||||||
"allowAction": "Allow",
|
"allowAction": "Allow",
|
||||||
"allowedUnmute": "You can unmute your microphone, start your camera or share your screen.",
|
"allowedUnmute": "You can unmute your microphone, start your camera or share your screen.",
|
||||||
|
"audioUnmuteBlockedTitle": "Mic unmute blocked!",
|
||||||
|
"audioUnmuteBlockedDescription": "Mic unmute operation has been temporarily blocked because of system limits.",
|
||||||
"connectedOneMember": "{{name}} joined the meeting",
|
"connectedOneMember": "{{name}} joined the meeting",
|
||||||
"connectedThreePlusMembers": "{{name}} and many others joined the meeting",
|
"connectedThreePlusMembers": "{{name}} and many others joined the meeting",
|
||||||
"connectedTwoMembers": "{{first}} and {{second}} joined the meeting",
|
"connectedTwoMembers": "{{first}} and {{second}} joined the meeting",
|
||||||
|
@ -622,7 +624,9 @@
|
||||||
"moderationToggleDescription": "by {{participantDisplayName}}",
|
"moderationToggleDescription": "by {{participantDisplayName}}",
|
||||||
"raiseHandAction": "Raise hand",
|
"raiseHandAction": "Raise hand",
|
||||||
"reactionSounds": "Disable sounds",
|
"reactionSounds": "Disable sounds",
|
||||||
"groupTitle": "Notifications"
|
"groupTitle": "Notifications",
|
||||||
|
"videoUnmuteBlockedTitle": "Camera unmute blocked!",
|
||||||
|
"videoUnmuteBlockedDescription": "Camera unmute operation has been temporarily blocked because of system limits."
|
||||||
},
|
},
|
||||||
"participantsPane": {
|
"participantsPane": {
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
|
|
|
@ -10,7 +10,15 @@ import { endpointMessageReceived } from '../../subtitles';
|
||||||
import { getReplaceParticipant } from '../config/functions';
|
import { getReplaceParticipant } from '../config/functions';
|
||||||
import { JITSI_CONNECTION_CONFERENCE_KEY } from '../connection';
|
import { JITSI_CONNECTION_CONFERENCE_KEY } from '../connection';
|
||||||
import { JitsiConferenceEvents } from '../lib-jitsi-meet';
|
import { JitsiConferenceEvents } from '../lib-jitsi-meet';
|
||||||
import { MEDIA_TYPE, setAudioMuted, setVideoMuted } from '../media';
|
import {
|
||||||
|
MEDIA_TYPE,
|
||||||
|
isAudioMuted,
|
||||||
|
isVideoMuted,
|
||||||
|
setAudioMuted,
|
||||||
|
setAudioUnmutePermissions,
|
||||||
|
setVideoMuted,
|
||||||
|
setVideoUnmutePermissions
|
||||||
|
} from '../media';
|
||||||
import {
|
import {
|
||||||
dominantSpeakerChanged,
|
dominantSpeakerChanged,
|
||||||
getNormalizedDisplayName,
|
getNormalizedDisplayName,
|
||||||
|
@ -146,6 +154,27 @@ function _addConferenceListeners(conference, dispatch, state) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
conference.on(
|
||||||
|
JitsiConferenceEvents.AUDIO_UNMUTE_PERMISSIONS_CHANGED,
|
||||||
|
disableAudioMuteChange => {
|
||||||
|
const muted = isAudioMuted(state);
|
||||||
|
|
||||||
|
// Disable the mute button only if its muted.
|
||||||
|
if (!disableAudioMuteChange || (disableAudioMuteChange && muted)) {
|
||||||
|
APP.store.dispatch(setAudioUnmutePermissions(disableAudioMuteChange));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
conference.on(
|
||||||
|
JitsiConferenceEvents.VIDEO_UNMUTE_PERMISSIONS_CHANGED,
|
||||||
|
disableVideoMuteChange => {
|
||||||
|
const muted = isVideoMuted(state);
|
||||||
|
|
||||||
|
// Disable the mute button only if its muted.
|
||||||
|
if (!disableVideoMuteChange || (disableVideoMuteChange && muted)) {
|
||||||
|
APP.store.dispatch(setVideoUnmutePermissions(disableVideoMuteChange));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Dispatches into features/base/tracks follow:
|
// Dispatches into features/base/tracks follow:
|
||||||
|
|
||||||
conference.on(
|
conference.on(
|
||||||
|
|
|
@ -1,3 +1,14 @@
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of (redux) action to adjust the availability of the local audio.
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* type: SET_AUDIO_AVAILABLE,
|
||||||
|
* muted: boolean
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const SET_AUDIO_AVAILABLE = 'SET_AUDIO_AVAILABLE';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of (redux) action to set the muted state of the local audio.
|
* The type of (redux) action to set the muted state of the local audio.
|
||||||
*
|
*
|
||||||
|
@ -9,14 +20,14 @@
|
||||||
export const SET_AUDIO_MUTED = 'SET_AUDIO_MUTED';
|
export const SET_AUDIO_MUTED = 'SET_AUDIO_MUTED';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of (redux) action to adjust the availability of the local audio.
|
* The type of (redux) action to enable/disable the audio mute icon.
|
||||||
*
|
*
|
||||||
* {
|
* {
|
||||||
* type: SET_AUDIO_AVAILABLE,
|
* type: SET_AUDIO_UNMUTE_PERMISSIONS,
|
||||||
* muted: boolean
|
* blocked: boolean
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
export const SET_AUDIO_AVAILABLE = 'SET_AUDIO_AVAILABLE';
|
export const SET_AUDIO_UNMUTE_PERMISSIONS = 'SET_AUDIO_UNMUTE_PERMISSIONS';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of (redux) action to set the facing mode of the local video camera
|
* The type of (redux) action to set the facing mode of the local video camera
|
||||||
|
@ -61,6 +72,16 @@ export const SET_VIDEO_MUTED = 'SET_VIDEO_MUTED';
|
||||||
*/
|
*/
|
||||||
export const STORE_VIDEO_TRANSFORM = 'STORE_VIDEO_TRANSFORM';
|
export const STORE_VIDEO_TRANSFORM = 'STORE_VIDEO_TRANSFORM';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of (redux) action to enable/disable the video mute icon.
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* type: SET_VIDEO_UNMUTE_PERMISSIONS,
|
||||||
|
* blocked: boolean
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const SET_VIDEO_UNMUTE_PERMISSIONS = 'SET_VIDEO_UNMUTE_PERMISSIONS';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of (redux) action to toggle the local video camera facing mode. In
|
* The type of (redux) action to toggle the local video camera facing mode. In
|
||||||
* contrast to SET_CAMERA_FACING_MODE, allows the toggling to be optimally
|
* contrast to SET_CAMERA_FACING_MODE, allows the toggling to be optimally
|
||||||
|
|
|
@ -9,9 +9,11 @@ import { isModerationNotificationDisplayed } from '../../notifications';
|
||||||
import {
|
import {
|
||||||
SET_AUDIO_MUTED,
|
SET_AUDIO_MUTED,
|
||||||
SET_AUDIO_AVAILABLE,
|
SET_AUDIO_AVAILABLE,
|
||||||
|
SET_AUDIO_UNMUTE_PERMISSIONS,
|
||||||
SET_CAMERA_FACING_MODE,
|
SET_CAMERA_FACING_MODE,
|
||||||
SET_VIDEO_AVAILABLE,
|
SET_VIDEO_AVAILABLE,
|
||||||
SET_VIDEO_MUTED,
|
SET_VIDEO_MUTED,
|
||||||
|
SET_VIDEO_UNMUTE_PERMISSIONS,
|
||||||
STORE_VIDEO_TRANSFORM,
|
STORE_VIDEO_TRANSFORM,
|
||||||
TOGGLE_CAMERA_FACING_MODE
|
TOGGLE_CAMERA_FACING_MODE
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
|
@ -59,6 +61,19 @@ export function setAudioMuted(muted: boolean, ensureTrack: boolean = false) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action to disable/enable the audio mute icon.
|
||||||
|
*
|
||||||
|
* @param {boolean} blocked - True if the audio mute icon needs to be disabled.
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
export function setAudioUnmutePermissions(blocked: boolean) {
|
||||||
|
return {
|
||||||
|
type: SET_AUDIO_UNMUTE_PERMISSIONS,
|
||||||
|
blocked
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action to set the facing mode of the local camera.
|
* Action to set the facing mode of the local camera.
|
||||||
*
|
*
|
||||||
|
@ -136,6 +151,19 @@ export function setVideoMuted(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action to disable/enable the video mute icon.
|
||||||
|
*
|
||||||
|
* @param {boolean} blocked - True if the video mute icon needs to be disabled.
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
export function setVideoUnmutePermissions(blocked: boolean) {
|
||||||
|
return {
|
||||||
|
type: SET_VIDEO_UNMUTE_PERMISSIONS,
|
||||||
|
blocked
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an action to store the last video {@link Transform} applied to a
|
* Creates an action to store the last video {@link Transform} applied to a
|
||||||
* stream.
|
* stream.
|
||||||
|
|
|
@ -88,6 +88,16 @@ export function getStartWithVideoMuted(stateful: Object | Function) {
|
||||||
return Boolean(getPropertyValue(stateful, 'startWithVideoMuted', START_WITH_AUDIO_VIDEO_MUTED_SOURCES));
|
return Boolean(getPropertyValue(stateful, 'startWithVideoMuted', START_WITH_AUDIO_VIDEO_MUTED_SOURCES));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether video is currently muted.
|
||||||
|
*
|
||||||
|
* @param {Function|Object} stateful - The redux store, state, or {@code getState} function.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isVideoMuted(stateful: Function | Object) {
|
||||||
|
return Boolean(toState(stateful)['features/base/media'].video.muted);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether video is currently muted by the user authority.
|
* Determines whether video is currently muted by the user authority.
|
||||||
*
|
*
|
||||||
|
|
|
@ -8,6 +8,10 @@ import {
|
||||||
sendAnalytics
|
sendAnalytics
|
||||||
} from '../../analytics';
|
} from '../../analytics';
|
||||||
import { APP_STATE_CHANGED } from '../../mobile/background';
|
import { APP_STATE_CHANGED } from '../../mobile/background';
|
||||||
|
import {
|
||||||
|
NOTIFICATION_TIMEOUT_TYPE,
|
||||||
|
showWarningNotification
|
||||||
|
} from '../../notifications';
|
||||||
import { isForceMuted } from '../../participants-pane/functions';
|
import { isForceMuted } from '../../participants-pane/functions';
|
||||||
import { SET_AUDIO_ONLY, setAudioOnly } from '../audio-only';
|
import { SET_AUDIO_ONLY, setAudioOnly } from '../audio-only';
|
||||||
import { isRoomValid, SET_ROOM } from '../conference';
|
import { isRoomValid, SET_ROOM } from '../conference';
|
||||||
|
@ -21,7 +25,12 @@ import {
|
||||||
TRACK_ADDED
|
TRACK_ADDED
|
||||||
} from '../tracks';
|
} from '../tracks';
|
||||||
|
|
||||||
import { SET_AUDIO_MUTED, SET_VIDEO_MUTED } from './actionTypes';
|
import {
|
||||||
|
SET_AUDIO_MUTED,
|
||||||
|
SET_AUDIO_UNMUTE_PERMISSIONS,
|
||||||
|
SET_VIDEO_MUTED,
|
||||||
|
SET_VIDEO_UNMUTE_PERMISSIONS
|
||||||
|
} from './actionTypes';
|
||||||
import { setAudioMuted, setCameraFacingMode, setVideoMuted } from './actions';
|
import { setAudioMuted, setCameraFacingMode, setVideoMuted } from './actions';
|
||||||
import {
|
import {
|
||||||
CAMERA_FACING_MODE,
|
CAMERA_FACING_MODE,
|
||||||
|
@ -74,6 +83,18 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SET_AUDIO_UNMUTE_PERMISSIONS: {
|
||||||
|
const { blocked } = action;
|
||||||
|
|
||||||
|
if (blocked) {
|
||||||
|
store.dispatch(showWarningNotification({
|
||||||
|
descriptionKey: 'notify.audioUnmuteBlockedDescription',
|
||||||
|
titleKey: 'notify.audioUnmuteBlockedTitle'
|
||||||
|
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SET_VIDEO_MUTED: {
|
case SET_VIDEO_MUTED: {
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
const participant = getLocalParticipant(state);
|
const participant = getLocalParticipant(state);
|
||||||
|
@ -83,6 +104,18 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SET_VIDEO_UNMUTE_PERMISSIONS: {
|
||||||
|
const { blocked } = action;
|
||||||
|
|
||||||
|
if (blocked) {
|
||||||
|
store.dispatch(showWarningNotification({
|
||||||
|
descriptionKey: 'notify.videoUnmuteBlockedDescription',
|
||||||
|
titleKey: 'notify.videoUnmuteBlockedTitle'
|
||||||
|
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return next(action);
|
return next(action);
|
||||||
|
|
|
@ -7,9 +7,11 @@ import { TRACK_REMOVED } from '../tracks/actionTypes';
|
||||||
import {
|
import {
|
||||||
SET_AUDIO_AVAILABLE,
|
SET_AUDIO_AVAILABLE,
|
||||||
SET_AUDIO_MUTED,
|
SET_AUDIO_MUTED,
|
||||||
|
SET_AUDIO_UNMUTE_PERMISSIONS,
|
||||||
SET_CAMERA_FACING_MODE,
|
SET_CAMERA_FACING_MODE,
|
||||||
SET_VIDEO_AVAILABLE,
|
SET_VIDEO_AVAILABLE,
|
||||||
SET_VIDEO_MUTED,
|
SET_VIDEO_MUTED,
|
||||||
|
SET_VIDEO_UNMUTE_PERMISSIONS,
|
||||||
STORE_VIDEO_TRANSFORM,
|
STORE_VIDEO_TRANSFORM,
|
||||||
TOGGLE_CAMERA_FACING_MODE
|
TOGGLE_CAMERA_FACING_MODE
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
|
@ -33,6 +35,7 @@ import { CAMERA_FACING_MODE } from './constants';
|
||||||
*/
|
*/
|
||||||
export const _AUDIO_INITIAL_MEDIA_STATE = {
|
export const _AUDIO_INITIAL_MEDIA_STATE = {
|
||||||
available: true,
|
available: true,
|
||||||
|
blocked: false,
|
||||||
muted: false
|
muted: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,6 +62,12 @@ function _audio(state = _AUDIO_INITIAL_MEDIA_STATE, action) {
|
||||||
muted: action.muted
|
muted: action.muted
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case SET_AUDIO_UNMUTE_PERMISSIONS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
blocked: action.blocked
|
||||||
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -83,6 +92,7 @@ function _audio(state = _AUDIO_INITIAL_MEDIA_STATE, action) {
|
||||||
*/
|
*/
|
||||||
export const _VIDEO_INITIAL_MEDIA_STATE = {
|
export const _VIDEO_INITIAL_MEDIA_STATE = {
|
||||||
available: true,
|
available: true,
|
||||||
|
blocked: false,
|
||||||
facingMode: CAMERA_FACING_MODE.USER,
|
facingMode: CAMERA_FACING_MODE.USER,
|
||||||
muted: 0,
|
muted: 0,
|
||||||
|
|
||||||
|
@ -126,6 +136,12 @@ function _video(state = _VIDEO_INITIAL_MEDIA_STATE, action) {
|
||||||
muted: action.muted
|
muted: action.muted
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case SET_VIDEO_UNMUTE_PERMISSIONS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
blocked: action.blocked
|
||||||
|
};
|
||||||
|
|
||||||
case STORE_VIDEO_TRANSFORM:
|
case STORE_VIDEO_TRANSFORM:
|
||||||
return _storeVideoTransform(state, action);
|
return _storeVideoTransform(state, action);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
showNotification
|
showNotification
|
||||||
} from '../notifications';
|
} from '../notifications';
|
||||||
import { isForceMuted } from '../participants-pane/functions';
|
import { isForceMuted } from '../participants-pane/functions';
|
||||||
|
import { isAudioMuteButtonDisabled } from '../toolbox/functions.any';
|
||||||
|
|
||||||
import { setCurrentNotificationUid } from './actions';
|
import { setCurrentNotificationUid } from './actions';
|
||||||
import { TALK_WHILE_MUTED_SOUND_ID } from './constants';
|
import { TALK_WHILE_MUTED_SOUND_ID } from './constants';
|
||||||
|
@ -46,24 +47,27 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
JitsiConferenceEvents.TALK_WHILE_MUTED, async () => {
|
JitsiConferenceEvents.TALK_WHILE_MUTED, async () => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const local = getLocalParticipant(state);
|
const local = getLocalParticipant(state);
|
||||||
const forceMuted = isForceMuted(local, MEDIA_TYPE.AUDIO, state);
|
|
||||||
const notification = await dispatch(showNotification({
|
|
||||||
titleKey: 'toolbar.talkWhileMutedPopup',
|
|
||||||
customActionNameKey: forceMuted ? 'notify.raiseHandAction' : 'notify.unmute',
|
|
||||||
customActionHandler: () => dispatch(forceMuted ? raiseHand(true) : setAudioMuted(false))
|
|
||||||
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
|
|
||||||
|
|
||||||
const { soundsTalkWhileMuted } = getState()['features/base/settings'];
|
// Display the talk while muted notification only when the audio button is not disabled.
|
||||||
|
if (!isAudioMuteButtonDisabled(state)) {
|
||||||
|
const forceMuted = isForceMuted(local, MEDIA_TYPE.AUDIO, state);
|
||||||
|
const notification = await dispatch(showNotification({
|
||||||
|
titleKey: 'toolbar.talkWhileMutedPopup',
|
||||||
|
customActionNameKey: forceMuted ? 'notify.raiseHandAction' : 'notify.unmute',
|
||||||
|
customActionHandler: () => dispatch(forceMuted ? raiseHand(true) : setAudioMuted(false))
|
||||||
|
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
|
||||||
|
|
||||||
if (soundsTalkWhileMuted) {
|
const { soundsTalkWhileMuted } = getState()['features/base/settings'];
|
||||||
dispatch(playSound(TALK_WHILE_MUTED_SOUND_ID));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (soundsTalkWhileMuted) {
|
||||||
|
dispatch(playSound(TALK_WHILE_MUTED_SOUND_ID));
|
||||||
|
}
|
||||||
|
|
||||||
if (notification) {
|
if (notification) {
|
||||||
// we store the last start muted notification id that we showed,
|
// we store the last start muted notification id that we showed,
|
||||||
// so we can hide it when unmuted mic is detected
|
// so we can hide it when unmuted mic is detected
|
||||||
dispatch(setCurrentNotificationUid(notification.uid));
|
dispatch(setCurrentNotificationUid(notification.uid));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { AbstractAudioMuteButton } from '../../base/toolbox/components';
|
||||||
import type { AbstractButtonProps } from '../../base/toolbox/components';
|
import type { AbstractButtonProps } from '../../base/toolbox/components';
|
||||||
import { isLocalTrackMuted } from '../../base/tracks';
|
import { isLocalTrackMuted } from '../../base/tracks';
|
||||||
import { muteLocal } from '../../video-menu/actions';
|
import { muteLocal } from '../../video-menu/actions';
|
||||||
|
import { isAudioMuteButtonDisabled } from '../functions';
|
||||||
|
|
||||||
declare var APP: Object;
|
declare var APP: Object;
|
||||||
|
|
||||||
|
@ -151,7 +152,7 @@ class AudioMuteButton extends AbstractAudioMuteButton<Props, *> {
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state): Object {
|
function _mapStateToProps(state): Object {
|
||||||
const _audioMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.AUDIO);
|
const _audioMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.AUDIO);
|
||||||
const _disabled = state['features/base/config'].startSilent;
|
const _disabled = state['features/base/config'].startSilent || isAudioMuteButtonDisabled(state);
|
||||||
const enabledFlag = getFeatureFlag(state, AUDIO_MUTE_BUTTON_ENABLED, true);
|
const enabledFlag = getFeatureFlag(state, AUDIO_MUTE_BUTTON_ENABLED, true);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the audio mute button is disabled or not.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The state from the Redux store.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isAudioMuteButtonDisabled(state: Object) {
|
||||||
|
const { audio } = state['features/base/media'];
|
||||||
|
|
||||||
|
return !(audio?.available && !audio?.blocked);
|
||||||
|
}
|
|
@ -6,6 +6,8 @@ import { getParticipantCountWithFake } from '../base/participants';
|
||||||
import { toState } from '../base/redux';
|
import { toState } from '../base/redux';
|
||||||
import { isLocalVideoTrackDesktop } from '../base/tracks';
|
import { isLocalVideoTrackDesktop } from '../base/tracks';
|
||||||
|
|
||||||
|
export * from './functions.any';
|
||||||
|
|
||||||
const WIDTH = {
|
const WIDTH = {
|
||||||
FIT_9_ICONS: 560,
|
FIT_9_ICONS: 560,
|
||||||
FIT_8_ICONS: 500,
|
FIT_8_ICONS: 500,
|
||||||
|
@ -78,5 +80,7 @@ export function isToolboxVisible(stateful: Object | Function) {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isVideoMuteButtonDisabled(state: Object) {
|
export function isVideoMuteButtonDisabled(state: Object) {
|
||||||
return !hasAvailableDevices(state, 'videoInput') || isLocalVideoTrackDesktop(state);
|
const { video } = state['features/base/media'];
|
||||||
|
|
||||||
|
return !hasAvailableDevices(state, 'videoInput') || video?.blocked || isLocalVideoTrackDesktop(state);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { hasAvailableDevices } from '../base/devices';
|
||||||
|
|
||||||
import { TOOLBAR_TIMEOUT } from './constants';
|
import { TOOLBAR_TIMEOUT } from './constants';
|
||||||
|
|
||||||
|
export * from './functions.any';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for getting the height of the toolbox.
|
* Helper for getting the height of the toolbox.
|
||||||
*
|
*
|
||||||
|
@ -58,8 +60,9 @@ export function isToolboxVisible(state: Object) {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isAudioSettingsButtonDisabled(state: Object) {
|
export function isAudioSettingsButtonDisabled(state: Object) {
|
||||||
return (!hasAvailableDevices(state, 'audioInput')
|
|
||||||
&& !hasAvailableDevices(state, 'audioOutput'))
|
return !(hasAvailableDevices(state, 'audioInput')
|
||||||
|
&& hasAvailableDevices(state, 'audioOutput'))
|
||||||
|| state['features/base/config'].startSilent;
|
|| state['features/base/config'].startSilent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +83,9 @@ export function isVideoSettingsButtonDisabled(state: Object) {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isVideoMuteButtonDisabled(state: Object) {
|
export function isVideoMuteButtonDisabled(state: Object) {
|
||||||
return !hasAvailableDevices(state, 'videoInput');
|
const { video } = state['features/base/media'];
|
||||||
|
|
||||||
|
return !hasAvailableDevices(state, 'videoInput') || video?.blocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue