You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2015/02/03 18:22:30 UTC

svn commit: r1656837 - in /openmeetings: branches/3.0.x/src/main/java/org/apache/openmeetings/remote/ branches/3.0.x/src/main/java/org/apache/openmeetings/remote/red5/ branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/ trunk/s...

Author: solomax
Date: Tue Feb  3 17:22:29 2015
New Revision: 1656837

URL: http://svn.apache.org/r1656837
Log:
[OPENMEETINGS-1154] screen-sharing app is refactored to work without delays

Modified:
    openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/FLVRecorderService.java
    openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java
    openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java
    openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java
    openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenShare.java
    openmeetings/trunk/singlewebapp/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/FLVRecorderService.java
    openmeetings/trunk/singlewebapp/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/red5/ScopeApplicationAdapter.java
    openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java
    openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java
    openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/IScreenShare.java

Modified: openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/FLVRecorderService.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/FLVRecorderService.java?rev=1656837&r1=1656836&r2=1656837&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/FLVRecorderService.java (original)
+++ openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/FLVRecorderService.java Tue Feb  3 17:22:29 2015
@@ -98,12 +98,11 @@ public class FLVRecorderService implemen
 		return "rec_" + flvRecording_id + "_stream_" + streamid + "_" + dateString;
 	}
 
-	public String recordMeetingStream(IConnection current, String roomRecordingName, String comment, Boolean isInterview) {
+	public String recordMeetingStream(IConnection current, Client client, String roomRecordingName, String comment, Boolean isInterview) {
 		try {
 			log.debug("##REC:: recordMeetingStream ::");
 
-			Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null);
-			Long room_id = currentClient.getRoom_id();
+			Long room_id = client.getRoom_id();
 
 			Date now = new Date();
 
@@ -111,7 +110,7 @@ public class FLVRecorderService implemen
 
 			flvRecording.setFileHash("");
 			flvRecording.setFileName(roomRecordingName);
-			flvRecording.setInsertedBy(currentClient.getUser_id());
+			flvRecording.setInsertedBy(client.getUser_id());
 			flvRecording.setFolder(false);
 			flvRecording.setIsImage(false);
 			flvRecording.setIsPresentation(false);
@@ -122,20 +121,20 @@ public class FLVRecorderService implemen
 			flvRecording.setRoom_id(room_id);
 			flvRecording.setRecordStart(now);
 
-			flvRecording.setWidth(currentClient.getVWidth());
-			flvRecording.setHeight(currentClient.getVHeight());
+			flvRecording.setWidth(client.getVWidth());
+			flvRecording.setHeight(client.getVHeight());
 
-			flvRecording.setOwnerId(currentClient.getUser_id());
+			flvRecording.setOwnerId(client.getUser_id());
 			flvRecording.setStatus(FlvRecording.Status.RECORDING);
 			flvRecording = recordingDao.update(flvRecording);
 			// Receive flvRecordingId
 			Long flvRecordingId = flvRecording.getFlvRecordingId();
-			log.debug("##REC:: recording created by USER: " + currentClient.getUser_id());
+			log.debug("##REC:: recording created by USER: " + client.getUser_id());
 
 			// Update Client and set Flag
-			currentClient.setIsRecording(true);
-			currentClient.setFlvRecordingId(flvRecordingId);
-			sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null);
+			client.setIsRecording(true);
+			client.setFlvRecordingId(flvRecordingId);
+			sessionManager.updateClientByStreamId(client.getStreamid(), client, false, null);
 
 			// get all stream and start recording them
 			for (IConnection conn : current.getScope().getClientConnections()) {
@@ -145,7 +144,7 @@ public class FLVRecorderService implemen
 
 						// Send every user a notification that the recording did start
 						if (!rcl.getIsAVClient()) {
-							((IServiceCapableConnection) conn).invoke("startedRecording", new Object[] { currentClient }, this);
+							((IServiceCapableConnection) conn).invoke("startedRecording", new Object[] { client }, this);
 						}
 
 						// If its the recording client we need another type of Meta Data

Modified: openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java?rev=1656837&r1=1656836&r2=1656837&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java (original)
+++ openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java Tue Feb  3 17:22:29 2015
@@ -152,42 +152,59 @@ public class ScopeApplicationAdapter ext
 	public boolean roomConnect(IConnection conn, Object[] params) {
 		log.debug("roomConnect : ");
 
-		try {
+		IServiceCapableConnection service = (IServiceCapableConnection) conn;
+		String streamId = conn.getClient().getId();
+		
+		boolean isAVClient = params.length == 1 ? Boolean.valueOf("" + params[0]) : false;
 
-			IServiceCapableConnection service = (IServiceCapableConnection) conn;
-			String streamId = conn.getClient().getId();
-			
-			boolean isAVClient = false;
-			if (params.length == 1) {
-				isAVClient = Boolean.valueOf("" + params[0]);
-			}
+		log.debug("### Client connected to OpenMeetings, register Client StreamId: " + streamId + " scope "
+				+ conn.getScope().getName() + " isAVClient " + isAVClient);
 
-			log.debug("### Client connected to OpenMeetings, register Client StreamId: " + streamId + " scope "
-					+ conn.getScope().getName() + " isAVClient " + isAVClient);
+		// Set StreamId in Client
+		service.invoke("setId", new Object[] { streamId }, this);
 
-			// Set StreamId in Client
-			service.invoke("setId", new Object[] { streamId }, this);
+		Map<String, Object> map = conn.getConnectParams();
+		String swfURL = map.containsKey("swfUrl") ? (String)map.get("swfUrl") : "";
 
-			String swfURL = "";
-			if (conn.getConnectParams().get("swfUrl") != null) {
-				swfURL = conn.getConnectParams().get("swfUrl").toString();
+		//TODO add similar code for other connections
+		if (map.containsKey("screenClient")) {
+			String parentSid = (String)map.get("parentSid");
+			Client parentClient = sessionManager.getClientByPublicSID(parentSid, false, null);
+			if (parentClient == null) {
+				rejectClient();
 			}
-
-			Client rcm = sessionManager.addClientListItem(streamId,
-					conn.getScope().getName(), conn.getRemotePort(),
-					conn.getRemoteAddress(), swfURL, isAVClient, null);
+		}
+		Client rcm = sessionManager.addClientListItem(conn.getClient().getId(),
+				conn.getScope().getName(), conn.getRemotePort(),
+				conn.getRemoteAddress(), swfURL, isAVClient, null);
+		
+		SessionVariablesUtil.initClient(conn.getClient(), isAVClient, rcm.getPublicSID());
+		//TODO add similar code for other connections, merge with above block
+		if (map.containsKey("screenClient")) {
+			//TODO add check for room rights
+			String parentSid = (String)map.get("parentSid");
+			rcm.setRoom_id(Long.parseLong(conn.getScope().getName()));
+			rcm.setIsScreenClient(true);
+			SessionVariablesUtil.setIsScreenClient(conn.getClient());
 			
-			SessionVariablesUtil.initClient(conn.getClient(), isAVClient, rcm.getPublicSID());
+			rcm.setUser_id(((Integer)map.get("userId")).longValue());
+			SessionVariablesUtil.setUserId(conn.getClient(), rcm.getUser_id());
 
-			// Log the User
-			conferenceLogDao.addConferenceLog("ClientConnect",
-					rcm.getUser_id(), streamId, null, rcm.getUserip(),
-					rcm.getScope(), rcm.getExternalUserId(),
-					rcm.getExternalUserType(), rcm.getEmail(),
-					rcm.getFirstname(), rcm.getLastname());
-		} catch (Exception err) {
-			log.error("roomJoin", err);
-		}
+			rcm.setStreamPublishName(parentSid);
+			User u = usersDao.get(rcm.getUser_id());
+			rcm.setUsername(u.getLogin());
+			rcm.setFirstname(u.getFirstname());
+			rcm.setLastname(u.getLastname());
+			log.debug("publishName :: " + rcm.getStreamPublishName());
+			sessionManager.updateClientByStreamId(streamId, rcm, false, null);
+		}
+
+		// Log the User
+		conferenceLogDao.addConferenceLog("ClientConnect",
+				rcm.getUser_id(), streamId, null, rcm.getUserip(),
+				rcm.getScope(), rcm.getExternalUserId(),
+				rcm.getExternalUserType(), rcm.getEmail(),
+				rcm.getFirstname(), rcm.getLastname());
 		return true;
 	}
 
@@ -196,44 +213,45 @@ public class ScopeApplicationAdapter ext
 			log.debug("-----------  screenSharerAction ENTER");
 			IConnection current = Red5.getConnectionLocal();
 
-			Client rc = sessionManager.getClientByStreamId(current.getClient().getId(), null);
+			Client control = sessionManager.getClientByStreamId(current.getClient().getId(), null);
+			Client client = sessionManager.getClientByPublicSID(control.getStreamPublishName(), false, null);
 
 			Map<String, String> returnMap = new HashMap<String, String>();
 
-			if (rc != null) {
+			if (client != null) {
 				boolean changed = false;
-				if (Boolean.valueOf("" + map.get("stopStreaming")) && rc.isStartStreaming()) {
+				if (Boolean.valueOf("" + map.get("stopStreaming")) && client.isStartStreaming()) {
 					changed = true;
-					rc.setStartStreaming(false);
+					client.setStartStreaming(false);
 					//Send message to all users
-					sendMessageToCurrentScope("stopScreenSharingMessage", rc, false);
+					sendMessageToCurrentScope("stopScreenSharingMessage", client, false);
 					
 					returnMap.put("result", "stopSharingOnly");
 				}
-				if (Boolean.valueOf("" + map.get("stopRecording")) && rc.getIsRecording()) {
+				if (Boolean.valueOf("" + map.get("stopRecording")) && client.getIsRecording()) {
 					changed = true;
-					rc.setStartRecording(false);
-					rc.setIsRecording(false);
+					client.setStartRecording(false);
+					client.setIsRecording(false);
 					
 					returnMap.put("result", "stopRecordingOnly");
 					//Send message to all users
-					sendMessageToCurrentScope("stopRecordingMessage", rc, false);
+					sendMessageToCurrentScope("stopRecordingMessage", client, false);
 
-					flvRecorderService.stopRecordAndSave(current.getScope(), rc, null);
+					flvRecorderService.stopRecordAndSave(current.getScope(), client, null);
 				}
-				if (Boolean.valueOf("" + map.get("stopPublishing")) && rc.isScreenPublishStarted()) {
+				if (Boolean.valueOf("" + map.get("stopPublishing")) && client.isScreenPublishStarted()) {
 					changed = true;
-					rc.setScreenPublishStarted(false);
+					client.setScreenPublishStarted(false);
 					returnMap.put("result", "stopPublishingOnly");
 					
 					//Send message to all users
-					sendMessageToCurrentScope("stopPublishingMessage", rc, false);
+					sendMessageToCurrentScope("stopPublishingMessage", client, false);
 				}
 				
 				if (changed) {
-					sessionManager.updateClientByStreamId(rc.getStreamid(), rc, false, null);
+					sessionManager.updateClientByStreamId(client.getStreamid(), client, false, null);
 					
-					if (!rc.isStartStreaming() && !rc.isStartRecording() && !rc.isStreamPublishStarted()) {
+					if (!client.isStartStreaming() && !client.isStartRecording() && !client.isStreamPublishStarted()) {
 						returnMap.put("result", "stopAll");
 					}
 				}
@@ -277,75 +295,50 @@ public class ScopeApplicationAdapter ext
 	 * @return returns key,value Map with multiple return values or null in case of exception
 	 * 
 	 */
-	@SuppressWarnings({ "rawtypes", "unchecked" })
-	public Map setConnectionAsSharingClient(Map map) {
+	public Map<String, Object> setConnectionAsSharingClient(Map<String, Object> map) {
 		try {
 			log.debug("-----------  setConnectionAsSharingClient");
 			IConnection current = Red5.getConnectionLocal();
 
-			Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null);
+			Client control = sessionManager.getClientByStreamId(current.getClient().getId(), null);
+			Client client = sessionManager.getClientByPublicSID(control.getStreamPublishName(), false, null);
 
-			if (currentClient != null) {
+			if (client != null) {
 				boolean startRecording = Boolean.valueOf("" + map.get("startRecording"));
 				boolean startStreaming = Boolean.valueOf("" + map.get("startStreaming"));
-				boolean startPublishing = Boolean.valueOf("" + map.get("startPublishing"))
-					&& (0 == sessionManager.getPublishingCount(currentClient.getRoom_id()));
-
-				currentClient.setRoom_id(Long.parseLong(current.getScope().getName()));
-
-				// Set this connection to be a RTMP-Java Client
-				currentClient.setIsScreenClient(true);
-				
-				SessionVariablesUtil.setIsScreenClient(current.getClient());
-				
-				currentClient.setUser_id(Long.parseLong(map.get("user_id").toString()));
-				SessionVariablesUtil.setUserId(current.getClient(), Long.parseLong(map.get("user_id").toString()));
+				boolean startPublishing = Boolean.valueOf("" + map.get("startPublishing")) && (0 == sessionManager.getPublishingCount(client.getRoom_id()));
 
-				boolean alreadyStreaming = currentClient.isStartStreaming();
+				boolean alreadyStreaming = client.isStartStreaming();
 				if (startStreaming) {
-					currentClient.setStartStreaming(true);
+					client.setStartStreaming(true);
 				}
-				boolean alreadyRecording = currentClient.isStartRecording();
+				boolean alreadyRecording = client.isStartRecording();
 				if (startRecording) {
-					currentClient.setStartRecording(true);
+					client.setStartRecording(true);
 				}
 				if (startPublishing) {
-					currentClient.setStreamPublishStarted(true);
+					client.setStreamPublishStarted(true);
 				}
 
-				sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null);
+				client.setVX(Integer.parseInt(map.get("screenX").toString()));
+				client.setVY(Integer.parseInt(map.get("screenY").toString()));
+				client.setVWidth(Integer.parseInt(map.get("screenWidth").toString()));
+				client.setVHeight(Integer.parseInt(map.get("screenHeight").toString()));
+				sessionManager.updateClientByStreamId(current.getClient().getId(), client, false, null);
 
-				Map returnMap = new HashMap();
+				Map<String, Object> returnMap = new HashMap<String, Object>();
 				returnMap.put("alreadyPublished", false);
 
 				// if is already started screen sharing, then there is no need
 				// to start it again
-				if (currentClient.isScreenPublishStarted()) {
+				if (client.isScreenPublishStarted()) {
 					returnMap.put("alreadyPublished", true);
 				}
 
-				currentClient.setVX(Integer.parseInt(map.get("screenX").toString()));
-				currentClient.setVY(Integer.parseInt(map.get("screenY").toString()));
-				currentClient.setVWidth(Integer.parseInt(map.get("screenWidth").toString()));
-				currentClient.setVHeight(Integer.parseInt(map.get("screenHeight").toString()));
-
-				log.debug("screen x,y,width,height " + currentClient.getVX()
-						+ " " + currentClient.getVY() + " "
-						+ currentClient.getVWidth() + " "
-						+ currentClient.getVHeight());
-
-				log.debug("publishName :: " + map.get("publishName"));
-
-				currentClient.setStreamPublishName(map.get("publishName").toString());
-
-				Client currentScreenUser = sessionManager.getClientByPublicSID(currentClient.getStreamPublishName(), false, null);
-
-				currentClient.setFirstname(currentScreenUser.getFirstname());
-				currentClient.setLastname(currentScreenUser.getLastname());
-
-				// This is duplicated, but its not sure that in the meantime
-				// somebody requests this Client Object Info
-				sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null);
+				log.debug("screen x,y,width,height " + client.getVX()
+						+ " " + client.getVY() + " "
+						+ client.getVWidth() + " "
+						+ client.getVHeight());
 
 				if (startStreaming) {
 					if (!alreadyStreaming) {
@@ -354,9 +347,9 @@ public class ScopeApplicationAdapter ext
 						log.debug("start streamPublishStart Is Screen Sharing ");
 						
 						//Send message to all users
-						sendMessageToCurrentScope("newScreenSharing", currentClient, false);
+						sendMessageToCurrentScope("newScreenSharing", client, false);
 					} else {
-						log.warn("Streaming is already started for the client id=" + currentClient.getId() + ". Second request is ignored.");
+						log.warn("Streaming is already started for the client id=" + client.getId() + ". Second request is ignored.");
 					}
 				}
 				if (startRecording) {
@@ -365,17 +358,16 @@ public class ScopeApplicationAdapter ext
 	
 						String recordingName = "Recording " + CalendarPatterns.getDateWithTimeByMiliSeconds(new Date());
 	
-						flvRecorderService.recordMeetingStream(current, recordingName, "", false);
+						flvRecorderService.recordMeetingStream(current, client, recordingName, "", false);
 					} else {
-						log.warn("Recording is already started for the client id=" + currentClient.getId() + ". Second request is ignored.");
+						log.warn("Recording is already started for the client id=" + client.getId() + ". Second request is ignored.");
 					}
 				}
 				if (startPublishing) {
-					sendMessageToCurrentScope("startedPublishing", new Object[]{currentClient, "rtmp://" + map.get("publishingHost") + ":1935/"
+					sendMessageToCurrentScope("startedPublishing", new Object[]{client, "rtmp://" + map.get("publishingHost") + ":1935/"
 							+ map.get("publishingApp") + "/" + map.get("publishingId")}, false, true);
 					returnMap.put("modus", "startPublishing");
 				}
-
 				return returnMap;
 
 			} else {
@@ -836,10 +828,8 @@ public class ScopeApplicationAdapter ext
 	@SuppressWarnings("unchecked")
 	public void setNewCursorPosition(Object item) {
 		try {
-
 			IConnection current = Red5.getConnectionLocal();
-			String streamid = current.getClient().getId();
-			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
+			Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null);
 
 			@SuppressWarnings("rawtypes")
 			Map cursor = (Map) item;
@@ -1813,7 +1803,10 @@ public class ScopeApplicationAdapter ext
 		@Override
 		public void run() {
 			try {
-				if (scope != null) {
+				if (scope == null) {
+					log.debug(String.format("[MessageSender] -> 'Unable to send message to NULL scope' %s, %s", remoteMethodName, newMessage));
+				} else {
+					log.trace(String.format("[MessageSender] -> 'sending message' %s, %s", remoteMethodName, newMessage));
 					// Send to all Clients of that Scope(Room)
 					for (IConnection conn : scope.getClientConnections()) {
 						if (conn != null && conn instanceof IServiceCapableConnection) {
@@ -1823,9 +1816,10 @@ public class ScopeApplicationAdapter ext
 							((IServiceCapableConnection) conn).invoke(remoteMethodName, new Object[] { newMessage }, ScopeApplicationAdapter.this);
 						}
 					}
+					log.trace(String.format("[MessageSender] -> 'sending message DONE' %s", remoteMethodName));
 				}
 			} catch (Exception err) {
-				log.error(String.format("[sendMessageToCurrentScope -> %s, %s]", remoteMethodName, newMessage), err);
+				log.error(String.format("[MessageSender -> %s, %s]", remoteMethodName, newMessage), err);
 			}
 		}
 	}
@@ -2132,7 +2126,7 @@ public class ScopeApplicationAdapter ext
 			}
 			String recordingName = "Interview " + CalendarPatterns.getDateWithTimeByMiliSeconds(new Date());
 
-			flvRecorderService.recordMeetingStream(current, recordingName, "", true);
+			flvRecorderService.recordMeetingStream(current, current_rcl, recordingName, "", true);
 
 			return true;
 		} catch (Exception err) {
@@ -2142,24 +2136,15 @@ public class ScopeApplicationAdapter ext
 	}
 
 	@SuppressWarnings({ "rawtypes" })
-	public Boolean sendRemoteCursorEvent(String streamid, Map messageObj) {
-		try {
-
-			IConnection current = Red5.getConnectionLocal();
-
-			for (IConnection conn : current.getScope().getClientConnections()) {
-				if (conn != null) {
-					IClient client = conn.getClient();
-					if (SessionVariablesUtil.isScreenClient(client)) {
-						if (conn.getClient().getId().equals(streamid)) {
-							((IServiceCapableConnection) conn).invoke("sendRemoteCursorEvent", new Object[] { messageObj }, this);
-						}
-					}
-				}
+	public Boolean sendRemoteCursorEvent(final String streamid, Map messageObj) {
+		new MessageSender("sendRemoteCursorEvent", messageObj) {
+			
+			@Override
+			public boolean filter(IConnection conn) {
+				IClient client = conn.getClient();
+				return SessionVariablesUtil.isScreenClient(client) && conn.getClient().getId().equals(streamid);
 			}
-		} catch (Exception err) {
-			log.debug("[sendRemoteCursorEvent]", err);
-		}
+		}.start();
 		return null;
 	}
 

Modified: openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java?rev=1656837&r1=1656836&r2=1656837&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java (original)
+++ openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java Tue Feb  3 17:22:29 2015
@@ -30,9 +30,6 @@ import java.awt.Rectangle;
 import java.awt.Robot;
 import java.io.IOException;
 import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
 
 import org.quartz.DisallowConcurrentExecution;
 import org.quartz.Job;
@@ -41,7 +38,9 @@ import org.quartz.JobDataMap;
 import org.quartz.JobDetail;
 import org.quartz.JobExecutionContext;
 import org.quartz.JobExecutionException;
+import org.quartz.JobKey;
 import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
 import org.quartz.SchedulerFactory;
 import org.quartz.SimpleScheduleBuilder;
 import org.quartz.Trigger;
@@ -54,7 +53,9 @@ import org.slf4j.Logger;
 
 class CaptureScreen extends Thread {
 	private static final Logger log = getLogger(CaptureScreen.class);
-	private static final int NANO_MULTIPLIER = 1000 * 1000;
+	private final static String QUARTZ_GROUP_NAME = "ScreenShare";
+	private final static String QUARTZ_CURSOR_TRIGGER_NAME = "CursorTrigger";
+	private final static String QUARTZ_CURSOR_JOB_NAME = "CursorJob";
 	private CoreScreenShare core;
 	private int timeBetweenFrames;
 	private volatile int timestamp = 0;
@@ -68,8 +69,6 @@ class CaptureScreen extends Thread {
 	private int port = -1;
 	private int streamId;
 	private boolean startPublish = false;
-	private boolean sendCursor = false;
-	private final ScheduledExecutorService cursorScheduler = Executors.newScheduledThreadPool(1);
 	private Scheduler scheduler;
 
 	public CaptureScreen(CoreScreenShare coreScreenShare, IScreenShare client, String host, String app, int port) {
@@ -78,6 +77,12 @@ class CaptureScreen extends Thread {
 		this.host = host;
 		this.app = app;
 		this.port = port;
+		SchedulerFactory sf = new StdSchedulerFactory();
+		try {
+			scheduler = sf.getScheduler();
+		} catch (SchedulerException e) {
+			log.error("Unexpected error while creating scheduler", e);
+		}
 	}
 
 	public void release() {
@@ -89,11 +94,6 @@ class CaptureScreen extends Thread {
 		} catch (Exception e) {
 			log.error("Unexpected error while shutting down scheduler", e);
 		}
-		try {
-			cursorScheduler.shutdownNow();
-		} catch (Exception e) {
-			log.error("Unexpected error while shutting down scheduler", e);
-		}
 		active = false;
 		timestamp = 0;
 		timeCaptureStarted = 0;
@@ -109,32 +109,22 @@ class CaptureScreen extends Thread {
 			se = new ScreenV1Encoder(3 * FPS); //send keyframe every 3 seconds
 			timeCaptureStarted = System.currentTimeMillis();
 
-			JobDetail encodeJob = JobBuilder.newJob(EncodeJob.class).withIdentity("EncodeJob", "ScreenShare").build();
+			JobDetail encodeJob = JobBuilder.newJob(EncodeJob.class).withIdentity("EncodeJob", QUARTZ_GROUP_NAME).build();
 			encodeJob.getJobDataMap().put(EncodeJob.CAPTURE_KEY, this);
 			Trigger encodeTrigger = TriggerBuilder.newTrigger()
-					.withIdentity("EncodeTrigger", "ScreenShare")
+					.withIdentity("EncodeTrigger", QUARTZ_GROUP_NAME)
 					.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInMilliseconds(timeBetweenFrames).repeatForever())
 					.build();
-			JobDetail sendJob = JobBuilder.newJob(SendJob.class).withIdentity("SendJob", "ScreenShare").build();
+			JobDetail sendJob = JobBuilder.newJob(SendJob.class).withIdentity("SendJob", QUARTZ_GROUP_NAME).build();
 			Trigger sendTrigger = TriggerBuilder.newTrigger()
-					.withIdentity("SendTrigger", "ScreenShare")
+					.withIdentity("SendTrigger", QUARTZ_GROUP_NAME)
 					.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInMilliseconds(timeBetweenFrames).repeatForever())
 					.build();
 			sendJob.getJobDataMap().put(SendJob.CAPTURE_KEY, this);
 
-			SchedulerFactory sf = new StdSchedulerFactory();
-			scheduler = sf.getScheduler();
 			scheduler.scheduleJob(encodeJob, encodeTrigger);
 			scheduler.scheduleJob(sendJob, sendTrigger);
 			scheduler.start();
-			
-			if (sendCursor) {
-				cursorScheduler.scheduleWithFixedDelay(new Runnable() {
-					public void run() {
-						core.sendCursorStatus();
-					}
-				}, 0, timeBetweenFrames * NANO_MULTIPLIER, TimeUnit.NANOSECONDS);
-			}
 		} catch (Exception e) {
 			log.error("Error while running: ", e);
 		}
@@ -229,6 +219,20 @@ class CaptureScreen extends Thread {
 		}
 	}
 	
+	@DisallowConcurrentExecution
+	public static class CursorJob implements Job {
+		private static final String CAPTURE_KEY = "capture";
+		
+		public CursorJob() {}
+		
+		@Override
+		public void execute(JobExecutionContext context) throws JobExecutionException {
+			JobDataMap data = context.getJobDetail().getJobDataMap();
+			CaptureScreen capture = (CaptureScreen)data.get(CAPTURE_KEY);
+			capture.core.sendCursorStatus();
+		}
+	}
+	
 	private void pushVideo(VideoData data, int ts) throws IOException {
 		if (startPublish) {
 			if (Red5.getConnectionLocal() == null) {
@@ -264,6 +268,20 @@ class CaptureScreen extends Thread {
 	}
 
 	public void setSendCursor(boolean sendCursor) {
-		this.sendCursor = sendCursor;
+		try {
+			if (sendCursor) {
+				JobDetail cursorJob = JobBuilder.newJob(CursorJob.class).withIdentity(QUARTZ_CURSOR_JOB_NAME, QUARTZ_GROUP_NAME).build();
+				Trigger cursorTrigger = TriggerBuilder.newTrigger()
+						.withIdentity(QUARTZ_CURSOR_TRIGGER_NAME, QUARTZ_GROUP_NAME)
+						.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInMilliseconds(1000 / Math.min(2, FPS)).repeatForever())
+						.build();
+				cursorJob.getJobDataMap().put(CursorJob.CAPTURE_KEY, this);
+				scheduler.scheduleJob(cursorJob, cursorTrigger);
+			} else {
+				scheduler.deleteJob(JobKey.jobKey(QUARTZ_CURSOR_JOB_NAME, QUARTZ_GROUP_NAME));
+			}
+		} catch (SchedulerException e) {
+			log.error("Unexpected Error schedule/unschedule cursor job", e);
+		}
 	}
 }

Modified: openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java?rev=1656837&r1=1656836&r2=1656837&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java (original)
+++ openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java Tue Feb  3 17:22:29 2015
@@ -63,6 +63,7 @@ public class CoreScreenShare implements
 		rtmp, rtmpt, rtmpe, rtmps
 	}
 	private IScreenShare instance = null;
+	private IScreenShare controlInstance = null;
 	private Protocol protocol;
 	private String host;
 	private String app;
@@ -79,7 +80,7 @@ public class CoreScreenShare implements
 	public boolean showFPS = true;
 	public boolean allowRemote = true;
 
-	public Long user_id = null;
+	public Long userId = null;
 	private boolean allowRecording = true;
 	private boolean allowPublishing = true;
 
@@ -118,7 +119,7 @@ public class CoreScreenShare implements
 				host = args[1];
 				port = Integer.parseInt(args[2]);
 				app = args[3];
-				user_id = Long.parseLong(args[4]);
+				userId = Long.parseLong(args[4]);
 				publishName = args[5];
 				String labelTexts = args[6];
 				defaultQuality = Integer.parseInt(args[7]);
@@ -143,21 +144,28 @@ public class CoreScreenShare implements
 				switch (protocol) {
 					case rtmp:
 						instance = new RTMPScreenShare(this);
+						controlInstance = new RTMPScreenShare(this);
 						break;
 					case rtmpt:
 						instance = new RTMPTScreenShare(this);
+						controlInstance = new RTMPTScreenShare(this);
 						break;
 					case rtmps:
 						RTMPSScreenShare client = new RTMPSScreenShare(this);
 						client.setKeystoreBytes(Hex.decodeHex(args[13].toCharArray()));
 						client.setKeyStorePassword(args[14]);
 						instance = client;
+						RTMPSScreenShare controlClient = new RTMPSScreenShare(this);
+						controlClient.setKeystoreBytes(Hex.decodeHex(args[13].toCharArray()));
+						controlClient.setKeyStorePassword(args[14]);
+						controlInstance = controlClient;
 						break;
 					case rtmpe:
 					default:
 						throw new Exception("Unsupported protocol");
 				}
-				instance.setServiceProvider(instance);
+				instance.setServiceProvider(this);
+				controlInstance.setServiceProvider(this);
 				log.debug(String.format("host: %s, app: %s, port: %s, publish: %s", host, port, app, publishName));
 			} else {
 				System.exit(0);
@@ -190,7 +198,7 @@ public class CoreScreenShare implements
 		}
 	}
 
-	synchronized public void sendCursorStatus() {
+	public void sendCursorStatus() {
 		try {
 			Point mouseP = MouseInfo.getPointerInfo().getLocation();
 
@@ -205,11 +213,11 @@ public class CoreScreenShare implements
 			cursorPosition.put("cursor_x", x);
 			cursorPosition.put("cursor_y", y);
 
-			if (instance.getConnection() != null) {
+			if (controlInstance.getConnection() != null) {
 				if (Red5.getConnectionLocal() == null) {
-					Red5.setConnectionLocal(instance.getConnection());
+					Red5.setConnectionLocal(controlInstance.getConnection());
 				}
-				instance.invoke("setNewCursorPosition", new Object[] { cursorPosition }, this);
+				controlInstance.invoke("setNewCursorPosition", new Object[] { cursorPosition }, this);
 			}
 		} catch (NullPointerException npe) {
 			//noop
@@ -219,11 +227,13 @@ public class CoreScreenShare implements
 		}
 	}
 
-	synchronized public void setConnectionAsSharingClient() {
+	public void setConnectionAsSharingClient() {
+		log.debug("########## setConnectionAsSharingClient");
 		try {
-			log.debug("########## setConnectionAsSharingClient");
-
-			Map<Object, Object> map = new HashMap<Object, Object>();
+			if (Red5.getConnectionLocal() == null) {
+				Red5.setConnectionLocal(controlInstance.getConnection());
+			}
+			Map<String, Object> map = new HashMap<String, Object>();
 			map.put("screenX", spinnerX);
 			map.put("screenY", spinnerY);
 
@@ -233,20 +243,16 @@ public class CoreScreenShare implements
 			map.put("screenWidth", scaledWidth);
 			map.put("screenHeight", scaledHeight);
 
-			map.put("publishName", publishName);
 			map.put("startRecording", startRecording);
 			map.put("startStreaming", startStreaming);
 			map.put("startPublishing", startPublishing);
 			map.put("publishingHost", frame.getPublishHost());
 			map.put("publishingApp", frame.getPublishApp());
 			map.put("publishingId", frame.getPublishId());
-
-			map.put("user_id", user_id);
-
 			if (Red5.getConnectionLocal() == null) {
-				Red5.setConnectionLocal(instance.getConnection());
+				Red5.setConnectionLocal(controlInstance.getConnection());
 			}
-			instance.invoke("setConnectionAsSharingClient", new Object[] { map }, this);
+			controlInstance.invoke("setConnectionAsSharingClient", new Object[] { map }, this);
 		} catch (Exception err) {
 			frame.setStatus("Error: " + err.getLocalizedMessage());
 			log.error("[setConnectionAsSharingClient]", err);
@@ -268,14 +274,21 @@ public class CoreScreenShare implements
 		captureScreenStart();
 	}
 	
+	private void connect(String parentSid, boolean control) {
+		Map<String, Object> map = instance.makeDefaultConnectionParams(host, port, app);
+		map.put("screenClient", true);
+		map.put("userId", userId);
+		map.put("parentSid", parentSid);
+		(control ? controlInstance : instance).connect(host, port, map, this);
+	}
+	
 	private void captureScreenStart() {
 		try {
 			log.debug("captureScreenStart");
 			
 			if (!isConnected) {
-				instance.connect(host, port, app, this);
-			} 
-			if (isConnected) {
+				connect(publishName, false);
+			} else {
 				setConnectionAsSharingClient();
 			}
 		} catch (Exception err) {
@@ -307,9 +320,9 @@ public class CoreScreenShare implements
 			map.put(action, true);
 
 			if (Red5.getConnectionLocal() == null) {
-				Red5.setConnectionLocal(instance.getConnection());
+				Red5.setConnectionLocal(controlInstance.getConnection());
 			}
-			instance.invoke("screenSharerAction", new Object[] { map }, this);
+			controlInstance.invoke("screenSharerAction", new Object[] { map }, this);
 		} catch (Exception err) {
 			log.error("captureScreenStop Exception: ", err);
 			frame.setStatus("Exception: " + err);
@@ -382,6 +395,7 @@ public class CoreScreenShare implements
 			isConnected = false;
 
 			instance.disconnect();
+			controlInstance.disconnect();
 			setReadyToRecord(false);
 			getCapture().setStartPublish(false);
 			getCapture().release();
@@ -546,7 +560,7 @@ public class CoreScreenShare implements
 
 				String clientId = returnMap.get("clientId").toString();
 
-				instance.invoke("sendMessageWithClientById", new Object[]{map, clientId}, this);
+				controlInstance.invoke("sendMessageWithClientById", new Object[]{map, clientId}, this);
 			} else if (action.equals("show")) {
 				String paste = getClipboardText();
 
@@ -556,10 +570,7 @@ public class CoreScreenShare implements
 
 				String clientId = returnMap.get("clientId").toString();
 
-				// public synchronized int sendMessageWithClientById(Object
-				// newMessage, String clientId)
-
-				instance.invoke("sendMessageWithClientById", new Object[]{map, clientId}, this);
+				controlInstance.invoke("sendMessageWithClientById", new Object[]{map, clientId}, this);
 			}
 		} catch (Exception err) {
 			log.error("[sendRemoteCursorEvent]", err);
@@ -603,14 +614,14 @@ public class CoreScreenShare implements
 		}
 	}
 	
-	private String getHighlightedText(Robot instance) {
+	private String getHighlightedText(Robot robot) {
 		try {
 			if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") >= 0) {
 				// pressing STRG+C == copy
-				pressSequence(instance, 200, KeyEvent.VK_CONTROL, KeyEvent.VK_C, KeyEvent.VK_C, KeyEvent.VK_CONTROL);
+				pressSequence(robot, 200, KeyEvent.VK_CONTROL, KeyEvent.VK_C, KeyEvent.VK_C, KeyEvent.VK_CONTROL);
 			} else {
 				// Macintosh simulate Copy
-				pressSequence(instance, 200, 157, 67, 67, 157);
+				pressSequence(robot, 200, 157, 67, 67, 157);
 			}
 			return getClipboardText();
 		} catch (Exception e) {
@@ -619,7 +630,7 @@ public class CoreScreenShare implements
 		return "";
 	}
 
-	private void pressSpecialSign(String charValue, Robot instance) {
+	private void pressSpecialSign(String charValue, Robot robot) {
 		Clipboard clippy = getDefaultToolkit().getSystemClipboard();
 		try {
 			Transferable transferableText = new StringSelection(charValue);
@@ -627,10 +638,10 @@ public class CoreScreenShare implements
 
 			if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") >= 0) {
 				// pressing STRG+V == insert-mode
-				pressSequence(instance, 100, KeyEvent.VK_CONTROL, KeyEvent.VK_V, KeyEvent.VK_V, KeyEvent.VK_CONTROL);
+				pressSequence(robot, 100, KeyEvent.VK_CONTROL, KeyEvent.VK_V, KeyEvent.VK_V, KeyEvent.VK_CONTROL);
 			} else {
 				// Macintosh simulate Insert
-				pressSequence(instance, 100, 157, 86, 86, 157);
+				pressSequence(robot, 100, 157, 86, 86, 157);
 			}
 		} catch (Exception e) {
 			log.error("Unexpected exception while pressSpecialSign", e);
@@ -640,17 +651,30 @@ public class CoreScreenShare implements
 	public void resultReceived(IPendingServiceCall call) {
 		try {
 
-			log.trace( "service call result: " + call );
+			log.trace("service call result: " + call);
 
 			String method = call == null ? null : call.getServiceMethodName();
+			Object o = call == null ? null : call.getResult();
 			log.trace("call ### get Method Name " + method);
 			if ("connect".equals(method)) {
+				if (o instanceof Map) {
+					@SuppressWarnings("unchecked")
+					Map<String, Object> map = (Map<String, Object>) o;
+					Object code = map.get("code");
+					if ("NetConnection.Connect.Rejected".equals(code) || "NetConnection.Connect.Failed".equals(code)) {
+						frame.setStatus(String.format("Error: %s %s", code, map.get("description")));
+						return;
+					}
+				}
+				if (!isConnected) {
+					instance.invoke("getPublicSID", null, this);
+				} else {
+					setConnectionAsSharingClient();
+				}
 				isConnected = true;
-				setConnectionAsSharingClient();
+			} else if ("getPublicSID".equals(method)) {
+				connect((String)o, true);
 			} else if ("setConnectionAsSharingClient".equals(method)) {
-
-				Object o = call.getResult();
-
 				@SuppressWarnings("unchecked")
 				Map<String, Object> returnMap = (Map<String, Object>) o;
 
@@ -692,13 +716,15 @@ public class CoreScreenShare implements
 	
 					log.debug("setup capture thread spinnerWidth = {}; spinnerHeight = {};", spinnerWidth, spinnerHeight);
 	
-					getCapture().setSendCursor(true);
-					getCapture().start();
+					if (!getCapture().isAlive()) {
+						getCapture().setSendCursor(startStreaming);
+						getCapture().start();
+					}
 				}
 			} else if ("screenSharerAction".equals(method)) {
-				Object o = call.getResult();
-
-				log.trace("Result Map Type " + o.getClass().getName());
+				if (log.isTraceEnabled()) {
+					log.trace("Result Map Type " + (o == null ? null : o.getClass().getName()));
+				}
 
 				@SuppressWarnings("unchecked")
 				Map<String, Object> returnMap = (Map<String, Object>)o;

Modified: openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenShare.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenShare.java?rev=1656837&r1=1656836&r2=1656837&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenShare.java (original)
+++ openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenShare.java Tue Feb  3 17:22:29 2015
@@ -18,6 +18,8 @@
  */
 package org.apache.openmeetings.screen.webstart;
 
+import java.util.Map;
+
 import org.red5.client.net.rtmp.ClientExceptionHandler;
 import org.red5.client.net.rtmp.INetStreamEventHandler;
 import org.red5.server.api.service.IPendingServiceCallback;
@@ -27,7 +29,8 @@ import org.red5.server.net.rtmp.RTMPConn
 public interface IScreenShare extends ClientExceptionHandler {
 	RTMPConnection getConnection();
 	void invoke(String method, Object[] params, IPendingServiceCallback callback);
-	void connect(String server, int port, String application, IPendingServiceCallback connectCallback);
+	Map<String, Object> makeDefaultConnectionParams(String server, int port, String application);
+	void connect(String server, int port, Map<String, Object> connectionParams, IPendingServiceCallback connectCallback);
 	void setServiceProvider(Object serviceProvider);
 	void disconnect();
 	void createStream(IPendingServiceCallback callback);

Modified: openmeetings/trunk/singlewebapp/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/FLVRecorderService.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/FLVRecorderService.java?rev=1656837&r1=1656836&r2=1656837&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/FLVRecorderService.java (original)
+++ openmeetings/trunk/singlewebapp/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/FLVRecorderService.java Tue Feb  3 17:22:29 2015
@@ -99,12 +99,11 @@ public class FLVRecorderService implemen
 		return "rec_" + flvRecording_id + "_stream_" + streamid + "_" + dateString;
 	}
 
-	public String recordMeetingStream(IConnection current, String roomRecordingName, String comment, Boolean isInterview) {
+	public String recordMeetingStream(IConnection current, Client client, String roomRecordingName, String comment, Boolean isInterview) {
 		try {
 			log.debug("##REC:: recordMeetingStream ::");
 
-			Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null);
-			Long room_id = currentClient.getRoom_id();
+			Long room_id = client.getRoom_id();
 
 			Date now = new Date();
 
@@ -112,7 +111,7 @@ public class FLVRecorderService implemen
 
 			flvRecording.setFileHash("");
 			flvRecording.setFileName(roomRecordingName);
-			flvRecording.setInsertedBy(currentClient.getUser_id());
+			flvRecording.setInsertedBy(client.getUser_id());
 			flvRecording.setType(Type.Recording);
 			flvRecording.setComment(comment);
 			flvRecording.setIsInterview(isInterview);
@@ -120,20 +119,20 @@ public class FLVRecorderService implemen
 			flvRecording.setRoomId(room_id);
 			flvRecording.setRecordStart(now);
 
-			flvRecording.setWidth(currentClient.getVWidth());
-			flvRecording.setHeight(currentClient.getVHeight());
+			flvRecording.setWidth(client.getVWidth());
+			flvRecording.setHeight(client.getVHeight());
 
-			flvRecording.setOwnerId(currentClient.getUser_id());
+			flvRecording.setOwnerId(client.getUser_id());
 			flvRecording.setStatus(FlvRecording.Status.RECORDING);
 			flvRecording = recordingDao.update(flvRecording);
 			// Receive flvRecordingId
 			Long flvRecordingId = flvRecording.getId();
-			log.debug("##REC:: recording created by USER: " + currentClient.getUser_id());
+			log.debug("##REC:: recording created by USER: " + client.getUser_id());
 
 			// Update Client and set Flag
-			currentClient.setIsRecording(true);
-			currentClient.setFlvRecordingId(flvRecordingId);
-			sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null);
+			client.setIsRecording(true);
+			client.setFlvRecordingId(flvRecordingId);
+			sessionManager.updateClientByStreamId(client.getStreamid(), client, false, null);
 
 			// get all stream and start recording them
 			for (IConnection conn : current.getScope().getClientConnections()) {
@@ -143,7 +142,7 @@ public class FLVRecorderService implemen
 
 						// Send every user a notification that the recording did start
 						if (!rcl.isAvClient()) {
-							((IServiceCapableConnection) conn).invoke("startedRecording", new Object[] { currentClient }, this);
+							((IServiceCapableConnection) conn).invoke("startedRecording", new Object[] { client }, this);
 						}
 
 						// If its the recording client we need another type of Meta Data

Modified: openmeetings/trunk/singlewebapp/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/red5/ScopeApplicationAdapter.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/red5/ScopeApplicationAdapter.java?rev=1656837&r1=1656836&r2=1656837&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/red5/ScopeApplicationAdapter.java (original)
+++ openmeetings/trunk/singlewebapp/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/red5/ScopeApplicationAdapter.java Tue Feb  3 17:22:29 2015
@@ -143,42 +143,59 @@ public class ScopeApplicationAdapter ext
 	public boolean roomConnect(IConnection conn, Object[] params) {
 		log.debug("roomConnect : ");
 
-		try {
+		IServiceCapableConnection service = (IServiceCapableConnection) conn;
+		String streamId = conn.getClient().getId();
+		
+		boolean isAVClient = params.length == 1 ? Boolean.valueOf("" + params[0]) : false;
 
-			IServiceCapableConnection service = (IServiceCapableConnection) conn;
-			String streamId = conn.getClient().getId();
-			
-			boolean isAVClient = false;
-			if (params.length == 1) {
-				isAVClient = Boolean.valueOf("" + params[0]);
-			}
+		log.debug("### Client connected to OpenMeetings, register Client StreamId: " + streamId + " scope "
+				+ conn.getScope().getName() + " isAVClient " + isAVClient);
 
-			log.debug("### Client connected to OpenMeetings, register Client StreamId: " + streamId + " scope "
-					+ conn.getScope().getName() + " isAVClient " + isAVClient);
+		// Set StreamId in Client
+		service.invoke("setId", new Object[] { streamId }, this);
 
-			// Set StreamId in Client
-			service.invoke("setId", new Object[] { streamId }, this);
+		Map<String, Object> map = conn.getConnectParams();
+		String swfURL = map.containsKey("swfUrl") ? (String)map.get("swfUrl") : "";
 
-			String swfURL = "";
-			if (conn.getConnectParams().get("swfUrl") != null) {
-				swfURL = conn.getConnectParams().get("swfUrl").toString();
+		//TODO add similar code for other connections
+		if (map.containsKey("screenClient")) {
+			String parentSid = (String)map.get("parentSid");
+			Client parentClient = sessionManager.getClientByPublicSID(parentSid, false, null);
+			if (parentClient == null) {
+				rejectClient();
 			}
-
-			Client rcm = sessionManager.addClientListItem(streamId,
-					conn.getScope().getName(), conn.getRemotePort(),
-					conn.getRemoteAddress(), swfURL, isAVClient, null);
+		}
+		Client rcm = sessionManager.addClientListItem(conn.getClient().getId(),
+				conn.getScope().getName(), conn.getRemotePort(),
+				conn.getRemoteAddress(), swfURL, isAVClient, null);
+		
+		SessionVariablesUtil.initClient(conn.getClient(), isAVClient, rcm.getPublicSID());
+		//TODO add similar code for other connections, merge with above block
+		if (map.containsKey("screenClient")) {
+			//TODO add check for room rights
+			String parentSid = (String)map.get("parentSid");
+			rcm.setRoom_id(Long.parseLong(conn.getScope().getName()));
+			rcm.setScreenClient(true);
+			SessionVariablesUtil.setIsScreenClient(conn.getClient());
 			
-			SessionVariablesUtil.initClient(conn.getClient(), isAVClient, rcm.getPublicSID());
+			rcm.setUser_id(((Integer)map.get("userId")).longValue());
+			SessionVariablesUtil.setUserId(conn.getClient(), rcm.getUser_id());
 
-			// Log the User
-			conferenceLogDao.addConferenceLog("ClientConnect",
-					rcm.getUser_id(), streamId, null, rcm.getUserip(),
-					rcm.getScope(), rcm.getExternalUserId(),
-					rcm.getExternalUserType(), rcm.getEmail(),
-					rcm.getFirstname(), rcm.getLastname());
-		} catch (Exception err) {
-			log.error("roomJoin", err);
-		}
+			rcm.setStreamPublishName(parentSid);
+			User u = usersDao.get(rcm.getUser_id());
+			rcm.setUsername(u.getLogin());
+			rcm.setFirstname(u.getFirstname());
+			rcm.setLastname(u.getLastname());
+			log.debug("publishName :: " + rcm.getStreamPublishName());
+			sessionManager.updateClientByStreamId(streamId, rcm, false, null);
+		}
+
+		// Log the User
+		conferenceLogDao.addConferenceLog("ClientConnect",
+				rcm.getUser_id(), streamId, null, rcm.getUserip(),
+				rcm.getScope(), rcm.getExternalUserId(),
+				rcm.getExternalUserType(), rcm.getEmail(),
+				rcm.getFirstname(), rcm.getLastname());
 		return true;
 	}
 
@@ -187,44 +204,45 @@ public class ScopeApplicationAdapter ext
 			log.debug("-----------  screenSharerAction ENTER");
 			IConnection current = Red5.getConnectionLocal();
 
-			Client rc = sessionManager.getClientByStreamId(current.getClient().getId(), null);
+			Client control = sessionManager.getClientByStreamId(current.getClient().getId(), null);
+			Client client = sessionManager.getClientByPublicSID(control.getStreamPublishName(), false, null);
 
 			Map<String, String> returnMap = new HashMap<String, String>();
 
-			if (rc != null) {
+			if (client != null) {
 				boolean changed = false;
-				if (Boolean.valueOf("" + map.get("stopStreaming")) && rc.isStartStreaming()) {
+				if (Boolean.valueOf("" + map.get("stopStreaming")) && client.isStartStreaming()) {
 					changed = true;
-					rc.setStartStreaming(false);
+					client.setStartStreaming(false);
 					//Send message to all users
-					sendMessageToCurrentScope("stopScreenSharingMessage", rc, false);
+					sendMessageToCurrentScope("stopScreenSharingMessage", client, false);
 					
 					returnMap.put("result", "stopSharingOnly");
 				}
-				if (Boolean.valueOf("" + map.get("stopRecording")) && rc.getIsRecording()) {
+				if (Boolean.valueOf("" + map.get("stopRecording")) && client.getIsRecording()) {
 					changed = true;
-					rc.setStartRecording(false);
-					rc.setIsRecording(false);
+					client.setStartRecording(false);
+					client.setIsRecording(false);
 					
 					returnMap.put("result", "stopRecordingOnly");
 					//Send message to all users
-					sendMessageToCurrentScope("stopRecordingMessage", rc, false);
+					sendMessageToCurrentScope("stopRecordingMessage", client, false);
 
-					flvRecorderService.stopRecordAndSave(current.getScope(), rc, null);
+					flvRecorderService.stopRecordAndSave(current.getScope(), client, null);
 				}
-				if (Boolean.valueOf("" + map.get("stopPublishing")) && rc.isScreenPublishStarted()) {
+				if (Boolean.valueOf("" + map.get("stopPublishing")) && client.isScreenPublishStarted()) {
 					changed = true;
-					rc.setScreenPublishStarted(false);
+					client.setScreenPublishStarted(false);
 					returnMap.put("result", "stopPublishingOnly");
 					
 					//Send message to all users
-					sendMessageToCurrentScope("stopPublishingMessage", rc, false);
+					sendMessageToCurrentScope("stopPublishingMessage", client, false);
 				}
 				
 				if (changed) {
-					sessionManager.updateClientByStreamId(rc.getStreamid(), rc, false, null);
+					sessionManager.updateClientByStreamId(client.getStreamid(), client, false, null);
 					
-					if (!rc.isStartStreaming() && !rc.isStartRecording() && !rc.isStreamPublishStarted()) {
+					if (!client.isStartStreaming() && !client.isStartRecording() && !client.isStreamPublishStarted()) {
 						returnMap.put("result", "stopAll");
 					}
 				}
@@ -268,75 +286,50 @@ public class ScopeApplicationAdapter ext
 	 * @return returns key,value Map with multiple return values or null in case of exception
 	 * 
 	 */
-	@SuppressWarnings({ "rawtypes", "unchecked" })
-	public Map setConnectionAsSharingClient(Map map) {
+	public Map<String, Object> setConnectionAsSharingClient(Map<String, Object> map) {
 		try {
 			log.debug("-----------  setConnectionAsSharingClient");
 			IConnection current = Red5.getConnectionLocal();
 
-			Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null);
+			Client control = sessionManager.getClientByStreamId(current.getClient().getId(), null);
+			Client client = sessionManager.getClientByPublicSID(control.getStreamPublishName(), false, null);
 
-			if (currentClient != null) {
+			if (client != null) {
 				boolean startRecording = Boolean.valueOf("" + map.get("startRecording"));
 				boolean startStreaming = Boolean.valueOf("" + map.get("startStreaming"));
-				boolean startPublishing = Boolean.valueOf("" + map.get("startPublishing"))
-					&& (0 == sessionManager.getPublishingCount(currentClient.getRoom_id()));
-
-				currentClient.setRoom_id(Long.parseLong(current.getScope().getName()));
-
-				// Set this connection to be a RTMP-Java Client
-				currentClient.setScreenClient(true);
-				
-				SessionVariablesUtil.setIsScreenClient(current.getClient());
-				
-				currentClient.setUser_id(Long.parseLong(map.get("user_id").toString()));
-				SessionVariablesUtil.setUserId(current.getClient(), Long.parseLong(map.get("user_id").toString()));
+				boolean startPublishing = Boolean.valueOf("" + map.get("startPublishing")) && (0 == sessionManager.getPublishingCount(client.getRoom_id()));
 
-				boolean alreadyStreaming = currentClient.isStartStreaming();
+				boolean alreadyStreaming = client.isStartStreaming();
 				if (startStreaming) {
-					currentClient.setStartStreaming(true);
+					client.setStartStreaming(true);
 				}
-				boolean alreadyRecording = currentClient.isStartRecording();
+				boolean alreadyRecording = client.isStartRecording();
 				if (startRecording) {
-					currentClient.setStartRecording(true);
+					client.setStartRecording(true);
 				}
 				if (startPublishing) {
-					currentClient.setStreamPublishStarted(true);
+					client.setStreamPublishStarted(true);
 				}
 
-				sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null);
+				client.setVX(Integer.parseInt(map.get("screenX").toString()));
+				client.setVY(Integer.parseInt(map.get("screenY").toString()));
+				client.setVWidth(Integer.parseInt(map.get("screenWidth").toString()));
+				client.setVHeight(Integer.parseInt(map.get("screenHeight").toString()));
+				sessionManager.updateClientByStreamId(current.getClient().getId(), client, false, null);
 
-				Map returnMap = new HashMap();
+				Map<String, Object> returnMap = new HashMap<String, Object>();
 				returnMap.put("alreadyPublished", false);
 
 				// if is already started screen sharing, then there is no need
 				// to start it again
-				if (currentClient.isScreenPublishStarted()) {
+				if (client.isScreenPublishStarted()) {
 					returnMap.put("alreadyPublished", true);
 				}
 
-				currentClient.setVX(Integer.parseInt(map.get("screenX").toString()));
-				currentClient.setVY(Integer.parseInt(map.get("screenY").toString()));
-				currentClient.setVWidth(Integer.parseInt(map.get("screenWidth").toString()));
-				currentClient.setVHeight(Integer.parseInt(map.get("screenHeight").toString()));
-
-				log.debug("screen x,y,width,height " + currentClient.getVX()
-						+ " " + currentClient.getVY() + " "
-						+ currentClient.getVWidth() + " "
-						+ currentClient.getVHeight());
-
-				log.debug("publishName :: " + map.get("publishName"));
-
-				currentClient.setStreamPublishName(map.get("publishName").toString());
-
-				Client currentScreenUser = sessionManager.getClientByPublicSID(currentClient.getStreamPublishName(), false, null);
-
-				currentClient.setFirstname(currentScreenUser.getFirstname());
-				currentClient.setLastname(currentScreenUser.getLastname());
-
-				// This is duplicated, but its not sure that in the meantime
-				// somebody requests this Client Object Info
-				sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null);
+				log.debug("screen x,y,width,height " + client.getVX()
+						+ " " + client.getVY() + " "
+						+ client.getVWidth() + " "
+						+ client.getVHeight());
 
 				if (startStreaming) {
 					if (!alreadyStreaming) {
@@ -345,9 +338,9 @@ public class ScopeApplicationAdapter ext
 						log.debug("start streamPublishStart Is Screen Sharing ");
 						
 						//Send message to all users
-						sendMessageToCurrentScope("newScreenSharing", currentClient, false);
+						sendMessageToCurrentScope("newScreenSharing", client, false);
 					} else {
-						log.warn("Streaming is already started for the client id=" + currentClient.getId() + ". Second request is ignored.");
+						log.warn("Streaming is already started for the client id=" + client.getId() + ". Second request is ignored.");
 					}
 				}
 				if (startRecording) {
@@ -356,17 +349,16 @@ public class ScopeApplicationAdapter ext
 	
 						String recordingName = "Recording " + CalendarPatterns.getDateWithTimeByMiliSeconds(new Date());
 	
-						flvRecorderService.recordMeetingStream(current, recordingName, "", false);
+						flvRecorderService.recordMeetingStream(current, client, recordingName, "", false);
 					} else {
-						log.warn("Recording is already started for the client id=" + currentClient.getId() + ". Second request is ignored.");
+						log.warn("Recording is already started for the client id=" + client.getId() + ". Second request is ignored.");
 					}
 				}
 				if (startPublishing) {
-					sendMessageToCurrentScope("startedPublishing", new Object[]{currentClient, "rtmp://" + map.get("publishingHost") + ":1935/"
+					sendMessageToCurrentScope("startedPublishing", new Object[]{client, "rtmp://" + map.get("publishingHost") + ":1935/"
 							+ map.get("publishingApp") + "/" + map.get("publishingId")}, false, true);
 					returnMap.put("modus", "startPublishing");
 				}
-
 				return returnMap;
 
 			} else {
@@ -827,10 +819,8 @@ public class ScopeApplicationAdapter ext
 	@SuppressWarnings("unchecked")
 	public void setNewCursorPosition(Object item) {
 		try {
-
 			IConnection current = Red5.getConnectionLocal();
-			String streamid = current.getClient().getId();
-			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
+			Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null);
 
 			@SuppressWarnings("rawtypes")
 			Map cursor = (Map) item;
@@ -1799,7 +1789,10 @@ public class ScopeApplicationAdapter ext
 		@Override
 		public void run() {
 			try {
-				if (scope != null) {
+				if (scope == null) {
+					log.debug(String.format("[MessageSender] -> 'Unable to send message to NULL scope' %s, %s", remoteMethodName, newMessage));
+				} else {
+					log.trace(String.format("[MessageSender] -> 'sending message' %s, %s", remoteMethodName, newMessage));
 					// Send to all Clients of that Scope(Room)
 					for (IConnection conn : scope.getClientConnections()) {
 						if (conn != null && conn instanceof IServiceCapableConnection) {
@@ -1809,9 +1802,10 @@ public class ScopeApplicationAdapter ext
 							((IServiceCapableConnection) conn).invoke(remoteMethodName, new Object[] { newMessage }, ScopeApplicationAdapter.this);
 						}
 					}
+					log.trace(String.format("[MessageSender] -> 'sending message DONE' %s", remoteMethodName));
 				}
 			} catch (Exception err) {
-				log.error(String.format("[sendMessageToCurrentScope -> %s, %s]", remoteMethodName, newMessage), err);
+				log.error(String.format("[MessageSender -> %s, %s]", remoteMethodName, newMessage), err);
 			}
 		}
 	}
@@ -2118,7 +2112,7 @@ public class ScopeApplicationAdapter ext
 			}
 			String recordingName = "Interview " + CalendarPatterns.getDateWithTimeByMiliSeconds(new Date());
 
-			flvRecorderService.recordMeetingStream(current, recordingName, "", true);
+			flvRecorderService.recordMeetingStream(current, current_rcl, recordingName, "", true);
 
 			return true;
 		} catch (Exception err) {
@@ -2128,24 +2122,15 @@ public class ScopeApplicationAdapter ext
 	}
 
 	@SuppressWarnings({ "rawtypes" })
-	public Boolean sendRemoteCursorEvent(String streamid, Map messageObj) {
-		try {
-
-			IConnection current = Red5.getConnectionLocal();
-
-			for (IConnection conn : current.getScope().getClientConnections()) {
-				if (conn != null) {
-					IClient client = conn.getClient();
-					if (SessionVariablesUtil.isScreenClient(client)) {
-						if (conn.getClient().getId().equals(streamid)) {
-							((IServiceCapableConnection) conn).invoke("sendRemoteCursorEvent", new Object[] { messageObj }, this);
-						}
-					}
-				}
+	public Boolean sendRemoteCursorEvent(final String streamid, Map messageObj) {
+		new MessageSender("sendRemoteCursorEvent", messageObj) {
+			
+			@Override
+			public boolean filter(IConnection conn) {
+				IClient client = conn.getClient();
+				return SessionVariablesUtil.isScreenClient(client) && conn.getClient().getId().equals(streamid);
 			}
-		} catch (Exception err) {
-			log.debug("[sendRemoteCursorEvent]", err);
-		}
+		}.start();
 		return null;
 	}
 

Modified: openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java?rev=1656837&r1=1656836&r2=1656837&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java (original)
+++ openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java Tue Feb  3 17:22:29 2015
@@ -30,9 +30,6 @@ import java.awt.Rectangle;
 import java.awt.Robot;
 import java.io.IOException;
 import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
 
 import org.quartz.DisallowConcurrentExecution;
 import org.quartz.Job;
@@ -41,7 +38,9 @@ import org.quartz.JobDataMap;
 import org.quartz.JobDetail;
 import org.quartz.JobExecutionContext;
 import org.quartz.JobExecutionException;
+import org.quartz.JobKey;
 import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
 import org.quartz.SchedulerFactory;
 import org.quartz.SimpleScheduleBuilder;
 import org.quartz.Trigger;
@@ -54,7 +53,9 @@ import org.slf4j.Logger;
 
 class CaptureScreen extends Thread {
 	private static final Logger log = getLogger(CaptureScreen.class);
-	private static final int NANO_MULTIPLIER = 1000 * 1000;
+	private final static String QUARTZ_GROUP_NAME = "ScreenShare";
+	private final static String QUARTZ_CURSOR_TRIGGER_NAME = "CursorTrigger";
+	private final static String QUARTZ_CURSOR_JOB_NAME = "CursorJob";
 	private CoreScreenShare core;
 	private int timeBetweenFrames;
 	private volatile int timestamp = 0;
@@ -68,8 +69,6 @@ class CaptureScreen extends Thread {
 	private int port = -1;
 	private int streamId;
 	private boolean startPublish = false;
-	private boolean sendCursor = false;
-	private final ScheduledExecutorService cursorScheduler = Executors.newScheduledThreadPool(1);
 	private Scheduler scheduler;
 
 	public CaptureScreen(CoreScreenShare coreScreenShare, IScreenShare client, String host, String app, int port) {
@@ -78,6 +77,12 @@ class CaptureScreen extends Thread {
 		this.host = host;
 		this.app = app;
 		this.port = port;
+		SchedulerFactory sf = new StdSchedulerFactory();
+		try {
+			scheduler = sf.getScheduler();
+		} catch (SchedulerException e) {
+			log.error("Unexpected error while creating scheduler", e);
+		}
 	}
 
 	public void release() {
@@ -89,11 +94,6 @@ class CaptureScreen extends Thread {
 		} catch (Exception e) {
 			log.error("Unexpected error while shutting down scheduler", e);
 		}
-		try {
-			cursorScheduler.shutdownNow();
-		} catch (Exception e) {
-			log.error("Unexpected error while shutting down scheduler", e);
-		}
 		active = false;
 		timestamp = 0;
 		timeCaptureStarted = 0;
@@ -109,32 +109,22 @@ class CaptureScreen extends Thread {
 			se = new ScreenV1Encoder(3 * FPS); //send keyframe every 3 seconds
 			timeCaptureStarted = System.currentTimeMillis();
 
-			JobDetail encodeJob = JobBuilder.newJob(EncodeJob.class).withIdentity("EncodeJob", "ScreenShare").build();
+			JobDetail encodeJob = JobBuilder.newJob(EncodeJob.class).withIdentity("EncodeJob", QUARTZ_GROUP_NAME).build();
 			encodeJob.getJobDataMap().put(EncodeJob.CAPTURE_KEY, this);
 			Trigger encodeTrigger = TriggerBuilder.newTrigger()
-					.withIdentity("EncodeTrigger", "ScreenShare")
+					.withIdentity("EncodeTrigger", QUARTZ_GROUP_NAME)
 					.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInMilliseconds(timeBetweenFrames).repeatForever())
 					.build();
-			JobDetail sendJob = JobBuilder.newJob(SendJob.class).withIdentity("SendJob", "ScreenShare").build();
+			JobDetail sendJob = JobBuilder.newJob(SendJob.class).withIdentity("SendJob", QUARTZ_GROUP_NAME).build();
 			Trigger sendTrigger = TriggerBuilder.newTrigger()
-					.withIdentity("SendTrigger", "ScreenShare")
+					.withIdentity("SendTrigger", QUARTZ_GROUP_NAME)
 					.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInMilliseconds(timeBetweenFrames).repeatForever())
 					.build();
 			sendJob.getJobDataMap().put(SendJob.CAPTURE_KEY, this);
 
-			SchedulerFactory sf = new StdSchedulerFactory();
-			scheduler = sf.getScheduler();
 			scheduler.scheduleJob(encodeJob, encodeTrigger);
 			scheduler.scheduleJob(sendJob, sendTrigger);
 			scheduler.start();
-			
-			if (sendCursor) {
-				cursorScheduler.scheduleWithFixedDelay(new Runnable() {
-					public void run() {
-						core.sendCursorStatus();
-					}
-				}, 0, timeBetweenFrames * NANO_MULTIPLIER, TimeUnit.NANOSECONDS);
-			}
 		} catch (Exception e) {
 			log.error("Error while running: ", e);
 		}
@@ -229,6 +219,20 @@ class CaptureScreen extends Thread {
 		}
 	}
 	
+	@DisallowConcurrentExecution
+	public static class CursorJob implements Job {
+		private static final String CAPTURE_KEY = "capture";
+		
+		public CursorJob() {}
+		
+		@Override
+		public void execute(JobExecutionContext context) throws JobExecutionException {
+			JobDataMap data = context.getJobDetail().getJobDataMap();
+			CaptureScreen capture = (CaptureScreen)data.get(CAPTURE_KEY);
+			capture.core.sendCursorStatus();
+		}
+	}
+	
 	private void pushVideo(VideoData data, int ts) throws IOException {
 		if (startPublish) {
 			if (Red5.getConnectionLocal() == null) {
@@ -264,6 +268,20 @@ class CaptureScreen extends Thread {
 	}
 
 	public void setSendCursor(boolean sendCursor) {
-		this.sendCursor = sendCursor;
+		try {
+			if (sendCursor) {
+				JobDetail cursorJob = JobBuilder.newJob(CursorJob.class).withIdentity(QUARTZ_CURSOR_JOB_NAME, QUARTZ_GROUP_NAME).build();
+				Trigger cursorTrigger = TriggerBuilder.newTrigger()
+						.withIdentity(QUARTZ_CURSOR_TRIGGER_NAME, QUARTZ_GROUP_NAME)
+						.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInMilliseconds(1000 / Math.min(2, FPS)).repeatForever())
+						.build();
+				cursorJob.getJobDataMap().put(CursorJob.CAPTURE_KEY, this);
+				scheduler.scheduleJob(cursorJob, cursorTrigger);
+			} else {
+				scheduler.deleteJob(JobKey.jobKey(QUARTZ_CURSOR_JOB_NAME, QUARTZ_GROUP_NAME));
+			}
+		} catch (SchedulerException e) {
+			log.error("Unexpected Error schedule/unschedule cursor job", e);
+		}
 	}
 }

Modified: openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java?rev=1656837&r1=1656836&r2=1656837&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java (original)
+++ openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java Tue Feb  3 17:22:29 2015
@@ -63,6 +63,7 @@ public class CoreScreenShare implements
 		rtmp, rtmpt, rtmpe, rtmps
 	}
 	private IScreenShare instance = null;
+	private IScreenShare controlInstance = null;
 	private Protocol protocol;
 	private String host;
 	private String app;
@@ -79,7 +80,7 @@ public class CoreScreenShare implements
 	public boolean showFPS = true;
 	public boolean allowRemote = true;
 
-	public Long user_id = null;
+	public Long userId = null;
 	private boolean allowRecording = true;
 	private boolean allowPublishing = true;
 
@@ -118,7 +119,7 @@ public class CoreScreenShare implements
 				host = args[1];
 				port = Integer.parseInt(args[2]);
 				app = args[3];
-				user_id = Long.parseLong(args[4]);
+				userId = Long.parseLong(args[4]);
 				publishName = args[5];
 				String labelTexts = args[6];
 				defaultQuality = Integer.parseInt(args[7]);
@@ -143,21 +144,28 @@ public class CoreScreenShare implements
 				switch (protocol) {
 					case rtmp:
 						instance = new RTMPScreenShare(this);
+						controlInstance = new RTMPScreenShare(this);
 						break;
 					case rtmpt:
 						instance = new RTMPTScreenShare(this);
+						controlInstance = new RTMPTScreenShare(this);
 						break;
 					case rtmps:
 						RTMPSScreenShare client = new RTMPSScreenShare(this);
 						client.setKeystoreBytes(Hex.decodeHex(args[13].toCharArray()));
 						client.setKeyStorePassword(args[14]);
 						instance = client;
+						RTMPSScreenShare controlClient = new RTMPSScreenShare(this);
+						controlClient.setKeystoreBytes(Hex.decodeHex(args[13].toCharArray()));
+						controlClient.setKeyStorePassword(args[14]);
+						controlInstance = controlClient;
 						break;
 					case rtmpe:
 					default:
 						throw new Exception("Unsupported protocol");
 				}
-				instance.setServiceProvider(instance);
+				instance.setServiceProvider(this);
+				controlInstance.setServiceProvider(this);
 				log.debug(String.format("host: %s, app: %s, port: %s, publish: %s", host, port, app, publishName));
 			} else {
 				System.exit(0);
@@ -190,7 +198,7 @@ public class CoreScreenShare implements
 		}
 	}
 
-	synchronized public void sendCursorStatus() {
+	public void sendCursorStatus() {
 		try {
 			Point mouseP = MouseInfo.getPointerInfo().getLocation();
 
@@ -205,11 +213,11 @@ public class CoreScreenShare implements
 			cursorPosition.put("cursor_x", x);
 			cursorPosition.put("cursor_y", y);
 
-			if (instance.getConnection() != null) {
+			if (controlInstance.getConnection() != null) {
 				if (Red5.getConnectionLocal() == null) {
-					Red5.setConnectionLocal(instance.getConnection());
+					Red5.setConnectionLocal(controlInstance.getConnection());
 				}
-				instance.invoke("setNewCursorPosition", new Object[] { cursorPosition }, this);
+				controlInstance.invoke("setNewCursorPosition", new Object[] { cursorPosition }, this);
 			}
 		} catch (NullPointerException npe) {
 			//noop
@@ -219,11 +227,13 @@ public class CoreScreenShare implements
 		}
 	}
 
-	synchronized public void setConnectionAsSharingClient() {
+	public void setConnectionAsSharingClient() {
+		log.debug("########## setConnectionAsSharingClient");
 		try {
-			log.debug("########## setConnectionAsSharingClient");
-
-			Map<Object, Object> map = new HashMap<Object, Object>();
+			if (Red5.getConnectionLocal() == null) {
+				Red5.setConnectionLocal(controlInstance.getConnection());
+			}
+			Map<String, Object> map = new HashMap<String, Object>();
 			map.put("screenX", spinnerX);
 			map.put("screenY", spinnerY);
 
@@ -233,20 +243,16 @@ public class CoreScreenShare implements
 			map.put("screenWidth", scaledWidth);
 			map.put("screenHeight", scaledHeight);
 
-			map.put("publishName", publishName);
 			map.put("startRecording", startRecording);
 			map.put("startStreaming", startStreaming);
 			map.put("startPublishing", startPublishing);
 			map.put("publishingHost", frame.getPublishHost());
 			map.put("publishingApp", frame.getPublishApp());
 			map.put("publishingId", frame.getPublishId());
-
-			map.put("user_id", user_id);
-
 			if (Red5.getConnectionLocal() == null) {
-				Red5.setConnectionLocal(instance.getConnection());
+				Red5.setConnectionLocal(controlInstance.getConnection());
 			}
-			instance.invoke("setConnectionAsSharingClient", new Object[] { map }, this);
+			controlInstance.invoke("setConnectionAsSharingClient", new Object[] { map }, this);
 		} catch (Exception err) {
 			frame.setStatus("Error: " + err.getLocalizedMessage());
 			log.error("[setConnectionAsSharingClient]", err);
@@ -268,14 +274,21 @@ public class CoreScreenShare implements
 		captureScreenStart();
 	}
 	
+	private void connect(String parentSid, boolean control) {
+		Map<String, Object> map = instance.makeDefaultConnectionParams(host, port, app);
+		map.put("screenClient", true);
+		map.put("userId", userId);
+		map.put("parentSid", parentSid);
+		(control ? controlInstance : instance).connect(host, port, map, this);
+	}
+	
 	private void captureScreenStart() {
 		try {
 			log.debug("captureScreenStart");
 			
 			if (!isConnected) {
-				instance.connect(host, port, app, this);
-			} 
-			if (isConnected) {
+				connect(publishName, false);
+			} else {
 				setConnectionAsSharingClient();
 			}
 		} catch (Exception err) {
@@ -307,9 +320,9 @@ public class CoreScreenShare implements
 			map.put(action, true);
 
 			if (Red5.getConnectionLocal() == null) {
-				Red5.setConnectionLocal(instance.getConnection());
+				Red5.setConnectionLocal(controlInstance.getConnection());
 			}
-			instance.invoke("screenSharerAction", new Object[] { map }, this);
+			controlInstance.invoke("screenSharerAction", new Object[] { map }, this);
 		} catch (Exception err) {
 			log.error("captureScreenStop Exception: ", err);
 			frame.setStatus("Exception: " + err);
@@ -382,6 +395,7 @@ public class CoreScreenShare implements
 			isConnected = false;
 
 			instance.disconnect();
+			controlInstance.disconnect();
 			setReadyToRecord(false);
 			getCapture().setStartPublish(false);
 			getCapture().release();
@@ -546,7 +560,7 @@ public class CoreScreenShare implements
 
 				String clientId = returnMap.get("clientId").toString();
 
-				instance.invoke("sendMessageWithClientById", new Object[]{map, clientId}, this);
+				controlInstance.invoke("sendMessageWithClientById", new Object[]{map, clientId}, this);
 			} else if (action.equals("show")) {
 				String paste = getClipboardText();
 
@@ -556,10 +570,7 @@ public class CoreScreenShare implements
 
 				String clientId = returnMap.get("clientId").toString();
 
-				// public synchronized int sendMessageWithClientById(Object
-				// newMessage, String clientId)
-
-				instance.invoke("sendMessageWithClientById", new Object[]{map, clientId}, this);
+				controlInstance.invoke("sendMessageWithClientById", new Object[]{map, clientId}, this);
 			}
 		} catch (Exception err) {
 			log.error("[sendRemoteCursorEvent]", err);
@@ -603,14 +614,14 @@ public class CoreScreenShare implements
 		}
 	}
 	
-	private String getHighlightedText(Robot instance) {
+	private String getHighlightedText(Robot robot) {
 		try {
 			if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") >= 0) {
 				// pressing STRG+C == copy
-				pressSequence(instance, 200, KeyEvent.VK_CONTROL, KeyEvent.VK_C, KeyEvent.VK_C, KeyEvent.VK_CONTROL);
+				pressSequence(robot, 200, KeyEvent.VK_CONTROL, KeyEvent.VK_C, KeyEvent.VK_C, KeyEvent.VK_CONTROL);
 			} else {
 				// Macintosh simulate Copy
-				pressSequence(instance, 200, 157, 67, 67, 157);
+				pressSequence(robot, 200, 157, 67, 67, 157);
 			}
 			return getClipboardText();
 		} catch (Exception e) {
@@ -619,7 +630,7 @@ public class CoreScreenShare implements
 		return "";
 	}
 
-	private void pressSpecialSign(String charValue, Robot instance) {
+	private void pressSpecialSign(String charValue, Robot robot) {
 		Clipboard clippy = getDefaultToolkit().getSystemClipboard();
 		try {
 			Transferable transferableText = new StringSelection(charValue);
@@ -627,10 +638,10 @@ public class CoreScreenShare implements
 
 			if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") >= 0) {
 				// pressing STRG+V == insert-mode
-				pressSequence(instance, 100, KeyEvent.VK_CONTROL, KeyEvent.VK_V, KeyEvent.VK_V, KeyEvent.VK_CONTROL);
+				pressSequence(robot, 100, KeyEvent.VK_CONTROL, KeyEvent.VK_V, KeyEvent.VK_V, KeyEvent.VK_CONTROL);
 			} else {
 				// Macintosh simulate Insert
-				pressSequence(instance, 100, 157, 86, 86, 157);
+				pressSequence(robot, 100, 157, 86, 86, 157);
 			}
 		} catch (Exception e) {
 			log.error("Unexpected exception while pressSpecialSign", e);
@@ -640,17 +651,30 @@ public class CoreScreenShare implements
 	public void resultReceived(IPendingServiceCall call) {
 		try {
 
-			log.trace( "service call result: " + call );
+			log.trace("service call result: " + call);
 
 			String method = call == null ? null : call.getServiceMethodName();
+			Object o = call == null ? null : call.getResult();
 			log.trace("call ### get Method Name " + method);
 			if ("connect".equals(method)) {
+				if (o instanceof Map) {
+					@SuppressWarnings("unchecked")
+					Map<String, Object> map = (Map<String, Object>) o;
+					Object code = map.get("code");
+					if ("NetConnection.Connect.Rejected".equals(code) || "NetConnection.Connect.Failed".equals(code)) {
+						frame.setStatus(String.format("Error: %s %s", code, map.get("description")));
+						return;
+					}
+				}
+				if (!isConnected) {
+					instance.invoke("getPublicSID", null, this);
+				} else {
+					setConnectionAsSharingClient();
+				}
 				isConnected = true;
-				setConnectionAsSharingClient();
+			} else if ("getPublicSID".equals(method)) {
+				connect((String)o, true);
 			} else if ("setConnectionAsSharingClient".equals(method)) {
-
-				Object o = call.getResult();
-
 				@SuppressWarnings("unchecked")
 				Map<String, Object> returnMap = (Map<String, Object>) o;
 
@@ -692,13 +716,15 @@ public class CoreScreenShare implements
 	
 					log.debug("setup capture thread spinnerWidth = {}; spinnerHeight = {};", spinnerWidth, spinnerHeight);
 	
-					getCapture().setSendCursor(true);
-					getCapture().start();
+					if (!getCapture().isAlive()) {
+						getCapture().setSendCursor(startStreaming);
+						getCapture().start();
+					}
 				}
 			} else if ("screenSharerAction".equals(method)) {
-				Object o = call.getResult();
-
-				log.trace("Result Map Type " + o.getClass().getName());
+				if (log.isTraceEnabled()) {
+					log.trace("Result Map Type " + (o == null ? null : o.getClass().getName()));
+				}
 
 				@SuppressWarnings("unchecked")
 				Map<String, Object> returnMap = (Map<String, Object>)o;

Modified: openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/IScreenShare.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/IScreenShare.java?rev=1656837&r1=1656836&r2=1656837&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/IScreenShare.java (original)
+++ openmeetings/trunk/singlewebapp/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screen/webstart/IScreenShare.java Tue Feb  3 17:22:29 2015
@@ -18,6 +18,8 @@
  */
 package org.apache.openmeetings.screen.webstart;
 
+import java.util.Map;
+
 import org.red5.client.net.rtmp.ClientExceptionHandler;
 import org.red5.client.net.rtmp.INetStreamEventHandler;
 import org.red5.server.api.service.IPendingServiceCallback;
@@ -27,7 +29,8 @@ import org.red5.server.net.rtmp.RTMPConn
 public interface IScreenShare extends ClientExceptionHandler {
 	RTMPConnection getConnection();
 	void invoke(String method, Object[] params, IPendingServiceCallback callback);
-	void connect(String server, int port, String application, IPendingServiceCallback connectCallback);
+	Map<String, Object> makeDefaultConnectionParams(String server, int port, String application);
+	void connect(String server, int port, Map<String, Object> connectionParams, IPendingServiceCallback connectCallback);
 	void setServiceProvider(Object serviceProvider);
 	void disconnect();
 	void createStream(IPendingServiceCallback callback);