From cf6202c5723f8a77c7a90e1a5c6bddc577910e98 Mon Sep 17 00:00:00 2001 From: prlanzarin <4529051+prlanzarin@users.noreply.github.com> Date: Mon, 1 Jul 2024 21:04:55 -0300 Subject: [PATCH] fix(audio): change unmute/unhold flow to work around FS unmute stutter FS has an intermittent issue where unmuting a HELD channel sometimes takes significantly (seconds) longer than usual. conference unmute simply gets stuck with no FS_API response, which delays the unmute action whenever transparent listen only is active. Apparently, unholding the channel PRIOR TO unmuting works around the issue - at least it could not be reproduced with the scenario at hand. The unmute API already triggered an unhold in FS internally, which is the reason why this was not done beforehand. The aforementioned issue is way worse than an extra "redudant" API call, though. Always unhold audio channels manually _before_ unmuting. --- .../org/bigbluebutton/LockSettingsUtil.scala | 43 +++++++++++------ .../core/apps/users/MuteUserCmdMsgHdlr.scala | 10 ++-- .../core/apps/voice/VoiceApp.scala | 47 ++++++++++++++++++- .../MuteAllExceptPresentersCmdMsgHdlr.scala | 18 ++----- .../handlers/MuteMeetingCmdMsgHdlr.scala | 16 +------ 5 files changed, 83 insertions(+), 51 deletions(-) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/LockSettingsUtil.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/LockSettingsUtil.scala index 69ddbf8e74..530cbe8b79 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/LockSettingsUtil.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/LockSettingsUtil.scala @@ -1,9 +1,10 @@ package org.bigbluebutton -import org.bigbluebutton.common2.msgs.{ BbbCommonEnvCoreMsg, BbbCoreEnvelope, BbbCoreHeaderWithMeetingId, MessageTypes, MuteUserInVoiceConfSysMsg, MuteUserInVoiceConfSysMsgBody, Routing } +import org.bigbluebutton.common2.msgs.{ BbbCommonEnvCoreMsg, BbbCoreEnvelope, BbbCoreHeaderWithMeetingId, MessageTypes, Routing } import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter } import org.bigbluebutton.core2.{ MeetingStatus2x } import org.bigbluebutton.core.apps.webcam.CameraHdlrHelpers +import org.bigbluebutton.core.apps.voice.VoiceApp import org.bigbluebutton.core.models.{ Roles, Users2x, @@ -16,19 +17,19 @@ import org.bigbluebutton.core.models.{ object LockSettingsUtil { - private def muteUserInVoiceConf(liveMeeting: LiveMeeting, outGW: OutMsgRouter, vu: VoiceUserState, mute: Boolean): Unit = { - val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, vu.intId) - val envelope = BbbCoreEnvelope(MuteUserInVoiceConfSysMsg.NAME, routing) - val header = BbbCoreHeaderWithMeetingId(MuteUserInVoiceConfSysMsg.NAME, liveMeeting.props.meetingProp.intId) - - val body = MuteUserInVoiceConfSysMsgBody(liveMeeting.props.voiceProp.voiceConf, vu.voiceUserId, mute) - val event = MuteUserInVoiceConfSysMsg(header, body) - val msgEvent = BbbCommonEnvCoreMsg(envelope, event) - - outGW.send(msgEvent) + private def muteUserInVoiceConf( + liveMeeting: LiveMeeting, + outGW: OutMsgRouter, + vu: VoiceUserState, mute: Boolean + )(implicit context: akka.actor.ActorContext): Unit = { + VoiceApp.muteUserInVoiceConf(liveMeeting, outGW, vu.intId, mute) } - private def applyMutingOfUsers(disableMic: Boolean, liveMeeting: LiveMeeting, outGW: OutMsgRouter): Unit = { + private def applyMutingOfUsers( + disableMic: Boolean, + liveMeeting: LiveMeeting, + outGW: OutMsgRouter + )(implicit context: akka.actor.ActorContext): Unit = { VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu => Users2x.findWithIntId(liveMeeting.users2x, vu.intId).foreach { user => if (user.role == Roles.VIEWER_ROLE && !vu.listenOnly && user.locked) { @@ -44,12 +45,20 @@ object LockSettingsUtil { } } - def enforceLockSettingsForAllVoiceUsers(liveMeeting: LiveMeeting, outGW: OutMsgRouter): Unit = { + def enforceLockSettingsForAllVoiceUsers( + liveMeeting: LiveMeeting, + outGW: OutMsgRouter + )(implicit context: akka.actor.ActorContext): Unit = { val permissions = MeetingStatus2x.getPermissions(liveMeeting.status) applyMutingOfUsers(permissions.disableMic, liveMeeting, outGW) } - def enforceLockSettingsForVoiceUser(voiceUser: VoiceUserState, liveMeeting: LiveMeeting, outGW: OutMsgRouter): Unit = { + def enforceLockSettingsForVoiceUser( + voiceUser: VoiceUserState, + liveMeeting: LiveMeeting, + outGW: OutMsgRouter + )(implicit context: akka.actor.ActorContext): Unit = { + val permissions = MeetingStatus2x.getPermissions(liveMeeting.status) if (permissions.disableMic) { Users2x.findWithIntId(liveMeeting.users2x, voiceUser.intId).foreach { user => @@ -65,7 +74,11 @@ object LockSettingsUtil { } } - private def enforceListenOnlyUserIsMuted(intUserId: String, liveMeeting: LiveMeeting, outGW: OutMsgRouter): Unit = { + private def enforceListenOnlyUserIsMuted( + intUserId: String, + liveMeeting: LiveMeeting, + outGW: OutMsgRouter + )(implicit context: akka.actor.ActorContext): Unit = { val voiceUser = VoiceUsers.findWithIntId(liveMeeting.voiceUsers, intUserId) voiceUser.foreach { vu => // Make sure that listen only user is muted. (ralam dec 6, 2019 diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/MuteUserCmdMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/MuteUserCmdMsgHdlr.scala index d29f40d113..e383ce3ba5 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/MuteUserCmdMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/MuteUserCmdMsgHdlr.scala @@ -2,6 +2,7 @@ package org.bigbluebutton.core.apps.users import org.bigbluebutton.common2.msgs.MuteUserCmdMsg import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } +import org.bigbluebutton.core.apps.voice.VoiceApp import org.bigbluebutton.core.models.{ Roles, Users2x, VoiceUsers } import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter } import org.bigbluebutton.core2.MeetingStatus2x @@ -51,13 +52,12 @@ trait MuteUserCmdMsgHdlr extends RightsManagementTrait { } else { if (u.muted != msg.body.mute) { log.info("Send mute user request. meetingId=" + meetingId + " userId=" + u.intId + " user=" + u) - val event = MsgBuilder.buildMuteUserInVoiceConfSysMsg( - meetingId, - voiceConf, - u.voiceUserId, + VoiceApp.muteUserInVoiceConf( + liveMeeting, + outGW, + u.intId, msg.body.mute ) - outGW.send(event) } } } 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 fa2bd08e2a..41e4704962 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 @@ -138,7 +138,7 @@ object VoiceApp extends SystemConfiguration { // If the user is muted or unmuted with an unheld channel, broadcast // the event right away. - // If the user is unmuted, but channel is held, we need to wait for the + // If the user is unmuted, but channel is held, we need to wait for the // channel to be active again to broadcast the event. See // VoiceApp.handleChannelHoldChanged for this second case. if (muted || (!muted && !mutedUser.hold)) { @@ -149,7 +149,6 @@ object VoiceApp extends SystemConfiguration { outGW ) } - } } @@ -614,4 +613,48 @@ object VoiceApp extends SystemConfiguration { case _ => } } + + def muteUserInVoiceConf( + liveMeeting: LiveMeeting, + outGW: OutMsgRouter, + userId: String, + muted: Boolean + )(implicit context: akka.actor.ActorContext): Unit = { + for { + u <- VoiceUsers.findWithIntId( + liveMeeting.voiceUsers, + userId + ) + } yield { + if (u.muted != muted) { + val muteEvent = MsgBuilder.buildMuteUserInVoiceConfSysMsg( + liveMeeting.props.meetingProp.intId, + liveMeeting.props.voiceProp.voiceConf, + u.voiceUserId, + muted + ) + + // If we're unmuting, trigger a channel unhold -> toggle listen only + // mode -> unmute + if (!muted) { + holdChannelInVoiceConf( + liveMeeting, + outGW, + u.uuid, + muted + ) + toggleListenOnlyMode( + liveMeeting, + outGW, + u.intId, + u.callerNum, + muted, + 0 + ) + } + + outGW.send(muteEvent) + } + } + } } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/MuteAllExceptPresentersCmdMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/MuteAllExceptPresentersCmdMsgHdlr.scala index 6f8f65e2fa..d10c404121 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/MuteAllExceptPresentersCmdMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/MuteAllExceptPresentersCmdMsgHdlr.scala @@ -6,6 +6,7 @@ import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } import org.bigbluebutton.core2.MeetingStatus2x import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core2.message.senders.{ MsgBuilder } +import org.bigbluebutton.core.apps.voice.VoiceApp trait MuteAllExceptPresentersCmdMsgHdlr extends RightsManagementTrait { this: MeetingActor => @@ -57,8 +58,8 @@ trait MuteAllExceptPresentersCmdMsgHdlr extends RightsManagementTrait { VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu => if (!vu.listenOnly) { Users2x.findWithIntId(liveMeeting.users2x, vu.intId) match { - case Some(u) => if (!u.presenter) muteUserInVoiceConf(vu, muted) - case None => muteUserInVoiceConf(vu, muted) + case Some(u) => if (!u.presenter) VoiceApp.muteUserInVoiceConf(liveMeeting, outGW, vu.intId, muted) + case None => VoiceApp.muteUserInVoiceConf(liveMeeting, outGW, vu.intId, muted) } } } @@ -82,17 +83,4 @@ trait MuteAllExceptPresentersCmdMsgHdlr extends RightsManagementTrait { BbbCommonEnvCoreMsg(envelope, event) } - def muteUserInVoiceConf(vu: VoiceUserState, mute: Boolean): Unit = { - val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId, vu.intId) - val envelope = BbbCoreEnvelope(MuteUserInVoiceConfSysMsg.NAME, routing) - val header = BbbCoreHeaderWithMeetingId(MuteUserInVoiceConfSysMsg.NAME, props.meetingProp.intId) - - val body = MuteUserInVoiceConfSysMsgBody(props.voiceProp.voiceConf, vu.voiceUserId, mute) - val event = MuteUserInVoiceConfSysMsg(header, body) - val msgEvent = BbbCommonEnvCoreMsg(envelope, event) - - outGW.send(msgEvent) - - } - } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/MuteMeetingCmdMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/MuteMeetingCmdMsgHdlr.scala index cde43a7f5a..5ce1897427 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/MuteMeetingCmdMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/MuteMeetingCmdMsgHdlr.scala @@ -6,6 +6,7 @@ import org.bigbluebutton.core.models.{ VoiceUserState, VoiceUsers } import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } import org.bigbluebutton.core2.MeetingStatus2x import org.bigbluebutton.core2.message.senders.{ MsgBuilder } +import org.bigbluebutton.core.apps.voice.VoiceApp trait MuteMeetingCmdMsgHdlr extends RightsManagementTrait { this: MeetingActor => @@ -30,19 +31,6 @@ trait MuteMeetingCmdMsgHdlr extends RightsManagementTrait { BbbCommonEnvCoreMsg(envelope, event) } - def muteUserInVoiceConf(vu: VoiceUserState, mute: Boolean): Unit = { - val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId, vu.intId) - val envelope = BbbCoreEnvelope(MuteUserInVoiceConfSysMsg.NAME, routing) - val header = BbbCoreHeaderWithMeetingId(MuteUserInVoiceConfSysMsg.NAME, props.meetingProp.intId) - - val body = MuteUserInVoiceConfSysMsgBody(props.voiceProp.voiceConf, vu.voiceUserId, mute) - val event = MuteUserInVoiceConfSysMsg(header, body) - val msgEvent = BbbCommonEnvCoreMsg(envelope, event) - - outGW.send(msgEvent) - - } - if (msg.body.mute != MeetingStatus2x.isMeetingMuted(liveMeeting.status)) { if (msg.body.mute) { val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg( @@ -79,7 +67,7 @@ trait MuteMeetingCmdMsgHdlr extends RightsManagementTrait { if (muted) { VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu => if (!vu.listenOnly) { - muteUserInVoiceConf(vu, muted) + VoiceApp.muteUserInVoiceConf(liveMeeting, outGW, vu.intId, muted) } } }