feat(silent): hide unmute if participant joined without audio (#14803)

* feat(silent): hide unmute if participant joined without audio

* Add additional listener for SILENT_STATUS_CHANGED

* squash: Rename local variable.

* chore(deps) lib-jitsi-meet@latest

https://github.com/jitsi/lib-jitsi-meet/compare/v1839.0.0+ea523fc6...v1840.0.0+fc115be5

---------

Co-authored-by: damencho <damencho@jitsi.org>
This commit is contained in:
Nathan Beck
2024-07-02 09:22:10 -04:00
committed by GitHub
parent 3ae50b6c4c
commit b4a5e63d1d
11 changed files with 75 additions and 15 deletions

View File

@@ -1676,6 +1676,18 @@ export default {
});
}
);
room.on(
JitsiConferenceEvents.SILENT_STATUS_CHANGED,
(id, isSilent) => {
APP.store.dispatch(participantUpdated({
conference: room,
id,
isSilent
}));
}
);
room.on(
JitsiConferenceEvents.BOT_TYPE_CHANGED,
(id, botType) => {

10
package-lock.json generated
View File

@@ -61,7 +61,7 @@
"js-md5": "0.6.1",
"js-sha512": "0.8.0",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1839.0.0+ea523fc6/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1840.0.0+fc115be5/lib-jitsi-meet.tgz",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
@@ -12310,8 +12310,8 @@
},
"node_modules/lib-jitsi-meet": {
"version": "0.0.0",
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1839.0.0+ea523fc6/lib-jitsi-meet.tgz",
"integrity": "sha512-pRIOBZFtIT4Y0WrrfxNKJnMbDx17ZYYbU3ygUd/hYvvyOkKMMteS4cZWqONAxn+esKhpkWksPSuZ8L4y4V5wnQ==",
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1840.0.0+fc115be5/lib-jitsi-meet.tgz",
"integrity": "sha512-eRS2ovayYegiD17OATaOCv4hwhRdjK71dgJwrlsLRBIf0EB01EGu1YBTcER4ajB1J1m7JFNBH1Qtmp3hZ1/7+A==",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
@@ -28096,8 +28096,8 @@
}
},
"lib-jitsi-meet": {
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1839.0.0+ea523fc6/lib-jitsi-meet.tgz",
"integrity": "sha512-pRIOBZFtIT4Y0WrrfxNKJnMbDx17ZYYbU3ygUd/hYvvyOkKMMteS4cZWqONAxn+esKhpkWksPSuZ8L4y4V5wnQ==",
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1840.0.0+fc115be5/lib-jitsi-meet.tgz",
"integrity": "sha512-eRS2ovayYegiD17OATaOCv4hwhRdjK71dgJwrlsLRBIf0EB01EGu1YBTcER4ajB1J1m7JFNBH1Qtmp3hZ1/7+A==",
"requires": {
"@jitsi/js-utils": "2.2.1",
"@jitsi/logger": "2.0.2",

View File

@@ -67,7 +67,7 @@
"js-md5": "0.6.1",
"js-sha512": "0.8.0",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1839.0.0+ea523fc6/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1840.0.0+fc115be5/lib-jitsi-meet.tgz",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",

View File

@@ -228,6 +228,14 @@ function _addConferenceListeners(conference: IJitsiConference, dispatch: IStore[
name: getNormalizedDisplayName(displayName)
})));
conference.on(
JitsiConferenceEvents.SILENT_STATUS_CHANGED,
(id: string, isSilent: boolean) => dispatch(participantUpdated({
conference,
id,
isSilent
})));
conference.on(
JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED,
(dominant: string, previous: string[], silence: boolean | string) => {

View File

@@ -706,6 +706,10 @@ function _updateLocalParticipantInConference({ dispatch, getState }: IStore, nex
conference.setDisplayName(participant.name);
}
if ('isSilent' in participant) {
conference.setIsSilent(participant.isSilent);
}
if ('role' in participant && participant.role === PARTICIPANT_ROLE.MODERATOR) {
const { pendingSubjectChange, subject } = getState()['features/base/conference'];

View File

@@ -135,6 +135,7 @@ export interface IJitsiConference {
setAssumedBandwidthBps: (value: number) => void;
setDesktopSharingFrameRate: Function;
setDisplayName: Function;
setIsSilent: Function;
setLocalParticipantProperty: Function;
setMediaEncryptionKey: Function;
setReceiverConstraints: Function;

View File

@@ -19,7 +19,7 @@ import { CALLING, INVITED } from '../../presence-status/constants';
import { RAISE_HAND_SOUND_ID } from '../../reactions/constants';
import { RECORDING_OFF_SOUND_ID, RECORDING_ON_SOUND_ID } from '../../recording/constants';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app/actionTypes';
import { CONFERENCE_WILL_JOIN } from '../conference/actionTypes';
import { CONFERENCE_JOINED, CONFERENCE_WILL_JOIN } from '../conference/actionTypes';
import { forEachConference, getCurrentConference } from '../conference/functions';
import { IJitsiConference } from '../conference/reducer';
import { SET_CONFIG } from '../config/actionTypes';
@@ -201,6 +201,28 @@ MiddlewareRegistry.register(store => next => action => {
return result;
}
case CONFERENCE_JOINED: {
const result = next(action);
const state = store.getState();
const { startSilent } = state['features/base/config'];
if (startSilent) {
const localId = getLocalParticipant(store.getState())?.id;
if (localId) {
store.dispatch(participantUpdated({
id: localId,
local: true,
isSilent: startSilent
}));
}
}
return result;
}
case SET_LOCAL_PARTICIPANT_RECORDING_STATUS: {
const state = store.getState();
const { recording, onlySelf } = action;

View File

@@ -25,6 +25,7 @@ export interface IParticipant {
isJigasi?: boolean;
isReplaced?: boolean;
isReplacing?: number;
isSilent?: boolean;
jwtId?: string;
loadableAvatarUrl?: string;
loadableAvatarUrlUseCORS?: boolean;

View File

@@ -63,6 +63,10 @@ export function getParticipantAudioMediaState(participant: IParticipant | undefi
muted: Boolean, state: IReduxState) {
const dominantSpeaker = getDominantSpeakerParticipant(state);
if (participant?.isSilent) {
return MEDIA_STATE.NONE;
}
if (muted) {
if (isForceMuted(participant, MEDIA_TYPE.AUDIO, state)) {
return MEDIA_STATE.FORCE_MUTED;
@@ -146,9 +150,10 @@ export function getQuickActionButtonType(
state: IReduxState) {
// handled only by moderators
const isVideoForceMuted = isForceMuted(participant, MEDIA_TYPE.VIDEO, state);
const isParticipantSilent = participant?.isSilent || false;
if (isLocalParticipantModerator(state)) {
if (!isAudioMuted) {
if (!isAudioMuted && !isParticipantSilent) {
return QUICK_ACTION_BUTTON.MUTE;
}
if (!isVideoMuted) {
@@ -157,7 +162,7 @@ export function getQuickActionButtonType(
if (isVideoForceMuted) {
return QUICK_ACTION_BUTTON.ALLOW_VIDEO;
}
if (isSupported()(state)) {
if (isSupported()(state) && !isParticipantSilent) {
return QUICK_ACTION_BUTTON.ASK_TO_UNMUTE;
}
}

View File

@@ -78,6 +78,11 @@ interface IProps {
*/
_isParticipantAvailable?: boolean;
/**
* Whether or not the targeted participant joined without audio.
*/
_isParticipantSilent: boolean;
/**
* Whether the local participant is moderator or not.
*/
@@ -143,6 +148,7 @@ class RemoteVideoMenu extends PureComponent<IProps> {
_disableGrantModerator,
_isBreakoutRoom,
_isParticipantAvailable,
_isParticipantSilent,
_moderator,
_rooms,
_showDemote,
@@ -166,10 +172,10 @@ class RemoteVideoMenu extends PureComponent<IProps> {
<BottomSheet
renderHeader = { this._renderMenuHeader }
showSlidingView = { _isParticipantAvailable }>
<AskUnmuteButton { ...buttonProps } />
{!_isParticipantSilent && <AskUnmuteButton { ...buttonProps } />}
{ !_disableRemoteMute && <MuteButton { ...buttonProps } /> }
<MuteEveryoneElseButton { ...buttonProps } />
{ !_disableRemoteMute && <MuteVideoButton { ...buttonProps } /> }
{ !_disableRemoteMute && !_isParticipantSilent && <MuteVideoButton { ...buttonProps } /> }
{/* @ts-ignore */}
<Divider style = { styles.divider as ViewStyle } />
{ !_disableKick && <KickButton { ...buttonProps } /> }
@@ -242,7 +248,7 @@ function _mapStateToProps(state: IReduxState, ownProps: any) {
const kickOutEnabled = getFeatureFlag(state, KICK_OUT_ENABLED, true);
const { participantId } = ownProps;
const { remoteVideoMenu = {}, disableRemoteMute } = state['features/base/config'];
const isParticipantAvailable = getParticipantById(state, participantId);
const participant = getParticipantById(state, participantId);
const { disableKick, disablePrivateChat } = remoteVideoMenu;
const _rooms = Object.values(getBreakoutRooms(state));
const _currentRoomId = getCurrentRoomId(state);
@@ -257,7 +263,8 @@ function _mapStateToProps(state: IReduxState, ownProps: any) {
_disableRemoteMute: Boolean(disableRemoteMute),
_disablePrivateChat: Boolean(disablePrivateChat) || _iAmVisitor,
_isBreakoutRoom,
_isParticipantAvailable: Boolean(isParticipantAvailable),
_isParticipantAvailable: Boolean(participant),
_isParticipantSilent: Boolean(participant?.isSilent),
_moderator: moderator,
_participantDisplayName: getParticipantDisplayName(state, participantId),
_rooms,

View File

@@ -214,7 +214,7 @@ const ParticipantContextMenu = ({
if (_isModerator) {
if (isModerationSupported) {
if (_isAudioMuted
if (_isAudioMuted && !participant.isSilent
&& !(isClickedFromParticipantPane && quickActionButtonType === QUICK_ACTION_BUTTON.ASK_TO_UNMUTE)) {
buttons.push(<AskToUnmuteButton
{ ...getButtonProps(BUTTONS.ASK_UNMUTE) }
@@ -230,7 +230,7 @@ const ParticipantContextMenu = ({
}
}
if (!disableRemoteMute) {
if (!disableRemoteMute && !participant.isSilent) {
if (!(isClickedFromParticipantPane && quickActionButtonType === QUICK_ACTION_BUTTON.MUTE)) {
buttons.push(<MuteButton { ...getButtonProps(BUTTONS.MUTE) } />);
}