Merge remote-tracking branch 'pedrobmarin/reconnection-timeout' into mconf/mconf
Conflicts: bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/api/InMessages.scala bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/api/ValueObjects.scala bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersModel.scala bigbluebutton-apps/src/main/scala/org/bigbluebutton/freeswitch/FreeswitchConference.scala bigbluebutton-apps/src/main/scala/org/bigbluebutton/freeswitch/FreeswitchConferenceActor.scala bigbluebutton-client/src/org/bigbluebutton/main/api/ExternalApiCallbacks.as bigbluebutton-client/src/org/bigbluebutton/main/api/ExternalApiCalls.as bigbluebutton-client/src/org/bigbluebutton/modules/phone/managers/ConnectionManager.as bigbluebutton-client/src/org/bigbluebutton/modules/phone/managers/FlashCallManager.as bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageReceiver.as
This commit is contained in:
commit
86841167e1
@ -37,7 +37,7 @@ class MeetingActor(val mProps: MeetingProperties, val outGW: OutMessageGateway)
|
||||
|
||||
private val InactivityDeadline = FiniteDuration(getInactivityDeadline(), "seconds")
|
||||
private val InactivityTimeLeft = FiniteDuration(getInactivityTimeLeft(), "seconds")
|
||||
private val MonitorFrequency = 30 seconds
|
||||
private val MonitorFrequency = 10 seconds
|
||||
private var deadline = InactivityDeadline.fromNow
|
||||
private var inactivityWarning: Deadline = null
|
||||
|
||||
@ -222,6 +222,8 @@ class MeetingActor(val mProps: MeetingProperties, val outGW: OutMessageGateway)
|
||||
handleRequestAdditionalNotesSetRequest(msg)
|
||||
case msg: SharedNotesSyncNoteRequest =>
|
||||
handleSharedNotesSyncNoteRequest(msg)
|
||||
case msg: ReconnectionTimeout =>
|
||||
handleReconnectionTimeout(msg)
|
||||
|
||||
case msg: EndMeeting => handleEndMeeting(msg)
|
||||
case StopMeetingActor => //exit
|
||||
@ -278,6 +280,7 @@ class MeetingActor(val mProps: MeetingProperties, val outGW: OutMessageGateway)
|
||||
def handleMonitor() {
|
||||
activity()
|
||||
numberOfWebUsers()
|
||||
usersReconnecting()
|
||||
}
|
||||
|
||||
private def numberOfWebUsers() {
|
||||
@ -303,6 +306,16 @@ class MeetingActor(val mProps: MeetingProperties, val outGW: OutMessageGateway)
|
||||
}
|
||||
}
|
||||
|
||||
private def usersReconnecting() {
|
||||
usersModel.getUsers foreach { u =>
|
||||
if (u.reconnectionStatus.reconnecting) {
|
||||
if (u.reconnectionStatus.deadline.isOverdue()) {
|
||||
self ! ReconnectionTimeout(mProps.meetingID, u.userID, u.reconnectionStatus.sessionId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def updateInactivityMonitors() {
|
||||
deadline = InactivityDeadline.fromNow
|
||||
inactivityWarning = null
|
||||
|
@ -45,6 +45,8 @@ case class SetRecordingStatus(meetingID: String, userId: String, recording: Bool
|
||||
case class GetRecordingStatus(meetingID: String, userId: String) extends InMessage
|
||||
case class ActivityResponse(meetingID: String) extends InMessage
|
||||
case class LogoutEndMeeting(meetingID: String, userID: String) extends InMessage
|
||||
// same attributes as UserLeaving
|
||||
case class ReconnectionTimeout(meetingID: String, userID: String, sessionId: String) extends InMessage
|
||||
|
||||
// Chat
|
||||
case class GetChatHistoryRequest(meetingID: String, requesterID: String, replyTo: String) extends InMessage
|
||||
|
@ -3,6 +3,7 @@ package org.bigbluebutton.core.api
|
||||
import java.lang.Boolean
|
||||
|
||||
import scala.collection.mutable.Stack
|
||||
import scala.concurrent.duration.Deadline
|
||||
|
||||
object Role extends Enumeration {
|
||||
type Role = Value
|
||||
@ -106,6 +107,11 @@ case class Voice(
|
||||
muted: Boolean,
|
||||
talking: Boolean)
|
||||
|
||||
case class ReconnectionStatus(
|
||||
sessionId: String,
|
||||
reconnecting: Boolean,
|
||||
deadline: Deadline)
|
||||
|
||||
case class UserVO(
|
||||
userID: String,
|
||||
externUserID: String,
|
||||
@ -121,7 +127,8 @@ case class UserVO(
|
||||
phoneUser: Boolean,
|
||||
voiceUser: VoiceUser,
|
||||
listenOnly: Boolean,
|
||||
joinedWeb: Boolean)
|
||||
joinedWeb: Boolean,
|
||||
reconnectionStatus: ReconnectionStatus)
|
||||
|
||||
case class VoiceUser(
|
||||
userId: String,
|
||||
|
@ -326,6 +326,7 @@ trait UsersApp {
|
||||
|
||||
val vu = wUser match {
|
||||
case Some(u) => {
|
||||
unshareAllWebcamsForUser(u.userID)
|
||||
log.debug("Found user. metingId=" + mProps.meetingID + " userId=" + msg.userID + " user=" + u)
|
||||
if (u.voiceUser.joined) {
|
||||
/*
|
||||
@ -354,18 +355,6 @@ trait UsersApp {
|
||||
}
|
||||
}
|
||||
|
||||
wUser.foreach { w =>
|
||||
if (!w.joinedWeb) {
|
||||
log.debug("User is in voice only. Mark as user left. metingId=" + mProps.meetingID + " userId=" + msg.userID)
|
||||
/**
|
||||
* If user is not joined through the web (perhaps reconnecting).
|
||||
* Send a user left event to clear up user list of all clients.
|
||||
*/
|
||||
val user = usersModel.removeUser(w.userID)
|
||||
outGW.send(new UserLeft(msg.meetingID, mProps.recorded, w))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the newly joined user copying voice status in case this
|
||||
* join is due to a reconnect.
|
||||
@ -375,7 +364,8 @@ trait UsersApp {
|
||||
ru.role, ru.guest, waitingForAcceptance = waitingForAcceptance, emojiStatus = "none", presenter = false,
|
||||
hasStream = false, locked = getInitialLockStatus(ru.role),
|
||||
webcamStreams = new ListSet[String](), phoneUser = false, vu,
|
||||
listenOnly = vu.listenOnly, joinedWeb = true)
|
||||
listenOnly = vu.listenOnly, joinedWeb = true,
|
||||
reconnectionStatus = new ReconnectionStatus("", false, null))
|
||||
|
||||
usersModel.addUser(uvo)
|
||||
|
||||
@ -404,26 +394,38 @@ trait UsersApp {
|
||||
if (usersModel.hasUser(msg.userID)) {
|
||||
val user = usersModel.removeUser(msg.userID)
|
||||
user foreach { u =>
|
||||
log.info("User left meeting. meetingId=" + mProps.meetingID + " userId=" + u.userID + " user=" + u)
|
||||
outGW.send(new UserLeft(msg.meetingID, mProps.recorded, u))
|
||||
if (u.voiceUser.joined && !u.reconnectionStatus.reconnecting) {
|
||||
log.info("User left meeting, but that might mean that the user is reconnecting. Marking the user as potential reconnection, and remove him in a few seconds if he doesn't reconnect: mid=[" + msg.meetingID + "] uid=[" + u.userID + "]")
|
||||
val rs = new ReconnectionStatus(msg.sessionId, true, usersModel.getReconnectionDeadline)
|
||||
val uvo = u.copy(hasStream = false, webcamStreams = new ListSet[String](), reconnectionStatus = rs)
|
||||
usersModel.addUser(uvo)
|
||||
} else {
|
||||
log.info("User left meeting: mid=[" + msg.meetingID + "] uid=[" + u.userID + "]")
|
||||
if (u.voiceUser.joined) {
|
||||
log.info("Sending eject to FreeSWITCH: mid=[" + msg.meetingID + "] uid=[" + u.userID + "]")
|
||||
outGW.send(new EjectVoiceUser(mProps.meetingID, mProps.recorded, null, msg.userID, mProps.voiceBridge, u.voiceUser.userId))
|
||||
}
|
||||
outGW.send(new UserLeft(mProps.meetingID, mProps.recorded, u))
|
||||
|
||||
makeSurePresenterIsAssigned(u)
|
||||
makeSurePresenterIsAssigned(u)
|
||||
|
||||
val vu = u.voiceUser
|
||||
if (vu.joined || u.listenOnly) {
|
||||
/**
|
||||
* The user that left is still in the voice conference. Maybe this user just got disconnected
|
||||
* and is reconnecting. Make the user as joined only in the voice conference. If we get a
|
||||
* user left voice conference message, then we will remove the user from the users list.
|
||||
*/
|
||||
switchUserToPhoneUser((new UserJoinedVoiceConfMessage(mProps.voiceBridge,
|
||||
vu.userId, u.userID, u.externUserID, vu.callerName,
|
||||
vu.callerNum, vu.muted, vu.talking, u.listenOnly)));
|
||||
startCheckingIfWeNeedToEndVoiceConf()
|
||||
stopAutoStartedRecording()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startCheckingIfWeNeedToEndVoiceConf()
|
||||
stopAutoStartedRecording()
|
||||
def handleReconnectionTimeout(msg: ReconnectionTimeout): Unit = {
|
||||
log.info("Reconnection timeout: mid=[" + msg.meetingID + "] uid=[" + msg.userID + "]")
|
||||
usersModel.getUser(msg.userID) match {
|
||||
case Some(u) => {
|
||||
if (u.reconnectionStatus.reconnecting) {
|
||||
log.info("User didn't reconnect in a few seconds: mid=[" + msg.meetingID + "] uid=[" + msg.userID + "]")
|
||||
this.context.self ! new UserLeaving(msg.meetingID, msg.userID, msg.sessionId)
|
||||
}
|
||||
}
|
||||
case None => // do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@ -463,7 +465,8 @@ trait UsersApp {
|
||||
Role.VIEWER, guest = false, waitingForAcceptance = false, emojiStatus = "none", presenter = false,
|
||||
hasStream = false, locked = getInitialLockStatus(Role.VIEWER),
|
||||
webcamStreams = new ListSet[String](),
|
||||
phoneUser = !msg.listenOnly, vu, listenOnly = msg.listenOnly, joinedWeb = false)
|
||||
phoneUser = !msg.listenOnly, vu, listenOnly = msg.listenOnly, joinedWeb = false,
|
||||
reconnectionStatus = new ReconnectionStatus("", false, null))
|
||||
|
||||
usersModel.addUser(uvo)
|
||||
|
||||
@ -659,4 +662,12 @@ trait UsersApp {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def unshareAllWebcamsForUser(userID: String) {
|
||||
usersModel.getUser(userID) foreach { user =>
|
||||
user.webcamStreams.foreach { stream =>
|
||||
this.context.self ! new UserUnshareWebcam(mProps.meetingID, user.userID, stream)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package org.bigbluebutton.core.apps
|
||||
|
||||
import scala.concurrent.duration.Deadline
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
import scala.collection.mutable.HashMap
|
||||
import org.bigbluebutton.core.api.UserVO
|
||||
import org.bigbluebutton.core.api.Role._
|
||||
@ -23,6 +25,7 @@ class UsersModel {
|
||||
private var locked = false
|
||||
private var meetingMuted = false
|
||||
private var recordingVoice = false
|
||||
private var reconnectionInterval = FiniteDuration(30, "seconds")
|
||||
|
||||
private var currentPresenter = new Presenter("system", "system", "system")
|
||||
|
||||
@ -211,4 +214,8 @@ class UsersModel {
|
||||
def isVoiceRecording: Boolean = {
|
||||
recordingVoice
|
||||
}
|
||||
|
||||
def getReconnectionDeadline: Deadline = {
|
||||
reconnectionInterval.fromNow
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<mate:Listener type="{PresenterStatusEvent.PRESENTER_NAME_CHANGE}" method="handlePresenterChangedEvent" />
|
||||
<mate:Listener type="{BBBEvent.USER_VOICE_LEFT}" method="handleUserVoiceChangedEvent" />
|
||||
<mate:Listener type="{BBBEvent.USER_VOICE_MUTED}" method="handleUserVoiceChangedEvent" />
|
||||
<mate:Listener type="{UserJoinedEvent.JOINED}" method="handleUserJoinedEvent" />
|
||||
|
||||
<mx:Script>
|
||||
<![CDATA[
|
||||
@ -47,6 +48,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
import org.bigbluebutton.core.vo.LockSettingsVO;
|
||||
import org.bigbluebutton.main.events.BBBEvent;
|
||||
import org.bigbluebutton.main.events.PresenterStatusEvent;
|
||||
import org.bigbluebutton.main.events.UserJoinedEvent;
|
||||
import org.bigbluebutton.main.model.users.BBBUser;
|
||||
import org.bigbluebutton.modules.videoconf.model.VideoConfOptions;
|
||||
import org.bigbluebutton.util.i18n.ResourceUtil;
|
||||
@ -78,6 +80,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
closeBtn.tabIndex = videoOptions.baseTabIndex + 10;
|
||||
}
|
||||
|
||||
private function handleUserJoinedEvent(event:UserJoinedEvent):void {
|
||||
// this is just to enforce the update of the BBBUser reference when the user reconnect
|
||||
if (user && event.userID == user.userID) {
|
||||
userId = event.userID;
|
||||
setUserProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public function set userId(value:String):void {
|
||||
_user = UsersUtil.getUser(value);
|
||||
_userId = value;
|
||||
|
Loading…
Reference in New Issue
Block a user