diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/RegisterUserReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/RegisterUserReqMsgHdlr.scala index eca545182d..69f63b1378 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/RegisterUserReqMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/RegisterUserReqMsgHdlr.scala @@ -57,7 +57,9 @@ trait RegisterUserReqMsgHdlr { val regUser = RegisteredUsers.create(msg.body.intUserId, msg.body.extUserId, msg.body.name, msg.body.role, msg.body.authToken, - msg.body.avatarURL, ColorPicker.nextColor(liveMeeting.props.meetingProp.intId), msg.body.guest, msg.body.authed, guestStatus, msg.body.excludeFromDashboard, false) + msg.body.avatarURL, + msg.body.webcamBackgroundURL, + ColorPicker.nextColor(liveMeeting.props.meetingProp.intId), msg.body.guest, msg.body.authed, guestStatus, msg.body.excludeFromDashboard, false) checkUserConcurrentAccesses(regUser) @@ -98,7 +100,7 @@ trait RegisterUserReqMsgHdlr { val g = GuestApprovedVO(regUser.id, GuestStatus.ALLOW) UsersApp.approveOrRejectGuest(liveMeeting, outGW, g, SystemUser.ID) case GuestStatus.WAIT => - val guest = GuestWaiting(regUser.id, regUser.name, regUser.role, regUser.guest, regUser.avatarURL, regUser.color, regUser.authed, regUser.registeredOn) + val guest = GuestWaiting(regUser.id, regUser.name, regUser.role, regUser.guest, regUser.avatarURL, regUser.webcamBackgroundURL, regUser.color, regUser.authed, regUser.registeredOn) addGuestToWaitingForApproval(guest, liveMeeting.guestsWaiting) notifyModeratorsOfGuestWaiting(Vector(guest), liveMeeting.users2x, liveMeeting.props.meetingProp.intId) val notifyEvent = MsgBuilder.buildNotifyRoleInMeetingEvtMsg( diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfEvtMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfEvtMsgHdlr.scala index 682b19e343..c1d796e8b1 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfEvtMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfEvtMsgHdlr.scala @@ -34,7 +34,7 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration { def registerUserInRegisteredUsers() = { val regUser = RegisteredUsers.create(msg.body.intId, msg.body.voiceUserId, - msg.body.callerIdName, Roles.VIEWER_ROLE, msg.body.intId, "", + msg.body.callerIdName, Roles.VIEWER_ROLE, msg.body.intId, "", "", userColor, true, true, GuestStatus.WAIT, true, false) RegisteredUsers.add(liveMeeting.registeredUsers, regUser) } @@ -57,6 +57,7 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration { presenter = false, locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin, avatar = "", + webcamBackground = "", color = userColor, clientType = "", pickExempted = false, @@ -67,7 +68,7 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration { def registerUserAsGuest() = { if (GuestsWaiting.findWithIntId(liveMeeting.guestsWaiting, msg.body.intId) == None) { - val guest = GuestWaiting(msg.body.intId, msg.body.callerIdName, Roles.VIEWER_ROLE, true, "", userColor, true, System.currentTimeMillis()) + val guest = GuestWaiting(msg.body.intId, msg.body.callerIdName, Roles.VIEWER_ROLE, true, "", "", userColor, true, System.currentTimeMillis()) GuestsWaiting.add(liveMeeting.guestsWaiting, guest) notifyModeratorsOfGuestWaiting(guest, liveMeeting.users2x, liveMeeting.props.meetingProp.intId) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfMessageHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfMessageHdlr.scala index 1e21f196ea..b23a5836d7 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfMessageHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfMessageHdlr.scala @@ -6,47 +6,4 @@ trait UserJoinedVoiceConfMessageHdlr { this: MeetingActor => val outGW: OutMsgRouter - - /* - def startRecordingVoiceConference() { - if (Users.numUsersInVoiceConference(liveMeeting.users) == 1 && - props.recordProp.record && - !MeetingStatus2x.isVoiceRecording(liveMeeting.status)) { - MeetingStatus2x.startRecordingVoice(liveMeeting.status) - log.info("Send START RECORDING voice conf. meetingId=" + props.meetingProp.intId + " voice conf=" + props.voiceProp.voiceConf) - outGW.send(new StartRecordingVoiceConf(props.meetingProp.intId, props.recordProp.record, props.voiceProp.voiceConf)) - } - } - - - - def handleUserJoinedVoiceConfMessage(msg: UserJoinedVoiceConfMessage) = { - log.info("Received user joined voice. meetingId=" + props.meetingProp.intId + " callername=" + msg.callerIdName - + " userId=" + msg.userId + " extUserId=" + msg.externUserId) - - Users.findWithId(msg.userId, liveMeeting.users) match { - case Some(user) => { - // this is used to restore the mute state on reconnect - val previouslyMuted = user.voiceUser.muted - - val nu = Users.restoreMuteState(user, liveMeeting.users, msg.voiceUserId, msg.userId, msg.callerIdName, - msg.callerIdNum, msg.muted, msg.talking, msg.avatarURL, msg.listenOnly) - - log.info("User joined voice. meetingId=" + props.meetingProp.intId + " userId=" + user.id + " user=" + nu) - outGW.send(new UserJoinedVoice(props.meetingProp.intId, props.recordProp.record, props.voiceProp.voiceConf, nu)) - - if (MeetingStatus2x.isMeetingMuted(liveMeeting.status) || previouslyMuted) { - outGW.send(new MuteVoiceUser(props.meetingProp.intId, props.recordProp.record, - nu.id, nu.id, props.voiceProp.voiceConf, - nu.voiceUser.userId, true)) - } - - startRecordingVoiceConference() - } - case None => { - startRecordingVoiceConference() - } - } - } - */ } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/GuestsWaiting.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/GuestsWaiting.scala index 0341e326b9..13171e1726 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/GuestsWaiting.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/GuestsWaiting.scala @@ -68,7 +68,7 @@ class GuestsWaiting { } } -case class GuestWaiting(intId: String, name: String, role: String, guest: Boolean, avatar: String, color: String, authenticated: Boolean, registeredOn: Long) +case class GuestWaiting(intId: String, name: String, role: String, guest: Boolean, avatar: String, webcamBackground: String, color: String, authenticated: Boolean, registeredOn: Long) case class GuestPolicy(policy: String, setBy: String) object GuestPolicyType { diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/RegisteredUsers.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/RegisteredUsers.scala index 96ec1dca19..4304cd193c 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/RegisteredUsers.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/RegisteredUsers.scala @@ -5,7 +5,7 @@ import org.bigbluebutton.core.domain.BreakoutRoom2x object RegisteredUsers { def create(userId: String, extId: String, name: String, roles: String, - token: String, avatar: String, color: String, guest: Boolean, authenticated: Boolean, + token: String, avatar: String, webcamBackground: String, color: String, guest: Boolean, authenticated: Boolean, guestStatus: String, excludeFromDashboard: Boolean, loggedOut: Boolean): RegisteredUser = { new RegisteredUser( userId, @@ -14,6 +14,7 @@ object RegisteredUsers { roles, token, avatar, + webcamBackground, color, guest, authenticated, @@ -198,6 +199,7 @@ case class RegisteredUser( role: String, authToken: String, avatarURL: String, + webcamBackgroundURL: String, color: String, guest: Boolean, authed: Boolean, diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala index 5a3b661bfb..5ce1812501 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala @@ -413,6 +413,7 @@ case class UserState( locked: Boolean, presenter: Boolean, avatar: String, + webcamBackground: String, color: String, roleChangedOn: Long = System.currentTimeMillis(), lastActivityTime: Long = System.currentTimeMillis(), 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 980431d48b..9f7e935be7 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 @@ -70,6 +70,7 @@ trait HandlerHelpers extends SystemConfiguration { presenter = false, locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin, avatar = regUser.avatarURL, + webcamBackground = regUser.webcamBackgroundURL, color = regUser.color, clientType = clientType, pickExempted = false, diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/UserJoinedMeetingEvtMsgBuilder.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/UserJoinedMeetingEvtMsgBuilder.scala index 24268a1525..1b80358a15 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/UserJoinedMeetingEvtMsgBuilder.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/UserJoinedMeetingEvtMsgBuilder.scala @@ -16,7 +16,7 @@ object UserJoinedMeetingEvtMsgBuilder { raiseHand = userState.raiseHand, away = userState.away, pin = userState.pin, - presenter = userState.presenter, locked = userState.locked, avatar = userState.avatar, color = userState.color, + presenter = userState.presenter, locked = userState.locked, avatar = userState.avatar, webcamBackground = userState.webcamBackground, color = userState.color, clientType = userState.clientType, userCustomData = userState.userCustomData) val event = UserJoinedMeetingEvtMsg(meetingId, userState.intId, body) 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 2e43892f8c..9674b8b798 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 @@ -20,13 +20,13 @@ trait FakeTestData { val guest1 = createUserVoiceAndCam(liveMeeting, Roles.VIEWER_ROLE, guest = true, authed = true, CallingWith.WEBRTC, muted = false, talking = false, listenOnly = false) Users2x.add(liveMeeting.users2x, guest1) - val guestWait1 = GuestWaiting(guest1.intId, guest1.name, guest1.role, guest1.guest, "", "#ff6242", guest1.authed, System.currentTimeMillis()) + val guestWait1 = GuestWaiting(guest1.intId, guest1.name, guest1.role, guest1.guest, "", "", "#ff6242", guest1.authed, System.currentTimeMillis()) GuestsWaiting.add(liveMeeting.guestsWaiting, guestWait1) val guest2 = createUserVoiceAndCam(liveMeeting, Roles.VIEWER_ROLE, guest = true, authed = true, CallingWith.FLASH, muted = false, talking = false, listenOnly = false) Users2x.add(liveMeeting.users2x, guest2) - val guestWait2 = GuestWaiting(guest2.intId, guest2.name, guest2.role, guest2.guest, "", "#ff6242", guest2.authed, System.currentTimeMillis()) + val guestWait2 = GuestWaiting(guest2.intId, guest2.name, guest2.role, guest2.guest, "", "", "#ff6242", guest2.authed, System.currentTimeMillis()) GuestsWaiting.add(liveMeeting.guestsWaiting, guestWait2) val vu1 = FakeUserGenerator.createFakeVoiceOnlyUser(CallingWith.PHONE, muted = false, talking = false, listenOnly = false) @@ -69,7 +69,8 @@ trait FakeTestData { UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role, pin = false, mobile = false, guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus, emoji = "none", reactionEmoji = "none", raiseHand = false, away = false, locked = false, presenter = false, - avatar = regUser.avatarURL, color = "#ff6242", clientType = "unknown", + avatar = regUser.avatarURL, webcamBackground = regUser.webcamBackgroundURL, + color = "#ff6242", clientType = "unknown", pickExempted = false, userLeftFlag = UserLeftFlag(false, 0)) } 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 3ac1a2d50f..046d499232 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 @@ -52,10 +52,12 @@ object FakeUserGenerator { val authToken = RandomStringGenerator.randomAlphanumericString(16) val avatarURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" + RandomStringGenerator.randomAlphanumericString(10) + ".png" + val webcamBackgroundURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" + + RandomStringGenerator.randomAlphanumericString(10) + ".jpg" val color = "#ff6242" val ru = RegisteredUsers.create(userId = id, extId, name, role, - authToken, avatarURL, color, guest, authed, guestStatus = GuestStatus.ALLOW, false, false) + authToken, avatarURL, webcamBackgroundURL, color, guest, authed, guestStatus = GuestStatus.ALLOW, false, false) RegisteredUsers.add(users, ru) ru } 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 285408e333..d2ac741898 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 @@ -12,9 +12,11 @@ object TestDataGen { val authToken = RandomStringGenerator.randomAlphanumericString(16) val avatarURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" + RandomStringGenerator.randomAlphanumericString(10) + ".png" + val webcamBackgroundURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" + + RandomStringGenerator.randomAlphanumericString(10) + ".jpg" val ru = RegisteredUsers.create(userId = id, extId, name, role, - authToken, avatarURL, guest, authed, GuestStatus.ALLOW, false) + authToken, avatarURL, webcamBackgroundURL, guest, authed, GuestStatus.ALLOW, false) RegisteredUsers.add(users, ru) ru @@ -48,7 +50,7 @@ object TestDataGen { val u = UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role, guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus, emoji = "none", reactionEmoji = "none", raiseHand = false, away = false, pin = false, mobile = false, - locked = false, presenter = false, avatar = regUser.avatarURL, color = "#ff6242", + locked = false, presenter = false, avatar = regUser.avatarURL, regUser.webcamBackgroundURL, color = "#ff6242", clientType = "unknown", pickExempted = false, userLeftFlag = UserLeftFlag(false, 0)) Users2x.add(liveMeeting.users2x, u) u diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Meeting2x.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Meeting2x.scala index aa25f667fb..f661df7481 100755 --- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Meeting2x.scala +++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Meeting2x.scala @@ -115,8 +115,8 @@ case class UserVO(id: String, externalId: String, name: String, role: String, guest: Boolean, authed: Boolean, guestStatus: String, emojiStatus: String, presenter: Boolean, hasStream: Boolean, locked: Boolean, webcamStreams: Set[String], phoneUser: Boolean, voiceUser: VoiceUserVO, listenOnly: Boolean, avatarURL: String, - joinedWeb: Boolean) + webcamBackgroundURL: String, joinedWeb: Boolean) case class VoiceUserVO(userId: String, webUserId: String, callerName: String, callerNum: String, joined: Boolean, locked: Boolean, muted: Boolean, - talking: Boolean, avatarURL: String, listenOnly: Boolean) + talking: Boolean, avatarURL: String, webcamBackgroundURL: String, listenOnly: Boolean) diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMsgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMsgs.scala index 4a61f738c4..a584b1a743 100755 --- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMsgs.scala +++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMsgs.scala @@ -6,7 +6,7 @@ case class RegisterUserReqMsg( body: RegisterUserReqMsgBody ) extends BbbCoreMsg case class RegisterUserReqMsgBody(meetingId: String, intUserId: String, name: String, role: String, - extUserId: String, authToken: String, avatarURL: String, + extUserId: String, authToken: String, avatarURL: String, webcamBackgroundURL: String, guest: Boolean, authed: Boolean, guestStatus: String, excludeFromDashboard: Boolean, userCustomData: Map[String, AnyRef]) @@ -90,24 +90,25 @@ case class UserJoinedMeetingEvtMsg( body: UserJoinedMeetingEvtMsgBody ) extends BbbCoreMsg case class UserJoinedMeetingEvtMsgBody( - intId: String, - extId: String, - name: String, - role: String, - guest: Boolean, - authed: Boolean, - guestStatus: String, - emoji: String, - reactionEmoji: String, - raiseHand: Boolean, - away: Boolean, - pin: Boolean, - presenter: Boolean, - locked: Boolean, - avatar: String, - color: String, - clientType: String, - userCustomData: Map[String, String] + intId: String, + extId: String, + name: String, + role: String, + guest: Boolean, + authed: Boolean, + guestStatus: String, + emoji: String, + reactionEmoji: String, + raiseHand: Boolean, + away: Boolean, + pin: Boolean, + presenter: Boolean, + locked: Boolean, + avatar: String, + webcamBackground: String, + color: String, + clientType: String, + userCustomData: Map[String, String] ) /** diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/MeetingService.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/MeetingService.java index 07b2a5d5b8..d7076d917a 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/MeetingService.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/MeetingService.java @@ -126,10 +126,10 @@ public class MeetingService implements MessageListener { public void registerUser(String meetingID, String internalUserId, String fullname, String role, String externUserID, - String authToken, String avatarURL, Boolean guest, + String authToken, String avatarURL, String webcamBackgroundURL, Boolean guest, Boolean authed, String guestStatus, Boolean excludeFromDashboard, Boolean leftGuestLobby) { handle(new RegisterUser(meetingID, internalUserId, fullname, role, - externUserID, authToken, avatarURL, guest, authed, guestStatus, excludeFromDashboard, leftGuestLobby)); + externUserID, authToken, avatarURL, webcamBackgroundURL, guest, authed, guestStatus, excludeFromDashboard, leftGuestLobby)); Meeting m = getMeeting(meetingID); if (m != null) { @@ -437,7 +437,7 @@ public class MeetingService implements MessageListener { gw.registerUser(message.meetingID, message.internalUserId, message.fullname, message.role, - message.externUserID, message.authToken, message.avatarURL, message.guest, + message.externUserID, message.authToken, message.avatarURL, message.webcamBackgroundURL, message.guest, message.authed, message.guestStatus, message.excludeFromDashboard, userCustomData); } @@ -933,7 +933,7 @@ public class MeetingService implements MessageListener { } User user = new User(message.userId, message.externalUserId, - message.name, message.role, message.avatarURL, message.guest, message.guestStatus, + message.name, message.role, message.avatarURL, message.webcamBackgroundURL, message.guest, message.guestStatus, message.clientType); if(m.getMaxUsers() > 0 && m.countUniqueExtIds() >= m.getMaxUsers()) { @@ -1053,8 +1053,8 @@ public class MeetingService implements MessageListener { } else { if (message.userId.startsWith("v_")) { // A dial-in user joined the meeting. Dial-in users by convention has userId that starts with "v_". - User vuser = new User(message.userId, message.userId, message.name, "DIAL-IN-USER", "", - true, GuestPolicy.ALLOW, "DIAL-IN"); + User vuser = new User(message.userId, message.userId, message.name, "DIAL-IN-USER", "", "", + true, GuestPolicy.ALLOW, "DIAL-IN"); vuser.setVoiceJoined(true); m.userJoined(vuser); } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/ParamsProcessorUtil.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/ParamsProcessorUtil.java index 0c51c530fc..1bbbac0fe7 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/ParamsProcessorUtil.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/ParamsProcessorUtil.java @@ -84,6 +84,8 @@ public class ParamsProcessorUtil { private Integer defaultHttpSessionTimeout = 14400; private Boolean useDefaultAvatar = false; private String defaultAvatarURL; + private Boolean useDefaultWebcamBackground = false; + private String defaultWebcamBackgroundURL; private String defaultGuestPolicy; private Boolean authenticatedGuest; private Boolean defaultAllowPromoteGuestToModerator; @@ -741,6 +743,7 @@ public class ParamsProcessorUtil { } String avatarURL = useDefaultAvatar ? defaultAvatarURL : ""; + String webcamBackgroundURL = useDefaultWebcamBackground ? defaultWebcamBackgroundURL : ""; int html5InstanceId = processHtml5InstanceId(params.get(ApiParams.HTML5_INSTANCE_ID)); @@ -760,6 +763,7 @@ public class ParamsProcessorUtil { .withTelVoice(telVoice).withWebVoice(webVoice) .withDialNumber(dialNumber) .withDefaultAvatarURL(avatarURL) + .withDefaultWebcamBackgroundURL(webcamBackgroundURL) .withAutoStartRecording(autoStartRec) .withAllowStartStopRecording(allowStartStoptRec) .withRecordFullDurationMedia(_recordFullDurationMedia) @@ -1296,6 +1300,14 @@ public class ParamsProcessorUtil { this.defaultAvatarURL = url; } + public void setUseDefaultWebcamBackground(Boolean value) { + this.useDefaultWebcamBackground = value; + } + + public void setDefaultWebcamBackgroundURL(String uri) { + this.defaultWebcamBackgroundURL = uri; + } + public void setDefaultGuestPolicy(String guestPolicy) { this.defaultGuestPolicy = guestPolicy; } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Meeting.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Meeting.java index 234d1e073f..6ebe9e9dc9 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Meeting.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Meeting.java @@ -79,6 +79,7 @@ public class Meeting { private Integer maxPinnedCameras = 0; private String dialNumber; private String defaultAvatarURL; + private String defaultWebcamBackgroundURL; private String guestPolicy = GuestPolicy.ASK_MODERATOR; private String guestLobbyMessage = ""; private Map usersWithGuestLobbyMessages; @@ -148,6 +149,7 @@ public class Meeting { logoutUrl = builder.logoutUrl; logoutTimer = builder.logoutTimer; defaultAvatarURL = builder.defaultAvatarURL; + defaultWebcamBackgroundURL = builder.defaultWebcamBackgroundURL; record = builder.record; autoStartRecording = builder.autoStartRecording; allowStartStopRecording = builder.allowStartStopRecording; @@ -462,6 +464,10 @@ public class Meeting { return defaultAvatarURL; } + public String getDefaultWebcamBackgroundURL() { + return defaultWebcamBackgroundURL; + } + public void setWaitingPositionsInWaitingQueue(HashMap guestUsersWithPositionInWaitingLine) { this.guestUsersWithPositionInWaitingLine = guestUsersWithPositionInWaitingLine; } @@ -909,6 +915,7 @@ public class Meeting { private Map metadata; private String dialNumber; private String defaultAvatarURL; + private String defaultWebcamBackgroundURL; private long createdTime; private boolean isBreakout; private String guestPolicy; @@ -1056,6 +1063,11 @@ public class Meeting { return this; } + public Builder withDefaultWebcamBackgroundURL(String w) { + defaultWebcamBackgroundURL = w; + return this; + } + public Builder isBreakout(Boolean b) { isBreakout = b; return this; diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/User.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/User.java index da93ef6b91..08859662e7 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/User.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/User.java @@ -31,6 +31,7 @@ public class User { private String fullname; private String role; private String avatarURL; + private String webcamBackgroundURL; private Map status; private Boolean guest; private String guestStatus; @@ -45,6 +46,7 @@ public class User { String fullname, String role, String avatarURL, + String webcamBackgroundURL, Boolean guest, String guestStatus, String clientType) { @@ -53,6 +55,7 @@ public class User { this.fullname = fullname; this.role = role; this.avatarURL = avatarURL; + this.webcamBackgroundURL = webcamBackgroundURL; this.guest = guest; this.guestStatus = guestStatus; this.status = new ConcurrentHashMap<>(); @@ -128,6 +131,14 @@ public class User { this.avatarURL = avatarURL; } + public String getWebcamBackgroundUrl() { + return webcamBackgroundURL; + } + + public void setWebcamBackgroundUrl(String webcamBackgroundURL) { + this.webcamBackgroundURL = webcamBackgroundURL; + } + public boolean isModerator() { return "MODERATOR".equalsIgnoreCase(this.role); } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/UserSession.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/UserSession.java index f4da7fdbd2..ccb228e50e 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/UserSession.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/UserSession.java @@ -42,6 +42,7 @@ public class UserSession { public String logoutUrl = null; public String defaultLayout = "NOLAYOUT"; public String avatarURL; + public String webcamBackgroundURL; public String guestStatus = GuestPolicy.ALLOW; public String clientUrl = null; public Boolean excludeFromDashboard = false; @@ -134,6 +135,10 @@ public class UserSession { return avatarURL; } + public String getWebcamBackgroundURL() { + return webcamBackgroundURL; + } + public String getGuestStatus() { return guestStatus; } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/messaging/messages/RegisterUser.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/messaging/messages/RegisterUser.java index 6314aa3fed..561739fc91 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/messaging/messages/RegisterUser.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/messaging/messages/RegisterUser.java @@ -10,6 +10,7 @@ public class RegisterUser implements IMessage { public final String externUserID; public final String authToken; public final String avatarURL; + public final String webcamBackgroundURL; public final Boolean guest; public final Boolean authed; public final String guestStatus; @@ -17,7 +18,7 @@ public class RegisterUser implements IMessage { public final Boolean leftGuestLobby; public RegisterUser(String meetingID, String internalUserId, String fullname, String role, String externUserID, - String authToken, String avatarURL, Boolean guest, + String authToken, String avatarURL, String webcamBackgroundURL, Boolean guest, Boolean authed, String guestStatus, Boolean excludeFromDashboard, Boolean leftGuestLobby) { this.meetingID = meetingID; this.internalUserId = internalUserId; @@ -25,7 +26,8 @@ public class RegisterUser implements IMessage { this.role = role; this.externUserID = externUserID; this.authToken = authToken; - this.avatarURL = avatarURL; + this.avatarURL = avatarURL; + this.webcamBackgroundURL = webcamBackgroundURL; this.guest = guest; this.authed = authed; this.guestStatus = guestStatus; diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/messaging/messages/UserJoined.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/messaging/messages/UserJoined.java index 669e498c47..b2f2c9d39d 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/messaging/messages/UserJoined.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/messaging/messages/UserJoined.java @@ -7,6 +7,7 @@ public class UserJoined implements IMessage { public final String name; public final String role; public final String avatarURL; + public final String webcamBackgroundURL; public final Boolean guest; public final String guestStatus; public final String clientType; @@ -18,6 +19,7 @@ public class UserJoined implements IMessage { String name, String role, String avatarURL, + String webcamBackgroundURL, Boolean guest, String guestStatus, String clientType) { @@ -27,6 +29,7 @@ public class UserJoined implements IMessage { this.name = name; this.role = role; this.avatarURL = avatarURL; + this.webcamBackgroundURL = webcamBackgroundURL; this.guest = guest; this.guestStatus = guestStatus; this.clientType = clientType; diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/pub/IPublisherService.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/pub/IPublisherService.java index 8792829324..b1fa386955 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/pub/IPublisherService.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/pub/IPublisherService.java @@ -22,7 +22,7 @@ public interface IPublisherService { void endMeeting(String meetingId); void send(String channel, String message); void registerUser(String meetingID, String internalUserId, String fullname, String role, String externUserID, - String authToken, String avatarURL, Boolean guest, Boolean excludeFromDashboard, Boolean authed); + String authToken, String avatarURL, String webcamBackgroundURL, Boolean guest, Boolean excludeFromDashboard, Boolean authed); void sendKeepAlive(String system, Long bbbWebTimestamp, Long akkaAppsTimestamp); void sendStunTurnInfo(String meetingId, String internalUserId, Set stuns, Set turns); } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api2/IBbbWebApiGWApp.java b/bbb-common-web/src/main/java/org/bigbluebutton/api2/IBbbWebApiGWApp.java index bd20ff5c84..73dab48e39 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api2/IBbbWebApiGWApp.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api2/IBbbWebApiGWApp.java @@ -50,7 +50,7 @@ public interface IBbbWebApiGWApp { String presentationUploadExternalUrl); void registerUser(String meetingID, String internalUserId, String fullname, String role, - String externUserID, String authToken, String avatarURL, + String externUserID, String authToken, String avatarURL, String webcamBackgroundURL, Boolean guest, Boolean authed, String guestStatus, Boolean excludeFromDashboard, Map userCustomData); void guestWaitingLeft(String meetingID, String internalUserId); diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api2/IMeetingService.java b/bbb-common-web/src/main/java/org/bigbluebutton/api2/IMeetingService.java index 15817fbb0f..def05fcff9 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api2/IMeetingService.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api2/IMeetingService.java @@ -15,7 +15,7 @@ public interface IMeetingService { void addUserSession(String token, UserSession user); void registerUser(String meetingID, String internalUserId, String fullname, String role, String externUserID, - String authToken, String avatarURL, Boolean guest, Boolean authed); + String authToken, String avatarURL, String webcamBackgroundURL, Boolean guest, Boolean authed); UserSession getUserSession(String token); UserSession removeUserSession(String token); void purgeRegisteredUsers(); diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api2/domain/Meeting2.java b/bbb-common-web/src/main/java/org/bigbluebutton/api2/domain/Meeting2.java index 9811b8ac39..fa5c562523 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api2/domain/Meeting2.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api2/domain/Meeting2.java @@ -17,6 +17,7 @@ public class Meeting2 { public final boolean forciblyEnded; public final String logoutUrl; public final String defaultAvatarURL; + public final String defaultWebcamBackgroundURL; public final Map metadata; public final List breakoutRooms; @@ -30,6 +31,7 @@ public class Meeting2 { boolean forciblyEnded, String logoutUrl, String defaultAvatarURL, + String defaultWebcamBackgroundURL, Map metadata, List breakoutRooms) { this.props = props; @@ -42,6 +44,7 @@ public class Meeting2 { this.forciblyEnded = forciblyEnded; this.logoutUrl = logoutUrl; this.defaultAvatarURL = defaultAvatarURL; + this.defaultWebcamBackgroundURL = defaultWebcamBackgroundURL; this.metadata = metadata; this.breakoutRooms = breakoutRooms; } diff --git a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/BbbWebApiGWApp.scala b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/BbbWebApiGWApp.scala index b8ed63892c..05453d5d77 100755 --- a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/BbbWebApiGWApp.scala +++ b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/BbbWebApiGWApp.scala @@ -253,27 +253,23 @@ class BbbWebApiGWApp( groupsAsVector ) - //meetingManagerActorRef ! new CreateMeetingMsg(defaultProps) - val event = MsgBuilder.buildCreateMeetingRequestToAkkaApps(defaultProps) msgToAkkaAppsEventBus.publish(MsgToAkkaApps(toAkkaAppsChannel, event)) } def registerUser(meetingId: String, intUserId: String, name: String, - role: String, extUserId: String, authToken: String, avatarURL: String, + role: String, extUserId: String, authToken: String, avatarURL: String, + webcamBackgroundURL: String, guest: java.lang.Boolean, authed: java.lang.Boolean, guestStatus: String, excludeFromDashboard: java.lang.Boolean, userCustomData: java.util.Map[String, AnyRef]): Unit = { - // meetingManagerActorRef ! new RegisterUser(meetingId = meetingId, intUserId = intUserId, name = name, - // role = role, extUserId = extUserId, authToken = authToken, avatarURL = avatarURL, - // guest = guest, authed = authed) - val ucd = userCustomData.asScala.toMap val regUser = new RegisterUser(meetingId = meetingId, intUserId = intUserId, name = name, role = role, extUserId = extUserId, authToken = authToken, avatarURL = avatarURL, - guest = guest.booleanValue(), authed = authed.booleanValue(), guestStatus = guestStatus, + webcamBackgroundURL = webcamBackgroundURL, guest = guest.booleanValue(), + authed = authed.booleanValue(), guestStatus = guestStatus, excludeFromDashboard = excludeFromDashboard, ucd) val event = MsgBuilder.buildRegisterUserRequestToAkkaApps(regUser) diff --git a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/MsgBuilder.scala b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/MsgBuilder.scala index 2150248b6a..0fb81a1a06 100755 --- a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/MsgBuilder.scala +++ b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/MsgBuilder.scala @@ -40,7 +40,8 @@ object MsgBuilder { val header = BbbCoreHeaderWithMeetingId(RegisterUserReqMsg.NAME, msg.meetingId) val body = RegisterUserReqMsgBody(meetingId = msg.meetingId, intUserId = msg.intUserId, name = msg.name, role = msg.role, extUserId = msg.extUserId, authToken = msg.authToken, - avatarURL = msg.avatarURL, guest = msg.guest, authed = msg.authed, guestStatus = msg.guestStatus, + avatarURL = msg.avatarURL, webcamBackgroundURL = msg.webcamBackgroundURL, + guest = msg.guest, authed = msg.authed, guestStatus = msg.guestStatus, excludeFromDashboard = msg.excludeFromDashboard, msg.userCustomData) val req = RegisterUserReqMsg(header, body) BbbCommonEnvCoreMsg(envelope, req) diff --git a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/domain/User2.scala b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/domain/User2.scala index 4d9e029e5b..a12a0b2be0 100755 --- a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/domain/User2.scala +++ b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/domain/User2.scala @@ -4,7 +4,8 @@ case class CallerId(name: String, number: String) case class VoiceUser(id: String, callerId: CallerId, status: String, vid: String, wid: String, callingWith: String) case class User2(intId: String, extId: String, name: String, role: String, avatarURL: String, - guest: Boolean, waitingForAcceptance: Boolean, status: Vector[String], + webcamBackgroundURL: String, + guest: Boolean, waitingForAcceptance: Boolean, status: Vector[String], streams: Set[String], customData: UserCustomData, voiceUser: VoiceUser, webcamStreams: Vector[String]) object Users { @@ -40,7 +41,8 @@ class Users { case class RegisteredUser2(meetingId: String, intId: String, name: String, role: String, extId: String, authToken: String, avatarURL: String, - guest: Boolean, authed: Boolean) + webcamBackgroundURL: String, + guest: Boolean, authed: Boolean) object RegisteredUsers { def findWithId(users: RegisteredUsers, id: String): Option[RegisteredUser2] = { diff --git a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/MeetingsManagerActor.scala b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/MeetingsManagerActor.scala index a1cb6352cd..1486a1393f 100755 --- a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/MeetingsManagerActor.scala +++ b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/MeetingsManagerActor.scala @@ -16,7 +16,7 @@ case class CreateBreakoutRoomMsg(meetingId: String, parentMeetingId: String, case class AddUserSession(token: String, session: UserSession) case class RegisterUser(meetingId: String, intUserId: String, name: String, role: String, - extUserId: String, authToken: String, avatarURL: String, + extUserId: String, authToken: String, avatarURL: String, webcamBackgroundURL: String, guest: Boolean, authed: Boolean, guestStatus: String, excludeFromDashboard: Boolean, userCustomData: Map[String, AnyRef]) case class CreateMeetingMsg(defaultProps: DefaultProps) diff --git a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/OldMeetingMsgHdlrActor.scala b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/OldMeetingMsgHdlrActor.scala index fb5b01bd09..8b058ae280 100755 --- a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/OldMeetingMsgHdlrActor.scala +++ b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/OldMeetingMsgHdlrActor.scala @@ -122,10 +122,9 @@ class OldMeetingMsgHdlrActor(val olgMsgGW: OldMessageReceivedGW) def handleUserJoinedMeetingEvtMsg(msg: UserJoinedMeetingEvtMsg): Unit = { olgMsgGW.handle(new UserJoined(msg.header.meetingId, msg.body.intId, - msg.body.extId, msg.body.name, msg.body.role, msg.body.avatar, msg.body.guest, + msg.body.extId, msg.body.name, msg.body.role, msg.body.avatar, msg.body.webcamBackground, msg.body.guest, msg.body.guestStatus, msg.body.clientType)) - } def handlePresenterUnassignedEvtMsg(msg: PresenterUnassignedEvtMsg): Unit = { diff --git a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/ToAkkaAppsSendersTrait.scala b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/ToAkkaAppsSendersTrait.scala index 1ab9a9dd35..b39c4c1fea 100755 --- a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/ToAkkaAppsSendersTrait.scala +++ b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/ToAkkaAppsSendersTrait.scala @@ -28,7 +28,8 @@ trait ToAkkaAppsSendersTrait extends SystemConfiguration { val header = BbbCoreHeaderWithMeetingId(RegisterUserReqMsg.NAME, msg.meetingId) val body = RegisterUserReqMsgBody(meetingId = msg.meetingId, intUserId = msg.intUserId, name = msg.name, role = msg.role, extUserId = msg.extUserId, authToken = msg.authToken, - avatarURL = msg.avatarURL, guest = msg.guest, authed = msg.authed, guestStatus = msg.guestStatus, + avatarURL = msg.avatarURL, webcamBackgroundURL = msg.webcamBackgroundURL, guest = msg.guest, + authed = msg.authed, guestStatus = msg.guestStatus, excludeFromDashboard = msg.excludeFromDashboard, msg.userCustomData) val req = RegisterUserReqMsg(header, body) val message = BbbCommonEnvCoreMsg(envelope, req) diff --git a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/UserSessions.scala b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/UserSessions.scala index 100643de93..3bc9dfca29 100755 --- a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/UserSessions.scala +++ b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/meeting/UserSessions.scala @@ -5,7 +5,7 @@ case class UserSession2(authToken: String, internalUserId: String, conferencenam role: String, conference: String, room: String, guest: Boolean = false, authed: Boolean = false, voicebridge: String, webvoiceconf: String, mode: String, record: String, welcome: String, logoutUrl: String, - defaultLayout: String = "NOLAYOUT", avatarURL: String) + defaultLayout: String = "NOLAYOUT", avatarURL: String, webcamBackgroundURL: String) class UserSessions { diff --git a/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/addUserPersistentData.js b/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/addUserPersistentData.js index 4e833027fc..33c6a510de 100644 --- a/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/addUserPersistentData.js +++ b/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/addUserPersistentData.js @@ -29,6 +29,7 @@ export default async function addUserPersistentData(user) { presenter: Boolean, locked: Boolean, avatar: String, + webcamBackground: String, clientType: String, left: Boolean, effectiveConnectionType: null, @@ -42,6 +43,7 @@ export default async function addUserPersistentData(user) { role, token, avatar, + webcamBackground, guest, color, pin, @@ -55,6 +57,7 @@ export default async function addUserPersistentData(user) { role, token, avatar, + webcamBackground, guest, color, pin, diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js b/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js index a2a922b0b8..570dbc1211 100755 --- a/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js +++ b/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js @@ -30,6 +30,7 @@ export default async function addUser(meetingId, userData) { presenter: Boolean, locked: Boolean, avatar: String, + webcamBackground: String, color: String, pin: Boolean, clientType: String, diff --git a/bigbluebutton-html5/imports/ui/components/video-preview/component.jsx b/bigbluebutton-html5/imports/ui/components/video-preview/component.jsx index 71cdac9b6b..12933560cf 100755 --- a/bigbluebutton-html5/imports/ui/components/video-preview/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-preview/component.jsx @@ -1,3 +1,5 @@ +import Auth from '/imports/ui/services/auth'; +import Users from '/imports/api/users'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { @@ -325,6 +327,21 @@ class VideoPreview extends Component { viewState: VIEW_STATES.found, }); this.displayPreview(); + + // Set the custom or default virtual background + const webcamBackground = Users.findOne({ + meetingId: Auth.meetingID, + userId: Auth.userID, + }, { + fields: { + webcamBackground: 1, + }, + }); + + const webcamBackgroundURL = webcamBackground?.webcamBackground; + if (webcamBackgroundURL !== '') { + this.handleVirtualBgSelected(EFFECT_TYPES.IMAGE_TYPE, '', { url: webcamBackgroundURL }); + } }); } else { // There were no webcams coming from enumerateDevices. Throw an error. @@ -428,7 +445,6 @@ class VideoPreview extends Component { // Resolves into true if the background switch is successful, false otherwise handleVirtualBgSelected(type, name, customParams) { - const { sharedDevices } = this.props; const { webcamDeviceId } = this.state; const shared = this.isAlreadyShared(webcamDeviceId); diff --git a/bigbluebutton-html5/imports/ui/services/virtual-background/index.js b/bigbluebutton-html5/imports/ui/services/virtual-background/index.js index 5f42d8c5d6..90e7c8eab6 100644 --- a/bigbluebutton-html5/imports/ui/services/virtual-background/index.js +++ b/bigbluebutton-html5/imports/ui/services/virtual-background/index.js @@ -15,7 +15,6 @@ import { getVirtualBgImagePath, } from '/imports/ui/services/virtual-background/service' import logger from '/imports/startup/client/logger'; - import { simd } from 'wasm-feature-detect/dist/cjs/index'; const blurValue = '25px'; @@ -387,10 +386,44 @@ export async function createVirtualBackgroundService(parameters = null) { parameters.backgroundType = 'blur'; parameters.isVirtualBackground = false; } else { + parameters.virtualSource = virtualBackgroundImagePath + parameters.backgroundFilename; + if (parameters.customParams) { - parameters.virtualSource = parameters.customParams.file; - } else { - parameters.virtualSource = virtualBackgroundImagePath + parameters.backgroundFilename; + if (parameters.customParams.file) { + parameters.virtualSource = parameters.customParams.file; + } else { + const imageUrl = parameters.customParams.url; + + // Function to convert image URL to a File object + async function getFileFromUrl(url) { + try { + const response = await fetch(url, { + credentials: 'omit', + mode: 'cors', + headers: { + 'Accept': 'image/*', + } + }); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const blob = await response.blob(); + const file = new File([blob], 'fetchedWebcamBackground', { type: blob.type }); + return file; + } catch (error) { + logger.error('Fetch error:', error); + return null; + } + } + + let fetchedWebcamBackground = await getFileFromUrl(imageUrl); + + if (fetchedWebcamBackground) { + parameters.virtualSource = URL.createObjectURL(fetchedWebcamBackground); + } else { + logger.error('Failed to fetch custom webcam background image. Using fallback image.'); + } + } } } diff --git a/bigbluebutton-web/grails-app/conf/bigbluebutton.properties b/bigbluebutton-web/grails-app/conf/bigbluebutton.properties index c6a04b1ed5..40161eeba9 100644 --- a/bigbluebutton-web/grails-app/conf/bigbluebutton.properties +++ b/bigbluebutton-web/grails-app/conf/bigbluebutton.properties @@ -321,6 +321,10 @@ defaultGuestWaitURL=${bigbluebutton.web.serverURL}/html5client/guestWait useDefaultAvatar=false defaultAvatarURL=${bigbluebutton.web.serverURL}/html5client/resources/images/avatar.png +# The default webcam background image to display. +useDefaultWebcamBackground=false +defaultWebcamBackgroundURL=${bigbluebutton.web.serverURL}/html5client/resources/images/virtual-backgrounds/board.jpg + apiVersion=2.0 # Salt which is used by 3rd-party apps to authenticate api calls diff --git a/bigbluebutton-web/grails-app/conf/spring/resources.xml b/bigbluebutton-web/grails-app/conf/spring/resources.xml index 95d621238b..df4a23a4c6 100755 --- a/bigbluebutton-web/grails-app/conf/spring/resources.xml +++ b/bigbluebutton-web/grails-app/conf/spring/resources.xml @@ -163,6 +163,8 @@ with BigBlueButton; if not, see . + + diff --git a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy index fe0514e40a..1031c6570c 100755 --- a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy +++ b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy @@ -405,6 +405,12 @@ class ApiController { us.avatarURL = meeting.defaultAvatarURL } + if (!StringUtils.isEmpty(params.webcamBackgroundURL)) { + us.webcamBackgroundURL = params.webcamBackgroundURL; + } else { + us.webcamBackgroundURL = meeting.defaultWebcamBackgroundURL + } + if (!StringUtils.isEmpty(params.excludeFromDashboard)) { try { us.excludeFromDashboard = Boolean.parseBoolean(params.excludeFromDashboard) @@ -435,6 +441,7 @@ class ApiController { us.externUserID, us.authToken, us.avatarURL, + us.webcamBackgroundURL, us.guest, us.authed, guestStatusVal, @@ -941,6 +948,7 @@ class ApiController { logoutUrl us.logoutUrl defaultLayout us.defaultLayout avatarURL us.avatarURL + webcamBackgroundURL us.webcamBackgroundURL if (meeting.breakoutRoomsParams != null) { breakoutRooms { record meeting.breakoutRoomsParams.record diff --git a/docs/docs/data/join.tsx b/docs/docs/data/join.tsx index ce52eaab86..24d10aab01 100644 --- a/docs/docs/data/join.tsx +++ b/docs/docs/data/join.tsx @@ -55,6 +55,12 @@ const joinEndpointTableData = [ "type": "String", "description": (<>The link for the user’s avatar to be displayed (default can be enabled/disabled and set with “useDefaultAvatar“ and “defaultAvatarURL“ in bbb-web.properties).) }, + { + "name": "webcamBackgroundURL", + "required": false, + "type": "String", + "description": (<>The link for the user's webcam background to be displayed (default can be enabled/disabled and set with “useDefaultWebcamBackground“ and “defaultWebcamBackgroundURL“ in bigbluebutton.properties). Added in BigBlueButton 2.7.10.) + }, { "name": "redirect", "required": false,