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 2014/02/22 10:52:40 UTC

svn commit: r1570813 - in /openmeetings: branches/3.0.x/src/db/java/org/apache/openmeetings/db/dao/record/ branches/3.0.x/src/db/java/org/apache/openmeetings/db/entity/record/ branches/3.0.x/src/main/java/org/apache/openmeetings/converter/ branches/3.0...

Author: solomax
Date: Sat Feb 22 09:52:39 2014
New Revision: 1570813

URL: http://svn.apache.org/r1570813
Log:
[OPENMEETINGS-902] screen sharing application seems to work as expected

Modified:
    openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java
    openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java
    openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.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/IScreenEncoder.java
    openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java
    openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java
    openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java
    openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java
    openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java
    openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java
    openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/data/flvrecord/listener/async/BaseStreamWriter.java
    openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java
    openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java
    openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java
    openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java
    openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java
    openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java
    openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java
    openmeetings/trunk/singlewebapp/src/screenshare/resources/logback.xml

Modified: openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java (original)
+++ openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java Sat Feb 22 09:52:39 2014
@@ -85,7 +85,7 @@ public class FlvRecordingMetaDataDao {
 	public List<FlvRecordingMetaData> getAudioMetaDataByRecording(Long flvRecordingId) {
 		try {
 			String hql = "SELECT c FROM FlvRecordingMetaData c WHERE c.flvRecording.flvRecordingId = :flvRecordingId "
-					+ "AND c.isScreenData = false AND c.streamStatus <> :none "
+					+ "AND c.screenData = false AND c.streamStatus <> :none "
 					+ "AND (c.isAudioOnly = true OR (c.isAudioOnly = false AND c.isVideoOnly = false))";
 
 			TypedQuery<FlvRecordingMetaData> query = em.createQuery(hql, FlvRecordingMetaData.class);
@@ -104,7 +104,7 @@ public class FlvRecordingMetaDataDao {
 	public FlvRecordingMetaData getScreenMetaDataByRecording(Long flvRecordingId) {
 		try {
 			String hql = "SELECT c FROM FlvRecordingMetaData c WHERE c.flvRecording.flvRecordingId = :flvRecordingId "
-					+ "AND c.isScreenData = true";
+					+ "AND c.screenData = true";
 
 			TypedQuery<FlvRecordingMetaData> query = em.createQuery(hql, FlvRecordingMetaData.class);
 			query.setParameter("flvRecordingId", flvRecordingId);
@@ -137,7 +137,7 @@ public class FlvRecordingMetaDataDao {
 
 			flvRecordingMetaData.setIsAudioOnly(isAudioOnly);
 			flvRecordingMetaData.setIsVideoOnly(isVideoOnly);
-			flvRecordingMetaData.setIsScreenData(isScreenData);
+			flvRecordingMetaData.setScreenData(isScreenData);
 
 			flvRecordingMetaData.setStreamName(streamName);
 

Modified: openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java (original)
+++ openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java Sat Feb 22 09:52:39 2014
@@ -95,7 +95,7 @@ public class FlvRecordingMetaData implem
 
 	@Column(name = "is_screen_data")
 	@Element(data = true)
-	private Boolean isScreenData;
+	private boolean screenData;
 
 	@Column(name = "inserted_by")
 	@Element(data = true, required = false)
@@ -228,12 +228,12 @@ public class FlvRecordingMetaData implem
 		this.updated = updated;
 	}
 
-	public Boolean getIsScreenData() {
-		return isScreenData;
+	public boolean isScreenData() {
+		return screenData;
 	}
 
-	public void setIsScreenData(Boolean isScreenData) {
-		this.isScreenData = isScreenData;
+	public void setScreenData(boolean screenData) {
+		this.screenData = screenData;
 	}
 
 	public String getStreamName() {

Modified: openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java (original)
+++ openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java Sat Feb 22 09:52:39 2014
@@ -76,11 +76,6 @@ public class FlvRecorderConverter extend
 		List<String> listOfFullWaveFiles = new LinkedList<String>();
 		File streamFolder = getStreamFolder(flvRecording);
 		try {
-			stripAudioFirstPass(flvRecording, returnLog, listOfFullWaveFiles, streamFolder);
-
-			// Merge Wave to Full Length
-			String streamFolderGeneralName = getStreamsHibernateDir().getCanonicalPath() + File.separator; // FIXME
-
 			FlvRecordingMetaData screenMetaData = metaDataDao.getScreenMetaDataByRecording(flvRecording.getFlvRecordingId());
 
 			if (screenMetaData == null) {
@@ -93,6 +88,11 @@ public class FlvRecorderConverter extend
 
 			screenMetaData = waitForTheStream(screenMetaData.getFlvRecordingMetaDataId());
 
+			stripAudioFirstPass(flvRecording, returnLog, listOfFullWaveFiles, streamFolder);
+
+			// Merge Wave to Full Length
+			String streamFolderGeneralName = getStreamsHibernateDir().getCanonicalPath() + File.separator; // FIXME
+
 			String hashFileFullName = screenMetaData.getStreamName() + "_FINAL_WAVE.wav";
 			String outputFullWav = new File(streamFolder, hashFileFullName).getCanonicalPath();
 

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=1570813&r1=1570812&r2=1570813&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 Sat Feb 22 09:52:39 2014
@@ -287,33 +287,24 @@ public class ScopeApplicationAdapter ext
 		try {
 			log.debug("-----------  setConnectionAsSharingClient");
 			IConnection current = Red5.getConnectionLocal();
-			// IServiceCapableConnection service = (IServiceCapableConnection)
-			// current;
 
-			Client currentClient = this.sessionManager
-					.getClientByStreamId(current.getClient().getId(), null);
+			Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null);
 
 			if (currentClient != 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()));
 
-				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()));
+				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()));
+				currentClient.setUser_id(Long.parseLong(map.get("user_id").toString()));
+				SessionVariablesUtil.setUserId(current.getClient(), Long.parseLong(map.get("user_id").toString()));
 
 				boolean alreadyStreaming = currentClient.isStartStreaming();
 				if (startStreaming) {
@@ -327,11 +318,9 @@ public class ScopeApplicationAdapter ext
 					currentClient.setStreamPublishStarted(true);
 				}
 
-				currentClient.setOrganization_id(Long.parseLong(map.get(
-						"organization_id").toString()));
+				currentClient.setOrganization_id(Long.parseLong(map.get("organization_id").toString()));
 
-				this.sessionManager.updateClientByStreamId(current
-						.getClient().getId(), currentClient, false, null);
+				sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null);
 
 				Map returnMap = new HashMap();
 				returnMap.put("alreadyPublished", false);
@@ -342,14 +331,10 @@ public class ScopeApplicationAdapter ext
 					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()));
+				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() + " "
@@ -358,20 +343,16 @@ public class ScopeApplicationAdapter ext
 
 				log.debug("publishName :: " + map.get("publishName"));
 
-				currentClient.setStreamPublishName(map.get("publishName")
-						.toString());
+				currentClient.setStreamPublishName(map.get("publishName").toString());
 
-				Client currentScreenUser = this.sessionManager
-						.getClientByPublicSID(currentClient
-								.getStreamPublishName(), false, null);
+				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
-				this.sessionManager.updateClientByStreamId(current
-						.getClient().getId(), currentClient, false, null);
+				sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null);
 
 				if (startStreaming) {
 					if (!alreadyStreaming) {
@@ -384,18 +365,19 @@ public class ScopeApplicationAdapter ext
 					} else {
 						log.warn("Streaming is already started for the client id=" + currentClient.getId() + ". Second request is ignored.");
 					}
-				} else if (startRecording) {
+				}
+				if (startRecording) {
 					if (!alreadyRecording) {
 						returnMap.put("modus", "startRecording");
 	
-						String recordingName = "Recording "
-								+ CalendarPatterns.getDateWithTimeByMiliSeconds(new Date());
+						String recordingName = "Recording " + CalendarPatterns.getDateWithTimeByMiliSeconds(new Date());
 	
 						flvRecorderService.recordMeetingStream(recordingName, "", false);
 					} else {
 						log.warn("Recording is already started for the client id=" + currentClient.getId() + ". Second request is ignored.");
 					}
-				} else if (startPublishing) {
+				}
+				if (startPublishing) {
 					syncMessageToCurrentScope("startedPublishing", new Object[]{currentClient, "rtmp://" + map.get("publishingHost") + ":1935/"
 							+ map.get("publishingApp") + "/" + map.get("publishingId")}, false, true);
 					returnMap.put("modus", "startPublishing");
@@ -404,8 +386,7 @@ public class ScopeApplicationAdapter ext
 				return returnMap;
 
 			} else {
-				throw new Exception("Could not find Screen Sharing Client "
-						+ current.getClient().getId());
+				throw new Exception("Could not find Screen Sharing Client " + current.getClient().getId());
 			}
 
 		} catch (Exception err) {

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=1570813&r1=1570812&r2=1570813&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 Sat Feb 22 09:52:39 2014
@@ -33,7 +33,6 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.mina.core.buffer.IoBuffer;
 import org.red5.server.net.rtmp.event.VideoData;
 import org.red5.server.stream.message.RTMPMessage;
 import org.slf4j.Logger;
@@ -64,7 +63,6 @@ final class CaptureScreen extends Thread
 		this.host = host;
 		this.app = app;
 		this.port = port;
-		se = new ScreenV1Encoder(); //NOTE get image should be changed in the code below
 	}
 
 	public void release() {
@@ -87,16 +85,13 @@ final class CaptureScreen extends Thread
 		}
 	}
 
-	public void resetBuffer() {
-		se.reset();
-	}
-
 	public void run() {
 		try {
 			while (active && !core.isReadyToRecord()) {
 				Thread.sleep(60);
 			}
 			timeBetweenFrames = 1000 / FPS;
+			se = new ScreenV1Encoder(3 * FPS); //send keyframe every 3 seconds
 			scheduler.scheduleWithFixedDelay(new Runnable() {
 				Robot robot = new Robot();
 				Rectangle screen = new Rectangle(spinnerX, spinnerY, spinnerWidth, spinnerHeight);
@@ -110,15 +105,12 @@ final class CaptureScreen extends Thread
 					}
 					start = System.currentTimeMillis();
 					try {
-						byte[] data = se.encode(screen, image);
+						VideoData data = se.encode(image);
 						if (log.isTraceEnabled()) {
 							log.trace(String.format("Image was encoded in %s ms", System.currentTimeMillis() - start));
 						}
-						IoBuffer buf = IoBuffer.allocate(data.length);
-						buf.clear();
-						buf.put(data);
-						buf.flip();
-						frames.offer(new VideoData(buf));
+						frames.offer(data);
+						se.createUnalteredFrame(screen);
 					} catch (IOException e) {
 						log.error("Error while encoding: ", e);
 					}
@@ -126,14 +118,15 @@ final class CaptureScreen extends Thread
 			}, 0, timeBetweenFrames * NANO_MULTIPLIER, TimeUnit.NANOSECONDS);
 			sendScheduler.scheduleWithFixedDelay(new Runnable() {
 				public void run() {
-					if (frames.size() > 1) {
-						frames.poll();
-					}
-					VideoData f = frames.peek();
+					VideoData f = frames.poll();
+					f = f == null ? se.getUnalteredFrame() : f;
 					if (f != null) {
 						try {
 							timestamp += timeBetweenFrames;
 							pushVideo(f, (int)timestamp);
+							if (log.isTraceEnabled()) {
+								log.trace("Sending video, timestamp: " + timestamp);
+							}
 						} catch (IOException e) {
 							log.error("Error while sending: ", 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=1570813&r1=1570812&r2=1570813&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 Sat Feb 22 09:52:39 2014
@@ -219,20 +219,24 @@ public class CoreScreenShare implements 
 		}
 	}
 
-	/**
-	 * @param startStreaming flag denoting the streaming is started
-	 * @param startRecording flag denoting the recording is started
-	 */
-	public void captureScreenStart(boolean startStreaming, boolean startRecording) {
-		captureScreenStart(startStreaming, startRecording, false);
+	public void streamingStart() {
+		startStreaming = true;
+		captureScreenStart();
 	}
-
-	public void captureScreenStart(boolean startStreaming, boolean startRecording, boolean startPublishing) {
+	
+	public void recordingStart() {
+		startRecording= true;
+		captureScreenStart();
+	}
+	
+	public void publishingStart() {
+		startPublishing = true;
+		captureScreenStart();
+	}
+	
+	private void captureScreenStart() {
 		try {
 			log.debug("captureScreenStart");
-			this.startStreaming = startStreaming;
-			this.startRecording= startRecording;
-			this.startPublishing = startPublishing;
 			
 			if (!isConnected) {
 				instance.connect(host, port, app, this);
@@ -245,13 +249,27 @@ public class CoreScreenShare implements 
 		}
 	}
 
-	public void sendCaptureScreenStop(boolean stopStreaming, boolean stopRecording) {
+	public void streamingStop() {
+		startStreaming = false;
+		captureScreenStop("stopStreaming");
+	}
+	
+	public void recordingStop() {
+		startRecording = false;
+		captureScreenStop("stopRecording");
+	}
+	
+	public void publishingStop() {
+		startPublishing = false;
+		captureScreenStop("stopPublishing");
+	}
+	
+	private void captureScreenStop(String action) {
 		try {
 			log.debug("INVOKE screenSharerAction" );
 
 			Map<String, Object> map = new HashMap<String, Object>();
-			map.put("stopStreaming", stopStreaming);
-			map.put("stopRecording", stopRecording);
+			map.put(action, true);
 
 			instance.invoke("screenSharerAction", new Object[] { map }, this);
 		} catch (Exception err) {
@@ -260,12 +278,6 @@ public class CoreScreenShare implements 
 		}
 	}
 
-	public void sendStopPublishing() {
-		Map<String, Object> map = new HashMap<String, Object>();
-		map.put("stopPublishing", true);
-		instance.invoke("screenSharerAction", new Object[] { map }, this);
-	}
-	
 	public void stopStreaming() {
 		startStreaming = false;
 		frame.setSharingStatus(false, !startPublishing && !startRecording && !startStreaming);
@@ -602,7 +614,6 @@ public class CoreScreenShare implements 
 
 					instance.createStream(this);
 				} else {
-					getCapture().resetBuffer();
 					log.trace("The Stream was already started ");
 				}
 				if (returnMap != null) {
@@ -631,14 +642,10 @@ public class CoreScreenShare implements 
 					if (call.getResult() != null) {
 						getCapture().setStreamId((Integer)call.getResult());
 					}
-					log.debug("createPublishStream result stream id: " + getCapture().getStreamId());
-					log.debug("publishing video by name: " + publishName);
+					log.debug("createPublishStream result stream id: {}; name: {}", getCapture().getStreamId(), publishName);
 					instance.publish(getCapture().getStreamId(), publishName, "live", this);
 	
-					log.debug("setup capture thread");
-	
-					log.debug("setup capture thread vScreenSpinnerWidth " + spinnerWidth);
-					log.debug("setup capture thread vScreenSpinnerHeight " + spinnerHeight);
+					log.debug("setup capture thread spinnerWidth = {}; spinnerHeight = {];", spinnerWidth, spinnerHeight);
 	
 					getCapture().setSendCursor(true);
 					getCapture().start();

Modified: openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java (original)
+++ openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java Sat Feb 22 09:52:39 2014
@@ -21,8 +21,14 @@ package org.apache.openmeetings.screen.w
 import java.awt.Rectangle;
 import java.io.IOException;
 
+import org.red5.server.net.rtmp.event.VideoData;
+
 public interface IScreenEncoder {
-	byte[] encode(Rectangle screen, int[][] img)  throws IOException;
+	void createUnalteredFrame(Rectangle area) throws IOException;
+	
+	VideoData getUnalteredFrame();
+
+	VideoData encode(int[][] img) throws IOException;
 	
 	void reset();
 }

Modified: openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java (original)
+++ openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java Sat Feb 22 09:52:39 2014
@@ -67,7 +67,7 @@ class RTMPClientPublish extends RTMPClie
 	private void connectionClosed() {
 		publishScreen.setStartPublish(false);
 		publishScreen.release();
-		core.sendStopPublishing();
+		core.publishingStop();
 	}
 	
 	@Override

Modified: openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java (original)
+++ openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java Sat Feb 22 09:52:39 2014
@@ -32,6 +32,9 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.util.zip.Deflater;
 
+import org.apache.mina.core.buffer.IoBuffer;
+import org.red5.server.net.rtmp.event.VideoData;
+
 public class ScreenV1Encoder extends BaseScreenEncoder {
 	private int[][] last = null;
 	private static int KEY_FRAME_INDEX = 25;
@@ -41,16 +44,20 @@ public class ScreenV1Encoder extends Bas
 	private int keyFrameIndex;
 	private int frameCount = 0;
 	private int blockSize;
-	private Rectangle screen;
 	private ByteArrayOutputStream ba = new ByteArrayOutputStream(50 + 3 * DEFAULT_SCREEN_WIDTH * DEFAULT_SCREEN_HEIGHT);
 	private byte[] areaBuf = null;
 	private Deflater d = new Deflater(Deflater.DEFAULT_COMPRESSION);
 	private byte[] zipBuf = null;
+	private VideoData unalteredFrame = null;
 	
 	public ScreenV1Encoder() {
 		this(KEY_FRAME_INDEX, DEFAULT_BLOCK_SIZE);
 	}
 	
+	public ScreenV1Encoder(int keyFrameIndex) {
+		this(keyFrameIndex, DEFAULT_BLOCK_SIZE);
+	}
+	
 	//will create square blocks
 	public ScreenV1Encoder(int keyFrameIndex, int blockSize) {
 		this.keyFrameIndex = keyFrameIndex;
@@ -62,12 +69,47 @@ public class ScreenV1Encoder extends Bas
 		areaBuf = new byte[3 * blockSize * blockSize];
 		zipBuf = new byte[3 * blockSize * blockSize];
 	}
+
+	private VideoData getData(byte[] data) {
+		IoBuffer buf = IoBuffer.allocate(data.length);
+		buf.clear();
+		buf.put(data);
+		buf.flip();
+		return new VideoData(buf);
+	}
+	
+	public void createUnalteredFrame(Rectangle _area) throws IOException {
+		if (last == null) {
+			return;
+		}
+		if (unalteredFrame == null) {
+			ByteArrayOutputStream ba = new ByteArrayOutputStream(200);
+			
+			//header
+			ba.write(getTag(FLAG_FRAMETYPE_INTERFRAME, FLAG_CODEC_SCREEN));
+			writeShort(ba, _area.width + ((blockSize / 16 - 1) << 12));
+			writeShort(ba, _area.height + ((blockSize / 16 - 1) << 12));
+			Rectangle area = getNextBlock(_area, null);
+			while (area.width > 0 && area.height > 0) {
+				writeShort(ba, 0);
+				area = getNextBlock(_area, area);
+			}
+			unalteredFrame = getData(ba.toByteArray());
+		}
+	}
+	
+	public VideoData getUnalteredFrame() {
+		if (unalteredFrame != null && (frameCount % keyFrameIndex) != 0) {
+			frameCount++;
+		}
+		return unalteredFrame;
+	}
 	
-	public synchronized byte[] encode(Rectangle screen, int[][] img) throws IOException {
+	public synchronized VideoData encode(int[][] img) throws IOException {
 		ba.reset();
 		Rectangle imgArea = new Rectangle(img.length, img[0].length);
 		Rectangle area = getNextBlock(imgArea, null);
-		boolean isKeyFrame = (frameCount++ % keyFrameIndex) == 0 || last == null || !screen.equals(this.screen);
+		boolean isKeyFrame = (frameCount++ % keyFrameIndex) == 0 || last == null;
 		
 		//header
 		ba.write(getTag(isKeyFrame ? FLAG_FRAMETYPE_KEYFRAME : FLAG_FRAMETYPE_INTERFRAME, FLAG_CODEC_SCREEN));
@@ -78,13 +120,13 @@ public class ScreenV1Encoder extends Bas
 			writeBytesIfChanged(ba, isKeyFrame, img, area);
 			area = getNextBlock(imgArea, area);
 		}
-		this.screen = screen;
 		last = img;
-		return ba.toByteArray();
+		return getData(ba.toByteArray());
 	}
 	
 	public void reset() {
 		last = null;
+		unalteredFrame = null;
 	}
 	
 	private Rectangle getNextBlock(Rectangle img, Rectangle _prev) {

Modified: openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java (original)
+++ openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java Sat Feb 22 09:52:39 2014
@@ -266,14 +266,14 @@ public class ScreenSharerFrame extends J
 				if (sharingStarted) {
 					if (!sharingActionRequested) {
 						sharingActionRequested = true;
-						core.sendCaptureScreenStop(true, false);
+						core.streamingStop();;
 					} else {
 						logger.warn("Sharing action is already requested");
 					}
 				} else {
 					if (!sharingActionRequested) {
 						sharingActionRequested = true;
-						core.captureScreenStart(true, false);
+						core.streamingStart();
 					} else {
 						logger.warn("Sharing action is already requested");
 					}
@@ -490,14 +490,14 @@ public class ScreenSharerFrame extends J
 				if (recordingStarted) {
 					if (!recordingActionRequested) {
 						recordingActionRequested = true;
-						core.sendCaptureScreenStop(false, true);
+						core.recordingStop();
 					} else {
 						logger.warn("Recording action is already requested");
 					}
 				} else {
 					if (!recordingActionRequested) {
 						recordingActionRequested = true;
-						core.captureScreenStart(false, true);
+						core.recordingStart();
 					} else {
 						logger.warn("Recording action is already requested");
 					}
@@ -557,14 +557,14 @@ public class ScreenSharerFrame extends J
 				if (publishStarted) {
 					if (!publishingActionRequested) {
 						publishingActionRequested = true;
-						core.sendStopPublishing();
+						core.publishingStop();
 					} else {
 						logger.warn("Publishing action is already requested");
 					}
 				} else {
 					if (!publishingActionRequested) {
 						publishingActionRequested = true;
-						core.captureScreenStart(false, false, true);
+						core.publishingStart();
 					} else {
 						logger.warn("Publishing action is already requested");
 					}

Modified: openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java (original)
+++ openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java Sat Feb 22 09:52:39 2014
@@ -85,7 +85,7 @@ public class FlvRecordingMetaDataDao {
 	public List<FlvRecordingMetaData> getAudioMetaDataByRecording(Long flvRecordingId) {
 		try {
 			String hql = "SELECT c FROM FlvRecordingMetaData c WHERE c.flvRecording.flvRecordingId = :flvRecordingId "
-					+ "AND c.isScreenData = false AND c.streamStatus <> :none "
+					+ "AND c.screenData = false AND c.streamStatus <> :none "
 					+ "AND (c.isAudioOnly = true OR (c.isAudioOnly = false AND c.isVideoOnly = false))";
 
 			TypedQuery<FlvRecordingMetaData> query = em.createQuery(hql, FlvRecordingMetaData.class);
@@ -104,7 +104,7 @@ public class FlvRecordingMetaDataDao {
 	public FlvRecordingMetaData getScreenMetaDataByRecording(Long flvRecordingId) {
 		try {
 			String hql = "SELECT c FROM FlvRecordingMetaData c WHERE c.flvRecording.flvRecordingId = :flvRecordingId "
-					+ "AND c.isScreenData = true";
+					+ "AND c.screenData = true";
 
 			TypedQuery<FlvRecordingMetaData> query = em.createQuery(hql, FlvRecordingMetaData.class);
 			query.setParameter("flvRecordingId", flvRecordingId);
@@ -137,7 +137,7 @@ public class FlvRecordingMetaDataDao {
 
 			flvRecordingMetaData.setIsAudioOnly(isAudioOnly);
 			flvRecordingMetaData.setIsVideoOnly(isVideoOnly);
-			flvRecordingMetaData.setIsScreenData(isScreenData);
+			flvRecordingMetaData.setScreenData(isScreenData);
 
 			flvRecordingMetaData.setStreamName(streamName);
 

Modified: openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java (original)
+++ openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java Sat Feb 22 09:52:39 2014
@@ -95,7 +95,7 @@ public class FlvRecordingMetaData implem
 
 	@Column(name = "is_screen_data")
 	@Element(data = true)
-	private Boolean isScreenData;
+	private boolean screenData;
 
 	@Column(name = "inserted_by")
 	@Element(data = true, required = false)
@@ -228,12 +228,12 @@ public class FlvRecordingMetaData implem
 		this.updated = updated;
 	}
 
-	public Boolean getIsScreenData() {
-		return isScreenData;
+	public boolean isScreenData() {
+		return screenData;
 	}
 
-	public void setIsScreenData(Boolean isScreenData) {
-		this.isScreenData = isScreenData;
+	public void setScreenData(boolean screenData) {
+		this.screenData = screenData;
 	}
 
 	public String getStreamName() {

Modified: openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java (original)
+++ openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java Sat Feb 22 09:52:39 2014
@@ -76,11 +76,6 @@ public class FlvRecorderConverter extend
 		List<String> listOfFullWaveFiles = new LinkedList<String>();
 		File streamFolder = getStreamFolder(flvRecording);
 		try {
-			stripAudioFirstPass(flvRecording, returnLog, listOfFullWaveFiles, streamFolder);
-
-			// Merge Wave to Full Length
-			String streamFolderGeneralName = getStreamsHibernateDir().getCanonicalPath() + File.separator; // FIXME
-
 			FlvRecordingMetaData screenMetaData = metaDataDao.getScreenMetaDataByRecording(flvRecording.getFlvRecordingId());
 
 			if (screenMetaData == null) {
@@ -93,6 +88,11 @@ public class FlvRecorderConverter extend
 
 			screenMetaData = waitForTheStream(screenMetaData.getFlvRecordingMetaDataId());
 
+			stripAudioFirstPass(flvRecording, returnLog, listOfFullWaveFiles, streamFolder);
+
+			// Merge Wave to Full Length
+			String streamFolderGeneralName = getStreamsHibernateDir().getCanonicalPath() + File.separator; // FIXME
+
 			String hashFileFullName = screenMetaData.getStreamName() + "_FINAL_WAVE.wav";
 			String outputFullWav = new File(streamFolder, hashFileFullName).getCanonicalPath();
 

Modified: openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/data/flvrecord/listener/async/BaseStreamWriter.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/data/flvrecord/listener/async/BaseStreamWriter.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/data/flvrecord/listener/async/BaseStreamWriter.java (original)
+++ openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/data/flvrecord/listener/async/BaseStreamWriter.java Sat Feb 22 09:52:39 2014
@@ -32,12 +32,12 @@ import org.apache.openmeetings.db.entity
 import org.apache.openmeetings.db.entity.record.FlvRecordingMetaData.Status;
 import org.apache.openmeetings.util.OmFileHelper;
 import org.red5.io.IStreamableFile;
+import org.red5.io.IStreamableFileFactory;
+import org.red5.io.IStreamableFileService;
 import org.red5.io.ITagWriter;
+import org.red5.io.StreamableFileFactory;
 import org.red5.logging.Red5LoggerFactory;
 import org.red5.server.api.scope.IScope;
-import org.red5.server.api.service.IStreamableFileService;
-import org.red5.server.api.stream.IStreamableFileFactory;
-import org.red5.server.stream.StreamableFileFactory;
 import org.red5.server.util.ScopeUtils;
 import org.slf4j.Logger;
 

Modified: openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java (original)
+++ openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java Sat Feb 22 09:52:39 2014
@@ -287,33 +287,24 @@ public class ScopeApplicationAdapter ext
 		try {
 			log.debug("-----------  setConnectionAsSharingClient");
 			IConnection current = Red5.getConnectionLocal();
-			// IServiceCapableConnection service = (IServiceCapableConnection)
-			// current;
 
-			Client currentClient = this.sessionManager
-					.getClientByStreamId(current.getClient().getId(), null);
+			Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null);
 
 			if (currentClient != 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()));
 
-				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()));
+				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()));
+				currentClient.setUser_id(Long.parseLong(map.get("user_id").toString()));
+				SessionVariablesUtil.setUserId(current.getClient(), Long.parseLong(map.get("user_id").toString()));
 
 				boolean alreadyStreaming = currentClient.isStartStreaming();
 				if (startStreaming) {
@@ -327,11 +318,9 @@ public class ScopeApplicationAdapter ext
 					currentClient.setStreamPublishStarted(true);
 				}
 
-				currentClient.setOrganization_id(Long.parseLong(map.get(
-						"organization_id").toString()));
+				currentClient.setOrganization_id(Long.parseLong(map.get("organization_id").toString()));
 
-				this.sessionManager.updateClientByStreamId(current
-						.getClient().getId(), currentClient, false, null);
+				sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null);
 
 				Map returnMap = new HashMap();
 				returnMap.put("alreadyPublished", false);
@@ -342,14 +331,10 @@ public class ScopeApplicationAdapter ext
 					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()));
+				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() + " "
@@ -358,20 +343,16 @@ public class ScopeApplicationAdapter ext
 
 				log.debug("publishName :: " + map.get("publishName"));
 
-				currentClient.setStreamPublishName(map.get("publishName")
-						.toString());
+				currentClient.setStreamPublishName(map.get("publishName").toString());
 
-				Client currentScreenUser = this.sessionManager
-						.getClientByPublicSID(currentClient
-								.getStreamPublishName(), false, null);
+				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
-				this.sessionManager.updateClientByStreamId(current
-						.getClient().getId(), currentClient, false, null);
+				sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null);
 
 				if (startStreaming) {
 					if (!alreadyStreaming) {
@@ -384,18 +365,19 @@ public class ScopeApplicationAdapter ext
 					} else {
 						log.warn("Streaming is already started for the client id=" + currentClient.getId() + ". Second request is ignored.");
 					}
-				} else if (startRecording) {
+				}
+				if (startRecording) {
 					if (!alreadyRecording) {
 						returnMap.put("modus", "startRecording");
 	
-						String recordingName = "Recording "
-								+ CalendarPatterns.getDateWithTimeByMiliSeconds(new Date());
+						String recordingName = "Recording " + CalendarPatterns.getDateWithTimeByMiliSeconds(new Date());
 	
 						flvRecorderService.recordMeetingStream(recordingName, "", false);
 					} else {
 						log.warn("Recording is already started for the client id=" + currentClient.getId() + ". Second request is ignored.");
 					}
-				} else if (startPublishing) {
+				}
+				if (startPublishing) {
 					syncMessageToCurrentScope("startedPublishing", new Object[]{currentClient, "rtmp://" + map.get("publishingHost") + ":1935/"
 							+ map.get("publishingApp") + "/" + map.get("publishingId")}, false, true);
 					returnMap.put("modus", "startPublishing");
@@ -404,8 +386,7 @@ public class ScopeApplicationAdapter ext
 				return returnMap;
 
 			} else {
-				throw new Exception("Could not find Screen Sharing Client "
-						+ current.getClient().getId());
+				throw new Exception("Could not find Screen Sharing Client " + current.getClient().getId());
 			}
 
 		} catch (Exception err) {

Modified: openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java (original)
+++ openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java Sat Feb 22 09:52:39 2014
@@ -28,11 +28,11 @@ import static org.slf4j.LoggerFactory.ge
 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.apache.mina.core.buffer.IoBuffer;
 import org.red5.server.net.rtmp.event.VideoData;
 import org.red5.server.stream.message.RTMPMessage;
 import org.slf4j.Logger;
@@ -46,13 +46,14 @@ final class CaptureScreen extends Thread
 	private volatile boolean active = true;
 	private IScreenEncoder se;
 	private IScreenShare client;
-	private IoBuffer buffer;
+	private ArrayBlockingQueue<VideoData> frames = new ArrayBlockingQueue<VideoData>(2);
 	private String host = null;
 	private String app = null;
 	private int port = -1;
 	private int streamId;
 	private boolean startPublish = false;
 	private boolean sendCursor = false;
+	private final ScheduledExecutorService sendScheduler = Executors.newScheduledThreadPool(1);
 	private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(20);
 	private final ScheduledExecutorService cursorScheduler = Executors.newScheduledThreadPool(1);
 
@@ -62,7 +63,6 @@ final class CaptureScreen extends Thread
 		this.host = host;
 		this.app = app;
 		this.port = port;
-		se = new ScreenV1Encoder(); //NOTE get image should be changed in the code below
 	}
 
 	public void release() {
@@ -74,22 +74,24 @@ final class CaptureScreen extends Thread
 			//no-op
 		}
 		try {
+			sendScheduler.shutdownNow();
+		} catch (Exception e) {
+			//no-op
+		}
+		try {
 			cursorScheduler.shutdownNow();
 		} catch (Exception e) {
 			//no-op
 		}
 	}
 
-	public void resetBuffer() {
-		se.reset();
-	}
-
 	public void run() {
 		try {
 			while (active && !core.isReadyToRecord()) {
 				Thread.sleep(60);
 			}
 			timeBetweenFrames = 1000 / FPS;
+			se = new ScreenV1Encoder(3 * FPS); //send keyframe every 3 seconds
 			scheduler.scheduleWithFixedDelay(new Runnable() {
 				Robot robot = new Robot();
 				Rectangle screen = new Rectangle(spinnerX, spinnerY, spinnerWidth, spinnerHeight);
@@ -103,14 +105,31 @@ final class CaptureScreen extends Thread
 					}
 					start = System.currentTimeMillis();
 					try {
-						byte[] data = se.encode(screen, image);
+						VideoData data = se.encode(image);
 						if (log.isTraceEnabled()) {
 							log.trace(String.format("Image was encoded in %s ms", System.currentTimeMillis() - start));
 						}
-						timestamp += timeBetweenFrames;
-						pushVideo(data, timestamp);
+						frames.offer(data);
+						se.createUnalteredFrame(screen);
 					} catch (IOException e) {
-						log.error("Error while encoding/sending: ", e);
+						log.error("Error while encoding: ", e);
+					}
+				}
+			}, 0, timeBetweenFrames * NANO_MULTIPLIER, TimeUnit.NANOSECONDS);
+			sendScheduler.scheduleWithFixedDelay(new Runnable() {
+				public void run() {
+					VideoData f = frames.poll();
+					f = f == null ? se.getUnalteredFrame() : f;
+					if (f != null) {
+						try {
+							timestamp += timeBetweenFrames;
+							pushVideo(f, (int)timestamp);
+							if (log.isTraceEnabled()) {
+								log.trace("Sending video, timestamp: " + timestamp);
+							}
+						} catch (IOException e) {
+							log.error("Error while sending: ", e);
+						}
 					}
 				}
 			}, 0, timeBetweenFrames * NANO_MULTIPLIER, TimeUnit.NANOSECONDS);
@@ -143,19 +162,9 @@ final class CaptureScreen extends Thread
 	}
 	*/
 	
-	private void pushVideo(byte[] video, int ts) throws IOException {
+	private void pushVideo(VideoData data, int ts) throws IOException {
 		if (startPublish) {
-			if (buffer == null || (buffer.capacity() < video.length && !buffer.isAutoExpand())) {
-				buffer = IoBuffer.allocate(video.length);
-				buffer.setAutoExpand(true);
-			}
-	
-			buffer.clear();
-			buffer.put(video);
-			buffer.flip();
-	
-			log.trace("Video frame sent :: " + ts);
-			RTMPMessage rtmpMsg = RTMPMessage.build(new VideoData(buffer), ts);
+			RTMPMessage rtmpMsg = RTMPMessage.build(data, ts);
 			client.publishStreamData(streamId, rtmpMsg);
 		}
 	}

Modified: openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java (original)
+++ openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java Sat Feb 22 09:52:39 2014
@@ -214,26 +214,29 @@ public class CoreScreenShare implements 
 
 			instance.invoke("setConnectionAsSharingClient", new Object[] { map }, this);
 		} catch (Exception err) {
-			log.error("setConnectionAsSharingClient Exception: ", err);
 			frame.setStatus("Error: " + err.getLocalizedMessage());
 			log.error("[setConnectionAsSharingClient]", err);
 		}
 	}
 
-	/**
-	 * @param startStreaming flag denoting the streaming is started
-	 * @param startRecording flag denoting the recording is started
-	 */
-	public void captureScreenStart(boolean startStreaming, boolean startRecording) {
-		captureScreenStart(startStreaming, startRecording, false);
+	public void streamingStart() {
+		startStreaming = true;
+		captureScreenStart();
 	}
-
-	public void captureScreenStart(boolean startStreaming, boolean startRecording, boolean startPublishing) {
+	
+	public void recordingStart() {
+		startRecording= true;
+		captureScreenStart();
+	}
+	
+	public void publishingStart() {
+		startPublishing = true;
+		captureScreenStart();
+	}
+	
+	private void captureScreenStart() {
 		try {
 			log.debug("captureScreenStart");
-			this.startStreaming = startStreaming;
-			this.startRecording= startRecording;
-			this.startPublishing = startPublishing;
 			
 			if (!isConnected) {
 				instance.connect(host, port, app, this);
@@ -246,13 +249,27 @@ public class CoreScreenShare implements 
 		}
 	}
 
-	public void sendCaptureScreenStop(boolean stopStreaming, boolean stopRecording) {
+	public void streamingStop() {
+		startStreaming = false;
+		captureScreenStop("stopStreaming");
+	}
+	
+	public void recordingStop() {
+		startRecording = false;
+		captureScreenStop("stopRecording");
+	}
+	
+	public void publishingStop() {
+		startPublishing = false;
+		captureScreenStop("stopPublishing");
+	}
+	
+	private void captureScreenStop(String action) {
 		try {
 			log.debug("INVOKE screenSharerAction" );
 
 			Map<String, Object> map = new HashMap<String, Object>();
-			map.put("stopStreaming", stopStreaming);
-			map.put("stopRecording", stopRecording);
+			map.put(action, true);
 
 			instance.invoke("screenSharerAction", new Object[] { map }, this);
 		} catch (Exception err) {
@@ -261,12 +278,6 @@ public class CoreScreenShare implements 
 		}
 	}
 
-	public void sendStopPublishing() {
-		Map<String, Object> map = new HashMap<String, Object>();
-		map.put("stopPublishing", true);
-		instance.invoke("screenSharerAction", new Object[] { map }, this);
-	}
-	
 	public void stopStreaming() {
 		startStreaming = false;
 		frame.setSharingStatus(false, !startPublishing && !startRecording && !startStreaming);
@@ -603,7 +614,6 @@ public class CoreScreenShare implements 
 
 					instance.createStream(this);
 				} else {
-					getCapture().resetBuffer();
 					log.trace("The Stream was already started ");
 				}
 				if (returnMap != null) {
@@ -632,14 +642,10 @@ public class CoreScreenShare implements 
 					if (call.getResult() != null) {
 						getCapture().setStreamId((Integer)call.getResult());
 					}
-					log.debug("createPublishStream result stream id: " + getCapture().getStreamId());
-					log.debug("publishing video by name: " + publishName);
+					log.debug("createPublishStream result stream id: {}; name: {}", getCapture().getStreamId(), publishName);
 					instance.publish(getCapture().getStreamId(), publishName, "live", this);
 	
-					log.debug("setup capture thread");
-	
-					log.debug("setup capture thread vScreenSpinnerWidth " + spinnerWidth);
-					log.debug("setup capture thread vScreenSpinnerHeight " + spinnerHeight);
+					log.debug("setup capture thread spinnerWidth = {}; spinnerHeight = {];", spinnerWidth, spinnerHeight);
 	
 					getCapture().setSendCursor(true);
 					getCapture().start();

Modified: openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java (original)
+++ openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java Sat Feb 22 09:52:39 2014
@@ -21,8 +21,14 @@ package org.apache.openmeetings.screen.w
 import java.awt.Rectangle;
 import java.io.IOException;
 
+import org.red5.server.net.rtmp.event.VideoData;
+
 public interface IScreenEncoder {
-	byte[] encode(Rectangle screen, int[][] img)  throws IOException;
+	void createUnalteredFrame(Rectangle area) throws IOException;
+	
+	VideoData getUnalteredFrame();
+
+	VideoData encode(int[][] img) throws IOException;
 	
 	void reset();
 }

Modified: openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java (original)
+++ openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java Sat Feb 22 09:52:39 2014
@@ -67,7 +67,7 @@ class RTMPClientPublish extends RTMPClie
 	private void connectionClosed() {
 		publishScreen.setStartPublish(false);
 		publishScreen.release();
-		core.sendStopPublishing();
+		core.publishingStop();
 	}
 	
 	@Override

Modified: openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java (original)
+++ openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java Sat Feb 22 09:52:39 2014
@@ -32,6 +32,9 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.util.zip.Deflater;
 
+import org.apache.mina.core.buffer.IoBuffer;
+import org.red5.server.net.rtmp.event.VideoData;
+
 public class ScreenV1Encoder extends BaseScreenEncoder {
 	private int[][] last = null;
 	private static int KEY_FRAME_INDEX = 25;
@@ -41,16 +44,20 @@ public class ScreenV1Encoder extends Bas
 	private int keyFrameIndex;
 	private int frameCount = 0;
 	private int blockSize;
-	private Rectangle screen;
 	private ByteArrayOutputStream ba = new ByteArrayOutputStream(50 + 3 * DEFAULT_SCREEN_WIDTH * DEFAULT_SCREEN_HEIGHT);
 	private byte[] areaBuf = null;
 	private Deflater d = new Deflater(Deflater.DEFAULT_COMPRESSION);
 	private byte[] zipBuf = null;
+	private VideoData unalteredFrame = null;
 	
 	public ScreenV1Encoder() {
 		this(KEY_FRAME_INDEX, DEFAULT_BLOCK_SIZE);
 	}
 	
+	public ScreenV1Encoder(int keyFrameIndex) {
+		this(keyFrameIndex, DEFAULT_BLOCK_SIZE);
+	}
+	
 	//will create square blocks
 	public ScreenV1Encoder(int keyFrameIndex, int blockSize) {
 		this.keyFrameIndex = keyFrameIndex;
@@ -62,12 +69,47 @@ public class ScreenV1Encoder extends Bas
 		areaBuf = new byte[3 * blockSize * blockSize];
 		zipBuf = new byte[3 * blockSize * blockSize];
 	}
+
+	private VideoData getData(byte[] data) {
+		IoBuffer buf = IoBuffer.allocate(data.length);
+		buf.clear();
+		buf.put(data);
+		buf.flip();
+		return new VideoData(buf);
+	}
+	
+	public void createUnalteredFrame(Rectangle _area) throws IOException {
+		if (last == null) {
+			return;
+		}
+		if (unalteredFrame == null) {
+			ByteArrayOutputStream ba = new ByteArrayOutputStream(200);
+			
+			//header
+			ba.write(getTag(FLAG_FRAMETYPE_INTERFRAME, FLAG_CODEC_SCREEN));
+			writeShort(ba, _area.width + ((blockSize / 16 - 1) << 12));
+			writeShort(ba, _area.height + ((blockSize / 16 - 1) << 12));
+			Rectangle area = getNextBlock(_area, null);
+			while (area.width > 0 && area.height > 0) {
+				writeShort(ba, 0);
+				area = getNextBlock(_area, area);
+			}
+			unalteredFrame = getData(ba.toByteArray());
+		}
+	}
+	
+	public VideoData getUnalteredFrame() {
+		if (unalteredFrame != null && (frameCount % keyFrameIndex) != 0) {
+			frameCount++;
+		}
+		return unalteredFrame;
+	}
 	
-	public synchronized byte[] encode(Rectangle screen, int[][] img) throws IOException {
+	public synchronized VideoData encode(int[][] img) throws IOException {
 		ba.reset();
 		Rectangle imgArea = new Rectangle(img.length, img[0].length);
 		Rectangle area = getNextBlock(imgArea, null);
-		boolean isKeyFrame = (frameCount++ % keyFrameIndex) == 0 || last == null || !screen.equals(this.screen);
+		boolean isKeyFrame = (frameCount++ % keyFrameIndex) == 0 || last == null;
 		
 		//header
 		ba.write(getTag(isKeyFrame ? FLAG_FRAMETYPE_KEYFRAME : FLAG_FRAMETYPE_INTERFRAME, FLAG_CODEC_SCREEN));
@@ -78,13 +120,13 @@ public class ScreenV1Encoder extends Bas
 			writeBytesIfChanged(ba, isKeyFrame, img, area);
 			area = getNextBlock(imgArea, area);
 		}
-		this.screen = screen;
 		last = img;
-		return ba.toByteArray();
+		return getData(ba.toByteArray());
 	}
 	
 	public void reset() {
 		last = null;
+		unalteredFrame = null;
 	}
 	
 	private Rectangle getNextBlock(Rectangle img, Rectangle _prev) {

Modified: openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java (original)
+++ openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java Sat Feb 22 09:52:39 2014
@@ -266,14 +266,14 @@ public class ScreenSharerFrame extends J
 				if (sharingStarted) {
 					if (!sharingActionRequested) {
 						sharingActionRequested = true;
-						core.sendCaptureScreenStop(true, false);
+						core.streamingStop();;
 					} else {
 						logger.warn("Sharing action is already requested");
 					}
 				} else {
 					if (!sharingActionRequested) {
 						sharingActionRequested = true;
-						core.captureScreenStart(true, false);
+						core.streamingStart();
 					} else {
 						logger.warn("Sharing action is already requested");
 					}
@@ -466,7 +466,7 @@ public class ScreenSharerFrame extends J
 		        calcRescaleFactors();
 			}
 		}); 
-		comboFPS.setSelectedIndex(1);
+		comboFPS.setSelectedIndex(2);
 		comboFPS.setBounds(390, 170, 70, 24);
 		panelScreen.add(comboFPS);
 		
@@ -490,14 +490,14 @@ public class ScreenSharerFrame extends J
 				if (recordingStarted) {
 					if (!recordingActionRequested) {
 						recordingActionRequested = true;
-						core.sendCaptureScreenStop(false, true);
+						core.recordingStop();
 					} else {
 						logger.warn("Recording action is already requested");
 					}
 				} else {
 					if (!recordingActionRequested) {
 						recordingActionRequested = true;
-						core.captureScreenStart(false, true);
+						core.recordingStart();
 					} else {
 						logger.warn("Recording action is already requested");
 					}
@@ -557,14 +557,14 @@ public class ScreenSharerFrame extends J
 				if (publishStarted) {
 					if (!publishingActionRequested) {
 						publishingActionRequested = true;
-						core.sendStopPublishing();
+						core.publishingStop();
 					} else {
 						logger.warn("Publishing action is already requested");
 					}
 				} else {
 					if (!publishingActionRequested) {
 						publishingActionRequested = true;
-						core.captureScreenStart(false, false, true);
+						core.publishingStart();
 					} else {
 						logger.warn("Publishing action is already requested");
 					}

Modified: openmeetings/trunk/singlewebapp/src/screenshare/resources/logback.xml
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/screenshare/resources/logback.xml?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/screenshare/resources/logback.xml (original)
+++ openmeetings/trunk/singlewebapp/src/screenshare/resources/logback.xml Sat Feb 22 09:52:39 2014
@@ -19,35 +19,33 @@
   
 -->
 
-<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
-    xsi:noNamespaceSchemaLocation="logback.xsd">
+<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:noNamespaceSchemaLocation="logback.xsd">
 	<contextName>${current_openmeetings_context_name}</contextName>
-	
+
 	<jmxConfigurator contextName="${current_openmeetings_context_name}" />
 
-  <appender name="FLOG2" class="ch.qos.logback.core.FileAppender">
+	<appender name="FLOG2" class="ch.qos.logback.core.FileAppender">
 		<File>screensharing.log</File>
 		<Append>false</Append>
 		<Encoding>UTF-8</Encoding>
 		<BufferedIO>false</BufferedIO>
 		<ImmediateFlush>true</ImmediateFlush>
 		<layout class="ch.qos.logback.classic.PatternLayout">
-			<Pattern>
-				%5p %d{MM-dd HH:mm:ss.SSS } %F %r %L %c [%t] - %m%n
-			</Pattern>
+			<pattern>%5p %d{MM-dd HH:mm:ss.SSS } %L %c{10} [%t] - %m%n</pattern>
+		</layout>
+	</appender>
+	<appender name="CONSOLE2" class="ch.qos.logback.core.ConsoleAppender">
+		<layout class="ch.qos.logback.classic.PatternLayout">
+			<pattern>%5p %d{MM-dd HH:mm:ss.SSS } %L %c{10} [%t] - %m%n</pattern>
 		</layout>
-  </appender>
-  <appender name="CONSOLE2" class="ch.qos.logback.core.ConsoleAppender">
-    <layout class="ch.qos.logback.classic.PatternLayout">
-      <pattern>%5p %d{MM-dd HH:mm:ss.SSS } %F %r %L %c [%t] - %m%n</pattern>
-    </layout>
-  </appender>
-  <logger name="org.apache.openmeetings">
-    <level value="TRACE"/>
-  </logger>
-  <root>
-    <level value="TRACE"/>
-    <appender-ref ref="FLOG2"/>
-    <appender-ref ref="CONSOLE2"/>
-  </root>
+	</appender>
+	<logger name="org.apache.openmeetings">
+		<level value="DEBUG" />
+	</logger>
+	<root>
+		<level value="DEBUG" />
+		<appender-ref ref="FLOG2" />
+		<appender-ref ref="CONSOLE2" />
+	</root>
 </configuration>