Merge branch 'riadvice-recording-timer' into v2.0.x-release
This commit is contained in:
commit
126bb62d7d
@ -29,6 +29,8 @@ case class MonitorNumberOfUsersInternalMsg(meetingID: String) extends InMessage
|
||||
*/
|
||||
case class SendTimeRemainingAuditInternalMsg(meetingId: String) extends InMessage
|
||||
|
||||
case class SendRecordingTimerInternalMsg(meetingId: String) extends InMessage
|
||||
|
||||
case class ExtendMeetingDuration(meetingId: String, userId: String) extends InMessage
|
||||
case class DestroyMeetingInternalMsg(meetingId: String) extends InMessage
|
||||
|
||||
|
@ -0,0 +1,43 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
import org.bigbluebutton.core2.MeetingStatus2x
|
||||
import org.bigbluebutton.core.util.TimeUtil
|
||||
|
||||
trait RecordAndClearPreviousMarkersCmdMsgHdlr {
|
||||
this: UsersApp =>
|
||||
|
||||
val liveMeeting: LiveMeeting
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleRecordAndClearPreviousMarkersCmdMsg(msg: RecordAndClearPreviousMarkersCmdMsg, state: MeetingState2x): MeetingState2x = {
|
||||
log.info("Set a new recording marker and clear previous ones. meetingId=" + liveMeeting.props.meetingProp.intId + " recording=" + msg.body.recording)
|
||||
|
||||
def buildRecordingStatusChangedEvtMsg(meetingId: String, userId: String, recording: Boolean): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
|
||||
val envelope = BbbCoreEnvelope(RecordingStatusChangedEvtMsg.NAME, routing)
|
||||
val body = RecordingStatusChangedEvtMsgBody(recording, userId)
|
||||
val header = BbbClientMsgHeader(RecordingStatusChangedEvtMsg.NAME, meetingId, userId)
|
||||
val event = RecordingStatusChangedEvtMsg(header, body)
|
||||
|
||||
BbbCommonEnvCoreMsg(envelope, event)
|
||||
}
|
||||
|
||||
// Do not allow stop recording and clear previous markers
|
||||
if (liveMeeting.props.recordProp.allowStartStopRecording &&
|
||||
MeetingStatus2x.isRecording(liveMeeting.status) != msg.body.recording) {
|
||||
|
||||
MeetingStatus2x.recordingStarted(liveMeeting.status)
|
||||
|
||||
val tracker = state.recordingTracker.resetTimer(TimeUtil.timeNowInMs())
|
||||
val event = buildRecordingStatusChangedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.setBy, msg.body.recording)
|
||||
outGW.send(event)
|
||||
|
||||
state.update(tracker)
|
||||
} else {
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.api.SendRecordingTimerInternalMsg
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
import org.bigbluebutton.core.util.TimeUtil
|
||||
import org.bigbluebutton.core2.MeetingStatus2x
|
||||
|
||||
trait SendRecordingTimerInternalMsgHdlr {
|
||||
this: UsersApp =>
|
||||
|
||||
val liveMeeting: LiveMeeting
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleSendRecordingTimerInternalMsg(msg: SendRecordingTimerInternalMsg, state: MeetingState2x): MeetingState2x = {
|
||||
def buildUpdateRecordingTimerEvtMsg(meetingId: String, recordingTime: Long): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "not-used")
|
||||
val envelope = BbbCoreEnvelope(UpdateRecordingTimerEvtMsg.NAME, routing)
|
||||
val body = UpdateRecordingTimerEvtMsgBody(recordingTime)
|
||||
val header = BbbClientMsgHeader(UpdateRecordingTimerEvtMsg.NAME, meetingId, "not-used")
|
||||
val event = UpdateRecordingTimerEvtMsg(header, body)
|
||||
|
||||
BbbCommonEnvCoreMsg(envelope, event)
|
||||
}
|
||||
|
||||
var newDuration = 0L
|
||||
if (MeetingStatus2x.isRecording(liveMeeting.status)) {
|
||||
newDuration = TimeUtil.timeNowInMs()
|
||||
}
|
||||
|
||||
val tracker = state.recordingTracker.udpateCurrentDuration(newDuration)
|
||||
|
||||
val recordingTime = TimeUtil.millisToSeconds(tracker.recordingDuration())
|
||||
|
||||
val event = buildUpdateRecordingTimerEvtMsg(liveMeeting.props.meetingProp.intId, recordingTime)
|
||||
outGW.send(event)
|
||||
|
||||
state.update(tracker)
|
||||
}
|
||||
}
|
@ -1,37 +1,56 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
import org.bigbluebutton.core2.MeetingStatus2x
|
||||
|
||||
trait SetRecordingStatusCmdMsgHdlr {
|
||||
this: UsersApp =>
|
||||
|
||||
val liveMeeting: LiveMeeting
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleSetRecordingStatusCmdMsg(msg: SetRecordingStatusCmdMsg) {
|
||||
log.info("Change recording status. meetingId=" + liveMeeting.props.meetingProp.intId + " recording=" + msg.body.recording)
|
||||
if (liveMeeting.props.recordProp.allowStartStopRecording &&
|
||||
MeetingStatus2x.isRecording(liveMeeting.status) != msg.body.recording) {
|
||||
if (msg.body.recording) {
|
||||
MeetingStatus2x.recordingStarted(liveMeeting.status)
|
||||
} else {
|
||||
MeetingStatus2x.recordingStopped(liveMeeting.status)
|
||||
}
|
||||
|
||||
val event = buildRecordingStatusChangedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.setBy, msg.body.recording)
|
||||
outGW.send(event)
|
||||
}
|
||||
|
||||
def buildRecordingStatusChangedEvtMsg(meetingId: String, userId: String, recording: Boolean): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
|
||||
val envelope = BbbCoreEnvelope(RecordingStatusChangedEvtMsg.NAME, routing)
|
||||
val body = RecordingStatusChangedEvtMsgBody(recording, userId)
|
||||
val header = BbbClientMsgHeader(RecordingStatusChangedEvtMsg.NAME, meetingId, userId)
|
||||
val event = RecordingStatusChangedEvtMsg(header, body)
|
||||
|
||||
BbbCommonEnvCoreMsg(envelope, event)
|
||||
}
|
||||
}
|
||||
}
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
import org.bigbluebutton.core2.MeetingStatus2x
|
||||
import org.bigbluebutton.core.util.TimeUtil
|
||||
import org.bigbluebutton.core.bus.BigBlueButtonEvent
|
||||
import org.bigbluebutton.core.api.SendRecordingTimerInternalMsg
|
||||
|
||||
trait SetRecordingStatusCmdMsgHdlr {
|
||||
this: UsersApp =>
|
||||
|
||||
val liveMeeting: LiveMeeting
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleSetRecordingStatusCmdMsg(msg: SetRecordingStatusCmdMsg, state: MeetingState2x): MeetingState2x = {
|
||||
log.info("Change recording status. meetingId=" + liveMeeting.props.meetingProp.intId + " recording=" + msg.body.recording)
|
||||
|
||||
def buildRecordingStatusChangedEvtMsg(meetingId: String, userId: String, recording: Boolean): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
|
||||
val envelope = BbbCoreEnvelope(RecordingStatusChangedEvtMsg.NAME, routing)
|
||||
val body = RecordingStatusChangedEvtMsgBody(recording, userId)
|
||||
val header = BbbClientMsgHeader(RecordingStatusChangedEvtMsg.NAME, meetingId, userId)
|
||||
val event = RecordingStatusChangedEvtMsg(header, body)
|
||||
|
||||
BbbCommonEnvCoreMsg(envelope, event)
|
||||
}
|
||||
|
||||
if (liveMeeting.props.recordProp.allowStartStopRecording &&
|
||||
MeetingStatus2x.isRecording(liveMeeting.status) != msg.body.recording) {
|
||||
if (msg.body.recording) {
|
||||
MeetingStatus2x.recordingStarted(liveMeeting.status)
|
||||
} else {
|
||||
MeetingStatus2x.recordingStopped(liveMeeting.status)
|
||||
}
|
||||
|
||||
val event = buildRecordingStatusChangedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.setBy, msg.body.recording)
|
||||
outGW.send(event)
|
||||
|
||||
var newState = state
|
||||
if (MeetingStatus2x.isRecording(liveMeeting.status)) {
|
||||
val tracker = state.recordingTracker.startTimer(TimeUtil.timeNowInMs())
|
||||
newState = state.update(tracker)
|
||||
} else {
|
||||
val tracker = state.recordingTracker.pauseTimer(TimeUtil.timeNowInMs())
|
||||
newState = state.update(tracker)
|
||||
}
|
||||
eventBus.publish(BigBlueButtonEvent(liveMeeting.props.meetingProp.intId, SendRecordingTimerInternalMsg(liveMeeting.props.meetingProp.intId)))
|
||||
newState
|
||||
} else {
|
||||
state
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.domain.{ MeetingExpiryTracker, MeetingState2x }
|
||||
import org.bigbluebutton.common2.msgs.UserLeaveReqMsg
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models.Users2x
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, MeetingActor, OutMsgRouter }
|
||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||
import org.bigbluebutton.core.util.TimeUtil
|
||||
import org.bigbluebutton.core2.MeetingStatus2x
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
|
||||
trait UserLeaveReqMsgHdlr {
|
||||
@ -20,7 +19,7 @@ trait UserLeaveReqMsgHdlr {
|
||||
log.info("User left meeting. meetingId=" + props.meetingProp.intId + " userId=" + u.intId + " user=" + u)
|
||||
|
||||
captionApp2x.handleUserLeavingMsg(msg.body.userId)
|
||||
stopAutoStartedRecording()
|
||||
stopRecordingIfAutoStart2x(outGW, liveMeeting, state)
|
||||
|
||||
// send a user left event for the clients to update
|
||||
val userLeftMeetingEvent = MsgBuilder.buildUserLeftMeetingEvtMsg(liveMeeting.props.meetingProp.intId, u.intId)
|
||||
|
@ -19,6 +19,8 @@ class UsersApp(
|
||||
with LogoutAndEndMeetingCmdMsgHdlr
|
||||
with MeetingActivityResponseCmdMsgHdlr
|
||||
with SetRecordingStatusCmdMsgHdlr
|
||||
with RecordAndClearPreviousMarkersCmdMsgHdlr
|
||||
with SendRecordingTimerInternalMsgHdlr
|
||||
with UpdateWebcamsOnlyForModeratorCmdMsgHdlr
|
||||
with GetRecordingStatusReqMsgHdlr
|
||||
with GetWebcamsOnlyForModeratorReqMsgHdlr
|
||||
|
@ -1,7 +1,5 @@
|
||||
package org.bigbluebutton.core.domain
|
||||
|
||||
import org.bigbluebutton.core.util.TimeUtil
|
||||
|
||||
case class MeetingInactivityTracker(
|
||||
val maxInactivityTimeoutInMs: Long,
|
||||
val warningBeforeMaxInMs: Long,
|
||||
@ -93,3 +91,31 @@ case class MeetingExpiryTracker(
|
||||
}
|
||||
}
|
||||
|
||||
case class MeetingRecordingTracker(
|
||||
startedOnInMs: Long,
|
||||
previousDurationInMs: Long,
|
||||
currentDurationInMs: Long
|
||||
) {
|
||||
|
||||
def startTimer(nowInMs: Long): MeetingRecordingTracker = {
|
||||
copy(startedOnInMs = nowInMs)
|
||||
}
|
||||
|
||||
def pauseTimer(nowInMs: Long): MeetingRecordingTracker = {
|
||||
copy(currentDurationInMs = 0L, previousDurationInMs = previousDurationInMs + nowInMs - startedOnInMs, startedOnInMs = 0L)
|
||||
}
|
||||
|
||||
def resetTimer(nowInMs: Long): MeetingRecordingTracker = {
|
||||
copy(startedOnInMs = nowInMs, previousDurationInMs = 0L, currentDurationInMs = 0L)
|
||||
}
|
||||
|
||||
def udpateCurrentDuration(nowInMs: Long): MeetingRecordingTracker = {
|
||||
copy(currentDurationInMs = nowInMs - startedOnInMs)
|
||||
}
|
||||
|
||||
def recordingDuration(): Long = {
|
||||
currentDurationInMs + previousDurationInMs
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -9,12 +9,14 @@ object MeetingState2x {
|
||||
case class MeetingState2x(
|
||||
breakout: Option[BreakoutModel],
|
||||
inactivityTracker: MeetingInactivityTracker,
|
||||
expiryTracker: MeetingExpiryTracker
|
||||
expiryTracker: MeetingExpiryTracker,
|
||||
recordingTracker: MeetingRecordingTracker
|
||||
) {
|
||||
|
||||
def update(breakout: Option[BreakoutModel]) = copy(breakout = breakout)
|
||||
def update(expiry: MeetingExpiryTracker): MeetingState2x = copy(expiryTracker = expiry)
|
||||
def update(inactivityTracker: MeetingInactivityTracker): MeetingState2x = copy(inactivityTracker = inactivityTracker)
|
||||
def update(recordingTracker: MeetingRecordingTracker): MeetingState2x = copy(recordingTracker = recordingTracker)
|
||||
}
|
||||
|
||||
object MeetingEndReason {
|
||||
|
@ -238,6 +238,8 @@ class ReceivedJsonMsgHandlerActor(
|
||||
routeGenericMsg[LogoutAndEndMeetingCmdMsg](envelope, jsonNode)
|
||||
case SetRecordingStatusCmdMsg.NAME =>
|
||||
routeGenericMsg[SetRecordingStatusCmdMsg](envelope, jsonNode)
|
||||
case RecordAndClearPreviousMarkersCmdMsg.NAME =>
|
||||
routeGenericMsg[RecordAndClearPreviousMarkersCmdMsg](envelope, jsonNode)
|
||||
case GetRecordingStatusReqMsg.NAME =>
|
||||
routeGenericMsg[GetRecordingStatusReqMsg](envelope, jsonNode)
|
||||
case GetScreenshareStatusReqMsg.NAME =>
|
||||
|
@ -8,6 +8,7 @@ import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.models._
|
||||
import org.bigbluebutton.core2.MeetingStatus2x
|
||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, UserJoinedMeetingEvtMsgBuilder }
|
||||
import org.bigbluebutton.core.util.TimeUtil
|
||||
|
||||
trait HandlerHelpers extends SystemConfiguration {
|
||||
|
||||
@ -50,22 +51,25 @@ trait HandlerHelpers extends SystemConfiguration {
|
||||
|
||||
val event = UserJoinedMeetingEvtMsgBuilder.build(liveMeeting.props.meetingProp.intId, newUser)
|
||||
outGW.send(event)
|
||||
startRecordingIfAutoStart2x(outGW, liveMeeting)
|
||||
val newState = startRecordingIfAutoStart2x(outGW, liveMeeting, state)
|
||||
if (!Users2x.hasPresenter(liveMeeting.users2x)) {
|
||||
automaticallyAssignPresenter(outGW, liveMeeting)
|
||||
}
|
||||
state.update(state.expiryTracker.setUserHasJoined())
|
||||
newState.update(newState.expiryTracker.setUserHasJoined())
|
||||
case None =>
|
||||
state
|
||||
}
|
||||
}
|
||||
|
||||
def startRecordingIfAutoStart2x(outGW: OutMsgRouter, liveMeeting: LiveMeeting): Unit = {
|
||||
def startRecordingIfAutoStart2x(outGW: OutMsgRouter, liveMeeting: LiveMeeting, state: MeetingState2x): MeetingState2x = {
|
||||
var newState = state
|
||||
if (liveMeeting.props.recordProp.record && !MeetingStatus2x.isRecording(liveMeeting.status) &&
|
||||
liveMeeting.props.recordProp.autoStartRecording && Users2x.numUsers(liveMeeting.users2x) == 1) {
|
||||
|
||||
MeetingStatus2x.recordingStarted(liveMeeting.status)
|
||||
|
||||
val tracker = state.recordingTracker.startTimer(TimeUtil.timeNowInMs())
|
||||
|
||||
def buildRecordingStatusChangedEvtMsg(meetingId: String, userId: String, recording: Boolean): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
|
||||
val envelope = BbbCoreEnvelope(RecordingStatusChangedEvtMsg.NAME, routing)
|
||||
@ -81,8 +85,38 @@ trait HandlerHelpers extends SystemConfiguration {
|
||||
"system", MeetingStatus2x.isRecording(liveMeeting.status)
|
||||
)
|
||||
outGW.send(event)
|
||||
|
||||
newState = state.update(tracker)
|
||||
}
|
||||
newState
|
||||
}
|
||||
|
||||
def stopRecordingIfAutoStart2x(outGW: OutMsgRouter, liveMeeting: LiveMeeting, state: MeetingState2x): MeetingState2x = {
|
||||
var newState = state
|
||||
if (liveMeeting.props.recordProp.record && MeetingStatus2x.isRecording(liveMeeting.status) &&
|
||||
liveMeeting.props.recordProp.autoStartRecording && Users2x.numUsers(liveMeeting.users2x) == 0) {
|
||||
|
||||
MeetingStatus2x.recordingStopped(liveMeeting.status)
|
||||
|
||||
val tracker = state.recordingTracker.pauseTimer(TimeUtil.timeNowInMs())
|
||||
|
||||
def buildRecordingStatusChangedEvtMsg(meetingId: String, userId: String, recording: Boolean): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
|
||||
val envelope = BbbCoreEnvelope(RecordingStatusChangedEvtMsg.NAME, routing)
|
||||
val body = RecordingStatusChangedEvtMsgBody(recording, userId)
|
||||
val header = BbbClientMsgHeader(RecordingStatusChangedEvtMsg.NAME, meetingId, userId)
|
||||
val event = RecordingStatusChangedEvtMsg(header, body)
|
||||
|
||||
BbbCommonEnvCoreMsg(envelope, event)
|
||||
}
|
||||
|
||||
val event = buildRecordingStatusChangedEvtMsg(
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
"system", MeetingStatus2x.isRecording(liveMeeting.status)
|
||||
)
|
||||
outGW.send(event)
|
||||
newState = state.update(tracker)
|
||||
}
|
||||
newState
|
||||
}
|
||||
|
||||
def automaticallyAssignPresenter(outGW: OutMsgRouter, liveMeeting: LiveMeeting): Unit = {
|
||||
|
@ -4,9 +4,8 @@ import java.io.{ PrintWriter, StringWriter }
|
||||
|
||||
import org.bigbluebutton.core.apps.users._
|
||||
import org.bigbluebutton.core.apps.whiteboard.ClientToServerLatencyTracerMsgHdlr
|
||||
import org.bigbluebutton.core.domain.{ MeetingExpiryTracker, MeetingInactivityTracker, MeetingState2x }
|
||||
import org.bigbluebutton.core.domain.{ MeetingExpiryTracker, MeetingInactivityTracker, MeetingRecordingTracker, MeetingState2x }
|
||||
import org.bigbluebutton.core.util.TimeUtil
|
||||
//import java.util.concurrent.TimeUnit
|
||||
|
||||
import akka.actor._
|
||||
import akka.actor.SupervisorStrategy.Resume
|
||||
@ -127,7 +126,9 @@ class MeetingActor(
|
||||
meetingExpireWhenLastUserLeftInMs = TimeUtil.minutesToMillis(props.durationProps.meetingExpireWhenLastUserLeftInMinutes)
|
||||
)
|
||||
|
||||
var state = new MeetingState2x(None, inactivityTracker, expiryTracker)
|
||||
val recordingTracker = new MeetingRecordingTracker(startedOnInMs = 0L, previousDurationInMs = 0L, currentDurationInMs = 0L)
|
||||
|
||||
var state = new MeetingState2x(None, inactivityTracker, expiryTracker, recordingTracker)
|
||||
|
||||
var lastRttTestSentOn = System.currentTimeMillis()
|
||||
|
||||
@ -182,7 +183,10 @@ class MeetingActor(
|
||||
// Screenshare
|
||||
case msg: DeskShareGetDeskShareInfoRequest => handleDeskShareGetDeskShareInfoRequest(msg)
|
||||
|
||||
case _ => // do nothing
|
||||
case msg: SendRecordingTimerInternalMsg =>
|
||||
state = usersApp.handleSendRecordingTimerInternalMsg(msg, state)
|
||||
|
||||
case _ => // do nothing
|
||||
}
|
||||
|
||||
private def handleBbbCommonEnvCoreMsg(msg: BbbCommonEnvCoreMsg): Unit = {
|
||||
@ -206,8 +210,11 @@ class MeetingActor(
|
||||
case m: UserJoinedVoiceConfEvtMsg => handleUserJoinedVoiceConfEvtMsg(m)
|
||||
case m: MeetingActivityResponseCmdMsg =>
|
||||
state = usersApp.handleMeetingActivityResponseCmdMsg(m, state)
|
||||
case m: LogoutAndEndMeetingCmdMsg => usersApp.handleLogoutAndEndMeetingCmdMsg(m, state)
|
||||
case m: SetRecordingStatusCmdMsg => usersApp.handleSetRecordingStatusCmdMsg(m)
|
||||
case m: LogoutAndEndMeetingCmdMsg => usersApp.handleLogoutAndEndMeetingCmdMsg(m, state)
|
||||
case m: SetRecordingStatusCmdMsg =>
|
||||
state = usersApp.handleSetRecordingStatusCmdMsg(m, state)
|
||||
case m: RecordAndClearPreviousMarkersCmdMsg =>
|
||||
state = usersApp.handleRecordAndClearPreviousMarkersCmdMsg(m, state)
|
||||
case m: GetWebcamsOnlyForModeratorReqMsg => usersApp.handleGetWebcamsOnlyForModeratorReqMsg(m)
|
||||
case m: UpdateWebcamsOnlyForModeratorCmdMsg => usersApp.handleUpdateWebcamsOnlyForModeratorCmdMsg(m)
|
||||
case m: GetRecordingStatusReqMsg => usersApp.handleGetRecordingStatusReqMsg(m)
|
||||
@ -401,53 +408,4 @@ class MeetingActor(
|
||||
|
||||
}
|
||||
|
||||
def startRecordingIfAutoStart() {
|
||||
if (props.recordProp.record && !MeetingStatus2x.isRecording(liveMeeting.status) &&
|
||||
props.recordProp.autoStartRecording && Users2x.numUsers(liveMeeting.users2x) == 1) {
|
||||
|
||||
MeetingStatus2x.recordingStarted(liveMeeting.status)
|
||||
|
||||
def buildRecordingStatusChangedEvtMsg(meetingId: String, userId: String, recording: Boolean): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
|
||||
val envelope = BbbCoreEnvelope(RecordingStatusChangedEvtMsg.NAME, routing)
|
||||
val body = RecordingStatusChangedEvtMsgBody(recording, userId)
|
||||
val header = BbbClientMsgHeader(RecordingStatusChangedEvtMsg.NAME, meetingId, userId)
|
||||
val event = RecordingStatusChangedEvtMsg(header, body)
|
||||
|
||||
BbbCommonEnvCoreMsg(envelope, event)
|
||||
}
|
||||
|
||||
val event = buildRecordingStatusChangedEvtMsg(
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
"system", MeetingStatus2x.isRecording(liveMeeting.status)
|
||||
)
|
||||
outGW.send(event)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
def stopAutoStartedRecording() {
|
||||
if (props.recordProp.record && MeetingStatus2x.isRecording(liveMeeting.status) &&
|
||||
props.recordProp.autoStartRecording && Users2x.numUsers(liveMeeting.users2x) == 0) {
|
||||
log.info("Last web user left. Auto stopping recording. meetingId={}", props.meetingProp.intId)
|
||||
MeetingStatus2x.recordingStopped(liveMeeting.status)
|
||||
|
||||
def buildRecordingStatusChangedEvtMsg(meetingId: String, userId: String, recording: Boolean): BbbCommonEnvCoreMsg = {
|
||||
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
|
||||
val envelope = BbbCoreEnvelope(RecordingStatusChangedEvtMsg.NAME, routing)
|
||||
val body = RecordingStatusChangedEvtMsgBody(recording, userId)
|
||||
val header = BbbClientMsgHeader(RecordingStatusChangedEvtMsg.NAME, meetingId, userId)
|
||||
val event = RecordingStatusChangedEvtMsg(header, body)
|
||||
|
||||
BbbCommonEnvCoreMsg(envelope, event)
|
||||
}
|
||||
|
||||
val event = buildRecordingStatusChangedEvtMsg(
|
||||
liveMeeting.props.meetingProp.intId,
|
||||
"system", MeetingStatus2x.isRecording(liveMeeting.status)
|
||||
)
|
||||
outGW.send(event)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +78,11 @@ class MeetingActorAudit(
|
||||
props.meetingProp.intId,
|
||||
SendBreakoutUsersAuditInternalMsg(props.breakoutProps.parentId, props.meetingProp.intId)
|
||||
))
|
||||
|
||||
// Trigger recording timer, only for meeting allowing recording
|
||||
if (props.recordProp.record) {
|
||||
eventBus.publish(BigBlueButtonEvent(props.meetingProp.intId, SendRecordingTimerInternalMsg(props.meetingProp.intId)))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -74,6 +74,8 @@ class AnalyticsActor extends Actor with ActorLogging {
|
||||
case m: MeetingInactivityWarningEvtMsg => logMessage(msg)
|
||||
case m: StartRecordingVoiceConfSysMsg => logMessage(msg)
|
||||
case m: StopRecordingVoiceConfSysMsg => logMessage(msg)
|
||||
case m: UpdateRecordingTimerEvtMsg => logMessage(msg)
|
||||
case m: RecordAndClearPreviousMarkersCmdMsg => logMessage(msg)
|
||||
case m: TransferUserToVoiceConfSysMsg => logMessage(msg)
|
||||
case m: UserBroadcastCamStartMsg => logMessage(msg)
|
||||
case m: UserBroadcastCamStopMsg => logMessage(msg)
|
||||
|
@ -1,7 +1,7 @@
|
||||
package org.bigbluebutton.core2.message.handlers
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.api.{ SendBreakoutUsersAuditInternalMsg, SendTimeRemainingAuditInternalMsg }
|
||||
import org.bigbluebutton.core.api.SendTimeRemainingAuditInternalMsg
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
import org.bigbluebutton.core.util.TimeUtil
|
||||
|
@ -202,7 +202,6 @@ object MsgBuilder {
|
||||
val header = BbbClientMsgHeader(UserLeftMeetingEvtMsg.NAME, meetingId, userId)
|
||||
val body = UserLeftMeetingEvtMsgBody(userId)
|
||||
val event = UserLeftMeetingEvtMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
|
||||
BbbCommonEnvCoreMsg(envelope, event)
|
||||
}
|
||||
|
@ -92,6 +92,14 @@ object SetRecordingStatusCmdMsg { val NAME = "SetRecordingStatusCmdMsg" }
|
||||
case class SetRecordingStatusCmdMsg(header: BbbClientMsgHeader, body: SetRecordingStatusCmdMsgBody) extends StandardMsg
|
||||
case class SetRecordingStatusCmdMsgBody(recording: Boolean, setBy: String)
|
||||
|
||||
/**
|
||||
* Sent by user to start recording mark and ignore previsous marks
|
||||
*/
|
||||
object RecordAndClearPreviousMarkersCmdMsg { val NAME = "RecordAndClearPreviousMarkersCmdMsg" }
|
||||
case class RecordAndClearPreviousMarkersCmdMsg(header: BbbClientMsgHeader, body: RecordAndClearPreviousMarkersCmdMsgBody) extends StandardMsg
|
||||
case class RecordAndClearPreviousMarkersCmdMsgBody(recording: Boolean, setBy: String)
|
||||
|
||||
|
||||
/**
|
||||
* Sent to all users about start recording mark.
|
||||
*/
|
||||
@ -99,6 +107,10 @@ object RecordingStatusChangedEvtMsg { val NAME = "RecordingStatusChangedEvtMsg"
|
||||
case class RecordingStatusChangedEvtMsg(header: BbbClientMsgHeader, body: RecordingStatusChangedEvtMsgBody) extends BbbCoreMsg
|
||||
case class RecordingStatusChangedEvtMsgBody(recording: Boolean, setBy: String)
|
||||
|
||||
object UpdateRecordingTimerEvtMsg {val NAME = "UpdateRecordingTimerEvtMsg"}
|
||||
case class UpdateRecordingTimerEvtMsg(header: BbbClientMsgHeader, body: UpdateRecordingTimerEvtMsgBody) extends BbbCoreMsg
|
||||
case class UpdateRecordingTimerEvtMsgBody(time: Long)
|
||||
|
||||
/**
|
||||
* Sent by user to update webcamsOnlyForModerator meeting property.
|
||||
*/
|
||||
|
@ -114,9 +114,6 @@ bbb.mainToolbar.recordBtn.toolTip.notRecording = The session isn't being recorde
|
||||
bbb.mainToolbar.recordBtn.toolTip.onlyModerators = Only moderators can start and stop recordings
|
||||
bbb.mainToolbar.recordBtn.toolTip.wontInterrupt = This recording can't be interrupted
|
||||
bbb.mainToolbar.recordBtn.toolTip.wontRecord = This session cannot be recorded
|
||||
bbb.mainToolbar.recordBtn.confirm.title = Confirm recording
|
||||
bbb.mainToolbar.recordBtn.confirm.message.start = Are you sure you want to start recording the session?
|
||||
bbb.mainToolbar.recordBtn.confirm.message.stop = Are you sure you want to stop recording the session?
|
||||
bbb.mainToolbar.recordBtn.notification.title = Record Notification
|
||||
bbb.mainToolbar.recordBtn.notification.message1 = You can record this meeting.
|
||||
bbb.mainToolbar.recordBtn.notification.message2 = You must click the Start/Stop Recording button in the title bar to begin/end recording.
|
||||
@ -124,6 +121,11 @@ bbb.mainToolbar.recordingLabel.recording = (Recording)
|
||||
bbb.mainToolbar.recordingLabel.notRecording = Not Recording
|
||||
bbb.waitWindow.waitMessage.message = You are a guest, please wait moderator approval.
|
||||
bbb.waitWindow.waitMessage.title = Waiting
|
||||
bbb.recordWindow.title.start = Start recording
|
||||
bbb.recordWindow.title.stop = Stop recording
|
||||
bbb.recordWindow.confirm.yes = Yes
|
||||
bbb.recordWindow.confirm.no = No
|
||||
bbb.recordWindow.clearCheckbox.label = Clear all previous recording marks
|
||||
bbb.guests.title = Guests
|
||||
bbb.guests.message.singular = {0} user wants to join this meeting
|
||||
bbb.guests.message.plural = {0} users want to join this meeting
|
||||
|
@ -21,17 +21,19 @@ package org.bigbluebutton.core {
|
||||
import flash.events.TimerEvent;
|
||||
import flash.utils.Dictionary;
|
||||
import flash.utils.Timer;
|
||||
|
||||
|
||||
import mx.controls.Alert;
|
||||
import mx.controls.Label;
|
||||
import mx.managers.PopUpManager;
|
||||
|
||||
import org.bigbluebutton.util.i18n.ResourceUtil;
|
||||
|
||||
import org.bigbluebutton.util.i18n.ResourceUtil;
|
||||
|
||||
public final class TimerUtil {
|
||||
public static var timers:Dictionary = new Dictionary(true);
|
||||
private static var timers:Dictionary = new Dictionary(true);
|
||||
|
||||
public static function setCountDownTimer(label:Label, seconds:int, showMinuteWarning:Boolean=false):void {
|
||||
private static var times:Dictionary = new Dictionary(true);
|
||||
|
||||
public static function setCountDownTimer(label:Label, seconds:int, showMinuteWarning:Boolean = false):void {
|
||||
var timer:Timer = getTimer(label.id, seconds);
|
||||
var minuteWarningShown:Boolean = false;
|
||||
var minuteAlert:Alert = null;
|
||||
@ -58,6 +60,23 @@ package org.bigbluebutton.core {
|
||||
timer.start();
|
||||
}
|
||||
|
||||
public static function setTimer(label:Label, seconds:int, running:Boolean):void {
|
||||
var timer:Timer = getTimer(label.id, seconds);
|
||||
if (!timer.hasEventListener(TimerEvent.TIMER)) {
|
||||
timer.addEventListener(TimerEvent.TIMER, function():void {
|
||||
var elapsedSeconds:int = times[timer] + timer.currentCount;
|
||||
var formattedTime:String = (Math.floor(elapsedSeconds / 60)) + ":" + (elapsedSeconds % 60 >= 10 ? "" : "0") + (elapsedSeconds % 60);
|
||||
label.text = formattedTime;
|
||||
});
|
||||
}
|
||||
times[timer] = seconds - timer.currentCount;
|
||||
if (running) {
|
||||
timer.start();
|
||||
} else {
|
||||
timer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public static function getTimer(name:String, defaultRepeatCount:Number):Timer {
|
||||
if (timers[name] == undefined) {
|
||||
timers[name] = new Timer(1000, defaultRepeatCount);
|
||||
|
@ -0,0 +1,15 @@
|
||||
package org.bigbluebutton.core.events {
|
||||
import flash.events.Event;
|
||||
|
||||
public class UpdateRecordingTimerEvent extends Event {
|
||||
|
||||
public static const UPDATE_TIMER:String = "UPDATE_TIMER";
|
||||
|
||||
public var time:int;
|
||||
|
||||
public function UpdateRecordingTimerEvent(time:int) {
|
||||
super(UPDATE_TIMER, false, false);
|
||||
this.time = time;
|
||||
}
|
||||
}
|
||||
}
|
@ -47,11 +47,14 @@ package org.bigbluebutton.main.events {
|
||||
public static const MIC_SETTINGS_CLOSED:String = "MIC_SETTINGS_CLOSED";
|
||||
public static const CAM_SETTINGS_CLOSED:String = "CAM_SETTINGS_CLOSED";
|
||||
public static const JOIN_VOICE_FOCUS_HEAD:String = "JOIN_VOICE_FOCUS_HEAD";
|
||||
public static const RECORD_AND_CLEAR_PREVIOUS_MARKERS:String = "RECORD_AND_CLEAR_PREVIOUS_MARKERS";
|
||||
public static const CHANGE_RECORDING_STATUS:String = "CHANGE_RECORDING_STATUS";
|
||||
public static const CHANGE_WEBCAMS_ONLY_FOR_MODERATOR:String = "CHANGE_WEBCAMS_ONLY_FOR_MODERATOR";
|
||||
|
||||
public static const SETTINGS_CONFIRMED:String = "BBB_SETTINGS_CONFIRMED";
|
||||
public static const SETTINGS_CANCELLED:String = "BBB_SETTINGS_CANCELLED";
|
||||
|
||||
public static const OPEN_RECORD_WINDOW : String = "OPEN_RECORD_WINDOW";
|
||||
|
||||
public static const ACCEPT_ALL_WAITING_GUESTS:String = "BBB_ACCEPT_ALL_WAITING_GUESTS";
|
||||
public static const DENY_ALL_WAITING_GUESTS:String = "BBB_DENY_ALL_WAITING_GUESTS";
|
||||
|
@ -192,6 +192,12 @@ package org.bigbluebutton.main.model.users
|
||||
}
|
||||
}
|
||||
|
||||
public function recordAndClearPreviousMarkers(e:BBBEvent):void {
|
||||
if (this.isModerator() && !e.payload.remote) {
|
||||
sender.recordAndClearPreviousMarkers(UsersUtil.getMyUserID(), e.payload.recording);
|
||||
}
|
||||
}
|
||||
|
||||
public function userLoggedIn(e:UsersConnectionEvent):void {
|
||||
LOGGER.debug("In userLoggedIn - reconnecting and allowed to join");
|
||||
if (reconnecting && ! LiveMeeting.inst().me.waitingForApproval) {
|
||||
|
@ -86,6 +86,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<mate:Listener type="{BBBEvent.RECONNECT_DISCONNECTED_EVENT}" method="closeWaitWindow"/>
|
||||
<mate:Listener type="{RoundTripLatencyReceivedEvent.ROUND_TRIP_LATENCY_RECEIVED}" method="handleRoundTripLatencyReceivedEvent"/>
|
||||
<mate:Listener type="{ConferenceCreatedEvent.CONFERENCE_CREATED_EVENT}" method="handleConferenceCreatedEvent" />
|
||||
|
||||
<mate:Listener type="{BBBEvent.OPEN_RECORD_WINDOW}" method="handleOpenRecordWindowEvent" />
|
||||
|
||||
</fx:Declarations>
|
||||
<fx:Script>
|
||||
@ -99,8 +101,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
import flash.net.navigateToURL;
|
||||
import flash.utils.setTimeout;
|
||||
|
||||
import flexlib.mdi.effects.effectsLib.MDIVistaEffects;
|
||||
|
||||
import mx.binding.utils.ChangeWatcher;
|
||||
import mx.collections.ArrayCollection;
|
||||
import mx.controls.Alert;
|
||||
@ -109,6 +109,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
import mx.core.UIComponent;
|
||||
import mx.events.FlexEvent;
|
||||
|
||||
import flexlib.mdi.effects.effectsLib.MDIVistaEffects;
|
||||
|
||||
import org.as3commons.lang.StringUtils;
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
@ -850,6 +852,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
}
|
||||
}
|
||||
|
||||
private function handleOpenRecordWindowEvent(e:BBBEvent):void {
|
||||
var popUp:RecordWindow = PopUpUtil.createModalPopUp(FlexGlobals.topLevelApplication as DisplayObject, RecordWindow, true) as RecordWindow;
|
||||
popUp.setRecordingFlag(e.payload.recording);
|
||||
}
|
||||
|
||||
private function onFooterLinkClicked(e:TextEvent):void{
|
||||
if (ExternalInterface.available) {
|
||||
ExternalInterface.call("chatLinkClicked", e.text);
|
||||
|
@ -47,10 +47,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<mate:Listener type="{SettingsComponentEvent.ADD}" method="addSettingsComponent" />
|
||||
<mate:Listener type="{SettingsComponentEvent.REMOVE}" method="removeSettingsComponent"/>
|
||||
<mate:Listener type="{BBBEvent.CHANGE_RECORDING_STATUS}" method="onRecordingStatusChanged" />
|
||||
<mate:Listener type="{BBBEvent.RECORD_AND_CLEAR_PREVIOUS_MARKERS}" method="onRecordAndClearPreviousMarkersChanged" />
|
||||
<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="{MeetingTimeRemainingEvent.TIME_REMAINING}" method="handleRemainingTimeUpdate" />
|
||||
<mate:Listener type="{UpdateRecordingTimerEvent.UPDATE_TIMER}" method="handleUpdateRecordingTimer" />
|
||||
</fx:Declarations>
|
||||
<fx:Script>
|
||||
<![CDATA[
|
||||
@ -79,6 +81,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
import org.bigbluebutton.core.TimerUtil;
|
||||
import org.bigbluebutton.core.UsersUtil;
|
||||
import org.bigbluebutton.core.events.MeetingTimeRemainingEvent;
|
||||
import org.bigbluebutton.core.events.UpdateRecordingTimerEvent;
|
||||
import org.bigbluebutton.core.model.Config;
|
||||
import org.bigbluebutton.core.model.LiveMeeting;
|
||||
import org.bigbluebutton.main.events.BBBEvent;
|
||||
@ -196,6 +199,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
initBandwidthToolTip();
|
||||
}
|
||||
}
|
||||
|
||||
private function handleRemainingTimeUpdate(e:MeetingTimeRemainingEvent):void {
|
||||
// Display timer only if there is less than 30 minutes remaining
|
||||
if (!timeRemaining.visible && e.timeLeftInSec <= 1800) {
|
||||
@ -203,6 +207,15 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
}
|
||||
TimerUtil.setCountDownTimer(timeRemaining, e.timeLeftInSec, true);
|
||||
}
|
||||
|
||||
private function handleUpdateRecordingTimer(e:UpdateRecordingTimerEvent):void {
|
||||
if (e.time == 0) {
|
||||
recordingTimer.visible = false;
|
||||
} else {
|
||||
recordingTimer.visible = true;
|
||||
TimerUtil.setTimer(recordingTimer, e.time, LiveMeeting.inst().meetingStatus.isRecording);
|
||||
}
|
||||
}
|
||||
|
||||
private function retrieveMeetingName(e:ConferenceCreatedEvent):void {
|
||||
if (toolbarOptions.showMeetingName) {
|
||||
@ -476,21 +489,27 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
private function focusLogoutButton(e:ShortcutEvent):void{
|
||||
btnLogout.setFocus();
|
||||
}
|
||||
|
||||
private function onRecordingStatusChanged(event:BBBEvent):void {
|
||||
meetingNameLbl.text = "";
|
||||
|
||||
if (event.payload.recording) {
|
||||
meetingNameLbl.text = ResourceUtil.getInstance().getString('bbb.mainToolbar.recordingLabel.recording')
|
||||
}
|
||||
|
||||
if (toolbarOptions.showMeetingName) {
|
||||
var meetingTitle:String = LiveMeeting.inst().meeting.name;
|
||||
if (meetingTitle != null) {
|
||||
meetingNameLbl.text += " " + meetingTitle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function onRecordingStatusChanged(event:BBBEvent):void {
|
||||
|
||||
if (event.payload.recording) {
|
||||
meetingNameLbl.text = ResourceUtil.getInstance().getString('bbb.mainToolbar.recordingLabel.recording')
|
||||
} else {
|
||||
meetingNameLbl.text = "";
|
||||
TimerUtil.stopTimer(recordingTimer.id);
|
||||
}
|
||||
|
||||
if (toolbarOptions.showMeetingName) {
|
||||
var meetingTitle:String = LiveMeeting.inst().meeting.name;
|
||||
if (meetingTitle != null) {
|
||||
meetingNameLbl.text += " " + meetingTitle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function onRecordAndClearPreviousMarkersChanged(event:BBBEvent):void {
|
||||
recordingTimer.visible = false;
|
||||
}
|
||||
|
||||
private function onNetStatsButtonClick(e:Event = null):void {
|
||||
var d:Dispatcher = new Dispatcher();
|
||||
@ -582,6 +601,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<mx:HBox id="addedBtnsDeskShare" />
|
||||
</mx:HBox>
|
||||
<mx:HBox id="rightBox" width="40%" height="100%" horizontalAlign="right" verticalAlign="middle" horizontalScrollPolicy="off">
|
||||
<mx:Label id="recordingTimer" visible="false" includeInLayout="{recordingTimer.visible}"/>
|
||||
<views:RecordButton id="recordBtn" visible="{showRecordButton}" includeInLayout="{showRecordButton}"/>
|
||||
<views:WebRTCAudioStatus id="webRTCAudioStatus" height="30"/>
|
||||
|
||||
|
@ -44,14 +44,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<![CDATA[
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
|
||||
import flash.net.navigateToURL;
|
||||
|
||||
import mx.controls.Alert;
|
||||
import mx.events.CloseEvent;
|
||||
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
import org.bigbluebutton.core.BBB;
|
||||
import org.bigbluebutton.core.Options;
|
||||
import org.bigbluebutton.core.PopUpUtil;
|
||||
import org.bigbluebutton.core.UsersUtil;
|
||||
@ -65,74 +61,19 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
private static const LOGGER:ILogger = getClassLogger(RecordButton);
|
||||
|
||||
private var recordingFlag:Boolean;
|
||||
private var firstAudioJoin:Boolean = true;
|
||||
private var layoutOptions:LayoutOptions = null;
|
||||
private var _confirmationAlert:Alert = null;
|
||||
|
||||
private function onCreationComplete():void {
|
||||
ResourceUtil.getInstance().addEventListener(Event.CHANGE, localeChanged); // Listen for locale changing
|
||||
}
|
||||
|
||||
private function hideConfirmationAlert():void {
|
||||
if (_confirmationAlert != null) {
|
||||
PopUpUtil.unlockPosition(_confirmationAlert);
|
||||
_confirmationAlert = null;
|
||||
}
|
||||
}
|
||||
|
||||
private function showConfirmationAlert():void {
|
||||
hideConfirmationAlert();
|
||||
|
||||
var message:String = recordingFlag? ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.confirm.message.start'): ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.confirm.message.stop');
|
||||
|
||||
// Confirm logout using built-in alert
|
||||
_confirmationAlert = Alert.show(message, ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.confirm.title'), Alert.YES | Alert.NO, this, onCloseConfirmationDialog, null, Alert.YES);
|
||||
|
||||
PopUpUtil.lockPosition(_confirmationAlert, function():Point {
|
||||
return new Point(parentApplication.width - 150 - _confirmationAlert.width, y + height + 5);
|
||||
});
|
||||
}
|
||||
|
||||
private function confirmChangeRecordingStatus():void {
|
||||
LOGGER.debug("Confirming recording status change!!!!");
|
||||
|
||||
// need to save the flag in case of any remote update on the recording status
|
||||
recordingFlag = !this.selected;
|
||||
|
||||
showConfirmationAlert();
|
||||
}
|
||||
|
||||
private function onCloseConfirmationDialog(e:CloseEvent):void {
|
||||
// check to see if the YES button was pressed
|
||||
if (e.detail==Alert.YES) {
|
||||
doChangeRecordingStatus();
|
||||
}
|
||||
|
||||
hideConfirmationAlert();
|
||||
}
|
||||
|
||||
private function doChangeRecordingStatus():void {
|
||||
if (recordingFlag == this.selected) {
|
||||
// while the user was confirming the recording change, the
|
||||
// button state changed to the desired one (another user started
|
||||
// or stopped to record), so we do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
var event:BBBEvent = new BBBEvent(BBBEvent.CHANGE_RECORDING_STATUS);
|
||||
var event:BBBEvent = new BBBEvent(BBBEvent.OPEN_RECORD_WINDOW);
|
||||
event.payload.remote = false;
|
||||
event.payload.recording = recordingFlag;
|
||||
event.payload.recording = !LiveMeeting.inst().meetingStatus.isRecording;
|
||||
var d:Dispatcher = new Dispatcher();
|
||||
d.dispatchEvent(event);
|
||||
|
||||
this.enabled = false;
|
||||
LOGGER.debug("RecordButton:doChangeRecordingStatus changing record status to {0}", [event.payload.recording]);
|
||||
|
||||
if (!recordingFlag && getLayoutOptions().logoutOnStopRecording) {
|
||||
LOGGER.debug("Using 'logoutOnStopRecording' option to logout user after stopping recording");
|
||||
navigateToURL(new URLRequest(BBB.getLogoutURL()), "_self");
|
||||
}
|
||||
}
|
||||
|
||||
private function updateButton(recording:Boolean):void {
|
||||
@ -144,9 +85,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
this.enabled = UsersUtil.amIModerator()
|
||||
&& LiveMeeting.inst().meeting.allowStartStopRecording;
|
||||
}
|
||||
|
||||
if (! this.enabled) {
|
||||
hideConfirmationAlert();
|
||||
|
||||
if (!this.enabled) {
|
||||
PopUpUtil.removePopUp(RecordWindow);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<mx:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009"
|
||||
xmlns:s="library://ns.adobe.com/flex/spark"
|
||||
xmlns:mx="library://ns.adobe.com/flex/mx"
|
||||
implements="org.bigbluebutton.common.IKeyboardClose"
|
||||
xmlns:common="org.bigbluebutton.common.*"
|
||||
showCloseButton="false"
|
||||
layout="absolute"
|
||||
show="this.setFocus()">
|
||||
|
||||
<fx:Script>
|
||||
<![CDATA[
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
|
||||
import flash.net.navigateToURL;
|
||||
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
import org.bigbluebutton.core.BBB;
|
||||
import org.bigbluebutton.core.Options;
|
||||
import org.bigbluebutton.core.PopUpUtil;
|
||||
import org.bigbluebutton.core.model.LiveMeeting;
|
||||
import org.bigbluebutton.main.events.BBBEvent;
|
||||
import org.bigbluebutton.main.model.options.LayoutOptions;
|
||||
import org.bigbluebutton.util.i18n.ResourceUtil;
|
||||
|
||||
private static const LOGGER:ILogger = getClassLogger(RecordWindow);
|
||||
|
||||
[Bindable]
|
||||
private var _recordingFlag : Boolean;
|
||||
|
||||
private var layoutOptions:LayoutOptions = null;
|
||||
|
||||
public function setRecordingFlag(recording : Boolean):void {
|
||||
_recordingFlag = recording;
|
||||
}
|
||||
|
||||
private function getLayoutOptions() : LayoutOptions {
|
||||
if (layoutOptions == null) {
|
||||
layoutOptions = Options.getOptions(LayoutOptions) as LayoutOptions;
|
||||
}
|
||||
return layoutOptions;
|
||||
}
|
||||
|
||||
protected function yesButton_clickHandler(e:MouseEvent):void {
|
||||
if (_recordingFlag == LiveMeeting.inst().meetingStatus.isRecording) {
|
||||
// while the user was confirming the recording change, the
|
||||
// button state changed to the desired one (another user started
|
||||
// or stopped to record), so we do nothing
|
||||
close();
|
||||
}
|
||||
|
||||
var event:BBBEvent;
|
||||
if (_recordingFlag && clearRecordingsChecbox.selected) {
|
||||
event = new BBBEvent(BBBEvent.RECORD_AND_CLEAR_PREVIOUS_MARKERS);
|
||||
} else {
|
||||
event = new BBBEvent(BBBEvent.CHANGE_RECORDING_STATUS);
|
||||
}
|
||||
event.payload.remote = false;
|
||||
event.payload.recording = _recordingFlag;
|
||||
var d:Dispatcher = new Dispatcher();
|
||||
d.dispatchEvent(event);
|
||||
|
||||
LOGGER.debug("Changing record status to {0}", [event.payload.recording]);
|
||||
|
||||
if (!_recordingFlag && getLayoutOptions().logoutOnStopRecording) {
|
||||
LOGGER.debug("Using 'logoutOnStopRecording' option to logout user after stopping recording");
|
||||
navigateToURL(new URLRequest(BBB.getLogoutURL()), "_self");
|
||||
}
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
protected function close():void {
|
||||
PopUpUtil.removePopUp(this);
|
||||
}
|
||||
|
||||
]]>
|
||||
</fx:Script>
|
||||
|
||||
<mx:VBox width="100%" height="100%" paddingBottom="25" paddingLeft="70" paddingRight="70" paddingTop="25"
|
||||
horizontalAlign="center" verticalGap="16">
|
||||
<common:AdvancedLabel maxWidth="550"
|
||||
id="textArea"
|
||||
text="{_recordingFlag ? ResourceUtil.getInstance().getString('bbb.recordWindow.title.start') : ResourceUtil.getInstance().getString('bbb.recordWindow.title.stop')}"
|
||||
styleName="titleWindowStyle" />
|
||||
|
||||
<mx:HBox horizontalAlign="center" width="100%">
|
||||
<mx:Button id="yesButton" styleName="mainActionButton" click="yesButton_clickHandler(event)" label="{ResourceUtil.getInstance().getString('bbb.recordWindow.confirm.yes')}" width="120"/>
|
||||
<mx:Button id="noButton" styleName="mainActionButton" click="close()" label="{ResourceUtil.getInstance().getString('bbb.recordWindow.confirm.no')}" width="102"/>
|
||||
</mx:HBox>
|
||||
|
||||
<mx:CheckBox id="clearRecordingsChecbox" label="{ResourceUtil.getInstance().getString('bbb.recordWindow.clearCheckbox.label')}"
|
||||
visible="{_recordingFlag}" includeInLayout="{_recordingFlag}"/>
|
||||
</mx:VBox>
|
||||
|
||||
<mx:Button id="closeButton" click="close()" styleName="titleWindowCloseButton"
|
||||
toolTip="{ResourceUtil.getInstance().getString('bbb.micSettings.cancel')}"
|
||||
right="10" top="15"
|
||||
accessibilityName="{ResourceUtil.getInstance().getString('bbb.micSettings.cancel.toolTip')}" />
|
||||
|
||||
</mx:TitleWindow>
|
@ -109,7 +109,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<EventHandlers type="{BBBEvent.CHANGE_RECORDING_STATUS}">
|
||||
<MethodInvoker generator="{UserService}" method="changeRecordingStatus" arguments="{event}" />
|
||||
</EventHandlers>
|
||||
|
||||
|
||||
<EventHandlers type="{BBBEvent.RECORD_AND_CLEAR_PREVIOUS_MARKERS}">
|
||||
<MethodInvoker generator="{UserService}" method="recordAndClearPreviousMarkers" arguments="{event}" />
|
||||
</EventHandlers>
|
||||
|
||||
<EventHandlers type="{BBBEvent.ACTIVITY_RESPONSE_EVENT}">
|
||||
<MethodInvoker generator="{UserService}" method="activityResponse" />
|
||||
</EventHandlers>
|
||||
|
@ -31,6 +31,7 @@ package org.bigbluebutton.modules.users.services
|
||||
import org.bigbluebutton.core.events.CoreEvent;
|
||||
import org.bigbluebutton.core.events.MeetingTimeRemainingEvent;
|
||||
import org.bigbluebutton.core.events.NewGuestWaitingEvent;
|
||||
import org.bigbluebutton.core.events.UpdateRecordingTimerEvent;
|
||||
import org.bigbluebutton.core.events.UserEmojiChangedEvent;
|
||||
import org.bigbluebutton.core.events.UserStatusChangedEvent;
|
||||
import org.bigbluebutton.core.model.LiveMeeting;
|
||||
@ -135,6 +136,9 @@ package org.bigbluebutton.modules.users.services
|
||||
case "UserEmojiChangedEvtMsg":
|
||||
handleEmojiStatusHand(message);
|
||||
break;
|
||||
case "UpdateRecordingTimerEvtMsg":
|
||||
handleUpdateRecordingTimer(message);
|
||||
break;
|
||||
case "GetRecordingStatusRespMsg":
|
||||
handleGetRecordingStatusReply(message);
|
||||
break;
|
||||
@ -710,6 +714,11 @@ package org.bigbluebutton.modules.users.services
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function handleUpdateRecordingTimer(msg:Object):void {
|
||||
var e:UpdateRecordingTimerEvent = new UpdateRecordingTimerEvent(msg.body.time);
|
||||
dispatcher.dispatchEvent(e);
|
||||
}
|
||||
|
||||
private function sendUserEmojiChangedEvent(userId: String, emoji: String):void{
|
||||
var dispatcher:Dispatcher = new Dispatcher();
|
||||
|
@ -329,6 +329,27 @@ package org.bigbluebutton.modules.users.services
|
||||
); //_netConnection.call
|
||||
}
|
||||
|
||||
public function recordAndClearPreviousMarkers(userID:String, recording:Boolean):void {
|
||||
var message:Object = {
|
||||
header: {name: "RecordAndClearPreviousMarkersCmdMsg", meetingId: UsersUtil.getInternalMeetingID(),
|
||||
userId: UsersUtil.getMyUserID()},
|
||||
body: {recording: recording, setBy: userID}
|
||||
};
|
||||
|
||||
var _nc:ConnectionManager = BBB.initConnectionManager();
|
||||
_nc.sendMessage2x(
|
||||
function(result:String):void { // On successful result
|
||||
},
|
||||
function(status:String):void { // status - On error occurred
|
||||
var logData:Object = UsersUtil.initLogData();
|
||||
logData.tags = ["apps"];
|
||||
logData.logCode = "error_sending_change_recording_status";
|
||||
LOGGER.info(JSON.stringify(logData));
|
||||
},
|
||||
JSON.stringify(message)
|
||||
); //_netConnection.call
|
||||
}
|
||||
|
||||
public function muteAllUsers(mute:Boolean):void {
|
||||
var message:Object = {
|
||||
header: {name: "MuteMeetingCmdMsg", meetingId: UsersUtil.getInternalMeetingID(),
|
||||
|
Loading…
Reference in New Issue
Block a user