feat(audio): channel threshold for transparent listen only activation
Transparent listen only is currently only worth it for meetings with a number of duplex audio channels larger than a certain value (dependant on system performance). That is due to the fact that global audio bridges created for the mechanism also use significant CPU (roughly the same as an unheld duplex channel), which means it's cost is usually offset only once there are enough potential channels to be held in a conference. This commit adds a new optional feature that introduces some dynamicity for the mechanism: it'll only be triggered after at least @voiceConf.transparentListenOnlyThreshold number of muted duplex audio channels are present in a conference. The default is 0 (always trigger transparent listen only if the general mechanism is activated).
This commit is contained in:
parent
b4a11facd4
commit
e6e1f28036
@ -43,6 +43,7 @@ trait SystemConfiguration {
|
|||||||
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 dialInApprovalAudioPath = Try(config.getString("voiceConf.dialInApprovalAudioPath")).getOrElse("ivr/ivr-please_hold_while_party_contacted.wav")
|
||||||
lazy val toggleListenOnlyAfterMuteTimer = Try(config.getInt("voiceConf.toggleListenOnlyAfterMuteTimer")).getOrElse(4)
|
lazy val toggleListenOnlyAfterMuteTimer = Try(config.getInt("voiceConf.toggleListenOnlyAfterMuteTimer")).getOrElse(4)
|
||||||
|
lazy val transparentListenOnlyThreshold = Try(config.getInt("voiceConf.transparentListenOnlyThreshold")).getOrElse(0)
|
||||||
|
|
||||||
lazy val recordingChapterBreakLengthInMinutes = Try(config.getInt("recording.chapterBreakLengthInMinutes")).getOrElse(0)
|
lazy val recordingChapterBreakLengthInMinutes = Try(config.getInt("recording.chapterBreakLengthInMinutes")).getOrElse(0)
|
||||||
|
|
||||||
|
@ -260,7 +260,7 @@ object VoiceApp extends SystemConfiguration {
|
|||||||
callingInto: String,
|
callingInto: String,
|
||||||
hold: Boolean,
|
hold: Boolean,
|
||||||
uuid: String = "unused"
|
uuid: String = "unused"
|
||||||
): Unit = {
|
)(implicit context: akka.actor.ActorContext): Unit = {
|
||||||
|
|
||||||
def broadcastEvent(voiceUserState: VoiceUserState): Unit = {
|
def broadcastEvent(voiceUserState: VoiceUserState): Unit = {
|
||||||
val routing = Routing.addMsgToClientRouting(
|
val routing = Routing.addMsgToClientRouting(
|
||||||
@ -323,8 +323,28 @@ object VoiceApp extends SystemConfiguration {
|
|||||||
hold,
|
hold,
|
||||||
uuid
|
uuid
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val prevTransparentLOStatus = VoiceHdlrHelpers.transparentListenOnlyAllowed(
|
||||||
|
liveMeeting
|
||||||
|
)
|
||||||
|
|
||||||
VoiceUsers.add(liveMeeting.voiceUsers, voiceUserState)
|
VoiceUsers.add(liveMeeting.voiceUsers, voiceUserState)
|
||||||
|
|
||||||
|
val newTransparentLOStatus = VoiceHdlrHelpers.transparentListenOnlyAllowed(
|
||||||
|
liveMeeting
|
||||||
|
)
|
||||||
|
|
||||||
|
if (prevTransparentLOStatus != newTransparentLOStatus) {
|
||||||
|
// If the transparent listen only mode was activated or deactivated
|
||||||
|
// we need to update the listen only mode for all users in the meeting
|
||||||
|
// that are not muted.
|
||||||
|
handleTransparentLOModeChange(
|
||||||
|
liveMeeting,
|
||||||
|
outGW,
|
||||||
|
newTransparentLOStatus
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
broadcastEvent(voiceUserState)
|
broadcastEvent(voiceUserState)
|
||||||
|
|
||||||
if (liveMeeting.props.meetingProp.isBreakout) {
|
if (liveMeeting.props.meetingProp.isBreakout) {
|
||||||
@ -473,6 +493,22 @@ object VoiceApp extends SystemConfiguration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def handleTransparentLOModeChange(
|
||||||
|
liveMeeting: LiveMeeting,
|
||||||
|
outGW: OutMsgRouter,
|
||||||
|
allowed: Boolean,
|
||||||
|
)(implicit context: akka.actor.ActorContext): Unit = {
|
||||||
|
VoiceUsers.findAllMutedVoiceUsers(liveMeeting.voiceUsers) foreach { vu =>
|
||||||
|
toggleListenOnlyMode(
|
||||||
|
liveMeeting,
|
||||||
|
outGW,
|
||||||
|
vu.intId,
|
||||||
|
vu.callerNum,
|
||||||
|
allowed
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def toggleListenOnlyMode(
|
def toggleListenOnlyMode(
|
||||||
liveMeeting: LiveMeeting,
|
liveMeeting: LiveMeeting,
|
||||||
outGW: OutMsgRouter,
|
outGW: OutMsgRouter,
|
||||||
@ -482,6 +518,16 @@ object VoiceApp extends SystemConfiguration {
|
|||||||
delay: Int = 0
|
delay: Int = 0
|
||||||
)(implicit context: ActorContext): Unit = {
|
)(implicit context: ActorContext): Unit = {
|
||||||
implicit def executionContext = context.system.dispatcher
|
implicit def executionContext = context.system.dispatcher
|
||||||
|
val allowed = VoiceHdlrHelpers.transparentListenOnlyAllowed(liveMeeting)
|
||||||
|
// Guarantee there are no other tasks for this channel
|
||||||
|
removeToggleListenOnlyTask(userId)
|
||||||
|
|
||||||
|
// If the meeting has not yet hit the minium amount of duplex channels
|
||||||
|
// for transparent listen only to be enabled, we don't need to do anything
|
||||||
|
if (!allowed && enabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
def broacastEvent(): Unit = {
|
def broacastEvent(): Unit = {
|
||||||
val event = MsgBuilder.buildToggleListenOnlyModeSysMsg(
|
val event = MsgBuilder.buildToggleListenOnlyModeSysMsg(
|
||||||
liveMeeting.props.meetingProp.intId,
|
liveMeeting.props.meetingProp.intId,
|
||||||
@ -493,9 +539,6 @@ object VoiceApp extends SystemConfiguration {
|
|||||||
outGW.send(event)
|
outGW.send(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Guarantee there are no other tasks for this channel
|
|
||||||
removeToggleListenOnlyTask(userId)
|
|
||||||
|
|
||||||
if (enabled && delay > 0) {
|
if (enabled && delay > 0) {
|
||||||
// If we are enabling listen only mode, we wait a bit before actually
|
// If we are enabling listen only mode, we wait a bit before actually
|
||||||
// dispatching the command - the idea is that recently muted users
|
// dispatching the command - the idea is that recently muted users
|
||||||
|
@ -50,4 +50,14 @@ object VoiceHdlrHelpers extends SystemConfiguration {
|
|||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def transparentListenOnlyAllowed(liveMeeting: LiveMeeting): Boolean = {
|
||||||
|
// Transparent listen only meeting-wide activation threshold.
|
||||||
|
// Threshold is the number of muted duplex audio channels in a meeting.
|
||||||
|
// 0 means no threshold, all users are subject to it
|
||||||
|
val mutedDuplexChannels = VoiceUsers.findAllMutedVoiceUsers(liveMeeting.voiceUsers).length
|
||||||
|
val threshold = transparentListenOnlyThreshold
|
||||||
|
|
||||||
|
(threshold == 0) || (mutedDuplexChannels >= threshold)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ object VoiceUsers {
|
|||||||
def findAllListenOnlyVoiceUsers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.listenOnly == true)
|
def findAllListenOnlyVoiceUsers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.listenOnly == true)
|
||||||
def findAllFreeswitchCallers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.calledInto == "freeswitch")
|
def findAllFreeswitchCallers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.calledInto == "freeswitch")
|
||||||
def findAllKurentoCallers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.calledInto == "kms")
|
def findAllKurentoCallers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.calledInto == "kms")
|
||||||
|
def findAllMutedVoiceUsers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.muted == true && u.listenOnly == false)
|
||||||
|
|
||||||
def findAllBannedCallers(users: VoiceUsers): Vector[VoiceUserState] = users.bannedUsers.values.toVector
|
def findAllBannedCallers(users: VoiceUsers): Vector[VoiceUserState] = users.bannedUsers.values.toVector
|
||||||
|
|
||||||
|
@ -97,6 +97,11 @@ voiceConf {
|
|||||||
# Time (seconds) to wait before requesting an audio channel hold after
|
# Time (seconds) to wait before requesting an audio channel hold after
|
||||||
# muting a user. Used in the experimental, transparent listen only mode.
|
# muting a user. Used in the experimental, transparent listen only mode.
|
||||||
toggleListenOnlyAfterMuteTimer = 4
|
toggleListenOnlyAfterMuteTimer = 4
|
||||||
|
|
||||||
|
# Transparent listen only meeting-wide activation threshold.
|
||||||
|
# Threshold is the number of muted duplex audio channels in a meeting.
|
||||||
|
# 0 = disabled
|
||||||
|
transparentListenOnlyThreshold = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
recording {
|
recording {
|
||||||
|
Loading…
Reference in New Issue
Block a user