Merge pull request #15385 from mariogasparoni/fix-15163-v2.6
fix(audio): prevent dial-in waiting / guest users to speak/listen to the room
This commit is contained in:
commit
e35fee622b
@ -40,6 +40,7 @@ trait SystemConfiguration {
|
|||||||
lazy val checkVoiceRecordingInterval = Try(config.getInt("voiceConf.checkRecordingInterval")).getOrElse(19)
|
lazy val checkVoiceRecordingInterval = Try(config.getInt("voiceConf.checkRecordingInterval")).getOrElse(19)
|
||||||
lazy val syncVoiceUsersStatusInterval = Try(config.getInt("voiceConf.syncUserStatusInterval")).getOrElse(43)
|
lazy val syncVoiceUsersStatusInterval = Try(config.getInt("voiceConf.syncUserStatusInterval")).getOrElse(43)
|
||||||
lazy val ejectRogueVoiceUsers = Try(config.getBoolean("voiceConf.ejectRogueVoiceUsers")).getOrElse(true)
|
lazy val ejectRogueVoiceUsers = Try(config.getBoolean("voiceConf.ejectRogueVoiceUsers")).getOrElse(true)
|
||||||
|
lazy val dialInApprovalAudioPath = Try(config.getString("voiceConf.dialInApprovalAudioPath")).getOrElse("ivr/ivr-please_hold_while_party_contacted.wav")
|
||||||
|
|
||||||
lazy val recordingChapterBreakLengthInMinutes = Try(config.getInt("recording.chapterBreakLengthInMinutes")).getOrElse(0)
|
lazy val recordingChapterBreakLengthInMinutes = Try(config.getInt("recording.chapterBreakLengthInMinutes")).getOrElse(0)
|
||||||
|
|
||||||
|
@ -63,6 +63,13 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
|||||||
val guest = GuestWaiting(msg.body.intId, msg.body.callerIdName, Roles.VIEWER_ROLE, true, "", true, System.currentTimeMillis())
|
val guest = GuestWaiting(msg.body.intId, msg.body.callerIdName, Roles.VIEWER_ROLE, true, "", true, System.currentTimeMillis())
|
||||||
GuestsWaiting.add(liveMeeting.guestsWaiting, guest)
|
GuestsWaiting.add(liveMeeting.guestsWaiting, guest)
|
||||||
notifyModeratorsOfGuestWaiting(guest, liveMeeting.users2x, liveMeeting.props.meetingProp.intId)
|
notifyModeratorsOfGuestWaiting(guest, liveMeeting.users2x, liveMeeting.props.meetingProp.intId)
|
||||||
|
|
||||||
|
VoiceApp.toggleUserAudioInVoiceConf(
|
||||||
|
liveMeeting,
|
||||||
|
outGW,
|
||||||
|
msg.body.voiceUserId,
|
||||||
|
false
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,4 +353,66 @@ object VoiceApp extends SystemConfiguration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Toggle audio for the given user in voice conference.
|
||||||
|
*
|
||||||
|
* We first stop the current audio being played, preventing the playback
|
||||||
|
* to also mix the "You are the first person ..." audio.
|
||||||
|
* After that we check if we are turning on/off based on enabled param. If
|
||||||
|
* enabled is false we:
|
||||||
|
* - play a sound to let user know that an action is required
|
||||||
|
* (eg. guest approval) from the server/room.
|
||||||
|
* - put the user on hold, so DTMFs for mute / deaf mute are also disabled
|
||||||
|
* - mute the user (other participants won't hear users's audio)
|
||||||
|
* - deaf the user (user won't hear other participant's audio)
|
||||||
|
* If disabled, we remove user from hold, mute and deaf states, allowing the
|
||||||
|
* user to interact with the room.
|
||||||
|
*/
|
||||||
|
def toggleUserAudioInVoiceConf(
|
||||||
|
liveMeeting: LiveMeeting,
|
||||||
|
outGW: OutMsgRouter,
|
||||||
|
voiceUserId: String,
|
||||||
|
enabled: Boolean
|
||||||
|
): Unit = {
|
||||||
|
val stopEvent = MsgBuilder.buildStopSoundInVoiceConfSysMsg(
|
||||||
|
liveMeeting.props.meetingProp.intId,
|
||||||
|
liveMeeting.props.voiceProp.voiceConf,
|
||||||
|
""
|
||||||
|
)
|
||||||
|
outGW.send(stopEvent)
|
||||||
|
|
||||||
|
if (!enabled) {
|
||||||
|
val playEvent = MsgBuilder.buildPlaySoundInVoiceConfSysMsg(
|
||||||
|
liveMeeting.props.meetingProp.intId,
|
||||||
|
liveMeeting.props.voiceProp.voiceConf,
|
||||||
|
voiceUserId,
|
||||||
|
dialInApprovalAudioPath
|
||||||
|
)
|
||||||
|
outGW.send(playEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
val holdEvent = MsgBuilder.buildHoldUserInVoiceConfSysMsg(
|
||||||
|
liveMeeting.props.meetingProp.intId,
|
||||||
|
liveMeeting.props.voiceProp.voiceConf,
|
||||||
|
voiceUserId,
|
||||||
|
!enabled
|
||||||
|
)
|
||||||
|
outGW.send(holdEvent)
|
||||||
|
|
||||||
|
val muteEvent = MsgBuilder.buildMuteUserInVoiceConfSysMsg(
|
||||||
|
liveMeeting.props.meetingProp.intId,
|
||||||
|
liveMeeting.props.voiceProp.voiceConf,
|
||||||
|
voiceUserId,
|
||||||
|
!enabled
|
||||||
|
)
|
||||||
|
outGW.send(muteEvent)
|
||||||
|
|
||||||
|
val deafEvent = MsgBuilder.buildDeafUserInVoiceConfSysMsg(
|
||||||
|
liveMeeting.props.meetingProp.intId,
|
||||||
|
liveMeeting.props.voiceProp.voiceConf,
|
||||||
|
voiceUserId,
|
||||||
|
!enabled
|
||||||
|
)
|
||||||
|
outGW.send(deafEvent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,10 @@ class AnalyticsActor(val includeChat: Boolean) extends Actor with ActorLogging {
|
|||||||
case m: RecordingStartedVoiceConfEvtMsg => logMessage(msg)
|
case m: RecordingStartedVoiceConfEvtMsg => logMessage(msg)
|
||||||
case m: MuteUserCmdMsg => logMessage(msg)
|
case m: MuteUserCmdMsg => logMessage(msg)
|
||||||
case m: MuteUserInVoiceConfSysMsg => logMessage(msg)
|
case m: MuteUserInVoiceConfSysMsg => logMessage(msg)
|
||||||
|
case m: DeafUserInVoiceConfSysMsg => logMessage(msg)
|
||||||
|
case m: HoldUserInVoiceConfSysMsg => logMessage(msg)
|
||||||
|
case m: PlaySoundInVoiceConfSysMsg => logMessage(msg)
|
||||||
|
case m: StopSoundInVoiceConfSysMsg => logMessage(msg)
|
||||||
case m: MuteAllExceptPresentersCmdMsg => logMessage(msg)
|
case m: MuteAllExceptPresentersCmdMsg => logMessage(msg)
|
||||||
case m: EjectUserFromVoiceCmdMsg => logMessage(msg)
|
case m: EjectUserFromVoiceCmdMsg => logMessage(msg)
|
||||||
case m: MuteMeetingCmdMsg => logMessage(msg)
|
case m: MuteMeetingCmdMsg => logMessage(msg)
|
||||||
|
@ -49,6 +49,14 @@ class FromAkkaAppsMsgSenderActor(msgSender: MessageSender)
|
|||||||
msgSender.send(toVoiceConfRedisChannel, json)
|
msgSender.send(toVoiceConfRedisChannel, json)
|
||||||
case MuteUserInVoiceConfSysMsg.NAME =>
|
case MuteUserInVoiceConfSysMsg.NAME =>
|
||||||
msgSender.send(toVoiceConfRedisChannel, json)
|
msgSender.send(toVoiceConfRedisChannel, json)
|
||||||
|
case DeafUserInVoiceConfSysMsg.NAME =>
|
||||||
|
msgSender.send(toVoiceConfRedisChannel, json)
|
||||||
|
case HoldUserInVoiceConfSysMsg.NAME =>
|
||||||
|
msgSender.send(toVoiceConfRedisChannel, json)
|
||||||
|
case PlaySoundInVoiceConfSysMsg.NAME =>
|
||||||
|
msgSender.send(toVoiceConfRedisChannel, json)
|
||||||
|
case StopSoundInVoiceConfSysMsg.NAME =>
|
||||||
|
msgSender.send(toVoiceConfRedisChannel, json)
|
||||||
case StartRecordingVoiceConfSysMsg.NAME =>
|
case StartRecordingVoiceConfSysMsg.NAME =>
|
||||||
msgSender.send(toVoiceConfRedisChannel, json)
|
msgSender.send(toVoiceConfRedisChannel, json)
|
||||||
case StopRecordingVoiceConfSysMsg.NAME =>
|
case StopRecordingVoiceConfSysMsg.NAME =>
|
||||||
|
@ -45,6 +45,23 @@ trait GuestsWaitingApprovedMsgHdlr extends HandlerHelpers with RightsManagementT
|
|||||||
false,
|
false,
|
||||||
"freeswitch"
|
"freeswitch"
|
||||||
)
|
)
|
||||||
|
VoiceUsers.findWithIntId(
|
||||||
|
liveMeeting.voiceUsers,
|
||||||
|
dialInUser.intId
|
||||||
|
) match {
|
||||||
|
case Some(vu) =>
|
||||||
|
VoiceApp.toggleUserAudioInVoiceConf(
|
||||||
|
liveMeeting,
|
||||||
|
outGW,
|
||||||
|
vu.voiceUserId,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
case None =>
|
||||||
|
println(s"Skipping transferring dial-in user to the "
|
||||||
|
+ "voiceconf: dial-in user already left. meetingId= "
|
||||||
|
+ "${liveMeeting.props.meetingProp.intId}, userId="
|
||||||
|
+ "${dialInUser.intId}")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
VoiceApp.removeUserFromVoiceConf(liveMeeting, outGW, dialInUser.extId)
|
VoiceApp.removeUserFromVoiceConf(liveMeeting, outGW, dialInUser.extId)
|
||||||
val event = MsgBuilder.buildEjectUserFromVoiceConfSysMsg(liveMeeting.props.meetingProp.intId, liveMeeting.props.voiceProp.voiceConf, g.guest)
|
val event = MsgBuilder.buildEjectUserFromVoiceConfSysMsg(liveMeeting.props.meetingProp.intId, liveMeeting.props.voiceProp.voiceConf, g.guest)
|
||||||
|
@ -336,6 +336,46 @@ object MsgBuilder {
|
|||||||
BbbCommonEnvCoreMsg(envelope, event)
|
BbbCommonEnvCoreMsg(envelope, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def buildDeafUserInVoiceConfSysMsg(meetingId: String, voiceConf: String, voiceUserId: String, deaf: Boolean): BbbCommonEnvCoreMsg = {
|
||||||
|
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
|
||||||
|
val envelope = BbbCoreEnvelope(DeafUserInVoiceConfSysMsg.NAME, routing)
|
||||||
|
val body = DeafUserInVoiceConfSysMsgBody(voiceConf, voiceUserId, deaf)
|
||||||
|
val header = BbbCoreHeaderWithMeetingId(DeafUserInVoiceConfSysMsg.NAME, meetingId)
|
||||||
|
val event = DeafUserInVoiceConfSysMsg(header, body)
|
||||||
|
|
||||||
|
BbbCommonEnvCoreMsg(envelope, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
def buildHoldUserInVoiceConfSysMsg(meetingId: String, voiceConf: String, voiceUserId: String, hold: Boolean): BbbCommonEnvCoreMsg = {
|
||||||
|
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
|
||||||
|
val envelope = BbbCoreEnvelope(HoldUserInVoiceConfSysMsg.NAME, routing)
|
||||||
|
val body = HoldUserInVoiceConfSysMsgBody(voiceConf, voiceUserId, hold)
|
||||||
|
val header = BbbCoreHeaderWithMeetingId(HoldUserInVoiceConfSysMsg.NAME, meetingId)
|
||||||
|
val event = HoldUserInVoiceConfSysMsg(header, body)
|
||||||
|
|
||||||
|
BbbCommonEnvCoreMsg(envelope, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
def buildPlaySoundInVoiceConfSysMsg(meetingId: String, voiceConf: String, voiceUserId: String, soundPath: String): BbbCommonEnvCoreMsg = {
|
||||||
|
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
|
||||||
|
val envelope = BbbCoreEnvelope(PlaySoundInVoiceConfSysMsg.NAME, routing)
|
||||||
|
val body = PlaySoundInVoiceConfSysMsgBody(voiceConf, voiceUserId, soundPath)
|
||||||
|
val header = BbbCoreHeaderWithMeetingId(PlaySoundInVoiceConfSysMsg.NAME, meetingId)
|
||||||
|
val event = PlaySoundInVoiceConfSysMsg(header, body)
|
||||||
|
|
||||||
|
BbbCommonEnvCoreMsg(envelope, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
def buildStopSoundInVoiceConfSysMsg(meetingId: String, voiceConf: String, voiceUserId: String): BbbCommonEnvCoreMsg = {
|
||||||
|
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
|
||||||
|
val envelope = BbbCoreEnvelope(StopSoundInVoiceConfSysMsg.NAME, routing)
|
||||||
|
val body = StopSoundInVoiceConfSysMsgBody(voiceConf, voiceUserId)
|
||||||
|
val header = BbbCoreHeaderWithMeetingId(StopSoundInVoiceConfSysMsg.NAME, meetingId)
|
||||||
|
val event = StopSoundInVoiceConfSysMsg(header, body)
|
||||||
|
|
||||||
|
BbbCommonEnvCoreMsg(envelope, event)
|
||||||
|
}
|
||||||
|
|
||||||
def buildBreakoutRoomEndedEvtMsg(meetingId: String, userId: String, breakoutRoomId: String): BbbCommonEnvCoreMsg = {
|
def buildBreakoutRoomEndedEvtMsg(meetingId: String, userId: String, breakoutRoomId: String): BbbCommonEnvCoreMsg = {
|
||||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
|
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
|
||||||
val envelope = BbbCoreEnvelope(BreakoutRoomEndedEvtMsg.NAME, routing)
|
val envelope = BbbCoreEnvelope(BreakoutRoomEndedEvtMsg.NAME, routing)
|
||||||
|
@ -88,6 +88,10 @@ voiceConf {
|
|||||||
syncUserStatusInterval = 41
|
syncUserStatusInterval = 41
|
||||||
# Voice users with no matching user record
|
# Voice users with no matching user record
|
||||||
ejectRogueVoiceUsers = true
|
ejectRogueVoiceUsers = true
|
||||||
|
|
||||||
|
# Path to the audio file being played when dial-in user is waiting for
|
||||||
|
# approval. This can be relative to FreeSWITCH sounds folder
|
||||||
|
dialInApprovalAudioPath = "ivr/ivr-please_hold_while_party_contacted.wav"
|
||||||
}
|
}
|
||||||
|
|
||||||
recording {
|
recording {
|
||||||
|
@ -204,6 +204,34 @@ public class ConnectionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void deaf(DeafUserCommand duc) {
|
||||||
|
Client c = manager.getESLClient();
|
||||||
|
if (c.canSend()) {
|
||||||
|
c.sendAsyncApiCommand(duc.getCommand(), duc.getCommandArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hold(HoldUserCommand huc) {
|
||||||
|
Client c = manager.getESLClient();
|
||||||
|
if (c.canSend()) {
|
||||||
|
c.sendAsyncApiCommand(huc.getCommand(), huc.getCommandArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playSound(PlaySoundCommand psc) {
|
||||||
|
Client c = manager.getESLClient();
|
||||||
|
if (c.canSend()) {
|
||||||
|
c.sendAsyncApiCommand(psc.getCommand(), psc.getCommandArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopSound(StopSoundCommand ssc) {
|
||||||
|
Client c = manager.getESLClient();
|
||||||
|
if (c.canSend()) {
|
||||||
|
c.sendAsyncApiCommand(ssc.getCommand(), ssc.getCommandArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void tranfer(TransferUserToMeetingCommand tutmc) {
|
public void tranfer(TransferUserToMeetingCommand tutmc) {
|
||||||
Client c = manager.getESLClient();
|
Client c = manager.getESLClient();
|
||||||
if (c.canSend()) {
|
if (c.canSend()) {
|
||||||
|
@ -28,6 +28,10 @@ import org.bigbluebutton.freeswitch.voice.freeswitch.actions.EjectUserCommand;
|
|||||||
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.FreeswitchCommand;
|
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.FreeswitchCommand;
|
||||||
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.GetAllUsersCommand;
|
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.GetAllUsersCommand;
|
||||||
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.MuteUserCommand;
|
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.MuteUserCommand;
|
||||||
|
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.DeafUserCommand;
|
||||||
|
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.HoldUserCommand;
|
||||||
|
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.PlaySoundCommand;
|
||||||
|
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.StopSoundCommand;
|
||||||
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.RecordConferenceCommand;
|
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.RecordConferenceCommand;
|
||||||
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.TransferUserToMeetingCommand;
|
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.TransferUserToMeetingCommand;
|
||||||
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.*;
|
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.*;
|
||||||
@ -123,6 +127,26 @@ public class FreeswitchApplication implements IDelayedCommandListener{
|
|||||||
queueMessage(mpc);
|
queueMessage(mpc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void deafUser(String voiceConfId, String voiceUserId, Boolean deaf) {
|
||||||
|
DeafUserCommand duc = new DeafUserCommand(voiceConfId, voiceUserId, deaf, USER);
|
||||||
|
queueMessage(duc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void holdUser(String voiceConfId, String voiceUserId, Boolean hold) {
|
||||||
|
HoldUserCommand huc = new HoldUserCommand(voiceConfId, voiceUserId, hold, USER);
|
||||||
|
queueMessage(huc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playSound(String voiceConfId, String voiceUserId, String soundPath) {
|
||||||
|
PlaySoundCommand psc = new PlaySoundCommand(voiceConfId, voiceUserId, soundPath, USER);
|
||||||
|
queueMessage(psc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopSound(String voiceConfId, String voiceUserId) {
|
||||||
|
StopSoundCommand ssc = new StopSoundCommand(voiceConfId, voiceUserId, USER);
|
||||||
|
queueMessage(ssc);
|
||||||
|
}
|
||||||
|
|
||||||
public void eject(String voiceConfId, String voiceUserId) {
|
public void eject(String voiceConfId, String voiceUserId) {
|
||||||
EjectUserCommand mpc = new EjectUserCommand(voiceConfId, voiceUserId, USER);
|
EjectUserCommand mpc = new EjectUserCommand(voiceConfId, voiceUserId, USER);
|
||||||
queueMessage(mpc);
|
queueMessage(mpc);
|
||||||
@ -158,6 +182,18 @@ public class FreeswitchApplication implements IDelayedCommandListener{
|
|||||||
} else if (command instanceof MuteUserCommand) {
|
} else if (command instanceof MuteUserCommand) {
|
||||||
MuteUserCommand cmd = (MuteUserCommand) command;
|
MuteUserCommand cmd = (MuteUserCommand) command;
|
||||||
manager.mute(cmd);
|
manager.mute(cmd);
|
||||||
|
} else if (command instanceof DeafUserCommand) {
|
||||||
|
DeafUserCommand cmd = (DeafUserCommand) command;
|
||||||
|
manager.deaf(cmd);
|
||||||
|
} else if (command instanceof HoldUserCommand) {
|
||||||
|
HoldUserCommand cmd = (HoldUserCommand) command;
|
||||||
|
manager.hold(cmd);
|
||||||
|
} else if (command instanceof PlaySoundCommand) {
|
||||||
|
PlaySoundCommand cmd = (PlaySoundCommand) command;
|
||||||
|
manager.playSound(cmd);
|
||||||
|
} else if (command instanceof StopSoundCommand) {
|
||||||
|
StopSoundCommand cmd = (StopSoundCommand) command;
|
||||||
|
manager.stopSound(cmd);
|
||||||
} else if (command instanceof EjectUserCommand) {
|
} else if (command instanceof EjectUserCommand) {
|
||||||
EjectUserCommand cmd = (EjectUserCommand) command;
|
EjectUserCommand cmd = (EjectUserCommand) command;
|
||||||
manager.eject(cmd);
|
manager.eject(cmd);
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.bigbluebutton.freeswitch.voice.freeswitch.actions;
|
||||||
|
|
||||||
|
public class DeafUserCommand extends FreeswitchCommand {
|
||||||
|
|
||||||
|
private final String participant;
|
||||||
|
private final Boolean deaf;
|
||||||
|
|
||||||
|
public DeafUserCommand(String room, String participant, Boolean deaf, String requesterId) {
|
||||||
|
super(room, requesterId);
|
||||||
|
this.participant = participant;
|
||||||
|
this.deaf = deaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandArgs() {
|
||||||
|
String action = "undeaf";
|
||||||
|
if (deaf) action = "deaf";
|
||||||
|
|
||||||
|
return room + SPACE + action + SPACE + participant;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.bigbluebutton.freeswitch.voice.freeswitch.actions;
|
||||||
|
|
||||||
|
public class HoldUserCommand extends FreeswitchCommand {
|
||||||
|
|
||||||
|
private final String participant;
|
||||||
|
private final Boolean hold;
|
||||||
|
|
||||||
|
public HoldUserCommand(String room, String participant, Boolean hold, String requesterId) {
|
||||||
|
super(room, requesterId);
|
||||||
|
this.participant = participant;
|
||||||
|
this.hold = hold;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandArgs() {
|
||||||
|
String action = "unhold";
|
||||||
|
if (hold) action = "hold";
|
||||||
|
|
||||||
|
return room + SPACE + action + SPACE + participant;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.bigbluebutton.freeswitch.voice.freeswitch.actions;
|
||||||
|
|
||||||
|
public class PlaySoundCommand extends FreeswitchCommand {
|
||||||
|
|
||||||
|
private final String participant;
|
||||||
|
private final String soundPath;
|
||||||
|
|
||||||
|
public PlaySoundCommand(String room, String participant, String soundPath, String requesterId) {
|
||||||
|
super(room, requesterId);
|
||||||
|
this.participant = participant;
|
||||||
|
this.soundPath = soundPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandArgs() {
|
||||||
|
String action = "play";
|
||||||
|
|
||||||
|
return room + SPACE + action + SPACE
|
||||||
|
+ this.soundPath + SPACE + participant;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.bigbluebutton.freeswitch.voice.freeswitch.actions;
|
||||||
|
|
||||||
|
public class StopSoundCommand extends FreeswitchCommand {
|
||||||
|
|
||||||
|
private final String participant;
|
||||||
|
|
||||||
|
public StopSoundCommand(String room, String participant, String requesterId) {
|
||||||
|
super(room, requesterId);
|
||||||
|
this.participant = participant;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandArgs() {
|
||||||
|
String action = "stop all";
|
||||||
|
|
||||||
|
return room + SPACE + action + SPACE + participant;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -117,6 +117,78 @@ trait RxJsonMsgDeserializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def routeDeafUserInVoiceConfMsg(envelope: BbbCoreEnvelope, jsonNode: JsonNode): Unit = {
|
||||||
|
def deserialize(jsonNode: JsonNode): Option[DeafUserInVoiceConfSysMsg] = {
|
||||||
|
val (result, error) = JsonDeserializer.toBbbCommonMsg[DeafUserInVoiceConfSysMsg](jsonNode)
|
||||||
|
result match {
|
||||||
|
case Some(msg) => Some(msg.asInstanceOf[DeafUserInVoiceConfSysMsg])
|
||||||
|
case None =>
|
||||||
|
log.error("Failed to deserialize message: error: {} \n msg: {}", error, jsonNode)
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
m <- deserialize(jsonNode)
|
||||||
|
} yield {
|
||||||
|
fsApp.deafUser(m.body.voiceConf, m.body.voiceUserId, m.body.deaf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def routeHoldUserInVoiceConfMsg(envelope: BbbCoreEnvelope, jsonNode: JsonNode): Unit = {
|
||||||
|
def deserialize(jsonNode: JsonNode): Option[HoldUserInVoiceConfSysMsg] = {
|
||||||
|
val (result, error) = JsonDeserializer.toBbbCommonMsg[HoldUserInVoiceConfSysMsg](jsonNode)
|
||||||
|
result match {
|
||||||
|
case Some(msg) => Some(msg.asInstanceOf[HoldUserInVoiceConfSysMsg])
|
||||||
|
case None =>
|
||||||
|
log.error("Failed to deserialize message: error: {} \n msg: {}", error, jsonNode)
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
m <- deserialize(jsonNode)
|
||||||
|
} yield {
|
||||||
|
fsApp.holdUser(m.body.voiceConf, m.body.voiceUserId, m.body.hold)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def routePlaySoundInVoiceConfMsg(envelope: BbbCoreEnvelope, jsonNode: JsonNode): Unit = {
|
||||||
|
def deserialize(jsonNode: JsonNode): Option[PlaySoundInVoiceConfSysMsg] = {
|
||||||
|
val (result, error) = JsonDeserializer.toBbbCommonMsg[PlaySoundInVoiceConfSysMsg](jsonNode)
|
||||||
|
result match {
|
||||||
|
case Some(msg) => Some(msg.asInstanceOf[PlaySoundInVoiceConfSysMsg])
|
||||||
|
case None =>
|
||||||
|
log.error("Failed to deserialize message: error: {} \n msg: {}", error, jsonNode)
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
m <- deserialize(jsonNode)
|
||||||
|
} yield {
|
||||||
|
fsApp.playSound(m.body.voiceConf, m.body.voiceUserId, m.body.soundPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def routeStopSoundInVoiceConfMsg(envelope: BbbCoreEnvelope, jsonNode: JsonNode): Unit = {
|
||||||
|
def deserialize(jsonNode: JsonNode): Option[StopSoundInVoiceConfSysMsg] = {
|
||||||
|
val (result, error) = JsonDeserializer.toBbbCommonMsg[StopSoundInVoiceConfSysMsg](jsonNode)
|
||||||
|
result match {
|
||||||
|
case Some(msg) => Some(msg.asInstanceOf[StopSoundInVoiceConfSysMsg])
|
||||||
|
case None =>
|
||||||
|
log.error("Failed to deserialize message: error: {} \n msg: {}", error, jsonNode)
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
m <- deserialize(jsonNode)
|
||||||
|
} yield {
|
||||||
|
fsApp.stopSound(m.body.voiceConf, m.body.voiceUserId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def routeTransferUserToVoiceConfMsg(envelope: BbbCoreEnvelope, jsonNode: JsonNode): Unit = {
|
def routeTransferUserToVoiceConfMsg(envelope: BbbCoreEnvelope, jsonNode: JsonNode): Unit = {
|
||||||
def deserialize(jsonNode: JsonNode): Option[TransferUserToVoiceConfSysMsg] = {
|
def deserialize(jsonNode: JsonNode): Option[TransferUserToVoiceConfSysMsg] = {
|
||||||
val (result, error) = JsonDeserializer.toBbbCommonMsg[TransferUserToVoiceConfSysMsg](jsonNode)
|
val (result, error) = JsonDeserializer.toBbbCommonMsg[TransferUserToVoiceConfSysMsg](jsonNode)
|
||||||
|
@ -42,6 +42,14 @@ class RxJsonMsgHdlrActor(val fsApp: FreeswitchApplication) extends Actor with Ac
|
|||||||
routeEjectUserFromVoiceConfMsg(envelope, jsonNode)
|
routeEjectUserFromVoiceConfMsg(envelope, jsonNode)
|
||||||
case MuteUserInVoiceConfSysMsg.NAME =>
|
case MuteUserInVoiceConfSysMsg.NAME =>
|
||||||
routeMuteUserInVoiceConfMsg(envelope, jsonNode)
|
routeMuteUserInVoiceConfMsg(envelope, jsonNode)
|
||||||
|
case DeafUserInVoiceConfSysMsg.NAME =>
|
||||||
|
routeDeafUserInVoiceConfMsg(envelope, jsonNode)
|
||||||
|
case HoldUserInVoiceConfSysMsg.NAME =>
|
||||||
|
routeHoldUserInVoiceConfMsg(envelope, jsonNode)
|
||||||
|
case PlaySoundInVoiceConfSysMsg.NAME =>
|
||||||
|
routePlaySoundInVoiceConfMsg(envelope, jsonNode)
|
||||||
|
case StopSoundInVoiceConfSysMsg.NAME =>
|
||||||
|
routeStopSoundInVoiceConfMsg(envelope, jsonNode)
|
||||||
case TransferUserToVoiceConfSysMsg.NAME =>
|
case TransferUserToVoiceConfSysMsg.NAME =>
|
||||||
routeTransferUserToVoiceConfMsg(envelope, jsonNode)
|
routeTransferUserToVoiceConfMsg(envelope, jsonNode)
|
||||||
case StartRecordingVoiceConfSysMsg.NAME =>
|
case StartRecordingVoiceConfSysMsg.NAME =>
|
||||||
|
@ -258,6 +258,46 @@ case class MeetingMutedEvtMsg(
|
|||||||
) extends BbbCoreMsg
|
) extends BbbCoreMsg
|
||||||
case class MeetingMutedEvtMsgBody(muted: Boolean, mutedBy: String)
|
case class MeetingMutedEvtMsgBody(muted: Boolean, mutedBy: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send to FS to deaf user in the voice conference.
|
||||||
|
*/
|
||||||
|
object DeafUserInVoiceConfSysMsg { val NAME = "DeafUserInVoiceConfSysMsg" }
|
||||||
|
case class DeafUserInVoiceConfSysMsg(
|
||||||
|
header: BbbCoreHeaderWithMeetingId,
|
||||||
|
body: DeafUserInVoiceConfSysMsgBody
|
||||||
|
) extends BbbCoreMsg
|
||||||
|
case class DeafUserInVoiceConfSysMsgBody(voiceConf: String, voiceUserId: String, deaf: Boolean)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send to FS to hold user in the voice conference.
|
||||||
|
*/
|
||||||
|
object HoldUserInVoiceConfSysMsg { val NAME = "HoldUserInVoiceConfSysMsg" }
|
||||||
|
case class HoldUserInVoiceConfSysMsg(
|
||||||
|
header: BbbCoreHeaderWithMeetingId,
|
||||||
|
body: HoldUserInVoiceConfSysMsgBody
|
||||||
|
) extends BbbCoreMsg
|
||||||
|
case class HoldUserInVoiceConfSysMsgBody(voiceConf: String, voiceUserId: String, hold: Boolean)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send to FS to play sound in the voice conference, or specific user
|
||||||
|
*/
|
||||||
|
object PlaySoundInVoiceConfSysMsg { val NAME = "PlaySoundInVoiceConfSysMsg" }
|
||||||
|
case class PlaySoundInVoiceConfSysMsg(
|
||||||
|
header: BbbCoreHeaderWithMeetingId,
|
||||||
|
body: PlaySoundInVoiceConfSysMsgBody
|
||||||
|
) extends BbbCoreMsg
|
||||||
|
case class PlaySoundInVoiceConfSysMsgBody(voiceConf: String, voiceUserId: String, soundPath: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send to FS to stop current sound in the voice conference, or specific user
|
||||||
|
*/
|
||||||
|
object StopSoundInVoiceConfSysMsg { val NAME = "StopSoundInVoiceConfSysMsg" }
|
||||||
|
case class StopSoundInVoiceConfSysMsg(
|
||||||
|
header: BbbCoreHeaderWithMeetingId,
|
||||||
|
body: StopSoundInVoiceConfSysMsgBody
|
||||||
|
) extends BbbCoreMsg
|
||||||
|
case class StopSoundInVoiceConfSysMsgBody(voiceConf: String, voiceUserId: String)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Received from FS that voice is being recorded.
|
* Received from FS that voice is being recorded.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user