Merge pull request #14471 from pedrobmarin/r-w-ach
refactor(webcam): assemble core handlers
This commit is contained in:
commit
21d93f3d67
@ -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
|
||||
)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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 _ =>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
@ -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])
|
@ -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])
|
||||
|
@ -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 =>
|
||||
|
@ -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,
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user