From abb44a7949e5bd33a04da086c2b13a42736270f5 Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Fri, 5 Feb 2021 21:42:52 +0000 Subject: [PATCH 01/14] Set default cursorInterval to 150ms (was 40ms) --- bigbluebutton-html5/private/config/settings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-html5/private/config/settings.yml b/bigbluebutton-html5/private/config/settings.yml index 386026b025..3149cd1087 100755 --- a/bigbluebutton-html5/private/config/settings.yml +++ b/bigbluebutton-html5/private/config/settings.yml @@ -376,7 +376,7 @@ public: role_viewer: VIEWER whiteboard: annotationsQueueProcessInterval: 60 - cursorInterval: 40 + cursorInterval: 150 annotations: status: start: DRAW_START From 5af1f1cd8187117db197c310838e6573705da9fe Mon Sep 17 00:00:00 2001 From: basisbit Date: Mon, 8 Feb 2021 15:44:01 +0100 Subject: [PATCH 02/14] Enable video-pagination and cameraQualityThresholds by default One of the main issues in 2.2.x problem reports currently in the wild in social media and in the bbb admin groups seems to be that people turn a couple of webcams on and the clients or the server already can't handle it any more. In most cases, enabling video-pagination for mobile devices and also cameraQualityThresholds already "solves" the problem and makes it possible for much more students to attend online-class as well as raise acceptance of using BBB instead of other commercial services. Even after promoting these new settings for weeks, many BBB operators still don't know of them and are surprised and happy once they enable it. This change contians rather high values so that admins see that these features exist, but typical use cases which might not want video-pagination enabled (typical 28people school class) are still not "annoyed". --- bigbluebutton-html5/private/config/settings.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bigbluebutton-html5/private/config/settings.yml b/bigbluebutton-html5/private/config/settings.yml index dff1ce275c..a6cf299118 100755 --- a/bigbluebutton-html5/private/config/settings.yml +++ b/bigbluebutton-html5/private/config/settings.yml @@ -197,7 +197,7 @@ public: # profile: a camera profile id from the cameraProfiles configuration array # that will be applied to all cameras when threshold is hit cameraQualityThresholds: - enabled: false + enabled: true thresholds: - threshold: 8 profile: low-u8 @@ -213,19 +213,19 @@ public: profile: low-u30 pagination: # whether to globally enable or disable pagination. - enabled: false + enabled: true # how long (in ms) the negotiation will be debounced after a page change. pageChangeDebounceTime: 2500 # video page sizes for DESKTOP endpoints. It stands for the number of SUBSCRIBER streams. # PUBLISHERS aren't accounted for . # A page size of 0 (zero) means that the page size is unlimited (disabled). desktopPageSizes: - moderator: 0 - viewer: 5 + moderator: 50 + viewer: 25 # video page sizes for MOBILE endpoints mobilePageSizes: - moderator: 2 - viewer: 2 + moderator: 8 + viewer: 4 pingPong: clearUsersInSeconds: 180 pongTimeInSeconds: 15 From d5c9cc38e731598fc409a22b37f796dc5e215230 Mon Sep 17 00:00:00 2001 From: basisbit Date: Mon, 8 Feb 2021 18:13:26 +0100 Subject: [PATCH 03/14] disable video-pagination for desktop view users by default also adjusted moderator mobile video-pagination as suggested by @prlanzarin --- bigbluebutton-html5/private/config/settings.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bigbluebutton-html5/private/config/settings.yml b/bigbluebutton-html5/private/config/settings.yml index a6cf299118..4d7c9c91fa 100755 --- a/bigbluebutton-html5/private/config/settings.yml +++ b/bigbluebutton-html5/private/config/settings.yml @@ -220,11 +220,11 @@ public: # PUBLISHERS aren't accounted for . # A page size of 0 (zero) means that the page size is unlimited (disabled). desktopPageSizes: - moderator: 50 - viewer: 25 + moderator: 0 + viewer: 0 # video page sizes for MOBILE endpoints mobilePageSizes: - moderator: 8 + moderator: 6 viewer: 4 pingPong: clearUsersInSeconds: 180 From 2eb8abcba917868264fbf36bc3cc32a9a280c77b Mon Sep 17 00:00:00 2001 From: Joao Siebel Date: Tue, 9 Feb 2021 09:30:09 -0300 Subject: [PATCH 04/14] Clear guestUsers, voiceCallStates and whiteboard-multi-user collections on meeting end --- .../server/modifiers/clearGuestUsers.js | 26 +++++++++++++++++++ .../server/modifiers/meetingHasEnded.js | 4 +++ .../server/modifiers/clearVoiceCallStates.js | 2 +- .../modifiers/clearWhiteboardMultiUser.js | 26 +++++++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 bigbluebutton-html5/imports/api/guest-users/server/modifiers/clearGuestUsers.js create mode 100644 bigbluebutton-html5/imports/api/whiteboard-multi-user/server/modifiers/clearWhiteboardMultiUser.js diff --git a/bigbluebutton-html5/imports/api/guest-users/server/modifiers/clearGuestUsers.js b/bigbluebutton-html5/imports/api/guest-users/server/modifiers/clearGuestUsers.js new file mode 100644 index 0000000000..8ce5cd1a94 --- /dev/null +++ b/bigbluebutton-html5/imports/api/guest-users/server/modifiers/clearGuestUsers.js @@ -0,0 +1,26 @@ +import GuestUsers from '/imports/api/guest-users'; +import Logger from '/imports/startup/server/logger'; + +export default function clearGuestUsers(meetingId) { + if (meetingId) { + try { + const numberAffected = GuestUsers.remove({ meetingId }); + + if (numberAffected) { + Logger.info(`Cleared GuestUsers in (${meetingId})`); + } + } catch (err) { + Logger.info(`Error on clearing GuestUsers in (${meetingId}). ${err}`); + } + } else { + try { + const numberAffected = GuestUsers.remove({}); + + if (numberAffected) { + Logger.info('Cleared GuestUsers in all meetings'); + } + } catch (err) { + Logger.error(`Error on clearing GuestUsers in all meetings. ${err}`); + } + } +} diff --git a/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js b/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js index d4d1132ce4..3f7cc292df 100755 --- a/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js +++ b/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js @@ -7,6 +7,7 @@ import { removeCursorStreamer } from '/imports/api/cursor/server/streamer'; import clearUsers from '/imports/api/users/server/modifiers/clearUsers'; import clearUsersSettings from '/imports/api/users-settings/server/modifiers/clearUsersSettings'; import clearGroupChat from '/imports/api/group-chat/server/modifiers/clearGroupChat'; +import clearGuestUsers from '/imports/api/guest-users/server/modifiers/clearGuestUsers'; import clearBreakouts from '/imports/api/breakouts/server/modifiers/clearBreakouts'; import clearAnnotations from '/imports/api/annotations/server/modifiers/clearAnnotations'; import clearSlides from '/imports/api/slides/server/modifiers/clearSlides'; @@ -21,6 +22,7 @@ import clearLocalSettings from '/imports/api/local-settings/server/modifiers/cle import clearRecordMeeting from './clearRecordMeeting'; import clearVoiceCallStates from '/imports/api/voice-call-states/server/modifiers/clearVoiceCallStates'; import clearVideoStreams from '/imports/api/video-streams/server/modifiers/clearVideoStreams'; +import clearWhiteboardMultiUser from '/imports/api/whiteboard-multi-user/server/modifiers/clearWhiteboardMultiUser'; import BannedUsers from '/imports/api/users/server/store/bannedUsers'; import Metrics from '/imports/startup/server/metrics'; @@ -31,6 +33,7 @@ export default function meetingHasEnded(meetingId) { return Meetings.remove({ meetingId }, () => { clearCaptions(meetingId); clearGroupChat(meetingId); + clearGuestUsers(meetingId); clearPresentationPods(meetingId); clearBreakouts(meetingId); clearPolls(meetingId); @@ -46,6 +49,7 @@ export default function meetingHasEnded(meetingId) { clearRecordMeeting(meetingId); clearVoiceCallStates(meetingId); clearVideoStreams(meetingId); + clearWhiteboardMultiUser(meetingId); BannedUsers.delete(meetingId); Metrics.removeMeeting(meetingId); diff --git a/bigbluebutton-html5/imports/api/voice-call-states/server/modifiers/clearVoiceCallStates.js b/bigbluebutton-html5/imports/api/voice-call-states/server/modifiers/clearVoiceCallStates.js index 11fce2e4c5..0329bdd825 100644 --- a/bigbluebutton-html5/imports/api/voice-call-states/server/modifiers/clearVoiceCallStates.js +++ b/bigbluebutton-html5/imports/api/voice-call-states/server/modifiers/clearVoiceCallStates.js @@ -1,5 +1,5 @@ import Logger from '/imports/startup/server/logger'; -import VoiceCallStates from '/imports/api/voice-users'; +import VoiceCallStates from '/imports/api/voice-call-states'; export default function clearVoiceCallStates(meetingId) { if (meetingId) { diff --git a/bigbluebutton-html5/imports/api/whiteboard-multi-user/server/modifiers/clearWhiteboardMultiUser.js b/bigbluebutton-html5/imports/api/whiteboard-multi-user/server/modifiers/clearWhiteboardMultiUser.js new file mode 100644 index 0000000000..9875689660 --- /dev/null +++ b/bigbluebutton-html5/imports/api/whiteboard-multi-user/server/modifiers/clearWhiteboardMultiUser.js @@ -0,0 +1,26 @@ +import Logger from '/imports/startup/server/logger'; +import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user'; + +export default function clearWhiteboardMultiUser(meetingId) { + if (meetingId) { + try { + const numberAffected = WhiteboardMultiUser.remove({ meetingId }); + + if (numberAffected) { + Logger.info(`Cleared WhiteboardMultiUser (${meetingId})`); + } + } catch (err) { + Logger.info(`Error clearing WhiteboardMultiUser (${meetingId}). ${err}`); + } + } else { + try { + const numberAffected = WhiteboardMultiUser.remove({}); + + if (numberAffected) { + Logger.info('Cleared WhiteboardMultiUser (all)'); + } + } catch (err) { + Logger.info(`Error clearing WhiteboardMultiUser (all). ${err}`); + } + } +} From 6b3c97037fd87a008df3f9142b86f32d171dc8e5 Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Fri, 5 Feb 2021 21:42:52 +0000 Subject: [PATCH 05/14] Clear meeting-time-remaining collection --- .../modifiers/clearMeetingTimeRemaining.js | 26 +++++++++++++++++++ .../server/modifiers/meetingHasEnded.js | 2 ++ 2 files changed, 28 insertions(+) create mode 100644 bigbluebutton-html5/imports/api/meetings/server/modifiers/clearMeetingTimeRemaining.js diff --git a/bigbluebutton-html5/imports/api/meetings/server/modifiers/clearMeetingTimeRemaining.js b/bigbluebutton-html5/imports/api/meetings/server/modifiers/clearMeetingTimeRemaining.js new file mode 100644 index 0000000000..9be8b4abc3 --- /dev/null +++ b/bigbluebutton-html5/imports/api/meetings/server/modifiers/clearMeetingTimeRemaining.js @@ -0,0 +1,26 @@ +import { MeetingTimeRemaining } from '/imports/api/meetings'; +import Logger from '/imports/startup/server/logger'; + +export default function clearMeetingTimeRemaining(meetingId) { + if (meetingId) { + try { + const numberAffected = MeetingTimeRemaining.remove({ meetingId }); + + if (numberAffected) { + Logger.info(`Cleared MeetingTimeRemaining in (${meetingId})`); + } + } catch (err) { + Logger.info(`Error on clearing MeetingTimeRemaining in (${meetingId}). ${err}`); + } + } else { + try { + const numberAffected = MeetingTimeRemaining.remove({}); + + if (numberAffected) { + Logger.info('Cleared MeetingTimeRemaining in all meetings'); + } + } catch (err) { + Logger.error(`Error on clearing MeetingTimeRemaining in all meetings. ${err}`); + } + } +} diff --git a/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js b/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js index 3f7cc292df..255a97a453 100755 --- a/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js +++ b/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js @@ -18,6 +18,7 @@ import clearVoiceUsers from '/imports/api/voice-users/server/modifiers/clearVoic import clearUserInfo from '/imports/api/users-infos/server/modifiers/clearUserInfo'; import clearNote from '/imports/api/note/server/modifiers/clearNote'; import clearNetworkInformation from '/imports/api/network-information/server/modifiers/clearNetworkInformation'; +import clearMeetingTimeRemaining from '/imports/api/meetings/server/modifiers/clearMeetingTimeRemaining'; import clearLocalSettings from '/imports/api/local-settings/server/modifiers/clearLocalSettings'; import clearRecordMeeting from './clearRecordMeeting'; import clearVoiceCallStates from '/imports/api/voice-call-states/server/modifiers/clearVoiceCallStates'; @@ -46,6 +47,7 @@ export default function meetingHasEnded(meetingId) { clearNote(meetingId); clearNetworkInformation(meetingId); clearLocalSettings(meetingId); + clearMeetingTimeRemaining(meetingId); clearRecordMeeting(meetingId); clearVoiceCallStates(meetingId); clearVideoStreams(meetingId); From 0e792031191620d8eb9479fb22a1ce9a7d46262e Mon Sep 17 00:00:00 2001 From: Joao Siebel Date: Tue, 9 Feb 2021 13:44:49 -0300 Subject: [PATCH 06/14] Clear screenshare collection when meeting has ended while screensharing --- .../imports/api/meetings/server/modifiers/meetingHasEnded.js | 2 ++ .../api/screenshare/server/modifiers/clearScreenshare.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js b/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js index 255a97a453..bf304c43af 100755 --- a/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js +++ b/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js @@ -16,6 +16,7 @@ import clearCaptions from '/imports/api/captions/server/modifiers/clearCaptions' import clearPresentationPods from '/imports/api/presentation-pods/server/modifiers/clearPresentationPods'; import clearVoiceUsers from '/imports/api/voice-users/server/modifiers/clearVoiceUsers'; import clearUserInfo from '/imports/api/users-infos/server/modifiers/clearUserInfo'; +import clearScreenshare from '/imports/api/screenshare/server/modifiers/clearScreenshare'; import clearNote from '/imports/api/note/server/modifiers/clearNote'; import clearNetworkInformation from '/imports/api/network-information/server/modifiers/clearNetworkInformation'; import clearMeetingTimeRemaining from '/imports/api/meetings/server/modifiers/clearMeetingTimeRemaining'; @@ -52,6 +53,7 @@ export default function meetingHasEnded(meetingId) { clearVoiceCallStates(meetingId); clearVideoStreams(meetingId); clearWhiteboardMultiUser(meetingId); + clearScreenshare(meetingId); BannedUsers.delete(meetingId); Metrics.removeMeeting(meetingId); diff --git a/bigbluebutton-html5/imports/api/screenshare/server/modifiers/clearScreenshare.js b/bigbluebutton-html5/imports/api/screenshare/server/modifiers/clearScreenshare.js index 0679730481..2f365d99ed 100644 --- a/bigbluebutton-html5/imports/api/screenshare/server/modifiers/clearScreenshare.js +++ b/bigbluebutton-html5/imports/api/screenshare/server/modifiers/clearScreenshare.js @@ -7,6 +7,8 @@ export default function clearScreenshare(meetingId, screenshareConf) { if (meetingId && screenshareConf) { numberAffected = Screenshare.remove({ meetingId, 'screenshare.screenshareConf': screenshareConf }); + } else if (meetingId) { + numberAffected = Screenshare.remove({ meetingId }); } else { numberAffected = Screenshare.remove({}); } From 5f683809cde1563fc59e778364180933b3f5cf1c Mon Sep 17 00:00:00 2001 From: Ghazi Triki Date: Tue, 9 Feb 2021 19:03:54 +0100 Subject: [PATCH 07/14] Make sure checksum validation is done first in join API and display an error without redirection in failure case. --- .../web/controllers/ApiController.groovy | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy index 61d5d76220..b136854f8c 100755 --- a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy +++ b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy @@ -209,7 +209,12 @@ class ApiController { // BEGIN - backward compatibility if (StringUtils.isEmpty(params.checksum)) { - invalid("checksumError", "You did not pass the checksum security check", REDIRECT_RESPONSE) + invalid("checksumError", "You did not pass the checksum security check") + return + } + + if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) { + invalid("checksumError", "You did not pass the checksum security check") return } @@ -241,11 +246,6 @@ class ApiController { return } - if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) { - invalid("checksumError", "You did not pass the checksum security check", REDIRECT_RESPONSE) - return - } - // END - backward compatibility // Do we have a checksum? If none, complain. From 7216619811eea323bf967ace6dc70d8449a610d9 Mon Sep 17 00:00:00 2001 From: Lucas Zawacki Date: Tue, 9 Feb 2021 15:24:21 -0300 Subject: [PATCH 08/14] Don't validate insecure http urls for external video to prevent browser errors --- .../imports/ui/components/external-video-player/service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-html5/imports/ui/components/external-video-player/service.js b/bigbluebutton-html5/imports/ui/components/external-video-player/service.js index 66bd3ea7cc..9de4de3c7a 100644 --- a/bigbluebutton-html5/imports/ui/components/external-video-player/service.js +++ b/bigbluebutton-html5/imports/ui/components/external-video-player/service.js @@ -11,7 +11,7 @@ import ReactPlayer from 'react-player'; import Panopto from './custom-players/panopto'; const isUrlValid = (url) => { - return ReactPlayer.canPlay(url) || Panopto.canPlay(url); + return /^https.*$/.test(url) && (ReactPlayer.canPlay(url) || Panopto.canPlay(url)); } const startWatching = (url) => { From b7216dd1007f6845f1527e74a34f4b9478c46cb7 Mon Sep 17 00:00:00 2001 From: Mario Jr Date: Thu, 11 Feb 2021 23:55:34 -0300 Subject: [PATCH 09/14] Preserve mutestatus when disconnecting/reconnecting microphone After audio reconnection, a muted user would have it's microphone unmuted by default, unless muteOnStart is set to true. This fix this problem. Fixes #9016 --- .../voice-users/server/methods/muteToggle.js | 12 +++++-- .../imports/ui/components/audio/service.js | 35 ++++++++++++++++++- .../ui/services/audio-manager/index.js | 4 ++- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/bigbluebutton-html5/imports/api/voice-users/server/methods/muteToggle.js b/bigbluebutton-html5/imports/api/voice-users/server/methods/muteToggle.js index a91c5cc78e..3f89e94ee9 100644 --- a/bigbluebutton-html5/imports/api/voice-users/server/methods/muteToggle.js +++ b/bigbluebutton-html5/imports/api/voice-users/server/methods/muteToggle.js @@ -6,7 +6,7 @@ import VoiceUsers from '/imports/api/voice-users'; import Meetings from '/imports/api/meetings'; import Logger from '/imports/startup/server/logger'; -export default function muteToggle(uId) { +export default function muteToggle(uId, toggle) { const REDIS_CONFIG = Meteor.settings.private.redis; const CHANNEL = REDIS_CONFIG.channels.toAkkaApps; const EVENT_NAME = 'MuteUserCmdMsg'; @@ -39,10 +39,18 @@ export default function muteToggle(uId) { } } + let _muted; + + if ((toggle === undefined) || (toggle === null)) { + _muted = !muted; + } else { + _muted = !!toggle; + } + const payload = { userId: userToMute, mutedBy: requesterUserId, - mute: !muted, + mute: _muted, }; RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload); diff --git a/bigbluebutton-html5/imports/ui/components/audio/service.js b/bigbluebutton-html5/imports/ui/components/audio/service.js index 965371775d..2848ec87c0 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/service.js +++ b/bigbluebutton-html5/imports/ui/components/audio/service.js @@ -6,10 +6,40 @@ import { makeCall } from '/imports/ui/services/api'; import VoiceUsers from '/imports/api/voice-users'; import logger from '/imports/startup/client/logger'; import { throttle } from 'lodash'; +import Storage from '../../services/storage/session'; const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator; const TOGGLE_MUTE_THROTTLE_TIME = Meteor.settings.public.media.toggleMuteThrottleTime; +const MUTED_KEY = 'muted'; + +const recoverMicState = () => { + const muted = Storage.getItem(MUTED_KEY); + + if ((muted === undefined) || (muted === null)) { + return; + } + + logger.debug({ + logCode: 'audio_recover_mic_state', + }, `Audio recover previous mic state: muted = ${muted}`); + makeCall('toggleVoice', null, muted); +}; + +const audioEventHandler = (event) => { + if (!event) { + return; + } + + switch (event.name) { + case 'started': + recoverMicState(); + break; + default: + break; + } +}; + const init = (messages, intl) => { AudioManager.setAudioMessages(messages, intl); if (AudioManager.initialized) return; @@ -33,7 +63,7 @@ const init = (messages, intl) => { microphoneLockEnforced, }; - AudioManager.init(userData); + AudioManager.init(userData, audioEventHandler); }; const isVoiceUser = () => { @@ -46,6 +76,9 @@ const toggleMuteMicrophone = throttle(() => { const user = VoiceUsers.findOne({ meetingId: Auth.meetingID, intId: Auth.userID, }, { fields: { muted: 1 } }); + + Storage.setItem(MUTED_KEY, !user.muted); + if (user.muted) { logger.info({ logCode: 'audiomanager_unmute_audio', diff --git a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js index 644ed6ee7f..18f1e31f3b 100755 --- a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js +++ b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js @@ -58,13 +58,14 @@ class AudioManager { this.monitor = this.monitor.bind(this); } - init(userData) { + init(userData, audioEventHandler) { this.bridge = new SIPBridge(userData); // no alternative as of 2019-03-08 if (this.useKurento) { this.listenOnlyBridge = new KurentoBridge(userData); } this.userData = userData; this.initialized = true; + this.audioEventHandler = audioEventHandler; } setAudioMessages(messages, intl) { @@ -337,6 +338,7 @@ class AudioManager { window.parent.postMessage({ response: 'joinedAudio' }, '*'); this.notify(this.intl.formatMessage(this.messages.info.JOINED_AUDIO)); logger.info({ logCode: 'audio_joined' }, 'Audio Joined'); + this.audioEventHandler({ name: 'started' }); if (ENABLE_NETWORK_MONITORING) this.monitor(); } } From ba9528ebb1986c5b5612aa8dc1c6a8bbba805d65 Mon Sep 17 00:00:00 2001 From: Pedro Beschorner Marin Date: Wed, 14 Oct 2020 16:55:40 -0300 Subject: [PATCH 10/14] Option to eject voice users with no matching user Reconnects may introduce ghost voice users in a meeting when the client fails to rejoin but the audio connection remains active. While fetching for the voice conference user's status, apps can now check if a voice user has a matching user record. If it doesn't, eject the voice user. --- .../org/bigbluebutton/SystemConfiguration.scala | 1 + .../bigbluebutton/core/apps/voice/VoiceApp.scala | 15 ++++++++++++++- akka-bbb-apps/src/universal/conf/application.conf | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala index caa2b12fa4..24d4cebbfb 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala @@ -46,6 +46,7 @@ trait SystemConfiguration { lazy val voiceConfRecordCodec = Try(config.getString("voiceConf.recordCodec")).getOrElse("wav") lazy val checkVoiceRecordingInterval = Try(config.getInt("voiceConf.checkRecordingInterval")).getOrElse(19) lazy val syncVoiceUsersStatusInterval = Try(config.getInt("voiceConf.syncUserStatusInterval")).getOrElse(43) + lazy val ejectRogueVoiceUsers = Try(config.getBoolean("voiceConf.ejectRogueVoiceUsers")).getOrElse(false) lazy val recordingChapterBreakLengthInMinutes = Try(config.getInt("recording.chapterBreakLengthInMinutes")).getOrElse(0) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp.scala index d2d374d8aa..9a44b785fc 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp.scala @@ -4,7 +4,7 @@ import org.bigbluebutton.LockSettingsUtil import org.bigbluebutton.common2.msgs.{ BbbClientMsgHeader, BbbCommonEnvCoreMsg, BbbCoreEnvelope, ConfVoiceUser, MessageTypes, Routing, UserJoinedVoiceConfToClientEvtMsg, UserJoinedVoiceConfToClientEvtMsgBody, UserLeftVoiceConfToClientEvtMsg, UserLeftVoiceConfToClientEvtMsgBody, UserMutedVoiceEvtMsg, UserMutedVoiceEvtMsgBody } import org.bigbluebutton.core.apps.breakout.BreakoutHdlrHelpers import org.bigbluebutton.core.bus.InternalEventBus -import org.bigbluebutton.core.models.{ VoiceUserState, VoiceUsers } +import org.bigbluebutton.core.models.{ Users2x, VoiceUserState, VoiceUsers } import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter } import org.bigbluebutton.core2.MeetingStatus2x import org.bigbluebutton.core2.message.senders.MsgBuilder @@ -136,6 +136,19 @@ object VoiceApp { // Update the user status to indicate they are still in the voice conference. VoiceUsers.setLastStatusUpdate(liveMeeting.voiceUsers, vu) } + + // Purge voice users that don't have a matching user record + // Avoid this if the meeting is a breakout room since might be real + // voice users participating + if (ejectRogueVoiceUsers && !liveMeeting.props.meetingProp.isBreakout) { + Users2x.findWithIntId(liveMeeting.users2x, cvu.intId) match { + case Some(_) => + case None => + println(s"Ejecting rogue voice user. meetingId=${liveMeeting.props.meetingProp.intId} userId=${cvu.intId}") + val event = MsgBuilder.buildEjectUserFromVoiceConfSysMsg(liveMeeting.props.meetingProp.intId, liveMeeting.props.voiceProp.voiceConf, cvu.voiceUserId) + outGW.send(event) + } + } case None => handleUserJoinedVoiceConfEvtMsg( liveMeeting, diff --git a/akka-bbb-apps/src/universal/conf/application.conf b/akka-bbb-apps/src/universal/conf/application.conf index 5d2568bbd1..267b1f079c 100755 --- a/akka-bbb-apps/src/universal/conf/application.conf +++ b/akka-bbb-apps/src/universal/conf/application.conf @@ -90,6 +90,8 @@ voiceConf { checkRecordingInterval = 23 # Internval seconds to sync voice users status. syncUserStatusInterval = 41 + # Voice users with no matching user record + ejectRogueVoiceUsers = false } recording { From 703505c486da817221680750ed30957d28509b89 Mon Sep 17 00:00:00 2001 From: prlanzarin <4529051+prlanzarin@users.noreply.github.com> Date: Fri, 12 Feb 2021 16:01:44 -0300 Subject: [PATCH 11/14] akka-apps: extend SysConf in VoiceApp To be used with the ejectRogueVoiceUsers config option --- .../scala/org/bigbluebutton/core/apps/voice/VoiceApp.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp.scala index 9a44b785fc..7d6223fa55 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp.scala @@ -1,5 +1,6 @@ package org.bigbluebutton.core.apps.voice +import org.bigbluebutton.SystemConfiguration import org.bigbluebutton.LockSettingsUtil import org.bigbluebutton.common2.msgs.{ BbbClientMsgHeader, BbbCommonEnvCoreMsg, BbbCoreEnvelope, ConfVoiceUser, MessageTypes, Routing, UserJoinedVoiceConfToClientEvtMsg, UserJoinedVoiceConfToClientEvtMsgBody, UserLeftVoiceConfToClientEvtMsg, UserLeftVoiceConfToClientEvtMsgBody, UserMutedVoiceEvtMsg, UserMutedVoiceEvtMsgBody } import org.bigbluebutton.core.apps.breakout.BreakoutHdlrHelpers @@ -9,7 +10,7 @@ import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter } import org.bigbluebutton.core2.MeetingStatus2x import org.bigbluebutton.core2.message.senders.MsgBuilder -object VoiceApp { +object VoiceApp extends SystemConfiguration { def genRecordPath( recordDir: String, From 8f233b74eeee14d056111a208fb85dc523a1af25 Mon Sep 17 00:00:00 2001 From: prlanzarin <4529051+prlanzarin@users.noreply.github.com> Date: Fri, 12 Feb 2021 17:16:32 -0300 Subject: [PATCH 12/14] akka-apps: handle dial-in users in voice user ejection --- .../scala/org/bigbluebutton/core/apps/voice/VoiceApp.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp.scala index 7d6223fa55..4a49d961f1 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp.scala @@ -141,7 +141,8 @@ object VoiceApp extends SystemConfiguration { // Purge voice users that don't have a matching user record // Avoid this if the meeting is a breakout room since might be real // voice users participating - if (ejectRogueVoiceUsers && !liveMeeting.props.meetingProp.isBreakout) { + // Also avoid ejecting if the user is dial-in (v_*) + if (ejectRogueVoiceUsers && !liveMeeting.props.meetingProp.isBreakout && !cvu.intId.startsWith("v_")) { Users2x.findWithIntId(liveMeeting.users2x, cvu.intId) match { case Some(_) => case None => From 3c0493a295f6cc61ef7d6c40bd134d4affffeae2 Mon Sep 17 00:00:00 2001 From: prlanzarin Date: Mon, 21 Dec 2020 17:59:04 +0000 Subject: [PATCH 13/14] akka-fsesl: handle dial in/out users uIDs in GetUsersStatusToVoiceConfSysMsg responses The lack of handling to check whether the user was a dial-in user when answering akka-apps periodic member probes was making it use an arbitrary default (callerName) as the userId, explicitly violating the convention that dial-in/outs should have v_memberId userIds That would botch whichever added janitorial tasks that operated upon akka-apps GetUsersStatusToVoiceConfSysMsg probes --- .../voice/freeswitch/actions/GetUsersStatusCommand.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/GetUsersStatusCommand.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/GetUsersStatusCommand.java index 6c520c36d9..1d5c6ac8ea 100755 --- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/GetUsersStatusCommand.java +++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/GetUsersStatusCommand.java @@ -85,10 +85,12 @@ public class GetUsersStatusCommand extends FreeswitchCommand { voiceUserId = callWithSess.group(1).trim(); clientSession = callWithSess.group(2).trim(); callerIdName = callWithSess.group(3).trim(); - } else - if (matcher.matches()) { + } else if (matcher.matches()) { voiceUserId = matcher.group(1).trim(); callerIdName = matcher.group(2).trim(); + } else { + // This is a caller using dial in or out + voiceUserId = "v_" + member.getId().toString(); } log.info("Conf user. uuid=" + uuid From 866c7717923ced595f31a4803ac58a8f945d9d9f Mon Sep 17 00:00:00 2001 From: prlanzarin <4529051+prlanzarin@users.noreply.github.com> Date: Wed, 17 Feb 2021 08:54:47 -0300 Subject: [PATCH 14/14] akka-apps: make ejectRogueVoiceUsers true by default --- akka-bbb-apps/src/universal/conf/application.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/akka-bbb-apps/src/universal/conf/application.conf b/akka-bbb-apps/src/universal/conf/application.conf index 267b1f079c..3e14086537 100755 --- a/akka-bbb-apps/src/universal/conf/application.conf +++ b/akka-bbb-apps/src/universal/conf/application.conf @@ -91,7 +91,7 @@ voiceConf { # Internval seconds to sync voice users status. syncUserStatusInterval = 41 # Voice users with no matching user record - ejectRogueVoiceUsers = false + ejectRogueVoiceUsers = true } recording {