Merge branch 'fix-breakout-room-messaging' of github.com:ritzalam/bigbluebutton into fix-breakout-room-messaging

This commit is contained in:
Richard Alam 2017-07-25 17:44:17 -07:00
commit 0f04b69897
18 changed files with 1537 additions and 1506 deletions

View File

@ -3,7 +3,7 @@ package org.bigbluebutton.core.apps.users
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.domain.{ MeetingExpiryTracker, MeetingState2x }
import org.bigbluebutton.core.models.Users2x
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
import org.bigbluebutton.core.running.{ LiveMeeting, MeetingActor, OutMsgRouter }
import org.bigbluebutton.core.util.TimeUtil
import org.bigbluebutton.core2.message.senders.MsgBuilder
@ -26,10 +26,13 @@ trait UserLeaveReqMsgHdlr {
outGW.send(userLeftMeetingEvent)
log.info("User left meetingId=" + liveMeeting.props.meetingProp.intId + " userId=" + msg.body.userId)
if (u.presenter) {
automaticallyAssignPresenter(outGW, liveMeeting)
}
}
if (Users2x.numUsers(liveMeeting.users2x) == 0) {
val tracker = state.expiryTracker.setLastUserLeftOn(TimeUtil.timeNowInSeconds())
val tracker = state.expiryTracker.setLastUserLeftOn(TimeUtil.timeNowInMs())
state.update(tracker)
} else {
state

View File

@ -3,103 +3,93 @@ package org.bigbluebutton.core.domain
import org.bigbluebutton.core.util.TimeUtil
case class MeetingInactivityTracker(
val maxInactivityTimeoutMinutes: Int,
val warningMinutesBeforeMax: Int,
lastActivityTimestamp: Long,
warningSent: Boolean,
warningSentOnTimestamp: Long
val maxInactivityTimeoutInMs: Long,
val warningBeforeMaxInMs: Long,
lastActivityTimestampInMs: Long,
warningSent: Boolean,
warningSentOnTimestampInMs: Long
) {
def setWarningSentAndTimestamp(nowInSeconds: Long): MeetingInactivityTracker = {
copy(warningSent = true, warningSentOnTimestamp = nowInSeconds)
def setWarningSentAndTimestamp(nowInMs: Long): MeetingInactivityTracker = {
copy(warningSent = true, warningSentOnTimestampInMs = nowInMs)
}
def resetWarningSentAndTimestamp(): MeetingInactivityTracker = {
copy(warningSent = false, warningSentOnTimestamp = 0L)
copy(warningSent = false, warningSentOnTimestampInMs = 0L)
}
def updateLastActivityTimestamp(nowInSeconds: Long): MeetingInactivityTracker = {
copy(lastActivityTimestamp = nowInSeconds)
def updateLastActivityTimestamp(nowInMs: Long): MeetingInactivityTracker = {
copy(lastActivityTimestampInMs = nowInMs)
}
def hasRecentActivity(nowInSeconds: Long): Boolean = {
nowInSeconds - lastActivityTimestamp <
TimeUtil.minutesToSeconds(maxInactivityTimeoutMinutes) -
TimeUtil.minutesToSeconds(warningMinutesBeforeMax)
def hasRecentActivity(nowInMs: Long): Boolean = {
nowInMs - lastActivityTimestampInMs < maxInactivityTimeoutInMs - warningBeforeMaxInMs
}
def isMeetingInactive(nowInSeconds: Long): Boolean = {
warningSent &&
(nowInSeconds - lastActivityTimestamp) >
TimeUtil.minutesToSeconds(maxInactivityTimeoutMinutes)
def isMeetingInactive(nowInMs: Long): Boolean = {
warningSent && (nowInMs - lastActivityTimestampInMs) > maxInactivityTimeoutInMs
}
def timeLeftInSeconds(nowInSeconds: Long): Long = {
lastActivityTimestamp +
TimeUtil.minutesToSeconds(maxInactivityTimeoutMinutes) - nowInSeconds
def timeLeftInMs(nowInMs: Long): Long = {
lastActivityTimestampInMs + maxInactivityTimeoutInMs - nowInMs
}
}
case class MeetingExpiryTracker(
startedOn: Long,
userHasJoined: Boolean,
lastUserLeftOn: Option[Long],
durationInMinutes: Int,
meetingExpireIfNoUserJoinedInMinutes: Int,
meetingExpireWhenLastUserLeftInMinutes: Int
startedOnInMs: Long,
userHasJoined: Boolean,
lastUserLeftOnInMs: Option[Long],
durationInMs: Long,
meetingExpireIfNoUserJoinedInMs: Long,
meetingExpireWhenLastUserLeftInMs: Long
) {
def setMeetingStartedOn(timestampInSeconds: Long): MeetingExpiryTracker = {
copy(startedOn = timestampInSeconds)
}
def setUserHasJoined(): MeetingExpiryTracker = {
if (userHasJoined) {
if (!userHasJoined) {
copy(userHasJoined = true)
} else {
copy()
}
}
def setLastUserLeftOn(timestampInSeconds: Long): MeetingExpiryTracker = {
copy(lastUserLeftOn = Some(timestampInSeconds))
def setLastUserLeftOn(timestampInMs: Long): MeetingExpiryTracker = {
copy(lastUserLeftOnInMs = Some(timestampInMs))
}
def hasMeetingExpiredAfterLastUserLeft(timestampInSeconds: Long): Boolean = {
def hasMeetingExpiredAfterLastUserLeft(timestampInMs: Long): Boolean = {
val expire = for {
lastUserLeftOn <- lastUserLeftOn
lastUserLeftOn <- lastUserLeftOnInMs
} yield {
timestampInSeconds - lastUserLeftOn >
TimeUtil.minutesToSeconds(meetingExpireWhenLastUserLeftInMinutes)
timestampInMs - lastUserLeftOn > meetingExpireWhenLastUserLeftInMs
}
expire.getOrElse(false)
}
def hasMeetingExpired(timestampInSeconds: Long): (Boolean, Option[String]) = {
if (hasMeetingExpiredNeverBeenJoined(timestampInSeconds)) {
def hasMeetingExpired(timestampInMs: Long): (Boolean, Option[String]) = {
if (hasMeetingExpiredNeverBeenJoined(timestampInMs)) {
(true, Some(MeetingEndReason.ENDED_WHEN_NOT_JOINED))
} else if (meetingOverDuration(timestampInSeconds)) {
} else if (meetingOverDuration(timestampInMs)) {
(true, Some(MeetingEndReason.ENDED_AFTER_EXCEEDING_DURATION))
} else if (hasMeetingExpiredAfterLastUserLeft(timestampInSeconds)) {
} else if (hasMeetingExpiredAfterLastUserLeft(timestampInMs)) {
(true, Some(MeetingEndReason.ENDED_WHEN_LAST_USER_LEFT))
} else {
(false, None)
}
}
def hasMeetingExpiredNeverBeenJoined(nowInSeconds: Long): Boolean = {
!userHasJoined && (nowInSeconds - startedOn > TimeUtil.minutesToSeconds(meetingExpireIfNoUserJoinedInMinutes))
def hasMeetingExpiredNeverBeenJoined(nowInMs: Long): Boolean = {
!userHasJoined && (nowInMs - startedOnInMs > meetingExpireIfNoUserJoinedInMs)
}
def meetingOverDuration(nowInSeconds: Long): Boolean = {
if (durationInMinutes == 0) {
def meetingOverDuration(nowInMs: Long): Boolean = {
if (durationInMs == 0) {
false
} else {
nowInSeconds > startedOn + TimeUtil.minutesToSeconds(durationInMinutes)
nowInMs > startedOnInMs + durationInMs
}
}
def endMeetingTime(): Int = {
(startedOn + TimeUtil.minutesToSeconds(durationInMinutes)).toInt
def endMeetingTime(): Long = {
startedOnInMs + durationInMs
}
}

View File

@ -106,20 +106,20 @@ class MeetingActor(
object ExpiryTrackerHelper extends MeetingExpiryTrackerHelper
val inactivityTracker = new MeetingInactivityTracker(
props.durationProps.maxInactivityTimeoutMinutes,
props.durationProps.warnMinutesBeforeMax,
lastActivityTimestamp = TimeUtil.timeNowInSeconds(),
TimeUtil.minutesToMillis(props.durationProps.maxInactivityTimeoutMinutes),
TimeUtil.minutesToMillis(props.durationProps.warnMinutesBeforeMax),
lastActivityTimestampInMs = TimeUtil.timeNowInMs(),
warningSent = false,
warningSentOnTimestamp = 0L
warningSentOnTimestampInMs = 0L
)
val expiryTracker = new MeetingExpiryTracker(
startedOn = TimeUtil.timeNowInSeconds(),
startedOnInMs = TimeUtil.timeNowInMs(),
userHasJoined = false,
lastUserLeftOn = None,
durationInMinutes = props.durationProps.duration,
meetingExpireIfNoUserJoinedInMinutes = props.durationProps.meetingExpireIfNoUserJoinedInMinutes,
meetingExpireWhenLastUserLeftInMinutes = props.durationProps.meetingExpireWhenLastUserLeftInMinutes
lastUserLeftOnInMs = None,
durationInMs = TimeUtil.minutesToMillis(props.durationProps.duration),
meetingExpireIfNoUserJoinedInMs = TimeUtil.minutesToMillis(props.durationProps.meetingExpireIfNoUserJoinedInMinutes),
meetingExpireWhenLastUserLeftInMs = TimeUtil.minutesToMillis(props.durationProps.meetingExpireWhenLastUserLeftInMinutes)
)
var state = new MeetingState2x(None, inactivityTracker, expiryTracker)
@ -152,20 +152,23 @@ class MeetingActor(
case msg: SendTimeRemainingAuditInternalMsg =>
state = handleSendTimeRemainingUpdate(msg, state)
state = handleSendBreakoutTimeRemainingMsg(msg, state)
case msg: BreakoutRoomCreatedInternalMsg => state = handleBreakoutRoomCreatedInternalMsg(msg, state)
case msg: SendBreakoutUsersAuditInternalMsg => handleSendBreakoutUsersUpdateInternalMsg(msg)
case msg: BreakoutRoomUsersUpdateInternalMsg => state = handleBreakoutRoomUsersUpdateInternalMsg(msg, state)
case msg: EndBreakoutRoomInternalMsg => handleEndBreakoutRoomInternalMsg(msg)
case msg: BreakoutRoomEndedInternalMsg => state = handleBreakoutRoomEndedInternalMsg(msg, state)
case msg: BreakoutRoomCreatedInternalMsg =>
state = handleBreakoutRoomCreatedInternalMsg(msg, state)
case msg: SendBreakoutUsersAuditInternalMsg => handleSendBreakoutUsersUpdateInternalMsg(msg)
case msg: BreakoutRoomUsersUpdateInternalMsg =>
state = handleBreakoutRoomUsersUpdateInternalMsg(msg, state)
case msg: EndBreakoutRoomInternalMsg => handleEndBreakoutRoomInternalMsg(msg)
case msg: BreakoutRoomEndedInternalMsg =>
state = handleBreakoutRoomEndedInternalMsg(msg, state)
// Screenshare
case msg: DeskShareGetDeskShareInfoRequest => handleDeskShareGetDeskShareInfoRequest(msg)
case msg: DeskShareGetDeskShareInfoRequest => handleDeskShareGetDeskShareInfoRequest(msg)
case _ => // do nothing
case _ => // do nothing
}
private def handleBbbCommonEnvCoreMsg(msg: BbbCommonEnvCoreMsg): Unit = {
val tracker = state.inactivityTracker.updateLastActivityTimestamp(TimeUtil.timeNowInSeconds())
val tracker = state.inactivityTracker.updateLastActivityTimestamp(TimeUtil.timeNowInMs())
state = state.update(tracker)
msg.core match {
@ -181,37 +184,42 @@ class MeetingActor(
case m: UserJoinedVoiceConfEvtMsg => handleUserJoinedVoiceConfEvtMsg(m)
case m: MeetingActivityResponseCmdMsg =>
state = usersApp.handleMeetingActivityResponseCmdMsg(m, state)
case m: LogoutAndEndMeetingCmdMsg => usersApp.handleLogoutAndEndMeetingCmdMsg(m)
case m: SetRecordingStatusCmdMsg => usersApp.handleSetRecordingStatusCmdMsg(m)
case m: GetRecordingStatusReqMsg => usersApp.handleGetRecordingStatusReqMsg(m)
case m: ChangeUserEmojiCmdMsg => handleChangeUserEmojiCmdMsg(m)
case m: EjectUserFromMeetingCmdMsg => usersApp.handleEjectUserFromMeetingCmdMsg(m)
case m: GetUsersMeetingReqMsg => usersApp.handleGetUsersMeetingReqMsg(m)
case m: LogoutAndEndMeetingCmdMsg => usersApp.handleLogoutAndEndMeetingCmdMsg(m)
case m: SetRecordingStatusCmdMsg => usersApp.handleSetRecordingStatusCmdMsg(m)
case m: GetRecordingStatusReqMsg => usersApp.handleGetRecordingStatusReqMsg(m)
case m: ChangeUserEmojiCmdMsg => handleChangeUserEmojiCmdMsg(m)
case m: EjectUserFromMeetingCmdMsg => usersApp.handleEjectUserFromMeetingCmdMsg(m)
case m: GetUsersMeetingReqMsg => usersApp.handleGetUsersMeetingReqMsg(m)
// Whiteboard
case m: SendCursorPositionPubMsg => handleSendCursorPositionPubMsg(m)
case m: ClearWhiteboardPubMsg => handleClearWhiteboardPubMsg(m)
case m: UndoWhiteboardPubMsg => handleUndoWhiteboardPubMsg(m)
case m: ModifyWhiteboardAccessPubMsg => handleModifyWhiteboardAccessPubMsg(m)
case m: GetWhiteboardAccessReqMsg => handleGetWhiteboardAccessReqMsg(m)
case m: SendCursorPositionPubMsg => handleSendCursorPositionPubMsg(m)
case m: ClearWhiteboardPubMsg => handleClearWhiteboardPubMsg(m)
case m: UndoWhiteboardPubMsg => handleUndoWhiteboardPubMsg(m)
case m: ModifyWhiteboardAccessPubMsg => handleModifyWhiteboardAccessPubMsg(m)
case m: GetWhiteboardAccessReqMsg => handleGetWhiteboardAccessReqMsg(m)
case m: SendWhiteboardAnnotationPubMsg => handleSendWhiteboardAnnotationPubMsg(m)
case m: GetWhiteboardAnnotationsReqMsg => handleGetWhiteboardAnnotationsReqMsg(m)
// Poll
case m: StartPollReqMsg => handleStartPollReqMsg(m)
case m: StartCustomPollReqMsg => handleStartCustomPollReqMsg(m)
case m: StopPollReqMsg => handleStopPollReqMsg(m)
case m: ShowPollResultReqMsg => handleShowPollResultReqMsg(m)
case m: HidePollResultReqMsg => handleHidePollResultReqMsg(m)
case m: GetCurrentPollReqMsg => handleGetCurrentPollReqMsg(m)
case m: RespondToPollReqMsg => handleRespondToPollReqMsg(m)
case m: StartPollReqMsg => handleStartPollReqMsg(m)
case m: StartCustomPollReqMsg => handleStartCustomPollReqMsg(m)
case m: StopPollReqMsg => handleStopPollReqMsg(m)
case m: ShowPollResultReqMsg => handleShowPollResultReqMsg(m)
case m: HidePollResultReqMsg => handleHidePollResultReqMsg(m)
case m: GetCurrentPollReqMsg => handleGetCurrentPollReqMsg(m)
case m: RespondToPollReqMsg => handleRespondToPollReqMsg(m)
// Breakout
case m: BreakoutRoomsListMsg => state = handleBreakoutRoomsListMsg(m, state)
case m: CreateBreakoutRoomsCmdMsg => state = handleCreateBreakoutRoomsCmdMsg(m, state)
case m: EndAllBreakoutRoomsMsg => state = handleEndAllBreakoutRoomsMsg(m, state)
case m: RequestBreakoutJoinURLReqMsg => state = handleRequestBreakoutJoinURLReqMsg(m, state)
case m: TransferUserToMeetingRequestMsg => state = handleTransferUserToMeetingRequestMsg(m, state)
case m: BreakoutRoomsListMsg =>
state = handleBreakoutRoomsListMsg(m, state)
case m: CreateBreakoutRoomsCmdMsg =>
state = handleCreateBreakoutRoomsCmdMsg(m, state)
case m: EndAllBreakoutRoomsMsg =>
state = handleEndAllBreakoutRoomsMsg(m, state)
case m: RequestBreakoutJoinURLReqMsg =>
state = handleRequestBreakoutJoinURLReqMsg(m, state)
case m: TransferUserToMeetingRequestMsg =>
state = handleTransferUserToMeetingRequestMsg(m, state)
// Voice
case m: UserLeftVoiceConfEvtMsg => handleUserLeftVoiceConfEvtMsg(m)

View File

@ -6,19 +6,21 @@ import org.bigbluebutton.core.domain.{ MeetingEndReason, MeetingState2x }
import org.bigbluebutton.core.util.TimeUtil
trait MeetingExpiryTrackerHelper extends HandlerHelpers {
def processMeetingExpiryAudit(
outGW: OutMsgRouter,
eventBus: InternalEventBus,
liveMeeting: LiveMeeting,
state: MeetingState2x
): MeetingState2x = {
val nowInSeconds = TimeUtil.timeNowInSeconds()
val nowInMs = TimeUtil.timeNowInMs()
val (expired, reason) = state.expiryTracker.hasMeetingExpired(nowInSeconds)
val (expired, reason) = state.expiryTracker.hasMeetingExpired(nowInMs)
if (expired) {
for {
expireReason <- reason
} yield {
println("**** Ending meeting for reason " + expireReason)
sendEndMeetingDueToExpiry(expireReason, eventBus, outGW, liveMeeting)
}
}
@ -33,17 +35,18 @@ trait MeetingExpiryTrackerHelper extends HandlerHelpers {
state: MeetingState2x
): MeetingState2x = {
val nowInSeconds = TimeUtil.timeNowInSeconds()
if (!state.inactivityTracker.hasRecentActivity(nowInSeconds)) {
if (state.inactivityTracker.isMeetingInactive(nowInSeconds)) {
val nowInMs = TimeUtil.timeNowInMs()
if (!state.inactivityTracker.hasRecentActivity(nowInMs)) {
if (state.inactivityTracker.isMeetingInactive(nowInMs)) {
println("**** Ending meeting due to inactivity!")
sendEndMeetingDueToExpiry(MeetingEndReason.ENDED_DUE_TO_INACTIVITY, eventBus, outGW, liveMeeting)
state
} else {
if (!state.inactivityTracker.warningSent) {
val timeLeftSeconds = state.inactivityTracker.timeLeftInSeconds(nowInSeconds)
val timeLeftSeconds = TimeUtil.millisToSeconds(state.inactivityTracker.timeLeftInMs(nowInMs))
val event = buildMeetingInactivityWarningEvtMsg(liveMeeting.props.meetingProp.intId, timeLeftSeconds)
outGW.send(event)
val tracker = state.inactivityTracker.setWarningSentAndTimestamp(nowInSeconds)
val tracker = state.inactivityTracker.setWarningSentAndTimestamp(nowInMs)
state.update(tracker)
} else {
state

View File

@ -22,4 +22,5 @@ object TimeUtil {
def timeNowInMinutes(): Long = TimeUnit.NANOSECONDS.toMinutes(System.nanoTime())
def timeNowInSeconds(): Long = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime())
def timeNowInMs(): Long = TimeUnit.NANOSECONDS.toMillis(System.nanoTime())
}

View File

@ -15,9 +15,9 @@ trait SendTimeRemainingUpdateHdlr {
def handleSendTimeRemainingUpdate(msg: SendTimeRemainingAuditInternalMsg, state: MeetingState2x): MeetingState2x = {
if (liveMeeting.props.durationProps.duration > 0) {
if (state.expiryTracker.durationInMs > 0) {
val endMeetingTime = state.expiryTracker.endMeetingTime()
val timeRemaining = endMeetingTime - TimeUtil.timeNowInSeconds
val timeRemaining = TimeUtil.millisToSeconds(endMeetingTime - TimeUtil.timeNowInMs())
def buildMeetingTimeRemainingUpdateEvtMsg(meetingId: String, timeLeftInSec: Long): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "not-used")

View File

@ -107,7 +107,7 @@ trait AppsTestFixtures {
// We extract the meeting handlers into this class so it is
// easy to test.
new LiveMeeting(defaultProps, meetingStatux2x, deskshareModel, chatModel, layoutModel, layouts,
registeredUsers, polls2x, wbModel, presModel, breakoutRooms, captionModel,
registeredUsers, polls2x, wbModel, presModel, captionModel,
notesModel, webcams, voiceUsers, users2x, guestsWaiting)
}
}

View File

@ -30,7 +30,7 @@ class BreakoutRoomsUtilSpec extends UnitSpec {
params += "password" -> BreakoutRoomsUtil.urlEncode("mp")
params += "redirect" -> BreakoutRoomsUtil.urlEncode("true")
val result = BreakoutRoomsUtil.createBaseString(params)
val result = BreakoutRoomsUtil.createBaseString(params.toMap)
assert(result == baseString)
}

View File

@ -10,11 +10,11 @@ class MeetingInactivityTrackerTests extends UnitSpec {
val nowInMinutes = TimeUtil.minutesToSeconds(15)
val inactivityTracker = new MeetingInactivityTracker(
maxInactivityTimeoutMinutes = 12,
warningMinutesBeforeMax = 2,
lastActivityTimestamp = TimeUtil.minutesToSeconds(5),
maxInactivityTimeoutInMs = 12,
warningBeforeMaxInMs = 2,
lastActivityTimestampInMs = TimeUtil.minutesToSeconds(5),
warningSent = true,
warningSentOnTimestamp = 0L
warningSentOnTimestampInMs = 0L
)
val active = inactivityTracker.isMeetingInactive(nowInMinutes)
@ -24,11 +24,11 @@ class MeetingInactivityTrackerTests extends UnitSpec {
"A MeetingInactivityTrackerHelper" should "be return meeting is active" in {
val nowInMinutes = TimeUtil.minutesToSeconds(18)
val inactivityTracker = new MeetingInactivityTracker(
maxInactivityTimeoutMinutes = 12,
warningMinutesBeforeMax = 2,
lastActivityTimestamp = TimeUtil.minutesToSeconds(5),
maxInactivityTimeoutInMs = 12,
warningBeforeMaxInMs = 2,
lastActivityTimestampInMs = TimeUtil.minutesToSeconds(5),
warningSent = true,
warningSentOnTimestamp = 0L
warningSentOnTimestampInMs = 0L
)
val inactive = inactivityTracker.isMeetingInactive(nowInMinutes)

View File

@ -10,11 +10,11 @@ class MeetingExpiryTrackerHelperTests extends UnitSpec {
val nowInMinutes = TimeUtil.minutesToSeconds(15)
val inactivityTracker = new MeetingInactivityTracker(
maxInactivityTimeoutMinutes = 12,
warningMinutesBeforeMax = 2,
lastActivityTimestamp = TimeUtil.minutesToSeconds(5),
maxInactivityTimeoutInMs = 12,
warningBeforeMaxInMs = 2,
lastActivityTimestampInMs = TimeUtil.minutesToSeconds(5),
warningSent = true,
warningSentOnTimestamp = 0L
warningSentOnTimestampInMs = 0L
)
val active = inactivityTracker.isMeetingInactive(nowInMinutes)
@ -24,11 +24,11 @@ class MeetingExpiryTrackerHelperTests extends UnitSpec {
"A MeetingInactivityTrackerHelper" should "be return meeting is active" in {
val nowInMinutes = TimeUtil.minutesToSeconds(18)
val inactivityTracker = new MeetingInactivityTracker(
maxInactivityTimeoutMinutes = 12,
warningMinutesBeforeMax = 2,
lastActivityTimestamp = TimeUtil.minutesToSeconds(5),
maxInactivityTimeoutInMs = 12,
warningBeforeMaxInMs = 2,
lastActivityTimestampInMs = TimeUtil.minutesToSeconds(5),
warningSent = true,
warningSentOnTimestamp = 0L
warningSentOnTimestampInMs = 0L
)
val inactive = inactivityTracker.isMeetingInactive(nowInMinutes)

View File

@ -34,18 +34,18 @@ class ValidateAuthTokenReqMsgHdlrTestsSpec extends TestKit(ActorSystem(
val inactivityTracker = new MeetingInactivityTracker(
12,
2,
lastActivityTimestamp = 10,
lastActivityTimestampInMs = 10,
warningSent = false,
warningSentOnTimestamp = 0L
warningSentOnTimestampInMs = 0L
)
val expiryTracker = new MeetingExpiryTracker(
startedOn = TimeUtil.timeNowInSeconds(),
startedOnInMs = TimeUtil.timeNowInSeconds(),
userHasJoined = false,
lastUserLeftOn = None,
durationInMinutes = 120,
meetingExpireIfNoUserJoinedInMinutes = 5,
meetingExpireWhenLastUserLeftInMinutes = 2
lastUserLeftOnInMs = None,
durationInMs = 120,
meetingExpireIfNoUserJoinedInMs = 5,
meetingExpireWhenLastUserLeftInMs = 2
)
"A MeetingActor" should {
@ -57,7 +57,7 @@ class ValidateAuthTokenReqMsgHdlrTestsSpec extends TestKit(ActorSystem(
val outGW = new OutMsgRouter(false, msgGW)
val eventBus = new InMsgBusGW(new IncomingEventBusImp())
var state = new MeetingState2x(inactivityTracker, expiryTracker)
var state = new MeetingState2x(None, inactivityTracker, expiryTracker)
// Need to get an ActorContext
val actorRef = TestActorRef[MockTestActor]
@ -88,7 +88,7 @@ class ValidateAuthTokenReqMsgHdlrTestsSpec extends TestKit(ActorSystem(
val outGW = new OutMsgRouter(false, msgGW)
val eventBus = new InMsgBusGW(new IncomingEventBusImp())
var state = new MeetingState2x(inactivityTracker, expiryTracker)
var state = new MeetingState2x(None, inactivityTracker, expiryTracker)
val richard = TestDataGen.createRegisteredUser(live.registeredUsers, "Richard", Roles.MODERATOR_ROLE,
guest = false, authed = false, waitForApproval = false)
@ -121,7 +121,7 @@ class ValidateAuthTokenReqMsgHdlrTestsSpec extends TestKit(ActorSystem(
val outGW = new OutMsgRouter(false, msgGW)
val eventBus = new InMsgBusGW(new IncomingEventBusImp())
var state = new MeetingState2x(inactivityTracker, expiryTracker)
var state = new MeetingState2x(None, inactivityTracker, expiryTracker)
val richard = TestDataGen.createRegisteredUser(live.registeredUsers, "Richard", Roles.MODERATOR_ROLE,
guest = false, authed = false, waitForApproval = false)
@ -154,7 +154,7 @@ class ValidateAuthTokenReqMsgHdlrTestsSpec extends TestKit(ActorSystem(
val outGW = new OutMsgRouter(false, msgGW)
val eventBus = new InMsgBusGW(new IncomingEventBusImp())
var state = new MeetingState2x(inactivityTracker, expiryTracker)
var state = new MeetingState2x(None, inactivityTracker, expiryTracker)
// Set the guest policy to ask moderator
GuestsWaiting.setGuestPolicy(live.guestsWaiting, GuestPolicy(GuestPolicyType.ASK_MODERATOR, "SYSTEM"))
@ -192,7 +192,7 @@ class ValidateAuthTokenReqMsgHdlrTestsSpec extends TestKit(ActorSystem(
val registeredUsers = new RegisteredUsers
val users2x = new Users2x
val live = new LiveMeeting(defaultProps, meetingStatux2x, deskshareModel, chatModel, layoutModel, layouts,
registeredUsers, polls2x, wbModel, presModel, breakoutRooms, captionModel,
registeredUsers, polls2x, wbModel, presModel, captionModel,
notesModel, webcams, voiceUsers, users2x, guestsWaiting)
// Set the guest policy to ask moderator
@ -217,7 +217,7 @@ class ValidateAuthTokenReqMsgHdlrTestsSpec extends TestKit(ActorSystem(
val outGW = new OutMsgRouter(false, msgGW)
val eventBus = new InMsgBusGW(new IncomingEventBusImp())
var state = new MeetingState2x(inactivityTracker, expiryTracker)
var state = new MeetingState2x(None, inactivityTracker, expiryTracker)
// Need to get an ActorContext
val actorRef = TestActorRef[MockTestActor]

View File

@ -89,6 +89,10 @@ package org.bigbluebutton.core.model.users
if (user.intId == userId) {
user.muted = muted;
if (muted) {
// Force user to not talking if muted.
user.talking = false;
}
}
}
}
@ -98,6 +102,10 @@ package org.bigbluebutton.core.model.users
var user:VoiceUser2x = _users.getItemAt(i) as VoiceUser2x;
if (user.intId == userId) {
if (user.muted && talking) {
// if user is muted, we don't want to set it as talking.
return;
}
user.talking = talking;
}
}

View File

@ -49,47 +49,49 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<mate:Listener type="{SuccessfulLoginEvent.USER_LOGGED_IN}" method="refreshModeratorButtonsVisibility" />
<mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="refreshRole" />
<mate:Listener type="{BBBEvent.CONFIRM_LOGOUT_END_MEETING_EVENT}" method="confirmEndSession" />
<mate:Listener type="{BreakoutRoomEvent.UPDATE_REMAINING_TIME_PARENT}" method="handleRemainingTimeUpdate" />
</fx:Declarations>
<fx:Script>
<![CDATA[
import com.asfusion.mate.events.Dispatcher;
import mx.binding.utils.BindingUtils;
import mx.controls.Alert;
import mx.core.FlexGlobals;
import mx.core.IToolTip;
import mx.core.UIComponent;
import mx.events.CloseEvent;
import mx.events.ToolTipEvent;
import mx.managers.PopUpManager;
import org.as3commons.lang.StringUtils;
import org.as3commons.logging.api.ILogger;
import org.as3commons.logging.api.getClassLogger;
import org.bigbluebutton.common.IBbbToolbarComponent;
import org.bigbluebutton.common.events.SettingsComponentEvent;
import org.bigbluebutton.common.events.ToolbarButtonEvent;
import org.bigbluebutton.core.BBB;
import org.bigbluebutton.core.Options;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.core.model.Config;
import org.bigbluebutton.core.model.LiveMeeting;
import org.bigbluebutton.main.events.BBBEvent;
import org.bigbluebutton.main.events.ConfigLoadedEvent;
import org.bigbluebutton.main.events.LogoutEvent;
import org.bigbluebutton.main.events.NetworkStatsEvent;
import org.bigbluebutton.main.events.SettingsEvent;
import org.bigbluebutton.main.events.ShortcutEvent;
import org.bigbluebutton.main.events.SuccessfulLoginEvent;
import org.bigbluebutton.main.model.NetworkStatsData;
import org.bigbluebutton.main.model.options.BrandingOptions;
import org.bigbluebutton.main.model.options.LayoutOptions;
import org.bigbluebutton.main.model.options.ShortcutKeysOptions;
import org.bigbluebutton.main.model.users.events.ChangeMyRole;
import org.bigbluebutton.main.model.users.events.ConferenceCreatedEvent;
import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent;
import org.bigbluebutton.modules.users.model.UsersOptions;
import org.bigbluebutton.util.i18n.ResourceUtil;
import com.asfusion.mate.events.Dispatcher;
import mx.binding.utils.BindingUtils;
import mx.controls.Alert;
import mx.core.FlexGlobals;
import mx.core.IToolTip;
import mx.core.UIComponent;
import mx.events.CloseEvent;
import mx.events.ToolTipEvent;
import mx.managers.PopUpManager;
import org.as3commons.lang.StringUtils;
import org.as3commons.logging.api.ILogger;
import org.as3commons.logging.api.getClassLogger;
import org.bigbluebutton.common.IBbbToolbarComponent;
import org.bigbluebutton.common.events.SettingsComponentEvent;
import org.bigbluebutton.common.events.ToolbarButtonEvent;
import org.bigbluebutton.core.BBB;
import org.bigbluebutton.core.Options;
import org.bigbluebutton.core.TimerUtil;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.core.model.Config;
import org.bigbluebutton.core.model.LiveMeeting;
import org.bigbluebutton.main.events.BBBEvent;
import org.bigbluebutton.main.events.BreakoutRoomEvent;
import org.bigbluebutton.main.events.ConfigLoadedEvent;
import org.bigbluebutton.main.events.LogoutEvent;
import org.bigbluebutton.main.events.NetworkStatsEvent;
import org.bigbluebutton.main.events.SettingsEvent;
import org.bigbluebutton.main.events.ShortcutEvent;
import org.bigbluebutton.main.events.SuccessfulLoginEvent;
import org.bigbluebutton.main.model.NetworkStatsData;
import org.bigbluebutton.main.model.options.BrandingOptions;
import org.bigbluebutton.main.model.options.LayoutOptions;
import org.bigbluebutton.main.model.options.ShortcutKeysOptions;
import org.bigbluebutton.main.model.users.events.ChangeMyRole;
import org.bigbluebutton.main.model.users.events.ConferenceCreatedEvent;
import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent;
import org.bigbluebutton.modules.users.model.UsersOptions;
import org.bigbluebutton.util.i18n.ResourceUtil;
private static const LOGGER:ILogger = getClassLogger(MainToolbar);
@ -188,6 +190,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
}
private function handleRemainingTimeUpdate(e:BreakoutRoomEvent):void {
TimerUtil.setCountDownTimer(timeRemaining, e.durationInMinutes);
}
private function retrieveMeetingName(e:ConferenceCreatedEvent):void {
if (toolbarOptions.showMeetingName) {
var meetingTitle:String = LiveMeeting.inst().meeting.name;
@ -533,9 +539,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<mx:VRule styleName="toolbarSeparator" height="10" />
<mx:Label id="meetingNameLbl" minWidth="1" styleName="meetingNameLabelStyle" />
<mx:HBox id="addedBtns" width="100%" horizontalAlign="center"/>
<mx:Label id="timeRemaining"
text="{ResourceUtil.getInstance().getString('bbb.users.breakout.calculatingRemainingTime')}"
toolTip="{ResourceUtil.getInstance().getString('bbb.users.breakout.timer.toolTip')}"/>
<views:RecordButton id="recordBtn" visible="{showRecordButton}" includeInLayout="{showRecordButton}"/>
<views:WebRTCAudioStatus id="webRTCAudioStatus" height="30"/>
<mx:Button
id="bbbSettings"
visible="{showGuestSettingsButton}"

View File

@ -21,15 +21,15 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<mx:VBox xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mate="http://mate.asfusion.com/"
xmlns:common="org.bigbluebutton.common.*"
xmlns:chat="org.bigbluebutton.modules.chat.views.*"
implements="org.bigbluebutton.modules.chat.views.IChatTab"
click="setMessageRead()" verticalScrollPolicy="off"
creationComplete="onCreationComplete()">
<fx:Style>
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mate="http://mate.asfusion.com/"
xmlns:common="org.bigbluebutton.common.*"
xmlns:chat="org.bigbluebutton.modules.chat.views.*"
implements="org.bigbluebutton.modules.chat.views.IChatTab"
click="setMessageRead()" verticalScrollPolicy="off"
creationComplete="onCreationComplete()">
<fx:Style>
.chatColorPickerStyle {
backgroundColor:#E5E6E7;
columnCount:12;
@ -48,26 +48,25 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
</fx:Style>
<fx:Declarations>
<mate:Listener type="{ChatOptionsEvent.CHANGE_FONT_SIZE}" method="changeFontSize" />
<mate:Listener type="{PrivateChatMessageEvent.PRIVATE_CHAT_MESSAGE_EVENT}" method="handlePrivateChatMessageEvent"/>
<mate:Listener type="{PublicChatMessageEvent.PUBLIC_CHAT_MESSAGE_EVENT}" method="handlePublicChatMessageEvent"/>
<mate:Listener type="{ChatHistoryEvent.RECEIVED_HISTORY}" method="handleRecievedChatHistoryEvent" />
<mate:Listener type="{ClearPublicChatEvent.CLEAR_PUBLIC_CHAT_EVENT}" method="handleClearPublicChatBoxMessages"/>
<mate:Listener type="{ShortcutEvent.FOCUS_CHAT_INPUT}" method="focusChatInput" />
<mate:Listener type="{UserLeftEvent.LEFT}" method="handleUserLeftEvent"/>
<mate:Listener type="{UserJoinedEvent.JOINED}" method="handleUserJoinedEvent"/>
<mate:Listener type="{ShortcutEvent.FOCUS_CHAT_BOX}" method="focusChatBox" />
<mate:Listener type="{ShortcutEvent.CHANGE_FONT_COLOUR}" method="focusColourPicker" />
<mate:Listener type="{ShortcutEvent.SEND_MESSAGE}" method="remoteSendMessage" />
<mate:Listener type="{BBBEvent.RECONNECT_DISCONNECTED_EVENT}" receive="refreshChat(event)"/>
<mate:Listener type="{LockControlEvent.CHANGED_LOCK_SETTINGS}" method="lockSettingsChanged" />
<mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="refreshRole" />
</fx:Declarations>
<fx:Script>
<![CDATA[
<fx:Declarations>
<mate:Listener type="{ChatOptionsEvent.CHANGE_FONT_SIZE}" method="changeFontSize" />
<mate:Listener type="{PrivateChatMessageEvent.PRIVATE_CHAT_MESSAGE_EVENT}" method="handlePrivateChatMessageEvent"/>
<mate:Listener type="{PublicChatMessageEvent.PUBLIC_CHAT_MESSAGE_EVENT}" method="handlePublicChatMessageEvent"/>
<mate:Listener type="{ChatHistoryEvent.RECEIVED_HISTORY}" method="handleRecievedChatHistoryEvent" />
<mate:Listener type="{ClearPublicChatEvent.CLEAR_PUBLIC_CHAT_EVENT}" method="handleClearPublicChatBoxMessages"/>
<mate:Listener type="{ShortcutEvent.FOCUS_CHAT_INPUT}" method="focusChatInput" />
<mate:Listener type="{UserLeftEvent.LEFT}" method="handleUserLeftEvent"/>
<mate:Listener type="{UserJoinedEvent.JOINED}" method="handleUserJoinedEvent"/>
<mate:Listener type="{ShortcutEvent.FOCUS_CHAT_BOX}" method="focusChatBox" />
<mate:Listener type="{ShortcutEvent.CHANGE_FONT_COLOUR}" method="focusColourPicker" />
<mate:Listener type="{ShortcutEvent.SEND_MESSAGE}" method="remoteSendMessage" />
<mate:Listener type="{BBBEvent.RECONNECT_DISCONNECTED_EVENT}" receive="refreshChat(event)"/>
<mate:Listener type="{LockControlEvent.CHANGED_LOCK_SETTINGS}" method="lockSettingsChanged" />
<mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="refreshRole" />
</fx:Declarations>
<fx:Script>
<![CDATA[
import com.asfusion.mate.events.Dispatcher;
import flash.events.TextEvent;
@ -78,7 +77,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import org.as3commons.logging.api.ILogger;
import org.as3commons.logging.api.getClassLogger;
import org.bigbluebutton.core.Options;
import org.bigbluebutton.core.TimerUtil;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.core.events.LockControlEvent;
import org.bigbluebutton.core.model.LiveMeeting;
@ -102,144 +100,134 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import org.bigbluebutton.modules.chat.vo.ChatMessageVO;
import org.bigbluebutton.modules.polling.events.StartCustomPollEvent;
import org.bigbluebutton.util.i18n.ResourceUtil;
private static const LOGGER:ILogger = getClassLogger(ChatBox);
public var publicChat:Boolean = false;
public var chatWithUserID:String;
public var chatWithUsername:String
private static const LOGGER:ILogger = getClassLogger(ChatBox);
public var read:Boolean = true;
public var userHasLeft:Boolean = false;
private var globalDispatcher:Dispatcher = new Dispatcher();
[Bindable] public var colorPickerColours:Array = ['0x000000', '0x7A7A7A' ,'0xFF0000', '0xFF8800',
'0x88FF00', '0x00FF00', '0x00FF88', '0x00FFFF', '0x0088FF', '0x0000FF', '0x8800FF', '0xFF00FF'];
public var publicChat:Boolean = false;
public var chatWithUserID:String;
public var chatWithUsername:String
[Bindable]
private var backgroundColor:uint = 0x000000;
private var lastSenderId:String = "";
private var lastTime:String = "";
[Bindable]
private var chatMessages:ChatConversation = new ChatConversation();
private var lastCount:Number = 0;
private var scrollTimer:Timer;
private var currentMessage:int;
private var latestMessage:int;
public var focus:Boolean = false;
private var keyCombos:Object;
private var navToFirst:Boolean = false;
private var navToLatest:Boolean = false;
private var spacerNeeded:Boolean = false;
private var indicatorNeeded:Boolean = false
private var repeat:Boolean = false;
[Bindable]
private var chatListHeight:Number = 100;
[Bindable] public var chatOptions:ChatOptions;
private var shiftPressed:Boolean = false;
private var ctrlPressed:Boolean = false;
public var read:Boolean = true;
public var userHasLeft:Boolean = false;
private function onCreationComplete():void {
chatOptions = Options.getOptions(ChatOptions) as ChatOptions;
bindToHeightToDetermineHeightOfMessageList();
addContextMenuItems();
scrollTimer = new Timer(750, 1);
scrollTimer.addEventListener(TimerEvent.TIMER, onScrollTimer);
// Initialize the indicator for the position in the message history, and add the listener for message history navigation
currentMessage = -1;
latestMessage = -1;
ResourceUtil.getInstance().addEventListener(Event.CHANGE, localeChanged); // Listen for locale changing
// Listen for the ENTER key to send the message.
txtMsgArea.addEventListener(TextEvent.TEXT_INPUT, handleTextInput);
txtMsgArea.addEventListener(KeyboardEvent.KEY_DOWN, handleMsgAreaKeyDown);
// Listen for the navigable keys to avoid moving and resizing the chat box while text selection
txtMsgArea.addEventListener(KeyboardEvent.KEY_DOWN, checkNavigableButtonDown);
txtMsgArea.addEventListener(KeyboardEvent.KEY_UP, checkNavigableButtonUp);
chatMessagesList.addEventListener(KeyboardEvent.KEY_DOWN, checkNavigableButtonDown);
chatMessagesList.addEventListener(KeyboardEvent.KEY_UP, checkNavigableButtonUp);
this.addEventListener(FocusEvent.FOCUS_OUT, releaseNavigableButton);
queryForChatHistory();
chatMessagesList.accessibilityProperties.description = ResourceUtil.getInstance().getString('bbb.accessibility.chat.initialDescription');
if (publicChat && UsersUtil.isBreakout()){
var timerListener : Listener = new Listener();
timerListener.type = BreakoutRoomEvent.UPDATE_REMAINING_TIME_BREAKOUT;
timerListener.method = handleRemaininTimeBreakout;
timerBox.visible = timerBox.includeInLayout = true;
timerBox.height = 60;
}
LOGGER.debug(" onCreationComplete. Apply lock settings");
applyLockSettings();
chatToolbar.registerListeners(chatMessagesList);
chatMessagesList.addEventListener(ChatEvent.RESIZE_CHAT_TOOLBAR, adjustToolbarWidthAccordingToScrollBar);
}
private function handleRemaininTimeBreakout(e:BreakoutRoomEvent):void {
TimerUtil.setCountDownTimer(timerLabel, e.durationInMinutes);
}
private function checkNavigableButtonDown(e:KeyboardEvent):void {
if (e.shiftKey && !shiftPressed) {
shiftPressed = true;
parentDocument.handleDraggableStatus(false);
}
if (e.ctrlKey && !ctrlPressed) {
ctrlPressed = true;
parentDocument.handleResizableStatus(false);
}
}
private function checkNavigableButtonUp(e:KeyboardEvent):void {
if (!e.shiftKey && shiftPressed) {
shiftPressed = false;
parentDocument.handleDraggableStatus(true);
}
if (!e.ctrlKey && ctrlPressed) {
ctrlPressed = false;
parentDocument.handleResizableStatus(true);
}
}
private function releaseNavigableButton(focus:FocusEvent):void {
if (shiftPressed) {
shiftPressed = false;
parentDocument.handleDraggableStatus(true);
}
if (ctrlPressed) {
ctrlPressed = false;
parentDocument.handleResizableStatus(true);
}
}
private function focusChatBox(e:ShortcutEvent):void{
focusManager.setFocus(chatMessagesList);
}
private function focusColourPicker(e:ShortcutEvent):void{
focusManager.setFocus(cmpColorPicker);
}
private function remoteSendMessage(e:ShortcutEvent):void{
sendMessages();
}
private var globalDispatcher:Dispatcher = new Dispatcher();
[Bindable] public var colorPickerColours:Array = ['0x000000', '0x7A7A7A' ,'0xFF0000', '0xFF8800',
'0x88FF00', '0x00FF00', '0x00FF88', '0x00FFFF', '0x0088FF', '0x0000FF', '0x8800FF', '0xFF00FF'];
[Bindable]
private var backgroundColor:uint = 0x000000;
private var lastSenderId:String = "";
private var lastTime:String = "";
[Bindable]
private var chatMessages:ChatConversation = new ChatConversation();
private var lastCount:Number = 0;
private var scrollTimer:Timer;
private var currentMessage:int;
private var latestMessage:int;
public var focus:Boolean = false;
private var keyCombos:Object;
private var navToFirst:Boolean = false;
private var navToLatest:Boolean = false;
private var spacerNeeded:Boolean = false;
private var indicatorNeeded:Boolean = false
private var repeat:Boolean = false;
[Bindable]
private var chatListHeight:Number = 100;
[Bindable] public var chatOptions:ChatOptions;
private var shiftPressed:Boolean = false;
private var ctrlPressed:Boolean = false;
private function onCreationComplete():void {
chatOptions = Options.getOptions(ChatOptions) as ChatOptions;
bindToHeightToDetermineHeightOfMessageList();
addContextMenuItems();
scrollTimer = new Timer(750, 1);
scrollTimer.addEventListener(TimerEvent.TIMER, onScrollTimer);
// Initialize the indicator for the position in the message history, and add the listener for message history navigation
currentMessage = -1;
latestMessage = -1;
ResourceUtil.getInstance().addEventListener(Event.CHANGE, localeChanged); // Listen for locale changing
// Listen for the ENTER key to send the message.
txtMsgArea.addEventListener(TextEvent.TEXT_INPUT, handleTextInput);
txtMsgArea.addEventListener(KeyboardEvent.KEY_DOWN, handleMsgAreaKeyDown);
// Listen for the navigable keys to avoid moving and resizing the chat box while text selection
txtMsgArea.addEventListener(KeyboardEvent.KEY_DOWN, checkNavigableButtonDown);
txtMsgArea.addEventListener(KeyboardEvent.KEY_UP, checkNavigableButtonUp);
chatMessagesList.addEventListener(KeyboardEvent.KEY_DOWN, checkNavigableButtonDown);
chatMessagesList.addEventListener(KeyboardEvent.KEY_UP, checkNavigableButtonUp);
this.addEventListener(FocusEvent.FOCUS_OUT, releaseNavigableButton);
queryForChatHistory();
chatMessagesList.accessibilityProperties.description = ResourceUtil.getInstance().getString('bbb.accessibility.chat.initialDescription');
LOGGER.debug(" onCreationComplete. Apply lock settings");
applyLockSettings();
chatToolbar.registerListeners(chatMessagesList);
chatMessagesList.addEventListener(ChatEvent.RESIZE_CHAT_TOOLBAR, adjustToolbarWidthAccordingToScrollBar);
}
private function checkNavigableButtonDown(e:KeyboardEvent):void {
if (e.shiftKey && !shiftPressed) {
shiftPressed = true;
parentDocument.handleDraggableStatus(false);
}
if (e.ctrlKey && !ctrlPressed) {
ctrlPressed = true;
parentDocument.handleResizableStatus(false);
}
}
private function checkNavigableButtonUp(e:KeyboardEvent):void {
if (!e.shiftKey && shiftPressed) {
shiftPressed = false;
parentDocument.handleDraggableStatus(true);
}
if (!e.ctrlKey && ctrlPressed) {
ctrlPressed = false;
parentDocument.handleResizableStatus(true);
}
}
private function releaseNavigableButton(focus:FocusEvent):void {
if (shiftPressed) {
shiftPressed = false;
parentDocument.handleDraggableStatus(true);
}
if (ctrlPressed) {
ctrlPressed = false;
parentDocument.handleResizableStatus(true);
}
}
private function focusChatBox(e:ShortcutEvent):void{
focusManager.setFocus(chatMessagesList);
}
private function focusColourPicker(e:ShortcutEvent):void{
focusManager.setFocus(cmpColorPicker);
}
private function remoteSendMessage(e:ShortcutEvent):void{
sendMessages();
}
private function bindToHeightToDetermineHeightOfMessageList():void {
// Need to bind to the height for this container to be able to calculate the height
@ -279,13 +267,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
scrollToEndOfMessage();
}
}
private function refreshChat(e:BBBEvent):void {
if (e.payload.type == "BIGBLUEBUTTON_CONNECTION") {
if (publicChat) chatMessages = new ChatConversation();
}
}
private function handleUserJoinedEvent(event:UserJoinedEvent):void {
// Handle user joining so that the user can start to talk if the person rejoins
if (!publicChat && event.userID == chatWithUserID) {
@ -328,7 +316,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
txtMsgArea.setFocus();
txtMsgArea.drawFocus(true);
}
private function handlePublicChatMessageEvent(event:PublicChatMessageEvent):void {
if (publicChat) {
chatMessages.newChatMessage(event.message);
@ -342,7 +330,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
scrollToEndOfMessage();
}
}
private function adjustToolbarWidthAccordingToScrollBar(e:ChatEvent):void{
invalidateDisplayList();
validateNow();
@ -387,117 +375,117 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
if (scrollTimer != null) scrollTimer.start();
}
/**
* Magic sauce to force scrollbar to the bottom message. This took a lot
* of trial and error. If you change this, make sure you know what you are
* doing as I don't know why it works, but it does. (ralam Nov 3, 2010)
*
* New and improved scrollToBottom implemented (capilkey Dec 4, 2014)
*/
private function scrollToBottom():void {
chatMessagesList.scrollToBottom();
}
private function onScrollTimer(event:TimerEvent):void {
scrollToBottom();
}
public function setMessageUnread():void{
this.read = false;
backgroundColor = 0xFFFF00;
}
public function setMessageRead():void{
this.read = true;
backgroundColor = 0x000000;
}
private function onLinkClick(e:TextEvent):void {
var url:URLRequest = new URLRequest(e.text);
navigateToURL(url, '_blank');
}
private function changeFontSize(e:ChatOptionsEvent):void {
this.setStyle("fontSize", e.fontSize);
}
private function copyAllText():void{
System.setClipboard(chatMessages.getAllMessageAsString());
}
public function getChatMessages():ChatConversation {
return chatMessages;
}
private function addContextMenuItems():void {
var contextMenu:ContextMenu = new ContextMenu();
contextMenu.hideBuiltInItems();
var copyAllButton:ContextMenuItem = new ContextMenuItem(ResourceUtil.getInstance().getString("bbb.chat.contextmenu.copyalltext"));
copyAllButton.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, menuItemHandler);
contextMenu.customItems.push(copyAllButton);
this.contextMenu = contextMenu;
}
private function menuItemHandler(e:ContextMenuEvent):void{
if (e.target.caption == ResourceUtil.getInstance().getString("bbb.chat.contextmenu.copyalltext")){
System.setClipboard(chatMessages.getAllMessageAsString());
}
}
public function getLatestMessage():int{
return latestMessage;
}
public function getCurrentMessage():int{
return currentMessage;
}
private function localeChanged(e:Event):void {
var modifier:String = ExternalInterface.call("determineModifier");
addContextMenuItems();
}
/**
* Magic sauce to force scrollbar to the bottom message. This took a lot
* of trial and error. If you change this, make sure you know what you are
* doing as I don't know why it works, but it does. (ralam Nov 3, 2010)
*
* New and improved scrollToBottom implemented (capilkey Dec 4, 2014)
*/
private function scrollToBottom():void {
chatMessagesList.scrollToBottom();
}
private function onScrollTimer(event:TimerEvent):void {
scrollToBottom();
}
public function setMessageUnread():void{
this.read = false;
backgroundColor = 0xFFFF00;
}
public function setMessageRead():void{
this.read = true;
backgroundColor = 0x000000;
}
private function onLinkClick(e:TextEvent):void {
var url:URLRequest = new URLRequest(e.text);
navigateToURL(url, '_blank');
}
private function changeFontSize(e:ChatOptionsEvent):void {
this.setStyle("fontSize", e.fontSize);
}
private function copyAllText():void{
System.setClipboard(chatMessages.getAllMessageAsString());
}
public function getChatMessages():ChatConversation {
return chatMessages;
}
private function addContextMenuItems():void {
var contextMenu:ContextMenu = new ContextMenu();
contextMenu.hideBuiltInItems();
var copyAllButton:ContextMenuItem = new ContextMenuItem(ResourceUtil.getInstance().getString("bbb.chat.contextmenu.copyalltext"));
copyAllButton.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, menuItemHandler);
contextMenu.customItems.push(copyAllButton);
this.contextMenu = contextMenu;
}
private function menuItemHandler(e:ContextMenuEvent):void{
if (e.target.caption == ResourceUtil.getInstance().getString("bbb.chat.contextmenu.copyalltext")){
System.setClipboard(chatMessages.getAllMessageAsString());
}
}
public function getLatestMessage():int{
return latestMessage;
}
public function getCurrentMessage():int{
return currentMessage;
}
private function localeChanged(e:Event):void {
var modifier:String = ExternalInterface.call("determineModifier");
addContextMenuItems();
}
private function sendStartCustomPollEvent(answers:Array):void {
var dispatcher:Dispatcher = new Dispatcher();
dispatchEvent(new StartCustomPollEvent("Custom", answers));
}
private function sendPublicChatMessage(message:String):void {
//var pollRegex:RegExp = /^@poll\s+?((?:[^,]+?\s*?,\s*?)*?[^,]+?)\s*?$/;
var pollRegex:RegExp = /^@poll\s+?(.+)\s*?$/;
var matchedArray:Array = message.match(pollRegex);
if (UsersUtil.amIPresenter() && pollRegex.test(message)) {
var tmpAnswers: Array = matchedArray[1].split(",");
var answers:Array = new Array();
for (var i:int = 0; i < tmpAnswers.length; i++) {
var t:String = tmpAnswers[i] as String;
answers.push(StringUtils.trim(t));
}
sendStartCustomPollEvent(answers);
} else {
var publicEvent:SendPublicChatMessageEvent = new SendPublicChatMessageEvent(SendPublicChatMessageEvent.SEND_PUBLIC_CHAT_MESSAGE_EVENT);
var cm:ChatMessageVO = new ChatMessageVO();
cm.fromUserId = UsersUtil.getMyUserID();
cm.fromUsername = UsersUtil.getMyUsername();
// get the color value from ColorPicker
cm.fromColor = cmpColorPicker.selectedColor.toString();
// Get the current UTC time and the timezone for this sender.
// The receiver will have to convert this to local time.
var now:Date = new Date();
cm.fromTime = now.valueOf();
cm.fromTimezoneOffset = now.getTimezoneOffset();
//cm.message = ChatUtil.parseURLs(ChatUtil.cleanup(message));
cm.message = ExternalInterface.call('parseURLs', (ChatUtil.cleanup(message)));
publicEvent.chatMessage = cm;
globalDispatcher.dispatchEvent(publicEvent);
}
//var pollRegex:RegExp = /^@poll\s+?((?:[^,]+?\s*?,\s*?)*?[^,]+?)\s*?$/;
var pollRegex:RegExp = /^@poll\s+?(.+)\s*?$/;
var matchedArray:Array = message.match(pollRegex);
if (UsersUtil.amIPresenter() && pollRegex.test(message)) {
var tmpAnswers: Array = matchedArray[1].split(",");
var answers:Array = new Array();
for (var i:int = 0; i < tmpAnswers.length; i++) {
var t:String = tmpAnswers[i] as String;
answers.push(StringUtils.trim(t));
}
sendStartCustomPollEvent(answers);
} else {
var publicEvent:SendPublicChatMessageEvent = new SendPublicChatMessageEvent(SendPublicChatMessageEvent.SEND_PUBLIC_CHAT_MESSAGE_EVENT);
var cm:ChatMessageVO = new ChatMessageVO();
cm.fromUserId = UsersUtil.getMyUserID();
cm.fromUsername = UsersUtil.getMyUsername();
// get the color value from ColorPicker
cm.fromColor = cmpColorPicker.selectedColor.toString();
// Get the current UTC time and the timezone for this sender.
// The receiver will have to convert this to local time.
var now:Date = new Date();
cm.fromTime = now.valueOf();
cm.fromTimezoneOffset = now.getTimezoneOffset();
//cm.message = ChatUtil.parseURLs(ChatUtil.cleanup(message));
cm.message = ExternalInterface.call('parseURLs', (ChatUtil.cleanup(message)));
publicEvent.chatMessage = cm;
globalDispatcher.dispatchEvent(publicEvent);
}
}
private function sendPrivateChatMessage(message:String):void {
@ -505,7 +493,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
var cm:ChatMessageVO = new ChatMessageVO();
cm.fromUserId = UsersUtil.getMyUserID();
cm.fromUsername = UsersUtil.getMyUsername();
// get the color value from ColorPicker
// get the color value from ColorPicker
cm.fromColor = cmpColorPicker.selectedColor.toString();
// Get the current UTC time and the timezone for this sender.
@ -513,7 +501,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
var now:Date = new Date();
cm.fromTime = now.valueOf();
cm.fromTimezoneOffset = now.getTimezoneOffset();
//cm.message = ChatUtil.parseURLs(ChatUtil.cleanup(message));
cm.message = ExternalInterface.call('parseURLs', (ChatUtil.cleanup(message)));
cm.toUserId = chatWithUserID;
@ -522,20 +510,20 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
privateEvent.chatMessage = cm;
globalDispatcher.dispatchEvent(privateEvent);
}
private function handleTextInput(e:TextEvent):void {
if ((e.text.length == 1) && (e.text.charCodeAt(0) == 10) /*ENTER-KEY*/ && messageCanBeSent) {
sendMessages();
e.preventDefault();
}
}
private function handleMsgAreaKeyDown(e:KeyboardEvent):void {
if ((e.shiftKey || e.ctrlKey) && e.keyCode == Keyboard.ENTER) {
txtMsgArea.text += "\n";
txtMsgArea.setSelection(txtMsgArea.text.length, txtMsgArea.text.length);
}
}
if ((e.text.length == 1) && (e.text.charCodeAt(0) == 10) /*ENTER-KEY*/ && messageCanBeSent) {
sendMessages();
e.preventDefault();
}
}
private function handleMsgAreaKeyDown(e:KeyboardEvent):void {
if ((e.shiftKey || e.ctrlKey) && e.keyCode == Keyboard.ENTER) {
txtMsgArea.text += "\n";
txtMsgArea.setSelection(txtMsgArea.text.length, txtMsgArea.text.length);
}
}
private function handleTextAreaKeyDownEvent(e:KeyboardEvent):void {
// stops window moving when trying to navigate the text box
@ -545,11 +533,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
private function sendMessages():void {
if(!sendBtn.enabled) {
txtMsgArea.text = StringUtils.trim(txtMsgArea.text);
return;
}
if(!sendBtn.enabled) {
txtMsgArea.text = StringUtils.trim(txtMsgArea.text);
return;
}
// Trim the message. This will trim the '/n' char so we don't send a message when the
// user just hits the enter key
var msgToSend:String = StringUtils.trim(txtMsgArea.text);
@ -565,140 +553,132 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
txtMsgArea.validateNow();
txtMsgArea.setSelection(0, 0);
}
private function showMessageTooLong(messageLength : int):void {
msgTooLongLabel.text = ResourceUtil.getInstance().getString('bbb.chat.chatMessage.tooLong', [(messageLength - chatOptions.maxMessageLength).toString()]);
msgTooLongLabel.includeInLayout = msgTooLongLabel.visible = true;
if (chatCtrlBar.height != 80) {
chatCtrlBar.height = 80;
chatListHeight -= 20;
}
// The case where lock settings are set
if (txtMsgArea.enabled) {
sendBtn.enabled = false;
}
}
private function hideMessageTooLong():void {
msgTooLongLabel.includeInLayout = msgTooLongLabel.visible = false;
if (chatCtrlBar.height != 60) {
chatCtrlBar.height = 60;
chatListHeight += 20;
}
// The case where lock settings are set
if (txtMsgArea.enabled) {
sendBtn.enabled = true;
}
}
private function focusChatInput(e:ShortcutEvent):void{
txtMsgArea.setFocus();
}
private function lockSettingsChanged(e:Event):void {
applyLockSettings();
}
private function applyLockSettings():void {
if (publicChat) {
txtMsgArea.enabled = sendBtn.enabled = !LiveMeeting.inst().me.disableMyPublicChat;
} else {
txtMsgArea.enabled = sendBtn.enabled = !LiveMeeting.inst().me.disableMyPrivateChat;
}
}
private function refreshRole(e:ChangeMyRole):void {
applyLockSettings();
}
private function get messageCanBeSent() : Boolean {
return StringUtils.trim(txtMsgArea.text).length <= chatOptions.maxMessageLength;
}
protected function txtMsgAreaChangeHandler(event:Event):void
{
if (!messageCanBeSent) {
showMessageTooLong(StringUtils.trim(txtMsgArea.text).length);
}
else {
hideMessageTooLong();
}
}
private function handleClearPublicChatBoxMessages(event:ClearPublicChatEvent):void {
if(publicChat){
chatMessages.clearPublicChat();
invalidateDisplayList();
validateNow();
}
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
// Force validation before evaluation of toolbar width
validateNow();
const paddingHeight:int = 5;
const paddingWidth:int = 5;
chatToolbar.x = (chatMessagesCanvas.width - chatToolbar.width) - 20;
chatToolbar.y = 10;
if (!publicChat) {
chatToolbar.publicChat = false;
}
}
]]>
</fx:Script>
<fx:Declarations>
<common:TabIndexer id="tabIndexer" tabIndices="{[chatMessagesList, txtMsgArea, sendBtn, cmpColorPicker]}"/>
</fx:Declarations>
<mx:VBox width="100%" height="{chatListHeight}" verticalScrollPolicy="off">
<mx:Canvas id="chatMessagesCanvas" width="100%" height="{chatListHeight}" horizontalScrollPolicy="off" verticalScrollPolicy="off" >
<chat:AdvancedList width="100%" height="{chatListHeight - timerBox.height}" id="chatMessagesList" selectable="true" variableRowHeight="true"
itemRenderer="org.bigbluebutton.modules.chat.views.ChatMessageRenderer" verticalScrollPolicy="on" horizontalScrollPolicy="off" wordWrap="true"
dataProvider="{chatMessages.messages}"
styleName="chatMessageListStyle"
accessibilityName="{ResourceUtil.getInstance().getString('bbb.chat.messageList')}" />
<chat:ChatToolbar id="chatToolbar" />
</mx:Canvas>
<mx:HBox id="timerBox" styleName="breakoutRoomTimerBox"
includeInLayout="false" visible="false"
width="100%" height="0">
<mx:Label id="timerLabel"
text="{ResourceUtil.getInstance().getString('bbb.users.breakout.calculatingRemainingTime')}"
toolTip="{ResourceUtil.getInstance().getString('bbb.users.breakout.timer.toolTip')}"/>
</mx:HBox>
</mx:VBox>
<mx:HBox id="chatCtrlBar" width="100%" height="60" styleName="chatControlBarStyle" verticalScrollPolicy="off"
paddingLeft="5" paddingRight="5">
<mx:VBox width="100%" height="100%">
<!-- There is a restrict in this textArea to avoid a known issue where a \u007F, which is the delete character, would be seen written in some browsers as an invalid character -->
<mx:TextArea id="txtMsgArea" width="100%" height="100%" restrict="^\u007F"
styleName="chatControlBarTextMsgStyle"
change="txtMsgAreaChangeHandler(event)"
toolTip="{ResourceUtil.getInstance().getString('bbb.accessibility.chat.chatwindow.input')}"
accessibilityName="{ResourceUtil.getInstance().getString('bbb.chat.input.accessibilityName')}" />
<mx:Label id="msgTooLongLabel" width="100%" height="100%" includeInLayout="false" visible="false"/>
</mx:VBox>
<mx:VBox verticalScrollPolicy="off" verticalAlign="middle" height="100%" >
<mx:HBox horizontalGap="0">
<mx:Button id="sendBtn"
styleName="chatControlBarSendButtonStyle"
width="40" height="40"
toolTip="{ResourceUtil.getInstance().getString('bbb.chat.sendBtn.toolTip')}"
click="sendMessages()"
accessibilityName="{ResourceUtil.getInstance().getString('bbb.chat.sendBtn.accessibilityName')}"/>
</mx:HBox>
<mx:ColorPicker id="cmpColorPicker" showTextField="false" width="100%" visible="{chatOptions.colorPickerIsVisible}"
includeInLayout="{chatOptions.colorPickerIsVisible}"
toolTip="{ResourceUtil.getInstance().getString('bbb.chat.cmpColorPicker.toolTip')}"
selectedColor="0x000000" dataProvider="{colorPickerColours}" swatchPanelStyleName="chatColorPickerStyle"/>
</mx:VBox>
</mx:HBox>
private function showMessageTooLong(messageLength : int):void {
msgTooLongLabel.text = ResourceUtil.getInstance().getString('bbb.chat.chatMessage.tooLong', [(messageLength - chatOptions.maxMessageLength).toString()]);
msgTooLongLabel.includeInLayout = msgTooLongLabel.visible = true;
if (chatCtrlBar.height != 80) {
chatCtrlBar.height = 80;
chatListHeight -= 20;
}
// The case where lock settings are set
if (txtMsgArea.enabled) {
sendBtn.enabled = false;
}
}
private function hideMessageTooLong():void {
msgTooLongLabel.includeInLayout = msgTooLongLabel.visible = false;
if (chatCtrlBar.height != 60) {
chatCtrlBar.height = 60;
chatListHeight += 20;
}
// The case where lock settings are set
if (txtMsgArea.enabled) {
sendBtn.enabled = true;
}
}
private function focusChatInput(e:ShortcutEvent):void{
txtMsgArea.setFocus();
}
private function lockSettingsChanged(e:Event):void {
applyLockSettings();
}
private function applyLockSettings():void {
if (publicChat) {
txtMsgArea.enabled = sendBtn.enabled = !LiveMeeting.inst().me.disableMyPublicChat;
} else {
txtMsgArea.enabled = sendBtn.enabled = !LiveMeeting.inst().me.disableMyPrivateChat;
}
}
private function refreshRole(e:ChangeMyRole):void {
applyLockSettings();
}
private function get messageCanBeSent() : Boolean {
return StringUtils.trim(txtMsgArea.text).length <= chatOptions.maxMessageLength;
}
protected function txtMsgAreaChangeHandler(event:Event):void
{
if (!messageCanBeSent) {
showMessageTooLong(StringUtils.trim(txtMsgArea.text).length);
}
else {
hideMessageTooLong();
}
}
private function handleClearPublicChatBoxMessages(event:ClearPublicChatEvent):void {
if(publicChat){
chatMessages.clearPublicChat();
invalidateDisplayList();
validateNow();
}
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
// Force validation before evaluation of toolbar width
validateNow();
const paddingHeight:int = 5;
const paddingWidth:int = 5;
chatToolbar.x = (chatMessagesCanvas.width - chatToolbar.width) - 20;
chatToolbar.y = 10;
if (!publicChat) {
chatToolbar.publicChat = false;
}
}
]]>
</fx:Script>
<fx:Declarations>
<common:TabIndexer id="tabIndexer" tabIndices="{[chatMessagesList, txtMsgArea, sendBtn, cmpColorPicker]}"/>
</fx:Declarations>
<mx:VBox width="100%" height="{chatListHeight}" verticalScrollPolicy="off">
<mx:Canvas id="chatMessagesCanvas" width="100%" height="{chatListHeight}" horizontalScrollPolicy="off" verticalScrollPolicy="off" >
<chat:AdvancedList width="100%" height="{chatListHeight}" id="chatMessagesList" selectable="true" variableRowHeight="true"
itemRenderer="org.bigbluebutton.modules.chat.views.ChatMessageRenderer" verticalScrollPolicy="on" horizontalScrollPolicy="off" wordWrap="true"
dataProvider="{chatMessages.messages}"
styleName="chatMessageListStyle"
accessibilityName="{ResourceUtil.getInstance().getString('bbb.chat.messageList')}" />
<chat:ChatToolbar id="chatToolbar" />
</mx:Canvas>
</mx:VBox>
<mx:HBox id="chatCtrlBar" width="100%" height="60" styleName="chatControlBarStyle" verticalScrollPolicy="off"
paddingLeft="5" paddingRight="5">
<mx:VBox width="100%" height="100%">
<!-- There is a restrict in this textArea to avoid a known issue where a \u007F, which is the delete character, would be seen written in some browsers as an invalid character -->
<mx:TextArea id="txtMsgArea" width="100%" height="100%" restrict="^\u007F"
styleName="chatControlBarTextMsgStyle"
change="txtMsgAreaChangeHandler(event)"
toolTip="{ResourceUtil.getInstance().getString('bbb.accessibility.chat.chatwindow.input')}"
accessibilityName="{ResourceUtil.getInstance().getString('bbb.chat.input.accessibilityName')}" />
<mx:Label id="msgTooLongLabel" width="100%" height="100%" includeInLayout="false" visible="false"/>
</mx:VBox>
<mx:VBox verticalScrollPolicy="off" verticalAlign="middle" height="100%" >
<mx:HBox horizontalGap="0">
<mx:Button id="sendBtn"
styleName="chatControlBarSendButtonStyle"
width="40" height="40"
toolTip="{ResourceUtil.getInstance().getString('bbb.chat.sendBtn.toolTip')}"
click="sendMessages()"
accessibilityName="{ResourceUtil.getInstance().getString('bbb.chat.sendBtn.accessibilityName')}"/>
</mx:HBox>
<mx:ColorPicker id="cmpColorPicker" showTextField="false" width="100%" visible="{chatOptions.colorPickerIsVisible}"
includeInLayout="{chatOptions.colorPickerIsVisible}"
toolTip="{ResourceUtil.getInstance().getString('bbb.chat.cmpColorPicker.toolTip')}"
selectedColor="0x000000" dataProvider="{colorPickerColours}" swatchPanelStyleName="chatColorPickerStyle"/>
</mx:VBox>
</mx:HBox>
</mx:VBox>

View File

@ -51,24 +51,24 @@ package org.bigbluebutton.modules.users.services
import org.bigbluebutton.main.model.users.events.StreamStoppedEvent;
import org.bigbluebutton.modules.screenshare.events.WebRTCViewStreamEvent;
import org.bigbluebutton.modules.users.events.MeetingMutedEvent;
public class MessageReceiver implements IMessageListener
{
private static const LOGGER:ILogger = getClassLogger(MessageReceiver);
private static const LOGGER:ILogger = getClassLogger(MessageReceiver);
private var dispatcher:Dispatcher;
public var onAllowedToJoin:Function = null;
private static var globalDispatcher:Dispatcher = new Dispatcher();
public function MessageReceiver() {
BBB.initConnectionManager().addMessageListener(this);
this.dispatcher = new Dispatcher();
}
public function onMessage(messageName:String, message:Object):void {
LOGGER.debug(" received message " + messageName);
switch (messageName) {
case "GetUsersMeetingRespMsg":
handleGetUsersMeetingRespMsg(message);
@ -89,7 +89,7 @@ package org.bigbluebutton.modules.users.services
handleAssignPresenterCallback(message);
break;
case "PresenterUnassignedEvtMsg":
handleUnassignPresenterCallback(message);
handleUnassignPresenterCallback(message);
break;
case "UserBroadcastCamStartedEvtMsg":
handleUserBroadcastCamStartedEvtMsg(message);
@ -145,28 +145,28 @@ package org.bigbluebutton.modules.users.services
case "userLocked":
handleUserLocked(message);
break;
// Breakout room feature
case "BreakoutRoomsListEvtMsg":
handleBreakoutRoomsList(message)
break;
case "BreakoutRoomJoinURLEvtMsg":
handleBreakoutRoomJoinURL(message);
break;
case "UpdateBreakoutUsersEvtMsg":
handleUpdateBreakoutUsers(message);
break;
case "MeetingTimeRemainingUpdateEvtMsg":
handleMeetingTimeRemainingUpdateEvtMsg(message);
break;
case "BreakoutRoomsTimeRemainingUpdateEvtMsg":
handleBreakoutRoomsTimeRemainingUpdate(message);
break;
case "BreakoutRoomStartedEvtMsg":
handleBreakoutRoomStarted(message);
break;
case "BreakoutRoomEndedEvtMsg":
handleBreakoutRoomClosed(message);
break;
// Breakout room feature
case "BreakoutRoomsListEvtMsg":
handleBreakoutRoomsList(message)
break;
case "BreakoutRoomJoinURLEvtMsg":
handleBreakoutRoomJoinURL(message);
break;
case "UpdateBreakoutUsersEvtMsg":
handleUpdateBreakoutUsers(message);
break;
case "MeetingTimeRemainingUpdateEvtMsg":
handleMeetingTimeRemainingUpdateEvtMsg(message);
break;
case "BreakoutRoomsTimeRemainingUpdateEvtMsg":
handleBreakoutRoomsTimeRemainingUpdate(message);
break;
case "BreakoutRoomStartedEvtMsg":
handleBreakoutRoomStarted(message);
break;
case "BreakoutRoomEndedEvtMsg":
handleBreakoutRoomClosed(message);
break;
case "UserEjectedFromMeetingEvtMsg":
handleUserEjectedFromMeeting(message);
break;
@ -187,11 +187,11 @@ package org.bigbluebutton.modules.users.services
break;
}
}
private function handleUserJoinedVoiceConfToClientEvtMsg(msg: Object): void {
var header: Object = msg.header as Object;
var body: Object = msg.body as Object;
var vu: VoiceUser2x = new VoiceUser2x();
vu.intId = body.intId as String;
vu.voiceUserId = body.voiceUserId as String;
@ -212,7 +212,7 @@ package org.bigbluebutton.modules.users.services
var bbbEvent:BBBEvent = new BBBEvent(BBBEvent.USER_VOICE_JOINED);
bbbEvent.payload.userID = vu.intId;
globalDispatcher.dispatchEvent(bbbEvent);
}
private function handleUserLeftVoiceConfToClientEvtMsg(msg: Object):void {
@ -268,7 +268,7 @@ package org.bigbluebutton.modules.users.services
var guestWaiting: GuestWaiting = new GuestWaiting(guest.intId, guest.name, guest.role);
LiveMeeting.inst().guestsWaiting.add(guestWaiting);
}
private function handleGuestsWaitingForApprovalEvtMsg(msg: Object): void {
var body: Object = msg.body as Object;
var guests: Array = body.guests as Array;
@ -287,7 +287,7 @@ package org.bigbluebutton.modules.users.services
var body: Object = msg.body as Object
var users: Array = body.users as Array;
LOGGER.debug("Num USERs = " + users.length);
for (var i:int = 0; i < users.length; i++) {
var user:Object = users[i] as Object;
processUserJoinedMeetingMsg(user);
@ -410,7 +410,7 @@ package org.bigbluebutton.modules.users.services
}
}
private function handleScreenshareRtmpBroadcastStartedEvtMsg(msg:Object):void {
var body: Object = msg.body as Object
var stream: String = body.stream as String;
@ -440,45 +440,45 @@ package org.bigbluebutton.modules.users.services
dispatcher.dispatchEvent(event);
}
private function handleUserEjectedFromMeeting(msg: Object):void {
var body: Object = msg.body as Object;
var userId:String = body.userId as String;
UsersUtil.setUserEjected();
var logData:Object = UsersUtil.initLogData();
logData.tags = ["users"];
logData.status = "user_ejected";
logData.message = "User ejected from meeting.";
LOGGER.info(JSON.stringify(logData));
}
private function handleUserLocked(msg:Object):void {
var map:Object = JSON.parse(msg.msg);
var user:User2x = UsersUtil.getUser(map.user);
if(user.locked != map.lock) {
if (UsersUtil.isMe(user.intId)) {
LiveMeeting.inst().me.locked = map.locked;
private function handleUserLocked(msg:Object):void {
var map:Object = JSON.parse(msg.msg);
var user:User2x = UsersUtil.getUser(map.user);
if(user.locked != map.lock) {
if (UsersUtil.isMe(user.intId)) {
LiveMeeting.inst().me.locked = map.locked;
}
dispatcher.dispatchEvent(new UserStatusChangedEvent(user.intId));
}
dispatcher.dispatchEvent(new UserStatusChangedEvent(user.intId));
return;
}
return;
}
private function handlePermissionsSettingsChanged(msg:Object):void {
//LOGGER.debug("handlePermissionsSettingsChanged {0} \n", [msg.msg]);
var map:Object = JSON.parse(msg.msg);
var lockSettings:LockSettingsVO = new LockSettingsVO(map.disableCam,
map.disableMic,
map.disablePrivateChat,
map.disablePublicChat,
map.lockedLayout,
map.lockOnJoin,
map.lockOnJoinConfigurable);
map.disableMic,
map.disablePrivateChat,
map.disablePublicChat,
map.lockedLayout,
map.lockOnJoin,
map.lockOnJoinConfigurable);
UsersUtil.setLockSettings(lockSettings);
}
@ -488,7 +488,7 @@ package org.bigbluebutton.modules.users.services
var e:BBBEvent = new BBBEvent(BBBEvent.CHANGE_RECORDING_STATUS);
e.payload.remote = true;
e.payload.recording = recording;
dispatcher.dispatchEvent(e);
}
@ -506,8 +506,8 @@ package org.bigbluebutton.modules.users.services
var perm:Object = map.permissions;
var lockSettings:LockSettingsVO = new LockSettingsVO(perm.disableCam, perm.disableMic,
perm.disablePrivateChat, perm.disablePublicChat,
perm.lockedLayout, perm.lockOnJoin, perm.lockOnJoinConfigurable);
perm.disablePrivateChat, perm.disablePublicChat,
perm.lockedLayout, perm.lockOnJoin, perm.lockOnJoinConfigurable);
UsersUtil.setLockSettings(lockSettings);
LiveMeeting.inst().meetingStatus.isMeetingMuted = map.meetingMuted;
@ -516,17 +516,17 @@ package org.bigbluebutton.modules.users.services
private function handleInactivityWarning(msg:Object):void {
var map:Object = JSON.parse(msg.msg);
var bbbEvent:BBBEvent = new BBBEvent(BBBEvent.INACTIVITY_WARNING_EVENT);
bbbEvent.payload.duration = map.duration;
globalDispatcher.dispatchEvent(bbbEvent);
}
private function handleMeetingIsActive(msg:Object):void {
var bbbEvent:BBBEvent = new BBBEvent(BBBEvent.MEETING_IS_ACTIVE_EVENT);
globalDispatcher.dispatchEvent(bbbEvent);
}
private function handleGetRecordingStatusReply(msg: Object):void {
var body:Object = msg.body as Object;
var recording: Boolean = body.recording as Boolean;
@ -535,8 +535,8 @@ package org.bigbluebutton.modules.users.services
}
private function handleRecordingStatusChanged(msg: Object):void {
var body:Object = msg.body as Object;
var recording: Boolean = body.recording as Boolean;
var body:Object = msg.body as Object;
var recording: Boolean = body.recording as Boolean;
sendRecordingStatusUpdate(recording);
}
@ -548,7 +548,7 @@ package org.bigbluebutton.modules.users.services
LiveMeeting.inst().voiceUsers.setListenOnlyForUser(userId, listenOnly);
}
private function userTalk(userId:String, talking:Boolean):void {
LiveMeeting.inst().voiceUsers.setMutedForUser(userId, talking);
@ -567,8 +567,8 @@ package org.bigbluebutton.modules.users.services
// Avoid trying to reconnect
var cancelReconnectEvent:BBBEvent = new BBBEvent(BBBEvent.CANCEL_RECONNECTION_EVENT);
dispatcher.dispatchEvent(cancelReconnectEvent);
var endMeetingEvent:BBBEvent = new BBBEvent(BBBEvent.END_MEETING_EVENT);
dispatcher.dispatchEvent(endMeetingEvent);
var endMeetingEvent:BBBEvent = new BBBEvent(BBBEvent.END_MEETING_EVENT);
dispatcher.dispatchEvent(endMeetingEvent);
}
public function handleAssignPresenterCallback(msg:Object):void {
@ -577,10 +577,10 @@ package org.bigbluebutton.modules.users.services
var newPresenterID:String = body.presenterId as String;
var newPresenterName:String = body.presenterName as String;
var assignedBy:String = body.assignedBy as String;
UsersUtil.setUserAsPresent(newPresenterID, true);
sendSwitchedPresenterEvent(true, newPresenterID);
if (UsersUtil.getMyUserID() == newPresenterID) {
var e:MadePresenterEvent = new MadePresenterEvent(MadePresenterEvent.SWITCH_TO_PRESENTER_MODE);
e.userID = newPresenterID;
@ -591,17 +591,17 @@ package org.bigbluebutton.modules.users.services
dispatcher.dispatchEvent(new UserStatusChangedEvent(newPresenterID));
}
public function handleUnassignPresenterCallback(msg:Object):void {
var body: Object = msg.body as Object;
var oldPresenterID:String = body.intId as String;
var oldPresenterName:String = body.name as String;
var assignedBy:String = body.assignedBy as String;
UsersUtil.setUserAsPresent(oldPresenterID, false);
sendSwitchedPresenterEvent(false, oldPresenterID);
if (UsersUtil.getMyUserID() == oldPresenterID) {
var e:MadePresenterEvent = new MadePresenterEvent(MadePresenterEvent.SWITCH_TO_VIEWER_MODE);
e.userID = oldPresenterID;
@ -609,17 +609,17 @@ package org.bigbluebutton.modules.users.services
e.assignedBy = assignedBy;
dispatcher.dispatchEvent(e);
}
dispatcher.dispatchEvent(new UserStatusChangedEvent(oldPresenterID));
}
private function sendSwitchedPresenterEvent(amIPresenter:Boolean, newPresenterUserID:String):void {
var roleEvent:SwitchedPresenterEvent = new SwitchedPresenterEvent();
roleEvent.amIPresenter = amIPresenter;
roleEvent.newPresenterUserID = newPresenterUserID;
dispatcher.dispatchEvent(roleEvent);
}
private function handleEmojiStatusHand(msg: Object): void {
var body:Object = msg.body as Object;
var userId: String = body.userId as String;
@ -635,7 +635,7 @@ package org.bigbluebutton.modules.users.services
}
}
private function sendUserEmojiChangedEvent(userId: String, emoji: String):void{
var dispatcher:Dispatcher = new Dispatcher();
dispatcher.dispatchEvent(new UserEmojiChangedEvent(userId, emoji));
@ -643,145 +643,145 @@ package org.bigbluebutton.modules.users.services
private function handleUserBroadcastCamStartedEvtMsg(msg:Object):void {
var userId: String = msg.body.userId as String;
var streamId: String = msg.body.stream as String;
var logData:Object = UsersUtil.initLogData();
logData.tags = ["webcam"];
logData.message = "UserBroadcastCamStartedEvtMsg server message";
logData.user.webcamStream = streamId;
LOGGER.info(JSON.stringify(logData));
var mediaStream: MediaStream = new MediaStream(streamId, userId)
LiveMeeting.inst().webcams.add(mediaStream);
var webUser: User2x = UsersUtil.getUser(userId);
if (webUser != null) {
sendStreamStartedEvent(userId, webUser.name, streamId);
}
var userId: String = msg.body.userId as String;
var streamId: String = msg.body.stream as String;
var logData:Object = UsersUtil.initLogData();
logData.tags = ["webcam"];
logData.message = "UserBroadcastCamStartedEvtMsg server message";
logData.user.webcamStream = streamId;
LOGGER.info(JSON.stringify(logData));
var mediaStream: MediaStream = new MediaStream(streamId, userId)
LiveMeeting.inst().webcams.add(mediaStream);
var webUser: User2x = UsersUtil.getUser(userId);
if (webUser != null) {
sendStreamStartedEvent(userId, webUser.name, streamId);
}
}
private function sendStreamStartedEvent(userId: String, name: String, stream: String):void{
var dispatcher:Dispatcher = new Dispatcher();
dispatcher.dispatchEvent(new StreamStartedEvent(userId, name, stream));
}
private function handleUserBroadcastCamStoppedEvtMsg(msg: Object):void {
var userId: String = msg.body.userId as String;
var stream: String = msg.body.stream as String;
var logData:Object = UsersUtil.initLogData();
logData.tags = ["webcam"];
logData.message = "UserBroadcastCamStoppedEvtMsg server message";
logData.user.webcamStream = stream;
LOGGER.info(JSON.stringify(logData));
LiveMeeting.inst().webcams.remove(stream);
sendStreamStoppedEvent(userId, stream);
var userId: String = msg.body.userId as String;
var stream: String = msg.body.stream as String;
var logData:Object = UsersUtil.initLogData();
logData.tags = ["webcam"];
logData.message = "UserBroadcastCamStoppedEvtMsg server message";
logData.user.webcamStream = stream;
LOGGER.info(JSON.stringify(logData));
LiveMeeting.inst().webcams.remove(stream);
sendStreamStoppedEvent(userId, stream);
}
private function sendStreamStoppedEvent(userId: String, streamId: String):void{
var dispatcher:Dispatcher = new Dispatcher();
dispatcher.dispatchEvent(new StreamStoppedEvent(userId, streamId));
}
private function handleBreakoutRoomsList(msg:Object):void{
for each(var room : Object in msg.body.rooms) {
var breakoutRoom : BreakoutRoom = new BreakoutRoom();
breakoutRoom.meetingId = room.breakoutId as String;
breakoutRoom.externalMeetingId = room.externalId as String;
breakoutRoom.name = room.name as String;
breakoutRoom.sequence = room.sequence as Number;
LiveMeeting.inst().breakoutRooms.addBreakoutRoom(breakoutRoom);
}
LiveMeeting.inst().breakoutRooms.breakoutRoomsReady = msg.body.roomsReady as Boolean;
}
private function handleBreakoutRoomJoinURL(msg:Object):void{
var body: Object = msg.body as Object;
var externalId: String = body.externalId as String;
var redirectJoinURL: String = body.redirectJoinURL as String;
var breakoutRoom : BreakoutRoom = LiveMeeting.inst().breakoutRooms.getBreakoutRoomByExternalId(externalId);
var sequence : int = breakoutRoom.sequence;
var event : BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.BREAKOUT_JOIN_URL);
event.joinURL = redirectJoinURL;
event.breakoutMeetingSequence = sequence;
dispatcher.dispatchEvent(event);
// We delay assigning last room invitation sequence to be sure it is handle in time by the item renderer
setTimeout(function() : void {LiveMeeting.inst().breakoutRooms.setLastBreakoutRoomInvitation(sequence)}, 1000);
}
private function handleUpdateBreakoutUsers(msg:Object):void{
var body: Object = msg.body as Object;
var breakoutId: String = body.breakoutId as String;
var users: Array = body.users as Array;
LiveMeeting.inst().breakoutRooms.updateUsers(breakoutId, users);
}
private function handleMeetingTimeRemainingUpdateEvtMsg(msg:Object):void {
// var e:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.UPDATE_REMAINING_TIME_PARENT);
// e.durationInMinutes = msg.body.timeRemaining;
// dispatcher.dispatchEvent(e);
}
private function handleBreakoutRoomsTimeRemainingUpdate(msg:Object):void {
var e:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.UPDATE_REMAINING_TIME_PARENT);
e.durationInMinutes = msg.body.timeRemaining;
dispatcher.dispatchEvent(e);
}
private function handleBreakoutRoomStarted(msg:Object):void{
var breakout: Object = msg.body.breakout as Object;
var breakoutId: String = breakout.breakoutId as String;
var externalId: String = breakout.externalId as String;
var name: String = breakout.name as String;
var sequence: int = breakout.sequence as Number;
var breakoutRoom : BreakoutRoom = new BreakoutRoom();
breakoutRoom.meetingId = breakoutId;
breakoutRoom.externalMeetingId = externalId;
breakoutRoom.name = name;
breakoutRoom.sequence = sequence;
LiveMeeting.inst().breakoutRooms.addBreakoutRoom(breakoutRoom);
}
private function handleBreakoutRoomClosed(msg:Object):void{
var body: Object = msg.body as Object;
var breakoutId: String = body.breakoutId as String;
switchUserFromBreakoutToMainVoiceConf(breakoutId);
var breakoutRoom: BreakoutRoom = LiveMeeting.inst().breakoutRooms.getBreakoutRoom(breakoutId);
LiveMeeting.inst().breakoutRooms.removeBreakoutRoom(breakoutId);
}
private function switchUserFromBreakoutToMainVoiceConf(breakoutId: String): void {
// We need to switch the use back to the main audio confrence if he is in a breakout audio conference
if (LiveMeeting.inst().breakoutRooms.isListeningToBreakoutRoom(breakoutId)) {
private function sendStreamStoppedEvent(userId: String, streamId: String):void{
var dispatcher:Dispatcher = new Dispatcher();
var e:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.LISTEN_IN);
e.breakoutMeetingId = breakoutId;
e.listen = false;
dispatcher.dispatchEvent(new StreamStoppedEvent(userId, streamId));
}
private function handleBreakoutRoomsList(msg:Object):void{
for each(var room : Object in msg.body.rooms) {
var breakoutRoom : BreakoutRoom = new BreakoutRoom();
breakoutRoom.meetingId = room.breakoutId as String;
breakoutRoom.externalMeetingId = room.externalId as String;
breakoutRoom.name = room.name as String;
breakoutRoom.sequence = room.sequence as Number;
LiveMeeting.inst().breakoutRooms.addBreakoutRoom(breakoutRoom);
}
LiveMeeting.inst().breakoutRooms.breakoutRoomsReady = msg.body.roomsReady as Boolean;
}
private function handleBreakoutRoomJoinURL(msg:Object):void{
var body: Object = msg.body as Object;
var externalId: String = body.externalId as String;
var redirectJoinURL: String = body.redirectJoinURL as String;
var breakoutRoom : BreakoutRoom = LiveMeeting.inst().breakoutRooms.getBreakoutRoomByExternalId(externalId);
var sequence : int = breakoutRoom.sequence;
var event : BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.BREAKOUT_JOIN_URL);
event.joinURL = redirectJoinURL;
event.breakoutMeetingSequence = sequence;
dispatcher.dispatchEvent(event);
// We delay assigning last room invitation sequence to be sure it is handle in time by the item renderer
setTimeout(function() : void {LiveMeeting.inst().breakoutRooms.setLastBreakoutRoomInvitation(sequence)}, 1000);
}
private function handleUpdateBreakoutUsers(msg:Object):void{
var body: Object = msg.body as Object;
var breakoutId: String = body.breakoutId as String;
var users: Array = body.users as Array;
LiveMeeting.inst().breakoutRooms.updateUsers(breakoutId, users);
}
private function handleMeetingTimeRemainingUpdateEvtMsg(msg:Object):void {
var e:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.UPDATE_REMAINING_TIME_PARENT);
e.durationInMinutes = msg.body.timeLeftInSec;
dispatcher.dispatchEvent(e);
}
}
private function handleBreakoutRoomsTimeRemainingUpdate(msg:Object):void {
var e:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.UPDATE_REMAINING_TIME_PARENT);
e.durationInMinutes = msg.body.timeRemaining;
dispatcher.dispatchEvent(e);
}
private function handleBreakoutRoomStarted(msg:Object):void{
var breakout: Object = msg.body.breakout as Object;
var breakoutId: String = breakout.breakoutId as String;
var externalId: String = breakout.externalId as String;
var name: String = breakout.name as String;
var sequence: int = breakout.sequence as Number;
var breakoutRoom : BreakoutRoom = new BreakoutRoom();
breakoutRoom.meetingId = breakoutId;
breakoutRoom.externalMeetingId = externalId;
breakoutRoom.name = name;
breakoutRoom.sequence = sequence;
LiveMeeting.inst().breakoutRooms.addBreakoutRoom(breakoutRoom);
}
private function handleBreakoutRoomClosed(msg:Object):void{
var body: Object = msg.body as Object;
var breakoutId: String = body.breakoutId as String;
switchUserFromBreakoutToMainVoiceConf(breakoutId);
var breakoutRoom: BreakoutRoom = LiveMeeting.inst().breakoutRooms.getBreakoutRoom(breakoutId);
LiveMeeting.inst().breakoutRooms.removeBreakoutRoom(breakoutId);
}
private function switchUserFromBreakoutToMainVoiceConf(breakoutId: String): void {
// We need to switch the use back to the main audio confrence if he is in a breakout audio conference
if (LiveMeeting.inst().breakoutRooms.isListeningToBreakoutRoom(breakoutId)) {
var dispatcher:Dispatcher = new Dispatcher();
var e:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.LISTEN_IN);
e.breakoutMeetingId = breakoutId;
e.listen = false;
dispatcher.dispatchEvent(e);
}
}
public function handleGuestPolicyChanged(msg:Object):void {
var header: Object = msg.header as Object;
var body: Object = msg.body as Object;
var policy: String = body.policy as String;
var policyEvent:BBBEvent = new BBBEvent(BBBEvent.RETRIEVE_GUEST_POLICY);
policyEvent.payload['guestPolicy'] = policy;
dispatcher.dispatchEvent(policyEvent);
}
public function handleGetGuestPolicyReply(msg:Object):void {
var header: Object = msg.header as Object;
var body: Object = msg.body as Object;
@ -793,11 +793,11 @@ package org.bigbluebutton.modules.users.services
policyEvent.payload['guestPolicy'] = policyEvent;
dispatcher.dispatchEvent(policyEvent);
}
public function handleGuestAccessDenied(msg:Object):void {
LOGGER.debug("*** handleGuestAccessDenied " + msg.msg + " ****");
var map:Object = JSON.parse(msg.msg);
if (UsersUtil.getMyUserID() == map.userId) {
dispatcher.dispatchEvent(new LogoutEvent(LogoutEvent.MODERATOR_DENIED_ME));
}

View File

@ -131,7 +131,7 @@ package org.bigbluebutton.modules.users.services
var message:Object = {
header: {name: "TransferUserToMeetingRequestMsg", meetingId: UsersUtil.getInternalMeetingID(),
userId: UsersUtil.getMyUserID()},
body: {meetingId: fomMeetingId, toMeetingId: toMeetingId, userId: UsersUtil.getMyUserID()}
body: {fomMeetingId: fomMeetingId, toMeetingId: toMeetingId, userId: UsersUtil.getMyUserID()}
};
var _nc:ConnectionManager = BBB.initConnectionManager();

View File

@ -151,7 +151,6 @@ package org.bigbluebutton.modules.users.views
// We want to remove the user if it's already in the collection and re-add it.
removeUser(user.userId, users);
trace("Adding User joined to voice conference " + user.name + " id=" + user.userId);
users.addItem(user);
}
}
@ -159,7 +158,6 @@ package org.bigbluebutton.modules.users.views
public function handleUserJoinedVoiceConfEvent(userId: String):void {
var webUser: BBBUser2x = findUser(userId);
if (webUser != null) {
trace("User joined to voice conference " + webUser.name + " id=" + webUser.userId);
addVoiceUserToWebUser(webUser);
} else {
var vu: VoiceUser2x = LiveMeeting.inst().voiceUsers.getUser(userId);
@ -247,6 +245,7 @@ package org.bigbluebutton.modules.users.views
var user: BBBUser2x = findUser(userId);
if (user != null) {
user.talking = talking;
if (user.muted && talking) user.talking = false;
}
users.refresh();
}
@ -255,6 +254,7 @@ package org.bigbluebutton.modules.users.views
var user: BBBUser2x = findUser(userId);
if (user != null) {
user.muted = muted;
if (muted) user.talking = false;
}
users.refresh();
}
@ -285,6 +285,22 @@ package org.bigbluebutton.modules.users.views
refreshWebcamStreamsInfo(event.userId);
}
public function handleMadePresenterEvent(userId: String): void {
var user: BBBUser2x = findUser(userId);
if (user != null) {
user.presenter = true;
}
users.refresh();
}
public function handleMadeVieweEvent(userId: String): void {
var user: BBBUser2x = findUser(userId);
if (user != null) {
user.presenter = false;
}
users.refresh();
}
private function findUser(userId: String): BBBUser2x {
for (var i: int = 0; i < users.length; i++) {
var user: BBBUser2x = users[i] as BBBUser2x;