From 3ce1c610101785c1daf196b0d25d63a423ac4e89 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sat, 18 Nov 2023 22:12:15 +0100 Subject: [PATCH] [mirotalksfu] - add more moderator options, update dep --- app/src/Room.js | 23 +++++++--- app/src/Server.js | 12 +++++- package.json | 6 +-- public/css/Room.css | 4 ++ public/js/LocalStorage.js | 7 ++- public/js/Room.js | 54 +++++++++++++++++++---- public/js/RoomClient.js | 91 ++++++++++++++++++++++++++++++++------- public/js/Rules.js | 20 +++++++-- public/views/Room.html | 60 ++++++++++++++++++++++++++ 9 files changed, 237 insertions(+), 40 deletions(-) diff --git a/app/src/Room.js b/app/src/Room.js index c2791e6f..4481bf8f 100644 --- a/app/src/Room.js +++ b/app/src/Room.js @@ -17,8 +17,11 @@ module.exports = class Room { this._roomPassword = null; this._hostOnlyRecording = false; this._moderator = { - start_audio_muted: false, - start_video_hidden: false, + audio_start_muted: false, + video_start_hidden: false, + audio_cant_unmute: false, + video_cant_unhide: false, + screen_cant_share: false, }; this.survey = config.survey; this.redirect = config.redirect; @@ -109,11 +112,19 @@ module.exports = class Room { updateRoomModerator(data) { log.debug('Update room moderator', data); switch (data.type) { - case 'audio': - this._moderator.start_audio_muted = data.status; + case 'audio_start_muted': + this._moderator.audio_start_muted = data.status; + break; + case 'video_start_hidden': + this._moderator.video_start_hidden = data.status; + case 'audio_cant_unmute': + this._moderator.audio_cant_unmute = data.status; + break; + case 'video_cant_unhide': + this._moderator.video_cant_unhide = data.status; + case 'screen_cant_share': + this._moderator.screen_cant_share = data.status; break; - case 'video': - this._moderator.start_video_hidden = data.status; default: break; } diff --git a/app/src/Server.js b/app/src/Server.js index 79a9dafd..510bed8a 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -40,7 +40,7 @@ dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.2.2 + * @version 1.2.3 * */ @@ -758,6 +758,16 @@ function startServer() { const room = roomList.get(socket.room_id); room.updateRoomModerator(data); + + switch (data.type) { + case 'audio_cant_unmute': + case 'video_cant_unhide': + case 'screen_cant_share': + room.broadCast(socket.id, 'updateRoomModerator', data); + break; + default: + break; + } }); socket.on('fileInfo', (dataObject) => { diff --git a/package.json b/package.json index b11b665d..5eff4771 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.2.2", + "version": "1.2.3", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -44,10 +44,10 @@ "crypto-js": "4.2.0", "express": "4.18.2", "httpolyglot": "0.1.2", - "mediasoup": "3.13.1", + "mediasoup": "3.13.2", "mediasoup-client": "3.7.0", "ngrok": "^4.3.3", - "openai": "^4.18.0", + "openai": "^4.19.0", "qs": "6.11.2", "socket.io": "4.7.2", "swagger-ui-express": "5.0.0", diff --git a/public/css/Room.css b/public/css/Room.css index f3031ca3..9eed9a4b 100644 --- a/public/css/Room.css +++ b/public/css/Room.css @@ -881,6 +881,10 @@ button:hover { transform: var(--btns-hover-scale); } +.red { + color: red !important; +} + /*-------------------------------------------------------------- # Lobby users list --------------------------------------------------------------*/ diff --git a/public/js/LocalStorage.js b/public/js/LocalStorage.js index 0ea063f8..fa735811 100644 --- a/public/js/LocalStorage.js +++ b/public/js/LocalStorage.js @@ -20,8 +20,11 @@ class LocalStorage { show_chat_on_msg: true, // show chat on new message show_transcript_on_msg: true, // show transcript on new message speech_in_msg: false, // speech incoming message - moderator_audio_muted: false, // Everyone starts muted in the room - moderator_video_hidden: false, // Everyone starts hidden in the room + moderator_audio_start_muted: false, // Everyone starts muted in the room + moderator_video_start_hidden: false, // Everyone starts hidden in the room + moderator_audio_cant_unmute: false, // Everyone can't unmute themselves + moderator_video_cant_unhide: false, // Everyone can't unhide themselves + moderator_screen_cant_share: false, // Everyone can't share screen mic_auto_gain_control: false, mic_echo_cancellations: true, mic_noise_suppression: true, diff --git a/public/js/Room.js b/public/js/Room.js index 97118304..5ce79864 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.2.2 + * @version 1.2.3 * */ @@ -1299,6 +1299,10 @@ function handleButtons() { rc.updatePeerInfo(peer_name, socket.id, 'hand', false); }; startAudioButton.onclick = () => { + const moderator = rc.getModerator(); + if (moderator.audio_cant_unmute) { + return userLog('warning', 'The moderator does not allow you to unmute', 'top-end', 6000); + } if (isPushToTalkActive) return; setAudioButtonsDisabled(true); if (!isEnumerateAudioDevices) initEnumerateAudioDevices(); @@ -1314,6 +1318,10 @@ function handleButtons() { // rc.pauseProducer(RoomClient.mediaType.audio); }; startVideoButton.onclick = () => { + const moderator = rc.getModerator(); + if (moderator.video_cant_unhide) { + return userLog('warning', 'The moderator does not allow you to unhide', 'top-end', 6000); + } setVideoButtonsDisabled(true); if (!isEnumerateVideoDevices) initEnumerateVideoDevices(); if (isHideMeActive) rc.handleHideMe(); @@ -1327,6 +1335,10 @@ function handleButtons() { // rc.pauseProducer(RoomClient.mediaType.video); }; startScreenButton.onclick = () => { + const moderator = rc.getModerator(); + if (moderator.screen_cant_share) { + return userLog('warning', 'The moderator does not allow you to share the screen', 'top-end', 6000); + } if (isHideMeActive) rc.handleHideMe(); rc.produce(RoomClient.mediaType.screen); }; @@ -1801,18 +1813,42 @@ function handleSelects() { }; // room moderator rules switchEveryoneMute.onchange = (e) => { - const startMuted = e.currentTarget.checked; - rc.updateRoomModerator({ type: 'audio', status: startMuted }); - rc.roomMessage('mod_audio', startMuted); - lsSettings.moderator_audio_muted = startMuted; + const audioStartMuted = e.currentTarget.checked; + rc.updateRoomModerator({ type: 'audio_start_muted', status: audioStartMuted }); + rc.roomMessage('audio_start_muted', audioStartMuted); + lsSettings.moderator_audio_start_muted = audioStartMuted; lS.setSettings(lsSettings); e.target.blur(); }; switchEveryoneHidden.onchange = (e) => { - const startHidden = e.currentTarget.checked; - rc.updateRoomModerator({ type: 'video', status: startHidden }); - rc.roomMessage('mod_video', startHidden); - lsSettings.moderator_video_hidden = startHidden; + const videoStartHidden = e.currentTarget.checked; + rc.updateRoomModerator({ type: 'video_start_hidden', status: videoStartHidden }); + rc.roomMessage('video_start_hidden', videoStartHidden); + lsSettings.moderator_video_start_hidden = videoStartHidden; + lS.setSettings(lsSettings); + e.target.blur(); + }; + switchEveryoneCantUnmute.onchange = (e) => { + const audioCantUnmute = e.currentTarget.checked; + rc.updateRoomModerator({ type: 'audio_cant_unmute', status: audioCantUnmute }); + rc.roomMessage('audio_cant_unmute', audioCantUnmute); + lsSettings.moderator_audio_cant_unmute = audioCantUnmute; + lS.setSettings(lsSettings); + e.target.blur(); + }; + switchEveryoneCantUnhide.onchange = (e) => { + const videoCantUnhide = e.currentTarget.checked; + rc.updateRoomModerator({ type: 'video_cant_unhide', status: videoCantUnhide }); + rc.roomMessage('video_cant_unhide', videoCantUnhide); + lsSettings.moderator_video_cant_unhide = videoCantUnhide; + lS.setSettings(lsSettings); + e.target.blur(); + }; + switchEveryoneCantShareScreen.onchange = (e) => { + const screenCantShare = e.currentTarget.checked; + rc.updateRoomModerator({ type: 'screen_cant_share', status: screenCantShare }); + rc.roomMessage('screen_cant_share', screenCantShare); + lsSettings.moderator_screen_cant_share = screenCantShare; lS.setSettings(lsSettings); e.target.blur(); }; diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 91f0448e..fda65764 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.2.2 + * @version 1.2.3 * */ @@ -160,8 +160,13 @@ class RoomClient { this.peer_info = peer_info; // Moderator - this.start_muted = false; - this.start_hidden = false; + this._moderator = { + audio_start_muted: false, + video_start_hidden: false, + audio_cant_unmute: false, + video_cant_unhide: false, + screen_cant_share: false, + }; this.isAudioAllowed = isAudioAllowed; this.isVideoAllowed = isVideoAllowed; @@ -370,17 +375,21 @@ class RoomClient { : this.event(_EVENTS.hostOnlyRecordingOff); // Handle Room moderator rules - if (!isRulesActive || !isPresenter) { + if (room.moderator && (!isRulesActive || !isPresenter)) { console.log('07.2 ----> MODERATOR', room.moderator); - this.start_muted = room.moderator && room.moderator.start_audio_muted; - this.start_hidden = room.moderator && room.moderator.start_video_hidden; - if (this.start_muted && this.start_hidden) { + this._moderator.audio_start_muted = room.moderator.audio_start_muted; + this._moderator.video_start_hidden = room.moderator.video_start_hidden; + this._moderator.audio_cant_unmute = room.moderator.audio_cant_unmute; + this._moderator.video_cant_unhide = room.moderator.video_cant_unhide; + this._moderator.screen_cant_share = room.moderator.screen_cant_share; + // + if (this._moderator.audio_start_muted && this._moderator.video_start_hidden) { this.userLog('warning', 'The Moderator disabled your audio and video', 'top-end'); } - if (this.start_muted && !this.start_hidden) { + if (this._moderator.audio_start_muted && !this._moderator.video_start_hidden) { this.userLog('warning', 'The Moderator disabled your audio', 'top-end'); } - if (!this.start_muted && this.start_hidden) { + if (!this._moderator.audio_start_muted && this._moderator.video_start_hidden) { this.userLog('warning', 'The Moderator disabled your video', 'top-end'); } } @@ -740,6 +749,14 @@ class RoomClient { }.bind(this), ); + this.socket.on( + 'updateRoomModerator', + function (data) { + console.log('Update room moderator', data); + this.handleUpdateRoomModerator(data); + }.bind(this), + ); + this.socket.on( 'recordingAction', function (data) { @@ -828,7 +845,7 @@ class RoomClient { async startLocalMedia() { console.log('08 ----> Start local media'); - if (this.isAudioAllowed && !this.start_muted) { + if (this.isAudioAllowed && !this._moderator.audio_start_muted) { console.log('09 ----> Start audio media'); this.produce(mediaType.audio, microphoneSelect.value); } else { @@ -838,7 +855,7 @@ class RoomClient { this.event(_EVENTS.stopAudio); this.updatePeerInfo(this.peer_name, this.peer_id, 'audio', false); } - if (this.isVideoAllowed && !this.start_hidden) { + if (this.isVideoAllowed && !this._moderator.video_start_hidden) { console.log('10 ----> Start video media'); this.produce(mediaType.video, videoSelect.value); } else { @@ -849,7 +866,7 @@ class RoomClient { this.event(_EVENTS.stopVideo); this.updatePeerInfo(this.peer_name, this.peer_id, 'video', false); } - if (this.joinRoomWithScreen) { + if (this.joinRoomWithScreen && !this._moderator.screen_cant_share) { console.log('08 ----> Start Screen media'); this.produce(mediaType.screen, null, false, true); } @@ -1530,7 +1547,7 @@ class RoomClient { this.myAudioEl = elem; this.localAudioEl.appendChild(elem); this.attachMediaStream(elem, stream, type, 'Producer'); - if (this.isAudioAllowed && !this.start_muted && !speakerSelect.disabled) { + if (this.isAudioAllowed && !this._moderator.audio_start_muted && !speakerSelect.disabled) { this.attachSinkId(elem, speakerSelect.value); } console.log('[addProducer] audio-element-count', this.localAudioEl.childElementCount); @@ -4583,12 +4600,33 @@ class RoomClient { 'top-end', ); break; - case 'mod_audio': + case 'audio_start_muted': this.userLog('info', `${icons.moderator} Moderator: everyone starts muted ${status}`, 'top-end'); break; - case 'mod_video': + case 'video_start_hidden': this.userLog('info', `${icons.moderator} Moderator: everyone starts hidden ${status}`, 'top-end'); break; + case 'audio_cant_unmute': + this.userLog( + 'info', + `${icons.moderator} Moderator: everyone can't unmute themselves ${status}`, + 'top-end', + ); + break; + case 'video_cant_unhide': + this.userLog( + 'info', + `${icons.moderator} Moderator: everyone can't unhide themselves ${status}`, + 'top-end', + ); + break; + case 'screen_cant_share': + this.userLog( + 'info', + `${icons.moderator} Moderator: everyone can't share the screen ${status}`, + 'top-end', + ); + break; default: break; } @@ -5395,6 +5433,29 @@ class RoomClient { } } + handleUpdateRoomModerator(data) { + switch (data.type) { + case 'audio_cant_unmute': + this._moderator.audio_cant_unmute = data.status; + rc.roomMessage('audio_cant_unmute', data.status); + break; + case 'video_cant_unhide': + this._moderator.video_cant_unhide = data.status; + rc.roomMessage('video_cant_unhide', data.status); + case 'screen_cant_share': + this._moderator.screen_cant_share = data.status; + rc.roomMessage('screen_cant_share', data.status); + break; + default: + break; + } + } + + getModerator() { + console.log('Get Moderator', this._moderator); + return this._moderator; + } + // #################################################### // UPDATE PEER INFO // #################################################### diff --git a/public/js/Rules.js b/public/js/Rules.js index 597d3812..8ab8ee96 100644 --- a/public/js/Rules.js +++ b/public/js/Rules.js @@ -83,6 +83,9 @@ function handleRules(isPresenter) { console.log('06.1 ----> IsPresenter: ' + isPresenter); if (!isRulesActive) return; if (!isPresenter) { + // ################################## + // GUEST + // ################################## BUTTONS.participantsList.saveInfoButton = false; BUTTONS.settings.lockRoomButton = false; BUTTONS.settings.unlockRoomButton = false; @@ -97,6 +100,9 @@ function handleRules(isPresenter) { BUTTONS.whiteboard.whiteboardLockButton = false; //... } else { + // ################################## + // PRESENTER + // ################################## BUTTONS.participantsList.saveInfoButton = true; BUTTONS.settings.lockRoomButton = !isRoomLocked; BUTTONS.settings.unlockRoomButton = isRoomLocked; @@ -124,10 +130,16 @@ function handleRules(isPresenter) { switchHostOnlyRecording.checked = hostOnlyRecording; rc.roomAction(hostOnlyRecording ? 'hostOnlyRecordingOn' : 'hostOnlyRecordingOff', true, false); // Room moderator - switchEveryoneMute.checked = lsSettings.moderator_audio_muted; - switchEveryoneHidden.checked = lsSettings.moderator_video_hidden; - rc.updateRoomModerator({ type: 'audio', status: switchEveryoneMute.checked }); - rc.updateRoomModerator({ type: 'video', status: switchEveryoneHidden.checked }); + switchEveryoneMute.checked = lsSettings.moderator_audio_start_muted; + switchEveryoneHidden.checked = lsSettings.moderator_video_start_hidden; + switchEveryoneCantUnmute.checked = lsSettings.moderator_audio_cant_unmute; + switchEveryoneCantUnhide.checked = lsSettings.moderator_video_cant_unhide; + switchEveryoneCantShareScreen.checked = lsSettings.moderator_screen_cant_share; + rc.updateRoomModerator({ type: 'audio_start_muted', status: switchEveryoneMute.checked }); + rc.updateRoomModerator({ type: 'video_start_hidden', status: switchEveryoneHidden.checked }); + rc.updateRoomModerator({ type: 'audio_cant_unmute', status: switchEveryoneCantUnmute.checked }); + rc.updateRoomModerator({ type: 'video_cant_unhide', status: switchEveryoneCantUnhide.checked }); + rc.updateRoomModerator({ type: 'screen_cant_share', status: switchEveryoneCantShareScreen.checked }); } // main. settings... BUTTONS.settings.lockRoomButton ? show(lockRoomButton) : hide(lockRoomButton); diff --git a/public/views/Room.html b/public/views/Room.html index 7f4c9f67..2bf2829e 100644 --- a/public/views/Room.html +++ b/public/views/Room.html @@ -593,6 +593,7 @@ access to use this app.

Moderator options

+
+ + + + + + + + + + + + + + +
@@ -625,6 +626,65 @@ access to use this app.
+
+
+
+ +

Everyone can't unmute themselves

+
+
+
+ +
+
+
+ +

Everyone can't unhide themselves

+
+
+
+ +
+
+
+ +

Everyone can't share screen

+
+
+
+ +
+