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:
Pedro Beschorner Marin 2017-04-07 19:40:35 +00:00
commit 86841167e1
6 changed files with 81 additions and 31 deletions

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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)
}
}
}
}

View File

@ -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
}
}

View File

@ -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;