Merge branch 'v2.2.x-release' of github.com:bigbluebutton/bigbluebutton into feb18-merge

This commit is contained in:
Anton Georgiev 2021-02-18 20:33:19 +00:00
commit 55e8de4357
10 changed files with 84 additions and 20 deletions

View File

@ -43,6 +43,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)

View File

@ -1,15 +1,16 @@
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
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
object VoiceApp {
object VoiceApp extends SystemConfiguration {
def genRecordPath(
recordDir: String,
@ -136,6 +137,20 @@ 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
// 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 =>
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,

View File

@ -85,6 +85,8 @@ voiceConf {
checkRecordingInterval = 23
# Internval seconds to sync voice users status.
syncUserStatusInterval = 41
# Voice users with no matching user record
ejectRogueVoiceUsers = true
}
recording {

View File

@ -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

View File

@ -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);

View File

@ -6,10 +6,41 @@ import Meetings from '/imports/api/meetings';
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 +64,7 @@ const init = (messages, intl) => {
microphoneLockEnforced,
};
AudioManager.init(userData);
AudioManager.init(userData, audioEventHandler);
};
const isVoiceUser = () => {
@ -46,6 +77,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',

View File

@ -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) => {

View File

@ -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) {
@ -338,6 +339,7 @@ class AudioManager {
this.notify(this.intl.formatMessage(this.messages.info.JOINED_AUDIO));
logger.info({ logCode: 'audio_joined' }, 'Audio Joined');
if (STATS.enabled) this.monitor();
this.audioEventHandler({ name: 'started' });
}
}

View File

@ -249,7 +249,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
@ -265,7 +265,7 @@ 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.
@ -273,11 +273,11 @@ public:
# A page size of 0 (zero) means that the page size is unlimited (disabled).
desktopPageSizes:
moderator: 0
viewer: 5
viewer: 0
# video page sizes for MOBILE endpoints
mobilePageSizes:
moderator: 2
viewer: 2
moderator: 6
viewer: 4
syncUsersWithConnectionManager:
enabled: false
syncInterval: 60000

View File

@ -212,7 +212,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
}
@ -244,11 +249,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.