Participant camera disable-enable by moderator : Trying to add this feature, Stuck at 'set mute error'

Hi, Am trying to add participant camera enable and disable by a moderator in Latest stable jitsi meet version 2.0.5765 (Web). Already have the camera disable the option in jitsi now. But the moderator couldn’t enable the camera of the participant due to privacy issues.

First of all similar way, am implemented mic unmute/mute by the moderator earlier. Now am trying to implement camera on-off by following these steps

Step 1

Jicofo file change and build from source.* Edit the following code block in file JitsiMeetConferenceImpl.java . Remove this condition or comment (Line: 2422).

// do not allow unmuting other participants even for the moderator
// if (!doMute && !fromJid.equals(toBeMutedJid))
// {
//    logger.warn("Blocking an unmute request (jid not the same).");
//    return false;
// }

This was successful. I replace jicofo.jar , and libs to usr/share/jicofo.

Step2: Frontend UI adding.

UnMuteVideoButton && AbstractUnMuteVideoButton classes created

Export UnMuteButton Component

export { default as UnMuteVideoButton } from ‘./UnMuteVideoButton’;
export { default as UnMuteRemoteParticipantsVideoDialog } from ‘./UnMuteRemoteParticipantsVideoDialog’;

UnMuteVideoButton Component added to remoteVideoOptionsMenu

  • RemoteVideoMenuTriggerButton.js

    • UnMuteButton added import list

      import {
      GrantModeratorButton,
      MuteButton,
      UnMuteButton,
      MuteVideoButton,
      UnMuteVideoButton,
      KickButton,
      PrivateMessageMenuButton,
      RemoteControlButton,
      VideoMenu,
      VolumeSlider
      } from ‘./’;

  • added UnMuteVideoButton component to moderator (_renderRemoteVideoMenu() → if(_isModerator))

    buttons.push(
    <UnMuteVideoButton
    key = ‘unmute-video’
    participantID = { participantID } />
    );

Create Unmute Button Dialog Component
  • Create AbstractUnMuteRemoteParticipantVideoDialog. Then include it in the UnMuteRemoteParticipantVideoDialog class.

  • AbstractUnMuteRemoteParticipantVideoDialog.js

  • UnMuteRemoteParticipantVideoDialog.js

      class UnMuteRemoteParticipantsVideoDialog extends AbstractUnMuteRemoteParticipantsVideoDialog {
          /**
           * Implements React's {@link Component#render()}.
           *
           * @inheritdoc
           * @returns {ReactElement}
           */
          render() {
              return (
                  <Dialog
                      okKey = 'dialog.unMuteParticipantsVideoButton'
                      onSubmit = { this._onSubmit }
                      titleKey = 'dialog.unMuteParticipantsVideoTitle'
                      width = 'small'>
                      <div>
                          { this.props.t('dialog.unMuteParticipantsVideoBody') }
                      </div>
                  </Dialog>
              );
          }
    
          _onSubmit: () => boolean;
      }
    
Controls of Unmute
  • Method created for unmute option unMuteRemoteParticipant imported.

    • action.js

      import {
      getLocalParticipant,
      muteRemoteParticipant,
      unMuteRemoteParticipant
      } from ‘…/base/participants’;

      export function unMuteRemote(participantId: string, mediaType: MEDIA_TYPE) {
      return (dispatch: Dispatch) => {
      if (mediaType !== MEDIA_TYPE.AUDIO && mediaType !== MEDIA_TYPE.VIDEO) {
      logger.error(Unsupported media type: ${mediaType});

              return;
          }
          sendAnalytics(createRemoteMuteConfirmedEvent(participantId, mediaType));
          dispatch(unMuteRemoteParticipant(participantId, mediaType));
      };
      

      }

  • Added const variable → UNMUTE_REMOTE_PARTICIPANT.

export const UNMUTE_REMOTE_PARTICIPANT = 'UNMUTE_REMOTE_PARTICIPANT';

This option import list added.

  • action.js

    import {
    UNMUTE_REMOTE_PARTICIPANT,
    }

    export function unMuteRemoteParticipant(id, mediaType) {
    return {
    type: UNMUTE_REMOTE_PARTICIPANT,
    id,
    mediaType
    };
    }

Created new case (UNMUTE_REMOTE_PARTICIPANT).

  • middleware.js

    import {
    UNMUTE_REMOTE_PARTICIPANT,
    }

    case UNMUTE_REMOTE_PARTICIPANT: {
    const { conference } = store.getState()[‘features/base/conference’];
    conference.unMuteParticipant(action.id, action.mediaType);
    break;
    }

Step 3 : Changes to be done in lib jitsi meet

Added new event for VIDEO_UNMUTED_BY_FOCUS → XMPPEvents.js

VIDEO_UNMUTED_BY_FOCUS: 'xmpp.video_unmuted_by_focus',

Created event listener for VIDEO_UNMUTED_BY_FOCUS → JitsiConferenceEventManager.js

//unmute-video
	chatRoom.addListener(XMPPEvents.VIDEO_UNMUTED_BY_FOCUS,
			actor => {
				// TODO: Add a way to differentiate between commands which caused
				// us to mute and those that did not change our state (i.e. we were
				// already muted).
				Statistics.sendAnalytics(createRemotelyMutedEvent(MediaType.VIDEO));

				conference.mutedVideoByFocusActor = actor;

				// set isVideoMutedByFocus when setVideoMute Promise ends
				conference.rtc.setVideoMute(false).then(
					() => {
						conference.isVideoMutedByFocus = false;
						conference.mutedVideoByFocusActor = null;
					})
					.catch(
						error => {
							conference.mutedVideoByFocusActor = null;
							logger.warn(
								'Error while video unmuting due to focus request', error);
						});
			}
		);

Added prototype for unMuteParticipant → JitsiConference.js

JitsiConference.prototype.unMuteParticipant = function(id, mediaType) {
    
	const UnmuteMediaType = mediaType ? mediaType : MediaType.AUDIO;

    if (UnmuteMediaType !== MediaType.AUDIO && UnmuteMediaType !== MediaType.VIDEO) {
        logger.error(`Unsupported media type: ${UnmuteMediaType}`);

        return;
    }

Added unMuteParticipant method and changed onMute method → ChatRoom.js

unMuteParticipant(jid, mute, mediaType) {
        logger.info('set mute', mute);
       const iqToFocus = $iq(
            { to: this.focusMucJid,
                type: 'set' })
            .c('mute', {
                xmlns: `http://jitsi.org/jitmeet/${mediaType}`,
                jid
            })
            .t(mute.toString())
           .up();

        this.connection.sendIQ(
           iqToFocus,
            result => logger.log('set mute', result),
            error => logger.log('set mute error', error));
   }


 onMuteVideo(iq) {
        const from = iq.getAttribute('from');

        if (from !== this.focusMucJid) {
            logger.warn('Ignored mute from non focus peer');

            return;
        }
        const mute = $(iq).find('mute');

        if (mute.length && mute.text() === 'true') {
            this.eventEmitter.emit(XMPPEvents.VIDEO_MUTED_BY_FOCUS, mute.attr('actor'));
        }else if (mute.length && mute.text() === 'false') { // added unmute condition
		this.eventEmitter.emit(XMPPEvents.VIDEO_UNMUTED_BY_FOCUS, mute.attr('actor'));
		}else {
            // XXX Why do we support anything but muting? Why do we encode the
            // value in the text of the element? Why do we use a separate XML
            // namespace?
            logger.warn('Ignoring a mute request which does not explicitly '
                + 'specify a positive mute command.');
        }
    }

Result :

Problem : Moderator can mute/unmute mic of the participant. But it’s not working for cam. this log error noted in the js console. Now, the moderator can’t disable the participant’s camera too. Did anyone implement this feature? pls help

image

Complete repo

inspired by @bayraktarulku raktarulku 's work GitHub - bayraktarulku/jitsi-meet-dev: This archive is about improvements to the open source jitsi meet. The steps required to control the remote user's microphone are explained.

We are activity working on this and will hit unstable in a week or so.

1 Like

Any updates on it?

The PR is merged and everything is in unstable, there are few bugs though we will be addressing soon. You can give it a try and report problems so we can fix it

Oh that’s great, i will try