diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/meeting/ValidateConnAuthTokenSysMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/meeting/ValidateConnAuthTokenSysMsgHdlr.scala
new file mode 100755
index 0000000000000000000000000000000000000000..1b0ac7a6a1c202273f84222037037c96baef20df
--- /dev/null
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/meeting/ValidateConnAuthTokenSysMsgHdlr.scala
@@ -0,0 +1,30 @@
+package org.bigbluebutton.core.apps.meeting
+
+import org.bigbluebutton.common2.msgs.ValidateConnAuthTokenSysMsg
+import org.bigbluebutton.core.models.RegisteredUsers
+import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
+import org.bigbluebutton.core2.message.senders.MsgBuilder
+
+trait ValidateConnAuthTokenSysMsgHdlr {
+  val liveMeeting: LiveMeeting
+  val outGW: OutMsgRouter
+
+  def handleValidateConnAuthTokenSysMsg(msg: ValidateConnAuthTokenSysMsg): Unit = {
+    val regUser = RegisteredUsers.getRegisteredUserWithToken(
+      msg.body.authToken,
+      msg.body.userId,
+      liveMeeting.registeredUsers
+    )
+
+    regUser match {
+      case Some(u) =>
+        val event = MsgBuilder.buildValidateConnAuthTokenSysRespMsg(msg.body.meetingId, msg.body.userId,
+          msg.body.authToken, true, msg.body.conn)
+        outGW.send(event)
+      case None =>
+        val event = MsgBuilder.buildValidateConnAuthTokenSysRespMsg(msg.body.meetingId, msg.body.userId,
+          msg.body.authToken, false, msg.body.conn)
+        outGW.send(event)
+    }
+  }
+}
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/CreateNewPresentationPodPubMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/CreateNewPresentationPodPubMsgHdlr.scala
old mode 100644
new mode 100755
index 54af514c2e0214acf8d60966e74289ded740ffab..1b3b3f73ef8c61cb99ef9c901292edaa8ddfa718
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/CreateNewPresentationPodPubMsgHdlr.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/CreateNewPresentationPodPubMsgHdlr.scala
@@ -1,53 +1,59 @@
 package org.bigbluebutton.core.apps.presentationpod
 
+import org.bigbluebutton.SystemConfiguration
 import org.bigbluebutton.common2.msgs._
+import org.bigbluebutton.core.apps.PermissionCheck
 import org.bigbluebutton.core.bus.MessageBus
 import org.bigbluebutton.core.domain.MeetingState2x
 import org.bigbluebutton.core.models.PresentationPod
 import org.bigbluebutton.core.running.LiveMeeting
 
-trait CreateNewPresentationPodPubMsgHdlr {
+trait CreateNewPresentationPodPubMsgHdlr extends SystemConfiguration {
   this: PresentationPodHdlrs =>
 
   def handle(msg: CreateNewPresentationPodPubMsg, state: MeetingState2x,
              liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
 
-    def buildCreateNewPresentationPodEvtMsg(meetingId: String, ownerId: String, podId: String): BbbCommonEnvCoreMsg = {
-      val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, ownerId)
-      val envelope = BbbCoreEnvelope(CreateNewPresentationPodEvtMsg.NAME, routing)
-      val header = BbbClientMsgHeader(CreateNewPresentationPodEvtMsg.NAME, meetingId, ownerId)
-
-      val body = CreateNewPresentationPodEvtMsgBody(ownerId, podId)
-      val event = CreateNewPresentationPodEvtMsg(header, body)
-
-      BbbCommonEnvCoreMsg(envelope, event)
-    }
+    if (applyPermissionCheck && !PermissionCheck.isAllowed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
+      val meetingId = liveMeeting.props.meetingProp.intId
+      val reason = "No permission to eject user from meeting."
+      PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW)
+      state
+    } else {
+      def buildCreateNewPresentationPodEvtMsg(meetingId: String, ownerId: String, podId: String): BbbCommonEnvCoreMsg = {
+        val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, ownerId)
+        val envelope = BbbCoreEnvelope(CreateNewPresentationPodEvtMsg.NAME, routing)
+        val header = BbbClientMsgHeader(CreateNewPresentationPodEvtMsg.NAME, meetingId, ownerId)
+
+        val body = CreateNewPresentationPodEvtMsgBody(ownerId, podId)
+        val event = CreateNewPresentationPodEvtMsg(header, body)
+
+        BbbCommonEnvCoreMsg(envelope, event)
+      }
 
-    val ownerId = msg.body.ownerId
+      val ownerId = msg.body.ownerId
 
-    val resultPod: PresentationPod = PresentationPodsApp.getPresentationPod(state, "DEFAULT_PRESENTATION_POD") match {
-      case None => PresentationPodsApp.createDefaultPresentationPod(ownerId)
-      case Some(pod) => {
-        if (pod.ownerId == "") {
-          PresentationPodsApp.changeOwnershipOfDefaultPod(state, ownerId).get
-        } else {
-          PresentationPodsApp.createPresentationPod(ownerId)
+      val resultPod: PresentationPod = PresentationPodsApp.getPresentationPod(state, "DEFAULT_PRESENTATION_POD") match {
+        case None => PresentationPodsApp.createDefaultPresentationPod(ownerId)
+        case Some(pod) => {
+          if (pod.ownerId == "") {
+            PresentationPodsApp.changeOwnershipOfDefaultPod(state, ownerId).get
+          } else {
+            PresentationPodsApp.createPresentationPod(ownerId)
+          }
         }
       }
-    }
-
-    val respMsg = buildCreateNewPresentationPodEvtMsg(
-      liveMeeting.props.meetingProp.intId,
-      ownerId, resultPod.id
-    )
-    bus.outGW.send(respMsg)
 
-    val pods = state.presentationPodManager.addPod(resultPod)
+      val respMsg = buildCreateNewPresentationPodEvtMsg(
+        liveMeeting.props.meetingProp.intId,
+        ownerId, resultPod.id
+      )
+      bus.outGW.send(respMsg)
 
-    log.warning("_____ pres pod add, after:" + pods.getNumberOfPods())
-    log.warning("_____ CreateNewPresentationPodPubMsgHdlr _" + pods.printPods())
+      val pods = state.presentationPodManager.addPod(resultPod)
 
-    state.update(pods)
+      state.update(pods)
+    }
 
   }
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/GetAllPresentationPodsReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/GetAllPresentationPodsReqMsgHdlr.scala
old mode 100644
new mode 100755
index 442598849901bc7163b3aa17711af75f50c416c2..ab3eddeb079c0b39aca1c52a4ee32b6652bef70d
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/GetAllPresentationPodsReqMsgHdlr.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/GetAllPresentationPodsReqMsgHdlr.scala
@@ -2,6 +2,7 @@ package org.bigbluebutton.core.apps.presentationpod
 
 import org.bigbluebutton.common2.domain.{ PresentationPodVO, PresentationVO }
 import org.bigbluebutton.common2.msgs._
+import org.bigbluebutton.core.apps.PermissionCheck
 import org.bigbluebutton.core.bus.MessageBus
 import org.bigbluebutton.core.domain.MeetingState2x
 import org.bigbluebutton.core.models.PresentationPod
@@ -13,26 +14,34 @@ trait GetAllPresentationPodsReqMsgHdlr {
   def handle(msg: GetAllPresentationPodsReqMsg, state: MeetingState2x,
              liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
 
-    def buildGetAllPresentationPodsRespMsg(pods: Vector[PresentationPodVO], requesterId: String): BbbCommonEnvCoreMsg = {
-      val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, requesterId)
-      val envelope = BbbCoreEnvelope(GetAllPresentationPodsRespMsg.NAME, routing)
-      val header = BbbClientMsgHeader(GetAllPresentationPodsRespMsg.NAME, liveMeeting.props.meetingProp.intId, requesterId)
+    if (applyPermissionCheck && !PermissionCheck.isAllowed(PermissionCheck.GUEST_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
+      val meetingId = liveMeeting.props.meetingProp.intId
+      val reason = "No permission to get all presentation pods from meeting."
+      PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW)
+      state
+    } else {
+      def buildGetAllPresentationPodsRespMsg(pods: Vector[PresentationPodVO], requesterId: String): BbbCommonEnvCoreMsg = {
+        val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, requesterId)
+        val envelope = BbbCoreEnvelope(GetAllPresentationPodsRespMsg.NAME, routing)
+        val header = BbbClientMsgHeader(GetAllPresentationPodsRespMsg.NAME, liveMeeting.props.meetingProp.intId, requesterId)
 
-      val body = GetAllPresentationPodsRespMsgBody(pods)
-      val event = GetAllPresentationPodsRespMsg(header, body)
+        val body = GetAllPresentationPodsRespMsgBody(pods)
+        val event = GetAllPresentationPodsRespMsg(header, body)
 
-      BbbCommonEnvCoreMsg(envelope, event)
-    }
+        BbbCommonEnvCoreMsg(envelope, event)
+      }
+
+      val requesterId = msg.body.requesterId
 
-    val requesterId = msg.body.requesterId
+      val pods = PresentationPodsApp.getAllPresentationPodsInMeeting(state)
 
-    val pods = PresentationPodsApp.getAllPresentationPodsInMeeting(state)
+      val podsVO = pods.map(pod => PresentationPodsApp.translatePresentationPodToVO(pod))
+      val event = buildGetAllPresentationPodsRespMsg(podsVO, requesterId)
 
-    val podsVO = pods.map(pod => PresentationPodsApp.translatePresentationPodToVO(pod))
-    val event = buildGetAllPresentationPodsRespMsg(podsVO, requesterId)
+      bus.outGW.send(event)
 
-    bus.outGW.send(event)
+      state
+    }
 
-    state
   }
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/GetPresentationInfoReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/GetPresentationInfoReqMsgHdlr.scala
old mode 100644
new mode 100755
index 98da14b504af1dbcf7e9a6f3b8028b23642540a3..bcecbfa096c00a37992c26cfaf1d451331429c30
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/GetPresentationInfoReqMsgHdlr.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/GetPresentationInfoReqMsgHdlr.scala
@@ -2,6 +2,7 @@ package org.bigbluebutton.core.apps.presentationpod
 
 import org.bigbluebutton.common2.domain.PresentationVO
 import org.bigbluebutton.common2.msgs._
+import org.bigbluebutton.core.apps.PermissionCheck
 import org.bigbluebutton.core.bus.MessageBus
 import org.bigbluebutton.core.domain.MeetingState2x
 import org.bigbluebutton.core.running.LiveMeeting
@@ -12,34 +13,42 @@ trait GetPresentationInfoReqMsgHdlr {
   def handle(msg: GetPresentationInfoReqMsg, state: MeetingState2x,
              liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
 
-    def buildGetPresentationInfoRespMsg(presentations: Vector[PresentationVO], podId: String,
-                                        requesterId: String): BbbCommonEnvCoreMsg = {
-      val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, requesterId)
-      val envelope = BbbCoreEnvelope(GetPresentationInfoRespMsg.NAME, routing)
-      val header = BbbClientMsgHeader(GetPresentationInfoRespMsg.NAME, liveMeeting.props.meetingProp.intId, requesterId)
-
-      val body = GetPresentationInfoRespMsgBody(podId, presentations)
-      val event = GetPresentationInfoRespMsg(header, body)
-
-      BbbCommonEnvCoreMsg(envelope, event)
+    if (applyPermissionCheck && !PermissionCheck.isAllowed(PermissionCheck.GUEST_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
+      val meetingId = liveMeeting.props.meetingProp.intId
+      val reason = "No permission get presentation info from meeting."
+      PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW)
+      state
+    } else {
+      def buildGetPresentationInfoRespMsg(presentations: Vector[PresentationVO], podId: String,
+                                          requesterId: String): BbbCommonEnvCoreMsg = {
+        val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, requesterId)
+        val envelope = BbbCoreEnvelope(GetPresentationInfoRespMsg.NAME, routing)
+        val header = BbbClientMsgHeader(GetPresentationInfoRespMsg.NAME, liveMeeting.props.meetingProp.intId, requesterId)
+
+        val body = GetPresentationInfoRespMsgBody(podId, presentations)
+        val event = GetPresentationInfoRespMsg(header, body)
+
+        BbbCommonEnvCoreMsg(envelope, event)
+      }
+
+      val requesterId = msg.body.userId
+      val podId = msg.body.podId
+
+      for {
+        pod <- PresentationPodsApp.getPresentationPod(state, podId)
+      } yield {
+        val presInPod = pod.presentations
+
+        val presVOs = presInPod.values.map { p =>
+          PresentationVO(p.id, p.name, p.current, p.pages.values.toVector, p.downloadable)
+        }.toVector
+        val event = buildGetPresentationInfoRespMsg(presVOs, podId, requesterId)
+
+        bus.outGW.send(event)
+
+      }
+      state
     }
 
-    val requesterId = msg.body.userId
-    val podId = msg.body.podId
-
-    for {
-      pod <- PresentationPodsApp.getPresentationPod(state, podId)
-    } yield {
-      val presInPod = pod.presentations
-
-      val presVOs = presInPod.values.map { p =>
-        PresentationVO(p.id, p.name, p.current, p.pages.values.toVector, p.downloadable)
-      }.toVector
-      val event = buildGetPresentationInfoRespMsg(presVOs, podId, requesterId)
-
-      bus.outGW.send(event)
-
-    }
-    state
   }
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationConversionCompletedSysPubMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationConversionCompletedSysPubMsgHdlr.scala
old mode 100644
new mode 100755
index 972009647f640cf03afdd5237b8e15a3730eef2a..2ac6696e2446602b49175dedad236d1deabb1816
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationConversionCompletedSysPubMsgHdlr.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationConversionCompletedSysPubMsgHdlr.scala
@@ -53,8 +53,6 @@ trait PresentationConversionCompletedSysPubMsgHdlr {
       pods = pods.addPresentationToPod(pod.id, pres)
       pods = pods.setCurrentPresentation(pod.id, pres.id)
 
-      log.warning("_____PresentationConversionCompletedSysPubMsgHdlr_ " + pods.printPods())
-
       state.update(pods)
     }
 
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationPodsApp.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationPodsApp.scala
old mode 100644
new mode 100755
index 622c8470cdebb8c20912f2ce9b23e63b2a3fc37d..309de533df5c8b4c2f0b6d25cd97d97c0a26950d
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationPodsApp.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationPodsApp.scala
@@ -72,7 +72,6 @@ object PresentationPodsApp {
     for {
       defPod <- getPresentationPod(state, "DEFAULT_PRESENTATION_POD")
     } yield {
-      println(s"\n\n\n changeOwnershipOfDefaultPod  $newOwnerId  \n\n\n")
       defPod.copy(ownerId = newOwnerId)
     }
   }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/RemovePresentationPodPubMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/RemovePresentationPodPubMsgHdlr.scala
old mode 100644
new mode 100755
index 17997714475796e0c58971d29cc4c12c5e8d974e..32b898301b2de9eac99ecfed0a724ffad0b018bb
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/RemovePresentationPodPubMsgHdlr.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/RemovePresentationPodPubMsgHdlr.scala
@@ -1,6 +1,7 @@
 package org.bigbluebutton.core.apps.presentationpod
 
 import org.bigbluebutton.common2.msgs._
+import org.bigbluebutton.core.apps.PermissionCheck
 import org.bigbluebutton.core.bus.MessageBus
 import org.bigbluebutton.core.domain.MeetingState2x
 import org.bigbluebutton.core.running.LiveMeeting
@@ -11,59 +12,61 @@ trait RemovePresentationPodPubMsgHdlr {
   def handle(msg: RemovePresentationPodPubMsg, state: MeetingState2x,
              liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
 
-    def buildRemovePresentationPodEvtMsg(meetingId: String, ownerId: String, podId: String): BbbCommonEnvCoreMsg = {
-      val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, ownerId)
-      val envelope = BbbCoreEnvelope(RemovePresentationPodEvtMsg.NAME, routing)
-      val header = BbbClientMsgHeader(RemovePresentationPodEvtMsg.NAME, meetingId, ownerId)
-
-      val body = RemovePresentationPodEvtMsgBody(ownerId, podId)
-      val event = RemovePresentationPodEvtMsg(header, body)
-
-      BbbCommonEnvCoreMsg(envelope, event)
+    if (applyPermissionCheck && !PermissionCheck.isAllowed(PermissionCheck.MOD_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
+      val meetingId = liveMeeting.props.meetingProp.intId
+      val reason = "No permission to remove presentation pod from meeting."
+      PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW)
+      state
+    } else {
+      def buildRemovePresentationPodEvtMsg(meetingId: String, ownerId: String, podId: String): BbbCommonEnvCoreMsg = {
+        val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, ownerId)
+        val envelope = BbbCoreEnvelope(RemovePresentationPodEvtMsg.NAME, routing)
+        val header = BbbClientMsgHeader(RemovePresentationPodEvtMsg.NAME, meetingId, ownerId)
+
+        val body = RemovePresentationPodEvtMsgBody(ownerId, podId)
+        val event = RemovePresentationPodEvtMsg(header, body)
+
+        BbbCommonEnvCoreMsg(envelope, event)
+      }
+
+      val requesterId = msg.body.requesterId // TODO -- use it
+
+      val newState = for {
+        pod <- PresentationPodsApp.getPresentationPod(state, msg.body.podId)
+      } yield {
+
+        val ownerId = pod.ownerId
+
+        val event = buildRemovePresentationPodEvtMsg(
+          liveMeeting.props.meetingProp.intId,
+          ownerId, pod.id
+        )
+
+        bus.outGW.send(event)
+
+        val pods = state.presentationPodManager.removePod(pod.id)
+        state.update(pods)
+      }
+
+      newState match {
+        case Some(ns) => ns
+        case None     => state
+      }
+
+      // TODO check if requesterId == ownerId
+      // TODO check about notifying only the list of authorized?
+
+      //    val respMsg = buildRemovePresentationPodEvtMsg(
+      //      liveMeeting.props.meetingProp.intId,
+      //      ownerId, pod.id
+      //    )
+      //    bus.outGW.send(respMsg)
+      //
+      //    log.warning("RemovePresentationPodPubMsgHdlr new podId=" + pod.id)
+      //
+      //    val pods = state.presentationPodManager.removePod(pod)
+      //    state.update(pods)
     }
 
-    val requesterId = msg.body.requesterId // TODO -- use it
-
-    log.warning(s"_____ attempt for pres pod removal by $requesterId, num before:${state.presentationPodManager.getNumberOfPods()}")
-
-    val newState = for {
-      pod <- PresentationPodsApp.getPresentationPod(state, msg.body.podId)
-    } yield {
-
-      val ownerId = pod.ownerId
-
-      val event = buildRemovePresentationPodEvtMsg(
-        liveMeeting.props.meetingProp.intId,
-        ownerId, pod.id
-      )
-
-      bus.outGW.send(event)
-
-      log.warning("_____ pres pod removal, before:" + state.presentationPodManager.getNumberOfPods())
-      val pods = state.presentationPodManager.removePod(pod.id)
-      //      PresentationPodsApp.removePresentationPod(state, pod.id)
-      log.warning("_____ pres pod removal, afterB:" + pods.getNumberOfPods())
-      state.update(pods)
-    }
-
-    newState match {
-      case Some(ns) => ns
-      case None     => state
-    }
-
-    // TODO check if requesterId == ownerId
-    // TODO check about notifying only the list of authorized?
-
-    //    val respMsg = buildRemovePresentationPodEvtMsg(
-    //      liveMeeting.props.meetingProp.intId,
-    //      ownerId, pod.id
-    //    )
-    //    bus.outGW.send(respMsg)
-    //
-    //    log.warning("RemovePresentationPodPubMsgHdlr new podId=" + pod.id)
-    //
-    //    val pods = state.presentationPodManager.removePod(pod)
-    //    state.update(pods)
-
   }
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/RemovePresentationPubMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/RemovePresentationPubMsgHdlr.scala
index 64cb5c37fd49c739ac327c071ed57f639f3cf636..7894a2a0f489753cab071e08865e95133355eaba 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/RemovePresentationPubMsgHdlr.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/RemovePresentationPubMsgHdlr.scala
@@ -1,6 +1,7 @@
 package org.bigbluebutton.core.apps.presentationpod
 
 import org.bigbluebutton.common2.msgs._
+import org.bigbluebutton.core.apps.PermissionCheck
 import org.bigbluebutton.core.bus.MessageBus
 import org.bigbluebutton.core.domain.MeetingState2x
 import org.bigbluebutton.core.running.LiveMeeting
@@ -13,36 +14,42 @@ trait RemovePresentationPubMsgHdlr {
     liveMeeting: LiveMeeting, bus: MessageBus
   ): MeetingState2x = {
 
-    def broadcastRemovePresentationEvtMsg(podId: String, userId: String, presentationId: String): Unit = {
-      val routing = Routing.addMsgToClientRouting(
-        MessageTypes.BROADCAST_TO_MEETING,
-        liveMeeting.props.meetingProp.intId, userId
-      )
-      val envelope = BbbCoreEnvelope(RemovePresentationEvtMsg.NAME, routing)
-      val header = BbbClientMsgHeader(RemovePresentationEvtMsg.NAME, liveMeeting.props.meetingProp.intId, userId)
-
-      val body = RemovePresentationEvtMsgBody(podId, presentationId)
-      val event = RemovePresentationEvtMsg(header, body)
-      val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
-      bus.outGW.send(msgEvent)
-    }
-
-    val podId = msg.body.podId
-    val presentationId = msg.body.presentationId
-
-    val newState = for {
-      pod <- PresentationPodsApp.getPresentationPod(state, podId)
-    } yield {
-      broadcastRemovePresentationEvtMsg(pod.id, msg.header.userId, presentationId)
-
-      val pods = state.presentationPodManager.removePresentationInPod(pod.id, presentationId)
-      log.warning("_____ RemovePresentationPubMsgHdlr _ " + pods.printPods())
-      state.update(pods)
-    }
-
-    newState match {
-      case Some(ns) => ns
-      case None     => state
+    if (applyPermissionCheck && !PermissionCheck.isAllowed(PermissionCheck.MOD_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
+      val meetingId = liveMeeting.props.meetingProp.intId
+      val reason = "No permission to remove presentation from meeting."
+      PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW)
+      state
+    } else {
+      def broadcastRemovePresentationEvtMsg(podId: String, userId: String, presentationId: String): Unit = {
+        val routing = Routing.addMsgToClientRouting(
+          MessageTypes.BROADCAST_TO_MEETING,
+          liveMeeting.props.meetingProp.intId, userId
+        )
+        val envelope = BbbCoreEnvelope(RemovePresentationEvtMsg.NAME, routing)
+        val header = BbbClientMsgHeader(RemovePresentationEvtMsg.NAME, liveMeeting.props.meetingProp.intId, userId)
+
+        val body = RemovePresentationEvtMsgBody(podId, presentationId)
+        val event = RemovePresentationEvtMsg(header, body)
+        val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
+        bus.outGW.send(msgEvent)
+      }
+
+      val podId = msg.body.podId
+      val presentationId = msg.body.presentationId
+
+      val newState = for {
+        pod <- PresentationPodsApp.getPresentationPod(state, podId)
+      } yield {
+        broadcastRemovePresentationEvtMsg(pod.id, msg.header.userId, presentationId)
+
+        val pods = state.presentationPodManager.removePresentationInPod(pod.id, presentationId)
+        state.update(pods)
+      }
+
+      newState match {
+        case Some(ns) => ns
+        case None     => state
+      }
     }
 
   }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/SetCurrentPagePubMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/SetCurrentPagePubMsgHdlr.scala
old mode 100644
new mode 100755
index b7bb49a520febf9a7c42025bcf0e6d3b47273192..fb26b89b7bbdb9277158b80f7954cb37fcb2d741
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/SetCurrentPagePubMsgHdlr.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/SetCurrentPagePubMsgHdlr.scala
@@ -1,6 +1,7 @@
 package org.bigbluebutton.core.apps.presentationpod
 
 import org.bigbluebutton.common2.msgs._
+import org.bigbluebutton.core.apps.PermissionCheck
 import org.bigbluebutton.core.bus.MessageBus
 import org.bigbluebutton.core.domain.MeetingState2x
 import org.bigbluebutton.core.running.LiveMeeting
@@ -15,44 +16,52 @@ trait SetCurrentPagePubMsgHdlr {
     liveMeeting: LiveMeeting, bus: MessageBus
   ): MeetingState2x = {
 
-    def broadcastSetCurrentPageEvtMsg(podId: String, presentationId: String, pageId: String, userId: String): Unit = {
-      val routing = Routing.addMsgToClientRouting(
-        MessageTypes.BROADCAST_TO_MEETING,
-        liveMeeting.props.meetingProp.intId, userId
-      )
-      val envelope = BbbCoreEnvelope(SetCurrentPageEvtMsg.NAME, routing)
-      val header = BbbClientMsgHeader(SetCurrentPageEvtMsg.NAME, liveMeeting.props.meetingProp.intId, userId)
-
-      val body = SetCurrentPageEvtMsgBody(podId, presentationId, pageId)
-      val event = SetCurrentPageEvtMsg(header, body)
-      val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
-      bus.outGW.send(msgEvent)
-    }
+    if (applyPermissionCheck && !PermissionCheck.isAllowed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
+      val meetingId = liveMeeting.props.meetingProp.intId
+      val reason = "No permission to set presentation page."
+      PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW)
+      state
+    } else {
+      def broadcastSetCurrentPageEvtMsg(podId: String, presentationId: String, pageId: String, userId: String): Unit = {
+        val routing = Routing.addMsgToClientRouting(
+          MessageTypes.BROADCAST_TO_MEETING,
+          liveMeeting.props.meetingProp.intId, userId
+        )
+        val envelope = BbbCoreEnvelope(SetCurrentPageEvtMsg.NAME, routing)
+        val header = BbbClientMsgHeader(SetCurrentPageEvtMsg.NAME, liveMeeting.props.meetingProp.intId, userId)
+
+        val body = SetCurrentPageEvtMsgBody(podId, presentationId, pageId)
+        val event = SetCurrentPageEvtMsg(header, body)
+        val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
+        bus.outGW.send(msgEvent)
+      }
 
-    val podId = msg.body.podId
-    val userId = msg.header.userId
-    val presentationId = msg.body.presentationId
-    val pageId = msg.body.pageId
+      val podId = msg.body.podId
+      val userId = msg.header.userId
+      val presentationId = msg.body.presentationId
+      val pageId = msg.body.pageId
 
-    val newState = for {
-      pod <- PresentationPodsApp.getPresentationPod(state, podId)
-      presentationToModify <- pod.getPresentation(presentationId)
-      updatedPod <- pod.setCurrentPage(presentationId, pageId)
-    } yield {
+      val newState = for {
+        pod <- PresentationPodsApp.getPresentationPod(state, podId)
+        presentationToModify <- pod.getPresentation(presentationId)
+        updatedPod <- pod.setCurrentPage(presentationId, pageId)
+      } yield {
 
-      if (Users2x.userIsInPresenterGroup(liveMeeting.users2x, userId) || userId.equals(pod.ownerId)) {
-        broadcastSetCurrentPageEvtMsg(pod.id, presentationId, pageId, userId)
+        if (Users2x.userIsInPresenterGroup(liveMeeting.users2x, userId) || userId.equals(pod.ownerId)) {
+          broadcastSetCurrentPageEvtMsg(pod.id, presentationId, pageId, userId)
 
-        val pods = state.presentationPodManager.addPod(updatedPod)
-        state.update(pods)
-      } else {
-        state
+          val pods = state.presentationPodManager.addPod(updatedPod)
+          state.update(pods)
+        } else {
+          state
+        }
       }
-    }
 
-    newState match {
-      case Some(ns) => ns
-      case None     => state
+      newState match {
+        case Some(ns) => ns
+        case None     => state
+      }
     }
+
   }
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/SetCurrentPresentationPubMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/SetCurrentPresentationPubMsgHdlr.scala
old mode 100644
new mode 100755
index 52431df0ef84932cd4ac834b5a885e0adce4986e..5a166aaf1f2ee7dc2bb302ee328dfd53806aeb38
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/SetCurrentPresentationPubMsgHdlr.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/SetCurrentPresentationPubMsgHdlr.scala
@@ -1,6 +1,7 @@
 package org.bigbluebutton.core.apps.presentationpod
 
 import org.bigbluebutton.common2.msgs._
+import org.bigbluebutton.core.apps.PermissionCheck
 import org.bigbluebutton.core.bus.MessageBus
 import org.bigbluebutton.core.domain.MeetingState2x
 import org.bigbluebutton.core.running.LiveMeeting
@@ -13,34 +14,39 @@ trait SetCurrentPresentationPubMsgHdlr {
     liveMeeting: LiveMeeting, bus: MessageBus
   ): MeetingState2x = {
 
-    def broadcastSetCurrentPresentationEvent(podId: String, userId: String, presentationId: String): Unit = {
-      val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, userId)
-      val envelope = BbbCoreEnvelope(SetCurrentPresentationEvtMsg.NAME, routing)
-      val header = BbbClientMsgHeader(SetCurrentPresentationEvtMsg.NAME, liveMeeting.props.meetingProp.intId, userId)
-
-      val body = SetCurrentPresentationEvtMsgBody(podId, presentationId)
-      val event = SetCurrentPresentationEvtMsg(header, body)
-      val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
-      bus.outGW.send(msgEvent)
-    }
-
-    val podId = msg.body.podId
-    val presId = msg.body.presentationId
-
-    val newState = for {
-      updatedPod <- PresentationPodsApp.setCurrentPresentationInPod(state, podId, presId)
-    } yield {
-      broadcastSetCurrentPresentationEvent(podId, msg.header.userId, presId)
-
-      log.warning("_____ SetCurrentPresentationPubMsgHdlr before_ " + state.presentationPodManager.printPods())
-      val pods = state.presentationPodManager.addPod(updatedPod)
-      log.warning("_____ SetCurrentPresentationPubMsgHdlr after_ " + pods.printPods())
-      state.update(pods)
-    }
-
-    newState match {
-      case Some(ns) => ns
-      case None     => state
+    if (applyPermissionCheck && !PermissionCheck.isAllowed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
+      val meetingId = liveMeeting.props.meetingProp.intId
+      val reason = "No permission to set presentation page."
+      PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW)
+      state
+    } else {
+      def broadcastSetCurrentPresentationEvent(podId: String, userId: String, presentationId: String): Unit = {
+        val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, userId)
+        val envelope = BbbCoreEnvelope(SetCurrentPresentationEvtMsg.NAME, routing)
+        val header = BbbClientMsgHeader(SetCurrentPresentationEvtMsg.NAME, liveMeeting.props.meetingProp.intId, userId)
+
+        val body = SetCurrentPresentationEvtMsgBody(podId, presentationId)
+        val event = SetCurrentPresentationEvtMsg(header, body)
+        val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
+        bus.outGW.send(msgEvent)
+      }
+
+      val podId = msg.body.podId
+      val presId = msg.body.presentationId
+
+      val newState = for {
+        updatedPod <- PresentationPodsApp.setCurrentPresentationInPod(state, podId, presId)
+      } yield {
+        broadcastSetCurrentPresentationEvent(podId, msg.header.userId, presId)
+
+        val pods = state.presentationPodManager.addPod(updatedPod)
+        state.update(pods)
+      }
+
+      newState match {
+        case Some(ns) => ns
+        case None     => state
+      }
     }
 
   }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/SetPresenterInPodReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/SetPresenterInPodReqMsgHdlr.scala
old mode 100644
new mode 100755
index 4828a0fbbaf65fa94a78b0b05b1a611a8769f2be..0e3b63ee45b296945d419ff09b32aa8b70072f16
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/SetPresenterInPodReqMsgHdlr.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/SetPresenterInPodReqMsgHdlr.scala
@@ -1,6 +1,7 @@
 package org.bigbluebutton.core.apps.presentationpod
 
 import org.bigbluebutton.common2.msgs._
+import org.bigbluebutton.core.apps.PermissionCheck
 import org.bigbluebutton.core.bus.MessageBus
 import org.bigbluebutton.core.domain.MeetingState2x
 import org.bigbluebutton.core.running.LiveMeeting
@@ -14,44 +15,52 @@ trait SetPresenterInPodReqMsgHdlr {
     liveMeeting: LiveMeeting, bus: MessageBus
   ): MeetingState2x = {
 
-    def broadcastSetPresenterInPodRespMsg(podId: String, prevPresenterId: String, nextPresenterId: String, requesterId: String): Unit = {
-      val routing = Routing.addMsgToClientRouting(
-        MessageTypes.BROADCAST_TO_MEETING,
-        liveMeeting.props.meetingProp.intId, requesterId
-      )
-      val envelope = BbbCoreEnvelope(SetPresenterInPodRespMsg.NAME, routing)
-      val header = BbbClientMsgHeader(SetPresenterInPodRespMsg.NAME, liveMeeting.props.meetingProp.intId, requesterId)
-
-      val body = SetPresenterInPodRespMsgBody(podId, prevPresenterId, nextPresenterId)
-      val event = SetPresenterInPodRespMsg(header, body)
-      val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
-      bus.outGW.send(msgEvent)
-    }
+    if (applyPermissionCheck && !PermissionCheck.isAllowed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
+      val meetingId = liveMeeting.props.meetingProp.intId
+      val reason = "No permission to set presenter in presentation."
+      PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW)
+      state
+    } else {
+      def broadcastSetPresenterInPodRespMsg(podId: String, prevPresenterId: String, nextPresenterId: String, requesterId: String): Unit = {
+        val routing = Routing.addMsgToClientRouting(
+          MessageTypes.BROADCAST_TO_MEETING,
+          liveMeeting.props.meetingProp.intId, requesterId
+        )
+        val envelope = BbbCoreEnvelope(SetPresenterInPodRespMsg.NAME, routing)
+        val header = BbbClientMsgHeader(SetPresenterInPodRespMsg.NAME, liveMeeting.props.meetingProp.intId, requesterId)
+
+        val body = SetPresenterInPodRespMsgBody(podId, prevPresenterId, nextPresenterId)
+        val event = SetPresenterInPodRespMsg(header, body)
+        val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
+        bus.outGW.send(msgEvent)
+      }
 
-    val podId: String = msg.body.podId
-    val requesterId: String = msg.header.userId
-    val nextPresenterId: String = msg.body.nextPresenterId
-    val prevPresenterId: String = msg.body.prevPresenterId
+      val podId: String = msg.body.podId
+      val requesterId: String = msg.header.userId
+      val nextPresenterId: String = msg.body.nextPresenterId
+      val prevPresenterId: String = msg.body.prevPresenterId
 
-    val newState = for {
-      pod <- PresentationPodsApp.getPresentationPod(state, podId)
-    } yield {
+      val newState = for {
+        pod <- PresentationPodsApp.getPresentationPod(state, podId)
+      } yield {
 
-      if (Users2x.userIsInPresenterGroup(liveMeeting.users2x, requesterId) || requesterId.equals(pod.ownerId)) {
-        val updatedPod = pod.setCurrentPresenter(nextPresenterId)
+        if (Users2x.userIsInPresenterGroup(liveMeeting.users2x, requesterId) || requesterId.equals(pod.ownerId)) {
+          val updatedPod = pod.setCurrentPresenter(nextPresenterId)
 
-        broadcastSetPresenterInPodRespMsg(pod.id, prevPresenterId, nextPresenterId, requesterId)
+          broadcastSetPresenterInPodRespMsg(pod.id, prevPresenterId, nextPresenterId, requesterId)
 
-        val pods = state.presentationPodManager.addPod(updatedPod)
-        state.update(pods)
-      } else {
-        state
+          val pods = state.presentationPodManager.addPod(updatedPod)
+          state.update(pods)
+        } else {
+          state
+        }
       }
-    }
 
-    newState match {
-      case Some(ns) => ns
-      case None     => state
+      newState match {
+        case Some(ns) => ns
+        case None     => state
+      }
     }
+
   }
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/AddUserToPresenterGroupCmdMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/AddUserToPresenterGroupCmdMsgHdlr.scala
index 8d664ebc520bd1e3b130b6b2034a7cf12e885939..c73a32f7f251c4b8bc59ff7a513b496ed6354e4c 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/AddUserToPresenterGroupCmdMsgHdlr.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/AddUserToPresenterGroupCmdMsgHdlr.scala
@@ -13,17 +13,6 @@ trait AddUserToPresenterGroupCmdMsgHdlr {
 
   def handleAddUserToPresenterGroupCmdMsg(msg: AddUserToPresenterGroupCmdMsg) {
 
-    def broadcastAddUserToPresenterGroup(meetingId: String, userId: String, requesterId: String): Unit = {
-      val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
-      val envelope = BbbCoreEnvelope(UserAddedToPresenterGroupEvtMsg.NAME, routing)
-      val header = BbbClientMsgHeader(UserAddedToPresenterGroupEvtMsg.NAME, meetingId, userId)
-      val body = UserAddedToPresenterGroupEvtMsgBody(userId, requesterId)
-      val event = UserAddedToPresenterGroupEvtMsg(header, body)
-      val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
-
-      outGW.send(msgEvent)
-    }
-
     if (applyPermissionCheck && !PermissionCheck.isAllowed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
       val meetingId = liveMeeting.props.meetingProp.intId
       val reason = "No permission to add user to presenter group."
@@ -36,8 +25,7 @@ trait AddUserToPresenterGroupCmdMsgHdlr {
         requester <- Users2x.findWithIntId(liveMeeting.users2x, requesterId)
       } yield {
         if (requester.role == Roles.MODERATOR_ROLE) {
-          Users2x.addUserToPresenterGroup(liveMeeting.users2x, userId)
-          broadcastAddUserToPresenterGroup(liveMeeting.props.meetingProp.intId, userId, requesterId)
+          UsersApp.addUserToPresenterGroup(liveMeeting, outGW, userId, requesterId)
         }
       }
     }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala
index a0f414b3edc317a6111cf6d1ffbd8815691fc9b0..99bf9aebf8800dcb885c8f447a2cb970fa701354 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala
@@ -2,9 +2,35 @@ package org.bigbluebutton.core.apps.users
 
 import akka.actor.ActorContext
 import akka.event.Logging
+import org.bigbluebutton.common2.msgs._
 import org.bigbluebutton.core.bus.InternalEventBus
+import org.bigbluebutton.core.models.{ Roles, Users2x }
 import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
 
+object UsersApp {
+  def broadcastAddUserToPresenterGroup(meetingId: String, userId: String, requesterId: String,
+                                       outGW: OutMsgRouter): Unit = {
+    val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
+    val envelope = BbbCoreEnvelope(UserAddedToPresenterGroupEvtMsg.NAME, routing)
+    val header = BbbClientMsgHeader(UserAddedToPresenterGroupEvtMsg.NAME, meetingId, userId)
+    val body = UserAddedToPresenterGroupEvtMsgBody(userId, requesterId)
+    val event = UserAddedToPresenterGroupEvtMsg(header, body)
+    val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
+
+    outGW.send(msgEvent)
+  }
+
+  def addUserToPresenterGroup(liveMeeting: LiveMeeting, outGW: OutMsgRouter,
+                              userId: String, requesterId: String): Unit = {
+    Users2x.addUserToPresenterGroup(liveMeeting.users2x, userId)
+    UsersApp.broadcastAddUserToPresenterGroup(
+      liveMeeting.props.meetingProp.intId,
+      userId, requesterId, outGW
+    )
+  }
+
+}
+
 class UsersApp(
   val liveMeeting: LiveMeeting,
   val outGW:       OutMsgRouter,
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala
index c730c55e5b49a010dc9dcc186a60d557934d7063..6f6782535008c31d386c1f3d16f9db2718e8afa5 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala
@@ -297,6 +297,9 @@ class ReceivedJsonMsgHandlerActor(
       case CreateGroupChatReqMsg.NAME =>
         routeGenericMsg[CreateGroupChatReqMsg](envelope, jsonNode)
 
+      case ValidateConnAuthTokenSysMsg.NAME =>
+        routeGenericMsg[ValidateConnAuthTokenSysMsg](envelope, jsonNode)
+
       case _ =>
         log.error("Cannot route envelope name " + envelope.name)
       // do nothing
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala
index 328f529965fc31f96a16ffc3cc6e86218aa5a20c..3a5bf819779b0f1982e8477242dfd4525aa9f591 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala
@@ -3,6 +3,7 @@ package org.bigbluebutton.core.running
 import org.bigbluebutton.SystemConfiguration
 import org.bigbluebutton.common2.msgs._
 import org.bigbluebutton.core.api.{ BreakoutRoomEndedInternalMsg, DestroyMeetingInternalMsg, EndBreakoutRoomInternalMsg }
+import org.bigbluebutton.core.apps.users.UsersApp
 import org.bigbluebutton.core.bus.{ BigBlueButtonEvent, InternalEventBus }
 import org.bigbluebutton.core.domain.MeetingState2x
 import org.bigbluebutton.core.models._
@@ -54,6 +55,11 @@ trait HandlerHelpers extends SystemConfiguration {
         if (!Users2x.hasPresenter(liveMeeting.users2x)) {
           automaticallyAssignPresenter(outGW, liveMeeting)
         }
+
+        if (newUser.role == Roles.MODERATOR_ROLE) {
+          UsersApp.addUserToPresenterGroup(liveMeeting, outGW, newUser.intId, newUser.intId)
+        }
+
         state.update(state.expiryTracker.setUserHasJoined())
       case None =>
         state
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala
index d36b2aac9afb7dcf844233bb0db3ec209e16abc7..0c0933acb21b440af35b3601c0ef887eb73aa0de 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala
@@ -1,6 +1,7 @@
 package org.bigbluebutton.core.running
 
 import java.io.{ PrintWriter, StringWriter }
+
 import akka.actor._
 import akka.actor.SupervisorStrategy.Resume
 import org.bigbluebutton.core.apps.groupchats.{ GroupChatApp, GroupChatHdlrs }
@@ -28,10 +29,11 @@ import org.bigbluebutton.common2.msgs._
 import org.bigbluebutton.core.apps.breakout._
 import org.bigbluebutton.core.apps.polls._
 import org.bigbluebutton.core.apps.voice._
+
 import scala.concurrent.duration._
 import org.bigbluebutton.core2.testdata.FakeTestData
 import org.bigbluebutton.core.apps.layout.LayoutApp2x
-import org.bigbluebutton.core.apps.meeting.SyncGetMeetingInfoRespMsgHdlr
+import org.bigbluebutton.core.apps.meeting.{ SyncGetMeetingInfoRespMsgHdlr, ValidateConnAuthTokenSysMsgHdlr }
 import org.bigbluebutton.core.apps.users.ChangeLockSettingsInMeetingCmdMsgHdlr
 import org.bigbluebutton.core2.message.senders.MsgBuilder
 
@@ -76,7 +78,8 @@ class MeetingActor(
     with SendBreakoutTimeRemainingMsgHdlr
     with ChangeLockSettingsInMeetingCmdMsgHdlr
     with SyncGetMeetingInfoRespMsgHdlr
-    with ClientToServerLatencyTracerMsgHdlr {
+    with ClientToServerLatencyTracerMsgHdlr
+    with ValidateConnAuthTokenSysMsgHdlr {
 
   override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
     case e: Exception => {
@@ -342,6 +345,8 @@ class MeetingActor(
       case m: GetGroupChatsReqMsg => state = groupChatApp.handle(m, state, liveMeeting, msgBus)
       case m: SendGroupChatMessageMsg => state = groupChatApp.handle(m, state, liveMeeting, msgBus)
 
+      case m: ValidateConnAuthTokenSysMsg => handleValidateConnAuthTokenSysMsg(m)
+
       case _ => log.warning("***** Cannot handle " + msg.envelope.name)
     }
   }
@@ -414,7 +419,7 @@ class MeetingActor(
     val elapsedInMs = now - lastRecBreakSentOn
     val elapsedInMin = TimeUtil.millisToMinutes(elapsedInMs)
 
-    if (elapsedInMin > 1) {
+    if (elapsedInMin > recordingChapterBreakLenghtInMinutes) {
       lastRecBreakSentOn = now
       val event = MsgBuilder.buildRecordingChapterBreakSysMsg(props.meetingProp.intId, TimeUtil.timeNowInMs())
       outGW.send(event)
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala
index 8ddf5eb3bd669c12c721e93b672301d0a7a3e5b8..ef81b67e1a9b320a5c911d5b60360a3364c66c1d 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala
@@ -63,6 +63,16 @@ object MsgBuilder {
     BbbCommonEnvCoreMsg(envelope, event)
   }
 
+  def buildValidateConnAuthTokenSysRespMsg(meetingId: String, userId: String, authToken: String,
+                                           authzed: Boolean, conn: String): BbbCommonEnvCoreMsg = {
+    val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, userId)
+    val envelope = BbbCoreEnvelope(ValidateConnAuthTokenSysRespMsg.NAME, routing)
+    val header = BbbCoreHeaderWithMeetingId(ValidateConnAuthTokenSysRespMsg.NAME, meetingId)
+    val body = ValidateConnAuthTokenSysRespMsgBody(meetingId, userId, authToken, conn, authzed)
+    val event = ValidateConnAuthTokenSysRespMsg(header, body)
+    BbbCommonEnvCoreMsg(envelope, event)
+  }
+
   def buildValidateAuthTokenRespMsg(meetingId: String, userId: String, authToken: String,
                                     valid: Boolean, waitForApproval: Boolean): BbbCommonEnvCoreMsg = {
     val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, userId)
diff --git a/bbb-apps-common/build.sbt b/bbb-apps-common/build.sbt
index 79190720d8e210d18dc943fb6c40ad970a7af4b1..355f55b53d4f3ed10d5cbc025391502798dd19d0 100755
--- a/bbb-apps-common/build.sbt
+++ b/bbb-apps-common/build.sbt
@@ -3,7 +3,7 @@ name := "bbb-apps-common"
 
 organization := "org.bigbluebutton"
 
-version := "0.0.2"
+version := "0.0.3-SNAPSHOT"
 
 scalaVersion  := "2.12.2"
 
diff --git a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/ClientGWApplication.scala b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/ClientGWApplication.scala
index db86d661d7884f0aed168bb82e9e2f85b6d66a63..c25fd9b5bcdbf82c4c5c7c5b50634602295b309e 100755
--- a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/ClientGWApplication.scala
+++ b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/ClientGWApplication.scala
@@ -73,22 +73,22 @@ class ClientGWApplication(val msgToClientGW: MsgToClientGW,
     */
 
   def connect(connInfo: ConnInfo): Unit = {
-    log.debug("**** ClientGWApplication connect " + connInfo)
+    //log.debug("**** ClientGWApplication connect " + connInfo)
     msgFromClientEventBus.publish(MsgFromClientBusMsg(fromClientChannel, new ConnectMsg(connInfo)))
   }
 
   def disconnect(connInfo: ConnInfo): Unit = {
-    log.debug("**** ClientGWApplication disconnect " + connInfo)
+    //log.debug("**** ClientGWApplication disconnect " + connInfo)
     msgFromClientEventBus.publish(MsgFromClientBusMsg(fromClientChannel, new DisconnectMsg(connInfo)))
   }
 
   def handleMsgFromClient(connInfo: ConnInfo, json: String): Unit = {
-    log.debug("**** ClientGWApplication handleMsgFromClient " + json)
+    //log.debug("**** ClientGWApplication handleMsgFromClient " + json)
     msgFromClientEventBus.publish(MsgFromClientBusMsg(fromClientChannel, new MsgFromClientMsg(connInfo, json)))
   }
 
   def send(channel: String, json: String): Unit = {
-    log.debug("Sending message {}", json)
+    //log.debug("Sending message {}", json)
     jsonMsgToAkkaAppsBus.publish(JsonMsgToAkkaAppsBusMsg(toAkkaAppsJsonChannel, new JsonMsgToSendToAkkaApps(channel, json)))
   }
 
diff --git a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/ReceivedJsonMsgHdlrActor.scala b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/ReceivedJsonMsgHdlrActor.scala
index 83b4f0e88123bb30a8cb81629008cd20b7dd57dc..d18cb333ed7e2cbd1066db5c11e61bf3e50160e8 100755
--- a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/ReceivedJsonMsgHdlrActor.scala
+++ b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/ReceivedJsonMsgHdlrActor.scala
@@ -24,7 +24,7 @@ class ReceivedJsonMsgHdlrActor(val msgFromAkkaAppsEventBus: MsgFromAkkaAppsEvent
   }
 
   def handleReceivedJsonMessage(msg: JsonMsgFromAkkaApps): Unit = {
-    log.debug("****** Received JSON msg " + msg.data)
+    //log.debug("****** Received JSON msg " + msg.data)
     JsonUtil.fromJson[BbbCommonEnvJsNodeMsg](msg.data) match {
       case Success(m) => msgFromAkkaAppsEventBus.publish(MsgFromAkkaApps(fromAkkaAppsChannel, m))
       case Failure(ex) => log.error("Failed to deserialize message " + ex)
diff --git a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/endpoint/redis/AppsRedisSubscriberActor.scala b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/endpoint/redis/AppsRedisSubscriberActor.scala
index 51a8574cc12ba6d2af63eb9266098bcd4342bb0e..efd2335cd43fe0a9a6f9ebabba89c36920f47fe3 100755
--- a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/endpoint/redis/AppsRedisSubscriberActor.scala
+++ b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/endpoint/redis/AppsRedisSubscriberActor.scala
@@ -49,7 +49,7 @@ class AppsRedisSubscriberActor(jsonMsgBus: JsonMsgFromAkkaAppsBus, oldMessageEve
   def onMessage(message: Message) {
     //log.error(s"SHOULD NOT BE RECEIVING: $message")
     if (channels.contains(message.channel)) {
-      log.debug(s"RECEIVED:\n ${message.data.utf8String} \n")
+      //log.debug(s"RECEIVED:\n ${message.data.utf8String} \n")
       val receivedJsonMessage = new JsonMsgFromAkkaApps(message.channel, message.data.utf8String)
       jsonMsgBus.publish(JsonMsgFromAkkaAppsEvent(fromAkkaAppsJsonChannel, receivedJsonMessage))
     }
diff --git a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/endpoint/redis/RedisPublisher.scala b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/endpoint/redis/RedisPublisher.scala
index 97333a93aea75ef29b0c39372e19cbf7be5f2881..379b15f5dec53f025e454613d7c8b2a08bdcf042 100755
--- a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/endpoint/redis/RedisPublisher.scala
+++ b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/endpoint/redis/RedisPublisher.scala
@@ -17,7 +17,7 @@ class RedisPublisher(val system: ActorSystem) extends SystemConfiguration {
   redis.clientSetname("Red5AppsPub")
 
   def publish(channel: String, data: String) {
-    log.debug("PUBLISH TO [" + channel + "]: \n [" + data + "]")
+    //log.debug("PUBLISH TO [" + channel + "]: \n [" + data + "]")
     redis.publish(channel, ByteString(data))
   }
 
diff --git a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/MeetingActor.scala b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/MeetingActor.scala
index 1a77e0c628da1424e183c8bd174a12abd8716cf3..e002dfcf577cb592c74939de5f2ea5cd43560a0a 100755
--- a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/MeetingActor.scala
+++ b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/MeetingActor.scala
@@ -31,7 +31,7 @@ class MeetingActor(val meetingId: String, msgToAkkaAppsEventBus: MsgToAkkaAppsEv
   }
 
   def handleConnectMsg(msg: ConnectMsg): Unit = {
-    log.debug("**** MeetingActor handleConnectMsg " + msg.connInfo.meetingId)
+    //log.debug("**** MeetingActor handleConnectMsg " + msg.connInfo.meetingId)
     UsersManager.findWithId(userMgr, msg.connInfo.userId) match {
       case Some(m) => m.actorRef forward(msg)
       case None =>
@@ -42,7 +42,7 @@ class MeetingActor(val meetingId: String, msgToAkkaAppsEventBus: MsgToAkkaAppsEv
   }
 
   def handleDisconnectMsg(msg: DisconnectMsg): Unit = {
-    log.debug("**** MeetingActor handleDisconnectMsg " + msg.connInfo.meetingId)
+    //log.debug("**** MeetingActor handleDisconnectMsg " + msg.connInfo.meetingId)
     for {
       m <- UsersManager.findWithId(userMgr, msg.connInfo.userId)
     } yield {
@@ -51,7 +51,7 @@ class MeetingActor(val meetingId: String, msgToAkkaAppsEventBus: MsgToAkkaAppsEv
   }
 
   def handleMsgFromClientMsg(msg: MsgFromClientMsg):Unit = {
-    log.debug("**** MeetingActor handleMsgFromClient " + msg.json)
+    //log.debug("**** MeetingActor handleMsgFromClient " + msg.json)
     for {
       m <- UsersManager.findWithId(userMgr, msg.connInfo.userId)
     } yield {
@@ -60,7 +60,7 @@ class MeetingActor(val meetingId: String, msgToAkkaAppsEventBus: MsgToAkkaAppsEv
   }
 
   def handleBbbServerMsg(msg: BbbCommonEnvJsNodeMsg): Unit = {
-    log.debug("**** MeetingActor handleBbbServerMsg " + msg.envelope.name)
+    //log.debug("**** MeetingActor handleBbbServerMsg " + msg.envelope.name)
     for {
       msgType <- msg.envelope.routing.get("msgType")
     } yield {
@@ -69,7 +69,7 @@ class MeetingActor(val meetingId: String, msgToAkkaAppsEventBus: MsgToAkkaAppsEv
   }
 
   def handleServerMsg(msgType: String, msg: BbbCommonEnvJsNodeMsg): Unit = {
-    log.debug("**** MeetingActor handleServerMsg " + msg.envelope.name)
+    //log.debug("**** MeetingActor handleServerMsg " + msg.envelope.name)
     msgType match {
       case MessageTypes.DIRECT => handleDirectMessage(msg)
       case MessageTypes.BROADCAST_TO_MEETING => handleBroadcastMessage(msg)
@@ -78,18 +78,18 @@ class MeetingActor(val meetingId: String, msgToAkkaAppsEventBus: MsgToAkkaAppsEv
   }
 
   private def forwardToUser(msg: BbbCommonEnvJsNodeMsg): Unit = {
-    log.debug("**** MeetingActor forwardToUser " + msg.envelope.name)
+    //log.debug("**** MeetingActor forwardToUser " + msg.envelope.name)
     for {
       userId <- msg.envelope.routing.get("userId")
       m <- UsersManager.findWithId(userMgr, userId)
     } yield {
-      log.debug("**** MeetingActor forwardToUser " + m.userId)
+      //log.debug("**** MeetingActor forwardToUser " + m.userId)
       m.actorRef forward(msg)
     }
   }
 
   def handleDirectMessage(msg: BbbCommonEnvJsNodeMsg): Unit = {
-    log.debug("**** MeetingActor handleDirectMessage " + msg.envelope.name)
+    //log.debug("**** MeetingActor handleDirectMessage " + msg.envelope.name)
     // In case we want to handle specific messages. We can do it here.
     forwardToUser(msg)
   }
diff --git a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/MeetingManagerActor.scala b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/MeetingManagerActor.scala
index e2cde3288761b2f229e8098bb96080ef14e3fcd7..696cff1b83133c3150f6c90015b2799394fcfbd3 100755
--- a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/MeetingManagerActor.scala
+++ b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/MeetingManagerActor.scala
@@ -30,7 +30,7 @@ class MeetingManagerActor(msgToAkkaAppsEventBus: MsgToAkkaAppsEventBus,
   }
 
   def handleConnectMsg(msg: ConnectMsg): Unit = {
-    log.debug("****** Received handleConnectMsg " + msg)
+    //log.debug("****** Received handleConnectMsg " + msg)
      MeetingManager.findWithMeetingId(meetingMgr, msg.connInfo.meetingId) match {
        case Some(m) => m.actorRef forward(msg)
        case None =>
@@ -41,7 +41,7 @@ class MeetingManagerActor(msgToAkkaAppsEventBus: MsgToAkkaAppsEventBus,
   }
 
   def handleDisconnectMsg(msg: DisconnectMsg): Unit = {
-    log.debug("****** Received handleDisconnectMsg " + msg)
+    //log.debug("****** Received handleDisconnectMsg " + msg)
     for {
       m <- MeetingManager.findWithMeetingId(meetingMgr, msg.connInfo.meetingId)
     } yield {
@@ -50,7 +50,7 @@ class MeetingManagerActor(msgToAkkaAppsEventBus: MsgToAkkaAppsEventBus,
   }
 
   def handleMsgFromClientMsg(msg: MsgFromClientMsg):Unit = {
-    log.debug("**** MeetingManagerActor handleMsgFromClient " + msg.json)
+    //log.debug("**** MeetingManagerActor handleMsgFromClient " + msg.json)
     for {
       m <- MeetingManager.findWithMeetingId(meetingMgr, msg.connInfo.meetingId)
     } yield {
@@ -59,7 +59,7 @@ class MeetingManagerActor(msgToAkkaAppsEventBus: MsgToAkkaAppsEventBus,
   }
 
   def handleBbbServerMsg(msg: BbbCommonEnvJsNodeMsg): Unit = {
-    log.debug("**** MeetingManagerActor handleBbbServerMsg " + msg.envelope.name)
+    //log.debug("**** MeetingManagerActor handleBbbServerMsg " + msg.envelope.name)
     for {
       msgType <- msg.envelope.routing.get("msgType")
     } yield {
@@ -68,7 +68,7 @@ class MeetingManagerActor(msgToAkkaAppsEventBus: MsgToAkkaAppsEventBus,
   }
 
   def handleServerMsg(msgType: String, msg: BbbCommonEnvJsNodeMsg): Unit = {
-    log.debug("**** MeetingManagerActor handleServerMsg " + msg.envelope.name)
+    //log.debug("**** MeetingManagerActor handleServerMsg " + msg.envelope.name)
     msgType match {
       case MessageTypes.DIRECT => handleDirectMessage(msg)
       case MessageTypes.BROADCAST_TO_MEETING => handleBroadcastMessage(msg)
@@ -78,10 +78,10 @@ class MeetingManagerActor(msgToAkkaAppsEventBus: MsgToAkkaAppsEventBus,
 
   private def forwardToMeeting(msg: BbbCommonEnvJsNodeMsg): Unit = {
     msg.envelope.routing.get("meetingId") match {
-      case Some(meetingId2) => log.debug("**** MeetingManagerActor forwardToMeeting. Found " + meetingId2)
+      case Some(meetingId2) => //log.debug("**** MeetingManagerActor forwardToMeeting. Found " + meetingId2)
         MeetingManager.findWithMeetingId(meetingMgr, meetingId2) match {
-          case Some(meetingId2) => log.debug("**** MeetingManagerActor forwardToMeeting. Found " + meetingId2.meetingId)
-          case None => log.debug("**** MeetingManagerActor forwardToMeeting. Could not find meetingId")
+          case Some(meetingId2) => //log.debug("**** MeetingManagerActor forwardToMeeting. Found " + meetingId2.meetingId)
+          case None => //log.debug("**** MeetingManagerActor forwardToMeeting. Could not find meetingId")
         }
       case None => log.debug("**** MeetingManagerActor forwardToMeeting. Could not find meetingId")
     }
@@ -92,25 +92,25 @@ class MeetingManagerActor(msgToAkkaAppsEventBus: MsgToAkkaAppsEventBus,
       meetingId <- msg.envelope.routing.get("meetingId")
       m <- MeetingManager.findWithMeetingId(meetingMgr, meetingId)
     } yield {
-      log.debug("**** MeetingManagerActor forwardToMeeting. " + m.meetingId)
+      //log.debug("**** MeetingManagerActor forwardToMeeting. " + m.meetingId)
       m.actorRef forward(msg)
     }
   }
 
   def handleDirectMessage(msg: BbbCommonEnvJsNodeMsg): Unit = {
-    log.debug("**** MeetingManagerActor handleDirectMessage " + msg.envelope.name)
+    //log.debug("**** MeetingManagerActor handleDirectMessage " + msg.envelope.name)
     // In case we want to handle specific message. We can do it here.
     forwardToMeeting(msg)
   }
 
   def handleBroadcastMessage(msg: BbbCommonEnvJsNodeMsg): Unit = {
-    log.debug("**** MeetingManagerActor handleBroadcastMessage " + msg.envelope.name)
+   // log.debug("**** MeetingManagerActor handleBroadcastMessage " + msg.envelope.name)
     // In case we want to handle specific message. We can do it here.
     forwardToMeeting(msg)
   }
 
   def handleSystemMessage(msg: BbbCommonEnvJsNodeMsg): Unit = {
-    log.debug("**** MeetingManagerActor handleSystemMessage " + msg.envelope.name)
+    //log.debug("**** MeetingManagerActor handleSystemMessage " + msg.envelope.name)
     // In case we want to handle specific message. We can do it here.
     forwardToMeeting(msg)
   }
diff --git a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/UserActor.scala b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/UserActor.scala
index f8c483abf65f393bc8dd2d5f5ecc99b4193207bb..bcd29a40fbc57d0270b25cc6e10e5c43bce02afb 100755
--- a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/UserActor.scala
+++ b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/meeting/UserActor.scala
@@ -119,7 +119,7 @@ class UserActor(val userId: String,
   }
 
   def handleBbbServerMsg(msg: BbbCommonEnvJsNodeMsg): Unit = {
-    log.debug("**** UserActor handleBbbServerMsg " + msg)
+    //log.debug("**** UserActor handleBbbServerMsg " + msg)
     for {
       msgType <- msg.envelope.routing.get("msgType")
     } yield {
@@ -128,7 +128,7 @@ class UserActor(val userId: String,
   }
 
   def handleServerMsg(msgType: String, msg: BbbCommonEnvJsNodeMsg): Unit = {
-    log.debug("**** UserActor handleServerMsg " + msg)
+   // log.debug("**** UserActor handleServerMsg " + msg)
     msgType match {
       case MessageTypes.DIRECT => handleDirectMessage(msg)
       case MessageTypes.BROADCAST_TO_MEETING => handleBroadcastMessage(msg)
@@ -137,7 +137,7 @@ class UserActor(val userId: String,
   }
 
   private def forwardToUser(msg: BbbCommonEnvJsNodeMsg): Unit = {
-    log.debug("UserActor forwardToUser. Forwarding to connection. " + msg)
+    //log.debug("UserActor forwardToUser. Forwarding to connection. " + msg)
     for {
       conn <- Connections.findActiveConnection(conns)
     } yield {
diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/SystemMsgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/SystemMsgs.scala
index fb1dc6af3b30b0ebea20a2e7ebe83a09c8c83f40..333c95a5d87c98bdafde054c905c4eb1077bf0f8 100755
--- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/SystemMsgs.scala
+++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/SystemMsgs.scala
@@ -128,4 +128,15 @@ case class CheckAlivePongSysMsgBody(system: String, timestamp: Long)
 object RecordingChapterBreakSysMsg { val NAME = "RecordingChapterBreakSysMsg" }
 case class RecordingChapterBreakSysMsg(header: BbbCoreHeaderWithMeetingId,
                                 body: RecordingChapterBreakSysMsgBody) extends BbbCoreMsg
-case class RecordingChapterBreakSysMsgBody(meetingId: String, timestamp: Long)
\ No newline at end of file
+case class RecordingChapterBreakSysMsgBody(meetingId: String, timestamp: Long)
+
+object ValidateConnAuthTokenSysMsg { val NAME = "ValidateConnAuthTokenSysMsg" }
+case class ValidateConnAuthTokenSysMsg(header: BbbClientMsgHeader,
+                                       body: ValidateConnAuthTokenSysMsgBody) extends StandardMsg
+case class ValidateConnAuthTokenSysMsgBody(meetingId: String, userId: String, authToken: String, conn: String)
+
+object ValidateConnAuthTokenSysRespMsg { val NAME = "ValidateConnAuthTokenSysRespMsg" }
+case class ValidateConnAuthTokenSysRespMsg(header: BbbCoreHeaderWithMeetingId,
+                                       body: ValidateConnAuthTokenSysRespMsgBody) extends BbbCoreMsg
+case class ValidateConnAuthTokenSysRespMsgBody(meetingId: String, userId: String,
+                                               authToken: String, conn: String, authzed: Boolean)
\ No newline at end of file
diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/Meeting.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/Meeting.java
new file mode 100755
index 0000000000000000000000000000000000000000..9a932c938b3d6ba9fcb029610b6d147bb0fad2a9
--- /dev/null
+++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/Meeting.java
@@ -0,0 +1,44 @@
+package org.bigbluebutton.app.screenshare;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Meeting {
+    public final String id;
+
+    private Map<String, VideoStream> videoStreams = new HashMap<String, VideoStream>();
+
+    public Meeting(String id) {
+        this.id = id;
+    }
+
+    public synchronized void addStream(VideoStream stream) {
+        videoStreams.put(stream.getStreamId(), stream);
+    }
+
+    public synchronized void removeStream(String streamId) {
+        VideoStream vs = videoStreams.remove(streamId);
+    }
+
+    public synchronized void streamBroadcastClose(String streamId) {
+        VideoStream vs = videoStreams.remove(streamId);
+        if (vs != null) {
+            vs.streamBroadcastClose();
+        }
+    }
+
+    public synchronized boolean hasVideoStreams() {
+        return !videoStreams.isEmpty();
+    }
+
+    public synchronized void stopStartRecording(String streamId) {
+        VideoStream vs = videoStreams.get(streamId);
+        if (vs != null) vs.stopStartRecording();
+    }
+
+    public synchronized void stopStartAllRecordings() {
+        for (VideoStream vs : videoStreams.values()) {
+            stopStartRecording(vs.getStreamId());
+        }
+    }
+}
diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/MeetingManager.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/MeetingManager.java
new file mode 100755
index 0000000000000000000000000000000000000000..76861013ed9c7767457fc484986129263e08ce49
--- /dev/null
+++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/MeetingManager.java
@@ -0,0 +1,53 @@
+package org.bigbluebutton.app.screenshare;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MeetingManager {
+
+    private Map<String, Meeting> meetings = new HashMap<String, Meeting>();
+
+    private void add(Meeting m) {
+        meetings.put(m.id, m);
+    }
+
+    private void remove(String id) {
+        Meeting m = meetings.remove(id);
+    }
+
+    public void addStream(String meetingId, VideoStream vs) {
+        Meeting m = meetings.get(meetingId);
+        if (m != null) {
+            m.addStream(vs);
+        } else {
+            Meeting nm = new Meeting(meetingId);
+            nm.addStream(vs);
+            add(nm);
+        }
+    }
+
+    public void removeStream(String meetingId, String streamId) {
+        Meeting m = meetings.get(meetingId);
+        if (m != null) {
+            m.removeStream(streamId);
+        }
+    }
+
+    public void streamBroadcastClose(String meetingId, String streamId) {
+        Meeting m = meetings.get(meetingId);
+        if (m != null) {
+            m.streamBroadcastClose(streamId);
+            if (!m.hasVideoStreams()) {
+                remove(m.id);
+            }
+        }
+    }
+
+    public synchronized void stopStartAllRecordings(String meetingId) {
+        Meeting m = meetings.get(meetingId);
+        if (m != null) {
+            m.stopStartAllRecordings();
+        }
+    }
+}
+
diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/VideoStream.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/VideoStream.java
new file mode 100755
index 0000000000000000000000000000000000000000..0ff5b30d93b538347494354f922b100d841a16cf
--- /dev/null
+++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/VideoStream.java
@@ -0,0 +1,65 @@
+package org.bigbluebutton.app.screenshare;
+
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.IConnection;
+import org.red5.server.api.Red5;
+import org.red5.server.api.scope.IScope;
+import org.red5.server.api.stream.IBroadcastStream;
+import org.red5.server.stream.ClientBroadcastStream;
+import org.slf4j.Logger;
+
+public class VideoStream {
+    private static Logger log = Red5LoggerFactory.getLogger(VideoStream.class, "screenshare");
+
+    private VideoStreamListener videoStreamListener;
+    private IScope scope;
+    private String streamId;
+    private IBroadcastStream stream;
+    private String recordingStreamName;
+    private ClientBroadcastStream cstream;
+
+    public VideoStream(IBroadcastStream stream, VideoStreamListener videoStreamListener, ClientBroadcastStream cstream) {
+        this.stream = stream;
+        this.videoStreamListener = videoStreamListener;
+        stream.addStreamListener(videoStreamListener);
+        this.cstream = cstream;
+    }
+
+    public String getStreamId() {
+        return streamId;
+    }
+
+    public synchronized void startRecording() {
+        long now = System.currentTimeMillis();
+        recordingStreamName = stream.getPublishedName() + "-" + now;
+        try {
+            log.info("Recording stream " + recordingStreamName);
+            videoStreamListener.setStreamId(recordingStreamName);
+            cstream.saveAs(recordingStreamName, false);
+        } catch (Exception e) {
+            log.error("ERROR while recording stream " + e.getMessage());
+            e.printStackTrace();
+        }
+    }
+
+    public synchronized void stopRecording() {
+        if (cstream.isRecording()) {
+            cstream.stopRecording();
+            videoStreamListener.stopRecording();
+            videoStreamListener.reset();
+        }
+    }
+
+    public synchronized void stopStartRecording() {
+        stopRecording();
+        videoStreamListener.reset();
+        startRecording();
+    }
+
+    public synchronized void streamBroadcastClose() {
+        stopRecording();
+
+        videoStreamListener.streamStopped();
+        stream.removeStreamListener(videoStreamListener);
+    }
+}
diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/VideoStreamListener.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/VideoStreamListener.java
new file mode 100755
index 0000000000000000000000000000000000000000..49d461c4241d1ac2d81e47c2bd978c3ebe2f4ea2
--- /dev/null
+++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/VideoStreamListener.java
@@ -0,0 +1,236 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ * <p>
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ * <p>
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 3.0 of the License, or (at your option) any later
+ * version.
+ * <p>
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ */
+package org.bigbluebutton.app.screenshare;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.red5.server.api.scheduling.IScheduledJob;
+import org.red5.server.api.scheduling.ISchedulingService;
+import org.red5.server.api.scope.IScope;
+import org.red5.server.api.stream.IBroadcastStream;
+import org.red5.server.api.stream.IStreamListener;
+import org.red5.server.api.stream.IStreamPacket;
+import org.red5.server.net.rtmp.event.VideoData;
+import org.red5.server.scheduling.QuartzSchedulingService;
+import org.slf4j.Logger;
+import org.red5.logging.Red5LoggerFactory;
+
+import com.google.gson.Gson;
+
+/**
+ * Class to listen for the first video packet of the webcam.
+ * We need to listen for the first packet and send a startWebcamEvent.
+ * The reason is that when starting the webcam, sometimes Flash Player
+ * needs to prompt the user for permission to access the webcam. However,
+ * while waiting for the user to click OK to the prompt, Red5 has already
+ * called the startBroadcast method which we take as the start of the recording.
+ * When the user finally clicks OK, the packets then start to flow through.
+ * This introduces a delay of when we assume the start of the recording and
+ * the webcam actually publishes video packets. When we do the ingest and
+ * processing of the video and multiplex the audio, the video and audio will
+ * be un-synched by at least this amount of delay. 
+ * @author Richard Alam
+ *
+ */
+public class VideoStreamListener implements IStreamListener {
+  private static final Logger log = Red5LoggerFactory.getLogger(VideoStreamListener.class, "video");
+
+  private EventRecordingService recordingService;
+  private volatile boolean firstPacketReceived = false;
+
+  // Maximum time between video packets
+  private int videoTimeout = 10000;
+  private long firstPacketTime = 0L;
+  private long packetCount = 0L;
+
+  // Last time video was received, not video timestamp
+  private long lastVideoTime;
+
+  private String recordingDir;
+
+  // Stream being observed
+  private String streamId;
+
+  // if this stream is recorded or not
+  private boolean record;
+
+  // Scheduler
+  private QuartzSchedulingService scheduler;
+
+  // Event queue worker job name
+  private String timeoutJobName;
+
+  private volatile boolean publishing = false;
+
+  private volatile boolean streamPaused = false;
+
+  private String meetingId;
+
+  private long recordingStartTime;
+  private String filename;
+
+  public VideoStreamListener(String meetingId, String streamId, Boolean record,
+                             String recordingDir, int packetTimeout,
+                             QuartzSchedulingService scheduler,
+                             EventRecordingService recordingService) {
+    this.meetingId = meetingId;
+    this.streamId = streamId;
+    this.record = record;
+    this.videoTimeout = packetTimeout;
+    this.recordingDir = recordingDir;
+    this.scheduler = scheduler;
+    this.recordingService = recordingService;
+  }
+
+  private Long genTimestamp() {
+    return TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
+  }
+
+  public void reset() {
+    firstPacketReceived = false;
+  }
+
+  public void setStreamId(String streamId) {
+    this.streamId = streamId;
+  }
+
+  @Override
+  public void packetReceived(IBroadcastStream stream, IStreamPacket packet) {
+    IoBuffer buf = packet.getData();
+    if (buf != null)
+      buf.rewind();
+
+    if (buf == null || buf.remaining() == 0) {
+      return;
+    }
+
+    if (packet instanceof VideoData) {
+      // keep track of last time video was received
+      lastVideoTime = System.currentTimeMillis();
+      packetCount++;
+
+      if (!firstPacketReceived) {
+        firstPacketReceived = true;
+        publishing = true;
+        firstPacketTime = lastVideoTime;
+
+        // start the worker to monitor if we are still receiving video packets
+        timeoutJobName = scheduler.addScheduledJob(videoTimeout, new TimeoutJob());
+
+        if (record) {
+          recordingStartTime = System.currentTimeMillis();
+          filename = recordingDir;
+          if (!filename.endsWith("/")) {
+            filename.concat("/");
+          }
+
+          filename = filename.concat(meetingId).concat("/").concat(streamId).concat(".flv");
+          recordingStartTime = System.currentTimeMillis();
+          Map<String, String> event = new HashMap<String, String>();
+          event.put("module", "Deskshare");
+          event.put("timestamp", genTimestamp().toString());
+          event.put("meetingId", meetingId);
+          event.put("file", filename);
+          event.put("stream", streamId);
+          event.put("eventName", "DeskshareStartedEvent");
+
+          recordingService.record(meetingId, event);
+        }
+      }
+
+
+      if (streamPaused) {
+        streamPaused = false;
+        long now = System.currentTimeMillis();
+        long numSeconds = (now - lastVideoTime) / 1000;
+
+        Map<String, Object> logData = new HashMap<String, Object>();
+        logData.put("meetingId", meetingId);
+        logData.put("stream", streamId);
+        logData.put("packetCount", packetCount);
+        logData.put("publishing", publishing);
+        logData.put("pausedFor (sec)", numSeconds);
+
+        Gson gson = new Gson();
+        String logStr = gson.toJson(logData);
+
+        log.warn("Screenshare stream restarted. data={}", logStr);
+      }
+
+    }
+  }
+
+  public void stopRecording() {
+    if (record) {
+      long publishDuration = (System.currentTimeMillis() - recordingStartTime) / 1000;
+
+      Map<String, String> event = new HashMap<String, String>();
+      event.put("module", "Deskshare");
+      event.put("timestamp", genTimestamp().toString());
+      event.put("meetingId", meetingId);
+      event.put("stream", streamId);
+      event.put("file", filename);
+      event.put("duration", new Long(publishDuration).toString());
+      event.put("eventName", "DeskshareStoppedEvent");
+      recordingService.record(meetingId, event);
+    }
+  }
+
+  public void streamStopped() {
+    this.publishing = false;
+  }
+
+  private class TimeoutJob implements IScheduledJob {
+    private boolean streamStopped = false;
+
+    public void execute(ISchedulingService service) {
+      Map<String, Object> logData = new HashMap<String, Object>();
+      logData.put("meetingId", meetingId);
+      logData.put("stream", streamId);
+      logData.put("packetCount", packetCount);
+      logData.put("publishing", publishing);
+
+      Gson gson = new Gson();
+
+      long now = System.currentTimeMillis();
+      if ((now - lastVideoTime) > videoTimeout && !streamPaused) {
+        streamPaused = true;
+        long numSeconds = (now - lastVideoTime) / 1000;
+
+        logData.put("lastPacketTime (sec)", numSeconds);
+
+        String logStr = gson.toJson(logData);
+
+        log.warn("Screenshare packet timeout. data={}", logStr);
+
+      }
+
+      String logStr = gson.toJson(logData);
+      if (!publishing) {
+        log.warn("Removing scheduled job. data={}", logStr);
+        // remove the scheduled job
+        scheduler.removeScheduledJob(timeoutJobName);
+      }
+    }
+
+  }
+
+}
diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/events/RecordChapterBreakMessage.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/events/RecordChapterBreakMessage.java
new file mode 100755
index 0000000000000000000000000000000000000000..afaf2c61eec3961874e6e00c8b8992f5d1c2b3d5
--- /dev/null
+++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/events/RecordChapterBreakMessage.java
@@ -0,0 +1,11 @@
+package org.bigbluebutton.app.screenshare.events;
+
+public class RecordChapterBreakMessage implements IEvent {
+    public final String meetingId;
+    public final Long timestamp;
+
+    public RecordChapterBreakMessage(String meetingId, Long timestamp) {
+        this.meetingId = meetingId;
+        this.timestamp = timestamp;
+    }
+}
diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/EventListenerImp.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/EventListenerImp.java
index d862ee9d1edc2f080e6c288363fcba71d2e24052..438c6f81f9ab158ac873fc7b020c42278344df3e 100755
--- a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/EventListenerImp.java
+++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/EventListenerImp.java
@@ -6,11 +6,13 @@ import org.bigbluebutton.app.screenshare.events.*;
 import com.google.gson.Gson;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
+import org.bigbluebutton.app.screenshare.MeetingManager;
 
 public class EventListenerImp implements IEventListener {
   private static Logger log = Red5LoggerFactory.getLogger(EventListenerImp.class, "screenshare");
   private ConnectionInvokerService sender;
-  
+  private MeetingManager meetingManager;
+
   @Override
   public void handleMessage(IEvent event) {
     if (event instanceof ScreenShareStartedEvent) {
@@ -27,6 +29,9 @@ public class EventListenerImp implements IEventListener {
         sendIsScreenSharingResponse((IsScreenSharingResponse) event);
     } else if (event instanceof ScreenShareClientPing) {
       sendScreenShareClientPing((ScreenShareClientPing) event);
+    } else if (event instanceof RecordChapterBreakMessage) {
+      RecordChapterBreakMessage rcbm = (RecordChapterBreakMessage) event;
+      meetingManager.stopStartAllRecordings(rcbm.meetingId);
     }
 
   }
@@ -202,7 +207,10 @@ public class EventListenerImp implements IEventListener {
 
 
   }
-  
+
+  public void setMeetingManager(MeetingManager meetingManager) {
+    this.meetingManager = meetingManager;
+  }
 
   public void setMessageSender(ConnectionInvokerService sender) {
     this.sender = sender;
diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/Red5AppAdapter.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/Red5AppAdapter.java
index ac7e46022893738bd814e29231c66dfb190c3844..394846d26fa8fe953a549f64d40bab365b738d00 100755
--- a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/Red5AppAdapter.java
+++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/Red5AppAdapter.java
@@ -34,9 +34,11 @@ import org.red5.server.api.stream.IServerStream;
 import org.red5.server.api.stream.IStreamListener;
 import org.red5.server.stream.ClientBroadcastStream;
 import org.slf4j.Logger;
-
+import org.red5.server.scheduling.QuartzSchedulingService;
 import com.google.gson.Gson;
-
+import org.bigbluebutton.app.screenshare.MeetingManager;
+import org.bigbluebutton.app.screenshare.VideoStreamListener;
+import org.bigbluebutton.app.screenshare.VideoStream;
 import org.bigbluebutton.app.screenshare.EventRecordingService;
 import org.bigbluebutton.app.screenshare.IScreenShareApplication;
 import org.bigbluebutton.app.screenshare.ScreenshareStreamListener;
@@ -44,21 +46,27 @@ import org.bigbluebutton.app.screenshare.ScreenshareStreamListener;
 public class Red5AppAdapter extends MultiThreadedApplicationAdapter {
   private static Logger log = Red5LoggerFactory.getLogger(Red5AppAdapter.class, "screenshare");
 
-  private EventRecordingService recordingService;
-  private final Map<String, IStreamListener> streamListeners = new HashMap<String, IStreamListener>();
+  // Scheduler
+  private QuartzSchedulingService scheduler;
 
+  private EventRecordingService recordingService;
   private IScreenShareApplication app;
   private String streamBaseUrl;
   private ConnectionInvokerService sender;
   private String recordingDirectory;
 
   private final Pattern STREAM_ID_PATTERN = Pattern.compile("(.*)-(.*)-(.*)$");
-  
+
+  private MeetingManager meetingManager;
+  private int packetTimeout = 10000;
+
   @Override
   public boolean appStart(IScope app) {
     super.appStart(app);
     log.info("BBB Screenshare appStart");
     sender.setAppScope(app);
+    // get the scheduler
+    scheduler = (QuartzSchedulingService) getContext().getBean(QuartzSchedulingService.BEAN_NAME);
     return true;
   }
 
@@ -148,12 +156,14 @@ public class Red5AppAdapter extends MultiThreadedApplicationAdapter {
         app.streamStarted(meetingId, streamId, url);
 
 	    boolean recordVideoStream = app.recordStream(meetingId, streamId);
-	    if (recordVideoStream) {
-	      recordStream(stream);
-	      ScreenshareStreamListener listener = new ScreenshareStreamListener(recordingService, recordingDirectory);
-	      stream.addStreamListener(listener);
-	      streamListeners.put(conn.getScope().getName() + "-" + stream.getPublishedName(), listener);
-	    }
+          VideoStreamListener listener = new VideoStreamListener(meetingId, streamId,
+                  recordVideoStream, recordingDirectory, packetTimeout, scheduler, recordingService);
+          ClientBroadcastStream cstream = (ClientBroadcastStream) this.getBroadcastStream(conn.getScope(), stream.getPublishedName());
+          stream.addStreamListener(listener);
+          VideoStream vstream = new VideoStream(stream, listener, cstream);
+          vstream.startRecording();
+
+          meetingManager.addStream(meetingId, vstream);
 
       Map<String, Object> logData = new HashMap<String, Object>();
       logData.put("meetingId", meetingId);
@@ -182,43 +192,12 @@ public class Red5AppAdapter extends MultiThreadedApplicationAdapter {
     String streamId = stream.getPublishedName();
     Matcher matcher = STREAM_ID_PATTERN.matcher(stream.getPublishedName());
     if (matcher.matches()) {
-        String meetingId = matcher.group(1).trim();
-        app.streamStopped(meetingId, streamId);
-
-        boolean recordVideoStream = app.recordStream(meetingId, streamId);
-        if (recordVideoStream) {
-          IConnection conn = Red5.getConnectionLocal();
-          String scopeName;
-          if (conn != null) {
-            scopeName = conn.getScope().getName();
-          } else {
-            log.info("Connection local was null, using scope name from the stream: {}", stream);
-            scopeName = stream.getScope().getName();
-          }
-          IStreamListener listener = streamListeners.remove(scopeName + "-" + stream.getPublishedName());
-          if (listener != null) {
-            stream.removeStreamListener(listener);
-          }
-
-          String filename = recordingDirectory;
-          if (!filename.endsWith("/")) {
-            filename.concat("/");
-          }
-
-          filename = filename.concat(meetingId).concat("/").concat(stream.getPublishedName()).concat(".flv");
-
-          long publishDuration = (System.currentTimeMillis() - stream.getCreationTime()) / 1000;
-
-          Map<String, String> event = new HashMap<String, String>();
-          event.put("module", "Deskshare");
-          event.put("timestamp", genTimestamp().toString());
-          event.put("meetingId", scopeName);
-          event.put("stream", stream.getPublishedName());
-          event.put("file", filename);
-          event.put("duration", new Long(publishDuration).toString());
-          event.put("eventName", "DeskshareStoppedEvent");
-          recordingService.record(scopeName, event);
-        }
+      String meetingId = matcher.group(1).trim();
+      app.streamStopped(meetingId, streamId);
+
+      boolean recordVideoStream = app.recordStream(meetingId, streamId);
+      meetingManager.streamBroadcastClose(meetingId, streamId);
+
 
       Map<String, Object> logData = new HashMap<String, Object>();
       logData.put("meetingId", meetingId);
@@ -234,27 +213,10 @@ public class Red5AppAdapter extends MultiThreadedApplicationAdapter {
     }
   }
 
-  /**
-   * A hook to record a stream. A file is written in webapps/video/streams/
-   * @param stream
-   */
-  private void recordStream(IBroadcastStream stream) {
-    IConnection conn = Red5.getConnectionLocal();
-    long now = System.currentTimeMillis();
-    String recordingStreamName = stream.getPublishedName(); // + "-" + now; /** Comment out for now...forgot why I added this - ralam */
-
-    try {
-      log.info("Recording stream " + recordingStreamName );
-      ClientBroadcastStream cstream = (ClientBroadcastStream) this.getBroadcastStream(conn.getScope(), stream.getPublishedName());
-      cstream.saveAs(recordingStreamName, false);
-    } catch(Exception e) {
-      log.error("ERROR while recording stream " + e.getMessage());
-      e.printStackTrace();
-    }
+  public void setMeetingManager(MeetingManager meetingManager) {
+    this.meetingManager = meetingManager;
   }
 
-
-
   public void setEventRecordingService(EventRecordingService s) {
     recordingService = s;
   }
diff --git a/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/redis/ReceivedJsonMsgHandlerActor.scala b/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/redis/ReceivedJsonMsgHandlerActor.scala
index 0e360cd810cf60dd08347d85ece9f94502339c94..7bc9e89f34ad0c3e18d7b5ee751e2fc4fee460cc 100755
--- a/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/redis/ReceivedJsonMsgHandlerActor.scala
+++ b/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/redis/ReceivedJsonMsgHandlerActor.scala
@@ -1,8 +1,8 @@
 package org.bigbluebutton.app.screenshare.redis
 
-import akka.actor.{Actor, ActorLogging, ActorRef, Props}
 import com.fasterxml.jackson.databind.JsonNode
-import org.bigbluebutton.app.screenshare.server.sessions.messages.{MeetingCreated, MeetingEnded}
+import org.bigbluebutton.app.screenshare.server.sessions.messages.{MeetingCreated, MeetingEnded, RecordingChapterBreak}
+import akka.actor.{Actor, ActorLogging, ActorRef, Props}
 
 import scala.reflect.runtime.universe._
 import org.bigbluebutton.common2.msgs._
@@ -56,6 +56,12 @@ class ReceivedJsonMsgHandlerActor(screenshareManager: ActorRef)
         } yield {
           screenshareManager ! new MeetingEnded(m.body.meetingId)
         }
+      case RecordingChapterBreakSysMsg.NAME =>
+        for {
+          m <- deserialize[RecordingChapterBreakSysMsg](jsonNode)
+        } yield {
+          screenshareManager ! new RecordingChapterBreak(m.body.meetingId, m.body.timestamp)
+        }
       case _ =>
        // log.error("Cannot route envelope name " + envelope.name)
       // do nothing
diff --git a/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/ScreenshareManager.scala b/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/ScreenshareManager.scala
index 5fbe4f31a5e9d4fcec37ed03c89c5d31e7975eea..d3cfbb370fd9efe1a48157a944c36a528e88e0da 100755
--- a/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/ScreenshareManager.scala
+++ b/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/ScreenshareManager.scala
@@ -18,11 +18,11 @@
  */
 package org.bigbluebutton.app.screenshare.server.sessions
 
-import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
 import org.bigbluebutton.app.screenshare.StreamInfo
 import org.bigbluebutton.app.screenshare.server.sessions.Session.StopSession
+import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
 import scala.collection.mutable.HashMap
-import org.bigbluebutton.app.screenshare.events.{IEventsMessageBus, IsScreenSharingResponse, ScreenShareRequestTokenFailedResponse}
+import org.bigbluebutton.app.screenshare.events.{IEventsMessageBus, IsScreenSharingResponse, RecordChapterBreakMessage, ScreenShareRequestTokenFailedResponse}
 import org.bigbluebutton.app.screenshare.server.sessions.messages._
 
 object ScreenshareManager {
@@ -57,10 +57,15 @@ class ScreenshareManager(val aSystem: ActorSystem, val bus: IEventsMessageBus)
     case msg: MeetingEnded             => handleMeetingHasEnded(msg)
     case msg: MeetingCreated              => handleMeetingCreated(msg)
     case msg: ClientPongMessage           => handleClientPongMessage(msg)
+    case msg: RecordingChapterBreak       => handleRecordingChapterBreak(msg)
 
     case msg: Any => log.warning("Unknown message " + msg)
   }
 
+  private def handleRecordingChapterBreak(msg: RecordingChapterBreak): Unit = {
+    bus.send(new RecordChapterBreakMessage(msg.meetingId, msg.timestamp))
+  }
+
   private def handleClientPongMessage(msg: ClientPongMessage) {
     if (log.isDebugEnabled) {
       log.debug("Received ClientPongMessage message for meeting=[" + msg.meetingId + "]")
diff --git a/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/messages/IMessage.scala b/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/messages/IMessage.scala
index 9819d807237dd969a5e531f3ee2dd47a9c227611..23cbcb2212b3b9e23982d789a4d8458bbdd8ee7e 100755
--- a/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/messages/IMessage.scala
+++ b/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/messages/IMessage.scala
@@ -47,4 +47,6 @@ case class MeetingEnded(meetingId: String)
 
 case class MeetingCreated(meetingId: String, record: Boolean)
 
-case class ClientPongMessage(meetingId: String, userId: String, streamId: String, timestamp: Long)
\ No newline at end of file
+case class ClientPongMessage(meetingId: String, userId: String, streamId: String, timestamp: Long)
+
+case class RecordingChapterBreak(meetingId: String, timestamp: Long)
\ No newline at end of file
diff --git a/bbb-screenshare/app/src/main/webapp/WEB-INF/red5-web.xml b/bbb-screenshare/app/src/main/webapp/WEB-INF/red5-web.xml
index 1773918626992aed94e15e4aa3e6ec59458e4e46..cab5891b7ea3e795dd5cb0cdb27310b8db5786f3 100755
--- a/bbb-screenshare/app/src/main/webapp/WEB-INF/red5-web.xml
+++ b/bbb-screenshare/app/src/main/webapp/WEB-INF/red5-web.xml
@@ -52,7 +52,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
     <property name="recordingDirectory" value="${recordingDirectory}"/>
     <property name="application" ref="screenShareApplication"/>
     <property name="messageSender" ref="connectionInvokerService"/>
+    <property name="meetingManager" ref="meetingManager"/>
   </bean>
+
+  <bean id="meetingManager" class="org.bigbluebutton.app.screenshare.MeetingManager"/>
   
   <bean id="screenshare.service" class="org.bigbluebutton.app.screenshare.red5.Red5AppService">
     <property name="appHandler" ref="red5AppHandler"/>
@@ -77,6 +80,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 
   <bean id="eventListenerImp" class="org.bigbluebutton.app.screenshare.red5.EventListenerImp">
     <property name="messageSender" ref="connectionInvokerService"/>
+    <property name="meetingManager" ref="meetingManager"/>
   </bean>
 
   <bean id="jnlpConfigurator" class="org.bigbluebutton.app.screenshare.server.servlet.JnlpConfigurator">
diff --git a/bbb-video/src/main/java/org/bigbluebutton/app/video/ConnectionInvokerService.java b/bbb-video/src/main/java/org/bigbluebutton/app/video/ConnectionInvokerService.java
new file mode 100755
index 0000000000000000000000000000000000000000..e1a68b223e0011df36fe86bec05c1756422c29fb
--- /dev/null
+++ b/bbb-video/src/main/java/org/bigbluebutton/app/video/ConnectionInvokerService.java
@@ -0,0 +1,172 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+* 
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+* 
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.app.video;
+
+import com.google.gson.Gson;
+import org.bigbluebutton.red5.pubsub.message.ClientMessage;
+import org.bigbluebutton.red5.pubsub.message.ValidateConnTokenRespMsg;
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.IConnection;
+import org.red5.server.api.scope.IScope;
+import org.red5.server.api.so.ISharedObject;
+import org.red5.server.api.so.ISharedObjectService;
+import org.red5.server.so.SharedObjectService;
+import org.red5.server.util.ScopeUtils;
+import org.slf4j.Logger;
+import org.slf4j.Marker;
+import org.slf4j.MarkerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.*;
+
+public class ConnectionInvokerService {
+  private static Logger log = Red5LoggerFactory.getLogger(ConnectionInvokerService.class, "video");
+
+  private final String CONN = "RED5-";
+  private static final int NTHREADS = 1;
+  private static final Executor exec = Executors.newFixedThreadPool(NTHREADS);
+  private static final ExecutorService runExec = Executors.newFixedThreadPool(3);
+
+  private BlockingQueue<ClientMessage> messages;
+  private volatile boolean sendMessages = false;
+  private IScope bbbAppScope;
+
+  private final long SEND_TIMEOUT = 5000000000L; // 5s
+
+  private Long lastMsgLengthLog = System.currentTimeMillis();
+
+  public ConnectionInvokerService() {
+    messages = new LinkedBlockingQueue<ClientMessage>();
+  }
+
+  public void setAppScope(IScope scope) {
+    bbbAppScope = scope;
+  }
+
+  public void start() {
+    sendMessages = true;
+    Runnable sender = new Runnable() {
+      public void run() {
+        while (sendMessages) {
+          ClientMessage message;
+          try {
+            if (System.currentTimeMillis() - lastMsgLengthLog > 60000) {
+              lastMsgLengthLog = System.currentTimeMillis();
+              log.info("Message queue length = " + messages.size());
+            }
+            message = messages.take();
+            if (log.isTraceEnabled()) {
+              log.trace("Took message from queue: " + message.getMessageName());
+            }
+            sendMessageToClient(message);
+            if (log.isTraceEnabled()) {
+              log.trace("Sent message to client: " + message.getMessageName());
+            }
+          } catch (Exception e) {
+            Marker sendingException = MarkerFactory.getMarker("SENDING_EXCEPTION");
+            log.error(sendingException, "Exception while sending message to client.", e);
+          }
+        }
+      }
+    };
+    exec.execute(sender);
+  }
+
+  public void stop() {
+    sendMessages = false;
+    runExec.shutdown();
+  }
+
+  public void sendMessage(final ClientMessage message) {
+    if (log.isTraceEnabled()) {
+      log.trace("Queue message: " + message.getMessageName());
+    }
+    messages.offer(message);
+  }
+
+  private void sendMessageToClient(ClientMessage message) {
+    if (message instanceof ValidateConnTokenRespMsg) {
+      handleValidateConnTokenRespMsg((ValidateConnTokenRespMsg) message);
+    }
+  }
+
+  private void handleValidateConnTokenRespMsg(ValidateConnTokenRespMsg msg) {
+    if (log.isTraceEnabled()) {
+      log.trace("Handle direct message: " + msg.getMessageName() + " conn=" + msg.connId);
+    }
+
+    IScope meetingScope = getScope(msg.meetingId);
+    if (meetingScope != null) {
+      String userId = msg.userId;
+      IConnection conn = getConnection(meetingScope, userId);
+      if (conn != null) {
+        if (conn.isConnected() && !msg.authzed) {
+          Map<String, Object> logData = new HashMap<String, Object>();
+          logData.put("meetingId", msg.meetingId);
+          logData.put("userId", userId);
+          logData.put("authzed", msg.authzed);
+          logData.put("app", "video");
+          logData.put("event", "close_unauthorized_connection");
+          logData.put("description", "Closing unauthorized connection.");
+
+          Gson gson = new Gson();
+          String logStr = gson.toJson(logData);
+
+          log.info("Closing unauthorized connection: data={}", logStr);
+          conn.close();
+        }
+      }
+    }
+  }
+
+  private IConnection getConnectionWithConnId(IScope scope, String connId) {
+    for (IConnection conn : scope.getClientConnections()) {
+      String connID = (String) conn.getSessionId();
+      if (connID != null && connID.equals(connId)) {
+        return conn;
+      }
+    }
+
+    log.warn("Failed to get connection for connId = " + connId);
+    return null;
+  }
+
+  private IConnection getConnection(IScope scope, String userId) {
+    for (IConnection conn : scope.getClientConnections()) {
+      String connID = (String) conn.getAttribute("USERID");
+      if (connID != null && connID.equals(userId)) {
+        return conn;
+      }
+    }
+
+    log.warn("Failed to get connection for userId = " + userId);
+    return null;
+  }
+
+  public IScope getScope(String meetingID) {
+    if (bbbAppScope != null) {
+      return bbbAppScope.getContext().resolveScope("video");
+    } else {
+      log.error("BigBlueButton Scope not initialized. No messages are going to the Flash client!");
+    }
+    
+    return null;
+  }
+}
diff --git a/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java b/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java
index e5232265cd073705601637de19312fa91b78deb8..d66101b725803063a9b395063722824af370ad2e 100755
--- a/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java
+++ b/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java
@@ -65,11 +65,14 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
     private final Map<String, VideoRotator> videoRotators = new HashMap<String, VideoRotator>();
 
     private MeetingManager meetingManager;
+    private ConnectionInvokerService connInvokerService;
 
     @Override
     public boolean appStart(IScope app) {
         super.appStart(app);
         log.info("BBB Video appStart");
+        connInvokerService.setAppScope(app);
+
         // get the scheduler
         scheduler = (QuartzSchedulingService) getContext().getBean(QuartzSchedulingService.BEAN_NAME);
         return true;
@@ -88,13 +91,18 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
             params = new Object[2];
             params[0] = "UNKNOWN-MEETING-ID";
             params[1] = "UNKNOWN-USER-ID";
+            params[2] = "UNKNOWN-AUTH-TOKEN";
         }
 
-        String meetingId = ((String) params[0]).toString();
+        String meetingId = connection.getScope().getName();
         String userId = ((String) params[1]).toString();
+        String authToken = ((String) params[2]).toString();
 
         Red5.getConnectionLocal().setAttribute("MEETING_ID", meetingId);
         Red5.getConnectionLocal().setAttribute("USERID", userId);
+        Red5.getConnectionLocal().setAttribute("AUTH_TOKEN", authToken);
+
+        publisher.validateConnAuthToken(meetingId, userId, authToken);
 
         String connType = getConnectionType(Red5.getConnectionLocal().getType());
         String sessionId = Red5.getConnectionLocal().getSessionId();
@@ -455,4 +463,8 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
             }
         }
     }
+
+    public void setConnInvokerService(ConnectionInvokerService connInvokerService) {
+        this.connInvokerService = connInvokerService;
+    }
 }
diff --git a/bbb-video/src/main/java/org/bigbluebutton/red5/pubsub/MeetingMessageHandler.java b/bbb-video/src/main/java/org/bigbluebutton/red5/pubsub/MeetingMessageHandler.java
index 48e7aa3d299c540124027d4d5dfd29c0d2e735a7..bbb12614ff59f0219fdedb61deace4d6ab04cdf5 100755
--- a/bbb-video/src/main/java/org/bigbluebutton/red5/pubsub/MeetingMessageHandler.java
+++ b/bbb-video/src/main/java/org/bigbluebutton/red5/pubsub/MeetingMessageHandler.java
@@ -2,8 +2,10 @@ package org.bigbluebutton.red5.pubsub;
 
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
+import org.bigbluebutton.app.video.ConnectionInvokerService;
 import org.bigbluebutton.app.video.MeetingManager;
 import org.bigbluebutton.red5.pubsub.message.RecordChapterBreakMessage;
+import org.bigbluebutton.red5.pubsub.message.ValidateConnTokenRespMsg;
 
 public class MeetingMessageHandler implements MessageHandler {
 
@@ -15,9 +17,15 @@ public class MeetingMessageHandler implements MessageHandler {
     private final String ENVELOPE = "envelope";
     private final String CORE = "core";
 
+    private final String USERID = "userId";
+    private final String AUTHZED = "authzed";
+    private final String CONN = "conn";
+
     private final String RecordingChapterBreakSysMsg = "RecordingChapterBreakSysMsg";
+    private final String ValidateConnAuthTokenSysRespMsg = "ValidateConnAuthTokenSysRespMsg";
 
     private MeetingManager meetingManager;
+    private ConnectionInvokerService connInvokerService;
 
     public void handleMessage(String pattern, String channel, String message) {
         JsonParser parser = new JsonParser();
@@ -41,10 +49,26 @@ public class MeetingMessageHandler implements MessageHandler {
                 RecordChapterBreakMessage chBreak = new RecordChapterBreakMessage(meetingId, timestamp);
                 meetingManager.stopStartAllRecordings(meetingId);
             }
+        } else if (ValidateConnAuthTokenSysRespMsg.equals(name)) {
+            if (body.has(MEETING_ID) && body.has(USERID)
+                    && body.has(AUTHZED) && body.has(CONN)) {
+                String meetingId = body.get(MEETING_ID).getAsString();
+                String userId = body.get(USERID).getAsString();
+                Boolean authzed = body.get(AUTHZED).getAsBoolean();
+                String conn = body.get(CONN).getAsString();
+                if (conn.equals("VIDEO")) {
+                    ValidateConnTokenRespMsg vctrm = new ValidateConnTokenRespMsg(meetingId, userId, authzed, conn);
+                    connInvokerService.sendMessage(vctrm);
+                }
+            }
         }
     }
 
     public void setMeetingManager(MeetingManager mgr) {
         this.meetingManager = mgr;
     }
+
+    public void setConnInvokerService(ConnectionInvokerService connInvokerService) {
+        this.connInvokerService = connInvokerService;
+    }
 }
diff --git a/bbb-video/src/main/java/org/bigbluebutton/red5/pubsub/MessagePublisher.java b/bbb-video/src/main/java/org/bigbluebutton/red5/pubsub/MessagePublisher.java
index 5b6de28e9828ec66f29d209317d1d7629d61d824..2ad2ecd9988ab4bc2ac0074ff39c4f53d27ef8b2 100755
--- a/bbb-video/src/main/java/org/bigbluebutton/red5/pubsub/MessagePublisher.java
+++ b/bbb-video/src/main/java/org/bigbluebutton/red5/pubsub/MessagePublisher.java
@@ -3,11 +3,10 @@ package org.bigbluebutton.red5.pubsub;
 import org.bigbluebutton.common.messages.MessagingConstants;
 import org.bigbluebutton.common.messages.UserSharedWebcamMessage;
 import org.bigbluebutton.common.messages.UserUnshareWebcamRequestMessage;
-
 import java.util.HashMap;
 import java.util.Map;
-
 import com.google.gson.Gson;
+import org.bigbluebutton.common2.msgs.*;
 
 public class MessagePublisher {
 
@@ -16,7 +15,40 @@ public class MessagePublisher {
 	public void setMessageSender(MessageSender sender) {
 		this.sender = sender;
 	}
-	
+
+	private Map<String, Object> buildEnvelope(String name, Map<String, String> routing) {
+		Map<String, Object> envelope = new HashMap<String, Object>();
+		envelope.put("name", name);
+		envelope.put("routing", routing);
+		return envelope;
+	}
+
+	private Map<String, String> buildRouting() {
+		Map<String, String> routing = new HashMap<String, String>();
+		routing.put("msgType", "SYSTEM");
+		routing.put("sender", "bbb-video");
+		return routing;
+	}
+
+	public void validateConnAuthToken(String meetingId, String userId, String authToken) {
+		BbbClientMsgHeader header = new BbbClientMsgHeader("ValidateConnAuthTokenSysMsg", meetingId, userId);
+		ValidateConnAuthTokenSysMsgBody body = new ValidateConnAuthTokenSysMsgBody(meetingId,
+				userId, authToken, "VIDEO");
+		ValidateConnAuthTokenSysMsg msg = new ValidateConnAuthTokenSysMsg(header, body);
+
+		Map<String, String> routing = buildRouting();
+		Map<String, Object> envelope = buildEnvelope("ValidateConnAuthTokenSysMsg", routing);
+
+		Map<String, Object> fullmsg = new HashMap<String, Object>();
+		fullmsg.put("envelope", envelope);
+		fullmsg.put("core", msg);
+
+		Gson gson = new Gson();
+		String json = gson.toJson(fullmsg);
+
+		sender.send("to-akka-apps-redis-channel", json);
+	}
+
 	// Polling 
 	public void userSharedWebcamMessage(String meetingId, String userId, String streamId) {
 		UserSharedWebcamMessage msg = new UserSharedWebcamMessage(meetingId, userId, streamId);
diff --git a/bbb-video/src/main/java/org/bigbluebutton/red5/pubsub/message/ClientMessage.java b/bbb-video/src/main/java/org/bigbluebutton/red5/pubsub/message/ClientMessage.java
new file mode 100755
index 0000000000000000000000000000000000000000..e96c2a079691bc8e58b1e2f024c3d96397ecd372
--- /dev/null
+++ b/bbb-video/src/main/java/org/bigbluebutton/red5/pubsub/message/ClientMessage.java
@@ -0,0 +1,25 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+* 
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+* 
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.red5.pubsub.message;
+
+
+public interface ClientMessage {
+
+    String getMessageName();
+}
diff --git a/bbb-video/src/main/java/org/bigbluebutton/red5/pubsub/message/ValidateConnTokenRespMsg.java b/bbb-video/src/main/java/org/bigbluebutton/red5/pubsub/message/ValidateConnTokenRespMsg.java
new file mode 100755
index 0000000000000000000000000000000000000000..10e2c8b09113d2ba158a7a2b6d69d8ad0dfac453
--- /dev/null
+++ b/bbb-video/src/main/java/org/bigbluebutton/red5/pubsub/message/ValidateConnTokenRespMsg.java
@@ -0,0 +1,20 @@
+package org.bigbluebutton.red5.pubsub.message;
+
+public class ValidateConnTokenRespMsg implements ClientMessage {
+
+    public final String meetingId;
+    public final String connId;
+    public final String userId;
+    public final Boolean authzed;
+
+    public ValidateConnTokenRespMsg(String meetingId, String userId, Boolean authzed, String connId) {
+        this.meetingId = meetingId;
+        this.connId = connId;
+        this.authzed = authzed;
+        this.userId = userId;
+    }
+
+    public String getMessageName() {
+        return "ValidateConnTokenRespMsg";
+    }
+}
diff --git a/bbb-video/src/main/webapp/WEB-INF/red5-web.xml b/bbb-video/src/main/webapp/WEB-INF/red5-web.xml
index b5a9854bb8cf52f730797e13bb2f7c76e221d47e..99342ccabc69412ba0debecb8fa262a60287c2e2 100755
--- a/bbb-video/src/main/webapp/WEB-INF/red5-web.xml
+++ b/bbb-video/src/main/webapp/WEB-INF/red5-web.xml
@@ -50,8 +50,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		<property name="eventRecordingService" ref="redisRecorder"/>
 		<property name="messagePublisher" ref="redisPublisher"/>
 		<property name="meetingManager" ref="meetingManager"/>
+		<property name="connInvokerService" ref="connInvokerService"/>
 	</bean>
 
+	<bean id="connInvokerService" class="org.bigbluebutton.app.video.ConnectionInvokerService"
+		  init-method="start" destroy-method="stop"/>
+
 	<bean id="meetingManager" class="org.bigbluebutton.app.video.MeetingManager"/>
 
     <bean id="redisPublisher" class="org.bigbluebutton.red5.pubsub.MessagePublisher">
@@ -82,6 +86,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 
 	<bean id="meetingMessageHandler" class="org.bigbluebutton.red5.pubsub.MeetingMessageHandler">
 		<property name="meetingManager" ref="meetingManager"/>
+		<property name="connInvokerService" ref="connInvokerService"/>
 	</bean>
 
 	<bean id="receivedMessageHandler" class="org.bigbluebutton.red5.pubsub.ReceivedMessageHandler"
diff --git a/bigbluebutton-apps/build.gradle b/bigbluebutton-apps/build.gradle
index 38de8618dc76055a13d95a805f1cced5831ecd2f..67871ae8ba5bf9c0b9970f5ad24ec8f734b454af 100755
--- a/bigbluebutton-apps/build.gradle
+++ b/bigbluebutton-apps/build.gradle
@@ -64,7 +64,7 @@ dependencies {
    providedCompile 'org.apache.commons:commons-lang3:3.6'
 
   compile 'org.bigbluebutton:bbb-common-message_2.12:0.0.19-SNAPSHOT'
-  compile 'org.bigbluebutton:bbb-apps-common_2.12:0.0.2'
+  compile 'org.bigbluebutton:bbb-apps-common_2.12:0.0.3-SNAPSHOT'
 }
 
 test {
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/PortTest.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/PortTest.as
index 501e118685ca4af6e7fb0e5077078ba6a0ed4527..f6b1b6877f49ef3c35626ef38ebcb2b6dea8600f 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/PortTest.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/PortTest.as
@@ -154,7 +154,8 @@ package org.bigbluebutton.main.model
         
         var curTime:Number = new Date().getTime();
 				// Create connection with the server.
-				nc.connect( this.baseURI, "portTestMeetingId-" + curTime, "portTestDummyUserId-" + curTime);
+				nc.connect( this.baseURI, "portTestMeetingId-" + curTime, 
+          "portTestDummyUserId-" + curTime, "portTestDummyToken-" + curTime);
 				status = "Connecting...";
 			} catch( e : ArgumentError ) {
 				// Invalid parameters.
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/business/VideoProxy.as b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/business/VideoProxy.as
index ec1341728c34e5e6bacc8905f4958650cd80a057..58c7b4c8c17d63f14820ffab265adfa596bbe3a2 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/business/VideoProxy.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/business/VideoProxy.as
@@ -29,14 +29,13 @@ package org.bigbluebutton.modules.videoconf.business
 	import flash.media.H264VideoStreamSettings;
 	import flash.net.NetConnection;
 	import flash.net.NetStream;
-	
 	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.UsersUtil;
 	import org.bigbluebutton.core.managers.ReconnectionManager;
-	import org.bigbluebutton.main.api.JSLog;
+	import org.bigbluebutton.core.model.LiveMeeting;
 	import org.bigbluebutton.main.events.BBBEvent;
 	import org.bigbluebutton.modules.videoconf.events.ConnectedEvent;
 	import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent;
@@ -82,7 +81,8 @@ package org.bigbluebutton.modules.videoconf.business
 		}
 		
 	    public function connect():void {
-	      nc.connect(_url, UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID());
+	      nc.connect(_url, UsersUtil.getInternalMeetingID(), 
+          UsersUtil.getMyUserID(), LiveMeeting.inst().me.authToken);
 	    }
 	    
 		private function onAsyncError(event:AsyncErrorEvent):void{