diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/ScreenshareModel.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/ScreenshareModel.scala index cae06abb02763bff02e2584313f7484d8f9c4e6b..d2de81fe320a7e2ad86a51932053162e11705a60 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/ScreenshareModel.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/ScreenshareModel.scala @@ -16,8 +16,8 @@ object ScreenshareModel { return status.screenshareStarted } - def setScreenshareStarted(status: ScreenshareModel, b: Boolean) { - status.screenshareStarted = b + def setScreenshareStarted(status: ScreenshareModel, started: Boolean) { + status.screenshareStarted = started } def setScreenshareVideoWidth(status: ScreenshareModel, videoWidth: Int) { @@ -37,6 +37,7 @@ object ScreenshareModel { } def broadcastingRTMPStarted(status: ScreenshareModel) { + status.screenshareCountTotal += 1 status.broadcastingRTMP = true } @@ -79,9 +80,12 @@ object ScreenshareModel { def getTimestamp(status: ScreenshareModel): String = { status.timestamp } + + def getscreenshareCountTotal(status: ScreenshareModel): Int = status.screenshareCountTotal } class ScreenshareModel { + private var screenshareCountTotal = 0 private var rtmpBroadcastingUrl: String = "" private var screenshareStarted = false private var screenshareVideoWidth = 0 diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserConnectedToGlobalAudioMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserConnectedToGlobalAudioMsgHdlr.scala index bc938437c07663a8f70a7bc9d6ba1e0bd7518adb..2dd74771ddf00ca77f8d74410dbec9e7436dad9d 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserConnectedToGlobalAudioMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserConnectedToGlobalAudioMsgHdlr.scala @@ -33,7 +33,7 @@ trait UserConnectedToGlobalAudioMsgHdlr { val vu = VoiceUserState( intId = user.intId, voiceUserId = user.intId, - callingWith = "flash", + callingWith = "kms", callerName = user.name, callerNum = user.name, muted = true, diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/RegisteredUsers.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/RegisteredUsers.scala index c009167680c03bc19a158c44e716d8fa730ff579..28cedab9b517744b4330ae42496a50b8d2bd054e 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/RegisteredUsers.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/RegisteredUsers.scala @@ -22,6 +22,8 @@ object RegisteredUsers { ) } + def findAll(users: RegisteredUsers): Vector[RegisteredUser] = users.toVector + def findWithToken(token: String, users: RegisteredUsers): Option[RegisteredUser] = { users.toVector.find(u => u.authToken == token) } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala index 7cf646c2739a02aad668deb72b6eb821d7aefc9b..9d9e7a23c2f942542d45628236ddcf200ffe8f39 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala @@ -9,6 +9,8 @@ object Users2x { } def findAll(users: Users2x): Vector[UserState] = users.toVector + def findAllModerators(users: Users2x): Vector[UserState] = users.toVector.filter(u => u.role == Roles.MODERATOR_ROLE) + def findAllViewers(users: Users2x): Vector[UserState] = users.toVector.filter(u => u.role == Roles.VIEWER_ROLE) def add(users: Users2x, user: UserState): Option[UserState] = { users.save(user) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/VoiceUsers.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/VoiceUsers.scala index ba0783a9df0e9a61b083089c6444e17b3f3f30af..6359a637c9752a32759953459c453231c20006cc 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/VoiceUsers.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/VoiceUsers.scala @@ -14,8 +14,19 @@ object VoiceUsers { def findAll(users: VoiceUsers): Vector[VoiceUserState] = users.toVector def findAllNonListenOnlyVoiceUsers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.listenOnly == false) + def findAllListenOnlyVoiceUsers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.listenOnly == true) + + def findAllFreeswitchListenOnly(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.calledInto == "freeswitch" && u.listenOnly) + 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 findAllDialInUsers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.callingWith == "phone") + + def findTwoWayCallers(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.calledInto == "freeswitch" && !u.listenOnly) + + def findAllMuted(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => u.muted && !u.listenOnly) + + def findAllUnMuted(users: VoiceUsers): Vector[VoiceUserState] = users.toVector.filter(u => !u.muted && !u.listenOnly) def add(users: VoiceUsers, user: VoiceUserState): Unit = { users.save(user) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Webcams.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Webcams.scala index 58eee795a2de98d3af3f0d40e22af25ad1ab206e..cbd9d588ac218c14b5787f16c6a8882868f0a030 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Webcams.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Webcams.scala @@ -9,6 +9,8 @@ object Webcams { webcams.toVector.filter(w => w.stream.userId == userId) } + def findWebcamsCountTotal(webcams: Webcams): Int = webcams.webcamsCountTotal + def findAll(webcams: Webcams): Vector[WebcamStream] = webcams.toVector def addWebcamBroadcastStream(webcams: Webcams, webcamStream: WebcamStream): Option[WebcamStream] = { @@ -33,11 +35,14 @@ object Webcams { } class Webcams { + private var webcamsCountTotal = 0 + private var webcams: collection.immutable.HashMap[String, WebcamStream] = new collection.immutable.HashMap[String, WebcamStream] private def toVector: Vector[WebcamStream] = webcams.values.toVector private def save(webcam: WebcamStream): WebcamStream = { + webcamsCountTotal += 1 webcams += webcam.stream.id -> webcam webcam } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala index e14e30a7e0c4e4e3bd2796d33e77f40a8a82b9d1..5512ff153c6c5a090857fd9ac755475b295bdef2 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala @@ -1,6 +1,6 @@ package org.bigbluebutton.core.running -import java.io.{ PrintWriter, StringWriter } +import java.io.{PrintWriter, StringWriter} import akka.actor._ import akka.actor.SupervisorStrategy.Resume @@ -11,7 +11,7 @@ import org.bigbluebutton.core.apps.users._ import org.bigbluebutton.core.apps.whiteboard.ClientToServerLatencyTracerMsgHdlr import org.bigbluebutton.core.domain._ import org.bigbluebutton.core.util.TimeUtil -import org.bigbluebutton.common2.domain.{ DefaultProps, LockSettingsProps } +import org.bigbluebutton.common2.domain.{DefaultProps, LockSettingsProps, MeetingStatsInfoVO, MeetingStatsVO, ScreenshareStatsVO, UsersCountVO, UsersStatsVO, VoiceUsersListenOnlyStatsVO, VoiceUsersStatsVO, WebcamStatsVO} import org.bigbluebutton.core.api._ import org.bigbluebutton.core.apps._ import org.bigbluebutton.core.apps.caption.CaptionApp2x @@ -23,7 +23,7 @@ import org.bigbluebutton.core.apps.sharednotes.SharedNotesApp2x import org.bigbluebutton.core.apps.whiteboard.WhiteboardApp2x import org.bigbluebutton.core.bus._ import org.bigbluebutton.core.models._ -import org.bigbluebutton.core2.{ MeetingStatus2x, Permissions } +import org.bigbluebutton.core2.{MeetingStatus2x, Permissions} import org.bigbluebutton.core2.message.handlers._ import org.bigbluebutton.core2.message.handlers.meeting._ import org.bigbluebutton.common2.msgs._ @@ -35,9 +35,9 @@ import akka.actor.SupervisorStrategy.Resume import scala.concurrent.duration._ import org.bigbluebutton.core.apps.layout.LayoutApp2x -import org.bigbluebutton.core.apps.meeting.{ SyncGetMeetingInfoRespMsgHdlr, ValidateConnAuthTokenSysMsgHdlr } +import org.bigbluebutton.core.apps.meeting.{SyncGetMeetingInfoRespMsgHdlr, ValidateConnAuthTokenSysMsgHdlr} import org.bigbluebutton.core.apps.users.ChangeLockSettingsInMeetingCmdMsgHdlr -import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender } +import org.bigbluebutton.core2.message.senders.{MsgBuilder, Sender} import scala.concurrent.ExecutionContext.Implicits.global @@ -569,8 +569,73 @@ class MeetingActor( processUserInactivityAudit() flagRegisteredUsersWhoHasNotJoined() checkIfNeetToEndMeetingWhenNoAuthedUsers(liveMeeting) + + if (System.currentTimeMillis - lastsendMeetingStatsData > 5*1000*60) { + sendMeetingStatsData() + } + + } + + var lastsendMeetingStatsData = System.currentTimeMillis + + def sendMeetingStatsData(): Unit = { + lastsendMeetingStatsData = System.currentTimeMillis + + val meetingStatsInfo = MeetingStatsInfoVO( + props.meetingProp, + props.recordProp, + props.metadataProp, + MeetingStatus2x.isRecording(liveMeeting.status) + ) + + val usersCount = UsersCountVO( + Users2x.findAll(liveMeeting.users2x).size, + Users2x.findAllModerators(liveMeeting.users2x).size, + Users2x.findAllViewers(liveMeeting.users2x).size + ) + val usersStats = UsersStatsVO( + registered = RegisteredUsers.findAll(liveMeeting.registeredUsers).size, + usersCount + ) + + val listenOnlyStats = VoiceUsersListenOnlyStatsVO( + total = VoiceUsers.findAllListenOnlyVoiceUsers(liveMeeting.voiceUsers).size, + kurento = VoiceUsers.findAllKurentoCallers(liveMeeting.voiceUsers).size, + freeswitch = VoiceUsers.findAllFreeswitchListenOnly(liveMeeting.voiceUsers).size + ) + + val voiceUsersStats = VoiceUsersStatsVO( + users = VoiceUsers.findAllNonListenOnlyVoiceUsers(liveMeeting.voiceUsers).size, + listenOnly = listenOnlyStats, + twoWayCallers = VoiceUsers.findTwoWayCallers(liveMeeting.voiceUsers).size, + dialIn = VoiceUsers.findAllDialInUsers(liveMeeting.voiceUsers).size, + muted = VoiceUsers.findAllMuted(liveMeeting.voiceUsers).size, + unmuted = VoiceUsers.findAllUnMuted(liveMeeting.voiceUsers).size, + ) + + val webcamStats = WebcamStatsVO( + Webcams.findWebcamsCountTotal(liveMeeting.webcams), + Webcams.findAll(liveMeeting.webcams).size + ) + + val screenshareStats = ScreenshareStatsVO( + ScreenshareModel.getscreenshareCountTotal(liveMeeting.screenshareModel), + ScreenshareModel.getScreenshareStarted(liveMeeting.screenshareModel) + ) + + val meetingStats = MeetingStatsVO( + meetingStatsInfo, + usersStats, + voiceUsersStats, + webcamStats, + screenshareStats + ) + + val event = MsgBuilder.buildMeetingStatsDataSysMsg(meetingStats) + outGW.send(event) } + def checkVoiceConfUsersStatus(): Unit = { val event = MsgBuilder.buildLastcheckVoiceConfUsersStatus( props.meetingProp.intId, 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 d299cf706bb37dc2567f94290b26dba19a63a595..ef353b199cb5982670be6368aa15849cb9a1417d 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 @@ -30,6 +30,7 @@ class AnalyticsActor extends Actor with ActorLogging { def handleBbbCommonEnvCoreMsg(msg: BbbCommonEnvCoreMsg): Unit = { msg.core match { + case m: MeetingStatsDataSysMsg => logMessage(msg) case m: GetAllMeetingsReqMsg => logMessage(msg) case m: RegisterUserReqMsg => logMessage(msg) 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 c24d64e29f0b3995a66b20570adc3d8009d4a61d..74cd9d465070b495461180da7072119ff263d86c 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 @@ -1,6 +1,6 @@ package org.bigbluebutton.core2.message.senders -import org.bigbluebutton.common2.domain.DefaultProps +import org.bigbluebutton.common2.domain.{ DefaultProps, MeetingStatsVO } import org.bigbluebutton.common2.msgs.{ BbbCommonEnvCoreMsg, BbbCoreEnvelope, BbbCoreHeaderWithMeetingId, MessageTypes, Routing, ValidateConnAuthTokenSysRespMsg, ValidateConnAuthTokenSysRespMsgBody, _ } import org.bigbluebutton.core.models.GuestWaiting @@ -344,4 +344,13 @@ object MsgBuilder { val event = RegisteredUserJoinTimeoutMsg(header, body) BbbCommonEnvCoreMsg(envelope, event) } + + def buildMeetingStatsDataSysMsg(stats: MeetingStatsVO): BbbCommonEnvCoreMsg = { + val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka") + val envelope = BbbCoreEnvelope(MeetingStatsDataSysMsg.NAME, routing) + val header = BbbCoreBaseHeader(MeetingStatsDataSysMsg.NAME) + val body = MeetingStatsDataSysMsgBody(stats) + val event = MeetingStatsDataSysMsg(header, body) + BbbCommonEnvCoreMsg(envelope, event) + } } diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ESLEventListener.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ESLEventListener.java index a6a4e60a0c2f02bd090d3a5644fc18545eb1b0e9..90592e307fdff41bcc21ef1294cb3467ff6564f4 100755 --- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ESLEventListener.java +++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ESLEventListener.java @@ -87,6 +87,7 @@ public class ESLEventListener implements IEslEventListener { String origCallerIdName = headers.get("Caller-Caller-ID-Name"); String origCallerDestNumber = headers.get("Caller-Destination-Number"); String clientSession = "0"; + String callingWith = "browser"; Matcher matcher = CALLERNAME_PATTERN.matcher(callerIdName); Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(callerIdName); @@ -102,6 +103,7 @@ public class ESLEventListener implements IEslEventListener { // us to identify the user as such in other parts of the system. // (ralam - sept 1, 2017) voiceUserId = "v_" + memberId.toString(); + callingWith = "phone"; } VoiceCallStateEvent csEvent = new VoiceCallStateEvent( @@ -132,7 +134,7 @@ public class ESLEventListener implements IEslEventListener { callerIdName, muted, speaking, - "none"); + callingWith); conferenceEventListener.handleConferenceEvent(pj); diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/GetAllUsersCommand.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/GetAllUsersCommand.java index 5bf6fae2b4ffa78b60dab872331980a63ea1ccd1..33992cad19e4b2cf58ebe294024e5aa4232a8706 100755 --- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/GetAllUsersCommand.java +++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/GetAllUsersCommand.java @@ -51,7 +51,8 @@ public class GetAllUsersCommand extends FreeswitchCommand { } private static final Pattern CALLERNAME_PATTERN = Pattern.compile("(.*)-bbbID-(.*)$"); - + private static final Pattern CALLERNAME_WITH_SESS_INFO_PATTERN = Pattern.compile("^(.*)_(\\d+)-bbbID-(.*)$"); + public void handleResponse(EslMessage response, ConferenceEventListener eventListener) { //Test for Known Conference @@ -99,16 +100,29 @@ public class GetAllUsersCommand extends FreeswitchCommand { String callerIdName = member.getCallerIdName(); String voiceUserId = callerIdName; String uuid = member.getUUID(); + String callingWith = "browser"; + log.info("Conf user. uuid=" + uuid + ",caller=" + callerIdName + ",callerId=" + callerId + ",conf=" + room); + Matcher matcher = CALLERNAME_PATTERN.matcher(callerIdName); - if (matcher.matches()) { + Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(callerIdName); + if (callWithSess.matches()) { + voiceUserId = callWithSess.group(1).trim(); + callerIdName = callWithSess.group(3).trim(); + } else if (matcher.matches()) { voiceUserId = matcher.group(1).trim(); callerIdName = matcher.group(2).trim(); + } else { + // This is a caller using phone. Let's create a userId that will allow + // us to identify the user as such in other parts of the system. + // (ralam - sept 1, 2017) + voiceUserId = "v_" + member.getId().toString(); + callingWith = "phone"; } VoiceUserJoinedEvent pj = new VoiceUserJoinedEvent(voiceUserId, member.getId().toString(), confXML.getConferenceRoom(), - callerId, callerIdName, member.getMuted(), member.getSpeaking(), "none"); + callerId, callerIdName, member.getMuted(), member.getSpeaking(), callingWith); eventListener.handleConferenceEvent(pj); } else if ("recording_node".equals(member.getMemberType())) { diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/GetUsersStatusCommand.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/GetUsersStatusCommand.java index 6c520c36d9c9fb25c40ab021fdf3e1f4ebc35425..d050b14a8a06be1ad9fe4c64a69dcb39daf5fca9 100755 --- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/GetUsersStatusCommand.java +++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/GetUsersStatusCommand.java @@ -75,6 +75,7 @@ public class GetUsersStatusCommand extends FreeswitchCommand { String voiceUserId = callerIdName; String uuid = member.getUUID(); String clientSession = "0"; + String callingWith = "browser"; Matcher gapMatcher = GLOBAL_AUDION_PATTERN.matcher(callerIdName); // Ignore GLOBAL_AUDIO user. @@ -85,10 +86,15 @@ 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 phone. Let's create a userId that will allow + // us to identify the user as such in other parts of the system. + // (ralam - sept 1, 2017) + voiceUserId = "v_" + member.getId().toString(); + callingWith = "phone"; } log.info("Conf user. uuid=" + uuid @@ -104,7 +110,7 @@ public class GetUsersStatusCommand extends FreeswitchCommand { callerId, callerIdName, member.getMuted(), member.getSpeaking(), - "none"); + callingWith); confMembers.add(confMember); } } else if ("recording_node".equals(member.getMemberType())) { diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Meeting2x.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Meeting2x.scala index 2edcbabaab3256ee3717da0c9e0e85e466c63fc1..f6898ff242663afbb352d641f2ce9a6be5945b8a 100755 --- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Meeting2x.scala +++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Meeting2x.scala @@ -86,3 +86,52 @@ case class UserVO(id: String, externalId: String, name: String, role: String, case class VoiceUserVO(userId: String, webUserId: String, callerName: String, callerNum: String, joined: Boolean, locked: Boolean, muted: Boolean, talking: Boolean, avatarURL: String, listenOnly: Boolean) + +case class UsersCountVO( + users: Int, + moderators: Int, + viewers: Int + ) + +case class UsersStatsVO( + registered: Int, + users: UsersCountVO + ) + +case class VoiceUsersListenOnlyStatsVO( + total: Int, + kurento: Int, + freeswitch: Int, + ) +case class VoiceUsersStatsVO( + users: Int, + listenOnly: VoiceUsersListenOnlyStatsVO, + twoWayCallers: Int, + dialIn: Int, + muted: Int, + unmuted: Int + ) + +case class WebcamStatsVO( + total: Int, + webcams: Int + ) + +case class ScreenshareStatsVO( + total: Int, + isSharing: Boolean + ) + +case class MeetingStatsInfoVO( + meeting: MeetingProp, + record: RecordProp, + metadata: MetadataProp, + isRecording: Boolean + ) +case class MeetingStatsVO( + meeting: MeetingStatsInfoVO, + users: UsersStatsVO, + voice: VoiceUsersStatsVO, + webcams: WebcamStatsVO, + screenshare: ScreenshareStatsVO + ) \ No newline at end of file diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/SystemMsgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/SystemMsgs.scala index 677c475b91c530bb8d157c38c31a38017be28070..d7d7ff7ea7aef87ea10974b6f9f37becc3394205 100755 --- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/SystemMsgs.scala +++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/SystemMsgs.scala @@ -1,6 +1,15 @@ package org.bigbluebutton.common2.msgs -import org.bigbluebutton.common2.domain.DefaultProps +import org.bigbluebutton.common2.domain.{ DefaultProps, MeetingStatsVO } + +object MeetingStatsDataSysMsg { val NAME = "MeetingStatsDataSysMsg" } +case class MeetingStatsDataSysMsg( + header: BbbCoreBaseHeader, + body: MeetingStatsDataSysMsgBody +) extends BbbCoreMsg +case class MeetingStatsDataSysMsgBody( + stats: MeetingStatsVO +) /** Request Messages **/ object CreateMeetingReqMsg { val NAME = "CreateMeetingReqMsg" }