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 4e43561515..e1f9f483fc 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/LockSettingsUtil.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/LockSettingsUtil.scala @@ -3,7 +3,7 @@ package org.bigbluebutton import org.bigbluebutton.common2.msgs.{ BbbCommonEnvCoreMsg, BbbCoreEnvelope, BbbCoreHeaderWithMeetingId, MessageTypes, MuteUserInVoiceConfSysMsg, MuteUserInVoiceConfSysMsgBody, Routing } import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter } import org.bigbluebutton.core2.{ MeetingStatus2x } -import org.bigbluebutton.core2.message.senders.MsgBuilder +import org.bigbluebutton.core.apps.webcam.CameraHdlrHelpers import org.bigbluebutton.core.models.{ Roles, Users2x, @@ -75,15 +75,6 @@ object LockSettingsUtil { } } - private def requestBroadcastedCamEjection( - meetingId: String, userId: String, streamId: String, outGW: OutMsgRouter - ): Unit = { - val event = MsgBuilder.buildCamBroadcastStopSysMsg( - meetingId, userId, streamId - ) - outGW.send(event) - } - def isCameraBroadcastLocked(user: UserState, liveMeeting: LiveMeeting): Boolean = { val permissions = MeetingStatus2x.getPermissions(liveMeeting.status) @@ -94,10 +85,9 @@ object LockSettingsUtil { user: UserState, stream: WebcamStream, liveMeeting: LiveMeeting ): Boolean = { var locked = false - val publisherUserId: String = stream.stream.userId for { - publisher <- Users2x.findWithIntId(liveMeeting.users2x, publisherUserId) + publisher <- Users2x.findWithIntId(liveMeeting.users2x, stream.userId) } yield { if (MeetingStatus2x.webcamsOnlyForModeratorEnabled(liveMeeting.status) && publisher.role != Roles.MODERATOR_ROLE @@ -110,29 +100,18 @@ object LockSettingsUtil { locked } - private def requestCamSubscriptionEjection( - meetingId: String, userId: String, streamId: String, outGW: OutMsgRouter - ): Unit = { - val event = MsgBuilder.buildCamStreamUnsubscribeSysMsg( - meetingId, userId, streamId - ) - outGW.send(event) - } - private def enforceSeeOtherViewersForUser( user: UserState, liveMeeting: LiveMeeting, outGW: OutMsgRouter ): Unit = { if (MeetingStatus2x.webcamsOnlyForModeratorEnabled(liveMeeting.status)) { Webcams.findAll(liveMeeting.webcams) foreach { webcam => - val streamId = webcam.stream.id - val userId = user.intId if (isCameraSubscribeLocked(user, webcam, liveMeeting) - && Webcams.isViewingWebcam(liveMeeting.webcams, user.intId, webcam.stream.id)) { - requestCamSubscriptionEjection( + && Webcams.isSubscriber(liveMeeting.webcams, user.intId, webcam.streamId)) { + CameraHdlrHelpers.requestCamSubscriptionEjection( liveMeeting.props.meetingProp.intId, - userId, - streamId, + user.intId, + webcam.streamId, outGW ) } @@ -146,10 +125,10 @@ object LockSettingsUtil { if (isCameraBroadcastLocked(user, liveMeeting)) { val broadcastedWebcams = Webcams.findWebcamsForUser(liveMeeting.webcams, user.intId) broadcastedWebcams foreach { webcam => - requestBroadcastedCamEjection( + CameraHdlrHelpers.requestBroadcastedCamEjection( liveMeeting.props.meetingProp.intId, user.intId, - webcam.stream.id, + webcam.streamId, outGW ) } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/GetCamBroadcastPermissionReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/GetCamBroadcastPermissionReqMsgHdlr.scala deleted file mode 100755 index fc512beded..0000000000 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/GetCamBroadcastPermissionReqMsgHdlr.scala +++ /dev/null @@ -1,29 +0,0 @@ -package org.bigbluebutton.core2.message.handlers - -import org.bigbluebutton.common2.msgs._ -import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } -import org.bigbluebutton.core2.message.senders.MsgBuilder - -trait GetCamBroadcastPermissionReqMsgHdlr { - this: MeetingActor => - - val outGW: OutMsgRouter - - def handleGetCamBroadcastPermissionReqMsg(msg: GetCamBroadcastPermissionReqMsg) { - val allowed = CameraHdlrHelpers.isCameraBroadcastAllowed( - liveMeeting, - msg.body.meetingId, - msg.body.userId, - msg.body.streamId - ) - - val event = MsgBuilder.buildGetCamBroadcastPermissionRespMsg( - liveMeeting.props.meetingProp.intId, - msg.body.userId, - msg.body.streamId, - msg.body.sfuSessionId, - allowed - ) - outGW.send(event) - } -} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/GetCamSubscribePermissionReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/GetCamSubscribePermissionReqMsgHdlr.scala deleted file mode 100755 index 9ce75b04ce..0000000000 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/GetCamSubscribePermissionReqMsgHdlr.scala +++ /dev/null @@ -1,36 +0,0 @@ -package org.bigbluebutton.core2.message.handlers - -import org.bigbluebutton.common2.msgs._ -import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } -import org.bigbluebutton.core.models.{ Webcams } -import org.bigbluebutton.core2.message.senders.MsgBuilder - -trait GetCamSubscribePermissionReqMsgHdlr { - this: MeetingActor => - - val outGW: OutMsgRouter - - def handleGetCamSubscribePermissionReqMsg(msg: GetCamSubscribePermissionReqMsg) { - var allowed = false - - for { - stream <- Webcams.findWithStreamId(liveMeeting.webcams, msg.body.streamId) - } yield { - allowed = CameraHdlrHelpers.isCameraSubscribeAllowed( - liveMeeting, - msg.body.meetingId, - msg.body.userId, - stream - ) - } - - val event = MsgBuilder.buildGetCamSubscribePermissionRespMsg( - liveMeeting.props.meetingProp.intId, - msg.body.userId, - msg.body.streamId, - msg.body.sfuSessionId, - allowed - ) - outGW.send(event) - } -} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/GetUsersMeetingReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/GetUsersMeetingReqMsgHdlr.scala index a1aaa97b59..350c6c68cf 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/GetUsersMeetingReqMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/GetUsersMeetingReqMsgHdlr.scala @@ -12,6 +12,5 @@ trait GetUsersMeetingReqMsgHdlr extends HandlerHelpers { def handleGetUsersMeetingReqMsg(msg: GetUsersMeetingReqMsg): Unit = { sendAllUsersInMeeting(msg.body.userId) sendAllVoiceUsersInMeeting(msg.body.userId, liveMeeting.voiceUsers, liveMeeting.props.meetingProp.intId) - sendAllWebcamStreams(outGW, msg.body.userId, liveMeeting.webcams, liveMeeting.props.meetingProp.intId) } } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/GetWebcamsOnlyForModeratorReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/GetWebcamsOnlyForModeratorReqMsgHdlr.scala deleted file mode 100644 index 8f626f74b9..0000000000 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/GetWebcamsOnlyForModeratorReqMsgHdlr.scala +++ /dev/null @@ -1,29 +0,0 @@ -package org.bigbluebutton.core.apps.users - -import org.bigbluebutton.common2.msgs._ -import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter } -import org.bigbluebutton.core2.MeetingStatus2x - -trait GetWebcamsOnlyForModeratorReqMsgHdlr { - this: UsersApp => - - val liveMeeting: LiveMeeting - val outGW: OutMsgRouter - - def handleGetWebcamsOnlyForModeratorReqMsg(msg: GetWebcamsOnlyForModeratorReqMsg) { - - def buildGetWebcamsOnlyForModeratorRespMsg(meetingId: String, userId: String, webcamsOnlyForModerator: Boolean): BbbCommonEnvCoreMsg = { - val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, userId) - val envelope = BbbCoreEnvelope(GetWebcamsOnlyForModeratorRespMsg.NAME, routing) - val body = GetWebcamsOnlyForModeratorRespMsgBody(webcamsOnlyForModerator, userId) - val header = BbbClientMsgHeader(GetWebcamsOnlyForModeratorRespMsg.NAME, meetingId, userId) - val event = GetWebcamsOnlyForModeratorRespMsg(header, body) - - BbbCommonEnvCoreMsg(envelope, event) - } - - val event = buildGetWebcamsOnlyForModeratorRespMsg(liveMeeting.props.meetingProp.intId, msg.body.requestedBy, - MeetingStatus2x.webcamsOnlyForModeratorEnabled(liveMeeting.status)) - outGW.send(event) - } -} \ No newline at end of file diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UpdateWebcamsOnlyForModeratorCmdMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UpdateWebcamsOnlyForModeratorCmdMsgHdlr.scala deleted file mode 100644 index 800e6f1d74..0000000000 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UpdateWebcamsOnlyForModeratorCmdMsgHdlr.scala +++ /dev/null @@ -1,41 +0,0 @@ -package org.bigbluebutton.core.apps.users - -import org.bigbluebutton.common2.msgs._ -import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter } -import org.bigbluebutton.core2.MeetingStatus2x -import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } -import org.bigbluebutton.LockSettingsUtil - -trait UpdateWebcamsOnlyForModeratorCmdMsgHdlr extends RightsManagementTrait { - this: UsersApp => - - val liveMeeting: LiveMeeting - val outGW: OutMsgRouter - - def handleUpdateWebcamsOnlyForModeratorCmdMsg(msg: UpdateWebcamsOnlyForModeratorCmdMsg) { - - if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId) || liveMeeting.props.meetingProp.isBreakout) { - val meetingId = liveMeeting.props.meetingProp.intId - val reason = "No permission to change lock settings" - PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting) - } else { - if (MeetingStatus2x.webcamsOnlyForModeratorEnabled(liveMeeting.status) != msg.body.webcamsOnlyForModerator) { - log.info("Change webcams only for moderator status. meetingId=" + liveMeeting.props.meetingProp.intId + " webcamsOnlyForModeratorrecording=" + msg.body.webcamsOnlyForModerator) - MeetingStatus2x.setWebcamsOnlyForModerator(liveMeeting.status, msg.body.webcamsOnlyForModerator) - LockSettingsUtil.enforceCamLockSettingsForAllUsers(liveMeeting, outGW) - val event = buildWebcamsOnlyForModeratorChangedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.setBy, msg.body.webcamsOnlyForModerator) - outGW.send(event) - } - } - - def buildWebcamsOnlyForModeratorChangedEvtMsg(meetingId: String, userId: String, webcamsOnlyForModerator: Boolean): BbbCommonEnvCoreMsg = { - val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId) - val envelope = BbbCoreEnvelope(WebcamsOnlyForModeratorChangedEvtMsg.NAME, routing) - val body = WebcamsOnlyForModeratorChangedEvtMsgBody(webcamsOnlyForModerator, userId) - val header = BbbClientMsgHeader(WebcamsOnlyForModeratorChangedEvtMsg.NAME, meetingId, userId) - val event = WebcamsOnlyForModeratorChangedEvtMsg(header, body) - - BbbCommonEnvCoreMsg(envelope, event) - } - } -} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserBroadcastCamStartMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserBroadcastCamStartMsgHdlr.scala deleted file mode 100755 index f2c0133323..0000000000 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserBroadcastCamStartMsgHdlr.scala +++ /dev/null @@ -1,47 +0,0 @@ -package org.bigbluebutton.core.apps.users - -import org.bigbluebutton.common2.msgs._ -import org.bigbluebutton.core2.message.handlers.{ CameraHdlrHelpers } -import org.bigbluebutton.core.models.{ MediaStream, WebcamStream, Webcams } -import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } -import org.bigbluebutton.core.apps.PermissionCheck - -trait UserBroadcastCamStartMsgHdlr { - this: MeetingActor => - - val outGW: OutMsgRouter - - def handleUserBroadcastCamStartMsg(msg: UserBroadcastCamStartMsg): Unit = { - def broadcastEvent(msg: UserBroadcastCamStartMsg): Unit = { - val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId, msg.header.userId) - val envelope = BbbCoreEnvelope(UserBroadcastCamStartedEvtMsg.NAME, routing) - val header = BbbClientMsgHeader(UserBroadcastCamStartedEvtMsg.NAME, props.meetingProp.intId, msg.header.userId) - - val body = UserBroadcastCamStartedEvtMsgBody(msg.header.userId, msg.body.stream) - val event = UserBroadcastCamStartedEvtMsg(header, body) - val msgEvent = BbbCommonEnvCoreMsg(envelope, event) - outGW.send(msgEvent) - } - - val allowed = CameraHdlrHelpers.isCameraBroadcastAllowed( - liveMeeting, - msg.header.meetingId, - msg.header.userId, - msg.body.stream - ) - - if (!allowed) { - val reason = "No permission to share camera." - PermissionCheck.ejectUserForFailedPermission(props.meetingProp.intId, msg.header.userId, reason, outGW, liveMeeting) - } else { - val stream = new MediaStream(msg.body.stream, msg.body.stream, msg.header.userId, Map.empty, Set.empty) - val webcamStream = new WebcamStream(msg.body.stream, stream) - - for { - uvo <- Webcams.addWebcamBroadcastStream(liveMeeting.webcams, webcamStream) - } yield { - broadcastEvent(msg) - } - } - } -} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserBroadcastCamStopMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserBroadcastCamStopMsgHdlr.scala deleted file mode 100755 index a2ca22e350..0000000000 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserBroadcastCamStopMsgHdlr.scala +++ /dev/null @@ -1,36 +0,0 @@ -package org.bigbluebutton.core.apps.users - -import org.bigbluebutton.common2.msgs._ -import org.bigbluebutton.core.models.Webcams -import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } -import org.bigbluebutton.core.apps.PermissionCheck -import org.bigbluebutton.core2.message.senders.MsgBuilder - -trait UserBroadcastCamStopMsgHdlr { - this: MeetingActor => - - val outGW: OutMsgRouter - - def handleUserBroadcastCamStopMsg(msg: UserBroadcastCamStopMsg): Unit = { - for { - publisherStream <- Webcams.findWithStreamId(liveMeeting.webcams, msg.body.stream) - } yield { - if (publisherStream.stream.userId != msg.header.userId - || !msg.body.stream.startsWith(msg.header.userId)) { - val reason = "User does not own camera stream" - PermissionCheck.ejectUserForFailedPermission( - props.meetingProp.intId, msg.header.userId, reason, outGW, liveMeeting - ) - } else { - for { - _ <- Webcams.removeWebcamBroadcastStream(liveMeeting.webcams, msg.body.stream) - } yield { - val event = MsgBuilder.buildUserBroadcastCamStoppedEvtMsg( - props.meetingProp.intId, msg.header.userId, msg.body.stream - ) - outGW.send(event) - } - } - } - } -} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala index e875c1e1d2..b61bb97189 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala @@ -165,16 +165,13 @@ class UsersApp( with SetRecordingStatusCmdMsgHdlr with RecordAndClearPreviousMarkersCmdMsgHdlr with SendRecordingTimerInternalMsgHdlr - with UpdateWebcamsOnlyForModeratorCmdMsgHdlr with GetRecordingStatusReqMsgHdlr with SelectRandomViewerReqMsgHdlr - with GetWebcamsOnlyForModeratorReqMsgHdlr with AssignPresenterReqMsgHdlr with ChangeUserPinStateReqMsgHdlr with EjectDuplicateUserReqMsgHdlr with EjectUserFromMeetingCmdMsgHdlr with EjectUserFromMeetingSysMsgHdlr - with SyncGetWebcamInfoRespMsgHdlr with MuteUserCmdMsgHdlr { val log = Logging(context.system, getClass) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/CamBroadcastStoppedInSfuEvtMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/CamBroadcastStoppedInSfuEvtMsgHdlr.scala new file mode 100644 index 0000000000..033cb1544c --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/CamBroadcastStoppedInSfuEvtMsgHdlr.scala @@ -0,0 +1,29 @@ +package org.bigbluebutton.core.apps.webcam + +import org.bigbluebutton.common2.msgs._ +import org.bigbluebutton.core.apps.PermissionCheck +import org.bigbluebutton.core.bus.MessageBus +import org.bigbluebutton.core.models.Webcams +import org.bigbluebutton.core.running.LiveMeeting + +trait CamBroadcastStoppedInSfuEvtMsgHdlr { + this: WebcamApp2x => + + def handle( + msg: CamBroadcastStoppedInSfuEvtMsg, + liveMeeting: LiveMeeting, + bus: MessageBus + ): Unit = { + val meetingId = liveMeeting.props.meetingProp.intId + val userId = msg.header.userId + val streamId = msg.body.streamId + + CameraHdlrHelpers.stopBroadcastedCam( + liveMeeting, + meetingId, + userId, + streamId, + bus.outGW + ) + } +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/CamStreamSubscribedInSfuEvtMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/CamStreamSubscribedInSfuEvtMsgHdlr.scala new file mode 100644 index 0000000000..2408648c2e --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/CamStreamSubscribedInSfuEvtMsgHdlr.scala @@ -0,0 +1,36 @@ +package org.bigbluebutton.core.apps.webcam + +import org.bigbluebutton.common2.msgs._ +import org.bigbluebutton.core.bus.MessageBus +import org.bigbluebutton.core.models.Webcams +import org.bigbluebutton.core.running.LiveMeeting + +trait CamStreamSubscribedInSfuEvtMsgHdlr { + this: WebcamApp2x => + + def handle( + msg: CamStreamSubscribedInSfuEvtMsg, + liveMeeting: LiveMeeting, + bus: MessageBus + ) { + val meetingId = liveMeeting.props.meetingProp.intId + + val allowed = CameraHdlrHelpers.isCameraSubscribeAllowed( + liveMeeting, + meetingId, + msg.header.userId, + msg.body.streamId + ) + + if (allowed) { + Webcams.addSubscriber(liveMeeting.webcams, msg.body.streamId, msg.header.userId) + } else { + CameraHdlrHelpers.requestCamSubscriptionEjection( + meetingId, + msg.header.userId, + msg.body.streamId, + bus.outGW + ) + } + } +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/CamStreamUnsubscribedInSfuEvtMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/CamStreamUnsubscribedInSfuEvtMsgHdlr.scala new file mode 100644 index 0000000000..fc9f257c08 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/CamStreamUnsubscribedInSfuEvtMsgHdlr.scala @@ -0,0 +1,23 @@ +package org.bigbluebutton.core.apps.webcam + +import org.bigbluebutton.common2.msgs._ +import org.bigbluebutton.core.bus.MessageBus +import org.bigbluebutton.core.models.Webcams +import org.bigbluebutton.core.running.LiveMeeting + +trait CamStreamUnsubscribedInSfuEvtMsgHdlr { + this: WebcamApp2x => + + def handle( + msg: CamStreamUnsubscribedInSfuEvtMsg, + liveMeeting: LiveMeeting, + bus: MessageBus + ) { + + Webcams.removeSubscriber( + liveMeeting.webcams, + msg.body.streamId, + msg.header.userId + ) + } +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/CameraHdlrHelpers.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/CameraHdlrHelpers.scala new file mode 100644 index 0000000000..4a95706c2c --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/CameraHdlrHelpers.scala @@ -0,0 +1,194 @@ +package org.bigbluebutton.core.apps.webcam + +import org.bigbluebutton.common2.msgs._ +import org.bigbluebutton.LockSettingsUtil +import org.bigbluebutton.SystemConfiguration +import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } +import org.bigbluebutton.core.models.{ Users2x, Webcams, WebcamStream } +import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter } +import org.bigbluebutton.core2.MeetingStatus2x + +object CameraHdlrHelpers extends SystemConfiguration with RightsManagementTrait { + def isCameraBroadcastAllowed( + liveMeeting: LiveMeeting, + meetingId: String, + userId: String, + streamId: String + ): Boolean = { + Users2x.findWithIntId(liveMeeting.users2x, userId) match { + case Some(user) => { + val camBroadcastLocked = LockSettingsUtil.isCameraBroadcastLocked(user, liveMeeting) + val camCapReached = hasReachedCameraCap(liveMeeting, userId) + + (applyPermissionCheck && + !camBroadcastLocked && + !camCapReached && + !user.userLeftFlag.left && + streamId.startsWith(user.intId) && + liveMeeting.props.meetingProp.intId == meetingId) + } + case _ => false + } + } + + def isCameraSubscribeAllowed( + liveMeeting: LiveMeeting, + meetingId: String, + userId: String, + stream: WebcamStream + ): Boolean = { + Users2x.findWithIntId(liveMeeting.users2x, userId) match { + case Some(user) => { + val camSubscribeLocked = LockSettingsUtil.isCameraSubscribeLocked(user, stream, liveMeeting) + + (applyPermissionCheck && + !camSubscribeLocked && + !user.userLeftFlag.left && + liveMeeting.props.meetingProp.intId == meetingId) + } + case _ => false + } + } + + def isCameraSubscribeAllowed( + liveMeeting: LiveMeeting, + meetingId: String, + userId: String, + streamId: String + ): Boolean = { + Webcams.findWithStreamId(liveMeeting.webcams, streamId) match { + case Some(stream) => isCameraSubscribeAllowed(liveMeeting, meetingId, userId, stream) + case _ => false + } + } + + def isCameraEjectAllowed( + liveMeeting: LiveMeeting, + userId: String + ): Boolean = { + val allowModsToEjectCameras = liveMeeting.props.usersProp.allowModsToEjectCameras + val isBreakout = liveMeeting.props.meetingProp.isBreakout + val hasPermission = !permissionFailed( + PermissionCheck.MOD_LEVEL, + PermissionCheck.VIEWER_LEVEL, + liveMeeting.users2x, + userId + ) + + (allowModsToEjectCameras && + !isBreakout && + hasPermission) + } + + def isWebcamsOnlyForModeratorUpdateAllowed( + liveMeeting: LiveMeeting, + userId: String + ): Boolean = { + val isBreakout = liveMeeting.props.meetingProp.isBreakout + val hasPermission = !permissionFailed( + PermissionCheck.MOD_LEVEL, + PermissionCheck.VIEWER_LEVEL, + liveMeeting.users2x, + userId + ) + + (!isBreakout && hasPermission) + } + + def updateWebcamsOnlyForModerator( + liveMeeting: LiveMeeting, + value: Boolean, + outGW: OutMsgRouter + ): Option[Boolean] = { + MeetingStatus2x.webcamsOnlyForModeratorEnabled(liveMeeting.status) match { + case x if x != value => { + MeetingStatus2x.setWebcamsOnlyForModerator(liveMeeting.status, value) + LockSettingsUtil.enforceCamLockSettingsForAllUsers(liveMeeting, outGW) + Some(value) + } + case _ => None + } + } + + def hasReachedCameraCap( + liveMeeting: LiveMeeting, + userId: String + ): Boolean = { + val cameras = Webcams.findWebcamsForUser(liveMeeting.webcams, userId).length + + liveMeeting.props.usersProp.userCameraCap match { + case 0 => false // disabled + case x if x > cameras => false + case _ => true + } + } + + def stopBroadcastedCam( + liveMeeting: LiveMeeting, + meetingId: String, + userId: String, + streamId: String, + outGW: OutMsgRouter + ): Unit = { + + def broadcastEvent(meetingId: String, userId: String, streamId: String) { + val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId) + val envelope = BbbCoreEnvelope(UserBroadcastCamStoppedEvtMsg.NAME, routing) + val header = BbbClientMsgHeader(UserBroadcastCamStoppedEvtMsg.NAME, meetingId, userId) + val body = UserBroadcastCamStoppedEvtMsgBody(userId, streamId) + val event = UserBroadcastCamStoppedEvtMsg(header, body) + val msgEvent = BbbCommonEnvCoreMsg(envelope, event) + + outGW.send(msgEvent) + } + + if (Webcams.hasWebcamStream(liveMeeting.webcams, streamId)) { + if (Webcams.isPublisher(liveMeeting.webcams, userId, streamId)) { + for { + _ <- Webcams.removeWebcamStream(liveMeeting.webcams, streamId) + } yield broadcastEvent(meetingId, userId, streamId) + } else { + val reason = "User does not own camera stream" + PermissionCheck.ejectUserForFailedPermission( + meetingId, + userId, + reason, + outGW, + liveMeeting + ) + } + } + } + + def requestBroadcastedCamEjection( + meetingId: String, + userId: String, + streamId: String, + outGW: OutMsgRouter + ): Unit = { + val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka") + val envelope = BbbCoreEnvelope(CamBroadcastStopSysMsg.NAME, routing) + val body = CamBroadcastStopSysMsgBody(meetingId, userId, streamId) + val header = BbbCoreBaseHeader(CamBroadcastStopSysMsg.NAME) + val event = CamBroadcastStopSysMsg(header, body) + val msgEvent = BbbCommonEnvCoreMsg(envelope, event) + + outGW.send(msgEvent) + } + + def requestCamSubscriptionEjection( + meetingId: String, + userId: String, + streamId: String, + outGW: OutMsgRouter + ): Unit = { + val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka") + val envelope = BbbCoreEnvelope(CamStreamUnsubscribeSysMsg.NAME, routing) + val body = CamStreamUnsubscribeSysMsgBody(meetingId, userId, streamId) + val header = BbbCoreBaseHeader(CamStreamUnsubscribeSysMsg.NAME) + val event = CamStreamUnsubscribeSysMsg(header, body) + val msgEvent = BbbCommonEnvCoreMsg(envelope, event) + + outGW.send(msgEvent) + } +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/EjectUserCamerasCmdMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/EjectUserCamerasCmdMsgHdlr.scala new file mode 100644 index 0000000000..e2f65e1f31 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/EjectUserCamerasCmdMsgHdlr.scala @@ -0,0 +1,48 @@ +package org.bigbluebutton.core.apps.webcam + +import org.bigbluebutton.common2.msgs._ +import org.bigbluebutton.core.apps.PermissionCheck +import org.bigbluebutton.core.bus.MessageBus +import org.bigbluebutton.core.models.Webcams +import org.bigbluebutton.core.running.LiveMeeting + +trait EjectUserCamerasCmdMsgHdlr { + this: WebcamApp2x => + + def handle( + msg: EjectUserCamerasCmdMsg, + liveMeeting: LiveMeeting, + bus: MessageBus + ): Unit = { + val meetingId = liveMeeting.props.meetingProp.intId + val requesterUserId = msg.header.userId + val userId = msg.body.userId + + val allow = CameraHdlrHelpers.isCameraEjectAllowed( + liveMeeting, + requesterUserId + ) + + if (!allow) { + val reason = "No permission to eject cameras from user." + PermissionCheck.ejectUserForFailedPermission( + meetingId, + requesterUserId, + reason, + bus.outGW, + liveMeeting + ) + } else { + log.info(s"Ejecting user cameras. meetingId=${meetingId} userId=${userId} requesterUserId=${requesterUserId}") + Webcams.findWebcamsForUser(liveMeeting.webcams, userId) foreach { webcam => + // Goes to SFU and comes back through CamBroadcastStoppedInSfuEvtMsg + CameraHdlrHelpers.requestBroadcastedCamEjection( + meetingId, + userId, + webcam.streamId, + bus.outGW + ) + } + } + } +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/GetCamBroadcastPermissionReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/GetCamBroadcastPermissionReqMsgHdlr.scala new file mode 100644 index 0000000000..f4e61a4626 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/GetCamBroadcastPermissionReqMsgHdlr.scala @@ -0,0 +1,55 @@ +package org.bigbluebutton.core.apps.webcam + +import org.bigbluebutton.common2.msgs._ +import org.bigbluebutton.core.bus.MessageBus +import org.bigbluebutton.core.running.LiveMeeting + +trait GetCamBroadcastPermissionReqMsgHdlr { + this: WebcamApp2x => + + def handle( + msg: GetCamBroadcastPermissionReqMsg, + liveMeeting: LiveMeeting, + bus: MessageBus + ) { + val meetingId = liveMeeting.props.meetingProp.intId + + def broadcastEvent( + meetingId: String, + userId: String, + streamId: String, + sfuSessionId: String, + allowed: Boolean + ) { + val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, userId) + val envelope = BbbCoreEnvelope(GetCamBroadcastPermissionRespMsg.NAME, routing) + val header = BbbClientMsgHeader(GetCamBroadcastPermissionRespMsg.NAME, meetingId, userId) + val body = GetCamBroadcastPermissionRespMsgBody( + meetingId, + userId, + streamId, + sfuSessionId, + allowed + ) + val event = GetCamBroadcastPermissionRespMsg(header, body) + val msgEvent = BbbCommonEnvCoreMsg(envelope, event) + + bus.outGW.send(msgEvent) + } + + val allowed = CameraHdlrHelpers.isCameraBroadcastAllowed( + liveMeeting, + meetingId, + msg.body.userId, + msg.body.streamId + ) + + broadcastEvent( + meetingId, + msg.body.userId, + msg.body.streamId, + msg.body.sfuSessionId, + allowed + ) + } +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/GetCamSubscribePermissionReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/GetCamSubscribePermissionReqMsgHdlr.scala new file mode 100644 index 0000000000..2301a280f7 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/GetCamSubscribePermissionReqMsgHdlr.scala @@ -0,0 +1,55 @@ +package org.bigbluebutton.core.apps.webcam + +import org.bigbluebutton.common2.msgs._ +import org.bigbluebutton.core.bus.MessageBus +import org.bigbluebutton.core.running.LiveMeeting + +trait GetCamSubscribePermissionReqMsgHdlr { + this: WebcamApp2x => + + def handle( + msg: GetCamSubscribePermissionReqMsg, + liveMeeting: LiveMeeting, + bus: MessageBus + ) { + val meetingId = liveMeeting.props.meetingProp.intId + + def broadcastEvent( + meetingId: String, + userId: String, + streamId: String, + sfuSessionId: String, + allowed: Boolean + ) { + val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, userId) + val envelope = BbbCoreEnvelope(GetCamSubscribePermissionRespMsg.NAME, routing) + val header = BbbClientMsgHeader(GetCamSubscribePermissionRespMsg.NAME, meetingId, userId) + val body = GetCamSubscribePermissionRespMsgBody( + meetingId, + userId, + streamId, + sfuSessionId, + allowed + ) + val event = GetCamSubscribePermissionRespMsg(header, body) + val msgEvent = BbbCommonEnvCoreMsg(envelope, event) + + bus.outGW.send(msgEvent) + } + + val allowed = CameraHdlrHelpers.isCameraSubscribeAllowed( + liveMeeting, + meetingId, + msg.body.userId, + msg.body.streamId + ) + + broadcastEvent( + meetingId, + msg.body.userId, + msg.body.streamId, + msg.body.sfuSessionId, + allowed + ) + } +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/GetWebcamsOnlyForModeratorReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/GetWebcamsOnlyForModeratorReqMsgHdlr.scala new file mode 100644 index 0000000000..21afe564e9 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/GetWebcamsOnlyForModeratorReqMsgHdlr.scala @@ -0,0 +1,33 @@ +package org.bigbluebutton.core.apps.webcam + +import org.bigbluebutton.common2.msgs._ +import org.bigbluebutton.core.bus.MessageBus +import org.bigbluebutton.core.running.LiveMeeting +import org.bigbluebutton.core2.MeetingStatus2x + +trait GetWebcamsOnlyForModeratorReqMsgHdlr { + this: WebcamApp2x => + + def handle( + msg: GetWebcamsOnlyForModeratorReqMsg, + liveMeeting: LiveMeeting, + bus: MessageBus + ) { + val meetingId = liveMeeting.props.meetingProp.intId + + def broadcastEvent(meetingId: String, userId: String, webcamsOnlyForModerator: Boolean) { + val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, userId) + val envelope = BbbCoreEnvelope(GetWebcamsOnlyForModeratorRespMsg.NAME, routing) + val body = GetWebcamsOnlyForModeratorRespMsgBody(webcamsOnlyForModerator, userId) + val header = BbbClientMsgHeader(GetWebcamsOnlyForModeratorRespMsg.NAME, meetingId, userId) + val event = GetWebcamsOnlyForModeratorRespMsg(header, body) + val msgEvent = BbbCommonEnvCoreMsg(envelope, event) + + bus.outGW.send(msgEvent) + } + + val webcamsOnlyForModerator = MeetingStatus2x.webcamsOnlyForModeratorEnabled(liveMeeting.status) + + broadcastEvent(meetingId, msg.body.requestedBy, webcamsOnlyForModerator) + } +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/SyncGetWebcamInfoRespMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/SyncGetWebcamInfoRespMsgHdlr.scala similarity index 75% rename from akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/SyncGetWebcamInfoRespMsgHdlr.scala rename to akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/SyncGetWebcamInfoRespMsgHdlr.scala index 24ead08a8d..a485b157a2 100644 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/SyncGetWebcamInfoRespMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/SyncGetWebcamInfoRespMsgHdlr.scala @@ -1,16 +1,16 @@ -package org.bigbluebutton.core.apps.users +package org.bigbluebutton.core.apps.webcam import org.bigbluebutton.common2.msgs._ +import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.models.{ Users2x, VoiceUsers, Webcams } -import org.bigbluebutton.core.bus.MessageBus import org.bigbluebutton.core.running.LiveMeeting trait SyncGetWebcamInfoRespMsgHdlr { - this: UsersApp => + this: WebcamApp2x => def handleSyncGetWebcamInfoRespMsg(liveMeeting: LiveMeeting, bus: MessageBus): Unit = { val routing = Routing.addMsgToHtml5InstanceIdRouting( @@ -25,22 +25,20 @@ trait SyncGetWebcamInfoRespMsgHdlr { ) val webcamsList = Webcams.findAll(liveMeeting.webcams) flatMap { webcam => - val stream = webcam.stream.id - val userId = webcam.stream.userId + val streamId = webcam.streamId + val userId = webcam.userId val pin = Users2x.isPin(userId, liveMeeting.users2x) for { u <- Users2x.findWithIntId(liveMeeting.users2x, userId) } yield { VoiceUsers.findWIthIntId(liveMeeting.voiceUsers, userId) match { - case Some(vu) => WebcamStreamInfo(stream, userId, u.name, pin, vu.floor, vu.lastFloorTime) - case _ => WebcamStreamInfo(stream, userId, u.name, pin, false, "0") + case Some(vu) => WebcamStreamInfo(streamId, userId, u.name, pin, vu.floor, vu.lastFloorTime) + case _ => WebcamStreamInfo(streamId, userId, u.name, pin, false, "0") } } } - val body = SyncGetWebcamInfoRespMsgBody( - webcamsList - ) + val body = SyncGetWebcamInfoRespMsgBody(webcamsList) val event = SyncGetWebcamInfoRespMsg(header, body) val msgEvent = BbbCommonEnvCoreMsg(envelope, event) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/UpdateWebcamsOnlyForModeratorCmdMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/UpdateWebcamsOnlyForModeratorCmdMsgHdlr.scala new file mode 100644 index 0000000000..c524fdd0ea --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/UpdateWebcamsOnlyForModeratorCmdMsgHdlr.scala @@ -0,0 +1,57 @@ +package org.bigbluebutton.core.apps.webcam + +import org.bigbluebutton.common2.msgs._ +import org.bigbluebutton.core.apps.PermissionCheck +import org.bigbluebutton.core.bus.MessageBus +import org.bigbluebutton.core.running.LiveMeeting + +trait UpdateWebcamsOnlyForModeratorCmdMsgHdlr { + this: WebcamApp2x => + + def handle( + msg: UpdateWebcamsOnlyForModeratorCmdMsg, + liveMeeting: LiveMeeting, + bus: MessageBus + ) { + val meetingId = liveMeeting.props.meetingProp.intId + + def broadcastEvent(meetingId: String, userId: String, webcamsOnlyForModerator: Boolean) { + val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId) + val envelope = BbbCoreEnvelope(WebcamsOnlyForModeratorChangedEvtMsg.NAME, routing) + val body = WebcamsOnlyForModeratorChangedEvtMsgBody(webcamsOnlyForModerator, userId) + val header = BbbClientMsgHeader(WebcamsOnlyForModeratorChangedEvtMsg.NAME, meetingId, userId) + val event = WebcamsOnlyForModeratorChangedEvtMsg(header, body) + val msgEvent = BbbCommonEnvCoreMsg(envelope, event) + + bus.outGW.send(msgEvent) + } + + val allow = CameraHdlrHelpers.isWebcamsOnlyForModeratorUpdateAllowed( + liveMeeting, + msg.header.userId + ) + + if (!allow) { + val reason = "No permission to change lock settings" + PermissionCheck.ejectUserForFailedPermission( + meetingId, + msg.header.userId, + reason, + bus.outGW, + liveMeeting + ) + } else { + CameraHdlrHelpers.updateWebcamsOnlyForModerator( + liveMeeting, + msg.body.webcamsOnlyForModerator, + bus.outGW + ) match { + case Some(value) => { + log.info(s"Change webcams only for moderator status. meetingId=${meetingId} value=${value}") + broadcastEvent(meetingId, msg.body.setBy, value) + } + case _ => + } + } + } +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/UserBroadcastCamStartMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/UserBroadcastCamStartMsgHdlr.scala new file mode 100644 index 0000000000..c8478c6ee2 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/UserBroadcastCamStartMsgHdlr.scala @@ -0,0 +1,54 @@ +package org.bigbluebutton.core.apps.webcam + +import org.bigbluebutton.common2.msgs._ +import org.bigbluebutton.core.apps.PermissionCheck +import org.bigbluebutton.core.bus.MessageBus +import org.bigbluebutton.core.models.{ WebcamStream, Webcams } +import org.bigbluebutton.core.running.LiveMeeting + +trait UserBroadcastCamStartMsgHdlr { + this: WebcamApp2x => + + def handle( + msg: UserBroadcastCamStartMsg, + liveMeeting: LiveMeeting, + bus: MessageBus + ): Unit = { + val meetingId = liveMeeting.props.meetingProp.intId + + def broadcastEvent(meetingId: String, userId: String, streamId: String): Unit = { + val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId) + val envelope = BbbCoreEnvelope(UserBroadcastCamStartedEvtMsg.NAME, routing) + val header = BbbClientMsgHeader(UserBroadcastCamStartedEvtMsg.NAME, meetingId, userId) + val body = UserBroadcastCamStartedEvtMsgBody(userId, streamId) + val event = UserBroadcastCamStartedEvtMsg(header, body) + val msgEvent = BbbCommonEnvCoreMsg(envelope, event) + + bus.outGW.send(msgEvent) + } + + val allowed = CameraHdlrHelpers.isCameraBroadcastAllowed( + liveMeeting, + msg.header.meetingId, + msg.header.userId, + msg.body.stream + ) + + if (!allowed) { + val reason = "No permission to share camera." + PermissionCheck.ejectUserForFailedPermission( + meetingId, + msg.header.userId, + reason, + bus.outGW, + liveMeeting + ) + } else { + val webcam = new WebcamStream(msg.body.stream, msg.header.userId, Set.empty) + + for { + _ <- Webcams.addWebcamStream(liveMeeting.webcams, webcam) + } yield broadcastEvent(meetingId, msg.header.userId, msg.body.stream) + } + } +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/UserBroadcastCamStopMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/UserBroadcastCamStopMsgHdlr.scala new file mode 100644 index 0000000000..65082005d0 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/UserBroadcastCamStopMsgHdlr.scala @@ -0,0 +1,29 @@ +package org.bigbluebutton.core.apps.webcam + +import org.bigbluebutton.common2.msgs._ +import org.bigbluebutton.core.apps.PermissionCheck +import org.bigbluebutton.core.bus.MessageBus +import org.bigbluebutton.core.models.Webcams +import org.bigbluebutton.core.running.LiveMeeting + +trait UserBroadcastCamStopMsgHdlr { + this: WebcamApp2x => + + def handle( + msg: UserBroadcastCamStopMsg, + liveMeeting: LiveMeeting, + bus: MessageBus + ): Unit = { + val meetingId = liveMeeting.props.meetingProp.intId + val userId = msg.header.userId + val streamId = msg.body.stream + + CameraHdlrHelpers.stopBroadcastedCam( + liveMeeting, + meetingId, + userId, + streamId, + bus.outGW + ) + } +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/WebcamApp2x.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/WebcamApp2x.scala new file mode 100644 index 0000000000..9dc619331a --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/webcam/WebcamApp2x.scala @@ -0,0 +1,20 @@ +package org.bigbluebutton.core.apps.webcam + +import akka.actor.ActorContext +import akka.event.Logging + +class WebcamApp2x(implicit val context: ActorContext) + extends CamBroadcastStoppedInSfuEvtMsgHdlr + with CamStreamSubscribedInSfuEvtMsgHdlr + with CamStreamUnsubscribedInSfuEvtMsgHdlr + with EjectUserCamerasCmdMsgHdlr + with GetCamBroadcastPermissionReqMsgHdlr + with GetCamSubscribePermissionReqMsgHdlr + with GetWebcamsOnlyForModeratorReqMsgHdlr + with SyncGetWebcamInfoRespMsgHdlr + with UpdateWebcamsOnlyForModeratorCmdMsgHdlr + with UserBroadcastCamStartMsgHdlr + with UserBroadcastCamStopMsgHdlr { + + val log = Logging(context.system, getClass) +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Streams.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Streams.scala deleted file mode 100755 index e802c78216..0000000000 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Streams.scala +++ /dev/null @@ -1,22 +0,0 @@ -package org.bigbluebutton.core.models - -import com.softwaremill.quicklens._ - -trait Streams { - - def addViewer(stream: MediaStream, user: String): MediaStream = { - val newViewers = stream.viewers + user - modify(stream)(_.viewers).setTo(newViewers) - } - - def removeViewer(stream: MediaStream, user: String): MediaStream = { - val newViewers = stream.viewers - user - modify(stream)(_.viewers).setTo(newViewers) - } -} - -/** - * Borrow some ideas from SDP for attributes. - * https://en.wikipedia.org/wiki/Session_Description_Protocol - */ -case class MediaStream(id: String, url: String, userId: String, attributes: collection.immutable.Map[String, String], viewers: Set[String]) 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 22a4864b27..075849b56d 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 @@ -1,97 +1,93 @@ package org.bigbluebutton.core.models -import com.softwaremill.quicklens._ +import collection.immutable.HashMap object Webcams { def findWithStreamId(webcams: Webcams, streamId: String): Option[WebcamStream] = { - webcams.toVector.find(w => w.stream.id == streamId) + webcams.toVector.find(webcam => webcam.streamId == streamId) } def findWebcamsForUser(webcams: Webcams, userId: String): Vector[WebcamStream] = { - webcams.toVector.filter(w => w.stream.userId == userId) + webcams.toVector.filter(webcam => webcam.userId == userId) } def findAll(webcams: Webcams): Vector[WebcamStream] = webcams.toVector - def addWebcamBroadcastStream(webcams: Webcams, webcamStream: WebcamStream): Option[WebcamStream] = { - - findWithStreamId(webcams, webcamStream.streamId) match { - case Some(p) => { - None - } - case None => { - webcams.save(webcamStream) - Some(webcamStream) - } + def addWebcamStream(webcams: Webcams, webcam: WebcamStream): Option[WebcamStream] = { + findWithStreamId(webcams, webcam.streamId) match { + case None => Some(webcams.save(webcam)) + case _ => None } } - def removeWebcamBroadcastStream(webcams: Webcams, streamId: String): Option[WebcamStream] = { + def removeWebcamStream(webcams: Webcams, streamId: String): Option[WebcamStream] = { for { - stream <- findWithStreamId(webcams, streamId) - removedStream <- webcams.remove(streamId) - } yield removedStream + webcam <- webcams.remove(streamId) + } yield webcam } - def addViewer(webcams: Webcams, streamId: String, subscriberId: String): Unit = { - for { - webcamStream <- findWithStreamId(webcams, streamId) - } yield { - val mediaStream = webcamStream.stream - if (!mediaStream.viewers.contains(subscriberId)) { - val newViewers = mediaStream.viewers + subscriberId - webcams.updateViewers(webcamStream, newViewers) - } - } - } - - def removeViewer(webcams: Webcams, streamId: String, subscriberId: String): Unit = { - for { - webcamStream <- findWithStreamId(webcams, streamId) - } yield { - val mediaStream = webcamStream.stream - if (mediaStream.viewers.contains(subscriberId)) { - val newViewers = mediaStream.viewers - subscriberId - webcams.updateViewers(webcamStream, newViewers) - } - } - } - - def isViewingWebcam(webcams: Webcams, userId: String, streamId: String): Boolean = { + def hasWebcamStream(webcams: Webcams, streamId: String): Boolean = { findWithStreamId(webcams, streamId) match { - case Some(webcam) => { - val viewing = webcam.stream.viewers contains userId - viewing - } - case None => { - false - } + case Some(webcam) => true + case _ => false + } + } + + def addSubscriber(webcams: Webcams, streamId: String, userId: String): Unit = { + findWithStreamId(webcams, streamId) match { + case Some(webcam) => webcams.addSubscriber(webcam, userId) + case _ => + } + } + + def removeSubscriber(webcams: Webcams, streamId: String, userId: String): Unit = { + findWithStreamId(webcams, streamId) match { + case Some(webcam) => webcams.removeSubscriber(webcam, userId) + case _ => + } + } + + def isSubscriber(webcams: Webcams, userId: String, streamId: String): Boolean = { + findWithStreamId(webcams, streamId) match { + case Some(webcam) => webcam.subscribers contains userId + case None => false + } + } + + def isPublisher(webcams: Webcams, userId: String, streamId: String): Boolean = { + findWithStreamId(webcams, streamId) match { + case Some(webcam) => webcam.userId == userId && webcam.streamId.startsWith(userId) + case None => false } } } class Webcams { - private var webcams: collection.immutable.HashMap[String, WebcamStream] = new collection.immutable.HashMap[String, WebcamStream] + private var webcams: HashMap[String, WebcamStream] = new HashMap[String, WebcamStream] private def toVector: Vector[WebcamStream] = webcams.values.toVector private def save(webcam: WebcamStream): WebcamStream = { - webcams += webcam.stream.id -> webcam + webcams += webcam.streamId -> webcam webcam } private def remove(streamId: String): Option[WebcamStream] = { - val webcam = webcams.get(streamId) - webcam foreach (u => webcams -= streamId) - webcam + for { + webcam <- webcams.get(streamId) + } yield { + webcams -= streamId + webcam + } } - private def updateViewers(webcamStream: WebcamStream, viewers: Set[String]): WebcamStream = { - val mediaStream: MediaStream = webcamStream.stream - val newMediaStream = mediaStream.modify(_.viewers).setTo(viewers) - val newWebcamStream = webcamStream.modify(_.stream).setTo(newMediaStream) - save(newWebcamStream) + private def addSubscriber(webcam: WebcamStream, userId: String): Unit = { + save(webcam.copy(subscribers = webcam.subscribers + userId)) + } + + private def removeSubscriber(webcam: WebcamStream, userId: String): Unit = { + save(webcam.copy(subscribers = webcam.subscribers - userId)) } } -case class WebcamStream(streamId: String, stream: MediaStream) +case class WebcamStream(streamId: String, userId: String, subscribers: Set[String]) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala index 09215e9143..f0575ea23a 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala @@ -147,6 +147,10 @@ class ReceivedJsonMsgHandlerActor( routeGenericMsg[CamBroadcastStoppedInSfuEvtMsg](envelope, jsonNode) case EjectUserCamerasCmdMsg.NAME => routeGenericMsg[EjectUserCamerasCmdMsg](envelope, jsonNode) + case GetWebcamsOnlyForModeratorReqMsg.NAME => + routeGenericMsg[GetWebcamsOnlyForModeratorReqMsg](envelope, jsonNode) + case UpdateWebcamsOnlyForModeratorCmdMsg.NAME => + routeGenericMsg[UpdateWebcamsOnlyForModeratorCmdMsg](envelope, jsonNode) // Pads case PadCreateGroupReqMsg.NAME => @@ -338,10 +342,6 @@ class ReceivedJsonMsgHandlerActor( routeGenericMsg[GetRecordingStatusReqMsg](envelope, jsonNode) case GetScreenshareStatusReqMsg.NAME => routeGenericMsg[GetScreenshareStatusReqMsg](envelope, jsonNode) - case GetWebcamsOnlyForModeratorReqMsg.NAME => - routeGenericMsg[GetWebcamsOnlyForModeratorReqMsg](envelope, jsonNode) - case UpdateWebcamsOnlyForModeratorCmdMsg.NAME => - routeGenericMsg[UpdateWebcamsOnlyForModeratorCmdMsg](envelope, jsonNode) // Lock settings case LockUserInMeetingCmdMsg.NAME => diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala index 496a415d32..a0bdcafb45 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala @@ -15,19 +15,6 @@ import org.bigbluebutton.core.util.TimeUtil trait HandlerHelpers extends SystemConfiguration { - def sendAllWebcamStreams(outGW: OutMsgRouter, requesterId: String, webcams: Webcams, meetingId: String): Unit = { - val streams = org.bigbluebutton.core.models.Webcams.findAll(webcams) - val webcamStreams = streams.map { u => - val msVO = MediaStreamVO(id = u.stream.id, url = u.stream.url, userId = u.stream.userId, - attributes = u.stream.attributes, viewers = u.stream.viewers) - - WebcamStreamVO(streamId = msVO.id, stream = msVO) - } - - val event = MsgBuilder.buildGetWebcamStreamsMeetingRespMsg(meetingId, requesterId, webcamStreams) - outGW.send(event) - } - def trackUserJoin( outGW: OutMsgRouter, liveMeeting: LiveMeeting, 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 e69bfa31e3..b6656e3f88 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 @@ -20,6 +20,7 @@ import org.bigbluebutton.core.apps.pads.PadsApp2x import org.bigbluebutton.core.apps.screenshare.ScreenshareApp2x import org.bigbluebutton.core.apps.presentation.PresentationApp2x import org.bigbluebutton.core.apps.users.UsersApp2x +import org.bigbluebutton.core.apps.webcam.WebcamApp2x import org.bigbluebutton.core.apps.whiteboard.WhiteboardApp2x import org.bigbluebutton.core.bus._ import org.bigbluebutton.core.models.{ Users2x, VoiceUsers, _ } @@ -71,10 +72,8 @@ class MeetingActor( with BreakoutApp2x with UsersApp2x - with UserBroadcastCamStartMsgHdlr with UserJoinMeetingReqMsgHdlr with UserJoinMeetingAfterReconnectReqMsgHdlr - with UserBroadcastCamStopMsgHdlr with UserConnectedToGlobalAudioMsgHdlr with UserDisconnectedFromGlobalAudioMsgHdlr with MuteAllExceptPresentersCmdMsgHdlr @@ -83,12 +82,6 @@ class MeetingActor( with GetGlobalAudioPermissionReqMsgHdlr with GetScreenBroadcastPermissionReqMsgHdlr with GetScreenSubscribePermissionReqMsgHdlr - with GetCamBroadcastPermissionReqMsgHdlr - with GetCamSubscribePermissionReqMsgHdlr - with CamStreamSubscribedInSfuEvtMsgHdlr - with CamStreamUnsubscribedInSfuEvtMsgHdlr - with CamBroadcastStoppedInSfuEvtMsgHdlr - with EjectUserCamerasCmdMsgHdlr with EjectUserFromVoiceCmdMsgHdlr with EndMeetingSysCmdMsgHdlr @@ -138,6 +131,7 @@ class MeetingActor( val groupChatApp = new GroupChatHdlrs val presentationPodsApp = new PresentationPodHdlrs val pollApp = new PollApp2x + val webcamApp2x = new WebcamApp2x val wbApp = new WhiteboardApp2x object ExpiryTrackerHelper extends MeetingExpiryTrackerHelper @@ -376,14 +370,6 @@ class MeetingActor( case m: UserLeaveReqMsg => state = handleUserLeaveReqMsg(m, state) updateModeratorsPresence() - case m: UserBroadcastCamStartMsg => handleUserBroadcastCamStartMsg(m) - case m: UserBroadcastCamStopMsg => handleUserBroadcastCamStopMsg(m) - case m: GetCamBroadcastPermissionReqMsg => handleGetCamBroadcastPermissionReqMsg(m) - case m: GetCamSubscribePermissionReqMsg => handleGetCamSubscribePermissionReqMsg(m) - case m: CamStreamSubscribedInSfuEvtMsg => handleCamStreamSubscribedInSfuEvtMsg(m) - case m: CamStreamUnsubscribedInSfuEvtMsg => handleCamStreamUnsubscribedInSfuEvtMsg(m) - case m: CamBroadcastStoppedInSfuEvtMsg => handleCamBroadcastStoppedInSfuEvtMsg(m) - case m: EjectUserCamerasCmdMsg => handleEjectUserCamerasCmdMsg(m) case m: UserJoinedVoiceConfEvtMsg => handleUserJoinedVoiceConfEvtMsg(m) case m: LogoutAndEndMeetingCmdMsg => usersApp.handleLogoutAndEndMeetingCmdMsg(m, state) @@ -393,8 +379,6 @@ class MeetingActor( case m: RecordAndClearPreviousMarkersCmdMsg => state = usersApp.handleRecordAndClearPreviousMarkersCmdMsg(m, state) updateUserLastActivity(m.body.setBy) - case m: GetWebcamsOnlyForModeratorReqMsg => usersApp.handleGetWebcamsOnlyForModeratorReqMsg(m) - case m: UpdateWebcamsOnlyForModeratorCmdMsg => usersApp.handleUpdateWebcamsOnlyForModeratorCmdMsg(m) case m: GetRecordingStatusReqMsg => usersApp.handleGetRecordingStatusReqMsg(m) case m: ChangeUserEmojiCmdMsg => handleChangeUserEmojiCmdMsg(m) case m: SelectRandomViewerReqMsg => usersApp.handleSelectRandomViewerReqMsg(m) @@ -573,6 +557,18 @@ class MeetingActor( state = groupChatApp.handle(m, state, liveMeeting, msgBus) updateUserLastActivity(m.body.msg.sender.id) + // Webcams + case m: UserBroadcastCamStartMsg => webcamApp2x.handle(m, liveMeeting, msgBus) + case m: UserBroadcastCamStopMsg => webcamApp2x.handle(m, liveMeeting, msgBus) + case m: GetCamBroadcastPermissionReqMsg => webcamApp2x.handle(m, liveMeeting, msgBus) + case m: GetCamSubscribePermissionReqMsg => webcamApp2x.handle(m, liveMeeting, msgBus) + case m: CamStreamSubscribedInSfuEvtMsg => webcamApp2x.handle(m, liveMeeting, msgBus) + case m: CamStreamUnsubscribedInSfuEvtMsg => webcamApp2x.handle(m, liveMeeting, msgBus) + case m: CamBroadcastStoppedInSfuEvtMsg => webcamApp2x.handle(m, liveMeeting, msgBus) + case m: EjectUserCamerasCmdMsg => webcamApp2x.handle(m, liveMeeting, msgBus) + case m: GetWebcamsOnlyForModeratorReqMsg => webcamApp2x.handle(m, liveMeeting, msgBus) + case m: UpdateWebcamsOnlyForModeratorCmdMsg => webcamApp2x.handle(m, liveMeeting, msgBus) + // ExternalVideo case m: StartExternalVideoPubMsg => externalVideoApp2x.handle(m, liveMeeting, msgBus) case m: UpdateExternalVideoPubMsg => externalVideoApp2x.handle(m, liveMeeting, msgBus) @@ -633,11 +629,11 @@ class MeetingActor( val liveWebcams: Vector[org.bigbluebutton.core.models.WebcamStream] = findAll(liveMeeting.webcams) val numOfLiveWebcams: Int = liveWebcams.length val broadcasts: List[Broadcast] = liveWebcams.map(webcam => Broadcast( - webcam.stream.id, - User(webcam.stream.userId, resolveUserName(webcam.stream.userId)), 0L + webcam.streamId, + User(webcam.userId, resolveUserName(webcam.userId)), 0L )).toList - val viewers: Set[String] = liveWebcams.flatMap(_.stream.viewers).toSet - val webcamStream: msgs.WebcamStream = msgs.WebcamStream(broadcasts, viewers) + val subscribers: Set[String] = liveWebcams.flatMap(_.subscribers).toSet + val webcamStream: msgs.WebcamStream = msgs.WebcamStream(broadcasts, subscribers) Webcam(numOfLiveWebcams, webcamStream) } @@ -700,7 +696,7 @@ class MeetingActor( screenshareApp2x.handleSyncGetScreenshareInfoRespMsg(liveMeeting, msgBus) // send all webcam info - usersApp.handleSyncGetWebcamInfoRespMsg(liveMeeting, msgBus) + webcamApp2x.handleSyncGetWebcamInfoRespMsg(liveMeeting, msgBus) } def handleGetAllMeetingsReqMsg(msg: GetAllMeetingsReqMsg): Unit = { diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/CameraHdlrHelpers.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/CameraHdlrHelpers.scala deleted file mode 100644 index b4f41e92d4..0000000000 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/CameraHdlrHelpers.scala +++ /dev/null @@ -1,62 +0,0 @@ -package org.bigbluebutton.core2.message.handlers - -import org.bigbluebutton.SystemConfiguration -import org.bigbluebutton.core.running.{ LiveMeeting } -import org.bigbluebutton.core.models.{ Users2x, Webcams, WebcamStream } -import org.bigbluebutton.LockSettingsUtil - -object CameraHdlrHelpers extends SystemConfiguration { - def isCameraBroadcastAllowed( - liveMeeting: LiveMeeting, - meetingId: String, - userId: String, - streamId: String - ): Boolean = { - Users2x.findWithIntId(liveMeeting.users2x, userId) match { - case Some(user) => { - val camBroadcastLocked = LockSettingsUtil.isCameraBroadcastLocked(user, liveMeeting) - val camCapReached = hasReachedCameraCap(liveMeeting, userId) - - (applyPermissionCheck && - !camBroadcastLocked && - !camCapReached && - !user.userLeftFlag.left && - streamId.startsWith(user.intId) && - liveMeeting.props.meetingProp.intId == meetingId) - } - case _ => false - } - } - - def isCameraSubscribeAllowed( - liveMeeting: LiveMeeting, - meetingId: String, - userId: String, - stream: WebcamStream - ): Boolean = { - Users2x.findWithIntId(liveMeeting.users2x, userId) match { - case Some(user) => { - val camSubscribeLocked = LockSettingsUtil.isCameraSubscribeLocked(user, stream, liveMeeting) - - (applyPermissionCheck && - !camSubscribeLocked && - !user.userLeftFlag.left && - liveMeeting.props.meetingProp.intId == meetingId) - } - case _ => false - } - } - - def hasReachedCameraCap( - liveMeeting: LiveMeeting, - userId: String - ): Boolean = { - val cameras = Webcams.findWebcamsForUser(liveMeeting.webcams, userId).length - - liveMeeting.props.usersProp.userCameraCap match { - case 0 => false // disabled - case x if x > cameras => false - case _ => true - } - } -} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/streams/CamBroadcastStoppedInSfuEvtMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/streams/CamBroadcastStoppedInSfuEvtMsgHdlr.scala deleted file mode 100644 index 8a1f7f734a..0000000000 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/streams/CamBroadcastStoppedInSfuEvtMsgHdlr.scala +++ /dev/null @@ -1,36 +0,0 @@ -package org.bigbluebutton.core.apps.users - -import org.bigbluebutton.common2.msgs._ -import org.bigbluebutton.core.models.Webcams -import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } -import org.bigbluebutton.core.apps.PermissionCheck -import org.bigbluebutton.core2.message.senders.MsgBuilder - -trait CamBroadcastStoppedInSfuEvtMsgHdlr { - this: MeetingActor => - - val outGW: OutMsgRouter - - def handleCamBroadcastStoppedInSfuEvtMsg(msg: CamBroadcastStoppedInSfuEvtMsg): Unit = { - for { - publisherStream <- Webcams.findWithStreamId(liveMeeting.webcams, msg.body.streamId) - } yield { - if (publisherStream.stream.userId != msg.header.userId - || !msg.body.streamId.startsWith(msg.header.userId)) { - val reason = "User does not own camera stream" - PermissionCheck.ejectUserForFailedPermission( - props.meetingProp.intId, msg.header.userId, reason, outGW, liveMeeting - ) - } else { - for { - _ <- Webcams.removeWebcamBroadcastStream(liveMeeting.webcams, msg.body.streamId) - } yield { - val event = MsgBuilder.buildUserBroadcastCamStoppedEvtMsg( - props.meetingProp.intId, msg.header.userId, msg.body.streamId - ) - outGW.send(event) - } - } - } - } -} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/streams/CamStreamSubscribedInSfuEvtMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/streams/CamStreamSubscribedInSfuEvtMsgHdlr.scala deleted file mode 100644 index 605b40a8d8..0000000000 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/streams/CamStreamSubscribedInSfuEvtMsgHdlr.scala +++ /dev/null @@ -1,50 +0,0 @@ -package org.bigbluebutton.core2.message.handlers - -import org.bigbluebutton.common2.msgs._ -import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } -import org.bigbluebutton.core.models.{ Users2x } -import org.bigbluebutton.core.models.Webcams.{ findWithStreamId, addViewer } -import org.bigbluebutton.core2.message.senders.MsgBuilder -import org.bigbluebutton.LockSettingsUtil - -trait CamStreamSubscribedInSfuEvtMsgHdlr { - this: MeetingActor => - - val outGW: OutMsgRouter - - def isAllowedToSubscribeToCam(userId: String, streamId: String): Boolean = { - var allowed = false - - for { - user <- Users2x.findWithIntId(liveMeeting.users2x, userId) - stream <- findWithStreamId(liveMeeting.webcams, streamId) - } yield { - val camSubscribeLocked = LockSettingsUtil.isCameraSubscribeLocked(user, stream, liveMeeting) - if (!user.userLeftFlag.left - && (applyPermissionCheck && !camSubscribeLocked)) { - allowed = true - } - } - - allowed - } - - def handleCamStreamSubscribedInSfuEvtMsg(msg: CamStreamSubscribedInSfuEvtMsg) { - // Subscriber's user ID - val userId = msg.header.userId - // Publisher's stream ID - val streamId = msg.body.streamId - val allowed = isAllowedToSubscribeToCam(userId, streamId) - - if (allowed) { - addViewer(liveMeeting.webcams, streamId, userId) - } else { - val event = MsgBuilder.buildCamStreamUnsubscribeSysMsg( - liveMeeting.props.meetingProp.intId, - userId, - streamId - ) - outGW.send(event) - } - } -} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/streams/CamStreamUnsubscribedInSfuEvtMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/streams/CamStreamUnsubscribedInSfuEvtMsgHdlr.scala deleted file mode 100644 index 4f2e7e04f2..0000000000 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/streams/CamStreamUnsubscribedInSfuEvtMsgHdlr.scala +++ /dev/null @@ -1,20 +0,0 @@ -package org.bigbluebutton.core2.message.handlers - -import org.bigbluebutton.common2.msgs._ -import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } -import org.bigbluebutton.core.models.Webcams.{ removeViewer } - -trait CamStreamUnsubscribedInSfuEvtMsgHdlr { - this: MeetingActor => - - val outGW: OutMsgRouter - - def handleCamStreamUnsubscribedInSfuEvtMsg(msg: CamStreamUnsubscribedInSfuEvtMsg) { - // Subscriber's user ID - val userId = msg.header.userId - // Publisher's stream ID - val streamId = msg.body.streamId - - removeViewer(liveMeeting.webcams, streamId, userId) - } -} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/streams/EjectUserCamerasCmdMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/streams/EjectUserCamerasCmdMsgHdlr.scala deleted file mode 100644 index 19130e2b26..0000000000 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/streams/EjectUserCamerasCmdMsgHdlr.scala +++ /dev/null @@ -1,50 +0,0 @@ -package org.bigbluebutton.core2.message.handlers - -import org.bigbluebutton.common2.msgs._ -import org.bigbluebutton.core.models.Webcams -import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } -import org.bigbluebutton.core.apps.PermissionCheck -import org.bigbluebutton.core2.message.senders.MsgBuilder - -trait EjectUserCamerasCmdMsgHdlr { - this: MeetingActor => - - val outGW: OutMsgRouter - - def handleEjectUserCamerasCmdMsg(msg: EjectUserCamerasCmdMsg): Unit = { - val requesterUserId = msg.header.userId - val meetingId = liveMeeting.props.meetingProp.intId - val userToEject = msg.body.userId - val ejectionDisabled = !liveMeeting.props.usersProp.allowModsToEjectCameras - val isBreakout = liveMeeting.props.meetingProp.isBreakout - val badPermission = permissionFailed( - PermissionCheck.MOD_LEVEL, - PermissionCheck.VIEWER_LEVEL, - liveMeeting.users2x, - requesterUserId - ) - - if (ejectionDisabled || isBreakout || badPermission) { - val reason = "No permission to eject cameras from user." - PermissionCheck.ejectUserForFailedPermission( - meetingId, - requesterUserId, - reason, - outGW, - liveMeeting - ) - } else { - log.info("Ejecting user cameras. meetingId=" + meetingId - + " userId=" + userToEject - + " requesterUserId=" + requesterUserId) - val broadcastedWebcams = Webcams.findWebcamsForUser(liveMeeting.webcams, userToEject) - broadcastedWebcams foreach { webcam => - // Goes to SFU and comes back through CamBroadcastStoppedInSfuEvtMsg - val event = MsgBuilder.buildCamBroadcastStopSysMsg( - meetingId, userToEject, webcam.stream.id - ) - outGW.send(event) - } - } - } -} 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 ba44ba1d3f..77886eb0d6 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 @@ -130,17 +130,6 @@ object MsgBuilder { BbbCommonEnvCoreMsg(envelope, event) } - def buildGetWebcamStreamsMeetingRespMsg(meetingId: String, userId: String, streams: Vector[WebcamStreamVO]): BbbCommonEnvCoreMsg = { - val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, userId) - val envelope = BbbCoreEnvelope(GetWebcamStreamsMeetingRespMsg.NAME, routing) - val header = BbbClientMsgHeader(GetWebcamStreamsMeetingRespMsg.NAME, meetingId, userId) - - val body = GetWebcamStreamsMeetingRespMsgBody(streams) - val event = GetWebcamStreamsMeetingRespMsg(header, body) - - BbbCommonEnvCoreMsg(envelope, event) - } - def buildGetVoiceUsersMeetingRespMsg(meetingId: String, userId: String, voiceUsers: Vector[VoiceConfUser]): BbbCommonEnvCoreMsg = { val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, userId) val envelope = BbbCoreEnvelope(GetVoiceUsersMeetingRespMsg.NAME, routing) @@ -483,51 +472,6 @@ object MsgBuilder { BbbCommonEnvCoreMsg(envelope, event) } - def buildGetCamSubscribePermissionRespMsg( - meetingId: String, - userId: String, - streamId: String, - sfuSessionId: String, - allowed: Boolean - ): BbbCommonEnvCoreMsg = { - val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, userId) - val envelope = BbbCoreEnvelope(GetCamSubscribePermissionRespMsg.NAME, routing) - val header = BbbClientMsgHeader(GetCamSubscribePermissionRespMsg.NAME, meetingId, userId) - val body = GetCamSubscribePermissionRespMsgBody( - meetingId, - userId, - streamId, - sfuSessionId, - allowed - ) - val event = GetCamSubscribePermissionRespMsg(header, body) - - BbbCommonEnvCoreMsg(envelope, event) - } - - def buildGetCamBroadcastPermissionRespMsg( - meetingId: String, - userId: String, - streamId: String, - sfuSessionId: String, - allowed: Boolean - ): BbbCommonEnvCoreMsg = { - val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, userId) - val envelope = BbbCoreEnvelope(GetCamBroadcastPermissionRespMsg.NAME, routing) - val header = BbbClientMsgHeader(GetCamBroadcastPermissionRespMsg.NAME, meetingId, userId) - - val body = GetCamBroadcastPermissionRespMsgBody( - meetingId, - userId, - streamId, - sfuSessionId, - allowed - ) - val event = GetCamBroadcastPermissionRespMsg(header, body) - - BbbCommonEnvCoreMsg(envelope, event) - } - def buildGetGlobalAudioPermissionRespMsg( meetingId: String, voiceConf: String, @@ -578,44 +522,6 @@ object MsgBuilder { BbbCommonEnvCoreMsg(envelope, event) } - def buildCamBroadcastStopSysMsg( - meetingId: String, - userId: String, - streamId: String - ): BbbCommonEnvCoreMsg = { - val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka") - val envelope = BbbCoreEnvelope(CamBroadcastStopSysMsg.NAME, routing) - val body = CamBroadcastStopSysMsgBody(meetingId, userId, streamId) - val header = BbbCoreBaseHeader(CamBroadcastStopSysMsg.NAME) - val event = CamBroadcastStopSysMsg(header, body) - - BbbCommonEnvCoreMsg(envelope, event) - } - - def buildCamStreamUnsubscribeSysMsg( - meetingId: String, userId: String, streamId: String - ): BbbCommonEnvCoreMsg = { - val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka") - val envelope = BbbCoreEnvelope(CamStreamUnsubscribeSysMsg.NAME, routing) - val body = CamStreamUnsubscribeSysMsgBody(meetingId, userId, streamId) - val header = BbbCoreBaseHeader(CamStreamUnsubscribeSysMsg.NAME) - val event = CamStreamUnsubscribeSysMsg(header, body) - - BbbCommonEnvCoreMsg(envelope, event) - } - - def buildUserBroadcastCamStoppedEvtMsg( - meetingId: String, userId: String, streamId: String - ): BbbCommonEnvCoreMsg = { - val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId) - val envelope = BbbCoreEnvelope(UserBroadcastCamStoppedEvtMsg.NAME, routing) - val header = BbbClientMsgHeader(UserBroadcastCamStoppedEvtMsg.NAME, meetingId, userId) - val body = UserBroadcastCamStoppedEvtMsgBody(userId, streamId) - val event = UserBroadcastCamStoppedEvtMsg(header, body) - - BbbCommonEnvCoreMsg(envelope, event) - } - def buildScreenBroadcastStopSysMsg( meetingId: String, voiceConf: String, diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeTestData.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeTestData.scala index 841ed64e3a..b892fa7b06 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeTestData.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeTestData.scala @@ -58,9 +58,9 @@ trait FakeTestData { val rusers = Users2x.findAll(liveMeeting.users2x) val others = rusers.filterNot(u => u.intId == ruser1.id) - val viewers = others.map { o => o.intId } - val wstream1 = FakeUserGenerator.createFakeWebcamStreamFor(ruser1.id, viewers.toSet) - Webcams.addWebcamBroadcastStream(liveMeeting.webcams, wstream1) + val subscribers = others.map { o => o.intId } + val wstream1 = FakeUserGenerator.createFakeWebcamStreamFor(ruser1.id, subscribers.toSet) + Webcams.addWebcamStream(liveMeeting.webcams, wstream1) createFakeUser(liveMeeting, ruser1) } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeUserGenerator.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeUserGenerator.scala index 09ae9566eb..47bf72abad 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeUserGenerator.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeUserGenerator.scala @@ -77,12 +77,9 @@ object FakeUserGenerator { callerNum = name, muted, talking, listenOnly, "freeswitch", System.currentTimeMillis(), floor, lastFloorTime) } - def createFakeWebcamStreamFor(userId: String, viewers: Set[String]): WebcamStream = { + def createFakeWebcamStreamFor(userId: String, subscribers: Set[String]): WebcamStream = { val streamId = RandomStringGenerator.randomAlphanumericString(10) - val url = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" + streamId - val attributes = collection.immutable.HashMap("height" -> "600", "width" -> "800", "codec" -> "h264") - val media = MediaStream(streamId, url: String, userId: String, attributes, viewers) - WebcamStream(streamId, stream = media) + WebcamStream(streamId, userId, subscribers) } } diff --git a/akka-bbb-apps/src/test/scala/org/bigbluebutton/core2/testdata/TestDataGen.scala b/akka-bbb-apps/src/test/scala/org/bigbluebutton/core2/testdata/TestDataGen.scala index 690efce2d1..566c5caf1b 100755 --- a/akka-bbb-apps/src/test/scala/org/bigbluebutton/core2/testdata/TestDataGen.scala +++ b/akka-bbb-apps/src/test/scala/org/bigbluebutton/core2/testdata/TestDataGen.scala @@ -35,12 +35,9 @@ object TestDataGen { callerNum = name, muted, talking, listenOnly) } - def createFakeWebcamStreamFor(userId: String, viewers: Set[String]): WebcamStream = { + def createFakeWebcamStreamFor(userId: String, subscribers: Set[String]): WebcamStream = { val streamId = RandomStringGenerator.randomAlphanumericString(10) - val url = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" + streamId - val attributes = collection.immutable.HashMap("height" -> "600", "width" -> "800", "codec" -> "h264") - val media = MediaStream(streamId, url: String, userId: String, attributes, viewers) - WebcamStream(streamId, stream = media) + WebcamStream(streamId, userId, subscribers) } def createUserFor(liveMeeting: LiveMeeting, regUser: RegisteredUser, presenter: Boolean): UserState = { diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/WebcamsMsgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/WebcamsMsgs.scala index 02878633f7..dc11b3db8f 100755 --- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/WebcamsMsgs.scala +++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/WebcamsMsgs.scala @@ -6,50 +6,34 @@ case class UserBroadcastCamStartedEvtMsg( header: BbbClientMsgHeader, body: UserBroadcastCamStartedEvtMsgBody ) extends BbbCoreMsg -case class UserBroadcastCamStartedEvtMsgBody(userId: String, stream: String) +case class UserBroadcastCamStartedEvtMsgBody( + userId: String, + stream: String +) object UserBroadcastCamStartMsg { val NAME = "UserBroadcastCamStartMsg" } -case class UserBroadcastCamStartMsg(header: BbbClientMsgHeader, body: UserBroadcastCamStartMsgBody) extends StandardMsg +case class UserBroadcastCamStartMsg( + header: BbbClientMsgHeader, + body: UserBroadcastCamStartMsgBody +) extends StandardMsg case class UserBroadcastCamStartMsgBody(stream: String) object UserBroadcastCamStopMsg { val NAME = "UserBroadcastCamStopMsg" } -case class UserBroadcastCamStopMsg(header: BbbClientMsgHeader, body: UserBroadcastCamStopMsgBody) extends StandardMsg +case class UserBroadcastCamStopMsg( + header: BbbClientMsgHeader, + body: UserBroadcastCamStopMsgBody +) extends StandardMsg case class UserBroadcastCamStopMsgBody(stream: String) object UserBroadcastCamStoppedEvtMsg { val NAME = "UserBroadcastCamStoppedEvtMsg" } -case class UserBroadcastCamStoppedEvtMsg(header: BbbClientMsgHeader, body: UserBroadcastCamStoppedEvtMsgBody) extends BbbCoreMsg -case class UserBroadcastCamStoppedEvtMsgBody(userId: String, stream: String) - -object GetWebcamStreamsMeetingRespMsg { - val NAME = "GetWebcamStreamsMeetingRespMsg" - - def apply(meetingId: String, userId: String, streams: Vector[WebcamStreamVO]): GetWebcamStreamsMeetingRespMsg = { - val header = BbbClientMsgHeader(GetWebcamStreamsMeetingRespMsg.NAME, meetingId, userId) - - val body = GetWebcamStreamsMeetingRespMsgBody(streams) - GetWebcamStreamsMeetingRespMsg(header, body) - } -} -case class GetWebcamStreamsMeetingRespMsg(header: BbbClientMsgHeader, body: GetWebcamStreamsMeetingRespMsgBody) extends BbbCoreMsg -case class GetWebcamStreamsMeetingRespMsgBody(streams: Vector[WebcamStreamVO]) - -case class WebcamStreamVO(streamId: String, stream: MediaStreamVO) -case class MediaStreamVO(id: String, url: String, userId: String, attributes: collection.immutable.Map[String, String], viewers: Set[String]) - -object GetWebcamStreamsRespMsg { - val NAME = "GetWebcamStreamsRespMsg" - - def apply(meetingId: String, userId: String, webcamStreams: Vector[String]): GetWebcamStreamsRespMsg = { - val header = BbbClientMsgHeader(GetWebcamStreamsRespMsg.NAME, meetingId, userId) - - val body = GetWebcamStreamsRespMsgBody(webcamStreams) - GetWebcamStreamsRespMsg(header, body) - } -} - -case class GetWebcamStreamsRespMsg(header: BbbClientMsgHeader, body: GetWebcamStreamsRespMsgBody) extends BbbCoreMsg - -case class GetWebcamStreamsRespMsgBody(webcamStreams: Vector[String]) +case class UserBroadcastCamStoppedEvtMsg( + header: BbbClientMsgHeader, + body: UserBroadcastCamStoppedEvtMsgBody +) extends BbbCoreMsg +case class UserBroadcastCamStoppedEvtMsgBody( + userId: String, + stream: String +) /* Sent by bbb-webrtc-sfu to ask permission for broadcasting a webcam */