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 ffc94b6bab..6cf879b890 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala
@@ -40,6 +40,7 @@ trait SystemConfiguration {
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(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)
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfEvtMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfEvtMsgHdlr.scala
index 221db4e39a..5ea211ffec 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfEvtMsgHdlr.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfEvtMsgHdlr.scala
@@ -63,6 +63,13 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
val guest = GuestWaiting(msg.body.intId, msg.body.callerIdName, Roles.VIEWER_ROLE, true, "", true, System.currentTimeMillis())
GuestsWaiting.add(liveMeeting.guestsWaiting, guest)
notifyModeratorsOfGuestWaiting(guest, liveMeeting.users2x, liveMeeting.props.meetingProp.intId)
+
+ VoiceApp.toggleUserAudioInVoiceConf(
+ liveMeeting,
+ outGW,
+ msg.body.voiceUserId,
+ false
+ )
}
}
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 54146a56e5..776731fe41 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
@@ -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)
+ }
}
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala
index 126a99f0a5..ca6bc9f171 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala
@@ -65,6 +65,10 @@ class AnalyticsActor(val includeChat: Boolean) extends Actor with ActorLogging {
case m: RecordingStartedVoiceConfEvtMsg => logMessage(msg)
case m: MuteUserCmdMsg => 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: EjectUserFromVoiceCmdMsg => logMessage(msg)
case m: MuteMeetingCmdMsg => logMessage(msg)
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/FromAkkaAppsMsgSenderActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/FromAkkaAppsMsgSenderActor.scala
index 9d46810e4a..15a5fbead9 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/FromAkkaAppsMsgSenderActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/FromAkkaAppsMsgSenderActor.scala
@@ -49,6 +49,14 @@ class FromAkkaAppsMsgSenderActor(msgSender: MessageSender)
msgSender.send(toVoiceConfRedisChannel, json)
case MuteUserInVoiceConfSysMsg.NAME =>
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 =>
msgSender.send(toVoiceConfRedisChannel, json)
case StopRecordingVoiceConfSysMsg.NAME =>
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/guests/GuestsWaitingApprovedMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/guests/GuestsWaitingApprovedMsgHdlr.scala
index ceb53eb1de..afebbae7ce 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/guests/GuestsWaitingApprovedMsgHdlr.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/guests/GuestsWaitingApprovedMsgHdlr.scala
@@ -45,6 +45,23 @@ trait GuestsWaitingApprovedMsgHdlr extends HandlerHelpers with RightsManagementT
false,
"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 {
VoiceApp.removeUserFromVoiceConf(liveMeeting, outGW, dialInUser.extId)
val event = MsgBuilder.buildEjectUserFromVoiceConfSysMsg(liveMeeting.props.meetingProp.intId, liveMeeting.props.voiceProp.voiceConf, g.guest)
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala
index 8b4ce3d073..0b1db206b5 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala
@@ -336,6 +336,46 @@ object MsgBuilder {
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 = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
val envelope = BbbCoreEnvelope(BreakoutRoomEndedEvtMsg.NAME, routing)
diff --git a/akka-bbb-apps/src/universal/conf/application.conf b/akka-bbb-apps/src/universal/conf/application.conf
index f44cfd6062..60ee61d713 100755
--- a/akka-bbb-apps/src/universal/conf/application.conf
+++ b/akka-bbb-apps/src/universal/conf/application.conf
@@ -88,6 +88,10 @@ voiceConf {
syncUserStatusInterval = 41
# Voice users with no matching user record
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 {
diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ConnectionManager.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ConnectionManager.java
index d87f80422e..f66a2e3a69 100755
--- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ConnectionManager.java
+++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ConnectionManager.java
@@ -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) {
Client c = manager.getESLClient();
if (c.canSend()) {
diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/FreeswitchApplication.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/FreeswitchApplication.java
index 90fbcd590c..9acdcc5672 100755
--- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/FreeswitchApplication.java
+++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/FreeswitchApplication.java
@@ -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.GetAllUsersCommand;
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.TransferUserToMeetingCommand;
import org.bigbluebutton.freeswitch.voice.freeswitch.actions.*;
@@ -123,6 +127,26 @@ public class FreeswitchApplication implements IDelayedCommandListener{
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) {
EjectUserCommand mpc = new EjectUserCommand(voiceConfId, voiceUserId, USER);
queueMessage(mpc);
@@ -158,6 +182,18 @@ public class FreeswitchApplication implements IDelayedCommandListener{
} else if (command instanceof MuteUserCommand) {
MuteUserCommand cmd = (MuteUserCommand) command;
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) {
EjectUserCommand cmd = (EjectUserCommand) command;
manager.eject(cmd);
diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/DeafUserCommand.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/DeafUserCommand.java
new file mode 100644
index 0000000000..12c67136bc
--- /dev/null
+++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/DeafUserCommand.java
@@ -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 .
+*
+*/
+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;
+ }
+
+}
diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/HoldUserCommand.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/HoldUserCommand.java
new file mode 100644
index 0000000000..43ec940327
--- /dev/null
+++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/HoldUserCommand.java
@@ -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 .
+*
+*/
+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;
+ }
+
+}
diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/PlaySoundCommand.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/PlaySoundCommand.java
new file mode 100644
index 0000000000..b4aeba0e36
--- /dev/null
+++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/PlaySoundCommand.java
@@ -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 .
+*
+*/
+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;
+ }
+
+}
diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/StopSoundCommand.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/StopSoundCommand.java
new file mode 100644
index 0000000000..0c96fd310c
--- /dev/null
+++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/StopSoundCommand.java
@@ -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 .
+*
+*/
+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;
+ }
+
+}
diff --git a/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgDeserializer.scala b/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgDeserializer.scala
index 5df337fb31..c6557a5317 100755
--- a/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgDeserializer.scala
+++ b/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgDeserializer.scala
@@ -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 deserialize(jsonNode: JsonNode): Option[TransferUserToVoiceConfSysMsg] = {
val (result, error) = JsonDeserializer.toBbbCommonMsg[TransferUserToVoiceConfSysMsg](jsonNode)
diff --git a/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgHdlrActor.scala b/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgHdlrActor.scala
index 0d82974ffd..51a812eca0 100755
--- a/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgHdlrActor.scala
+++ b/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgHdlrActor.scala
@@ -42,6 +42,14 @@ class RxJsonMsgHdlrActor(val fsApp: FreeswitchApplication) extends Actor with Ac
routeEjectUserFromVoiceConfMsg(envelope, jsonNode)
case MuteUserInVoiceConfSysMsg.NAME =>
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 =>
routeTransferUserToVoiceConfMsg(envelope, jsonNode)
case StartRecordingVoiceConfSysMsg.NAME =>
diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/VoiceConfMsgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/VoiceConfMsgs.scala
index 87aabea605..7abc4127c5 100755
--- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/VoiceConfMsgs.scala
+++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/VoiceConfMsgs.scala
@@ -258,6 +258,46 @@ case class MeetingMutedEvtMsg(
) extends BbbCoreMsg
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.
*/