diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/api/IBigBlueButtonInGW.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/api/IBigBlueButtonInGW.java index 957eca1d1f00b9e4f1e49fdfbec3fe878c013549..3964e884ab78986f6c443b0f701dc2a5d9be3779 100755 --- a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/api/IBigBlueButtonInGW.java +++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/api/IBigBlueButtonInGW.java @@ -40,6 +40,7 @@ public interface IBigBlueButtonInGW { void userLeft(String meetingID, String userID, String sessionId); void userJoin(String meetingID, String userID, String authToken); void getCurrentPresenter(String meetingID, String requesterID); + void checkIfAllowedToShareDesktop(String meetingID, String userID); void assignPresenter(String meetingID, String newPresenterID, String newPresenterName, String assignedBy); void setRecordingStatus(String meetingId, String userId, Boolean recording); void getRecordingStatus(String meetingId, String userId); diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/UsersMessageReceiver.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/UsersMessageReceiver.java index 44382376de93478aab8b7379301f3d715fc721ad..a43ec10c7e3bbd69db0a21cce621b4318ca56a01 100755 --- a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/UsersMessageReceiver.java +++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/UsersMessageReceiver.java @@ -33,6 +33,9 @@ public class UsersMessageReceiver implements MessageHandler{ case UserLeavingMessage.USER_LEAVING: processUserLeavingMessage(message); break; + case AllowUserToShareDesktopRequest.NAME: + processAllowUserToShareDesktopRequest(message); + break; case AssignPresenterRequestMessage.ASSIGN_PRESENTER_REQUEST: processAssignPresenterRequestMessage(message); break; @@ -193,7 +196,14 @@ public class UsersMessageReceiver implements MessageHandler{ bbbInGW.userLeft(ulm.meetingId, ulm.userId, ulm.meetingId); } } - + + private void processAllowUserToShareDesktopRequest(String message) { + AllowUserToShareDesktopRequest msg = AllowUserToShareDesktopRequest.fromJson(message); + if (msg != null) { + bbbInGW.checkIfAllowedToShareDesktop(msg.meetingId, msg.userId); + } + } + private void processAssignPresenterRequestMessage(String message) { AssignPresenterRequestMessage apm = AssignPresenterRequestMessage.fromJson(message); if (apm != null) { diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala index 508011e47fea43eda6fed683a05c162a5915688d..37eacf898d8559f4889402466c21ad712467d868 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala @@ -243,6 +243,11 @@ class BigBlueButtonInGW( eventBus.publish(BigBlueButtonEvent(meetingID, new UserJoining(meetingID, userID, authToken))) } + def checkIfAllowedToShareDesktop(meetingID: String, userID: String): Unit = { + eventBus.publish(BigBlueButtonEvent(meetingID, AllowUserToShareDesktop(meetingID: String, + userID: String))) + } + def assignPresenter(meetingID: String, newPresenterID: String, newPresenterName: String, assignedBy: String): Unit = { eventBus.publish(BigBlueButtonEvent(meetingID, new AssignPresenter(meetingID, newPresenterID, newPresenterName, assignedBy))) } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/LiveMeeting.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/LiveMeeting.scala index 8d5e313e3fbaeaf4a1e72234820d7d90e65d649b..51da9d7816ca4174ed58b84f2ee5ab579195f7e0 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/LiveMeeting.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/LiveMeeting.scala @@ -125,6 +125,16 @@ class LiveMeeting(val mProps: MeetingProperties, outGW.send(new DisconnectAllUsers(msg.meetingId)) } + def handleAllowUserToShareDesktop(msg: AllowUserToShareDesktop): Unit = { + usersModel.getCurrentPresenter() match { + case Some(curPres) => { + val allowed = msg.userID equals (curPres.userID) + outGW.send(AllowUserToShareDesktopOut(msg.meetingID, msg.userID, allowed)) + } + case None => // do nothing + } + } + def handleVoiceConfRecordingStartedMessage(msg: VoiceConfRecordingStartedMessage) { if (msg.recording) { meetingModel.setVoiceRecordingFilename(msg.recordStream) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala index 72d17227ea32d9700456ccb0fe16db0d605d77ff..c3a67357ddf95c55d19cc5f7dc4fa4bcf0bdc683 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala @@ -105,6 +105,7 @@ class MeetingActor(val mProps: MeetingProperties, case msg: UserJoining => liveMeeting.handleUserJoin(msg) case msg: UserLeaving => liveMeeting.handleUserLeft(msg) case msg: AssignPresenter => liveMeeting.handleAssignPresenter(msg) + case msg: AllowUserToShareDesktop => liveMeeting.handleAllowUserToShareDesktop(msg) case msg: GetUsers => liveMeeting.handleGetUsers(msg) case msg: ChangeUserStatus => liveMeeting.handleChangeUserStatus(msg) case msg: EjectUserFromMeeting => liveMeeting.handleEjectUserFromMeeting(msg) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MessageSenderActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MessageSenderActor.scala index 46c7bda4ceb3205ecf93e76b3fb806a09390443c..e587c3c24011d4b15c3bd9fefec524eb6627766f 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MessageSenderActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MessageSenderActor.scala @@ -15,7 +15,9 @@ import org.bigbluebutton.core.pubsub.senders.CaptionMessageToJsonConverter import org.bigbluebutton.core.pubsub.senders.DeskShareMessageToJsonConverter import org.bigbluebutton.common.messages.GetPresentationInfoReplyMessage import org.bigbluebutton.common.messages.PresentationRemovedMessage +import org.bigbluebutton.common.messages.AllowUserToShareDesktopReply import org.bigbluebutton.core.apps.Page + import collection.JavaConverters._ import scala.collection.JavaConversions._ import org.bigbluebutton.core.apps.SimplePollResultOutVO @@ -31,6 +33,7 @@ import org.bigbluebutton.common.messages.LockLayoutMessage import org.bigbluebutton.core.pubsub.senders.WhiteboardMessageToJsonConverter import org.bigbluebutton.common.converters.ToJsonEncoder import org.bigbluebutton.common.messages.TransferUserToVoiceConfRequestMessage +import org.bigbluebutton.core object MessageSenderActor { def props(msgSender: MessageSender): Props = @@ -82,6 +85,7 @@ class MessageSenderActor(val service: MessageSender) case msg: MeetingMuted => handleMeetingMuted(msg) case msg: MeetingState => handleMeetingState(msg) case msg: DisconnectAllUsers => handleDisconnectAllUsers(msg) + case msg: AllowUserToShareDesktopOut => handleAllowUserToShareDesktopOut(msg) case msg: DisconnectUser => handleDisconnectUser(msg) case msg: PermissionsSettingInitialized => handlePermissionsSettingInitialized(msg) case msg: NewPermissionsSetting => handleNewPermissionsSetting(msg) @@ -535,6 +539,13 @@ class MessageSenderActor(val service: MessageSender) service.send(MessagingConstants.FROM_MEETING_CHANNEL, json) } + private def handleAllowUserToShareDesktopOut(msg: AllowUserToShareDesktopOut): Unit = { + val obj = new AllowUserToShareDesktopReply(msg.meetingID, msg.userID, msg.allowed, + TimestampGenerator.generateTimestamp) + val json = obj.toJson() + service.send(MessagingConstants.FROM_MEETING_CHANNEL, json) + } + private def handlePermissionsSettingInitialized(msg: PermissionsSettingInitialized) { val json = UsersMessageToJsonConverter.permissionsSettingInitializedToJson(msg) service.send(MessagingConstants.FROM_MEETING_CHANNEL, json) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/InMessages.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/InMessages.scala index 2fb1ab82d96e65946c8b1b9b3353af374fe7dd86..bacab94d0baf2dc984fcdc47a894b047f4101044 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/InMessages.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/InMessages.scala @@ -90,6 +90,7 @@ case class ChangeUserStatus(meetingID: String, userID: String, status: String, v case class AssignPresenter(meetingID: String, newPresenterID: String, newPresenterName: String, assignedBy: String) extends InMessage case class SetRecordingStatus(meetingID: String, userId: String, recording: Boolean) extends InMessage case class GetRecordingStatus(meetingID: String, userId: String) extends InMessage +case class AllowUserToShareDesktop(meetingID: String, userID: String) extends InMessage ////////////////////////////////////////////////////////////////////////////////// // Chat diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/OutMessages.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/OutMessages.scala index 7ae93d2803377569b470a83c0660aed7c64f4baa..d3c9588ac5ec22414c4041def951bf4d0d8e905d 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/OutMessages.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/OutMessages.scala @@ -73,6 +73,7 @@ case class EjectVoiceUser(meetingID: String, recorded: Boolean, requesterID: Str case class TransferUserToMeeting(voiceConfId: String, targetVoiceConfId: String, userId: String) extends IOutMessage case class UserJoinedVoice(meetingID: String, recorded: Boolean, confNum: String, user: UserVO) extends IOutMessage case class UserLeftVoice(meetingID: String, recorded: Boolean, confNum: String, user: UserVO) extends IOutMessage +case class AllowUserToShareDesktopOut(meetingID: String, userID: String, allowed: Boolean) extends IOutMessage // Voice case class IsMeetingMutedReply(meetingID: String, recorded: Boolean, requesterID: String, meetingMuted: Boolean) extends IOutMessage diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/AllowUserToShareDesktopReply.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/AllowUserToShareDesktopReply.java new file mode 100644 index 0000000000000000000000000000000000000000..cbe769de7d684c5a052c2ecfc824c8ee6d0cf058 --- /dev/null +++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/AllowUserToShareDesktopReply.java @@ -0,0 +1,66 @@ +package org.bigbluebutton.common.messages; + +import java.util.HashMap; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class AllowUserToShareDesktopReply implements ISubscribedMessage { + public static final String NAME = "AllowUserToShareDesktopReply"; + public static final String VERSION = "0.0.1"; + + public static final String TIMESTAMP = "timestamp"; + public static final String MEETING_ID = "meeting_id"; + public static final String USER_ID = "user_id"; + public static final String ALLOWED = "allowed"; + + public final Long timestamp; + public final String userId; + public final String meetingId; + public final Boolean allowed; + + public AllowUserToShareDesktopReply(String meetingId, String userId, + Boolean allowed, Long timestamp) { + this.meetingId = meetingId; + this.userId = userId; + this.allowed = allowed; + this.timestamp = timestamp; + } + + public String toJson() { + HashMap<String, Object> payload = new HashMap<String, Object>(); + payload.put(TIMESTAMP, timestamp); + payload.put(MEETING_ID, meetingId); + payload.put(USER_ID, userId); + payload.put(ALLOWED, allowed); + + java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(NAME, VERSION, null); + return MessageBuilder.buildJson(header, payload); + } + + public static AllowUserToShareDesktopReply fromJson(String message) { + JsonParser parser = new JsonParser(); + JsonObject obj = (JsonObject) parser.parse(message); + if (obj.has("header") && obj.has("payload")) { + JsonObject header = (JsonObject) obj.get("header"); + JsonObject payload = (JsonObject) obj.get("payload"); + + if (header.has("name")) { + String messageName = header.get("name").getAsString(); + if (NAME.equals(messageName)) { + + if (payload.has(TIMESTAMP) && payload.has(MEETING_ID) + && payload.has(USER_ID) && payload.has(ALLOWED)) { + Long timestamp = payload.get(TIMESTAMP).getAsLong(); + String meetingId = payload.get(MEETING_ID).getAsString(); + String userId = payload.get(USER_ID).getAsString(); + Boolean allowed = payload.get(ALLOWED).getAsBoolean(); + return new AllowUserToShareDesktopReply(meetingId, userId, allowed, + timestamp); + } + } + } + } + return null; + } +} diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/AllowUserToShareDesktopRequest.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/AllowUserToShareDesktopRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..f35fb98cc12114c109b3d6cce9c5e221dff61f48 --- /dev/null +++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/AllowUserToShareDesktopRequest.java @@ -0,0 +1,58 @@ +package org.bigbluebutton.common.messages; + +import java.util.HashMap; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class AllowUserToShareDesktopRequest implements ISubscribedMessage { + public static final String NAME = "AllowUserToShareDesktopRequest"; + public static final String VERSION = "0.0.1"; + + public static final String TIMESTAMP = "timestamp"; + public static final String MEETING_ID = "meeting_id"; + public static final String USER_ID = "user_id"; + + public final Long timestamp; + public final String userId; + public final String meetingId; + + public AllowUserToShareDesktopRequest(String meetingId, String userId, Long timestamp) { + this.meetingId = meetingId; + this.userId = userId; + this.timestamp = timestamp; + } + + public String toJson() { + HashMap<String, Object> payload = new HashMap<String, Object>(); + payload.put(TIMESTAMP, timestamp); + payload.put(MEETING_ID, meetingId); + payload.put(USER_ID, userId); + + java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(NAME, VERSION, null); + return MessageBuilder.buildJson(header, payload); + } + + public static AllowUserToShareDesktopRequest fromJson(String message) { + JsonParser parser = new JsonParser(); + JsonObject obj = (JsonObject) parser.parse(message); + if (obj.has("header") && obj.has("payload")) { + JsonObject header = (JsonObject) obj.get("header"); + JsonObject payload = (JsonObject) obj.get("payload"); + + if (header.has("name")) { + String messageName = header.get("name").getAsString(); + if (NAME.equals(messageName)) { + + if (payload.has(TIMESTAMP) && payload.has(MEETING_ID) && payload.has(USER_ID)) { + Long timestamp = payload.get(TIMESTAMP).getAsLong(); + String meetingId = payload.get(MEETING_ID).getAsString(); + String userId = payload.get(USER_ID).getAsString(); + return new AllowUserToShareDesktopRequest(meetingId, userId, timestamp); + } + } + } + } + return null; + } +} diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MeetingCreatedMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MeetingCreatedMessage.java new file mode 100755 index 0000000000000000000000000000000000000000..02db9d0a6db17c60fdd7515340f7680f687d0193 --- /dev/null +++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MeetingCreatedMessage.java @@ -0,0 +1,49 @@ +package org.bigbluebutton.common.messages; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import java.util.HashMap; + +public class MeetingCreatedMessage implements ISubscribedMessage { + public static final String MEETING_CREATED = "meeting_created_message"; + public final String VERSION = "0.0.1"; + + public final String meetingId; + + public MeetingCreatedMessage(String meetingID) { + this.meetingId = meetingID; + } + + public String toJson() { + HashMap<String, Object> payload = new HashMap<String, Object>(); + payload.put(Constants.MEETING_ID, meetingId); + + HashMap<String, Object> header = MessageBuilder.buildHeader(MEETING_CREATED, VERSION, null); + + return MessageBuilder.buildJson(header, payload); + } + + public static MeetingCreatedMessage fromJson(String message) { + JsonParser parser = new JsonParser(); + JsonObject obj = (JsonObject) parser.parse(message); + + if (obj.has("header") && obj.has("payload")) { + JsonObject header = (JsonObject) obj.get("header"); + JsonObject payload = (JsonObject) obj.get("payload"); + + if (header.has("name")) { + String messageName = header.get("name").getAsString(); + if (MEETING_CREATED.equals(messageName)) { + if (payload.has(Constants.MEETING_ID)) { + String meetingId = payload.get(Constants.MEETING_ID).getAsString(); + + return new MeetingCreatedMessage(meetingId); + } + } + } + } + + return null; + } +} diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MeetingDestroyedMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MeetingDestroyedMessage.java new file mode 100755 index 0000000000000000000000000000000000000000..689233dc8e7f04fe9423e51d2f5e63d8f25c87ef --- /dev/null +++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MeetingDestroyedMessage.java @@ -0,0 +1,49 @@ +package org.bigbluebutton.common.messages; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import java.util.HashMap; + +public class MeetingDestroyedMessage implements ISubscribedMessage { + public static final String NAME = "meeting_destroyed_event"; + public final String VERSION = "0.0.1"; + + public final String meetingId; + + public MeetingDestroyedMessage(String meetingID) { + this.meetingId = meetingID; + } + + public String toJson() { + HashMap<String, Object> payload = new HashMap<String, Object>(); + payload.put(Constants.MEETING_ID, meetingId); + + HashMap<String, Object> header = MessageBuilder.buildHeader(NAME, VERSION, null); + + return MessageBuilder.buildJson(header, payload); + } + + public static MeetingDestroyedMessage fromJson(String message) { + JsonParser parser = new JsonParser(); + JsonObject obj = (JsonObject) parser.parse(message); + + if (obj.has("header") && obj.has("payload")) { + JsonObject header = (JsonObject) obj.get("header"); + JsonObject payload = (JsonObject) obj.get("payload"); + + if (header.has("name")) { + String messageName = header.get("name").getAsString(); + if (NAME.equals(messageName)) { + if (payload.has(Constants.MEETING_ID)) { + String meetingId = payload.get(Constants.MEETING_ID).getAsString(); + + return new MeetingDestroyedMessage(meetingId); + } + } + } + } + + return null; + } +} diff --git a/bbb-screenshare/app/build.sbt b/bbb-screenshare/app/build.sbt index 1443d205fa233f7c3e902c0f5833c97651401c49..c1a489f77218274e048177bbdcf3600de18b039b 100644 --- a/bbb-screenshare/app/build.sbt +++ b/bbb-screenshare/app/build.sbt @@ -7,7 +7,6 @@ organization := "org.bigbluebutton" version := "0.0.1" -//scalaVersion := "2.11.6" scalaVersion := "2.11.7" scalacOptions ++= Seq( @@ -16,7 +15,7 @@ scalacOptions ++= Seq( "-Xlint", "-Ywarn-dead-code", "-language:_", - "-target:jvm-1.8", //TODO this was 1.7 + "-target:jvm-1.8", "-encoding", "UTF-8" ) @@ -34,7 +33,6 @@ publishTo := Some(Resolver.file("file", new File(Path.userHome.absolutePath+"/d retrieveManaged := true libraryDependencies ++= { -// val akkaVersion = "2.3.11" val akkaVersion = "2.4.2" val springVersion = "4.2.5.RELEASE" Seq( @@ -49,15 +47,16 @@ libraryDependencies ++= { "commons-codec" % "commons-codec" % "1.8", "redis.clients" % "jedis" % "2.7.2", // "org.apache.commons" % "commons-lang3" % "3.2", + "org.apache.commons" % "commons-pool2" % "2.3", "org.red5" % "red5-server" % "1.0.7-M10", - "com.google.code.gson" % "gson" % "1.7.1", - + "com.google.code.gson" % "gson" % "2.5", "org.springframework" % "spring-web" % springVersion, "org.springframework" % "spring-beans" % springVersion, "org.springframework" % "spring-context" % springVersion, "org.springframework" % "spring-core" % springVersion, "org.springframework" % "spring-webmvc" % springVersion, "org.springframework" % "spring-aop" % springVersion, + "org.bigbluebutton" % "bbb-common-message"% "0.0.18-SNAPSHOT", "javax.servlet" % "servlet-api" % "2.5" @@ -92,4 +91,3 @@ daemonUser in Linux := user // group which will execute the application daemonGroup in Linux := group - diff --git a/bbb-screenshare/app/deploy.sh b/bbb-screenshare/app/deploy.sh index 5c1e81a5afa1c932503847ef6e58f379ce6f831a..47103026e68002accff2248f344b9def3ad109df 100755 --- a/bbb-screenshare/app/deploy.sh +++ b/bbb-screenshare/app/deploy.sh @@ -1,8 +1,3 @@ -##!/usr/bin/env bash -#sudo chmod -R 777 /usr/share/red5/webapps -#gradle clean war deploy -#sudo chmod -R 777 /usr/share/red5/webapps - #!/bin/bash # deploying 'screenshare' to /usr/share/red5/webapps @@ -20,9 +15,11 @@ sudo cp ~/dev/bigbluebutton/bbb-screenshare/app/target/webapp/WEB-INF/lib/bbb-sc ~/dev/bigbluebutton/bbb-screenshare/app/target/webapp/WEB-INF/lib/scala-library-* \ ~/dev/bigbluebutton/bbb-screenshare/app/target/webapp/WEB-INF/lib/akka-* \ ~/dev/bigbluebutton/bbb-screenshare/app/target/webapp/WEB-INF/lib/config-1.3.0.jar \ - ~/dev/bigbluebutton/bbb-screenshare/app/target/webapp/WEB-INF/lib/gson-1.7.1.jar \ + ~/dev/bigbluebutton/bbb-screenshare/app/target/webapp/WEB-INF/lib/gson-2.5.jar \ ~/dev/bigbluebutton/bbb-screenshare/app/target/webapp/WEB-INF/lib/jedis-2.7.2.jar \ + ~/dev/bigbluebutton/bbb-screenshare/app/target/webapp/WEB-INF/lib/commons-pool2-2.3.jar \ ~/dev/bigbluebutton/bbb-screenshare/app/target/webapp/WEB-INF/lib/spring-webmvc-4.2.5.RELEASE.jar \ + ~/dev/bigbluebutton/bbb-screenshare/app/target/webapp/WEB-INF/lib/bbb-common-message-0.0.18-SNAPSHOT.jar \ /usr/share/red5/webapps/screenshare/WEB-INF/lib/ @@ -43,3 +40,8 @@ sudo chown -R red5:red5 /usr/share/red5/webapps/screenshare # TODO change the owner username to 'firstuser' +# // Dev only +#sudo service red5 restart +#sudo service tomcat7 restart +#sudo service bbb-apps-akka restart + diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/IScreenShareApplication.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/IScreenShareApplication.java index 1923906f319605d1f890028dd55d22c0dcfccb07..0772e4f0d2660869b75a65e90337da8b71661fbd 100755 --- a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/IScreenShareApplication.java +++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/IScreenShareApplication.java @@ -1,10 +1,17 @@ package org.bigbluebutton.app.screenshare; + +import org.bigbluebutton.app.screenshare.events.IsScreenSharingResponse; + public interface IScreenShareApplication { - IsScreenSharingResponse isScreenSharing(String meetingId); + ScreenShareInfoResponse getScreenShareInfo(String meetingId, String token); - StartShareRequestResponse startShareRequest(String meetingId, String userId, Boolean record); + SharingStatus getSharingStatus(String meetingId, String streamId); + Boolean recordStream(String meetingId, String streamId); + + void isScreenSharing(String meetingId, String userId); + void startShareRequest(String meetingId, String userId, Boolean record); void pauseShareRequest(String meetingId, String userId, String streamId); void restartShareRequest(String meetingId, String userId); void stopShareRequest(String meetingId, String streamId); @@ -13,8 +20,8 @@ public interface IScreenShareApplication { void sharingStarted(String meetingId, String streamId, Integer width, Integer height); void sharingStopped(String meetingId, String streamId); void updateShareStatus(String meetingId, String streamId, Integer seqNum); - SharingStatus getSharingStatus(String meetingId, String streamId); - Boolean recordStream(String meetingId, String streamId); void userDisconnected(String meetingId, String userId); void userConnected(String meetingId, String userId); + void meetingHasEnded(String meetingId); + void meetingCreated(String meetingId); } diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/IsScreenSharingResponse.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/IsScreenSharingResponse.java deleted file mode 100755 index 2cab8dea76454735b89183d102ca432746c6d837..0000000000000000000000000000000000000000 --- a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/IsScreenSharingResponse.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.bigbluebutton.app.screenshare; - -public class IsScreenSharingResponse { - - public final StreamInfo info; - public final Error error; - - public IsScreenSharingResponse(StreamInfo info, Error error) { - this.info = info; - this.error = error; - } -} diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/StartShareRequestResponse.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/StartShareRequestResponse.java deleted file mode 100755 index 36faab1a3cc95aefc28416ec4e55ee103a57606d..0000000000000000000000000000000000000000 --- a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/StartShareRequestResponse.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.bigbluebutton.app.screenshare; - -public class StartShareRequestResponse { - - public final String token; - public final String jnlp; - public final String streamId; - public final Error error; - - public StartShareRequestResponse(String token, String jnlp, String streamId, Error error) { - this.token = token; - this.jnlp = jnlp; - this.streamId = streamId; - this.error = error; - } -} diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/events/IsScreenSharingResponse.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/events/IsScreenSharingResponse.java new file mode 100755 index 0000000000000000000000000000000000000000..699409caca63bfbffe5f33160fd5ebacbbf73cfe --- /dev/null +++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/events/IsScreenSharingResponse.java @@ -0,0 +1,18 @@ +package org.bigbluebutton.app.screenshare.events; + +import org.bigbluebutton.app.screenshare.Error; +import org.bigbluebutton.app.screenshare.StreamInfo; + +public class IsScreenSharingResponse implements IEvent { + + public final String meetingId; + public final String userId; + + public final StreamInfo info; + + public IsScreenSharingResponse(String meetingId, String userId, StreamInfo info) { + this.meetingId = meetingId; + this.userId = userId; + this.info = info; + } +} diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/events/StartShareRequestFailedResponse.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/events/StartShareRequestFailedResponse.java new file mode 100755 index 0000000000000000000000000000000000000000..6d82ed0ad9cbb37e85a771d4c823fcfe9ddba9f9 --- /dev/null +++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/events/StartShareRequestFailedResponse.java @@ -0,0 +1,14 @@ +package org.bigbluebutton.app.screenshare.events; + +public class StartShareRequestFailedResponse implements IEvent { + + public final String meetingId; + public final String userId; + public final String reason; + + public StartShareRequestFailedResponse(String meetingId, String userId, String reason) { + this.meetingId = meetingId; + this.userId = userId; + this.reason = reason; + } +} diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/events/StartShareRequestResponse.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/events/StartShareRequestResponse.java new file mode 100755 index 0000000000000000000000000000000000000000..65fdaa2b5460fcf2fb8c2e7d8ecc1d950e8c3bc7 --- /dev/null +++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/events/StartShareRequestResponse.java @@ -0,0 +1,20 @@ +package org.bigbluebutton.app.screenshare.events; + +import org.bigbluebutton.app.screenshare.Error; + +public class StartShareRequestResponse implements IEvent { + + public final String meetingId; + public final String userId; + public final String token; + public final String jnlp; + public final String streamId; + + public StartShareRequestResponse(String meetingId, String userId, String token, String jnlp, String streamId) { + this.meetingId = meetingId; + this.userId = userId; + this.token = token; + this.jnlp = jnlp; + this.streamId = streamId; + } +} diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MeetingMessageHandler.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MeetingMessageHandler.java index e4bf6fd309e761a3ea532cd608f57ebb587432ed..c6551880999c72e385bccd3e5cd2f2f3099e2579 100755 --- a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MeetingMessageHandler.java +++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MeetingMessageHandler.java @@ -6,7 +6,7 @@ import java.util.Map; import org.red5.logging.Red5LoggerFactory; import org.slf4j.Logger; import com.google.gson.Gson; - +import org.bigbluebutton.common.messages.MessagingConstants; public class MeetingMessageHandler implements MessageHandler { private static Logger log = Red5LoggerFactory.getLogger(MeetingMessageHandler.class, "screenshare"); diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MessageReceiver.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MessageReceiver.java index a59df4c096472a43d3737d45c436b4282b286861..5747fe5406481ccc47fc9d621c2599ccfe3a142e 100755 --- a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MessageReceiver.java +++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MessageReceiver.java @@ -2,87 +2,107 @@ package org.bigbluebutton.app.screenshare.messaging.redis; import java.util.concurrent.Executor; import java.util.concurrent.Executors; + +import org.bigbluebutton.common.messages.MessagingConstants; import org.red5.logging.Red5LoggerFactory; import org.slf4j.Logger; + import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPubSub; +import redis.clients.jedis.exceptions.JedisConnectionException; public class MessageReceiver { - private static Logger log = Red5LoggerFactory.getLogger(MessageReceiver.class, "bigbluebutton"); - - private ReceivedMessageHandler handler; - - private JedisPool redisPool; - private volatile boolean receiveMessage = false; - - private final Executor msgReceiverExec = Executors.newSingleThreadExecutor(); - - public void stop() { - receiveMessage = false; - } - - public void start() { - log.info("Ready to receive messages from Redis pubsub."); - try { - receiveMessage = true; - final Jedis jedis = redisPool.getResource(); - - Runnable messageReceiver = new Runnable() { - public void run() { - if (receiveMessage) { - jedis.psubscribe(new PubSubListener(), MessagingConstants.TO_BBB_APPS_PATTERN); - } - } - }; - msgReceiverExec.execute(messageReceiver); - } catch (Exception e) { - log.error("Error subscribing to channels: " + e.getMessage()); - } - } - - public void setRedisPool(JedisPool redisPool){ - this.redisPool = redisPool; - } - - public void setMessageHandler(ReceivedMessageHandler handler) { - this.handler = handler; - } - - private class PubSubListener extends JedisPubSub { - - public PubSubListener() { - super(); - } - - @Override - public void onMessage(String channel, String message) { - // Not used. - } - - @Override - public void onPMessage(String pattern, String channel, String message) { - handler.handleMessage(pattern, channel, message); - } - - @Override - public void onPSubscribe(String pattern, int subscribedChannels) { - log.debug("Subscribed to the pattern: " + pattern); - } - - @Override - public void onPUnsubscribe(String pattern, int subscribedChannels) { - // Not used. - } - - @Override - public void onSubscribe(String channel, int subscribedChannels) { - // Not used. - } - - @Override - public void onUnsubscribe(String channel, int subscribedChannels) { - // Not used. - } - } + private static Logger log = Red5LoggerFactory.getLogger(MessageReceiver.class, "screenshare"); + + private ReceivedMessageHandler handler; + + private Jedis jedis; + private volatile boolean receiveMessage = false; + + private final Executor msgReceiverExec = Executors.newSingleThreadExecutor(); + + private String host; + private int port; + + public void stop() { + receiveMessage = false; + } + + public void start() { + log.info("Ready to receive messages from Redis pubsub."); + try { + receiveMessage = true; + jedis = new Jedis(host, port); + // Set the name of this client to be able to distinguish when doing + // CLIENT LIST on redis-cli + jedis.clientSetname("bbb-screenshare"); + + Runnable messageReceiver = new Runnable() { + public void run() { + if (receiveMessage) { + try { + jedis.psubscribe(new PubSubListener(), + MessagingConstants.FROM_BBB_APPS_PATTERN); + } catch(JedisConnectionException ex) { + log.warn("Exception on Jedis connection. Resubscribing to pubsub."); + start(); + } + + } + } + }; + msgReceiverExec.execute(messageReceiver); + } catch (Exception e) { + log.error("Error subscribing to channels: " + e.getMessage()); + } + } + + public void setHost(String host){ + this.host = host; + } + + public void setPort(int port) { + this.port = port; + } + + public void setMessageHandler(ReceivedMessageHandler handler) { + this.handler = handler; + } + + private class PubSubListener extends JedisPubSub { + + public PubSubListener() { + super(); + } + + @Override + public void onMessage(String channel, String message) { + // Not used. + } + + @Override + public void onPMessage(String pattern, String channel, String message) { + handler.handleMessage(pattern, channel, message); + } + + @Override + public void onPSubscribe(String pattern, int subscribedChannels) { + log.debug("Subscribed to the pattern: " + pattern); + } + + @Override + public void onPUnsubscribe(String pattern, int subscribedChannels) { + // Not used. + } + + @Override + public void onSubscribe(String channel, int subscribedChannels) { + // Not used. + } + + @Override + public void onUnsubscribe(String channel, int subscribedChannels) { + // Not used. + } + } } diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MessageSender.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MessageSender.java index 18067a0a986a34ae5b7440e0c90decafeb8ef410..182ab1dac605fa0b6cdc2e7216ab476de0afecdc 100755 --- a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MessageSender.java +++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MessageSender.java @@ -4,71 +4,99 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; + +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.red5.logging.Red5LoggerFactory; import org.slf4j.Logger; + import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; +import redis.clients.jedis.Protocol; public class MessageSender { - private static Logger log = Red5LoggerFactory.getLogger(MessageSender.class, "bigbluebutton"); - - private JedisPool redisPool; - private volatile boolean sendMessage = false; - - private final Executor msgSenderExec = Executors.newSingleThreadExecutor(); - private final Executor runExec = Executors.newSingleThreadExecutor(); - private BlockingQueue<MessageToSend> messages = new LinkedBlockingQueue<MessageToSend>(); - - public void stop() { - sendMessage = false; - } - - public void start() { - log.info("Redis message publisher starting!"); - try { - sendMessage = true; - - Runnable messageSender = new Runnable() { - public void run() { - while (sendMessage) { - try { - MessageToSend msg = messages.take(); - publish(msg.getChannel(), msg.getMessage()); - } catch (InterruptedException e) { - log.warn("Failed to get message from queue."); - } - } - } - }; - msgSenderExec.execute(messageSender); - } catch (Exception e) { - log.error("Error subscribing to channels: " + e.getMessage()); - } - } - - public void send(String channel, String message) { - MessageToSend msg = new MessageToSend(channel, message); - messages.add(msg); - } - - private void publish(final String channel, final String message) { - Runnable task = new Runnable() { - public void run() { - Jedis jedis = redisPool.getResource(); - try { - jedis.publish(channel, message); - } catch(Exception e){ - log.warn("Cannot publish the message to redis", e); - } finally { - redisPool.returnResource(jedis); - } - } - }; - - runExec.execute(task); - } - - public void setRedisPool(JedisPool redisPool){ - this.redisPool = redisPool; - } + private static Logger log = Red5LoggerFactory.getLogger(MessageSender.class, "bigbluebutton"); + + private volatile boolean sendMessage = false; + private final Executor msgSenderExec = Executors.newSingleThreadExecutor(); + private final Executor runExec = Executors.newSingleThreadExecutor(); + private BlockingQueue<MessageToSend> messages = new LinkedBlockingQueue<MessageToSend>(); + + private JedisPool redisPool; + private String host; + private int port; + + public void stop() { + sendMessage = false; + redisPool.destroy(); + } + + public void start() { + GenericObjectPoolConfig config = new GenericObjectPoolConfig(); + config.setMaxTotal(32); + config.setMaxIdle(8); + config.setMinIdle(1); + config.setTestOnBorrow(true); + config.setTestOnReturn(true); + config.setTestWhileIdle(true); + config.setNumTestsPerEvictionRun(12); + config.setMaxWaitMillis(5000); + config.setTimeBetweenEvictionRunsMillis(60000); + config.setBlockWhenExhausted(true); + + // Set the name of this client to be able to distinguish when doing + // CLIENT LIST on redis-cli + redisPool = new JedisPool(config, host, port, Protocol.DEFAULT_TIMEOUT, null, + Protocol.DEFAULT_DATABASE, "BbbRed5AppsPub"); + + log.info("Redis message publisher starting!"); + try { + sendMessage = true; + + Runnable messageSender = new Runnable() { + public void run() { + while (sendMessage) { + try { + MessageToSend msg = messages.take(); + publish(msg.getChannel(), msg.getMessage()); + } catch (InterruptedException e) { + log.warn("Failed to get message from queue."); + } + } + } + }; + msgSenderExec.execute(messageSender); + } catch (Exception e) { + log.error("Error subscribing to channels: " + e.getMessage()); + } + } + + public void send(String channel, String message) { + MessageToSend msg = new MessageToSend(channel, message); + messages.add(msg); + } + + private void publish(final String channel, final String message) { + Runnable task = new Runnable() { + public void run() { + Jedis jedis = redisPool.getResource(); + try { + jedis.publish(channel, message); + } catch(Exception e){ + log.warn("Cannot publish the message to redis", e); + } finally { + jedis.close(); + } + } + }; + + runExec.execute(task); + } + + public void setHost(String host){ + this.host = host; + } + + public void setPort(int port) { + this.port = port; + } } diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MessagingConstants.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MessagingConstants.java deleted file mode 100755 index 0a787e84d3788d7d562b198694078f545ce84e74..0000000000000000000000000000000000000000 --- a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/MessagingConstants.java +++ /dev/null @@ -1,40 +0,0 @@ -/** -* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ -* -* Copyright (c) 2014 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.screenshare.messaging.redis; - -public class MessagingConstants { - - public static final String FROM_BBB_APPS_CHANNEL = "bigbluebutton:from-bbb-apps"; - public static final String FROM_BBB_APPS_PATTERN = FROM_BBB_APPS_CHANNEL + ":*"; - public static final String FROM_SYSTEM_CHANNEL = FROM_BBB_APPS_CHANNEL + ":system"; - public static final String FROM_MEETING_CHANNEL = FROM_BBB_APPS_CHANNEL + ":meeting"; - - public static final String TO_BBB_APPS_CHANNEL = "bigbluebutton:to-bbb-apps"; - public static final String TO_BBB_APPS_PATTERN = TO_BBB_APPS_CHANNEL + ":*"; - public static final String TO_MEETING_CHANNEL = TO_BBB_APPS_CHANNEL + ":meeting"; - public static final String TO_SYSTEM_CHANNEL = TO_BBB_APPS_CHANNEL + ":system"; - - public static final String DESTROY_MEETING_REQUEST_EVENT = "DestroyMeetingRequestEvent"; - public static final String CREATE_MEETING_REQUEST_EVENT = "CreateMeetingRequestEvent"; - public static final String END_MEETING_REQUEST_EVENT = "EndMeetingRequestEvent"; - public static final String MEETING_STARTED_EVENT = "meeting_created_message"; - public static final String MEETING_ENDED_EVENT = "meeting_ended_event"; - public static final String MEETING_DESTROYED_EVENT = "meeting_destroyed_event"; - -} diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/RedisPubSubMessageHandler.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/RedisPubSubMessageHandler.java new file mode 100755 index 0000000000000000000000000000000000000000..9d64989664e73431bd1b54afc527db1e8163cc99 --- /dev/null +++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/messaging/redis/RedisPubSubMessageHandler.java @@ -0,0 +1,46 @@ +package org.bigbluebutton.app.screenshare.messaging.redis; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.bigbluebutton.app.screenshare.red5.Red5AppHandler; +import org.bigbluebutton.common.messages.MeetingDestroyedMessage; +import org.bigbluebutton.common.messages.MeetingCreatedMessage; +import org.bigbluebutton.common.messages.MessagingConstants; +import org.red5.logging.Red5LoggerFactory; +import org.slf4j.Logger; + +public class RedisPubSubMessageHandler implements MessageHandler { + private static Logger log = Red5LoggerFactory.getLogger(RedisPubSubMessageHandler.class, "screenshare"); + private Red5AppHandler handler; + + @Override + public void handleMessage(String pattern, String channel, String message) { + if (channel.equalsIgnoreCase(MessagingConstants.FROM_MEETING_CHANNEL)) { + JsonParser parser = new JsonParser(); + JsonObject obj = (JsonObject) parser.parse(message); + if (obj.has("header") && obj.has("payload")) { + JsonObject header = (JsonObject) obj.get("header"); + if (header.has("name")) { + String messageName = header.get("name").getAsString(); + + if (MeetingDestroyedMessage.NAME.equals(messageName)) { + MeetingDestroyedMessage msg = MeetingDestroyedMessage.fromJson(message); + handler.meetingHasEnded(msg.meetingId); + + } else if (MeetingCreatedMessage.MEETING_CREATED.equals(messageName)) { + MeetingCreatedMessage msg = MeetingCreatedMessage.fromJson(message); + handler.meetingCreated(msg.meetingId); + + } + } + } + } + + + } + + public void setAppHandler(Red5AppHandler handler) { + this.handler = handler; + } + +} diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/ConnectionInvokerService.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/ConnectionInvokerService.java index 12f811f039ce2c3c4f907791de82e4917e444e92..54b75a028090c50b1bb5fb51bb0802f8c11c05ae 100755 --- a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/ConnectionInvokerService.java +++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/ConnectionInvokerService.java @@ -65,7 +65,7 @@ public class ConnectionInvokerService { ClientMessage message; try { message = messages.take(); - sendMessageToClient(message); + sendMessageToClient(message); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); 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 d42bdd32d897204c03e9e6fcabd0b57c88650a8f..6425eff75c7557cb05fb78158a05e2d5576e580a 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 @@ -2,14 +2,7 @@ package org.bigbluebutton.app.screenshare.red5; import java.util.HashMap; import java.util.Map; - -import org.bigbluebutton.app.screenshare.events.IEvent; -import org.bigbluebutton.app.screenshare.events.IEventListener; -import org.bigbluebutton.app.screenshare.events.ShareStartedEvent; -import org.bigbluebutton.app.screenshare.events.ShareStoppedEvent; -import org.bigbluebutton.app.screenshare.events.StreamStartedEvent; -import org.bigbluebutton.app.screenshare.events.StreamStoppedEvent; - +import org.bigbluebutton.app.screenshare.events.*; import com.google.gson.Gson; import org.red5.logging.Red5LoggerFactory; import org.slf4j.Logger; @@ -28,10 +21,86 @@ public class EventListenerImp implements IEventListener { sendStreamStartedEvent((StreamStartedEvent) event); } else if (event instanceof StreamStoppedEvent) { sendStreamStoppedEvent((StreamStoppedEvent) event); + } else if (event instanceof StartShareRequestResponse) { + sendStartShareRequestResponse((StartShareRequestResponse) event); + } else if (event instanceof StartShareRequestFailedResponse) { + sendStartShareRequestFailedResponse((StartShareRequestFailedResponse) event); + } else if (event instanceof IsScreenSharingResponse) { + sendIsScreenSharingResponse((IsScreenSharingResponse) event); } - } - + + private void sendIsScreenSharingResponse(IsScreenSharingResponse event) { + Map<String, Object> data = new HashMap<String, Object>(); + data.put("sharing", event.info.sharing); + + if (event.info.sharing) { + data.put("streamId", event.info.streamId); + data.put("width", event.info.width); + data.put("height", event.info.height); + data.put("url", event.info.url); + } + + Map<String, Object> message = new HashMap<String, Object>(); + Gson gson = new Gson(); + message.put("msg", gson.toJson(data)); + + log.info("Sending isSharingScreenRequestResponse to client, meetingId=" + event.meetingId + " userid=" + event.userId); + DirectClientMessage msg = new DirectClientMessage(event.meetingId, event.userId, "isSharingScreenRequestResponse", message); + sender.sendMessage(msg); + } + + private void sendStartShareRequestFailedResponse(StartShareRequestFailedResponse event) { + Map<String, Object> data = new HashMap<String, Object>(); + + data.put("reason", event.reason); + + Map<String, Object> message = new HashMap<String, Object>(); + Gson gson = new Gson(); + message.put("msg", gson.toJson(data)); + + DirectClientMessage msg = new DirectClientMessage(event.meetingId, event.userId, "startShareRequestRejectedResponse", message); + sender.sendMessage(msg); + + Map<String, Object> logData = new HashMap<String, Object>(); + logData.put("meetingId", event.meetingId); + logData.put("userId", event.userId); + logData.put("reason", event.reason); + + Gson gson2 = new Gson(); + String logStr = gson2.toJson(logData); + + log.info("Start ScreenShare request rejected response: data={}", logStr); + } + + private void sendStartShareRequestResponse(StartShareRequestResponse event) { + Map<String, Object> data = new HashMap<String, Object>(); + + data.put("authToken", event.token); + data.put("jnlp", event.jnlp); + data.put("streamId", event.streamId); + + Map<String, Object> message = new HashMap<String, Object>(); + Gson gson = new Gson(); + message.put("msg", gson.toJson(data)); + + DirectClientMessage msg = new DirectClientMessage(event.meetingId, event.userId, "startShareRequestResponse", message); + sender.sendMessage(msg); + + Map<String, Object> logData = new HashMap<String, Object>(); + logData.put("meetingId", event.meetingId); + logData.put("userId", event.userId); + + logData.put("authToken", event.token); + logData.put("jnlp", event.jnlp); + + + Gson gson2 = new Gson(); + String logStr = gson2.toJson(logData); + + log.info("Start ScreenShare request response: data={}", logStr); + } + private void sendShareStartedEvent(ShareStartedEvent event) { Map<String, Object> data = new HashMap<String, Object>(); data.put("meetingId", event.meetingId); @@ -131,4 +200,7 @@ public class EventListenerImp implements IEventListener { this.sender = sender; } + + + } diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/Red5AppHandler.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/Red5AppHandler.java index b5c726da353ce60ab834a478c7e60faaca7182ca..245b00bbbedbb76dfccdd8209ad2c135ca3dc814 100755 --- a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/Red5AppHandler.java +++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/Red5AppHandler.java @@ -5,8 +5,7 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.bigbluebutton.app.screenshare.IScreenShareApplication; -import org.bigbluebutton.app.screenshare.IsScreenSharingResponse; -import org.bigbluebutton.app.screenshare.StartShareRequestResponse; +import org.bigbluebutton.app.screenshare.events.IsScreenSharingResponse; import org.red5.logging.Red5LoggerFactory; import org.slf4j.Logger; import com.google.gson.Gson; @@ -19,81 +18,30 @@ public class Red5AppHandler { private final Pattern STREAM_ID_PATTERN = Pattern.compile("(.*)-(.*)-(.*)$"); + public void meetingHasEnded(String meetingId) { + app.meetingHasEnded(meetingId); + } + + public void meetingCreated(String meetingId) { + app.meetingCreated(meetingId); + } + public void userConnected(String meetingId, String userId) { app.userConnected(meetingId, userId); } public void isScreenSharing(String meetingId, String userId) { - IsScreenSharingResponse resp = app.isScreenSharing(meetingId); - - Map<String, Object> data = new HashMap<String, Object>(); - data.put("sharing", resp.info.sharing); - - if (resp.info.sharing) { - data.put("streamId", resp.info.streamId); - data.put("width", resp.info.width); - data.put("height", resp.info.height); - data.put("url", resp.info.url); - } - - Map<String, Object> message = new HashMap<String, Object>(); - Gson gson = new Gson(); - message.put("msg", gson.toJson(data)); - - log.info("Sending isSharingScreenRequestResponse to client, meetingId=" + meetingId + " userid=" + userId); - DirectClientMessage msg = new DirectClientMessage(meetingId, userId, "isSharingScreenRequestResponse", message); - sender.sendMessage(msg); + app.isScreenSharing(meetingId, userId); } - public void startShareRequest(String meetingId, String userId, Boolean record) { - StartShareRequestResponse resp = app.startShareRequest(meetingId, userId, record); - - Map<String, Object> data = new HashMap<String, Object>(); - - if (resp.error != null) { - data.put("error", resp.error.reason); - } else { - data.put("authToken", resp.token); - data.put("jnlp", resp.jnlp); - data.put("streamId", resp.streamId); - } - - Map<String, Object> message = new HashMap<String, Object>(); - Gson gson = new Gson(); - message.put("msg", gson.toJson(data)); - - DirectClientMessage msg = new DirectClientMessage(meetingId, userId, "startShareRequestResponse", message); - sender.sendMessage(msg); - - Map<String, Object> logData = new HashMap<String, Object>(); - logData.put("meetingId", meetingId); - logData.put("userId", userId); - - if (resp.error != null) { - logData.put("error", resp.error.reason); - } else { - logData.put("authToken", resp.token); - logData.put("jnlp", resp.jnlp); - } - - Gson gson2 = new Gson(); - String logStr = gson2.toJson(logData); - - log.info("Start ScreenShare request response: data={}", logStr); + public void startShareRequest(String meetingId, String userId, Boolean allowed) { + app.startShareRequest(meetingId, userId, allowed); } public void restartShareRequest(String meetingId, String userId) { app.restartShareRequest(meetingId, userId); - Map<String, Object> logData = new HashMap<String, Object>(); - logData.put("meetingId", meetingId); - logData.put("userId", userId); - - Gson gson2 = new Gson(); - String logStr = gson2.toJson(logData); - - log.info("Restart ScreenShare message: data={}", logStr); } public void pauseShareRequest(String meetingId, String userId, String streamId) { @@ -101,54 +49,13 @@ public class Red5AppHandler { if (matcher.matches()) { app.pauseShareRequest(meetingId, userId, streamId); } - - Map<String, Object> data = new HashMap<String, Object>(); - data.put("meetingId", meetingId); - data.put("streamId", streamId); - data.put("userId", userId); - - Map<String, Object> message = new HashMap<String, Object>(); - Gson gson = new Gson(); - message.put("msg", gson.toJson(data)); - - BroadcastClientMessage msg = new BroadcastClientMessage(meetingId, "pauseScreenSharingEvent", message); - sender.sendMessage(msg); - - Map<String, Object> logData = new HashMap<String, Object>(); - logData.put("meetingId", meetingId); - logData.put("streamId", streamId); - - Gson gson2 = new Gson(); - String logStr = gson2.toJson(logData); - - log.info("Stop viewing ScreenShare broadcast message: data={}", logStr); } public void stopShareRequest(String meetingId, String streamId) { Matcher matcher = STREAM_ID_PATTERN.matcher(streamId); if (matcher.matches()) { app.stopShareRequest(meetingId, streamId); - } - - Map<String, Object> data = new HashMap<String, Object>(); - data.put("meetingId", meetingId); - data.put("streamId", streamId); - - Map<String, Object> message = new HashMap<String, Object>(); - Gson gson = new Gson(); - message.put("msg", gson.toJson(data)); - - BroadcastClientMessage msg = new BroadcastClientMessage(meetingId, "stopViewingStream", message); - sender.sendMessage(msg); - - Map<String, Object> logData = new HashMap<String, Object>(); - logData.put("meetingId", meetingId); - logData.put("streamId", streamId); - - Gson gson2 = new Gson(); - String logStr = gson2.toJson(logData); - - log.info("Stop viewing ScreenShare broadcast message: data={}", logStr); + } } public void setApplication(IScreenShareApplication app) { diff --git a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/Red5AppService.java b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/Red5AppService.java index 352ef84af8d72edd5035e8ccdf52933262806cc5..2697a37c0cb94cee9d784af20df0ca2db3d2047b 100755 --- a/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/Red5AppService.java +++ b/bbb-screenshare/app/src/main/java/org/bigbluebutton/app/screenshare/red5/Red5AppService.java @@ -3,7 +3,12 @@ package org.bigbluebutton.app.screenshare.red5; import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; +import org.bigbluebutton.app.screenshare.messaging.redis.MessageSender; +//import org.bigbluebutton.app.screenshare.messaging.redis.MessagingConstants; +import org.bigbluebutton.common.messages.AllowUserToShareDesktopRequest; +import org.bigbluebutton.common.messages.MessagingConstants; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; @@ -15,7 +20,8 @@ import com.google.gson.Gson; public class Red5AppService { private static Logger log = Red5LoggerFactory.getLogger(Red5AppService.class, "screenshare"); - private Red5AppHandler handler; + private Red5AppHandler handler; + private MessageSender red5RedisSender; /** * Called from the client to pass us the userId. @@ -97,12 +103,12 @@ public class Red5AppService { } public void startShareRequest(Map<String, Object> msg) { - Boolean record = (Boolean) msg.get("record"); + Boolean record = (Boolean) msg.get("record"); String meetingId = Red5.getConnectionLocal().getScope().getName(); log.debug("Received startShareRequest for meeting=[{}]", meetingId); String userId = (String) Red5.getConnectionLocal().getAttribute("USERID"); - handler.startShareRequest(meetingId, userId, record); + handler.startShareRequest(meetingId, userId, record); //TODO REMOVE } public void stopShareRequest(Map<String, Object> msg) { @@ -113,8 +119,15 @@ public class Red5AppService { handler.stopShareRequest(meetingId, streamId); } + private Long genTimestamp() { + return TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + } public void setAppHandler(Red5AppHandler handler) { this.handler = handler; } + + public void setRed5RedisSender(MessageSender red5RedisSender) { + this.red5RedisSender = red5RedisSender; + } } diff --git a/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/ScreenShareApplication.scala b/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/ScreenShareApplication.scala index 623945609d5b4c4852f7d62c9000a7b0e1e26b27..c7355d7d7aebf6e9b706ff682d9ec9eb58ba886e 100755 --- a/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/ScreenShareApplication.scala +++ b/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/ScreenShareApplication.scala @@ -19,12 +19,13 @@ package org.bigbluebutton.app.screenshare import akka.util.Timeout -import org.bigbluebutton.app.screenshare.events.IEventsMessageBus +import org.bigbluebutton.app.screenshare.events.{IEventsMessageBus, IsScreenSharingResponse, StartShareRequestResponse} import org.bigbluebutton.app.screenshare.server.sessions.ScreenshareManager import org.bigbluebutton.app.screenshare.server.sessions.messages._ import org.bigbluebutton.app.screenshare.server.util.LogHelper import akka.actor.ActorSystem import akka.pattern.ask + import scala.concurrent.Await import scala.concurrent.duration._ @@ -39,6 +40,24 @@ class ScreenShareApplication(val bus: IEventsMessageBus, val jnlpFile: String, logger.info("Creating a new ScreenShareApplication") + def meetingHasEnded(meetingId: String) { + if (logger.isDebugEnabled()) { + logger.debug("Received meetingHasEnded on meeting=" + meetingId + "]") + } + + screenshareManager ! new MeetingHasEnded(meetingId) + + } + + def meetingCreated(meetingId: String) { + if (logger.isDebugEnabled()) { + logger.debug("Received meetingCreated on meeting=" + meetingId + "]") + } + + screenshareManager ! new MeetingCreated(meetingId) + + } + def userConnected(meetingId: String, userId: String) { if (logger.isDebugEnabled()) { logger.debug("Received user disconnected on meeting=" + meetingId @@ -55,16 +74,12 @@ class ScreenShareApplication(val bus: IEventsMessageBus, val jnlpFile: String, screenshareManager ! new UserDisconnected(meetingId, userId) } - def isScreenSharing(meetingId: String):IsScreenSharingResponse = { + def isScreenSharing(meetingId: String, userId: String) { if (logger.isDebugEnabled()) { logger.debug("Received is screen sharing on meeting=" + meetingId + "]") } - implicit val timeout = Timeout(3 seconds) - val future = screenshareManager ? IsScreenSharing(meetingId) - val reply = Await.result(future, timeout.duration).asInstanceOf[IsScreenSharingReply] - val info = new StreamInfo(reply.sharing, reply.streamId, reply.width, reply.height, reply.url) - new IsScreenSharingResponse(info, null) + screenshareManager ! IsScreenSharing(meetingId, userId) } def getScreenShareInfo(meetingId: String, token: String):ScreenShareInfoResponse = { @@ -93,16 +108,12 @@ class ScreenShareApplication(val bus: IEventsMessageBus, val jnlpFile: String, record } - def startShareRequest(meetingId: String, userId: String, record: java.lang.Boolean): StartShareRequestResponse = { + def startShareRequest(meetingId: String, userId: String, record: java.lang.Boolean) { if (logger.isDebugEnabled()) { logger.debug("Received start share request on meeting=" + meetingId + "for user=" + userId + "]") } - implicit val timeout = Timeout(3 seconds) - val future = screenshareManager ? StartShareRequestMessage(meetingId, userId, record) - val reply = Await.result(future, timeout.duration).asInstanceOf[StartShareRequestReplyMessage] - val response = new StartShareRequestResponse(reply.token, jnlpFile, reply.streamId, null) - response + screenshareManager ! StartShareRequestMessage(meetingId, userId, jnlpFile, record) } def restartShareRequest(meetingId: String, userId: String) { diff --git a/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/Screenshare.scala b/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/Screenshare.scala index 748a76613ede473786faedb846cfe5e89a26922d..a21cab9346567ea908524be7bdade15eb829e276 100755 --- a/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/Screenshare.scala +++ b/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/Screenshare.scala @@ -19,16 +19,14 @@ package org.bigbluebutton.app.screenshare.server.sessions import akka.actor.{Actor, ActorLogging, Props} -import org.bigbluebutton.app.screenshare.server.sessions.Session.KeepAliveTimeout +import org.bigbluebutton.app.screenshare.StreamInfo import org.bigbluebutton.app.screenshare.server.sessions.ScreenshareManager.MeetingHasEnded import scala.collection.mutable.HashMap -import org.bigbluebutton.app.screenshare.events.IEventsMessageBus -import org.bigbluebutton.app.screenshare.server.util._ +import org.bigbluebutton.app.screenshare.events.{IEventsMessageBus, IsScreenSharingResponse, StartShareRequestResponse} import org.bigbluebutton.app.screenshare.server.sessions.messages._ import scala.collection.immutable.StringOps -import scala.concurrent.duration._ object Screenshare { def props(screenshareSessionManager: ScreenshareManager, bus: IEventsMessageBus, meetingId:String): Props = @@ -42,8 +40,6 @@ class Screenshare(val sessionManager: ScreenshareManager, log.info("Creating a new Screenshare") private val sessions = new HashMap[String, ActiveSession] - private var lastHasSessionCheck:Long = TimeUtil.getCurrentMonoTime() - private var activeSession:Option[ActiveSession] = None private val START = "START" @@ -60,17 +56,10 @@ class Screenshare(val sessionManager: ScreenshareManager, private var sessionToken = "" - private val IS_MEETING_RUNNING = "IsMeetingRunning" - private var currentStreamId:Option[String] = None private var currentPresenterId:Option[String] = None private var record:Boolean = false - implicit def executionContext = sessionManager.actorSystem.dispatcher - - def scheduleIsMeetingRunningCheck() { - sessionManager.actorSystem.scheduler.scheduleOnce(60.seconds, self, IS_MEETING_RUNNING) - } def receive = { case msg: RestartShareRequestMessage => handleRestartShareRequestMessage(msg) @@ -88,8 +77,7 @@ class Screenshare(val sessionManager: ScreenshareManager, case msg: UserDisconnected => handleUserDisconnected(msg) case msg: UserConnected => handleUserConnected(msg) case msg: ScreenShareInfoRequest => handleScreenShareInfoRequest(msg) - case IS_MEETING_RUNNING => handleIsMeetingRunning() - case msg: KeepAliveTimeout => handleKeepAliveTimeout(msg) + case msg: MeetingHasEnded => handleMeetingHasEnded(msg) case m: Any => log.warning("Session: Unknown message [{}]", m) } @@ -101,6 +89,18 @@ class Screenshare(val sessionManager: ScreenshareManager, sessions.values find (su => su.token == token) } + private def handleMeetingHasEnded(msg: MeetingHasEnded) { + if (log.isDebugEnabled) { + log.debug("Received MeetingHasEnded for meetingId=[" + msg.meetingId + "]") + } + + activeSession foreach { session => + context.stop(session.actorRef) + } + + context.stop(self) + } + private def handleUserDisconnected(msg: UserDisconnected) { if (log.isDebugEnabled) { log.debug("Received UserDisconnected for meetingId=[" + msg.meetingId + "] userId=[" + msg.userId + "]") @@ -118,7 +118,6 @@ class Screenshare(val sessionManager: ScreenshareManager, currentStreamId foreach { curStreamId => handleStopShareRequestMessage(new StopShareRequestMessage(meetingId, curStreamId)) } - } } } @@ -152,7 +151,8 @@ class Screenshare(val sessionManager: ScreenshareManager, } if (activeSession.isEmpty) { - sender ! new IsScreenSharingReply(false, "none", 0, 0, "none") + val info = new StreamInfo(false, "", 0, 0, "") + bus.send(new IsScreenSharingResponse(meetingId, msg.userId, info)) } else { activeSession foreach { session => session.actorRef forward msg @@ -276,7 +276,6 @@ class Screenshare(val sessionManager: ScreenshareManager, } } - private def handlePauseShareRequestMessage(msg: PauseShareRequestMessage) { if (log.isDebugEnabled) { log.debug("Received PauseShareRequestMessage for streamId=[" + msg.streamId + "]") @@ -289,8 +288,7 @@ class Screenshare(val sessionManager: ScreenshareManager, session.actorRef ! msg case None => - log.info("Stop share request on a non-existing session=[" + msg.streamId + "]") - + log.info("PauseShareRequestMessage on a non-existing session=[" + msg.streamId + "]") } } @@ -347,7 +345,8 @@ class Screenshare(val sessionManager: ScreenshareManager, status = START session.actorRef ! msg - sender ! new StartShareRequestReplyMessage(token, streamId) + + bus.send(new StartShareRequestResponse(meetingId, msg.userId, token, msg.jnlp, streamId)) } private def handleGetSharingStatus(msg: GetSharingStatus) { @@ -367,29 +366,4 @@ class Screenshare(val sessionManager: ScreenshareManager, } } } - - private def handleIsMeetingRunning() { - // If not sessions in the last 5 minutes, then assume meeting has ended. - if (sessions.isEmpty) { - if (TimeUtil.getCurrentMonoTime - lastHasSessionCheck > 300000) { - context.parent ! MeetingHasEnded(meetingId) - } else { - scheduleIsMeetingRunningCheck() - } - } else { - lastHasSessionCheck = TimeUtil.getCurrentMonoTime() - scheduleIsMeetingRunningCheck() - } - } - - private def handleKeepAliveTimeout(msg: KeepAliveTimeout) { - sessions.remove(msg.streamId) foreach { s => - if (activeSession != None) { - activeSession foreach { as => - if (as.streamId == s.streamId) activeSession = None - } - } - } - } - } \ No newline at end of file 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 27f57f37369e576b636358182a618680e8508bea..35c5f4229918e8e8b3d7fb148e89f938d5fb9bd8 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 @@ -19,13 +19,16 @@ package org.bigbluebutton.app.screenshare.server.sessions import akka.pattern.ask + import scala.concurrent.duration._ -import akka.actor.{ActorSystem, Actor, Props, ActorLogging} +import akka.actor.{Actor, ActorLogging, ActorSystem, Props} import akka.util.Timeout +import org.bigbluebutton.app.screenshare.StreamInfo import org.bigbluebutton.app.screenshare.server.sessions.Session.StopSession import org.bigbluebutton.app.screenshare.server.sessions.ScreenshareManager.MeetingHasEnded + import scala.collection.mutable.HashMap -import org.bigbluebutton.app.screenshare.events.IEventsMessageBus +import org.bigbluebutton.app.screenshare.events.{IEventsMessageBus, IsScreenSharingResponse, StartShareRequestFailedResponse} import org.bigbluebutton.app.screenshare.server.sessions.messages._ import scala.concurrent.Await @@ -63,6 +66,8 @@ class ScreenshareManager(val aSystem: ActorSystem, val bus: IEventsMessageBus) case msg: UserDisconnected => handleUserDisconnected(msg) case msg: UserConnected => handleUserConnected(msg) case msg: MeetingHasEnded => handleMeetingHasEnded(msg) + case msg: MeetingCreated => handleMeetingCreated(msg) + case msg: Any => log.warning("Unknown message " + msg) } @@ -101,7 +106,8 @@ class ScreenshareManager(val aSystem: ActorSystem, val bus: IEventsMessageBus) } if (screenshares.get(msg.meetingId).isEmpty) { - sender ! new IsScreenSharingReply(false, "none", 0, 0, "none") + val info = new StreamInfo(false, "", 0, 0, "") + bus.send(new IsScreenSharingResponse(msg.meetingId, msg.userId, info)) } else { screenshares.get(msg.meetingId) foreach { screenshare => screenshare.actorRef forward msg @@ -111,9 +117,34 @@ class ScreenshareManager(val aSystem: ActorSystem, val bus: IEventsMessageBus) private def handleMeetingHasEnded(msg: MeetingHasEnded) { log.info("Removing meeting [" + msg.meetingId + "]") + + screenshares.get(msg.meetingId) foreach { screenshare => + screenshare.actorRef forward msg + } + screenshares -= msg.meetingId } + private def handleMeetingCreated(msg: MeetingCreated) { + log.info("Creating meeting [" + msg.meetingId + "]") + + screenshares.get(msg.meetingId) match { + case None => { + if (log.isDebugEnabled) { + log.debug("Creating screenshare=[" + msg.meetingId + "]") + } + val activeScreenshare = ActiveScreenshare(this, bus, msg.meetingId) + screenshares += msg.meetingId -> activeScreenshare + + } + case Some(screenshare) => { + if (log.isDebugEnabled) { + log.debug("Screenshare already exists. screenshare=[" + msg.meetingId + "]") + } + } + } + } + private def handleScreenShareInfoRequest(msg: ScreenShareInfoRequest) { if (log.isDebugEnabled) { log.debug("Received ScreenShareInfoRequest message for meetingId=[" + msg.meetingId + "]") @@ -207,23 +238,19 @@ class ScreenshareManager(val aSystem: ActorSystem, val bus: IEventsMessageBus) log.debug("Received start share request message for meeting=[" + msg.meetingId + "]") } screenshares.get(msg.meetingId) match { - case None => { + case None => if (log.isDebugEnabled) { - log.debug("Creating screenshare=[" + msg.meetingId + "]") + log.warning("Reqeusting to share on non-existing meeting with id=[" + msg.meetingId + "]") } - val activeScreenshare = ActiveScreenshare(this, bus, msg.meetingId) - screenshares += msg.meetingId -> activeScreenshare + bus.send(new StartShareRequestFailedResponse(msg.meetingId, msg.userId, "UNKNOWN_MEETING")) - activeScreenshare.actorRef forward msg - } - case Some(screenshare) => { + case Some(screenshare) => if (log.isDebugEnabled) { - log.debug("Screenshare already exists. screenshare=[" + msg.meetingId + "]") + log.debug("Request to start screenshare=[" + msg.meetingId + "]") } screenshare.actorRef forward msg - } } } diff --git a/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/Session.scala b/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/Session.scala index ced6ad001529d0403f216dfca1dae4dbbc8b6abc..e5c3f6cb77f711e2b7c4580d7c00767f8d8efe4d 100755 --- a/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/Session.scala +++ b/bbb-screenshare/app/src/main/scala/org/bigbluebutton/app/screenshare/server/sessions/Session.scala @@ -18,14 +18,13 @@ */ package org.bigbluebutton.app.screenshare.server.sessions -import akka.actor.{ActorLogging, Actor, Props} +import akka.actor.{Actor, ActorLogging, Props} +import org.bigbluebutton.app.screenshare.StreamInfo import org.bigbluebutton.app.screenshare.server.sessions.Session.KeepAliveTimeout import org.bigbluebutton.app.screenshare.server.util.TimeUtil import org.bigbluebutton.app.screenshare.server.sessions.messages._ -import org.bigbluebutton.app.screenshare.events.IEventsMessageBus -import org.bigbluebutton.app.screenshare.events.ShareStoppedEvent -import org.bigbluebutton.app.screenshare.events.StreamStoppedEvent -import org.bigbluebutton.app.screenshare.events.StreamStartedEvent +import org.bigbluebutton.app.screenshare.events._ + import scala.concurrent.duration._ object Session { @@ -116,7 +115,10 @@ class Session(parent: Screenshare, w <- width h <- height url <- streamUrl - } yield (sender ! new IsScreenSharingReply(true, streamId, w, h, url)) + } yield { + val info = new StreamInfo(true, streamId, w, h, url) + bus.send(new IsScreenSharingResponse(meetingId, msg.userId, info)) + } } 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 e8ccb71c30654f772c3fc6d3528776e26442a41c..98320b74de024bfc392a711fe7b3f6acdfd7dad6 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 @@ -1,6 +1,6 @@ package org.bigbluebutton.app.screenshare.server.sessions.messages -case class StartShareRequestMessage(meetingId: String, userId: String, record: Boolean) +case class StartShareRequestMessage(meetingId: String, userId: String, jnlp: String, record: Boolean) case class StartShareRequestReplyMessage(token: String, streamId: String) @@ -28,7 +28,7 @@ case class GetSharingStatusReply(status: String, streamId: Option[String]) case class UpdateShareStatus(meetingId: String, streamId: String, sequence: Int) -case class IsScreenSharing(meetingId: String) +case class IsScreenSharing(meetingId: String, userId: String) case class IsScreenSharingReply(sharing: Boolean, streamId: String, width: Int, height: Int, url: String) @@ -39,4 +39,8 @@ case class ScreenShareInfoRequestReply(meetingId: String, streamId: String) case class UserDisconnected(meetingId: String, userId: String) -case class UserConnected(meetingId: String, userId: String) \ No newline at end of file +case class UserConnected(meetingId: String, userId: String) + +case class MeetingHasEnded(meetingId: String) + +case class MeetingCreated(meetingId: String) \ No newline at end of file diff --git a/bbb-screenshare/app/src/main/webapp/WEB-INF/bbb-red5-redis-pubsub.xml b/bbb-screenshare/app/src/main/webapp/WEB-INF/bbb-red5-redis-pubsub.xml new file mode 100755 index 0000000000000000000000000000000000000000..c64c2974aa5fc79bdf5cc5d0b8a690352921f9c9 --- /dev/null +++ b/bbb-screenshare/app/src/main/webapp/WEB-INF/bbb-red5-redis-pubsub.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + +BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ + +Copyright (c) 2014 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/>. + +--> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:util="http://www.springframework.org/schema/util" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans-2.5.xsd + http://www.springframework.org/schema/util + http://www.springframework.org/schema/util/spring-util-2.0.xsd + "> + + <bean id="red5RedisSender" + class="org.bigbluebutton.app.screenshare.messaging.redis.MessageSender" + init-method="start" destroy-method="stop"> + <property name="host" value="${redis.host}" /> + <property name="port" value="${redis.port}" /> + </bean> + + <bean id="red5RedisReceiver" class="org.bigbluebutton.app.screenshare.messaging.redis.MessageReceiver" + init-method="start" destroy-method="stop"> + <property name="messageHandler"> <ref local="red5RedisHandler"/> </property> + <property name="host" value="${redis.host}" /> + <property name="port" value="${redis.port}" /> + </bean> + + <bean id="red5RedisHandler" class="org.bigbluebutton.app.screenshare.messaging.redis.ReceivedMessageHandler" + init-method="start" destroy-method="stop"> + <property name="messageDistributor"><ref bean="red5RedisDistributor" /></property> + </bean> + + <bean id="red5RedisDistributor" class="org.bigbluebutton.app.screenshare.messaging.redis.MessageDistributor"> + <property name="messageHandler"> <ref local="red5RedisHandler"/> </property> + <property name="messageListeners"> + <set> + <ref bean="redisPubSubMessageHandler" /> + </set> + </property> + </bean> + +</beans> diff --git a/bbb-screenshare/app/src/main/webapp/WEB-INF/bbb-redis-pool.xml b/bbb-screenshare/app/src/main/webapp/WEB-INF/bbb-redis-pool.xml new file mode 100755 index 0000000000000000000000000000000000000000..eae411543fed0d67cb1317a28759ec6add1cc36a --- /dev/null +++ b/bbb-screenshare/app/src/main/webapp/WEB-INF/bbb-redis-pool.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + +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/>. + +--> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:util="http://www.springframework.org/schema/util" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans-2.5.xsd + http://www.springframework.org/schema/util + http://www.springframework.org/schema/util/spring-util-2.0.xsd + "> + + <bean id="redisPool" class="redis.clients.jedis.JedisPool"> + <constructor-arg index="0" value="${redis.host}"/> + <constructor-arg index="1" value="${redis.port}"/> + </bean> + +</beans> 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 5095085b619423b79356da4b7b708a9c3b733464..0e6048703c0fa6e6258e5cace2d54de8dbfd50f7 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 @@ -56,8 +56,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. <bean id="screenshare.service" class="org.bigbluebutton.app.screenshare.red5.Red5AppService"> <property name="appHandler" ref="red5AppHandler"/> + <property name="red5RedisSender" ref="red5RedisSender"/> </bean> - + <bean id="red5AppHandler" class="org.bigbluebutton.app.screenshare.red5.Red5AppHandler"> <property name="application" ref="screenShareApplication"/> <property name="messageSender" ref="connectionInvokerService"/> @@ -107,4 +108,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. <constructor-arg index="0" value="${redis.host}"/> <constructor-arg index="1" value="${redis.port}"/> </bean> + + <bean id="redisPubSubMessageHandler" + class="org.bigbluebutton.app.screenshare.messaging.redis.RedisPubSubMessageHandler"> + <property name="appHandler" ref="red5AppHandler"/> + </bean> + + <import resource="bbb-redis-pool.xml"/> + <import resource="bbb-red5-redis-pubsub.xml"/> </beans> diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/services/MessageReceiver.as b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/services/MessageReceiver.as index 9e6c5ec4b39a8464cbe5087e23f902c126bf1f50..1d6065cf5dbe1e6f7508b5906ae91e61ce69c521 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/services/MessageReceiver.as +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/services/MessageReceiver.as @@ -69,6 +69,9 @@ package org.bigbluebutton.modules.screenshare.services case "pauseScreenSharingEvent": handlePauseScreenSharingEvent(message); break; + case "startShareRequestRejectedResponse": + handleStartShareRequestRejectedResponse(message); + break; default: // LogUtil.warn("Cannot handle message [" + messageName + "]"); } @@ -83,6 +86,12 @@ package org.bigbluebutton.modules.screenshare.services } } + private function handleStartShareRequestRejectedResponse(message:Object):void { + LOGGER.debug("handleStartShareRequestRejectedResponse " + message); + var shareFailedEvent: ShareStartRequestResponseEvent = new ShareStartRequestResponseEvent(null, null, null, false); + dispatcher.dispatchEvent(shareFailedEvent); + } + private function handleStartShareRequestResponse(message:Object):void { LOGGER.debug("handleStartShareRequestResponse " + message); var map:Object = JSON.parse(message.msg);