diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingAfterReconnectReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingAfterReconnectReqMsgHdlr.scala new file mode 100644 index 0000000000..43015c26f5 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingAfterReconnectReqMsgHdlr.scala @@ -0,0 +1,34 @@ +package org.bigbluebutton.core.apps.users + +import org.bigbluebutton.common2.msgs.UserJoinMeetingAfterReconnectReqMsg +import org.bigbluebutton.core.apps.breakout.BreakoutHdlrHelpers +import org.bigbluebutton.core.apps.voice.UserJoinedVoiceConfEvtMsgHdlr +import org.bigbluebutton.core.domain.MeetingState2x +import org.bigbluebutton.core.models.VoiceUsers +import org.bigbluebutton.core.running.{ BaseMeetingActor, HandlerHelpers, LiveMeeting, OutMsgRouter } + +trait UserJoinMeetingAfterReconnectReqMsgHdlr extends HandlerHelpers with BreakoutHdlrHelpers with UserJoinedVoiceConfEvtMsgHdlr { + this: BaseMeetingActor => + + val liveMeeting: LiveMeeting + val outGW: OutMsgRouter + + def handleUserJoinMeetingAfterReconnectReqMsg(msg: UserJoinMeetingAfterReconnectReqMsg, state: MeetingState2x): MeetingState2x = { + val newState = userJoinMeeting(outGW, msg.body.authToken, liveMeeting, state) + + if (liveMeeting.props.meetingProp.isBreakout) { + updateParentMeetingWithUsers() + } + + // recover voice user + for { + vu <- VoiceUsers.recoverVoiceUser(liveMeeting.voiceUsers, msg.body.userId) + } yield { + handleUserJoinedVoiceConfEvtMsg(liveMeeting.props.voiceProp.voiceConf, vu.intId, vu.voiceUserId, vu.callingWith, vu.callerName, vu.callerNum, vu.muted, vu.talking) + } + + newState + } + +} + diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingReqMsgHdlr.scala index 28854e5a74..f2b451b3dc 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingReqMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingReqMsgHdlr.scala @@ -2,6 +2,7 @@ package org.bigbluebutton.core.apps.users import org.bigbluebutton.common2.msgs.UserJoinMeetingReqMsg import org.bigbluebutton.core.apps.breakout.BreakoutHdlrHelpers +import org.bigbluebutton.core.models.VoiceUsers import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.running.{ BaseMeetingActor, HandlerHelpers, LiveMeeting, OutMsgRouter } @@ -18,6 +19,9 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers with BreakoutHdlrHelpers updateParentMeetingWithUsers() } + // fresh user joined (not due to reconnection). Clear (pop) the cached voice user + VoiceUsers.recoverVoiceUser(liveMeeting.voiceUsers, msg.body.userId) + newState } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserLeaveReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserLeaveReqMsgHdlr.scala index e279757261..cfe141e650 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserLeaveReqMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserLeaveReqMsgHdlr.scala @@ -45,7 +45,7 @@ trait UserLeaveReqMsgHdlr { val envelope = BbbCoreEnvelope(UserLeftVoiceConfToClientEvtMsg.NAME, routing) val header = BbbClientMsgHeader(UserLeftVoiceConfToClientEvtMsg.NAME, liveMeeting.props.meetingProp.intId, vu.intId) - val body = UserLeftVoiceConfToClientEvtMsgBody(voiceConf = liveMeeting.props.voiceProp.voiceConf, intId = vu.intId, voiceUserId = vu.intId) + val body = UserLeftVoiceConfToClientEvtMsgBody(voiceConf = liveMeeting.props.voiceProp.voiceConf, intId = vu.intId, voiceUserId = vu.voiceUserId) val event = UserLeftVoiceConfToClientEvtMsg(header, body) val msgEvent = BbbCommonEnvCoreMsg(envelope, event) 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 7a67af294e..a3bdede2ad 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 @@ -2,7 +2,7 @@ package org.bigbluebutton.core.apps.voice import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.core.apps.breakout.BreakoutHdlrHelpers -import org.bigbluebutton.core.models.{ VoiceUser2x, VoiceUserState, VoiceUsers } +import org.bigbluebutton.core.models.{ VoiceUserState, VoiceUsers } import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting, OutMsgRouter } import org.bigbluebutton.core2.MeetingStatus2x @@ -15,6 +15,12 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends BreakoutHdlrHelpers { def handleUserJoinedVoiceConfEvtMsg(msg: UserJoinedVoiceConfEvtMsg): Unit = { log.info("Received user joined voice conference " + msg) + handleUserJoinedVoiceConfEvtMsg(msg.body.voiceConf, msg.body.intId, msg.body.voiceUserId, + msg.body.callingWith, msg.body.callerIdName, msg.body.callerIdNum, msg.body.muted, msg.body.talking) + } + + def handleUserJoinedVoiceConfEvtMsg(voiceConf: String, intId: String, voiceUserId: String, callingWith: String, + callerIdName: String, callerIdNum: String, muted: Boolean, talking: Boolean): Unit = { def broadcastEvent(voiceUserState: VoiceUserState): Unit = { val routing = Routing.addMsgToClientRouting( MessageTypes.BROADCAST_TO_MEETING, @@ -26,20 +32,16 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends BreakoutHdlrHelpers { liveMeeting.props.meetingProp.intId, voiceUserState.intId ) - val body = UserJoinedVoiceConfToClientEvtMsgBody(voiceConf = msg.body.voiceConf, intId = voiceUserState.intId, voiceUserId = voiceUserState.voiceUserId, - callerName = voiceUserState.callerName, callerNum = voiceUserState.callerNum, muted = voiceUserState.muted, - talking = voiceUserState.talking, callingWith = voiceUserState.callingWith, listenOnly = voiceUserState.listenOnly) + val body = UserJoinedVoiceConfToClientEvtMsgBody(voiceConf, voiceUserState.intId, voiceUserState.voiceUserId, + voiceUserState.callerName, voiceUserState.callerNum, voiceUserState.muted, voiceUserState.talking, + voiceUserState.callingWith, voiceUserState.listenOnly) val event = UserJoinedVoiceConfToClientEvtMsg(header, body) val msgEvent = BbbCommonEnvCoreMsg(envelope, event) outGW.send(msgEvent) - } - val voiceUser = VoiceUser2x(msg.body.intId, msg.body.voiceUserId) - val voiceUserState = VoiceUserState(intId = msg.body.intId, voiceUserId = msg.body.voiceUserId, - callingWith = msg.body.callingWith, callerName = msg.body.callerIdName, callerNum = msg.body.callerIdNum, - muted = msg.body.muted, talking = msg.body.talking, listenOnly = false) + val voiceUserState = VoiceUserState(intId, voiceUserId, callingWith, callerIdName, callerIdNum, muted, talking, listenOnly = false) VoiceUsers.add(liveMeeting.voiceUsers, voiceUserState) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/VoiceUsers.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/VoiceUsers.scala index 53b3988cf1..282999b16d 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/VoiceUsers.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/VoiceUsers.scala @@ -25,6 +25,10 @@ object VoiceUsers { users.toVector.find(u => u.intId == intId) } + def recoverVoiceUser(users: VoiceUsers, intId: String): Option[VoiceUserState] = { + users.removeFromCache(intId) + } + def userMuted(users: VoiceUsers, voiceUserId: String, muted: Boolean): Option[VoiceUserState] = { for { u <- findWithVoiceUserId(users, voiceUserId) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala index 4cf29839ba..6f0872b82d 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala @@ -62,6 +62,8 @@ class ReceivedJsonMsgHandlerActor( route[RegisterUserReqMsg](meetingManagerChannel, envelope, jsonNode) case UserJoinMeetingReqMsg.NAME => routeGenericMsg[UserJoinMeetingReqMsg](envelope, jsonNode) + case UserJoinMeetingAfterReconnectReqMsg.NAME => + routeGenericMsg[UserJoinMeetingAfterReconnectReqMsg](envelope, jsonNode) case GetAllMeetingsReqMsg.NAME => route[GetAllMeetingsReqMsg](meetingManagerChannel, envelope, jsonNode) case DestroyMeetingSysCmdMsg.NAME => diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala index 260fd4c0a5..965d16d973 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala @@ -64,6 +64,7 @@ class MeetingActor( with PermisssionCheck with UserBroadcastCamStartMsgHdlr with UserJoinMeetingReqMsgHdlr + with UserJoinMeetingAfterReconnectReqMsgHdlr with UserBroadcastCamStopMsgHdlr with UserConnectedToGlobalAudioMsgHdlr with UserDisconnectedFromGlobalAudioMsgHdlr @@ -181,6 +182,8 @@ class MeetingActor( state = usersApp.handleValidateAuthTokenReqMsg(m, state) case m: UserJoinMeetingReqMsg => state = handleUserJoinMeetingReqMsg(m, state) + case m: UserJoinMeetingAfterReconnectReqMsg => + state = handleUserJoinMeetingAfterReconnectReqMsg(m, state) case m: UserLeaveReqMsg => state = handleUserLeaveReqMsg(m, state) case m: UserBroadcastCamStartMsg => handleUserBroadcastCamStartMsg(m) diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMgs.scala index aa5bc35f31..ca9d422502 100755 --- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMgs.scala +++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMgs.scala @@ -229,6 +229,14 @@ object UserJoinMeetingReqMsg { val NAME = "UserJoinMeetingReqMsg" } case class UserJoinMeetingReqMsg(header: BbbClientMsgHeader, body: UserJoinMeetingReqMsgBody) extends StandardMsg case class UserJoinMeetingReqMsgBody(userId: String, authToken: String) +/** + * Sent from Flash client to rejoin meeting after reconnection + */ +object UserJoinMeetingAfterReconnectReqMsg { val NAME = "UserJoinMeetingAfterReconnectReqMsg" } +case class UserJoinMeetingAfterReconnectReqMsg(header: BbbClientMsgHeader, body: UserJoinMeetingAfterReconnectReqMsgBody) extends StandardMsg +case class UserJoinMeetingAfterReconnectReqMsgBody(userId: String, authToken: String) + + object UserLeaveReqMsg { val NAME = "UserLeaveReqMsg" } case class UserLeaveReqMsg(header: BbbClientMsgHeader, body: UserLeaveReqMsgBody) extends StandardMsg case class UserLeaveReqMsgBody(userId: String, sessionId: String) diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/events/TokenValidReconnectEvent.as b/bigbluebutton-client/src/org/bigbluebutton/core/events/TokenValidReconnectEvent.as new file mode 100644 index 0000000000..3ff05da640 --- /dev/null +++ b/bigbluebutton-client/src/org/bigbluebutton/core/events/TokenValidReconnectEvent.as @@ -0,0 +1,16 @@ +package org.bigbluebutton.core.events +{ +import flash.events.Event; + +public class TokenValidReconnectEvent extends Event +{ + public static const TOKEN_VALID_RECONNECT_EVENT:String = "auth token valid reconnect event"; + + public function TokenValidReconnectEvent() + { + super(TOKEN_VALID_RECONNECT_EVENT, true, false); + } + +} + +} diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as index cd896f1092..9653f1c9cc 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as +++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as @@ -38,6 +38,7 @@ package org.bigbluebutton.main.model.users import org.bigbluebutton.core.connection.messages.ValidateAuthTokenReqMsg; import org.bigbluebutton.core.connection.messages.ValidateAuthTokenReqMsgBody; import org.bigbluebutton.core.events.TokenValidEvent; + import org.bigbluebutton.core.events.TokenValidReconnectEvent; import org.bigbluebutton.core.managers.ReconnectionManager; import org.bigbluebutton.core.model.LiveMeeting; import org.bigbluebutton.core.services.BandwidthMonitor; @@ -136,15 +137,19 @@ package org.bigbluebutton.main.model.users LOGGER.info(JSON.stringify(logData)); if (tokenValid) { - LiveMeeting.inst().me.authTokenValid = true; - if (waitForApproval) { - var waitCommand:BBBEvent = new BBBEvent(BBBEvent.WAITING_FOR_MODERATOR_ACCEPTANCE); - dispatcher.dispatchEvent(waitCommand); + LiveMeeting.inst().me.authTokenValid = true; + if (waitForApproval) { + var waitCommand:BBBEvent = new BBBEvent(BBBEvent.WAITING_FOR_MODERATOR_ACCEPTANCE); + dispatcher.dispatchEvent(waitCommand); + } else { + LiveMeeting.inst().me.waitingForApproval = false; + if (reconnecting) { + dispatcher.dispatchEvent(new TokenValidReconnectEvent()); } else { - LiveMeeting.inst().me.waitingForApproval = false; dispatcher.dispatchEvent(new TokenValidEvent()); - sendConnectionSuccessEvent(userId); } + sendConnectionSuccessEvent(userId); + } } else { dispatcher.dispatchEvent(new InvalidAuthTokenEvent()); } diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as index 6fd2407513..246944c813 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as +++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as @@ -29,6 +29,7 @@ package org.bigbluebutton.main.model.users import org.bigbluebutton.core.UsersUtil; import org.bigbluebutton.core.events.LockControlEvent; import org.bigbluebutton.core.events.TokenValidEvent; + import org.bigbluebutton.core.events.TokenValidReconnectEvent; import org.bigbluebutton.core.events.VoiceConfEvent; import org.bigbluebutton.core.managers.ConnectionManager; import org.bigbluebutton.core.model.LiveMeeting; @@ -149,7 +150,11 @@ package org.bigbluebutton.main.model.users public function tokenValidEventHandler(event: TokenValidEvent): void { sender.joinMeeting(); } - + + public function tokenValidReconnectEventHandler(event: TokenValidReconnectEvent): void { + sender.joinMeetingAfterReconnect(); + } + public function logoutEndMeeting():void{ if (this.isModerator()) { var myUserId: String = UsersUtil.getMyUserID(); @@ -188,6 +193,7 @@ package org.bigbluebutton.main.model.users reconnecting = false; } else { onAllowedToJoin(); + } } diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/maps/UsersMainEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/maps/UsersMainEventMap.mxml index 2a67382431..610e50e8a3 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/maps/UsersMainEventMap.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/maps/UsersMainEventMap.mxml @@ -27,6 +27,7 @@ with BigBlueButton; if not, see . import org.bigbluebutton.core.events.LockControlEvent; import org.bigbluebutton.core.events.TokenValidEvent; + import org.bigbluebutton.core.events.TokenValidReconnectEvent; import org.bigbluebutton.core.events.VoiceConfEvent; import org.bigbluebutton.main.events.BBBEvent; import org.bigbluebutton.main.events.BreakoutRoomEvent; @@ -115,7 +116,11 @@ with BigBlueButton; if not, see . - + + + + + diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageSender.as b/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageSender.as index 28862d9573..5a2201f480 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageSender.as +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageSender.as @@ -73,11 +73,29 @@ package org.bigbluebutton.modules.users.services }, function(status:String):void { // status - On error occurred var logData:Object = UsersUtil.initLogData(); logData.tags = ["apps"]; - logData.message = "Error occurred assigning a presenter."; + logData.message = "Error occurred when user joining."; LOGGER.info(JSON.stringify(logData)); }, JSON.stringify(message)); } - + + public function joinMeetingAfterReconnect(): void { + LOGGER.info("Sending JOIN MEETING AFTER RECONNECT message"); + + var message:Object = { + header: {name: "UserJoinMeetingAfterReconnectReqMsg", meetingId: UsersUtil.getInternalMeetingID(), userId: UsersUtil.getMyUserID()}, + body: {userId: UsersUtil.getMyUserID(), authToken: LiveMeeting.inst().me.authToken} + }; + + var _nc:ConnectionManager = BBB.initConnectionManager(); + _nc.sendMessage2x(function(result:String):void { // On successful result + }, function(status:String):void { // status - On error occurred + var logData:Object = UsersUtil.initLogData(); + logData.tags = ["apps"]; + logData.message = "Error occurred when user joining after reconnect."; + LOGGER.info(JSON.stringify(logData)); + }, JSON.stringify(message)); + } + public function assignPresenter(newPresenterUserId:String, newPresenterName:String, assignedBy:String):void { var message:Object = { header: {name: "AssignPresenterReqMsg", meetingId: UsersUtil.getInternalMeetingID(), userId: UsersUtil.getMyUserID()},