diff --git a/deskshare/app/build.gradle b/deskshare/app/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..c28e270dbb19e6be2161cb29db2ed614c95ea742
--- /dev/null
+++ b/deskshare/app/build.gradle
@@ -0,0 +1,31 @@
+usePlugin 'java'
+usePlugin 'war'
+
+version = '0.62'
+
+jar.enabled = true
+
+archivesBaseName = 'bbb-deskshare-app' 
+
+dependencies {	  
+    providedCompile ':log4j-over-slf4j:1.5.6@jar', 'spring:spring-web:2.5.6@jar', 'javax.servlet:servlet-api:2.5@jar', 'org.apache.mina:mina-core:2.0.0-M6@jar'
+    providedCompile 'spring:spring-aop:2.5.6@jar', 'spring:spring-beans:2.5.6@jar', 'spring:spring-context:2.5.6@jar', 'spring:spring-core:2.5.6@jar'
+	providedCompile 'org/red5:red5:0.8@jar'
+	compile project(':common')
+    compile 'commons-fileupload:commons-fileupload:1.2.1@jar', 'commons-io:commons-io:1.4@jar' 
+    compile ':logback-core:0.9.14@jar', ':logback-classic:0.9.14@jar', ':slf4j-api:1.5.6@jar'
+    compile 'spring:spring-webmvc:2.5.6@jar', 'org.apache.mina:mina-integration-spring:1.1.7@jar'
+}
+
+war.doLast {
+  ant.unzip(src: war.archivePath, dest: "$buildDir/exploded")
+}
+   
+task deploy(dependsOn:war, type:Copy) {
+	def red5AppsDir = '/usr/share/red5/webapps'
+	def deskshareDir = new File("${red5AppsDir}/deskshare")
+	println "Deleting $deskshareDir"
+	ant.delete(dir: deskshareDir)
+	into(deskshareDir)
+    from "$buildDir/exploded"
+} 
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureEndEvent.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureEndEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..19dad0488a62658d15ba1105ec4ea6d1e9ea232b
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureEndEvent.java
@@ -0,0 +1,40 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+public class CaptureEndEvent implements ICaptureEvent {
+
+	private String room;
+
+	public CaptureEndEvent(String room) {
+		this.room = room;
+	}
+	
+	public String getRoom() {
+		return room;
+	}
+
+	public CaptureMessage getMessageType() {
+		return CaptureMessage.CAPTURE_END;
+	}
+	
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureEvents.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureEvents.java
new file mode 100644
index 0000000000000000000000000000000000000000..bccb268aeb7438a14c6d26d21d4a9665835d34a8
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureEvents.java
@@ -0,0 +1,50 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+public enum CaptureEvents {
+	CAPTURE_START(0), CAPTURE_UPDATE(1), CAPTURE_END(2);
+	
+	private final int event;
+	
+	CaptureEvents(int event) {
+		this.event = event;
+	}
+	
+	public int getEvent() {
+		return event;
+	}
+	
+	@Override
+	public String toString() {
+		switch (event) {
+		case 0:
+			return "Capture Start Event";
+		case 1:
+			return "Capture Update Event";
+		case 2: 
+			return "Capture End Event";
+		}
+		
+		return "Unknown Capture Event";
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureMessage.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..98a7671eced4e0daf5f61289b6c417bc99edac6d
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureMessage.java
@@ -0,0 +1,28 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+public enum CaptureMessage {
+	CAPTURE_START,
+	CAPTURE_UPDATE,
+	CAPTURE_END
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureStartEvent.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureStartEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..28e3089b59309c3edd67e9fa9db662914a6b60fb
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureStartEvent.java
@@ -0,0 +1,52 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+public final class CaptureStartEvent implements ICaptureEvent {
+
+	private final int width;
+	private final int height;
+	private final String room;
+	
+	public CaptureStartEvent(String room, int width, int height) {
+		this.room = room;
+		this.width = width;
+		this.height = height;
+	}
+
+	public int getWidth() {
+		return width;
+	}
+
+	public int getHeight() {
+		return height;
+	}
+
+	public String getRoom() {
+		return room;
+	}
+
+	public CaptureMessage getMessageType() {
+		return CaptureMessage.CAPTURE_START;
+	}
+
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureUpdateEvent.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureUpdateEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..6628e59e5ff16aeb358acb2bca5ba226b3f4a606
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CaptureUpdateEvent.java
@@ -0,0 +1,58 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+ 
+import org.apache.mina.core.buffer.IoBuffer;
+
+public class CaptureUpdateEvent implements ICaptureEvent {
+
+	private final IoBuffer data;
+	private final String room;
+	private final long timestamp;
+	
+	public CaptureUpdateEvent(String room, IoBuffer data) {
+
+		this.data = data;
+		this.room = room;
+		timestamp = System.currentTimeMillis();
+	}
+
+	public IoBuffer getData() {
+		return data;
+	}
+
+	public String getRoom() {
+		return room;
+	}
+
+	public CaptureMessage getMessageType() {
+		return CaptureMessage.CAPTURE_UPDATE;
+	}
+	
+	public static CaptureUpdateEvent copy(CaptureUpdateEvent event) {
+		return new CaptureUpdateEvent(event.getRoom(), event.getData());
+	}
+	
+	public long getTimestamp() {
+		return timestamp;
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CapturedScreen.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CapturedScreen.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae25f5b8f0172c85b93a95e1391d753f81c42d19
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/CapturedScreen.java
@@ -0,0 +1,67 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+import java.awt.image.BufferedImage;
+
+public class CapturedScreen {
+
+	private BufferedImage screen;
+	private String room;
+	
+	private int width;
+	private int height;
+	private int frameRate;
+	
+	public CapturedScreen(BufferedImage screen, String room, int width,
+			int height, int frameRate) {
+		super();
+		this.screen = screen;
+		this.room = room;
+		this.width = width;
+		this.height = height;
+		this.frameRate = frameRate;
+	}
+
+
+	public BufferedImage getScreen() {
+		return screen;
+	}
+
+	public String getRoom() {
+		return room;
+	}
+
+	public int getWidth() {
+		return width;
+	}
+
+	public int getHeight() {
+		return height;
+	}
+
+	public int getFrameRate() {
+		return frameRate;
+	}
+
+
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/DeskShareApplication.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/DeskShareApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..606b47cae50134521556f5df2e330f6bfae62f48
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/DeskShareApplication.java
@@ -0,0 +1,115 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+import java.util.List;
+
+import org.bigbluebutton.deskshare.server.socket.DeskShareServer;
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.adapter.MultiThreadedApplicationAdapter;
+import org.red5.server.api.IBandwidthConfigure;
+import org.red5.server.api.IConnection;
+import org.red5.server.api.IScope;
+import org.red5.server.api.Red5;
+import org.red5.server.api.stream.IServerStream;
+import org.red5.server.api.stream.IStreamCapableConnection;
+import org.red5.server.api.stream.support.SimpleConnectionBWConfig;
+
+import org.slf4j.Logger;
+
+/**
+ * The Application class is the main class of the deskShare server side
+ * @author Snap
+ *
+ */
+public class DeskShareApplication extends MultiThreadedApplicationAdapter {
+	private static Logger log = Red5LoggerFactory.getLogger(DeskShareApplication.class, "deskshare");
+	
+	private IScope appScope;
+	private IServerStream serverStream;
+	
+	private DeskShareServer deskShareServer;
+		
+	/**
+	 * Runs when the application is first started. Sets up relevant objects to listen to the deskShare client
+	 * and publish the stream on red5
+	 */
+	public boolean appStart(IScope app){
+		log.info("deskShare appStart");
+		System.out.println("deskShare appStart");
+		this.appScope = app;
+		
+		deskShareServer.start();
+		
+		return true;
+	}
+	
+	public boolean appConnect(IConnection conn, Object[] params){
+		log.info("deskShare appConnect to scope " + conn.getScope().getContext().toString());
+		System.out.println("deskShare appConnect to scope " + conn.getScope().getContextPath());
+		measureBandwidth(conn);
+		
+		if (conn instanceof IStreamCapableConnection){
+			IStreamCapableConnection streamConn = (IStreamCapableConnection) conn;
+			SimpleConnectionBWConfig bwConfig = new SimpleConnectionBWConfig();
+			bwConfig.getChannelBandwidth()[IBandwidthConfigure.OVERALL_CHANNEL] =
+				1024*1024;
+			bwConfig.getChannelInitialBurst()[IBandwidthConfigure.OVERALL_CHANNEL] =
+				128*1024;
+			streamConn.setBandwidthConfigure(bwConfig);
+		}
+		
+		return super.appConnect(conn, params);
+	}
+	
+	public void appDisconnect(IConnection conn){
+		log.info("deskShare appDisconnect");
+		if (getAppScope() == conn.getScope() && serverStream != null){
+			serverStream.close();
+		}
+		super.appDisconnect(conn);
+	}
+	
+	public List<String> getStreams(){
+		IConnection conn = Red5.getConnectionLocal();
+		return getBroadcastStreamNames(conn.getScope());
+	}
+	
+	/**
+	 * @return the appScope
+	 */
+	public IScope getAppScope() {
+		return appScope;
+	}
+	
+	/**
+	 * Called when the application is stopped
+	 */
+	public void appStop(){
+		deskShareServer.stop();
+	}
+
+	public void setDeskShareServer(DeskShareServer deskShareServer) {
+		this.deskShareServer = deskShareServer;
+	}
+	
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/DeskShareConstants.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/DeskShareConstants.java
new file mode 100644
index 0000000000000000000000000000000000000000..f9ac14f814f8b7591ddac742bb14d29bb0ba15d1
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/DeskShareConstants.java
@@ -0,0 +1,36 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+/**
+ * The constants for this application
+ * @author Snap
+ *
+ */
+public class DeskShareConstants {
+	public static final int PORT = 1026;
+	
+	public static final int BIT_RATE = 25000;
+	public static final int BIT_RATE_TOLERANCE = 50000;
+	public static final int NUM_PICTURES_IN_GROUP = 1;
+	
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/DeskShareService.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/DeskShareService.java
new file mode 100644
index 0000000000000000000000000000000000000000..2e4b49a9fad8afc3efbb446c478acad381ea0733
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/DeskShareService.java
@@ -0,0 +1,59 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.Red5;
+import org.slf4j.Logger;
+
+public class DeskShareService {
+	final private Logger log = Red5LoggerFactory.getLogger(DeskShareService.class, "deskshare");
+	
+	private FrameStreamerGateway sg;
+	
+	public boolean checkIfStreamIsPublishing(){
+		String roomName = Red5.getConnectionLocal().getScope().getName();
+		log.debug("Checking if {} is streaming.", roomName);
+		System.out.println("Checking if " + roomName + " is streaming.");
+		boolean streaming = sg.isStreaming(roomName);
+		if (streaming) {
+			System.out.println(roomName + " is streaming.");
+		}
+		return streaming;
+	}
+	
+	public int getVideoWidth(){
+		String roomName = Red5.getConnectionLocal().getScope().getName();
+		log.debug("Getting video width for {}.", roomName);
+		return sg.getRoomVideoWidth(roomName);
+	}
+	
+	public int getVideoHeight(){
+		String roomName = Red5.getConnectionLocal().getScope().getName();
+		log.debug("Getting video height for {}.", roomName);
+		return sg.getRoomVideoHeight(roomName);
+	}
+	
+	public void setStreamerGateway(FrameStreamerGateway sg) {
+		this.sg = sg;
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/FrameStreamFactory.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/FrameStreamFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..48caaef4ab245673c3228e5067f0145fc8825abf
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/FrameStreamFactory.java
@@ -0,0 +1,65 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+import org.bigbluebutton.deskshare.server.streamer.DeskShareStream;
+import org.bigbluebutton.deskshare.server.streamer.FlvStreamToFile;
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.IScope;
+import org.slf4j.Logger;
+
+public class FrameStreamFactory {
+	final private Logger log = Red5LoggerFactory.getLogger(FrameStreamFactory.class, "deskshare");
+	
+	private DeskShareApplication app;
+	
+	public IDeskShareStream createStream(String room, int screenWidth, int screenHeight) {
+//		int frameRate = event.getFrameRate();
+		
+//		IScope scope = app.getAppScope();
+		
+		IScope scope = app.getAppScope().getScope(room);
+/*
+		if (scope == null) {
+			if (app.getAppScope().createChildScope("testroom")) {
+				log.debug("create child scope testroom");
+				scope = app.getAppScope().getScope("testroom");
+			} else {
+				log.warn("Failed to create child scope testroom");
+			}			
+		}
+*/
+//		log.debug("Created stream {}", scope.getName());
+		return new DeskShareStream(scope, room, screenWidth, screenHeight);
+		//return new FlvStreamToFile();
+	}
+	
+	public void setDeskShareApplication(DeskShareApplication app) {
+		this.app = app;
+		if (app == null) {
+			log.error("DeskShareApplication is NULL!!!");
+		} else {
+			log.debug("DeskShareApplication is NOT NULL!!!");
+		}
+		
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/FrameStreamerGateway.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/FrameStreamerGateway.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce65d52e71c97b9e1f057378a42bdc973ca871c8
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/FrameStreamerGateway.java
@@ -0,0 +1,105 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.bigbluebutton.deskshare.server.session.ScreenVideoFrame;
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.so.ISharedObject;
+import org.slf4j.Logger;
+
+public class FrameStreamerGateway { 
+	final private Logger log = Red5LoggerFactory.getLogger(FrameStreamerGateway.class, "deskshare");
+	
+	private final Map<String, IDeskShareStream> streamsMap;
+	private FrameStreamFactory streamFactory;
+	private DeskShareApplication deskShareApp;
+	
+	public FrameStreamerGateway() {
+		streamsMap = new ConcurrentHashMap<String, IDeskShareStream>();
+	}
+	
+	public void createNewStream(String room, int screenWidth, int screenHeight) {
+		log.debug("Creating stream " + room);
+		System.out.println("FrameStreamerGateway Creating stream " + room);
+		IDeskShareStream stream = streamFactory.createStream(room, screenWidth, screenHeight);
+
+		streamsMap.put(room, stream);
+		stream.start();
+			
+		//notify the clients in the room that the stream has now started broadcasting.
+		ISharedObject deskSO = deskShareApp.getSharedObject(stream.getScope(), "deskSO");
+		deskSO.sendMessage("appletStarted" , new ArrayList<Object>());
+
+	}
+	
+	public void onCaptureEndEvent(String room) {
+		IDeskShareStream ds = streamsMap.remove(room);
+		if (ds != null) {
+			ds.stop();
+			ds = null;
+		}
+	}
+	
+	public void onCaptureEvent(ScreenVideoFrame event) {
+//		System.out.println("FrameStreamerGateway onCaptureEvent");
+		IDeskShareStream ds = streamsMap.get(event.getRoom());
+		if (ds != null) {
+			CaptureUpdateEvent cue = new CaptureUpdateEvent(event.getRoom(), event.getVideoData());
+//			System.out.println("FrameStreamerGateway passing to IDeskShareStream");
+			ds.accept(cue);
+		} else {
+			System.out.println("FrameStreamerGateway: could not find DeskShareStream " + event.getRoom());
+		}
+	}
+
+	public boolean isStreaming(String room){
+		return streamsMap.containsKey(room);
+	}
+	
+	public int getRoomVideoWidth(String room){
+		IDeskShareStream ds = streamsMap.get(room);
+		if (ds != null) {
+			return ds.getWidth();
+		}
+		return 0;
+	}
+	
+	public int getRoomVideoHeight(String room){
+		IDeskShareStream ds = streamsMap.get(room);
+		if (ds != null) {
+			return ds.getHeight();
+		}
+		return 0;
+	}	
+	
+	public void setStreamFactory(FrameStreamFactory sf) {
+		this.streamFactory = sf;
+	}
+	
+	public void setDeskShareApplication(DeskShareApplication app) {
+		this.deskShareApp = app;
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/ICaptureEvent.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/ICaptureEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..bab56622e7417160ab151e71345c5b79eff641be
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/ICaptureEvent.java
@@ -0,0 +1,27 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+public interface ICaptureEvent {
+
+	public CaptureMessage getMessageType();
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/IDeskShareStream.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/IDeskShareStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..0eedb40f342fc33376db7eb908a238a519573647
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/IDeskShareStream.java
@@ -0,0 +1,50 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+import org.bigbluebutton.deskshare.server.session.ScreenVideoFrame;
+import org.red5.server.api.IScope;
+
+
+
+/**
+ * The DeskShareStream class publishes captured video to a red5 stream.
+ * @author Snap
+ *
+ */
+public interface IDeskShareStream  {
+
+	public void stop();
+	
+	public void start();
+		
+	public void accept(CaptureUpdateEvent event);
+	
+	public void stream(ScreenVideoFrame frame);
+		
+	public int getWidth();
+	
+	public int getHeight();
+	
+	public IScope getScope();
+
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/NewScreenListener.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/NewScreenListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a0d986eabfd1241ee8af13e0b2f38d0bbe3a6d4
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/NewScreenListener.java
@@ -0,0 +1,29 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+import java.awt.image.BufferedImage;
+
+public interface NewScreenListener {
+
+	public void onNewScreen(BufferedImage newScreen);
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/ScreenVideo.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/ScreenVideo.java
new file mode 100644
index 0000000000000000000000000000000000000000..5bb9f8e247d1c586b37394cb5ba5dc4328fa9457
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/ScreenVideo.java
@@ -0,0 +1,79 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.stream.IVideoStreamCodec;
+import org.slf4j.Logger;
+
+public class ScreenVideo implements IVideoStreamCodec {
+
+	private Logger log = Red5LoggerFactory.getLogger(ScreenVideo.class, "deskshare");
+	static final String CODEC_NAME = "ScreenVideo";
+	static final byte FLV_FRAME_KEY = 0x10;
+	static final byte FLV_CODEC_SCREEN = 0x03;
+	private IoBuffer data;
+	
+    public ScreenVideo() {
+		this.reset();
+	}
+
+    public String getName() {
+		return CODEC_NAME;
+	}
+
+    public void reset() {
+    	
+	}
+
+    public boolean canHandleData(IoBuffer data) {
+		byte first = data.get();
+		boolean result = ((first & 0x0f) == FLV_CODEC_SCREEN);
+		data.rewind();
+		return result;
+	}
+
+    public boolean canDropFrames() {
+		return true;
+	}
+
+    public boolean addData(IoBuffer data) {
+		if (!this.canHandleData(data)) {
+			log.warn("Cannot handle data");
+			return false;
+		}
+		this.data = data;
+		
+		log.debug("Adding data " + data.remaining());
+		
+		this.data.rewind();
+		return true;
+	}
+
+    public IoBuffer getKeyframe() {
+    	log.debug("getting keyFrame");
+		return data;
+	}
+
+}
+
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/ScreenVideoBroadcastStream.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/ScreenVideoBroadcastStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..a2bd51a741f01c8bc57ccc3af36c6da7456633d9
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/ScreenVideoBroadcastStream.java
@@ -0,0 +1,273 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.IScope;
+import org.red5.server.api.event.IEvent;
+import org.red5.server.api.stream.IBroadcastStream;
+import org.red5.server.api.stream.IStreamCodecInfo;
+import org.red5.server.api.stream.IStreamListener;
+import org.red5.server.api.stream.IVideoStreamCodec;
+import org.red5.server.api.stream.ResourceExistException;
+import org.red5.server.api.stream.ResourceNotFoundException;
+import org.red5.server.messaging.IMessageComponent;
+import org.red5.server.messaging.IPipe;
+import org.red5.server.messaging.IPipeConnectionListener;
+import org.red5.server.messaging.IProvider;
+import org.red5.server.messaging.OOBControlMessage;
+import org.red5.server.messaging.PipeConnectionEvent;
+import org.red5.server.net.rtmp.event.IRTMPEvent;
+import org.red5.server.net.rtmp.event.VideoData;
+import org.bigbluebutton.deskshare.server.ScreenVideo;
+import org.red5.server.stream.codec.StreamCodecInfo;
+import org.red5.server.stream.message.RTMPMessage;
+
+import org.slf4j.Logger;
+
+import org.red5.server.api.stream.IStreamPacket;;
+
+public class ScreenVideoBroadcastStream implements IBroadcastStream, IProvider, IPipeConnectionListener
+{
+  /** Listeners to get notified about received packets. */
+  private Set<IStreamListener> streamListeners = new CopyOnWriteArraySet<IStreamListener>();
+  final private Logger log = Red5LoggerFactory.getLogger(ScreenVideoBroadcastStream.class, "deskshare");
+
+  private String publishedStreamName;
+  private IPipe livePipe;
+  private IScope mScope;
+
+  // Codec handling stuff for frame dropping
+  private StreamCodecInfo streamCodecInfo;
+  private Long mCreationTime;
+  
+  public ScreenVideoBroadcastStream(String name)
+  {
+    publishedStreamName = name;
+    livePipe = null;
+    log.trace("name: {}", name);
+
+    // we want to create a video codec when we get our
+    // first video packet.
+    streamCodecInfo = new StreamCodecInfo();
+    mCreationTime = null;
+  }
+
+  public IProvider getProvider()
+  {
+    log.trace("getProvider()");
+    return this;
+  }
+
+  public String getPublishedName()
+  {
+    log.trace("getPublishedName()");
+    return publishedStreamName;
+  }
+
+  public String getSaveFilename()
+  {
+    log.trace("getSaveFilename()");
+    throw new Error("unimplemented method");
+  }
+
+  public void addStreamListener(IStreamListener listener)
+  {
+    log.trace("addStreamListener(listener: {})", listener);
+    streamListeners.add(listener);
+  }
+
+  public Collection<IStreamListener> getStreamListeners()
+  {
+    log.trace("getStreamListeners()");
+    return streamListeners;
+  }
+
+  public void removeStreamListener(IStreamListener listener)
+  {
+    log.trace("removeStreamListener({})", listener);
+    streamListeners.remove(listener);
+  }
+
+  public void saveAs(String filePath, boolean isAppend) throws IOException,
+  ResourceNotFoundException, ResourceExistException
+  {
+    log.trace("saveAs(filepath:{}, isAppend:{})", filePath, isAppend);
+    throw new Error("unimplemented method");
+  }
+
+  public void setPublishedName(String name)
+  {
+    log.trace("setPublishedName(name:{})", name);
+    publishedStreamName = name;
+  }
+
+  public void close()
+  {
+    log.trace("close()");
+  }
+
+  public IStreamCodecInfo getCodecInfo()
+  {
+    log.trace("getCodecInfo()");
+    // we don't support this right now.
+    return streamCodecInfo;
+  }
+
+  public String getName()
+  {
+    log.trace("getName(): {}", publishedStreamName);
+    // for now, just return the published name
+    return publishedStreamName;
+  }
+
+  public void setScope(IScope scope)
+  {
+    mScope = scope;
+  }
+
+  public IScope getScope()
+  {
+    log.trace("getScope(): {}", mScope);
+    return mScope;
+  }
+
+  public void start()
+  {
+    log.trace("start()");
+  }
+
+  public void stop()
+  {
+    log.trace("stop");
+  }
+
+  public void onOOBControlMessage(IMessageComponent source, IPipe pipe,
+      OOBControlMessage oobCtrlMsg)
+  {
+    log.trace("onOOBControlMessage");
+  }
+
+  public void onPipeConnectionEvent(PipeConnectionEvent event)
+  {
+    log.trace("onPipeConnectionEvent(event:{})", event);
+    switch (event.getType())
+    {
+	    case PipeConnectionEvent.PROVIDER_CONNECT_PUSH:
+	    	log.trace("PipeConnectionEvent.PROVIDER_CONNECT_PUSH");
+		      if (event.getProvider() == this
+		          && (event.getParamMap() == null || !event.getParamMap()
+		              .containsKey("record")))
+		      {
+		    	  log.trace("Creating a live pipe");
+		    	  System.out.println("Creating a live pipe");
+		        this.livePipe = (IPipe) event.getSource();
+		      }
+	      break;
+	    case PipeConnectionEvent.PROVIDER_DISCONNECT:
+	    	log.trace("PipeConnectionEvent.PROVIDER_DISCONNECT");
+	      if (this.livePipe == event.getSource())
+	      {
+	    	  log.trace("PipeConnectionEvent.PROVIDER_DISCONNECT - this.mLivePipe = null;");
+	    	  System.out.println("PipeConnectionEvent.PROVIDER_DISCONNECT - this.mLivePipe = null;");
+	        this.livePipe = null;
+	      }
+	      break;
+	    case PipeConnectionEvent.CONSUMER_CONNECT_PUSH:
+	    	log.trace("PipeConnectionEvent.CONSUMER_CONNECT_PUSH");
+	    	System.out.println("PipeConnectionEvent.CONSUMER_CONNECT_PUSH");
+	      break;
+	    case PipeConnectionEvent.CONSUMER_DISCONNECT:
+	    	log.trace("PipeConnectionEvent.CONSUMER_DISCONNECT");
+	    	System.out.println("PipeConnectionEvent.CONSUMER_DISCONNECT");
+	      break;
+	    default:
+	    	log.trace("PipeConnectionEvent default");
+	    	System.out.println("PipeConnectionEvent default");
+	      break;
+    }
+  }
+
+  public void dispatchEvent(IEvent event)
+  {
+    try {
+      log.trace("dispatchEvent(event:{})", event);
+      if (event instanceof IRTMPEvent)
+      {
+        IRTMPEvent rtmpEvent = (IRTMPEvent) event;
+        if (livePipe != null)
+        {
+          RTMPMessage msg = new RTMPMessage();
+
+          msg.setBody(rtmpEvent);
+          
+          if (mCreationTime == null)
+            mCreationTime = (long)rtmpEvent.getTimestamp();
+          
+          try
+          {
+        	  IVideoStreamCodec videoStreamCodec = new ScreenVideo();
+        	  streamCodecInfo.setHasVideo(true);
+        	  streamCodecInfo.setVideoCodec(videoStreamCodec);
+        	  videoStreamCodec.reset();
+        	  videoStreamCodec.addData(((VideoData) rtmpEvent).getData());
+        	  livePipe.pushMessage(msg);
+
+              // Notify listeners about received packet
+              if (rtmpEvent instanceof IStreamPacket)
+              {
+                for (IStreamListener listener : getStreamListeners())
+                {
+                  try
+                  {
+                    listener.packetReceived(this, (IStreamPacket) rtmpEvent);
+                  }
+                  catch (Exception e)
+                  {
+                    log.error("Error while notifying listener " + listener, e);
+                  }
+                }
+              } 	  
+        	  
+          }
+          catch (IOException ex)
+          {
+            // ignore
+            log.error("Got exception: {}", ex);
+          }
+        }
+      }
+    } finally {
+      
+    }
+  }
+
+  public long getCreationTime()
+  {
+    return mCreationTime != null ? mCreationTime : 0L;
+  }
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/StreamFactory.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/StreamFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..584ecdd14e27e57492b424d9cff6bff7dcbc009b
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/StreamFactory.java
@@ -0,0 +1,68 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+import org.bigbluebutton.deskshare.server.streamer.DeskShareStream;
+import org.bigbluebutton.deskshare.server.streamer.FlvStreamToFile;
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.IScope;
+import org.slf4j.Logger;
+
+public class StreamFactory {
+	final private Logger log = Red5LoggerFactory.getLogger(StreamFactory.class, "deskshare");
+	
+	private DeskShareApplication app;
+	
+	public IDeskShareStream createStream(CaptureStartEvent event) {
+		String room = event.getRoom();
+		int width = event.getWidth();
+		int height = event.getHeight();
+//		int frameRate = event.getFrameRate();
+		
+//		IScope scope = app.getAppScope();
+		
+		IScope scope = app.getAppScope().getScope(room);
+/*
+		if (scope == null) {
+			if (app.getAppScope().createChildScope("testroom")) {
+				log.debug("create child scope testroom");
+				scope = app.getAppScope().getScope("testroom");
+			} else {
+				log.warn("Failed to create child scope testroom");
+			}			
+		}
+*/
+//		log.debug("Created stream {}", scope.getName());
+		return new DeskShareStream(scope, room, width, height);
+		//return new FlvStreamToFile();
+	}
+	
+	public void setDeskShareApplication(DeskShareApplication app) {
+		this.app = app;
+		if (app == null) {
+			log.error("DeskShareApplication is NULL!!!");
+		} else {
+			log.debug("DeskShareApplication is NOT NULL!!!");
+		}
+		
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/StreamerGateway.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/StreamerGateway.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b26beefc2c3a1fe318222831732c159467cab6c
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/StreamerGateway.java
@@ -0,0 +1,103 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.so.ISharedObject;
+import org.slf4j.Logger;
+
+public class StreamerGateway { 
+	final private Logger log = Red5LoggerFactory.getLogger(StreamerGateway.class, "deskshare");
+	
+	private final Map<String, IDeskShareStream> streamsMap;
+	private StreamFactory streamFactory;
+	private DeskShareApplication deskShareApp;
+	
+	public StreamerGateway() {
+		streamsMap = new ConcurrentHashMap<String, IDeskShareStream>();
+	}
+	
+	public void onCaptureStartEvent(CaptureStartEvent event) {
+		log.debug("Creating stream " + event.getRoom());
+		
+		IDeskShareStream stream = streamFactory.createStream(event);
+
+		streamsMap.put(event.getRoom(), stream);
+		stream.start();
+			
+		//notify the clients in the room that the stream has now started broadcasting.
+		ISharedObject deskSO = deskShareApp.getSharedObject(stream.getScope(), "deskSO");
+		deskSO.sendMessage("appletStarted" , new ArrayList<Object>());
+
+	}
+	
+	public void onCaptureEndEvent(CaptureEndEvent event) {
+		IDeskShareStream ds = streamsMap.remove(event.getRoom());
+		if (ds != null) {
+			ds.stop();
+			ds = null;
+		}
+	}
+	
+	public void onCaptureEvent(CaptureUpdateEvent event) {
+		IDeskShareStream ds = streamsMap.get(event.getRoom());
+		if (ds != null) {
+			ds.accept(event);
+		}
+	}
+
+	public boolean isStreaming(String room){
+		IDeskShareStream ds = streamsMap.get(room);
+		if (ds != null) {
+			return true;
+		}
+		return false;
+	}
+	
+	public int getRoomVideoWidth(String room){
+		IDeskShareStream ds = streamsMap.get(room);
+		if (ds != null) {
+			return ds.getWidth();
+		}
+		return 0;
+	}
+	
+	public int getRoomVideoHeight(String room){
+		IDeskShareStream ds = streamsMap.get(room);
+		if (ds != null) {
+			return ds.getHeight();
+		}
+		return 0;
+	}	
+	
+	public void setStreamFactory(StreamFactory sf) {
+		this.streamFactory = sf;
+	}
+	
+	public void setDeskShareApplication(DeskShareApplication app) {
+		this.deskShareApp = app;
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/events/CaptureEndBlockEvent.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/events/CaptureEndBlockEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f33035e8200118a685708b9842ac9c1111d7aa4
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/events/CaptureEndBlockEvent.java
@@ -0,0 +1,35 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.events;
+
+public class CaptureEndBlockEvent {
+
+	private final String room;
+	
+	public CaptureEndBlockEvent(String room) {
+		this.room = room;
+	}
+		
+	public String getRoom() {
+		return room;
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/events/CaptureStartBlockEvent.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/events/CaptureStartBlockEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..6310e457ca078d587c3104cfe0c1726541433cc5
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/events/CaptureStartBlockEvent.java
@@ -0,0 +1,49 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.events;
+
+import org.bigbluebutton.deskshare.common.Dimension;
+
+public class CaptureStartBlockEvent {
+
+	private final String room;
+	private final Dimension screenDim;
+	private final Dimension blockDim;
+	
+	public CaptureStartBlockEvent(String room, Dimension screen, Dimension block) {
+		this.room = room;
+		screenDim = screen;
+		blockDim = block;
+	}
+	
+	public Dimension getScreenDimension() {
+		return screenDim;
+	}
+	
+	public Dimension getBlockDimension() {
+		return blockDim;
+	}
+	
+	public String getRoom() {
+		return room;
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/events/CaptureUpdateBlockEvent.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/events/CaptureUpdateBlockEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb85f6c6dd4256175fbace4d36744a106191aac9
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/events/CaptureUpdateBlockEvent.java
@@ -0,0 +1,53 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.events;
+
+public class CaptureUpdateBlockEvent {
+	private final String room;
+	private final int position;
+	private final byte[] videoData;
+	private final boolean isKeyFrame;
+	
+	public CaptureUpdateBlockEvent(String room, int position, byte[] videoData, boolean isKeyFrame) {
+		this.room = room;
+		this.position = position;
+		this.videoData = videoData;
+		this.isKeyFrame = isKeyFrame;
+	}
+		
+	public String getRoom() {
+		return room;
+	}
+
+	public int getPosition() {
+		return position;
+	}
+
+	public byte[] getVideoData() {
+		return videoData;
+	}
+
+	public boolean isKeyFrame() {
+		return isKeyFrame;
+	}
+	
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/servlet/HttpTunnelStreamController.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/servlet/HttpTunnelStreamController.java
new file mode 100644
index 0000000000000000000000000000000000000000..485af8f544386d99df99e01a3d63c97dfdad7ce9
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/servlet/HttpTunnelStreamController.java
@@ -0,0 +1,133 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.servlet;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.bigbluebutton.deskshare.common.Dimension;
+import org.bigbluebutton.deskshare.server.CaptureEvents;
+import org.bigbluebutton.deskshare.server.session.SessionManager;
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
+
+public class HttpTunnelStreamController extends MultiActionController {
+	private static Logger log = Red5LoggerFactory.getLogger(HttpTunnelStreamController.class, "deskshare");
+	
+	private boolean hasSessionManager = false;
+	private SessionManager sessionManager;
+	
+	public ModelAndView screenCaptureHandler(HttpServletRequest request, HttpServletResponse response) throws Exception {		
+
+		String event = request.getParameterValues("event")[0];	
+		int captureRequest = Integer.parseInt(event);
+
+		if (CaptureEvents.CAPTURE_START.getEvent() == captureRequest) {
+			handleCaptureStartRequest(request, response);
+		} else if (CaptureEvents.CAPTURE_UPDATE.getEvent() == captureRequest) {
+			handleCaptureUpdateRequest(request, response);
+		} else if (CaptureEvents.CAPTURE_END.getEvent() == captureRequest) {
+			handleCaptureEndRequest(request, response);
+		} else {
+			log.debug("Cannot handle screen capture event " + captureRequest);
+			System.out.println("Cannot handle screen capture event " + captureRequest);
+		}
+		return null;
+	}	
+	
+	private void handleCaptureStartRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {		
+		String room = request.getParameterValues("room")[0];
+		String screenInfo = request.getParameterValues("screenInfo")[0];
+		String blockInfo = request.getParameterValues("blockInfo")[0];
+		
+		String[] screen = screenInfo.split("x");
+		String[] block = blockInfo.split("x");
+		
+		Dimension screenDim, blockDim;
+		screenDim = new Dimension(Integer.parseInt(screen[0]), Integer.parseInt(screen[1]));
+		blockDim = new Dimension(Integer.parseInt(block[0]), Integer.parseInt(block[1]));
+		
+		if (! hasSessionManager) {
+			sessionManager = getSessionManager();
+			hasSessionManager = true;
+		}
+				
+		sessionManager.createSession(room, screenDim, blockDim);		
+	}	
+	
+	private void handleCaptureUpdateRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {		
+		MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
+		// MultipartFile is a copy of file in memory, not in file system
+		MultipartFile multipartFile = multipartRequest.getFile("blockdata");
+	
+		long startRx = System.currentTimeMillis();
+		
+		byte[] blockData = multipartFile.getBytes();
+		String room = request.getParameterValues("room")[0];
+		String keyframe = request.getParameterValues("keyframe")[0];
+		String position = request.getParameterValues("position")[0];
+				
+		if (! hasSessionManager) {
+			sessionManager = getSessionManager();
+			hasSessionManager = true;
+		}
+			
+		sessionManager.updateBlock(room, Integer.valueOf(position), blockData, Boolean.parseBoolean(keyframe));
+			
+		long completeRx = System.currentTimeMillis();
+//		System.out.println("Http receive and send took " + (completeRx - startRx) + "ms.");
+	}
+	
+	private void handleCaptureEndRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {		
+		String room = request.getParameterValues("room")[0];
+		if (! hasSessionManager) {
+			sessionManager = getSessionManager();
+			hasSessionManager = true;
+		}
+		System.out.println("HttpTunnel: Received Capture Enfd Event.");
+    	sessionManager.removeSession(room);
+	}
+	    
+	private SessionManager getSessionManager() {
+		//Get the servlet context
+		ServletContext ctx = getServletContext();
+		log.info("Got the servlet context: {}", ctx);
+		
+		//Grab a reference to the application context
+		ApplicationContext appCtx = (ApplicationContext) ctx.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
+		log.info("Got the application context: {}", appCtx);
+		
+		//Get the bean holding the parameter
+		SessionManager manager = (SessionManager) appCtx.getBean("sessionManager");
+		if (manager != null) {
+			log.info("Got the SessionManager context: {}", appCtx);
+		}
+		return manager;
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/servlet/TunnelController.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/servlet/TunnelController.java
new file mode 100644
index 0000000000000000000000000000000000000000..4eb0ebde4a4ab6dd474bbbbac113c4e8a335f952
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/servlet/TunnelController.java
@@ -0,0 +1,161 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.servlet;
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import javax.imageio.ImageIO;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.bigbluebutton.deskshare.server.CaptureEndEvent;
+import org.bigbluebutton.deskshare.server.CaptureEvents;
+import org.bigbluebutton.deskshare.server.CaptureStartEvent;
+import org.bigbluebutton.deskshare.server.CaptureUpdateEvent;
+import org.bigbluebutton.deskshare.server.CapturedScreen;
+import org.bigbluebutton.deskshare.server.StreamerGateway;
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
+
+public class TunnelController extends MultiActionController {
+	private static Logger log = Red5LoggerFactory.getLogger(TunnelController.class, "deskshare");
+	
+	private StreamerGateway streamerGateway;
+	private boolean hasGateway = false;
+	
+	public ModelAndView screenCaptureHandler(HttpServletRequest request, HttpServletResponse response) throws Exception {		
+
+		String event = request.getParameterValues("event")[0];
+		System.out.println("Got screenCaptureStart request for event " + event);
+		
+		int captureRequest = Integer.valueOf(request.getParameterValues("event")[0]).intValue();
+
+		if (CaptureEvents.CAPTURE_START.getEvent() == captureRequest) {
+			handleCaptureStartRequest(request, response);
+		} else if (CaptureEvents.CAPTURE_UPDATE.getEvent() == captureRequest) {
+			handleCaptureUpdateRequest(request, response);
+		} else if (CaptureEvents.CAPTURE_END.getEvent() == captureRequest) {
+			handleCaptureEndRequest(request, response);
+		} else {
+			log.debug("Cannot handle screen capture event " + captureRequest);
+			System.out.println("Cannot handle screen capture event " + captureRequest);
+		}
+		return null;
+	}	
+	
+	private void handleCaptureStartRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {		
+		String room = request.getParameterValues("room")[0];
+		log.warn("Got screenCaptureStart request for room {}", room);
+		
+		String videoInfo = request.getParameterValues("videoInfo")[0];
+		log.warn("Received image from videoInfo {}", videoInfo);
+		
+		String[] screenDimensions = videoInfo.split("x");
+		int width = Integer.parseInt(screenDimensions[0]);
+		int height = Integer.parseInt(screenDimensions[1]);
+		
+		if (! hasGateway) {
+			streamerGateway = getStreamerGateway();
+			hasGateway = true;
+		}
+		
+		CaptureStartEvent event = new CaptureStartEvent(room, width, height);		
+		streamerGateway.onCaptureStartEvent(event);		
+	}	
+	
+	private void handleCaptureUpdateRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {		
+		MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
+		// MultipartFile is a copy of file in memory, not in file system
+		MultipartFile multipartFile = multipartRequest.getFile("videodata");
+	
+		long startRx = System.currentTimeMillis();
+		
+		byte[] videoData = multipartFile.getBytes();
+		IoBuffer buffer = IoBuffer.allocate(videoData.length, false);
+		buffer.put(videoData);
+		
+		/* Set the marker back to zero position so that "gets" start from the beginning.
+		 * Otherwise, you get BufferUnderFlowException.
+		 */		
+		buffer.rewind();
+		
+		String room = request.getParameterValues("room")[0];
+		log.debug("Received image from room {}", room);
+		String keyframe = request.getParameterValues("keyframe")[0];
+		log.debug("Received keyframe {}", keyframe);
+		
+		System.out.println("Room " + room + " keyFrame " + Boolean.parseBoolean(keyframe) 
+				+ " data size " + videoData.length + " buffer size " + buffer.remaining());
+		CaptureUpdateEvent cse = new CaptureUpdateEvent(room, buffer);
+				
+		if (! hasGateway) {
+			streamerGateway = getStreamerGateway();
+			hasGateway = true;
+		}
+			
+		streamerGateway.onCaptureEvent(cse);	
+		long completeRx = System.currentTimeMillis();
+		System.out.println("Http receive and send took " + (completeRx - startRx) + "ms.");
+	}
+	
+	private void handleCaptureEndRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {		
+		String room = request.getParameterValues("room")[0];
+		log.warn("Got screenCaptureEnd request for room {}", room);
+		
+		if (! hasGateway) {
+			streamerGateway = getStreamerGateway();
+			hasGateway = true;
+		}
+		
+		CaptureEndEvent event = new CaptureEndEvent(room);
+		
+		streamerGateway.onCaptureEndEvent(event);
+		
+	}
+	    
+	private StreamerGateway getStreamerGateway() {
+		//Get the servlet context
+		ServletContext ctx = getServletContext();
+		log.info("Got the servlet context: {}", ctx);
+		
+		//Grab a reference to the application context
+		ApplicationContext appCtx = (ApplicationContext) ctx.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
+		log.info("Got the application context: {}", appCtx);
+		
+		//Get the bean holding the parameter
+		StreamerGateway streamerGateway = (StreamerGateway) appCtx.getBean("streamerGateway");
+		if (streamerGateway != null) {
+			log.info("Got the streamerGateway context: {}", appCtx);
+		}
+		return streamerGateway;
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/Block.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/Block.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd99a6568bbfa50a278ab74ab77fbf8f2ba48117
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/Block.java
@@ -0,0 +1,93 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.session;
+
+import java.util.Random;
+
+import org.bigbluebutton.deskshare.common.Dimension;
+
+public class Block {
+	Random random = new Random();
+    private final Dimension dim;
+    private final int position;
+ 
+    private boolean isKeyFrame = false;
+    private byte[] encodedBlock;
+    private int[] pixels;
+    
+    private boolean encoded = false;
+    private boolean hasChanged = false;
+    private static int FORCE_UPDATE_DURATION = 10000;
+    private int nextForceUpdate = 10000;
+    private static int MIN_DURATION = 5000;
+    private static int MAX_DURATION = 10000;
+    private long lastChanged;
+    
+    Block(Dimension dim, int position) {
+        this.dim = dim;
+        this.position = position;
+    }
+    
+    public synchronized void update(byte[] videoData, boolean isKeyFrame)
+    {	
+    	this.isKeyFrame = isKeyFrame;
+    	encodedBlock = videoData;
+    	hasChanged = true;
+    }
+ 
+    public synchronized byte[] getEncodedBlock() {
+    	hasChanged = false;
+    	return encodedBlock;
+    }
+    
+    public Dimension getDimension() {
+    	return dim;
+    }
+
+	public boolean isKeyFrame() {
+		return isKeyFrame;
+	}
+    
+    public boolean hasChanged() {
+    	return (hasChanged || forceUpdate());
+    }
+    
+    private boolean forceUpdate() {         
+        long now = System.currentTimeMillis();    
+        boolean update = ((now - lastChanged) > nextForceUpdate);
+        if (update) {
+        	synchronized(this) {
+        		nextUpdate();
+        		lastChanged = now;
+        	}       	
+        }
+        return update;
+    }
+    
+    private void nextUpdate() {
+        //get the range, casting to long to avoid overflow problems
+        long range = (long)MAX_DURATION - (long)MIN_DURATION + 1;
+        // compute a fraction of the range, 0 <= frac < range
+        long fraction = (long)(range * random.nextDouble());
+        nextForceUpdate =  (int)(fraction + 5000); 
+    }
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/BlockFactory.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/BlockFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..d9645c5c5e1c5fc3ac8a96836ee2f2cd1f8e8825
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/BlockFactory.java
@@ -0,0 +1,108 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.session;
+
+import org.bigbluebutton.deskshare.common.Dimension;
+
+public class BlockFactory {
+
+    public static int getNumberOfColumns(Dimension screenDim, Dimension blockDim) {
+    	int columns = screenDim.getWidth() / blockDim.getWidth();
+    	if (hasPartialColumnBlock(screenDim, blockDim)) {
+    		columns += 1;
+    	}
+    	return columns;
+    }
+    
+    private static boolean hasPartialColumnBlock(Dimension screenDim, Dimension blockDim) {
+    	return (screenDim.getWidth() % blockDim.getWidth()) != 0;
+    }
+    
+    public static int getNumberOfRows(Dimension screenDim, Dimension blockDim) {
+    	int rows = screenDim.getHeight() / blockDim.getHeight();
+    	if (hasPartialRowBlock(screenDim, blockDim)) {
+    		rows += 1;
+    	}
+    	return rows;
+    }
+    
+    private static boolean hasPartialRowBlock(Dimension screenDim, Dimension blockDim) {
+    	return (screenDim.getHeight() % blockDim.getHeight()) != 0;
+    }
+  
+    public static Block createBlock(Dimension screenDim, Dimension blockDim, int position) {
+    	int numRows = getNumberOfRows(screenDim, blockDim);
+    	int numColumns = getNumberOfColumns(screenDim, blockDim);
+    	
+    	int col = computeColumn(position, numColumns);
+    	int row = computeRow(position, numRows, numColumns);
+		int w = computeTileWidth(col, screenDim, blockDim);
+		int h = computeTileHeight(row, screenDim, blockDim);		
+		
+		Block t = new Block(new Dimension(w, h), position);
+
+		return t;
+    }
+       
+    private static int computeRow(int position, int numRows, int numColumns) {
+    	return -(position - (numRows * numColumns)) / numColumns;
+    }
+    
+    private static int computeColumn(int position, int numColumns) {
+		return (position - 1) % numColumns;    	
+    }
+    
+    private static int computeTileWidth(int col, Dimension screenDim, Dimension blockDim) {
+    	int numColumns = getNumberOfColumns(screenDim, blockDim);
+    	if (isLastColumnTile(col, numColumns)) {
+    		if (hasPartialColumnBlock(screenDim, blockDim)) {
+    			return partialTileWidth(screenDim, blockDim);
+    		}
+    	}
+    	return blockDim.getWidth();
+    }
+    
+    private static int partialTileWidth(Dimension screenDim, Dimension blockDim) {
+    	return screenDim.getWidth() % blockDim.getWidth();
+    }
+    
+    private static int computeTileHeight(int row, Dimension screenDim, Dimension blockDim) {
+    	if (isTopRowTile(row)) {
+    		if (hasPartialRowBlock(screenDim, blockDim)) {
+    			return partialTileHeight(screenDim, blockDim);
+    		}
+    	}
+    	return blockDim.getWidth();
+    }
+    
+    private static int partialTileHeight(Dimension screenDim, Dimension blockDim) {
+    	return screenDim.getHeight() % blockDim.getHeight();
+    }
+
+    private static boolean isLastColumnTile(int col, int numColumns) {
+    	return ((col+1) % numColumns) == 0;
+    }
+    
+    private static boolean isTopRowTile(int row) {
+    	return (row == 0);
+    }
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/BlockManager.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/BlockManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..8fcbdf6d25b13f8662c58fea187499c87193d99e
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/BlockManager.java
@@ -0,0 +1,134 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.session;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.bigbluebutton.deskshare.common.ScreenVideoEncoder;
+import org.bigbluebutton.deskshare.common.Dimension;
+
+public class BlockManager {
+
+	private final ConcurrentMap<Integer, Block> blocksMap;
+
+	private final Dimension screenDim;
+	private final Dimension blockDim;
+	private final String room;
+	
+	private final int numberOfRows;
+	private final int numberOfColumns;
+    private long lastFrameTime = 0;
+    private long lastKeyFrameTime = 0;
+    private final static int KEYFRAME_INTERVAL = 20000;
+    private ByteArrayOutputStream screenVideoFrame;
+    
+    private FrameStreamer streamer;
+    
+	public BlockManager(String room, Dimension screen, Dimension block, FrameStreamer streamer) {
+		screenDim = screen;
+		blockDim = block;
+		this.room = room;
+		
+		blocksMap = new ConcurrentHashMap<Integer, Block>();
+
+		numberOfRows = BlockFactory.getNumberOfRows(screen, block);
+		numberOfColumns = BlockFactory.getNumberOfColumns(screen, block);
+		
+		screenVideoFrame = new ByteArrayOutputStream();
+				
+		this.streamer = streamer;
+	}
+	
+	public void initialize() {
+		System.out.println("Initialize BlockManager");
+		int numberOfBlocks = numberOfRows * numberOfColumns;
+		for (int position = 1; position <= numberOfBlocks; position++)  {
+			Block block = BlockFactory.createBlock(screenDim, blockDim, position);
+			initializeBlock(block);
+			blocksMap.put(new Integer(position), block);
+		}
+		generateFrame(true);
+	}
+	
+	private void initializeBlock(Block block) {
+		Dimension dim = block.getDimension();
+		int width = dim.getWidth();
+		int height = dim.getHeight();
+		int[] blankPixels = new int[width * height];
+		for (int i = 0; i < blankPixels.length; i++) {
+			blankPixels[i] = 0xFFFF;
+		}
+		byte[] encodedPixels = ScreenVideoEncoder.encodePixels(blankPixels, width, height, false, true);
+		block.update(encodedPixels, true);
+	}
+	
+	public void updateBlock(int position, byte[] videoData, boolean keyFrame) {
+		Block block = blocksMap.get(new Integer(position));
+		block.update(videoData, keyFrame);
+    	long now = System.currentTimeMillis();
+    	if ((now - lastFrameTime) > 100) {
+    		lastFrameTime = now;
+//    		if ((now-lastKeyFrameTime) > KEYFRAME_INTERVAL){
+//    			generateFrame(true);
+//    		} else {
+ //   			generateFrame(false);
+ //   		}
+    		generateFrame(false);	
+    	}
+	}
+	
+	private void generateFrame(boolean genKeyFrame) {
+//		System.out.println("Generating frame " + genKeyFrame);
+		Map<Integer, Block> blocks = Collections.unmodifiableMap(new HashMap<Integer, Block>(blocksMap));
+		
+		screenVideoFrame.reset();
+		byte[] encodedDim = ScreenVideoEncoder.encodeBlockAndScreenDimensions(blockDim.getWidth(), screenDim.getWidth(), blockDim.getHeight(), screenDim.getHeight());
+     	    	
+		try {
+    		int numberOfBlocks = numberOfRows * numberOfColumns;   		
+    		byte videoDataHeader = ScreenVideoEncoder.encodeFlvVideoDataHeader(genKeyFrame);
+    		    		
+    		screenVideoFrame.write(videoDataHeader);
+    		screenVideoFrame.write(encodedDim);
+    		
+    		for (int position = 1; position <= numberOfBlocks; position++)  {
+    			Block block = (Block) blocks.get(new Integer(position));
+    			byte[] encodedBlock = ScreenVideoEncoder.encodeBlockUnchanged();
+    			if (block.hasChanged() || genKeyFrame) {
+    				encodedBlock = block.getEncodedBlock();
+    			}
+    			screenVideoFrame.write(encodedBlock, 0, encodedBlock.length);
+    		}
+    		ScreenVideoFrame frame = new ScreenVideoFrame(room, screenVideoFrame);
+    		streamer.sendFrame(frame);
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}		
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/FlvEncodeException.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/FlvEncodeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..3ace8d69dd34848cce51c9f297f642df0bdfa5e6
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/FlvEncodeException.java
@@ -0,0 +1,31 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.session;
+
+public class FlvEncodeException extends Exception {
+
+	private static final long serialVersionUID = -3377474098350652011L;
+
+	public FlvEncodeException(String message) {
+		super(message);
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/FlvStreamToFile.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/FlvStreamToFile.java
new file mode 100644
index 0000000000000000000000000000000000000000..ccaffb302cf88864ab1e485f7e0176fa9d94ea90
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/FlvStreamToFile.java
@@ -0,0 +1,112 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.session;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class FlvStreamToFile {
+
+	private BlockingQueue<ScreenVideoFrame> screenQueue = new LinkedBlockingQueue<ScreenVideoFrame>();
+	private final Executor exec = Executors.newSingleThreadExecutor();
+	private Runnable capturedScreenSender;
+	private volatile boolean sendCapturedScreen = false;
+
+	private FileOutputStream fo;
+	private ScreenVideoFlvEncoder svf = new ScreenVideoFlvEncoder();
+	
+	private String flvFilename = "/tmp/screenvideostream.flv";
+	
+	public void accept(ScreenVideoFrame frame) {
+		try {
+			screenQueue.put(frame);
+		} catch (InterruptedException e) {
+			System.out.println("InterruptedException while putting event into queue.");
+		}
+	}
+
+	public void start() {
+		try {
+			fo = new FileOutputStream(flvFilename);
+			fo.write(svf.encodeHeader());
+		} catch (FileNotFoundException e1) {
+			// TODO Auto-generated catch block
+			e1.printStackTrace();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+		sendCapturedScreen = true;
+		System.out.println("Starting stream");
+		capturedScreenSender = new Runnable() {
+			public void run() {
+				while (sendCapturedScreen) {
+					try {
+						System.out.println("ScreenQueue size " + screenQueue.size());
+						ScreenVideoFrame newScreen = screenQueue.take();
+						sendCapturedScreen(newScreen);
+					} catch (InterruptedException e) {
+						System.out.println("InterruptedExeption while taking event.");
+					}
+				}
+			}
+		};
+		exec.execute(capturedScreenSender);
+	}
+
+	private void sendCapturedScreen(ScreenVideoFrame event) {
+//	System.out.println("ENABLE FlvStreamToFile:sendCapturedScreen");
+			
+		try {
+			byte[] data = svf.encodeFlvData(event.getVideoData().array());
+			System.out.println("Saving video data with length " + data.length);
+			fo.write(data);
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (FlvEncodeException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}		
+
+	}
+	
+	public void stop() {
+    	try {
+    		System.out.println("Closing stream");
+			fo.close();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
+	public void setFlvFilename(String filename) {
+		flvFilename = filename;
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/FrameStreamer.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/FrameStreamer.java
new file mode 100644
index 0000000000000000000000000000000000000000..cf48b9bc282c1e103a3e3ccd9df354a31d2426de
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/FrameStreamer.java
@@ -0,0 +1,88 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.session;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.bigbluebutton.deskshare.server.FrameStreamerGateway;
+
+public class FrameStreamer {
+	private BlockingQueue<ScreenVideoFrame> screenQ = new LinkedBlockingQueue<ScreenVideoFrame>(10);
+	private final Executor exec = Executors.newSingleThreadExecutor();
+	private Runnable capturedScreenSender;
+	private volatile boolean sendCapturedScreen = false;
+	
+	private FrameStreamerGateway gateway;
+	
+	public void start() {	
+		System.out.println("Starting FrameStreamer ");
+		sendCapturedScreen = true;
+		capturedScreenSender = new Runnable() {
+			public void run() {
+				while (sendCapturedScreen) {
+					try {
+						ScreenVideoFrame videoFrame = screenQ.take();
+						if (screenQ.size() > 9) screenQ.clear();
+						streamScreenVideoFrame(videoFrame);
+
+					} catch (InterruptedException e) {
+						System.out.println("InterruptedExeption while taking event.");
+					}
+				}
+			}
+		};
+		exec.execute(capturedScreenSender);		
+	}
+	
+	public void sendFrame(ScreenVideoFrame frame) {
+		
+		try {
+			screenQ.put(frame);
+		} catch (InterruptedException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	private void streamScreenVideoFrame(ScreenVideoFrame frame) {
+		//flvStreamer.accept(frame);
+		gateway.onCaptureEvent(frame);
+	}
+	
+	public void createNewStream(String room, int screenWidth, int screenHeight) {
+		System.out.println("Creating new Stream " + room);
+		gateway.createNewStream(room, screenWidth, screenHeight);
+	}
+	
+	public void endStream(String room) {
+		System.out.println("Stopping streamer");
+		gateway.onCaptureEndEvent(room);
+	}
+	
+	public void setFrameStreamerGateway(FrameStreamerGateway gateway) {
+		System.out.println("Setting FrameStreamerGateway");
+		this.gateway = gateway;
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/ScreenVideoFlvEncoder.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/ScreenVideoFlvEncoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..9d28feaee6ff131e6245be108882230679fc079f
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/ScreenVideoFlvEncoder.java
@@ -0,0 +1,106 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.session;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public final class ScreenVideoFlvEncoder {
+	private final static byte[] flvHeader = {'F','L','V',0x01,0x01,0x00,0x00,0x00,0x09};
+	private final static byte[] videoTagType = {0x09};
+	private final static byte[] streamId = {0, 0, 0};
+	private long startTimestamp = 0;
+	private boolean firstTag = true;
+	
+	private static byte FLV_TAG_HEADER_SIZE = 11;
+	
+	ByteArrayOutputStream flvDataStream = new ByteArrayOutputStream();
+	
+	public byte[] encodeHeader() {
+		byte[] prevTagSize =  encodePreviousTagSize(0);
+		byte[] header = new byte[flvHeader.length + prevTagSize.length];
+		
+		System.arraycopy(flvHeader, 0, header, 0, flvHeader.length);
+		System.arraycopy(prevTagSize, 0, header, flvHeader.length, prevTagSize.length);
+		return header;
+	}
+	
+    private byte[] encodePreviousTagSize(long previousTagSize) {    	
+    	int byte1 = (int)previousTagSize >> 24;
+    	int byte2 = (int)previousTagSize >> 16;
+    	int byte3 = (int)previousTagSize >> 8;
+    	int byte4 = (int)previousTagSize & 0xff;
+    	
+    	return new byte[] {(byte)byte1, (byte)byte2, (byte)byte3, (byte)byte4};
+    }
+    
+    public byte[] encodeFlvData (byte[] screenVideoData) throws FlvEncodeException {
+
+        byte[] flvData;
+		try {
+			flvData = encodeFlvTag(screenVideoData);
+		} catch (IOException e) {
+			throw new FlvEncodeException("Failed to encode FLV data.");
+		}   
+        return flvData;
+	}
+	
+	private byte[] encodeFlvTag(byte[] videoData) throws IOException {   
+
+		flvDataStream.reset();
+		
+		flvDataStream.write(videoTagType);
+		flvDataStream.write(encodeDataSize(videoData.length));
+	    flvDataStream.write(encodeTimestamp());
+	    flvDataStream.write(streamId);
+	    flvDataStream.write(videoData);
+	    flvDataStream.write(encodePreviousTagSize(FLV_TAG_HEADER_SIZE + videoData.length));
+	    
+	    return flvDataStream.toByteArray();
+	}	
+	        
+    private byte[] encodeDataSize(int size) {
+    	int byte1 = (size >> 16);
+    	int byte2 = (size >> 8);
+    	int byte3 = (size & 0x0ff);
+    	
+    	return new byte[] {(byte) byte1, (byte) byte2, (byte) byte3};
+    }
+    
+    private byte[] encodeTimestamp() {
+    	long now = System.currentTimeMillis();
+    	
+    	if (firstTag) {
+    		startTimestamp = now;
+    		firstTag = false;
+    	}
+    	
+    	long elapsed = now - startTimestamp;
+    	
+    	int byte1 = (int)(elapsed & 0xff0000) >> 16;
+    	int byte2 = (int)(elapsed & 0xff00) >> 8;
+    	int byte3 = (int)(elapsed & 0xff);
+    	int tsExtended = ((int)elapsed & 0xff000000) >> 24;
+    	
+    	return new byte[] {(byte) byte1, (byte) byte2, (byte) byte3, (byte) tsExtended};    		    	
+    }   
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/ScreenVideoFrame.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/ScreenVideoFrame.java
new file mode 100644
index 0000000000000000000000000000000000000000..92396fbc48e309a44af679c01e15a7329377f7e0
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/ScreenVideoFrame.java
@@ -0,0 +1,55 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.session;
+
+import java.io.ByteArrayOutputStream;
+
+import org.apache.mina.core.buffer.IoBuffer;
+
+public class ScreenVideoFrame {
+
+	private final String room;
+	private final ByteArrayOutputStream encodedData;
+	
+	public ScreenVideoFrame(String room, ByteArrayOutputStream encodedData) {
+		this.room = room;
+		this.encodedData = encodedData;
+	}
+	
+	public String getRoom() {
+		return room;
+	}
+	
+	public IoBuffer getVideoData() {
+		byte[] data = (byte[]) encodedData.toByteArray();
+		
+		IoBuffer buffer = IoBuffer.allocate(data.length, false);
+		buffer.put(data);
+		
+		/* Set the marker back to zero position so that "gets" start from the beginning.
+		 * Otherwise, you get BufferUnderFlowException.
+		 */		
+		buffer.rewind();	
+		return buffer;
+	}
+
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/Session.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/Session.java
new file mode 100644
index 0000000000000000000000000000000000000000..59f865a89f921747b83ee7de73a66b9d2755eeb7
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/Session.java
@@ -0,0 +1,39 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.session;
+
+import org.bigbluebutton.deskshare.common.Dimension;
+
+public class Session {
+	private BlockManager blockManager;
+	public Session(String room, Dimension screen, Dimension block, FrameStreamer streamer) {
+		blockManager = new BlockManager(room, screen, block, streamer);
+	}
+	
+	public void initialize() {
+		blockManager.initialize();
+	}
+	public void updateBlock(int position, byte[] videoData, boolean keyFrame) {
+		blockManager.updateBlock(position, videoData, keyFrame);
+	}
+	
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/SessionManager.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/SessionManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9c85a007eb4569cecabae35e87d484b4440cac3
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/SessionManager.java
@@ -0,0 +1,68 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.session;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.bigbluebutton.deskshare.common.Dimension;
+
+public class SessionManager {
+
+	private final ConcurrentHashMap<String, Session> sessions;
+	private FrameStreamer frameStreamer;
+	
+	public SessionManager() {
+		sessions = new ConcurrentHashMap<String, Session>();
+	}
+	
+	public synchronized void createSession(String room, Dimension screen, Dimension block) {
+		if (! sessions.containsKey(room)) {
+			System.out.println("Created session " + room);
+			frameStreamer.createNewStream(room, screen.getWidth(), screen.getHeight());
+			Session session = new Session(room, screen, block, frameStreamer);
+			if (sessions.putIfAbsent(room, session) == null) {
+				// Successfully inserted session. I.e. no previous session.
+				session.initialize();
+			}
+		} else {
+			System.out.println("Session already exist for " + room);
+		}
+	}
+
+	public synchronized void removeSession(String room) {
+		System.out.println("Removing session " + room);
+		sessions.remove(room);
+		frameStreamer.endStream(room);
+	}
+	
+	public void updateBlock(String room, int position, byte[] blockData, boolean keyframe) {
+		Session session = sessions.get(room);
+		if (session != null)
+			session.updateBlock(position, blockData, keyframe);
+	}
+		
+	public void setFrameStreamer(FrameStreamer streamer) {
+		System.out.println("Setting FrameStreamer");
+		frameStreamer = streamer;
+		frameStreamer.start();
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/BlockStreamEventMessageHandler.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/BlockStreamEventMessageHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..317aef0768960d39c0df34bf9422c74eec64b4e6
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/BlockStreamEventMessageHandler.java
@@ -0,0 +1,91 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.socket;
+
+import org.apache.mina.core.service.IoHandlerAdapter;
+import org.apache.mina.core.session.IdleStatus;
+import org.apache.mina.core.session.IoSession;
+import org.bigbluebutton.deskshare.server.events.CaptureEndBlockEvent;
+import org.bigbluebutton.deskshare.server.events.CaptureStartBlockEvent;
+import org.bigbluebutton.deskshare.server.events.CaptureUpdateBlockEvent;
+import org.bigbluebutton.deskshare.server.session.SessionManager;
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+
+public class BlockStreamEventMessageHandler extends IoHandlerAdapter {
+	final private Logger log = Red5LoggerFactory.getLogger(BlockStreamEventMessageHandler.class, "deskshare");
+	
+	private SessionManager sessionManager;
+	
+    @Override
+    public void exceptionCaught( IoSession session, Throwable cause ) throws Exception
+    {
+        log.warn(cause.toString() + " \n " + cause.getMessage());
+        cause.printStackTrace();
+    }
+
+    @Override
+    public void messageReceived( IoSession session, Object message ) throws Exception
+    {
+    	if (message instanceof CaptureStartBlockEvent) {
+    		System.out.println("Got CaptureStartBlockEvent");
+    		CaptureStartBlockEvent event = (CaptureStartBlockEvent) message;
+    		sessionManager.createSession(event.getRoom(), event.getScreenDimension(), event.getBlockDimension());
+    	} else if (message instanceof CaptureUpdateBlockEvent) {
+//    		System.out.println("Got CaptureUpdateBlockEvent");
+    		CaptureUpdateBlockEvent event = (CaptureUpdateBlockEvent) message;
+    		sessionManager.updateBlock(event.getRoom(), event.getPosition(), event.getVideoData(), event.isKeyFrame());
+    	} else if (message instanceof CaptureEndBlockEvent) {
+    		CaptureEndBlockEvent event = (CaptureEndBlockEvent) message;
+    		sessionManager.removeSession(event.getRoom());
+    	}
+    }
+
+    @Override
+    public void sessionIdle( IoSession session, IdleStatus status ) throws Exception
+    {
+    	log.debug( "IDLE " + session.getIdleCount( status ));
+    }
+    
+    @Override
+    public void sessionCreated(IoSession session) throws Exception {
+    	log.debug("Session Created");
+    }
+    
+    @Override
+    public void sessionOpened(IoSession session) throws Exception {
+    	log.debug("Session Opened.");
+    }
+    
+    @Override
+    public void sessionClosed(IoSession session) throws Exception {
+    	log.debug("Session Closed.");
+    	
+    	String room = (String) session.getAttribute("ROOM");
+    	System.out.println("Session Closed for room " + room);
+    	sessionManager.removeSession(room);
+    }
+    
+    public void setSessionManager(SessionManager sm) {
+    	sessionManager = sm;
+    }
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/BlockStreamProtocolDecoder.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/BlockStreamProtocolDecoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..99c7ce9f7691b29fc56dacaa5106272da10c1afb
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/BlockStreamProtocolDecoder.java
@@ -0,0 +1,151 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.socket;
+
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolDecoderOutput;
+import org.bigbluebutton.deskshare.common.Dimension;
+import org.bigbluebutton.deskshare.server.CaptureStartEvent;
+import org.bigbluebutton.deskshare.server.CaptureUpdateEvent;
+import org.bigbluebutton.deskshare.server.events.CaptureEndBlockEvent;
+import org.bigbluebutton.deskshare.server.events.CaptureStartBlockEvent;
+import org.bigbluebutton.deskshare.server.events.CaptureUpdateBlockEvent;
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+
+public class BlockStreamProtocolDecoder extends CumulativeProtocolDecoder {
+	final private Logger log = Red5LoggerFactory.getLogger(BlockStreamProtocolDecoder.class, "deskshare");
+	
+	private static final String ROOM = "ROOM";
+	
+    private static final byte[] HEADER = new byte[] {'B', 'B', 'B', '-', 'D', 'S'};
+    private static final byte CAPTURE_START_EVENT = 0;
+    private static final byte CAPTURE_UPDATE_EVENT = 1;
+    private static final byte CAPTURE_END_EVENT = 2;
+        
+    protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
+     	
+    	// Let's work with a buffer that contains header and the message length,
+    	// ten (10) should be enough since header (6-bytes) plus length (4-bytes)
+    	if (in.remaining() < 10) return false;
+    		
+    	byte[] header = new byte[HEADER.length];    
+    	
+    	int start = in.position();
+    	
+    	in.get(header, 0, HEADER.length);    	
+    	int messageLength = in.getInt();    	
+//    	System.out.println("Message Length " + messageLength);
+    	if (in.remaining() < messageLength) {
+    		in.position(start);
+    		return false;
+    	}
+    		
+    	decodeMessage(session, in, out);
+    	
+    	return true;
+    }
+    
+    private void decodeMessage(IoSession session, IoBuffer in, ProtocolDecoderOutput out) {
+    	byte event = in.get();
+    	switch (event) {
+	    	case CAPTURE_START_EVENT:
+	    		System.out.println("Decoding CAPTURE_START_EVENT");
+	    		decodeCaptureStartEvent(session, in, out);
+	    		break;
+	    	case CAPTURE_UPDATE_EVENT:
+//	    		System.out.println("Decoding CAPTURE_UPDATE_EVENT");
+	    		decodeCaptureUpdateEvent(session, in, out);
+	    		break;
+	    	case CAPTURE_END_EVENT:
+	    		log.warn("Got CAPTURE_END_EVENT event: " + event);
+	    		System.out.println("Got CAPTURE_END_EVENT event: " + event);
+	    		decodeCaptureEndEvent(session, in, out);
+	    		break;
+	    	default:
+    			log.error("Unknown event: " + event);
+    	}
+    }
+    
+    private void decodeCaptureEndEvent(IoSession session, IoBuffer in, ProtocolDecoderOutput out) {
+    	String room = decodeRoom(session, in);
+    	
+    	if (! room.isEmpty()) {
+    		CaptureEndBlockEvent event = new CaptureEndBlockEvent(room);
+    		out.write(event);
+    	} else {
+    		System.out.println("Room is empty.");
+    	}
+    }
+    
+    private void decodeCaptureStartEvent(IoSession session, IoBuffer in, ProtocolDecoderOutput out) { 
+    	String room = decodeRoom(session, in);
+
+		Dimension blockDim = decodeDimension(in);
+		Dimension screenDim = decodeDimension(in);    	
+	    System.out.println("Block dim [" + blockDim.getWidth() + "," + blockDim.getHeight() + "]");
+	    System.out.println("Screen dim [" + screenDim.getWidth() + "," + screenDim.getHeight() + "]");
+	    
+	    CaptureStartBlockEvent event = new CaptureStartBlockEvent(room, 
+	    									screenDim, blockDim);	
+	    out.write(event);
+    }
+    
+    private Dimension decodeDimension(IoBuffer in) {
+    	int width = in.getInt();
+    	int height = in.getInt();
+		return new Dimension(width, height);
+    }
+       
+    private String decodeRoom(IoSession session, IoBuffer in) {
+    	int roomLength = in.get();
+//    	System.out.println("Room length = " + roomLength);
+    	String room = "";
+    	try {    		
+    		room = in.getString(roomLength, Charset.forName( "UTF-8" ).newDecoder());
+    		session.setAttribute(ROOM, room);
+		} catch (CharacterCodingException e) {
+			e.printStackTrace();
+		}   
+		
+		return room;
+    }
+    
+    private void decodeCaptureUpdateEvent(IoSession session, IoBuffer in, ProtocolDecoderOutput out) {
+    	String room = decodeRoom(session, in);
+    	int position = in.getShort();
+    	boolean isKeyFrame = (in.get() == 1) ? true : false;
+    	int length = in.getInt();
+    	byte[] data = new byte[length];
+    	in.get(data, 0, length);
+    	
+//    	System.out.println("position=[" + position + "] keyframe=" + isKeyFrame + " length= " + length);
+    	
+    	CaptureUpdateBlockEvent event = new CaptureUpdateBlockEvent(room, position, data, isKeyFrame);
+    	out.write(event);
+    }
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/DebugScreenCaptureMessageHandler.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/DebugScreenCaptureMessageHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..cecd4d2f61cd5fe95cb3532e03e720442717b921
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/DebugScreenCaptureMessageHandler.java
@@ -0,0 +1,98 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.socket;
+
+import org.apache.mina.core.service.IoHandlerAdapter;
+import org.apache.mina.core.session.IdleStatus;
+import org.apache.mina.core.session.IoSession;
+import org.bigbluebutton.deskshare.server.CaptureEndEvent;
+import org.bigbluebutton.deskshare.server.CaptureStartEvent;
+import org.bigbluebutton.deskshare.server.CaptureUpdateEvent;
+import org.bigbluebutton.deskshare.server.CapturedScreen;
+import org.bigbluebutton.deskshare.server.StreamerGateway;
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+
+public class DebugScreenCaptureMessageHandler extends IoHandlerAdapter {
+	final private Logger log = Red5LoggerFactory.getLogger(DebugScreenCaptureMessageHandler.class, "deskshare");
+	
+	
+    @Override
+    public void exceptionCaught( IoSession session, Throwable cause ) throws Exception
+    {
+        log.warn(cause.toString());
+        cause.printStackTrace();
+    }
+
+    @Override
+    public void messageReceived( IoSession session, Object message ) throws Exception
+    {
+    	log.debug("Message Received " + (String) message);
+/*    	
+    	CapturedScreen cs = (CapturedScreen) message;
+        String room = cs.getRoom();
+        log.debug("Got room {}", room);
+        
+        if (session.containsAttribute("room")) {
+        	sendCaptureEvent(cs);
+        } else {
+        	session.setAttribute("room", room);
+        	sendCaptureStartEvent(cs);
+        }
+*/        
+    }
+
+    @Override
+    public void sessionIdle( IoSession session, IdleStatus status ) throws Exception
+    {
+    	log.debug( "IDLE " + session.getIdleCount( status ));
+    }
+    
+    @Override
+    public void sessionCreated(IoSession session) throws Exception {
+    	log.debug("Session Created");
+    }
+    
+    @Override
+    public void sessionOpened(IoSession session) throws Exception {
+    	log.debug("Session Opened.");
+    }
+    
+    @Override
+    public void sessionClosed(IoSession session) throws Exception {
+    	log.debug("Session Closed.");
+    	String room = (String) session.getAttribute("room");
+    	sendCaptureEndEvent(room);
+    }
+    
+    private void sendCaptureEndEvent(String room) {
+
+    }
+    
+    private void sendCaptureEvent(CapturedScreen cs) {
+
+    }
+    
+    private void sendCaptureStartEvent(CapturedScreen cs) {
+
+    }
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/DeskShareServer.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/DeskShareServer.java
new file mode 100644
index 0000000000000000000000000000000000000000..28761109f6e0c30334e0d8a67b8b113bb299c6ab
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/DeskShareServer.java
@@ -0,0 +1,66 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.socket;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+import org.apache.mina.core.service.IoHandlerAdapter;
+import org.apache.mina.core.session.IdleStatus;
+import org.apache.mina.filter.codec.ProtocolCodecFilter;
+import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+
+
+public class DeskShareServer {
+	final private Logger log = Red5LoggerFactory.getLogger(DeskShareServer.class, "deskshare");
+	
+    private static final int PORT = 9123;
+
+    private IoHandlerAdapter screenCaptureHandler;
+    private NioSocketAcceptor acceptor;
+    
+    public void start()
+    {
+        acceptor = new NioSocketAcceptor();
+        acceptor.getFilterChain().addLast( "codec",  new ProtocolCodecFilter(new ScreenCaptureProtocolCodecFactory()));
+
+        acceptor.setHandler( screenCaptureHandler);
+        acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 );
+        acceptor.setReuseAddress(true);
+        try {
+			acceptor.bind( new InetSocketAddress(PORT) );
+		} catch (IOException e) {
+			log.error("IOException while binding to port {}", PORT);
+		}
+    }
+
+	public void setScreenCaptureHandler(IoHandlerAdapter screenCaptureHandler) {
+		this.screenCaptureHandler = screenCaptureHandler;
+	}
+	
+	public void stop() {
+		acceptor.unbind();
+		acceptor.dispose();
+	}	
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/DeskShareServerMain.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/DeskShareServerMain.java
new file mode 100644
index 0000000000000000000000000000000000000000..021705fcd23671e3ef39644235c488a0fa46216f
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/DeskShareServerMain.java
@@ -0,0 +1,36 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.socket;
+
+public class DeskShareServerMain {
+
+
+	public static void main(String[] args) {
+		DeskShareServer server = new DeskShareServer();
+		
+		server.setScreenCaptureHandler(new DebugScreenCaptureMessageHandler());
+		server.start();
+		System.out.println("Server starting");
+		while (true) {}
+	}
+
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/NullProtocolEncoder.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/NullProtocolEncoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..dcf805078b58aa9053ce041170f095b651f9f99a
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/NullProtocolEncoder.java
@@ -0,0 +1,41 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.socket;
+
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+import org.apache.mina.filter.codec.ProtocolEncoderOutput;
+
+public class NullProtocolEncoder implements ProtocolEncoder {
+
+	public void dispose(IoSession in) throws Exception {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void encode(IoSession session, Object message, ProtocolEncoderOutput out)
+			throws Exception {
+		// TODO Auto-generated method stub
+
+	}
+
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/ScreenCaptureMessageHandler.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/ScreenCaptureMessageHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..c08a33bf955e5a7768d89c91d6a92c5f501380eb
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/ScreenCaptureMessageHandler.java
@@ -0,0 +1,100 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.socket;
+
+import org.apache.mina.core.service.IoHandlerAdapter;
+import org.apache.mina.core.session.IdleStatus;
+import org.apache.mina.core.session.IoSession;
+import org.bigbluebutton.deskshare.server.CaptureEndEvent;
+import org.bigbluebutton.deskshare.server.CaptureMessage;
+import org.bigbluebutton.deskshare.server.CaptureStartEvent;
+import org.bigbluebutton.deskshare.server.CaptureUpdateEvent;
+import org.bigbluebutton.deskshare.server.ICaptureEvent;
+import org.bigbluebutton.deskshare.server.StreamerGateway;
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+
+public class ScreenCaptureMessageHandler extends IoHandlerAdapter {
+	final private Logger log = Red5LoggerFactory.getLogger(ScreenCaptureMessageHandler.class, "deskshare");
+	
+	private StreamerGateway streamerGateway;
+	
+    @Override
+    public void exceptionCaught( IoSession session, Throwable cause ) throws Exception
+    {
+        log.warn(cause.toString() + " \n " + cause.getMessage());
+        cause.printStackTrace();
+    }
+
+    @Override
+    public void messageReceived( IoSession session, Object message ) throws Exception
+    {
+    	CaptureMessage msgType = ((ICaptureEvent) message).getMessageType();
+    	
+    	if (msgType == CaptureMessage.CAPTURE_START) {
+    		log.debug("Received CAPTURE_START");
+    		sendCaptureStartEvent((CaptureStartEvent) message);
+    	} else if (msgType == CaptureMessage.CAPTURE_UPDATE) {
+ //   		log.debug("Received CAPTURE_UPDATE");
+    		sendCaptureUpdateEvent((CaptureUpdateEvent) message);
+    	}       
+    }
+
+    @Override
+    public void sessionIdle( IoSession session, IdleStatus status ) throws Exception
+    {
+    	log.debug( "IDLE " + session.getIdleCount( status ));
+    }
+    
+    @Override
+    public void sessionCreated(IoSession session) throws Exception {
+    	log.debug("Session Created");
+    }
+    
+    @Override
+    public void sessionOpened(IoSession session) throws Exception {
+    	log.debug("Session Opened.");
+    }
+    
+    @Override
+    public void sessionClosed(IoSession session) throws Exception {
+    	log.debug("Session Closed.");
+    	String room = (String) session.getAttribute("ROOM");
+    	sendCaptureEndEvent(room);
+    }
+    
+    private void sendCaptureEndEvent(String room) {
+    	streamerGateway.onCaptureEndEvent(new CaptureEndEvent(room));
+    }
+    
+    private void sendCaptureUpdateEvent(CaptureUpdateEvent event) {
+    		streamerGateway.onCaptureEvent(event);   	
+    }
+    
+    private void sendCaptureStartEvent(CaptureStartEvent event) {
+    	streamerGateway.onCaptureStartEvent(event);
+    }
+    
+    public void setStreamerGateway(StreamerGateway sg) {
+    	streamerGateway = sg;
+    }
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/ScreenCaptureProtocolCodecFactory.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/ScreenCaptureProtocolCodecFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..158a6ec4d35d3be9cb7ad5412c13e218c5681c77
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/ScreenCaptureProtocolCodecFactory.java
@@ -0,0 +1,46 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.socket;
+
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolCodecFactory;
+import org.apache.mina.filter.codec.ProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+
+public class ScreenCaptureProtocolCodecFactory implements ProtocolCodecFactory {
+    private ProtocolEncoder encoder;
+    private ProtocolDecoder decoder;
+
+    public ScreenCaptureProtocolCodecFactory() {
+            encoder = new NullProtocolEncoder();
+            //decoder = new ScreenCaptureProtocolDecoder();
+            decoder = new BlockStreamProtocolDecoder();
+    }
+
+    public ProtocolEncoder getEncoder(IoSession ioSession) throws Exception {
+        return encoder;
+    }
+
+    public ProtocolDecoder getDecoder(IoSession ioSession) throws Exception {
+        return decoder;
+    }
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/ScreenCaptureProtocolDecoder.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/ScreenCaptureProtocolDecoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..5df06afd29215f72b818effa5f49d2ca0e413135
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/socket/ScreenCaptureProtocolDecoder.java
@@ -0,0 +1,233 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.socket;
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+
+import javax.imageio.ImageIO;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolDecoderOutput;
+import org.bigbluebutton.deskshare.server.CaptureStartEvent;
+import org.bigbluebutton.deskshare.server.CaptureUpdateEvent;
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+
+public class ScreenCaptureProtocolDecoder extends CumulativeProtocolDecoder {
+	final private Logger log = Red5LoggerFactory.getLogger(ScreenCaptureProtocolDecoder.class, "deskshare");
+	
+    private static final String ROOM = "ROOM";
+    private static final String VIDEO_INFO = "VIDEO_INFO";
+
+    private static final byte CAPTURE_START_EVENT = 0;
+    private static final byte CAPTURE_UPDATE_EVENT = 1;
+    private static final byte CAPTURE_END_EVENT = 2;
+    
+    private static final String EVENT_TYPE = "EVENT_TYPE";
+    private static final String IS_KEY_FRAME = "IS_KEY_FRAME";
+    private static final String ENCODED_DATA = "ENCODED_DATA";
+    
+    private static final int HEADER_LENGTH = 6;
+    
+    private long receiveStart;
+    
+    protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
+     	
+    	if (session.containsAttribute(EVENT_TYPE)) {
+    		
+    		Integer eventType = (Integer) session.getAttribute(EVENT_TYPE);
+    		
+    		boolean receiveDone = false;
+    		
+    		// Now we know which event we are dealing with.
+    		switch (eventType.intValue()) {
+	    		case CAPTURE_START_EVENT:
+	    			receiveDone = decodeCaptureStartEvent(session, in, out);
+	    			break;
+	    		case CAPTURE_UPDATE_EVENT:
+	    			receiveDone = decodeCaptureUpdateEvent(session, in, out);
+	    			break;
+	    		case CAPTURE_END_EVENT: 
+	  //  			decodeCaptureEnd(session, in, out);
+	    			break;
+    		}
+    		
+    		if (receiveDone) {
+    			long receiveComplete = System.currentTimeMillis();
+    			System.out.println("Receive took " + (receiveComplete - receiveStart) + "ms.");
+    		}
+    		
+    	} else {
+    		// Let's work with a buffer that contains header and the event and room
+    		// ten (10) should be enough since header plus event is 8 bytes
+    		if (in.remaining() < 10) return false;
+    		
+    		byte[] header = new byte[HEADER_LENGTH]; 
+    		in.get(header, 0, HEADER_LENGTH);
+    		int event = in.get();    		
+    		System.out.println("Received " + header + " type " + event);    		
+    		session.setAttribute(EVENT_TYPE, new Integer(event));
+    		receiveStart = System.currentTimeMillis();
+    		return true;
+
+    	}
+    	return false;
+    }
+        
+    private boolean decodeCaptureStartEvent(IoSession session, IoBuffer in, ProtocolDecoderOutput out) {   	
+    	if (session.containsAttribute(ROOM)) {
+    		if (decodeVideoInfo(session, in)) {
+    			sendCaptureStartMessage(session, out);
+    			return true; 
+    		}    		
+    	} else {
+    		decodeRoom(session, in);
+    	}
+    	return false;
+    }
+    
+    private void decodeRoom(IoSession session, IoBuffer in) {
+    	if (in.remaining() < 200) return;
+    	
+    	int len = in.getInt();
+    	String room = decodeString(len, in);
+    	if (room != "") {
+    		System.out.println("Decoded ROOM " + room);
+    		session.setAttribute(ROOM, room);
+    	}
+    }
+    
+    private boolean decodeVideoInfo(IoSession session, IoBuffer in) {
+    	if (in.remaining() < 200) return false;
+    	
+    	int len = in.getInt();
+    	String videoInfo = decodeString(len, in);
+    	if (videoInfo != "") {
+    		System.out.println("Decoded VIDEO_INFO " + videoInfo);
+    		session.setAttribute(VIDEO_INFO, videoInfo);
+    		return true;
+    	}
+    	return false;
+    }
+    
+    private String decodeString(int length, IoBuffer in) {
+    	try {
+    		if (in.remaining() >= length) {
+    			return in.getString(length, Charset.forName( "UTF-8" ).newDecoder());
+    		}
+		} catch (CharacterCodingException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+		return "";
+    }
+    
+    private void sendCaptureStartMessage(IoSession session, ProtocolDecoderOutput out) {
+		String room = (String) session.getAttribute(ROOM);
+		String videoInfo = (String) session.getAttribute(VIDEO_INFO);
+		log.debug("Room " + room + " videoInfo " + videoInfo);
+		System.out.println("Room " + room + " videoInfo " + videoInfo);
+		//Get the screen dimensions, i.e. the resolution of the video we need to create
+		String[] screenDimensions = videoInfo.split("x");
+		int width = Integer.parseInt(screenDimensions[0]);
+		int height = Integer.parseInt(screenDimensions[1]);
+		
+		CaptureStartEvent cse = new CaptureStartEvent(room, width, height); 
+		out.write(cse);
+		reset(session);
+    }
+    
+    private boolean decodeCaptureUpdateEvent(IoSession session, IoBuffer in, ProtocolDecoderOutput out) {
+    	if (session.containsAttribute(ROOM)) {
+    		if (decodeScreenVideoData(session, in)) {
+    			sendCaptureUpdateEvent(session, out);
+    			return true; 
+    		}    		
+    	} else {
+    		decodeRoom(session, in);
+    	}
+    	return false;
+    }
+    
+    private boolean decodeScreenVideoData(IoSession session, IoBuffer in) {
+    	int start = in.position();
+    	
+    	byte isKeyFrame = in.get();
+    	int length = in.getInt();
+    	
+    	if (in.remaining() < length) {
+    		in.position(start);
+    		return false;
+    	}
+    	
+    	byte[] data = new byte[length];
+    		
+    	in.get(data, 0, length);
+    	
+    	boolean keyFrame = false;
+    	
+    	if (isKeyFrame == 1) {
+    		keyFrame = true;
+    	}
+    	
+    	session.setAttribute(IS_KEY_FRAME, new Boolean(keyFrame));
+    	session.setAttribute(ENCODED_DATA, data);
+    	
+    	return true;    	
+    }
+
+    
+    private void sendCaptureUpdateEvent(IoSession session, ProtocolDecoderOutput out) {
+
+    	String room = (String) session.getAttribute(ROOM);
+		Boolean isKeyFrame = (Boolean) session.getAttribute(IS_KEY_FRAME);
+		byte[] data = (byte[]) session.getAttribute(ENCODED_DATA);
+		
+		IoBuffer buffer = IoBuffer.allocate(data.length, false);
+		buffer.put(data);
+		
+		/* Set the marker back to zero position so that "gets" start from the beginning.
+		 * Otherwise, you get BufferUnderFlowException.
+		 */		
+		buffer.rewind();
+		
+		System.out.println("Room " + room + " keyFrame " + isKeyFrame 
+				+ " data size " + data.length + " buffer size " + buffer.remaining());
+		CaptureUpdateEvent cse = new CaptureUpdateEvent(room, buffer);
+		out.write(cse);
+		reset(session);
+    }
+        
+    private void reset(IoSession session) {
+    	session.removeAttribute(EVENT_TYPE);
+    	session.removeAttribute(ROOM);
+    	session.removeAttribute(IS_KEY_FRAME);
+    	session.removeAttribute(ENCODED_DATA);
+    }
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/streamer/DeskShareStream.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/streamer/DeskShareStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..b589536b3c9c643230668c602790d264368a5ade
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/streamer/DeskShareStream.java
@@ -0,0 +1,180 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.streamer;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.bigbluebutton.deskshare.server.CaptureUpdateEvent;
+import org.bigbluebutton.deskshare.server.IDeskShareStream;
+import org.bigbluebutton.deskshare.server.ScreenVideoBroadcastStream;
+import org.bigbluebutton.deskshare.server.session.ScreenVideoFrame;
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.IContext;
+import org.red5.server.api.IScope;
+import org.red5.server.net.rtmp.event.VideoData;
+import org.red5.server.stream.BroadcastScope;
+import org.red5.server.stream.IBroadcastScope;
+import org.red5.server.stream.IProviderService;
+import org.slf4j.Logger;
+
+
+/**
+ * The DeskShareStream class publishes captured video to a red5 stream.
+ * @author Snap
+ *
+ */
+public class DeskShareStream  implements IDeskShareStream {
+	final private Logger log = Red5LoggerFactory.getLogger(DeskShareStream.class, "deskshare");
+	
+	private BlockingQueue<CaptureUpdateEvent> screenQueue = new LinkedBlockingQueue<CaptureUpdateEvent>(10);
+	private final Executor exec = Executors.newSingleThreadExecutor();
+	private Runnable capturedScreenSender;
+	private volatile boolean sendCapturedScreen = false;
+	
+	private ScreenVideoBroadcastStream broadcastStream;
+	
+	private long timestamp = 0, frameNumber = 0;
+	private int width, height, timestampBase;
+	private String outStreamName;
+	private IScope scope;
+	
+	public static final int LARGER_DIMENSION = 1280;
+
+	
+	/**
+	 * The default constructor
+	 * The stream which gets published by the streamer has the same name as the scope. One stream allowed per room
+	 */
+	public DeskShareStream(IScope scope, String streamName, int width, int height) {
+		this.scope = scope;
+		scope.setName(streamName);
+		this.outStreamName = streamName;
+		this.width = width;
+		this.height = height;		
+	}
+	
+	public void stop() {
+		sendCapturedScreen = false;
+		streamEnded();
+	}
+	
+	public void start() {
+		startPublishing(scope);
+		sendCapturedScreen = true;
+		System.out.println("DeskShareStream Starting stream " + outStreamName);
+		capturedScreenSender = new Runnable() {
+			public void run() {
+				while (sendCapturedScreen) {
+					try {
+//						System.out.println("ScreenQueue size " + screenQueue.size());						
+						CaptureUpdateEvent newScreen = screenQueue.take();
+						if (screenQueue.size() > 9) screenQueue.clear();
+						sendCapturedScreen(newScreen);
+					} catch (InterruptedException e) {
+						log.warn("InterruptedExeption while taking event.");
+					}
+				}
+			}
+		};
+		exec.execute(capturedScreenSender);
+	}
+	
+	public void stream(ScreenVideoFrame frame) {
+		
+		
+	}
+	
+	public void accept(CaptureUpdateEvent event) {
+		// Make a copy so we can process safely on our own thread.
+		CaptureUpdateEvent copy = CaptureUpdateEvent.copy(event);
+		try {
+			screenQueue.put(copy);
+		} catch (InterruptedException e) {
+			log.warn("InterruptedException while putting event into queue.");
+		}
+	}
+	
+	private void sendCapturedScreen(CaptureUpdateEvent event) {
+		long now = System.currentTimeMillis();
+		if ((now - event.getTimestamp()) > 3000) {
+			System.out.println("Discarding stale update event");
+			return;
+		}
+		
+		long startRx = System.currentTimeMillis();		
+//		System.out.println("Sending " + event.getData().remaining() + " " 
+//				+ event.getData().capacity() + " " + event.getData().position() + " to stream");
+		VideoData data = new VideoData(event.getData());
+		broadcastStream.dispatchEvent(data);
+		data.release();
+		long completeRx = System.currentTimeMillis();
+//		System.out.println("Send took " + (completeRx - startRx) + "ms.");
+	}
+
+	private void streamEnded() {
+		broadcastStream.stop();
+	    broadcastStream.close();
+	    log.debug("stopping and closing stream {}", outStreamName);
+	}
+	
+	/**
+	 * Starts outputting captured video to a red5 stream
+	 * @param aScope
+	 */
+	synchronized private void startPublishing(IScope aScope){
+		System.out.println("started publishing stream in " + aScope.getName());
+
+		broadcastStream = new ScreenVideoBroadcastStream(outStreamName);
+		broadcastStream.setPublishedName(outStreamName);
+		broadcastStream.setScope(aScope);
+		
+		IContext context = aScope.getContext();
+		
+		IProviderService providerService = (IProviderService) context.getBean(IProviderService.BEAN_NAME);
+		if (providerService.registerBroadcastStream(aScope, outStreamName, broadcastStream)){
+			IBroadcastScope bScope = (BroadcastScope) providerService.getLiveProviderInput(aScope, outStreamName, true);
+			
+			bScope.setAttribute(IBroadcastScope.STREAM_ATTRIBUTE, broadcastStream);
+		} else{
+			log.error("could not register broadcast stream");
+			throw new RuntimeException("could not register broadcast stream");
+		}
+	    
+	    broadcastStream.start();
+	}
+		
+	public int getWidth() {
+		return width;
+	}
+	
+	public int getHeight() {
+		return height;
+	}
+	
+	public IScope getScope() {
+		return scope;
+	}
+
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/streamer/FlvEncodeException.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/streamer/FlvEncodeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d3458412bf86b154cb7c49ef04f60e49553d111
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/streamer/FlvEncodeException.java
@@ -0,0 +1,31 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.streamer;
+
+public class FlvEncodeException extends Exception {
+
+	private static final long serialVersionUID = -3377474098350652011L;
+
+	public FlvEncodeException(String message) {
+		super(message);
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/streamer/FlvStreamToFile.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/streamer/FlvStreamToFile.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ccb3e6c6b4194153feb9601497003f085b89431
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/streamer/FlvStreamToFile.java
@@ -0,0 +1,135 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.streamer;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.bigbluebutton.deskshare.server.CaptureUpdateEvent;
+import org.bigbluebutton.deskshare.server.IDeskShareStream;
+import org.bigbluebutton.deskshare.server.session.ScreenVideoFrame;
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.IScope;
+import org.slf4j.Logger;
+
+public class FlvStreamToFile implements IDeskShareStream {
+	final private Logger log = Red5LoggerFactory.getLogger(FlvStreamToFile.class, "deskshare");
+	private BlockingQueue<CaptureUpdateEvent> screenQueue = new LinkedBlockingQueue<CaptureUpdateEvent>();
+	private final Executor exec = Executors.newSingleThreadExecutor();
+	private Runnable capturedScreenSender;
+	private volatile boolean sendCapturedScreen = false;
+
+	private FileOutputStream fo;
+	private ScreenVideoFlvEncoder svf = new ScreenVideoFlvEncoder();
+	
+	private String flvFilename = "/tmp/screenvideo.flv";
+	
+	public void accept(CaptureUpdateEvent event) {
+		// Make a copy so we can process safely on our own thread.
+		CaptureUpdateEvent copy = CaptureUpdateEvent.copy(event);
+		try {
+			screenQueue.put(copy);
+		} catch (InterruptedException e) {
+			log.warn("InterruptedException while putting event into queue.");
+		}
+	}
+
+	public int getHeight() {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+
+	public IScope getScope() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	public int getWidth() {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+
+	public void stream(ScreenVideoFrame frame) {}
+	
+	public void start() {
+		try {
+			fo = new FileOutputStream(flvFilename);
+			fo.write(svf.encodeHeader());
+		} catch (FileNotFoundException e1) {
+			// TODO Auto-generated catch block
+			e1.printStackTrace();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+		sendCapturedScreen = true;
+		System.out.println("Starting stream");
+		capturedScreenSender = new Runnable() {
+			public void run() {
+				while (sendCapturedScreen) {
+					try {
+						System.out.println("ScreenQueue size " + screenQueue.size());
+						CaptureUpdateEvent newScreen = screenQueue.take();
+						sendCapturedScreen(newScreen);
+					} catch (InterruptedException e) {
+						log.warn("InterruptedExeption while taking event.");
+					}
+				}
+			}
+		};
+		exec.execute(capturedScreenSender);
+	}
+
+	private void sendCapturedScreen(CaptureUpdateEvent event) {
+		System.out.println("Sending screen captured - built aug 20 12:39PM");
+		try {
+			byte[] data = svf.encodeFlvData(event.getData().array());
+			fo.write(data);
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (FlvEncodeException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}		
+	}
+	
+	public void stop() {
+    	try {
+    		System.out.println("Closing stream");
+			fo.close();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
+	public void setFlvFilename(String filename) {
+		flvFilename = filename;
+	}
+}
diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/streamer/ScreenVideoFlvEncoder.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/streamer/ScreenVideoFlvEncoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..6bd97a5a8eed83b583ef58dad0f3e28fd1301863
--- /dev/null
+++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/streamer/ScreenVideoFlvEncoder.java
@@ -0,0 +1,106 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.server.streamer;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public final class ScreenVideoFlvEncoder {
+	private final static byte[] flvHeader = {'F','L','V',0x01,0x01,0x00,0x00,0x00,0x09};
+	private final static byte[] videoTagType = {0x09};
+	private final static byte[] streamId = {0, 0, 0};
+	private long startTimestamp = 0;
+	private boolean firstTag = true;
+	
+	private static byte FLV_TAG_HEADER_SIZE = 11;
+	
+	ByteArrayOutputStream flvDataStream = new ByteArrayOutputStream();
+	
+	public byte[] encodeHeader() {
+		byte[] prevTagSize =  encodePreviousTagSize(0);
+		byte[] header = new byte[flvHeader.length + prevTagSize.length];
+		
+		System.arraycopy(flvHeader, 0, header, 0, flvHeader.length);
+		System.arraycopy(prevTagSize, 0, header, flvHeader.length, prevTagSize.length);
+		return header;
+	}
+	
+    private byte[] encodePreviousTagSize(long previousTagSize) {    	
+    	int byte1 = (int)previousTagSize >> 24;
+    	int byte2 = (int)previousTagSize >> 16;
+    	int byte3 = (int)previousTagSize >> 8;
+    	int byte4 = (int)previousTagSize & 0xff;
+    	
+    	return new byte[] {(byte)byte1, (byte)byte2, (byte)byte3, (byte)byte4};
+    }
+    
+    public byte[] encodeFlvData (byte[] screenVideoData) throws FlvEncodeException {
+
+        byte[] flvData;
+		try {
+			flvData = encodeFlvTag(screenVideoData);
+		} catch (IOException e) {
+			throw new FlvEncodeException("Failed to encode FLV data.");
+		}   
+        return flvData;
+	}
+	
+	private byte[] encodeFlvTag(byte[] videoData) throws IOException {   
+
+		flvDataStream.reset();
+		
+		flvDataStream.write(videoTagType);
+		flvDataStream.write(encodeDataSize(videoData.length));
+	    flvDataStream.write(encodeTimestamp());
+	    flvDataStream.write(streamId);
+	    flvDataStream.write(videoData);
+	    flvDataStream.write(encodePreviousTagSize(FLV_TAG_HEADER_SIZE + videoData.length));
+	    
+	    return flvDataStream.toByteArray();
+	}	
+	        
+    private byte[] encodeDataSize(int size) {
+    	int byte1 = (size >> 16);
+    	int byte2 = (size >> 8);
+    	int byte3 = (size & 0x0ff);
+    	
+    	return new byte[] {(byte) byte1, (byte) byte2, (byte) byte3};
+    }
+    
+    private byte[] encodeTimestamp() {
+    	long now = System.currentTimeMillis();
+    	
+    	if (firstTag) {
+    		startTimestamp = now;
+    		firstTag = false;
+    	}
+    	
+    	long elapsed = now - startTimestamp;
+    	
+    	int byte1 = (int)(elapsed & 0xff0000) >> 16;
+    	int byte2 = (int)(elapsed & 0xff00) >> 8;
+    	int byte3 = (int)(elapsed & 0xff);
+    	int tsExtended = ((int)elapsed & 0xff000000) >> 24;
+    	
+    	return new byte[] {(byte) byte1, (byte) byte2, (byte) byte3, (byte) tsExtended};    		    	
+    }   
+}
diff --git a/deskshare/app/src/main/webapp/WEB-INF/logback-deskshare.xml b/deskshare/app/src/main/webapp/WEB-INF/logback-deskshare.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d8997fd3546e70bd68b9aad57e89983d4e8ff677
--- /dev/null
+++ b/deskshare/app/src/main/webapp/WEB-INF/logback-deskshare.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+	<appender name="DESKSHARE" class="ch.qos.logback.core.FileAppender">
+		<File>log/deskshare.log</File>
+		<Append>false</Append>
+		<Encoding>UTF-8</Encoding>
+		<BufferedIO>false</BufferedIO>
+		<ImmediateFlush>true</ImmediateFlush>
+		<layout class="ch.qos.logback.classic.PatternLayout">
+			<Pattern>
+				%date [%thread] %-5level %logger{35} - %msg%n
+			</Pattern>
+		</layout>
+	</appender>
+	<root>
+		<level value="DEBUG" />	
+		<appender-ref ref="DESKSHARE" />
+	</root>		
+</configuration>
diff --git a/deskshare/app/src/main/webapp/WEB-INF/red5-web.properties b/deskshare/app/src/main/webapp/WEB-INF/red5-web.properties
new file mode 100644
index 0000000000000000000000000000000000000000..5684bccda86d48ee89b165a3aa0fb67653c9c34d
--- /dev/null
+++ b/deskshare/app/src/main/webapp/WEB-INF/red5-web.properties
@@ -0,0 +1,2 @@
+webapp.contextPath=/deskShare
+webapp.virtualHosts=*, localhost, localhost:8088, 127.0.0.1:8088
diff --git a/deskshare/app/src/main/webapp/WEB-INF/red5-web.xml b/deskshare/app/src/main/webapp/WEB-INF/red5-web.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d674a6ebab92c64ff3bfcb1f16ddb040e1de2462
--- /dev/null
+++ b/deskshare/app/src/main/webapp/WEB-INF/red5-web.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:lang="http://www.springframework.org/schema/lang"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+                           http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">
+
+	<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+	    <property name="location" value="/WEB-INF/red5-web.properties" />
+	</bean>
+
+	<bean id="web.context" class="org.red5.server.Context"
+		autowire="byType" />
+
+	<bean id="web.scope" class="org.red5.server.WebScope"
+		 init-method="register">
+		<property name="server" ref="red5.server" />
+		<property name="parent" ref="global.scope" />
+		<property name="context" ref="web.context" />
+		<property name="handler" ref="web.handler" />
+		<property name="contextPath" value="${webapp.contextPath}" />
+		<property name="virtualHosts" value="${webapp.virtualHosts}" />
+	</bean>
+
+  	<bean id="web.handler"  class="org.bigbluebutton.deskshare.server.DeskShareApplication">
+  		<property name="deskShareServer" ref="deskShareServer"/>
+  	</bean>	
+  	
+  	<bean id="deskshare.service" class="org.bigbluebutton.deskshare.server.DeskShareService">
+  		<property name="streamerGateway" ref="streamerGateway"/>
+  	</bean>
+  	
+	<bean id="deskShareServer" class="org.bigbluebutton.deskshare.server.socket.DeskShareServer" >
+		<property name="screenCaptureHandler" ref="screenCaptureHandler"/>
+	</bean>
+	
+    <!-- The IoHandler implementation -->
+    <bean id="screenCaptureHandler" class="org.bigbluebutton.deskshare.server.socket.BlockStreamEventMessageHandler">
+    	<property name="sessionManager" ref="sessionManager"/>
+    </bean>
+  	
+  	<bean id="sessionManager" class="org.bigbluebutton.deskshare.server.session.SessionManager">
+    	<property name="frameStreamer" ref="frameStreamer"/>
+    </bean>
+    
+    <bean id="frameStreamer" class="org.bigbluebutton.deskshare.server.session.FrameStreamer">
+    	<property name="frameStreamerGateway" ref="streamerGateway"/>
+    </bean>
+    
+  	<bean id="streamerGateway" class="org.bigbluebutton.deskshare.server.FrameStreamerGateway">
+  		<property name="streamFactory" ref="streamFactory"/>
+  		<property name="deskShareApplication" ref="web.handler"/>
+  	</bean>
+  	
+  	<bean id="streamFactory" class="org.bigbluebutton.deskshare.server.FrameStreamFactory">
+  		<property name="deskShareApplication" ref="web.handler"/>
+  	</bean>
+  	    
+</beans>
diff --git a/deskshare/app/src/main/webapp/WEB-INF/tunnel-servlet.xml b/deskshare/app/src/main/webapp/WEB-INF/tunnel-servlet.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6b5352c0e2a97ad2eadfe848004b9cacafdce800
--- /dev/null
+++ b/deskshare/app/src/main/webapp/WEB-INF/tunnel-servlet.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:lang="http://www.springframework.org/schema/lang"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+                           http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">
+
+  	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
+
+	<bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
+		<property name="defaultHandler" ref="httpTunnelController"/>
+	</bean>
+
+	<bean id="tunnelController" class="org.bigbluebutton.deskshare.server.servlet.TunnelController">
+		<property name="methodNameResolver">
+			<bean class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
+				<property name="mappings">
+					<props>
+						<prop key="/screenCapture">screenCaptureHandler</prop>
+					</props>
+				</property>
+			</bean>
+		</property>
+	</bean>
+
+	<bean id="httpTunnelController" class="org.bigbluebutton.deskshare.server.servlet.HttpTunnelStreamController">
+		<property name="methodNameResolver">
+			<bean class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
+				<property name="mappings">
+					<props>
+						<prop key="/screenCapture">screenCaptureHandler</prop>
+					</props>
+				</property>
+			</bean>
+		</property>
+	</bean>
+</beans>
\ No newline at end of file
diff --git a/deskshare/app/src/main/webapp/WEB-INF/web.xml b/deskshare/app/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000000000000000000000000000000000..081a2a861f4b0eeb13e82f5abdbec97cae9f0ec7
--- /dev/null
+++ b/deskshare/app/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app 
+   xmlns="http://java.sun.com/xml/ns/j2ee" 
+   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" 
+   version="2.4"> 
+
+    <display-name>deskShare</display-name>
+	
+	<context-param>
+		<param-name>webAppRootKey</param-name>
+		<param-value>/deskshare</param-value>
+	</context-param>
+ 
+    <listener>
+        <listener-class>org.red5.logging.ContextLoggingListener</listener-class>
+    </listener>
+    
+    <filter>
+        <filter-name>LoggerContextFilter</filter-name>
+        <filter-class>org.red5.logging.LoggerContextFilter</filter-class>
+    </filter>
+    
+    <filter-mapping>
+        <filter-name>LoggerContextFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+	<!--listener>
+		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+	</listener-->
+	    
+    <servlet>
+        <servlet-name>tunnel</servlet-name>
+        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <!-- maps the sample dispatcher to *.form -->
+    <servlet-mapping>
+        <servlet-name>tunnel</servlet-name>
+        <url-pattern>/tunnel/*</url-pattern>
+    </servlet-mapping>
+	    
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Forbidden</web-resource-name>
+            <url-pattern>/streams/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint/>
+    </security-constraint>
+    
+</web-app>
diff --git a/deskshare/applet/build.gradle b/deskshare/applet/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..80fac877811fbc714c152d39ca47fefcd87d4cad
--- /dev/null
+++ b/deskshare/applet/build.gradle
@@ -0,0 +1,25 @@
+ant.importBuild 'build.xml'
+
+archivesBaseName = 'bbb-deskshare-applet' 
+
+dependencies {	   
+	testRuntime 'org.testng:testng:5.8@jar'  
+	compile project(':common')
+	compile 'net/jcip:jcip-annotations:1.0@jar'
+}
+
+test {
+    useTestNG()
+}
+
+
+jar.doFirst {
+   println '''
+	/**
+	* Combine the common classes into the applet's jar because we
+	* do not want to sign and manage 2 jar files.
+	**/'''
+
+   jar.merge('../common/build/libs/bbb-deskshare-common-0.62.jar')
+}
+
diff --git a/deskshare/applet/build.xml b/deskshare/applet/build.xml
new file mode 100644
index 0000000000000000000000000000000000000000..001eecd42d20959719c142f4ff5cbe751badd83d
--- /dev/null
+++ b/deskshare/applet/build.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" ?>
+<project name="bbb-deskshare-applet" basedir=".">
+	
+	<!-- How to sign the applet. From Ant in Action book -->
+<!--
+	<target name="getPassword" depends="initSecurity" description="Prompts for password for keystore">
+		<input addproperty="keystore.password" >password for keystore:</input>
+		<echo level="verbose">password = ${keystore.password}</echo>
+	</target>
+	
+	<target name="initSecurity">
+		<property name="keystore.dir" location="${user.home}/.secret" />
+		<mkdir dir="${keystore.dir}" />
+		<chmod file="${keystore.dir}" perm="700"/>
+		<property name="keystore" location="${keystore.dir}/local.keystore" />
+		<property name="keystore.properties" location="${keystore.dir}/keystore.properties" />
+		<property name="keystore.alias" value="code.signer"/>
+	</target>
+	
+	<target name="createSigningKey" depends="getPassword">
+		<genkey	alias="${keystore.alias}" keystore="${keystore}" storepass="${keystore.password}" validity="366" >
+			<dname>
+				<param name="CN" value="BigBlueButton"/>
+				<param name="OU" value="BigBlueButton Project"/>
+				<param name="O" value="BigBlueButton"/>
+				<param name="C" value="CA"/>
+			</dname>
+		</genkey>
+	</target>
+	
+	<target name="signJar" depends="getPassword">
+		<signjar jar="build/libs/bbb-deskshare-applet-0.62.jar"
+			alias="${keystore.alias}"
+			keystore="${keystore}"
+			storepass="${keystore.password}" />
+	</target>
+-->
+	<!-- How to sign the applet. From Ant in Action book -->
+
+	<target name="get-password" depends="init-security" description="Prompts for password for keystore">
+		<input addproperty="keystore.password" >password for keystore:</input>
+		<echo level="verbose">password = ${keystore.password}</echo>
+	</target>
+	
+	<target name="init-security">
+		<property name="keystore.dir" location="${user.home}/.secret" />
+		<mkdir dir="${keystore.dir}" />
+		<chmod file="${keystore.dir}" perm="700"/>
+		<property name="keystore"
+			location="${keystore.dir}/local.keystore" />
+		<property file="${keystore.dir}/keystore.properties" />
+		<property name="keystore.alias" value="code.signer"/>
+	</target>
+	
+	<target name="create-signing-key" depends="get-password">
+		<genkey	alias="${keystore.alias}" keystore="${keystore}" storepass="${keystore.password}" validity="366" >
+			<dname>
+				<param name="CN" value="BigBlueButton"/>
+				<param name="OU" value="BigBlueButton Project"/>
+				<param name="O" value="BigBlueButton"/>
+				<param name="C" value="CA"/>
+			</dname>
+		</genkey>
+	</target>
+	
+	<target name="sign-jar" depends="get-password">
+		<signjar jar="build/libs/bbb-deskshare-applet-0.62.jar"
+			alias="${keystore.alias}"
+			keystore="${keystore}"
+			storepass="${keystore.password}" />
+	</target>
+
+</project>
diff --git a/deskshare/applet/src/main/java/com/myjavatools/web/ClientHttpRequest.java b/deskshare/applet/src/main/java/com/myjavatools/web/ClientHttpRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1dff7c9f7e0aff3b70601d801cd3d3422aa369d9
--- /dev/null
+++ b/deskshare/applet/src/main/java/com/myjavatools/web/ClientHttpRequest.java
@@ -0,0 +1,492 @@
+package com.myjavatools.web;
+
+import java.net.URLConnection;
+import java.net.URL;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.io.File;
+import java.io.InputStream;
+import java.util.Random;
+import java.io.OutputStream;
+import java.io.FileInputStream;
+import java.util.Iterator;
+
+/**
+ * <p>Title: Client HTTP Request class</p>
+ * <p>Description: this class helps to send POST HTTP requests with various form data,
+ * including files. Cookies can be added to be included in the request.</p>
+ *
+ * @author Vlad Patryshev
+ * @version 1.0
+ */
+public class ClientHttpRequest {
+  URLConnection connection;
+  OutputStream os = null;
+  Map cookies = new HashMap();
+
+  protected void connect() throws IOException {
+    if (os == null) os = connection.getOutputStream();
+  }
+
+  protected void write(char c) throws IOException {
+    connect();
+    os.write(c);
+  }
+
+  protected void write(String s) throws IOException {
+    connect();
+    os.write(s.getBytes());
+  }
+
+  protected void newline() throws IOException {
+    connect();
+    write("\r\n");
+  }
+
+  protected void writeln(String s) throws IOException {
+    connect();
+    write(s);
+    newline();
+  }
+
+  private static Random random = new Random();
+
+  protected static String randomString() {
+    return Long.toString(random.nextLong(), 36);
+  }
+
+  String boundary = "---------------------------" + randomString() + randomString() + randomString();
+
+  private void boundary() throws IOException {
+    write("--");
+    write(boundary);
+  }
+
+  /**
+   * Creates a new multipart POST HTTP request on a freshly opened URLConnection
+   *
+   * @param connection an already open URL connection
+   * @throws IOException
+   */
+  public ClientHttpRequest(URLConnection connection) throws IOException {
+    this.connection = connection;
+    connection.setDoOutput(true);
+    connection.setRequestProperty("Content-Type",
+                                  "multipart/form-data; boundary=" + boundary);
+  }
+
+  /**
+   * Creates a new multipart POST HTTP request for a specified URL
+   *
+   * @param url the URL to send request to
+   * @throws IOException
+   */
+  public ClientHttpRequest(URL url) throws IOException {
+    this(url.openConnection());
+  }
+
+  /**
+   * Creates a new multipart POST HTTP request for a specified URL string
+   *
+   * @param urlString the string representation of the URL to send request to
+   * @throws IOException
+   */
+  public ClientHttpRequest(String urlString) throws IOException {
+    this(new URL(urlString));
+  }
+
+
+  private void postCookies() {
+    StringBuffer cookieList = new StringBuffer();
+
+    for (Iterator i = cookies.entrySet().iterator(); i.hasNext();) {
+      Map.Entry entry = (Map.Entry)(i.next());
+      cookieList.append(entry.getKey().toString() + "=" + entry.getValue());
+
+      if (i.hasNext()) {
+        cookieList.append("; ");
+      }
+    }
+    if (cookieList.length() > 0) {
+      connection.setRequestProperty("Cookie", cookieList.toString());
+    }
+  }
+
+  /**
+   * adds a cookie to the requst
+   * @param name cookie name
+   * @param value cookie value
+   * @throws IOException
+   */
+  public void setCookie(String name, String value) throws IOException {
+    cookies.put(name, value);
+  }
+
+  /**
+   * adds cookies to the request
+   * @param cookies the cookie "name-to-value" map
+   * @throws IOException
+   */
+  public void setCookies(Map cookies) throws IOException {
+    if (cookies == null) return;
+    this.cookies.putAll(cookies);
+  }
+
+  /**
+   * adds cookies to the request
+   * @param cookies array of cookie names and values (cookies[2*i] is a name, cookies[2*i + 1] is a value)
+   * @throws IOException
+   */
+  public void setCookies(String[] cookies) throws IOException {
+    if (cookies == null) return;
+    for (int i = 0; i < cookies.length - 1; i+=2) {
+      setCookie(cookies[i], cookies[i+1]);
+    }
+  }
+
+  private void writeName(String name) throws IOException {
+    newline();
+    write("Content-Disposition: form-data; name=\"");
+    write(name);
+    write('"');
+  }
+
+  /**
+   * adds a string parameter to the request
+   * @param name parameter name
+   * @param value parameter value
+   * @throws IOException
+   */
+  public void setParameter(String name, String value) throws IOException {
+    boundary();
+    writeName(name);
+    newline(); newline();
+    writeln(value);
+  }
+
+  private static void pipe(InputStream in, OutputStream out) throws IOException {
+    byte[] buf = new byte[500000];
+    int nread;
+    int navailable;
+    int total = 0;
+    synchronized (in) {
+      while((nread = in.read(buf, 0, buf.length)) >= 0) {
+        out.write(buf, 0, nread);
+        total += nread;
+      }
+    }
+    out.flush();
+    buf = null;
+  }
+
+  /**
+   * adds a file parameter to the request
+   * @param name parameter name
+   * @param filename the name of the file
+   * @param is input stream to read the contents of the file from
+   * @throws IOException
+   */
+  public void setParameter(String name, String filename, InputStream is) throws IOException {
+    boundary();
+    writeName(name);
+    write("; filename=\"");
+    write(filename);
+    write('"');
+    newline();
+    write("Content-Type: ");
+    String type = connection.guessContentTypeFromName(filename);
+    if (type == null) type = "application/octet-stream";
+    writeln(type);
+    newline();
+    pipe(is, os);
+    newline();
+  }
+
+  /**
+   * adds a file parameter to the request
+   * @param name parameter name
+   * @param file the file to upload
+   * @throws IOException
+   */
+  public void setParameter(String name, File file) throws IOException {
+    setParameter(name, file.getPath(), new FileInputStream(file));
+  }
+
+  /**
+   * adds a parameter to the request; if the parameter is a File, the file is uploaded, otherwise the string value of the parameter is passed in the request
+   * @param name parameter name
+   * @param object parameter value, a File or anything else that can be stringified
+   * @throws IOException
+   */
+  public void setParameter(String name, Object object) throws IOException {
+    if (object instanceof File) {
+      setParameter(name, (File) object);
+    } else {
+      setParameter(name, object.toString());
+    }
+  }
+
+  /**
+   * adds parameters to the request
+   * @param parameters "name-to-value" map of parameters; if a value is a file, the file is uploaded, otherwise it is stringified and sent in the request
+   * @throws IOException
+   */
+  public void setParameters(Map parameters) throws IOException {
+    if (parameters == null) return;
+    for (Iterator i = parameters.entrySet().iterator(); i.hasNext();) {
+      Map.Entry entry = (Map.Entry)i.next();
+      setParameter(entry.getKey().toString(), entry.getValue());
+    }
+  }
+
+  /**
+   * adds parameters to the request
+   * @param parameters array of parameter names and values (parameters[2*i] is a name, parameters[2*i + 1] is a value); if a value is a file, the file is uploaded, otherwise it is stringified and sent in the request
+   * @throws IOException
+   */
+  public void setParameters(Object[] parameters) throws IOException {
+    if (parameters == null) return;
+    for (int i = 0; i < parameters.length - 1; i+=2) {
+      setParameter(parameters[i].toString(), parameters[i+1]);
+    }
+  }
+
+  /**
+   * posts the requests to the server, with all the cookies and parameters that were added
+   * @return input stream with the server response
+   * @throws IOException
+   */
+  public InputStream post() throws IOException {
+    boundary();
+    writeln("--");
+    os.close();
+    return connection.getInputStream();
+  }
+
+  /**
+   * posts the requests to the server, with all the cookies and parameters that were added before (if any), and with parameters that are passed in the argument
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameters
+   */
+  public InputStream post(Map parameters) throws IOException {
+    setParameters(parameters);
+    return post();
+  }
+
+  /**
+   * posts the requests to the server, with all the cookies and parameters that were added before (if any), and with parameters that are passed in the argument
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameters
+   */
+  public InputStream post(Object[] parameters) throws IOException {
+    setParameters(parameters);
+    return post();
+  }
+
+  /**
+   * posts the requests to the server, with all the cookies and parameters that were added before (if any), and with cookies and parameters that are passed in the arguments
+   * @param cookies request cookies
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameters
+   * @see setCookies
+   */
+  public InputStream post(Map cookies, Map parameters) throws IOException {
+    setCookies(cookies);
+    setParameters(parameters);
+    return post();
+  }
+
+  /**
+   * posts the requests to the server, with all the cookies and parameters that were added before (if any), and with cookies and parameters that are passed in the arguments
+   * @param cookies request cookies
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameters
+   * @see setCookies
+   */
+  public InputStream post(String[] cookies, Object[] parameters) throws IOException {
+    setCookies(cookies);
+    setParameters(parameters);
+    return post();
+  }
+
+  /**
+   * post the POST request to the server, with the specified parameter
+   * @param name parameter name
+   * @param value parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public InputStream post(String name, Object value) throws IOException {
+    setParameter(name, value);
+    return post();
+  }
+
+  /**
+   * post the POST request to the server, with the specified parameters
+   * @param name1 first parameter name
+   * @param value1 first parameter value
+   * @param name2 second parameter name
+   * @param value2 second parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public InputStream post(String name1, Object value1, String name2, Object value2) throws IOException {
+    setParameter(name1, value1);
+    return post(name2, value2);
+  }
+
+  /**
+   * post the POST request to the server, with the specified parameters
+   * @param name1 first parameter name
+   * @param value1 first parameter value
+   * @param name2 second parameter name
+   * @param value2 second parameter value
+   * @param name3 third parameter name
+   * @param value3 third parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public InputStream post(String name1, Object value1, String name2, Object value2, String name3, Object value3) throws IOException {
+    setParameter(name1, value1);
+    return post(name2, value2, name3, value3);
+  }
+
+  /**
+   * post the POST request to the server, with the specified parameters
+   * @param name1 first parameter name
+   * @param value1 first parameter value
+   * @param name2 second parameter name
+   * @param value2 second parameter value
+   * @param name3 third parameter name
+   * @param value3 third parameter value
+   * @param name4 fourth parameter name
+   * @param value4 fourth parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public InputStream post(String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4) throws IOException {
+    setParameter(name1, value1);
+    return post(name2, value2, name3, value3, name4, value4);
+  }
+
+  /**
+   * posts a new request to specified URL, with parameters that are passed in the argument
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameters
+   */
+  public static InputStream post(URL url, Map parameters) throws IOException {
+    return new ClientHttpRequest(url).post(parameters);
+  }
+
+  /**
+   * posts a new request to specified URL, with parameters that are passed in the argument
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameters
+   */
+  public static InputStream post(URL url, Object[] parameters) throws IOException {
+    return new ClientHttpRequest(url).post(parameters);
+  }
+
+  /**
+   * posts a new request to specified URL, with cookies and parameters that are passed in the argument
+   * @param cookies request cookies
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setCookies
+   * @see setParameters
+   */
+  public static InputStream post(URL url, Map cookies, Map parameters) throws IOException {
+    return new ClientHttpRequest(url).post(cookies, parameters);
+  }
+
+  /**
+   * posts a new request to specified URL, with cookies and parameters that are passed in the argument
+   * @param cookies request cookies
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setCookies
+   * @see setParameters
+   */
+  public static InputStream post(URL url, String[] cookies, Object[] parameters) throws IOException {
+    return new ClientHttpRequest(url).post(cookies, parameters);
+  }
+
+  /**
+   * post the POST request specified URL, with the specified parameter
+   * @param name parameter name
+   * @param value parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public static InputStream post(URL url, String name1, Object value1) throws IOException {
+    return new ClientHttpRequest(url).post(name1, value1);
+  }
+
+  /**
+   * post the POST request to specified URL, with the specified parameters
+   * @param name1 first parameter name
+   * @param value1 first parameter value
+   * @param name2 second parameter name
+   * @param value2 second parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public static InputStream post(URL url, String name1, Object value1, String name2, Object value2) throws IOException {
+    return new ClientHttpRequest(url).post(name1, value1, name2, value2);
+  }
+
+  /**
+   * post the POST request to specified URL, with the specified parameters
+   * @param name1 first parameter name
+   * @param value1 first parameter value
+   * @param name2 second parameter name
+   * @param value2 second parameter value
+   * @param name3 third parameter name
+   * @param value3 third parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public static InputStream post(URL url, String name1, Object value1, String name2, Object value2, String name3, Object value3) throws IOException {
+    return new ClientHttpRequest(url).post(name1, value1, name2, value2, name3, value3);
+  }
+
+  /**
+   * post the POST request to specified URL, with the specified parameters
+   * @param name1 first parameter name
+   * @param value1 first parameter value
+   * @param name2 second parameter name
+   * @param value2 second parameter value
+   * @param name3 third parameter name
+   * @param value3 third parameter value
+   * @param name4 fourth parameter name
+   * @param value4 fourth parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public static InputStream post(URL url, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4) throws IOException {
+    return new ClientHttpRequest(url).post(name1, value1, name2, value2, name3, value3, name4, value4);
+  }
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/DeskShareApplet.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/DeskShareApplet.java
new file mode 100644
index 0000000000000000000000000000000000000000..63ab51bfb0972663ed531dd8b2c1a7f63d4051e8
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/DeskShareApplet.java
@@ -0,0 +1,147 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client;
+
+import java.applet.Applet;
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+
+
+import org.bigbluebutton.deskshare.client.blocks.BlockManager;
+import org.bigbluebutton.deskshare.client.blocks.ChangedBlocksListener;
+import org.bigbluebutton.deskshare.client.net.ConnectionException;
+import org.bigbluebutton.deskshare.client.net.NetworkStreamSender;
+import org.bigbluebutton.deskshare.common.Dimension;
+
+public class DeskShareApplet extends Applet implements IScreenCaptureListener, ChangedBlocksListener {
+
+	private static final long serialVersionUID = 1L;
+	private ScreenCaptureTaker captureTaker;
+	private ScreenCapture capture;
+	private Thread captureTakerThread;
+//	private ScreenCaptureSender captureSender;
+	
+	private int screenWidth = 1680; //1536;
+	private int screenHeight = 1050; //1024;
+	private int x = 0;
+	private int y = 0;
+	private boolean httpTunnel = false;
+	private BlockManager blockManager;
+	private int blockWidth = 64;
+	private int blockHeight = 64;
+	private String room = "testroom";
+	private String host = "192.168.0.182";
+	
+	boolean connected = false;
+	private boolean senderStarted = false;
+	private NetworkStreamSender sender;
+	
+	public void init() {
+
+		System.out.println("Applet built oct 7, 2009 at 7:53PM");
+		screenWidth = Integer.parseInt(getParameter("CAPTURE_WIDTH"));
+		screenHeight = Integer.parseInt(getParameter("CAPTURE_HEIGHT"));
+				
+		x = Integer.parseInt(getParameter("X"));
+		y = Integer.parseInt(getParameter("Y"));
+		room = getParameter("ROOM");
+		host = getParameter("IP");
+		
+		httpTunnel = Boolean.parseBoolean(getParameter("TUNNEL"));
+		System.out.println("Tunnel " + httpTunnel);
+		String t = getParameter("TUNNEL");
+		System.out.println("Tunnel param " + t);
+	}
+	
+	public void stop() {
+		System.out.println("Stopping applet");
+		captureTaker.setCapture(false);
+		if (connected) {
+			try {
+				if (senderStarted)
+					sender.stop();
+			} catch (ConnectionException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}			
+	}
+	
+	public void start() {
+		System.out.println("RunnerApplet start()");
+		capture = new ScreenCapture(x, y, screenWidth, screenHeight);
+		captureTaker = new ScreenCaptureTaker(capture);
+		
+		Dimension screenDim = new Dimension(screenWidth, screenHeight);
+		Dimension tileDim = new Dimension(blockWidth, blockHeight);
+		blockManager = new BlockManager();
+		blockManager.addListener(this);
+		blockManager.initialize(screenDim, tileDim);
+	
+		sender = new NetworkStreamSender(blockManager, host, room);
+		connected = sender.connect();
+		if (connected) {
+			captureTaker.addListener(this);
+			captureTaker.setCapture(true);
+			
+			captureTakerThread = new Thread(captureTaker, "ScreenCaptureTaker");
+			captureTakerThread.start();	
+		}
+	}
+			
+	/**
+	 * This method is called when the user closes the browser window containing the applet
+	 * It is very important that the connection to the server is closed at this point. That way the server knows to
+	 * close the stream.
+	 */
+	public void destroy(){
+		stop();
+	}
+	
+	public void setScreenCoordinates(int x, int y){
+		capture.setX(x);
+		capture.setY(y);
+	}
+	
+	public void onScreenCaptured(BufferedImage screen, boolean isKeyFrame) {
+		blockManager.processCapturedScreen(screen, isKeyFrame);		
+	}
+	
+	
+	public void screenCaptureStopped() {
+		System.out.println("Screencapture stopped");
+		destroy();
+	}
+
+	public void onChangedTiles(ByteArrayOutputStream pixelData, boolean isKeyFrame) {
+		if (! senderStarted) {
+			sender.start();
+			senderStarted = true;
+		}
+	}
+	
+	static public void main (String argv[]) {
+	    final Applet applet = new DeskShareApplet();
+	    applet.start();
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/FlvFileWriter.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/FlvFileWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..ab6c597869b6d01a2c01a0f50020d4b650dff571
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/FlvFileWriter.java
@@ -0,0 +1,158 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class FlvFileWriter {
+
+	private FileOutputStream fo;
+	
+	private long previousTagSize = 0;
+	private final static byte[] header = {'F','L','V',0x01,0x01,0x00,0x00,0x00,0x09};
+	private static final byte[] videoTagType = {0x09};
+	private static final byte[] streamId = {0, 0, 0};
+	private int dataSize = 0;
+	private long startTimestamp = 0;
+	private boolean firstTag = true;
+	
+	private static byte FLV_TAG_HEADER_SIZE = 11;
+	
+	public void init() {
+		setupFlvFile();
+	}
+	
+    public void writeDataToFile (ByteArrayOutputStream videoData) {
+
+    		int size = videoData.size();
+            byte[] blockData = videoData.toByteArray();
+            
+            try {
+                writePreviousTagSize();
+                writeFlvTag(blockData, size);                              
+            } catch(Exception e) {
+                System.out.println("exception: "+e.getMessage());
+            }
+    }
+    
+    private void writeFlvTag(byte[] videoData, int size) throws IOException {       
+        writeTagType();
+        writeDataSize(size);
+        writeTimestamp();
+        writeStreamId();
+        writeVideoData(videoData);
+    }
+    
+    private void setupFlvFile() {
+    	try {
+			fo = new FileOutputStream("D://temp/"+"ApiDemo.flv");
+			fo.write(header);
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+    }
+    
+    private void writePreviousTagSize() throws IOException {
+    	
+    	int byte1 = (int)previousTagSize >> 24;
+    	int byte2 = (int)previousTagSize >> 16;
+    	int byte3 = (int)previousTagSize >> 8;
+    	int byte4 = (int)previousTagSize & 0xff;
+    	
+ //   	System.out.println("PrevTagSize: dec=" + previousTagSize + " hex=" + Long.toHexString(previousTagSize) + " bytes= " 
+ //   			+ Integer.toHexString(byte1) + " " + Integer.toHexString(byte2) 
+ //   			+ " " + Integer.toHexString(byte3) + " " + Integer.toHexString(byte4));
+    	
+    	fo.write(byte1);
+    	fo.write(byte2);
+    	fo.write(byte3);
+    	fo.write(byte4);
+    }
+    
+    private void writeTagType() throws IOException {
+    	fo.write(videoTagType);
+    }
+    
+    private void writeDataSize(int size) throws IOException {
+    	int byte1 = (size >> 16);
+    	int byte2 = (size >> 8);
+    	int byte3 = (size & 0x0ff);
+    	
+//    	System.out.println("DataSize: dec=" + size + " hex=" + Integer.toHexString(size) + " bytes= " 
+////    			+ Integer.toHexString(byte1) + " " + Integer.toHexString(byte2) 
+ //   			+ " " + Integer.toHexString(byte3));
+    	
+    	fo.write(byte1);
+    	fo.write(byte2);
+    	fo.write(byte3);
+    	
+    	previousTagSize = FLV_TAG_HEADER_SIZE + size;
+    }
+    
+    private void writeTimestamp() throws IOException {
+    	long now = System.currentTimeMillis();
+    	
+    	if (firstTag) {
+    		startTimestamp = now;
+    		firstTag = false;
+    	}
+    	
+    	long elapsed = now - startTimestamp;
+    	
+    	int fb = (int)(elapsed & 0xff0000) >> 16;
+    	int sb = (int)(elapsed & 0xff00) >> 8;
+    	int tb = (int)(elapsed & 0xff);
+    	int ub = ((int)elapsed & 0xff000000) >> 24;
+    	
+//    	System.out.println("timestamp: dec=" + elapsed + " hex=" + Long.toHexString(elapsed) + " bytes=" + 
+//    			Integer.toHexString(fb) + " " + Integer.toHexString(sb) + " " + Integer.toHexString(tb) + " " + Integer.toHexString(ub));
+    	
+    	fo.write(fb);
+    	fo.write(sb);
+    	fo.write(tb);
+    	
+    	fo.write(ub );
+    	
+    }
+    
+    private void writeStreamId() throws IOException {
+    	fo.write(streamId);
+    }
+    
+    private void writeVideoData(byte[] videoData) throws IOException {
+    	fo.write(videoData);
+    }
+    
+    public void stop() {
+    	try {
+    		System.out.println("Closing stream");
+			fo.close();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+    }
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/IScreenCaptureListener.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/IScreenCaptureListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..4875d98d06e492b9cd6584e0bddac2b2d75e3176
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/IScreenCaptureListener.java
@@ -0,0 +1,29 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client;
+
+import java.awt.image.BufferedImage;
+
+public interface IScreenCaptureListener {
+	public void screenCaptureStopped();
+	public void onScreenCaptured(BufferedImage screen, boolean isKeyFrame);
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/ScreenCapture.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/ScreenCapture.java
new file mode 100644
index 0000000000000000000000000000000000000000..60d7a9d48590eb3cb71af60630dad3c426bf2676
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/ScreenCapture.java
@@ -0,0 +1,126 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client;
+
+import java.awt.AWTException;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.Toolkit;
+import java.awt.image.BufferedImage;
+
+/**
+ * The Capture class uses the java Robot class to capture the screen
+ * The image captured is scaled down. This is done because of bandwidth issues and because it
+ * is unnecessary for the Flex Client to be able to see the full screen, in fact it is undesirable
+ * to do so.
+ * The image can then be sent for further processing
+ * @author Snap
+ *
+ */
+public class ScreenCapture {	
+	private Robot robot;
+	private Toolkit toolkit;
+	private Rectangle screenBounds;	
+	private int width, height, x,y, videoWidth, videoHeight;
+
+	public ScreenCapture(int x, int y, int screenWidth, int screenHeight){
+		this.width = screenWidth;
+		this.height = screenHeight;
+		try{
+			robot = new Robot();
+		}catch (AWTException e){
+			System.out.println(e.getMessage());
+		}
+		this.toolkit = Toolkit.getDefaultToolkit();
+		this.screenBounds = new Rectangle(x, y, this.width, this.height);
+	}
+	
+	public BufferedImage takeSingleSnapshot(){
+		return robot.createScreenCapture(this.screenBounds);
+	}
+	
+	public int getScreenshotWidth(){
+		return toolkit.getScreenSize().width;
+	}
+	
+	public int getScreenshotHeight(){
+		return toolkit.getScreenSize().height;
+	}
+	
+	public void setWidth(int width){
+		int screenWidth = toolkit.getScreenSize().width;
+		if (width > screenWidth) this.width = screenWidth;
+		else this.width = width;
+		updateBounds();
+	}
+	
+	public void setHeight(int height){
+		int screenHeight = toolkit.getScreenSize().height;
+		if (height > screenHeight) {
+			this.height = screenHeight;
+		}
+		else {
+			this.height = height;
+		}
+		updateBounds();
+	}
+	
+	public void setX(int x){
+		this.x = x;
+		updateBounds();
+	}
+	
+	public void setY(int y){
+		this.y = y;
+		updateBounds();
+	}
+	
+	public void updateBounds(){
+		this.screenBounds = new Rectangle(x,y,width,height);
+	}
+	
+	 public int getWidth(){
+		 return this.width;
+	 }
+	 
+	 public int getHeight(){
+		 return this.height;
+	 }
+	 
+	 public int getProperFrameRate(){
+		 long area = width*height;
+		 if (area > 1000000) return 1;
+		 else if (area > 600000) return 2;
+		 else if (area > 300000) return 4;
+		 else if (area > 150000) return 8;
+		 else return 10;
+	 }
+	 	 
+	 public int getVideoWidth(){
+		 return videoWidth;
+	 }
+	 
+	 public int getVideoHeight(){
+		 return videoHeight;
+	 }
+
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/ScreenCaptureTaker.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/ScreenCaptureTaker.java
new file mode 100644
index 0000000000000000000000000000000000000000..ea564cc8a3166baf03f50cdc471fa6173a1e7b96
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/ScreenCaptureTaker.java
@@ -0,0 +1,100 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client;
+
+import java.awt.image.BufferedImage;
+
+public class ScreenCaptureTaker implements Runnable {
+	
+	private ScreenCapture capture;
+	private int timeBase;
+	private int frameCount = 0;
+	private IScreenCaptureListener listeners;
+	
+	private volatile boolean startCapture = false;
+		
+	public ScreenCaptureTaker(ScreenCapture capture){
+		System.out.println("Capture thread constructor.");
+		this.capture = capture;
+		this.timeBase = 1000 / capture.getProperFrameRate();
+	}
+	
+	public void run(){		
+		while (startCapture){
+			System.out.println("----- Taking screen capture -----");
+			long snapshotTime = System.currentTimeMillis();
+			BufferedImage image = capture.takeSingleSnapshot();
+			long snapshotEnd = System.currentTimeMillis();
+//			System.out.println("Snapshot time = " + (snapshotEnd - snapshotTime) + "ms.");
+			notifyListeners(image);
+			long completeTime = System.currentTimeMillis();
+//			System.out.println("Processing time = " + (completeTime - snapshotTime) + "ms.");
+			try{
+				//Thread.sleep(timeBase);
+				Thread.sleep(500);
+			} catch (Exception e){
+				System.out.println("Exception sleeping.");
+				System.exit(0);
+			}
+		}
+		
+		System.out.println("Stopping screen capture.");
+		
+		listeners.screenCaptureStopped();
+	}
+	
+	private void notifyListeners(BufferedImage image) {
+		listeners.onScreenCaptured(image, isKeyFrame());
+	}
+	
+	private boolean isKeyFrame() {
+		
+		if (frameCount == 0) {
+//			System.out.println("Is Key Frame " + frameCount);
+			frameCount++;
+			
+			return true;
+		} else {
+//			System.out.println("Is Not Key Frame " + frameCount);
+			if (frameCount < 20) {
+				frameCount++;
+			} else {
+				frameCount = 0;
+			}
+			
+			return false;
+		}
+	}
+	
+	public void addListener(IScreenCaptureListener listener) {
+//		listeners.add(listener);
+		listeners = listener;
+	}
+
+	public void removeListener(IScreenCaptureListener listener) {
+//		listeners.remove(listener);
+	}
+	
+	public void setCapture(boolean capture) {
+		startCapture = capture;
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/Block.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/Block.java
new file mode 100644
index 0000000000000000000000000000000000000000..5dc6af60e4a8a6a1809a7007aa1b8a4c5059425e
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/Block.java
@@ -0,0 +1,151 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.blocks;
+
+import java.awt.Point;
+import java.awt.image.BufferedImage;
+import java.util.zip.Adler32;
+
+import org.bigbluebutton.deskshare.client.net.EncodedBlockData;
+import org.bigbluebutton.deskshare.common.PixelExtractException;
+import org.bigbluebutton.deskshare.common.ScreenVideoEncoder;
+import org.bigbluebutton.deskshare.common.Dimension;
+
+public final class Block {    
+    private final Adler32 checksum;
+    private final Dimension dim;
+    private final int position;
+    private final Point location;
+    
+    private boolean isKeyFrame = false;
+    private int[] pixels;
+    private EncodedBlockData encodedBlockData;
+    private long lastChanged;
+    private static int FORCE_UPDATE_DURATION = 10000;
+    
+    Block(Dimension dim, int position, Point location) {
+        checksum = new Adler32();
+        this.dim = dim;
+        this.position = position;
+        this.location = location;
+    }
+    
+    public void updateBlock(BufferedImage capturedScreen, boolean isKeyFrame)
+    {	
+    	synchronized(this) {
+        	this.isKeyFrame = isKeyFrame;        	
+        	try {
+    			pixels = ScreenVideoEncoder.getPixels(capturedScreen, getX(), getY(), getWidth(), getHeight());
+        	} catch (PixelExtractException e) {
+        		System.out.println(e.toString());
+    		}    		
+    	}
+
+    }
+    
+    public  EncodedBlockData encode() {
+    	int[] pixelsCopy = new int[pixels.length];
+    	synchronized (this) {           
+            System.arraycopy(pixels, 0, pixelsCopy, 0, pixels.length);
+		}
+    	
+        byte[] encodedBlock;
+        boolean hasChanged = false;
+        boolean forceUpdate = forceUpdate();
+        //if (!checksumSame(pixelsCopy) || forceUpdate) {
+        if (!checksumSame(pixelsCopy) || isKeyFrame) {// || forceUpdate()) {
+         	encodedBlock = ScreenVideoEncoder.encodePixels(pixelsCopy, getWidth(), getHeight(), false, isKeyFrame);
+           	hasChanged = true;           	
+        } else {
+           	encodedBlock = ScreenVideoEncoder.encodeBlockUnchanged();  
+           	hasChanged = false;
+        }    	    
+        
+        EncodedBlockData data = new EncodedBlockData(position, hasChanged, encodedBlock, isKeyFrame);
+        return data;			
+    }
+    
+    private boolean checksumSame(int[] pixelsCopy) {
+    	long oldsum;
+        oldsum = checksum.getValue(); 
+        calcChecksum(pixelsCopy);  
+        return (oldsum == checksum.getValue());
+    }
+    
+    private boolean forceUpdate() {         
+        long now = System.currentTimeMillis();        
+        boolean update = ((now - lastChanged) > FORCE_UPDATE_DURATION);
+        if (update) {
+        	synchronized(this) {
+        		lastChanged = now;
+        	}       	
+        }
+        return update;
+    }
+    
+    public synchronized EncodedBlockData getEncodedBlockData() {
+    	return encodedBlockData;
+    }
+    
+    private synchronized void calcChecksum(int pixelsCopy[])
+    {
+    	checksum.reset();   
+    	int height = getHeight();
+    	int width = getWidth();
+		for (int i = 0; i < height; i++) {
+		    for (int j = 0; j < width; j++) {
+		    	if ((i * width + i) % 13 == 0)
+		    		checksum.update(pixelsCopy[i * width + j]);
+		    }
+		}	 
+    }
+
+    public int getWidth()
+    {
+        return new Integer(dim.getWidth()).intValue();
+    }
+    
+    public int getHeight()
+    {
+        return new Integer(dim.getHeight()).intValue();
+    }
+    
+    public int getPosition() {
+		return new Integer(position).intValue();
+	}
+    
+    public int getX() {
+		return new Integer(location.x).intValue();
+	}
+
+    public int getY() {
+		return new Integer(location.y).intValue();
+	}
+	
+    Dimension getDimension() {
+		return new Dimension(dim.getWidth(), dim.getHeight());
+	}
+	
+    Point getLocation() {
+		return new Point(location.x, location.y);
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/BlockFactory.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/BlockFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..2f4a92bd77cc1affe9c98f6eae1fdb9684a7e8da
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/BlockFactory.java
@@ -0,0 +1,153 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.blocks;
+
+import java.awt.Point;
+
+import org.bigbluebutton.deskshare.common.Dimension;
+
+class BlockFactory {
+    private int numColumns;
+    private int numRows;
+    private Dimension screenDim;
+    private Dimension tileDim;
+        
+    public BlockFactory(Dimension screen, Dimension tile) {
+        this.screenDim = screen;
+        this.tileDim = tile;
+        
+        numColumns = computeNumberOfColumnTiles();
+        numRows = computeNumberOfRowTiles();
+    }
+    
+    private int computeNumberOfColumnTiles() {
+    	int columns = screenDim.getWidth() / tileDim.getWidth();
+    	if (hasPartialColumnTile()) {
+    		columns += 1;
+    	}
+    	return columns;
+    }
+    
+    private boolean hasPartialColumnTile() {
+    	return (screenDim.getWidth() % tileDim.getWidth()) != 0;
+    }
+    
+    private int computeNumberOfRowTiles() {
+    	int rows = screenDim.getHeight() / tileDim.getHeight();
+    	if (hasPartialRowTile()) {
+    		rows += 1;
+    	}
+    	return rows;
+    }
+    
+    private boolean hasPartialRowTile() {
+    	return (screenDim.getHeight() % tileDim.getHeight()) != 0;
+    }
+  
+    Block createBlock(int position) {
+    	int col = computeColumn(position);
+    	int row = computeRow(position);
+		int w = computeTileWidth(col);
+		int h = computeTileHeight(row);		
+		int x = computeTileXLocation(col);
+		int y = computeTileYLocation(row);
+		int pos = computeTilePosition(row, col);
+		
+		Block t = new Block(new Dimension(w, h), pos, new Point(x,y));
+
+		return t;
+    }
+    
+    private int computeTilePosition(int row, int col) {
+    	return (((numRows - (row+1)) * numColumns) + (col + 1));
+    }
+    
+    private int computeTileXLocation(int col) {
+    	return col * tileDim.getWidth();
+    }
+    
+    private int computeTileYLocation(int row) {
+    	if (isTopRowTile(row)) return 0;
+    	return screenDim.getHeight() - ((numRows - row) * tileDim.getHeight());
+    }
+    
+    Point positionToIndex(int position) {    
+    	return new Point(computeRow(position), computeColumn(position));
+    }
+    
+    int indexToPosition(int row, int col) {
+    	return computeTilePosition(row, col);
+    }
+    
+    private int computeRow(int position) {
+    	return -(position - (getRowCount() * getColumnCount())) / getColumnCount();
+    }
+    
+    private int computeColumn(int position) {
+		return (position - 1) % getColumnCount();    	
+    }
+    
+    private int computeTileWidth(int col) {
+    	if (isLastColumnTile(col)) {
+    		if (hasPartialColumnTile()) {
+    			return partialTileWidth();
+    		}
+    	}
+    	return tileDim.getWidth();
+    }
+    
+    private int partialTileWidth() {
+    	return screenDim.getWidth() % tileDim.getWidth();
+    }
+    
+    private int computeTileHeight(int row) {
+    	if (isTopRowTile(row)) {
+    		if (hasPartialRowTile()) {
+    			return partialTileHeight();
+    		}
+    	}
+    	return tileDim.getWidth();
+    }
+    
+    private int partialTileHeight() {
+    	return screenDim.getHeight() % tileDim.getHeight();
+    }
+
+    private boolean isLastColumnTile(int col) {
+    	return ((col+1) % numColumns) == 0;
+    }
+    
+    private boolean isTopRowTile(int row) {
+    	return (row == 0);
+    }
+
+    
+    int getRowCount()
+    {
+        return numRows;
+    }
+    
+    int getColumnCount()
+    {
+        return numColumns;
+    }
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/BlockImp.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/BlockImp.java
new file mode 100644
index 0000000000000000000000000000000000000000..f30bc2757fadeb9bacb09128f714e81571e1dffb
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/BlockImp.java
@@ -0,0 +1,135 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.blocks;
+
+import java.awt.Point;
+import java.awt.image.BufferedImage;
+import java.util.zip.Adler32;
+
+import org.bigbluebutton.deskshare.common.PixelExtractException;
+import org.bigbluebutton.deskshare.common.ScreenVideoEncoder;
+import org.bigbluebutton.deskshare.common.Dimension;
+
+public final class BlockImp implements IBlock {    
+    private final Adler32 checksum;
+    private final Dimension dim;
+    private final int position;
+    private final Point location;
+    
+    private boolean isKeyFrame = false;
+    private byte[] encodedBlock;
+    private int[] pixels;
+    
+    private boolean encoded = false;
+
+    BlockImp(Dimension dim, int position, Point location) {
+        checksum = new Adler32();
+        this.dim = dim;
+        this.position = position;
+        this.location = location;
+    }
+    
+    public synchronized void updateBlock(BufferedImage capturedScreen, boolean isKeyFrame)
+    {	
+    	this.isKeyFrame = isKeyFrame;
+    	
+    	try {
+			pixels = ScreenVideoEncoder.getPixels(capturedScreen, getX(), getY(), getWidth(), getHeight());
+    	} catch (PixelExtractException e) {
+    		System.out.println(e.toString());
+    		encodedBlock = ScreenVideoEncoder.encodeBlockUnchanged();
+		}
+    }
+    
+    public synchronized byte[] encode() {
+        long oldsum;
+        oldsum = checksum.getValue(); 
+        calcChecksum(pixels);
+
+        if ((oldsum == checksum.getValue()) && !isKeyFrame) {
+        	encodedBlock = ScreenVideoEncoder.encodeBlockUnchanged();  
+        }
+        else {
+        	encodedBlock = ScreenVideoEncoder.encodePixels(pixels, getWidth(), getHeight(), false, isKeyFrame);
+        }    	    	        
+    	return encodedBlock;
+    }
+    
+    public byte[] getEncodedBlock() {
+    	return encodedBlock;
+    }
+    
+    private synchronized void calcChecksum(int pixels[])
+    {
+    	checksum.reset();   
+    	int height = getHeight();
+    	int width = getWidth();
+		for (int i = 0; i < height; i++) {
+		    for (int j = 0; j < width; j++) {
+		    	if ((i * width + i) % 13 == 0)
+		    		checksum.update(pixels[i * width + j]);
+		    }
+		}	 
+    }
+    
+    public synchronized boolean isKeyFrame() {
+    	return isKeyFrame;
+    }
+    
+    public synchronized boolean hasChanged() {
+        long oldsum;
+        oldsum = checksum.getValue(); 
+        calcChecksum(pixels);
+
+        return ((oldsum == checksum.getValue()) && !isKeyFrame);
+    }
+    
+    public int getWidth()
+    {
+        return new Integer(dim.getWidth()).intValue();
+    }
+    
+    public int getHeight()
+    {
+        return new Integer(dim.getHeight()).intValue();
+    }
+    
+    public int getPosition() {
+		return new Integer(position).intValue();
+	}
+    
+    public int getX() {
+		return new Integer(location.x).intValue();
+	}
+
+    public int getY() {
+		return new Integer(location.y).intValue();
+	}
+	
+	Dimension getDimension() {
+		return new Dimension(dim.getWidth(), dim.getHeight());
+	}
+	
+	Point getLocation() {
+		return new Point(location.x, location.y);
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/BlockManager.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/BlockManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..4866034b53bca336423df8e0252631e069533f99
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/BlockManager.java
@@ -0,0 +1,172 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.blocks;
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.bigbluebutton.deskshare.client.encoder.BlockEncodeException;
+import org.bigbluebutton.deskshare.client.encoder.ScreenVideoBlockEncoder;
+import org.bigbluebutton.deskshare.common.ScreenVideoEncoder;
+import org.bigbluebutton.deskshare.common.Dimension;
+
+public class BlockManager {
+    private final Map<Integer, Block> blocksMap;
+    private final Map<Integer, Block> unmodifiableBlocksMap;
+    private int numColumns;
+    private int numRows;
+    
+    private BlockFactory factory;
+    private ChangedBlocksListener listeners;
+    
+    private ByteArrayOutputStream encodedPixelStream = new ByteArrayOutputStream();
+    private Dimension screenDim, blockDim;
+    
+//    private ScreenVideoBlockEncoder encoder;
+    
+    public BlockManager() {
+    	blocksMap = new HashMap<Integer, Block>();
+    	unmodifiableBlocksMap = Collections.unmodifiableMap(blocksMap);
+ //   	encoder = new ScreenVideoBlockEncoder();
+    }
+    
+    public void initialize(Dimension screen, Dimension tile) {
+    	screenDim = screen;
+    	blockDim = tile;
+    	
+    	factory = new BlockFactory(screen, tile);
+        
+        numColumns = factory.getColumnCount();
+        numRows = factory.getRowCount();
+        int numberOfBlocks = numColumns * numRows;
+        
+        for (int position = 1; position <= numberOfBlocks; position++) {
+        	Block block = factory.createBlock(position);
+        	blocksMap.put(new Integer(position), block);
+        }  
+    }
+    
+    public void processCapturedScreen(BufferedImage capturedScreen, boolean isKeyFrame)
+    {    	
+    	long start = System.currentTimeMillis();
+//		Block[] blocks = new Block[numRows * numColumns];
+		int index = 0;
+		int numberOfBlocks = numColumns * numRows;
+        for (int position = 1; position <= numberOfBlocks; position++) {
+        	Block block = blocksMap.get(new Integer(position));
+        	block.updateBlock(capturedScreen, isKeyFrame);
+        	
+        	
+//            blocks[index++] = block;
+        }
+        
+		long qEncode = System.currentTimeMillis();
+//		System.out.println("Grabbing pixels for blocks[" + numberOfBlocks + "] took " + (qEncode-start) + " ms.");   
+		
+//        try {
+//			encoder.encode(blocks);
+//			sendEncodedData(isKeyFrame);
+//		} catch (BlockEncodeException e) {
+//			e.printStackTrace();
+//		}
+		notifyChangedTilesListener(null, isKeyFrame);
+		long end = System.currentTimeMillis();
+		System.out.println("ProcessCapturedScreen took " + (end-start) + " ms.");
+    }
+/*    
+    private void sendEncodedData(boolean isKeyFrame) {
+    	long start = System.currentTimeMillis();
+    	encodedPixelStream.reset();
+    	byte[] encodedDim = ScreenVideoEncoder.encodeBlockDimensionsAndGridSize(blockDim.getWidth(), screenDim.getWidth(), blockDim.getHeight(), screenDim.getHeight());
+     	byte videoDataHeader = ScreenVideoEncoder.encodeFlvVideoDataHeader(isKeyFrame);
+    	try {
+    		encodedPixelStream.write(videoDataHeader);
+			encodedPixelStream.write(encodedDim);
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+
+		int numberOfBlocks = numColumns * numRows;
+        for (int position = 1; position <= numberOfBlocks; position++) {
+        	Block block = blocksMap.get(new Integer(position));
+        	byte[] data = block.getEncodedBlock();
+           	encodedPixelStream.write(data, 0, data.length);
+        }
+        
+//	    System.out.println("Encoded data length = " + encodedPixelStream.size());
+	    notifyChangedTilesListener(encodedPixelStream, isKeyFrame);	
+	    long end = System.currentTimeMillis();
+	    System.out.println("Sending encoded data took " + (end-start) + " ms.");
+    }
+*/    
+    private void notifyChangedTilesListener(ByteArrayOutputStream encodedPixelStream, boolean isKeyFrame) {
+    	listeners.onChangedTiles(encodedPixelStream, isKeyFrame);
+    }
+    
+
+	public void addListener(ChangedBlocksListener listener) {
+		listeners = listener;
+	}
+
+
+	public void removeListener(ChangedBlocksListener listener) {
+		//listeners.remove(listener);
+		listeners = null;
+	}
+    
+	public Block getBlock(int position) {
+		return (Block) blocksMap.get(Integer.valueOf(position));
+	}
+	
+    public int getRowCount()
+    {
+        return numRows;
+    }
+    
+    public int getColumnCount()
+    {
+        return numColumns;
+    }
+
+    public Dimension getScreenDim() {
+		return screenDim;
+	}
+
+	public Dimension getBlockDim() {
+		return blockDim;
+	}
+
+	/*
+	 * Returns a read-only "live" view of the blocks;
+	 */
+	public Map<Integer, Block> getBlocks() {
+		return unmodifiableBlocksMap;
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/ChangedBlocksListener.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/ChangedBlocksListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..c2d130e69bc80718f58a21cc2fe4fa4d8c1db14d
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/ChangedBlocksListener.java
@@ -0,0 +1,29 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.blocks;
+
+import java.io.ByteArrayOutputStream;
+
+public interface ChangedBlocksListener {
+
+	public void onChangedTiles(ByteArrayOutputStream pixelData, boolean isKeyFrame);
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/IBlock.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/IBlock.java
new file mode 100644
index 0000000000000000000000000000000000000000..c385bd72b7bfc1934924a8424941f8a307a90ceb
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/IBlock.java
@@ -0,0 +1,29 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.blocks;
+
+public interface IBlock {
+
+	public boolean hasChanged();
+	
+	public byte[] encode();
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/encoder/BlockEncodeException.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/encoder/BlockEncodeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..d39e7ec5f2c142ce754c381b48d9ffccb1e002a2
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/encoder/BlockEncodeException.java
@@ -0,0 +1,31 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.encoder;
+
+public class BlockEncodeException extends Exception {
+
+	private static final long serialVersionUID = -3377474098350652011L;
+
+	public BlockEncodeException(String message) {
+		super(message);
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/encoder/FlvEncodeException.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/encoder/FlvEncodeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..56f9b1e93be7b79cdc9071db3fa3aad0ed5ecf78
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/encoder/FlvEncodeException.java
@@ -0,0 +1,31 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.encoder;
+
+public class FlvEncodeException extends Exception {
+
+	private static final long serialVersionUID = -3377474098350652011L;
+
+	public FlvEncodeException(String message) {
+		super(message);
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/encoder/ScreenVideoBlockEncoder.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/encoder/ScreenVideoBlockEncoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..123d22bcd5ab8bd845ffdd2fb66ca75e7ce129e3
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/encoder/ScreenVideoBlockEncoder.java
@@ -0,0 +1,74 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.encoder;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.bigbluebutton.deskshare.client.blocks.Block;
+
+public class ScreenVideoBlockEncoder {
+	private ExecutorService executor;
+	private CompletionService<Block> completionService;
+	
+	public ScreenVideoBlockEncoder() {
+		int numThreads = Runtime.getRuntime().availableProcessors();
+		System.out.println("Starting up " + numThreads + " threads.");
+		executor = Executors.newFixedThreadPool(numThreads);
+		completionService = new ExecutorCompletionService<Block>(executor);
+	}
+
+	public void encode(Block[] blocks) throws BlockEncodeException {
+/*		long start = System.currentTimeMillis();
+		for (int i = 0; i < blocks.length; i++) {
+			final Block block = blocks[i];
+			completionService.submit(new Callable<Block>() {
+				public Block call() {
+					return block.encode();
+				}
+			});
+		}
+		
+		for (int t = 0; t < blocks.length; t++) {
+			Future<Block> f;
+			try {
+				f = completionService.take();
+				Block block = f.get();
+				block.encodeDone();
+			} catch (InterruptedException e) {
+				e.printStackTrace();
+				throw new BlockEncodeException("InterruptedException while encoding block.");
+			} catch (ExecutionException e) {
+				e.printStackTrace();
+				throw new BlockEncodeException("ExecutionException while encoding block.");
+			}
+		}
+		long end = System.currentTimeMillis();
+		System.out.println("Encoding blocks[" + blocks.length + "] took " + (end-start) + " ms.");
+*/
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/encoder/ScreenVideoFlvEncoder.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/encoder/ScreenVideoFlvEncoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..948c463bac9703ca5ea34b1a4a04a32c06efe9ed
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/encoder/ScreenVideoFlvEncoder.java
@@ -0,0 +1,107 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.encoder;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public final class ScreenVideoFlvEncoder {
+	private final static byte[] flvHeader = {'F','L','V',0x01,0x01,0x00,0x00,0x00,0x09};
+	private final static byte[] videoTagType = {0x09};
+	private final static byte[] streamId = {0, 0, 0};
+	private long startTimestamp = 0;
+	private boolean firstTag = true;
+	
+	private static byte FLV_TAG_HEADER_SIZE = 11;
+	
+	ByteArrayOutputStream flvDataStream = new ByteArrayOutputStream();
+	
+	public byte[] encodeHeader() {
+		byte[] prevTagSize =  encodePreviousTagSize(0);
+		byte[] header = new byte[flvHeader.length + prevTagSize.length];
+		
+		System.arraycopy(flvHeader, 0, header, 0, flvHeader.length);
+		System.arraycopy(prevTagSize, 0, header, flvHeader.length, prevTagSize.length);
+		return header;
+	}
+	
+    private byte[] encodePreviousTagSize(long previousTagSize) {    	
+    	int byte1 = (int)previousTagSize >> 24;
+    	int byte2 = (int)previousTagSize >> 16;
+    	int byte3 = (int)previousTagSize >> 8;
+    	int byte4 = (int)previousTagSize & 0xff;
+    	
+    	return new byte[] {(byte)byte1, (byte)byte2, (byte)byte3, (byte)byte4};
+    }
+    
+    public byte[] encodeFlvData (ByteArrayOutputStream screenVideoData) throws FlvEncodeException {
+        byte[] blockData = screenVideoData.toByteArray();
+
+        byte[] flvData;
+		try {
+			flvData = encodeFlvTag(blockData);
+		} catch (IOException e) {
+			throw new FlvEncodeException("Failed to encode FLV data.");
+		}   
+        return flvData;
+	}
+	
+	private byte[] encodeFlvTag(byte[] videoData) throws IOException {   
+
+		flvDataStream.reset();
+		
+		flvDataStream.write(videoTagType);
+		flvDataStream.write(encodeDataSize(videoData.length));
+	    flvDataStream.write(encodeTimestamp());
+	    flvDataStream.write(streamId);
+	    flvDataStream.write(videoData);
+	    flvDataStream.write(encodePreviousTagSize(FLV_TAG_HEADER_SIZE + videoData.length));
+	    
+	    return flvDataStream.toByteArray();
+	}	
+	        
+    private byte[] encodeDataSize(int size) {
+    	int byte1 = (size >> 16);
+    	int byte2 = (size >> 8);
+    	int byte3 = (size & 0x0ff);
+    	
+    	return new byte[] {(byte) byte1, (byte) byte2, (byte) byte3};
+    }
+    
+    private byte[] encodeTimestamp() {
+    	long now = System.currentTimeMillis();
+    	
+    	if (firstTag) {
+    		startTimestamp = now;
+    		firstTag = false;
+    	}
+    	
+    	long elapsed = now - startTimestamp;
+    	
+    	int byte1 = (int)(elapsed & 0xff0000) >> 16;
+    	int byte2 = (int)(elapsed & 0xff00) >> 8;
+    	int byte3 = (int)(elapsed & 0xff);
+    	int tsExtended = ((int)elapsed & 0xff000000) >> 24;
+    	
+    	return new byte[] {(byte) byte1, (byte) byte2, (byte) byte3, (byte) tsExtended};    		    	
+    }   
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/BlockStreamProtocolEncoder.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/BlockStreamProtocolEncoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6cf7086a22b67bd793715ddb74ed32f6ba6504a
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/BlockStreamProtocolEncoder.java
@@ -0,0 +1,88 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.bigbluebutton.deskshare.common.Dimension;
+
+public class BlockStreamProtocolEncoder {
+
+	private static final byte[] HEADER = new byte[] {'B', 'B', 'B', '-', 'D', 'S'}; 
+    private static final byte CAPTURE_START_EVENT = 0;
+    private static final byte CAPTURE_UPDATE_EVENT = 1;
+    private static final byte CAPTURE_END_EVENT = 2;
+    	
+	public static void encodeStartStreamMessage(String room, Dimension screen, Dimension block,
+						ByteArrayOutputStream data) throws IOException {		
+		data.write(CAPTURE_START_EVENT);
+		data.write(room.length());
+		data.write(room.getBytes());		
+		data.write(intToBytes(block.getWidth()));
+		data.write(intToBytes(block.getHeight()));
+		data.write(intToBytes(screen.getWidth()));
+		data.write(intToBytes(screen.getHeight()));
+	}
+	
+	public static void encodeBlock(BlockVideoData block, ByteArrayOutputStream data) throws IOException {
+		data.write(CAPTURE_UPDATE_EVENT);
+		data.write(block.getRoom().length());
+		data.write(block.getRoom().getBytes());
+			
+		byte[] position = new byte[2];
+		int pos = block.getPosition();
+		position[0] = (byte)((pos >> 8) & 0xff);
+		position[1] = (byte)(pos & 0xff);
+			
+		data.write(position);
+		data.write(block.isKeyFrame() ? 1:0);
+			
+		int length = block.getVideoData().length;			
+//		System.out.println("position=" + pos + " keyframe=" + block.isKeyFrame() + " data length=" + length);
+		data.write(intToBytes(length));
+			
+		data.write(block.getVideoData());		
+	}
+	
+	private static byte[] intToBytes(int i) {
+		byte[] data = new byte[4];
+		data[0] = (byte)((i >> 24) & 0xff);
+		data[1] = (byte)((i >> 16) & 0xff);
+		data[2] = (byte)((i >> 8) & 0xff);
+		data[3] = (byte)(i & 0xff);		
+		return data;
+	}
+	
+	public static byte[] encodeHeaderAndLength(ByteArrayOutputStream data) throws IOException {
+		ByteArrayOutputStream header = new ByteArrayOutputStream();
+		header.write(HEADER);
+		header.write(intToBytes(data.size()));
+		return header.toByteArray();
+	}
+	
+	public static void encodeEndStreamMessage(String room, ByteArrayOutputStream data) throws IOException {
+		data.write(CAPTURE_END_EVENT);
+		data.write(room.length());
+		data.write(room.getBytes());
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/BlockStreamSender.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/BlockStreamSender.java
new file mode 100644
index 0000000000000000000000000000000000000000..afbf995747fd125548a89d2ae860f5679e1ee8bd
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/BlockStreamSender.java
@@ -0,0 +1,198 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.bigbluebutton.deskshare.client.blocks.Block;
+import org.bigbluebutton.deskshare.client.blocks.BlockManager;
+import org.bigbluebutton.deskshare.common.Dimension;
+
+public class BlockStreamSender implements ScreenCaptureSender {
+	private static final int PORT = 9123;
+	
+	private Socket socket = null;
+	
+	private DataOutputStream outStream = null;
+	private String room;
+	
+	private BlockingQueue<BlockVideoData> screenQ = new LinkedBlockingQueue<BlockVideoData>(500);
+	private final Executor exec = Executors.newSingleThreadExecutor();
+	private Runnable capturedScreenSender;
+	private volatile boolean sendCapturedScreen = false;
+	
+	private BlockManager blockManager;
+
+	private ByteArrayOutputStream dataToSend;
+	
+	private static final byte[] HEADER = new byte[] {'B', 'B', 'B', '-', 'D', 'S'}; 
+    private static final byte CAPTURE_START_EVENT = 0;
+    private static final byte CAPTURE_UPDATE_EVENT = 1;
+    private static final byte CAPTURE_END_EVENT = 2;
+    
+	public BlockStreamSender(BlockManager blockManager) {
+		this.blockManager = blockManager;
+		dataToSend = new ByteArrayOutputStream();
+	}
+	
+	public void connect(String host, String room, int width, int height) throws ConnectionException {
+		this.room = room;
+		
+		System.out.println("Starting capturedScreenSender ");
+		try {
+			socket = new Socket(host, PORT);
+			outStream = new DataOutputStream(socket.getOutputStream());
+			sendStartStreamMessage(room, blockManager.getScreenDim(), blockManager.getBlockDim());
+			outStream.flush();
+		} catch (UnknownHostException e) {
+			e.printStackTrace();
+			throw new ConnectionException("UnknownHostException: " + host);
+		} catch (IOException e) {
+			e.printStackTrace();
+			throw new ConnectionException("IOException: " + host + ":" + PORT);
+		}
+						
+		sendCapturedScreen = true;
+		capturedScreenSender = new Runnable() {
+			public void run() {
+				while (sendCapturedScreen) {
+					try {
+						BlockVideoData block = screenQ.take();
+						
+//						long now = System.currentTimeMillis();
+//						if ((now - block.getTimestamp()) < 500) {
+							sendBlock(block);
+//							if (screenQ.size() == 500) screenQ.clear();
+//						} else {
+//							System.out.println("Discarding stale block.");
+//						}
+					} catch (InterruptedException e) {
+						System.out.println("InterruptedExeption while taking event.");
+					}
+				}
+			}
+		};
+		exec.execute(capturedScreenSender);	
+	}
+	
+	private void sendStartStreamMessage(String room, Dimension screen, Dimension block) {
+		dataToSend.reset();
+		
+		try {
+			dataToSend.write(CAPTURE_START_EVENT);
+			dataToSend.write(room.length());
+			dataToSend.write(room.getBytes());		
+			dataToSend.write(intToByte(block.getWidth()));
+			dataToSend.write(intToByte(block.getHeight()));
+			dataToSend.write(intToByte(screen.getWidth()));
+			dataToSend.write(intToByte(screen.getHeight()));
+			sendToStream(dataToSend);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	private void sendBlock(BlockVideoData block) {
+		long start = System.currentTimeMillis();
+		dataToSend.reset();
+		try {
+			dataToSend.write(CAPTURE_UPDATE_EVENT);
+			dataToSend.write(block.getRoom().length());
+			dataToSend.write(block.getRoom().getBytes());
+			
+			byte[] position = new byte[2];
+			int pos = block.getPosition();
+			position[0] = (byte)((pos >> 8) & 0xff);
+			position[1] = (byte)(pos & 0xff);
+			
+			dataToSend.write(position);
+			dataToSend.write(block.isKeyFrame() ? 1:0);
+			
+			int length = block.getVideoData().length;			
+//			System.out.println("position=" + pos + " keyframe=" + block.isKeyFrame() + " data length=" + length);
+			dataToSend.write(intToByte(length));
+			
+			dataToSend.write(block.getVideoData());	
+			sendToStream(dataToSend);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}		
+		long end = System.currentTimeMillis();
+		if ((end - start) > 200) {
+			System.out.println("Sending " + dataToSend.size() + " bytes took " + (end-start) + " ms.");
+		}
+	}
+	
+	private byte[] intToByte(int i) {
+		byte[] data = new byte[4];
+		data[0] = (byte)((i >> 24) & 0xff);
+		data[1] = (byte)((i >> 16) & 0xff);
+		data[2] = (byte)((i >> 8) & 0xff);
+		data[3] = (byte)(i & 0xff);		
+		return data;
+	}
+	
+	private void sendToStream(ByteArrayOutputStream data) throws IOException {
+//		System.out.println("Sending length " + data.size());
+		outStream.write(HEADER);
+		outStream.writeInt(data.size());
+		//outStream.write(data.toByteArray());
+		data.writeTo(outStream);
+	}
+	
+	public void send(ByteArrayOutputStream videoData, boolean isKeyFrame) throws ConnectionException {
+		int totalBlocks = blockManager.getColumnCount() * blockManager.getRowCount();
+		for (int i = 1; i <= totalBlocks; i++) {
+				Block block = blockManager.getBlock(i);
+//				if (block.getEncodedBlock().length < 5) continue;
+//				BlockVideoData blockData = new BlockVideoData(room, block.getPosition(), block.getEncodedBlock(), block.isKeyFrame());
+//				try {
+//					screenQ.put(blockData);
+//				} catch (InterruptedException e) {
+//					e.printStackTrace();
+//				}
+		}
+	}
+
+	public void disconnect() throws ConnectionException {
+		System.out.println("Closing connection.");
+		sendCapturedScreen = false;
+
+		dataToSend.reset();
+		try {
+			dataToSend.write(CAPTURE_END_EVENT);
+			dataToSend.write(room.length());
+			dataToSend.write(room.getBytes());
+			sendToStream(dataToSend);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}	
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/BlockVideoData.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/BlockVideoData.java
new file mode 100644
index 0000000000000000000000000000000000000000..962e7a40939b8746e6a1fc0b19683dd34f786be4
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/BlockVideoData.java
@@ -0,0 +1,59 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+public class BlockVideoData {
+
+	private final String room;
+	private final byte[] videoData;
+	private final boolean keyFrame;
+	private final int position;
+	private final long timestamp;
+	
+	public BlockVideoData(String room, int position, byte[] videoData, boolean keyFrame) {
+		this.room = room;
+		this.position = position;
+		this.videoData = videoData;
+		this.keyFrame = keyFrame;
+		timestamp = System.currentTimeMillis();
+	}
+	
+	public String getRoom() {
+		return room;
+	}
+
+	public int getPosition() {
+		return position;
+	}
+	
+	public byte[] getVideoData() {
+		return videoData;
+	}
+
+	public boolean isKeyFrame() {
+		return keyFrame;
+	}	
+	
+	public long getTimestamp() {
+		return timestamp;
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/ConnectionException.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/ConnectionException.java
new file mode 100644
index 0000000000000000000000000000000000000000..6791f52492f448d22feb1882faf5da08b962e261
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/ConnectionException.java
@@ -0,0 +1,31 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+public class ConnectionException extends Exception {
+
+	private static final long serialVersionUID = -8836714569259091334L;
+
+	public ConnectionException(String message) {
+		super(message);
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/EncodedBlockData.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/EncodedBlockData.java
new file mode 100644
index 0000000000000000000000000000000000000000..b30a9cffb02b2520c9fc476192304f3738a98493
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/EncodedBlockData.java
@@ -0,0 +1,59 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+public class EncodedBlockData {
+
+	private final byte[] videoData;
+	private final boolean keyFrame;
+	private final int position;
+	private final long timestamp;
+	private final boolean hasChanged;
+	
+	public EncodedBlockData(int position, boolean hasChanged, byte[] videoData, boolean keyFrame) {
+		this.position = position;
+		this.videoData = videoData;
+		this.keyFrame = keyFrame;
+		this.hasChanged = hasChanged;
+		timestamp = System.currentTimeMillis();
+	}
+	
+	public int getPosition() {
+		return position;
+	}
+	
+	public byte[] getVideoData() {
+		return videoData;
+	}
+
+	public boolean isKeyFrame() {
+		return keyFrame;
+	}	
+	
+	public long getTimestamp() {
+		return timestamp;
+	}
+	
+	public boolean hasChanged() {
+		return hasChanged;
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/FileScreenCaptureSender.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/FileScreenCaptureSender.java
new file mode 100644
index 0000000000000000000000000000000000000000..6b11d732a545787412bddfae5f4b1420c777a113
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/FileScreenCaptureSender.java
@@ -0,0 +1,69 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.bigbluebutton.deskshare.client.encoder.FlvEncodeException;
+import org.bigbluebutton.deskshare.client.encoder.ScreenVideoFlvEncoder;
+
+public class FileScreenCaptureSender implements ScreenCaptureSender {
+
+	private FileOutputStream fo;
+	private ScreenVideoFlvEncoder svf = new ScreenVideoFlvEncoder();
+	
+	public void connect(String host, String room, int width, int height) throws ConnectionException {
+    	try {
+			fo = new FileOutputStream("D://temp/"+"ScreenVideo.flv");
+			
+			fo.write(svf.encodeHeader());
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new ConnectionException("Failed to open file.");
+		}
+	}
+
+	public void disconnect() throws ConnectionException {
+    	try {
+    		System.out.println("Closing stream");
+			fo.close();
+		} catch (IOException e) {
+			e.printStackTrace();
+			throw new ConnectionException("Fail to clode file.");
+		}
+	}
+
+	public void send(ByteArrayOutputStream videoData, boolean isKeyFrame) throws ConnectionException {
+		try {
+			fo.write(svf.encodeFlvData(videoData));
+		} catch (IOException e) {
+			e.printStackTrace();
+			throw new ConnectionException("Fail to write to file.");
+		} catch (FlvEncodeException e) {
+			e.printStackTrace();
+			throw new ConnectionException("Fail to encode FLV.");
+		}
+	}
+
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/HttpScreenCaptureSender.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/HttpScreenCaptureSender.java
new file mode 100644
index 0000000000000000000000000000000000000000..dcf6e4063c402784b89cb6a6d3436dc44a154301
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/HttpScreenCaptureSender.java
@@ -0,0 +1,199 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.bigbluebutton.deskshare.common.CaptureEvents;
+
+import com.myjavatools.web.ClientHttpRequest;
+
+public class HttpScreenCaptureSender implements ScreenCaptureSender {
+	private String host = "localhost";
+	private String room;
+	private int videoWidth;
+	private int videoHeight;
+	private int frameRate;
+	private static final String SCREEN_CAPTURE__URL = "/deskshare/tunnel/screenCapture";
+	private URL url;
+	URLConnection conn;
+	private String videoInfo;
+
+	private BlockingQueue<ScreenVideo> screenQ = new LinkedBlockingQueue<ScreenVideo>();
+	private final Executor exec = Executors.newSingleThreadExecutor();
+	private Runnable capturedScreenSender;
+	private volatile boolean sendCapturedScreen = false;	
+	
+	public void connect(String host, String room, int width, int height) throws ConnectionException {
+		this.host = host;
+		this.room = room;
+		this.videoWidth = videoWidth;
+		this.videoHeight = videoHeight;
+				
+		openConnection();
+		sendCaptureStartEvent();
+
+/*
+		System.out.println("Starting capturedScreenSender ");
+		sendCapturedScreen = true;
+		capturedScreenSender = new Runnable() {
+			public void run() {
+				while (sendCapturedScreen) {
+					try {
+						System.out.println("ScreenQueue size " + screenQ.size());
+						ScreenVideo newScreen = screenQ.take();
+						try {
+							sendCapturedScreen(newScreen);
+						} catch (ConnectionException e) {
+							// TODO Auto-generated catch block
+							e.printStackTrace();
+						}
+					} catch (InterruptedException e) {
+						System.out.println("InterruptedExeption while taking event.");
+					}
+				}
+			}
+		};
+		exec.execute(capturedScreenSender);	
+*/
+	}
+
+	private void sendCapturedScreen(ScreenVideo video) throws ConnectionException {
+
+			long snapshotTime = System.currentTimeMillis();
+			ByteArrayOutputStream videoData = video.getVideoData();
+			openConnection();
+			sendVideoData(videoData, video.isKeyFrame());
+			long completeTime = System.currentTimeMillis();
+			System.out.println("Sending took " + (completeTime - snapshotTime) + "ms.");
+
+	}
+	
+	private void openConnection() throws ConnectionException {
+		/**
+		 * Need to re-establish connection each time, otherwise, 
+		 * we get java.net.ProtocolException: Cannot write output after reading input.
+		 * 
+		 * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4382944
+		 * 
+		 */				
+		try {
+			url = new URL("http://" + host + SCREEN_CAPTURE__URL);
+			conn = url.openConnection();
+		} catch (MalformedURLException e) {
+			e.printStackTrace();
+			throw new ConnectionException("MalformedURLException " + url.toString());
+		} catch (IOException e) {
+			e.printStackTrace();
+			throw new ConnectionException("IOException while connecting to " + url.toString());
+		}
+	}
+	
+	private void sendCaptureStartEvent() throws ConnectionException {
+		ClientHttpRequest chr;
+		try {
+			chr = new ClientHttpRequest(conn);
+			chr.setParameter("room", room);
+			
+			videoInfo = Integer.toString(videoWidth)
+								+ "x" + Integer.toString(videoHeight);
+			//					+ "x" + Integer.toString(frameRate);
+			//StringBuilder sb = new StringBuilder(videoWidth);
+			//sb.append("x").append(videoHeight);
+
+			chr.setParameter("videoInfo", videoInfo);
+			chr.setParameter("event", CaptureEvents.CAPTURE_START.getEvent());
+			chr.post();
+		} catch (IOException e) {
+			e.printStackTrace();
+			throw new ConnectionException("IOException while sending capture start event.");
+		}
+
+	}
+	
+	public void disconnect() throws ConnectionException {
+		openConnection();
+		sendCaptureEndEvent();
+	}
+
+	private void sendCaptureEndEvent() throws ConnectionException {
+		ClientHttpRequest chr;
+		try {
+			chr = new ClientHttpRequest(conn);
+			chr.setParameter("room", room);
+			
+			chr.setParameter("event", CaptureEvents.CAPTURE_END.getEvent());
+			chr.post();
+		} catch (IOException e) {
+			e.printStackTrace();
+			throw new ConnectionException("IOException while sending capture end event.");
+		}
+	}
+	
+	public void send(ByteArrayOutputStream videoData, boolean isKeyFrame) throws ConnectionException {
+/*
+		ScreenVideo sv = new ScreenVideo(videoData, isKeyFrame);
+		try {
+			screenQ.put(sv);
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}
+*/
+		long snapshotTime = System.currentTimeMillis();
+		openConnection();
+		sendVideoData(videoData, isKeyFrame);
+		long completeTime = System.currentTimeMillis();
+		System.out.println("Sending took " + (completeTime - snapshotTime) + "ms.");
+	}
+	
+	private void sendVideoData(ByteArrayOutputStream videoData, boolean isKeyFrame) throws ConnectionException {
+	    ClientHttpRequest chr;
+		try {
+			chr = new ClientHttpRequest(conn);
+		    chr.setParameter("room", room);
+		    
+		    chr.setParameter("event", CaptureEvents.CAPTURE_UPDATE.getEvent());
+		    chr.setParameter("keyframe", isKeyFrame);
+		    
+			ByteArrayInputStream cap = new ByteArrayInputStream(videoData.toByteArray());
+				
+			chr.setParameter("videodata", "screen", cap);
+			System.out.println("Video data length = " + videoData.toByteArray().length);
+			
+			chr.post();		
+		} catch (IOException e) {
+			e.printStackTrace();
+			throw new ConnectionException("IOException while sending video data.");
+		}
+
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/NetworkHttpStreamSender.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/NetworkHttpStreamSender.java
new file mode 100644
index 0000000000000000000000000000000000000000..07ccfac63a7345b930d8557fb7f0cba14c92c870
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/NetworkHttpStreamSender.java
@@ -0,0 +1,177 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.bigbluebutton.deskshare.client.blocks.Block;
+import org.bigbluebutton.deskshare.common.CaptureEvents;
+import org.bigbluebutton.deskshare.common.Dimension;
+
+import com.myjavatools.web.ClientHttpRequest;
+
+public class NetworkHttpStreamSender implements Runnable {
+	private String host = "localhost";
+	private static final String SCREEN_CAPTURE__URL = "/deskshare/tunnel/screenCapture";
+	private URL url;
+	URLConnection conn;
+	private String room;
+	private final NextBlockRetriever retriever;
+	private volatile boolean processBlocks = false;
+
+	
+	public NetworkHttpStreamSender(NextBlockRetriever retriever) {
+		this.retriever = retriever;
+	}
+	
+	public void connect(String host) throws ConnectionException {
+		this.host = host;
+		System.out.println("Starting NetworkHttpStreamSender to " + host);
+		openConnection();
+	}
+
+	private void openConnection() throws ConnectionException {
+		/**
+		 * Need to re-establish connection each time, otherwise, 
+		 * we get java.net.ProtocolException: Cannot write output after reading input.
+		 * 
+		 * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4382944
+		 * 
+		 */				
+		try {			
+			url = new URL("http://" + host + SCREEN_CAPTURE__URL);
+			conn = url.openConnection();
+		} catch (MalformedURLException e) {
+			e.printStackTrace();
+			throw new ConnectionException("MalformedURLException " + url.toString());
+		} catch (IOException e) {
+			e.printStackTrace();
+			throw new ConnectionException("IOException while connecting to " + url.toString());
+		}
+	}
+	
+	public void sendStartStreamMessage(String room, Dimension screen, Dimension block) {
+		this.room = room;
+		try {
+			openConnection();
+			sendCaptureStartEvent(screen, block);
+		} catch (ConnectionException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
+	private void sendCaptureStartEvent(Dimension screen, Dimension block) throws ConnectionException {
+		ClientHttpRequest chr;
+		try {
+			chr = new ClientHttpRequest(conn);
+			chr.setParameter("room", room);
+			
+			String screenInfo = Integer.toString(screen.getWidth())
+								+ "x" + Integer.toString(screen.getHeight());
+
+			chr.setParameter("screenInfo", screenInfo);
+			
+			String blockInfo = Integer.toString(block.getWidth())
+								+ "x" + Integer.toString(block.getHeight());
+
+			chr.setParameter("blockInfo", blockInfo);
+
+			chr.setParameter("event", CaptureEvents.CAPTURE_START.getEvent());
+			chr.post();
+		} catch (IOException e) {
+			e.printStackTrace();
+			throw new ConnectionException("IOException while sending capture start event.");
+		}
+
+	}
+	
+	public void disconnect() throws ConnectionException {
+		try {
+			openConnection();
+			sendCaptureEndEvent();
+		} catch (ConnectionException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+			throw e;
+		} finally {
+			processBlocks = false;
+		}
+	}
+
+	private void sendCaptureEndEvent() throws ConnectionException {
+		System.out.println("Disconnecting http stream");
+		ClientHttpRequest chr;
+		try {
+			chr = new ClientHttpRequest(conn);
+			chr.setParameter("room", room);
+			
+			chr.setParameter("event", CaptureEvents.CAPTURE_END.getEvent());
+			chr.post();
+		} catch (IOException e) {
+			e.printStackTrace();
+			throw new ConnectionException("IOException while sending capture end event.");
+		}
+	}
+	
+	public void run() {
+		processBlocks = true;
+		
+		while (processBlocks) {
+			Block block = retriever.fetchNextBlockToSend();
+			EncodedBlockData ebd = block.encode();
+			if (ebd.hasChanged()) {					
+				BlockVideoData	bv = new BlockVideoData(room, ebd.getPosition(), ebd.getVideoData(), ebd.isKeyFrame());	
+				
+				sendBlockData(bv);
+			}						
+		}
+	}
+	
+	private void sendBlockData(BlockVideoData blockData) {
+	    ClientHttpRequest chr;
+		try {
+			openConnection();
+			chr = new ClientHttpRequest(conn);
+		    chr.setParameter("room", blockData.getRoom());
+		    chr.setParameter("position", blockData.getPosition());
+		    chr.setParameter("keyframe", blockData.isKeyFrame());
+		    chr.setParameter("event", CaptureEvents.CAPTURE_UPDATE.getEvent());
+			ByteArrayInputStream block = new ByteArrayInputStream(blockData.getVideoData());
+				
+			chr.setParameter("blockdata", "block", block);
+			chr.post();		
+		} catch (IOException e) {
+			e.printStackTrace();
+		} catch (ConnectionException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}	
+	
+	
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/NetworkSocketStreamSender.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/NetworkSocketStreamSender.java
new file mode 100644
index 0000000000000000000000000000000000000000..fcb863eb342f677cadb1172c3ce799a0f501eb99
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/NetworkSocketStreamSender.java
@@ -0,0 +1,133 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import org.bigbluebutton.deskshare.client.blocks.Block;
+import org.bigbluebutton.deskshare.common.Dimension;
+
+public class NetworkSocketStreamSender implements Runnable {
+	private static final int PORT = 9123;
+	
+	private Socket socket = null;
+	
+	private DataOutputStream outstream = null;
+	private String room;
+	private Dimension screenDim;
+	private Dimension blockDim;
+	private final NextBlockRetriever retriever;
+	private volatile boolean processBlocks = false;
+	
+	public NetworkSocketStreamSender(NextBlockRetriever retriever) {
+		this.retriever = retriever;
+	}
+	
+	public void connect(String host) throws ConnectionException {
+		System.out.println("Starting NetworkSocketStreamSender ");
+		try {
+			socket = new Socket(host, PORT);
+			outstream = new DataOutputStream(socket.getOutputStream());
+		} catch (UnknownHostException e) {
+			e.printStackTrace();
+			throw new ConnectionException("UnknownHostException: " + host);
+		} catch (IOException e) {
+			e.printStackTrace();
+			throw new ConnectionException("IOException: " + host + ":" + PORT);
+		}
+	}
+	
+	public void sendStartStreamMessage(String room, Dimension screen, Dimension block) {
+		this.room = room;
+		screenDim = screen;
+		blockDim = block;
+		try {
+			ByteArrayOutputStream dataToSend = new ByteArrayOutputStream();
+			dataToSend.reset();
+			BlockStreamProtocolEncoder.encodeStartStreamMessage(room, screenDim, blockDim, dataToSend);
+			sendHeader(BlockStreamProtocolEncoder.encodeHeaderAndLength(dataToSend));
+			sendToStream(dataToSend);
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	private void sendBlock(BlockVideoData block) {
+		long start = System.currentTimeMillis();
+		try {
+			ByteArrayOutputStream dataToSend = new ByteArrayOutputStream();
+			dataToSend.reset();
+			BlockStreamProtocolEncoder.encodeBlock(block, dataToSend);
+			sendHeader(BlockStreamProtocolEncoder.encodeHeaderAndLength(dataToSend));
+			sendToStream(dataToSend);
+			long end = System.currentTimeMillis();
+			if ((end - start) > 200)
+				System.out.println("Sending " + dataToSend.size() + " bytes took " + (end - start) + "ms");
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+
+	}
+	
+	private void sendHeader(byte[] header) throws IOException {
+		outstream.write(header);
+	}
+	
+	private void sendToStream(ByteArrayOutputStream dataToSend) throws IOException {
+		dataToSend.writeTo(outstream);
+	}
+	
+	public void disconnect() throws ConnectionException {
+		System.out.println("Disconnecting socket stream");
+		try {
+			ByteArrayOutputStream dataToSend = new ByteArrayOutputStream();
+			dataToSend.reset();
+			BlockStreamProtocolEncoder.encodeEndStreamMessage(room, dataToSend);
+			sendHeader(BlockStreamProtocolEncoder.encodeHeaderAndLength(dataToSend));
+			sendToStream(dataToSend);
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} finally {
+			processBlocks = false;
+		}
+	}
+
+	public void run() {
+		processBlocks = true;		
+		while (processBlocks) {
+			Block block = retriever.fetchNextBlockToSend();
+			EncodedBlockData ebd = block.encode();
+			if (ebd.hasChanged()) {					
+				BlockVideoData	bv = new BlockVideoData(room, ebd.getPosition(), ebd.getVideoData(), ebd.isKeyFrame());	
+				sendBlock(bv);
+			}						
+		}
+
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/NetworkStreamSender.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/NetworkStreamSender.java
new file mode 100644
index 0000000000000000000000000000000000000000..9b09b838d751ff58a6c366f48f3c9de9dc79eb84
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/NetworkStreamSender.java
@@ -0,0 +1,136 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+import java.util.Map;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import net.jcip.annotations.GuardedBy;
+import net.jcip.annotations.ThreadSafe;
+
+import org.bigbluebutton.deskshare.client.blocks.Block;
+import org.bigbluebutton.deskshare.client.blocks.BlockManager;
+
+@ThreadSafe
+public class NetworkStreamSender implements NextBlockRetriever {	
+	private BlockManager blockManager;
+	private ExecutorService executor;
+	
+	@GuardedBy("this") private int nextBlockToSend = 1;
+    private final Map<Integer, Block> blocksMap;
+    private final int numThreads;
+    private final String host;
+    private final String room;
+    private NetworkSocketStreamSender[] senders;
+    private NetworkHttpStreamSender httpSender;
+    private boolean tunneling = false;
+    private int numRunningThreads = 0;
+    
+	public NetworkStreamSender(BlockManager blockManager, String host, String room) {
+		this.blockManager = blockManager;
+		blocksMap = blockManager.getBlocks();
+		this.host = host;
+		this.room = room;
+		
+		numThreads = Runtime.getRuntime().availableProcessors();
+		System.out.println("Starting up " + numThreads + " sender threads.");
+		executor = Executors.newFixedThreadPool(numThreads);
+	}
+	
+	public boolean connect() {	
+		senders = new NetworkSocketStreamSender[numThreads];
+		int failedAttempts = 0;
+		for (int i = 0; i < numThreads; i++) {
+			try {
+				createSender(i);
+				numRunningThreads++;
+			} catch (ConnectionException e) {
+				failedAttempts++;
+			}
+		}
+		
+		if (failedAttempts == numThreads) {
+			System.out.println("Trying http tunneling");
+			if (tryHttpTunneling()) {
+				tunneling = true;
+				return true;
+			}
+		} else {
+			return true;
+		}
+		System.out.println("Http tunneling failed.");
+		return false;
+	}
+	
+	private void createSender(int i) throws ConnectionException {
+		senders[i] = new NetworkSocketStreamSender(this);
+		senders[i].connect(host);		
+	}
+	
+	public void start() {
+		if (tunneling) {
+			httpSender.sendStartStreamMessage(room, blockManager.getScreenDim(), blockManager.getBlockDim());
+			executor.execute(httpSender);
+		} else {
+			for (int i = 0; i < numRunningThreads; i++) {
+				senders[i].sendStartStreamMessage(room, blockManager.getScreenDim(), blockManager.getBlockDim());
+				executor.execute(senders[i]);
+			}	
+		}
+	}
+	
+	public void stop() throws ConnectionException {
+		System.out.println("Stopping network sender");
+		if (tunneling) {
+			httpSender.disconnect();
+		} else {
+			for (int i = 0; i < numRunningThreads; i++) {
+				senders[i].disconnect();
+			}				
+		}
+	
+		executor.shutdownNow();
+	}
+
+	private boolean tryHttpTunneling() {
+		httpSender = new NetworkHttpStreamSender(this);
+		try {
+			httpSender.connect(host);
+			return true;
+		} catch (ConnectionException e) {
+			System.out.println("Problem connecting to " + host);
+		}
+		return false;
+	}
+	
+	public Block fetchNextBlockToSend() {
+		synchronized(this) {
+			//Block block = blocksMap.get(new Integer(nextBlockToSend));
+			Block block = blockManager.getBlock(nextBlockToSend);
+//			System.out.println("Fetched block " + nextBlockToSend);
+			nextBlockToSend++;
+			if (nextBlockToSend > blocksMap.size()) nextBlockToSend = 1;
+			return block;
+		}
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/NextBlockRetriever.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/NextBlockRetriever.java
new file mode 100644
index 0000000000000000000000000000000000000000..3894e2b141253bf45fa96da3ac3ba8ad9c4ec91a
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/NextBlockRetriever.java
@@ -0,0 +1,29 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+import org.bigbluebutton.deskshare.client.blocks.Block;
+
+public interface NextBlockRetriever {
+
+	public Block fetchNextBlockToSend();
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/ScreenCaptureSender.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/ScreenCaptureSender.java
new file mode 100644
index 0000000000000000000000000000000000000000..f78e9462bb699ea8fe3c804fca1ef98b79e08e66
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/ScreenCaptureSender.java
@@ -0,0 +1,32 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+import java.io.ByteArrayOutputStream;
+
+public interface ScreenCaptureSender {
+
+	public void connect(String host, String room, int width, int height) throws ConnectionException;
+	public void send(ByteArrayOutputStream pixelData, boolean isKeyFrame) throws ConnectionException;
+	public void disconnect() throws ConnectionException;
+	
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/ScreenVideo.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/ScreenVideo.java
new file mode 100644
index 0000000000000000000000000000000000000000..d306194f49ff389fa5bf249a53acc113bf25e42b
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/ScreenVideo.java
@@ -0,0 +1,43 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+import java.io.ByteArrayOutputStream;
+
+public class ScreenVideo {
+
+	private ByteArrayOutputStream videoData;
+	private boolean isKeyFrame;
+	
+	public ScreenVideo(ByteArrayOutputStream videoData, boolean isKeyFrame) {
+		this.videoData = videoData;
+		this.isKeyFrame = isKeyFrame;		
+	}
+	
+	public ByteArrayOutputStream getVideoData() {
+		return videoData;
+	}
+	
+	public boolean isKeyFrame() {
+		return isKeyFrame;
+	}
+}
diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/SocketScreenVideoSender.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/SocketScreenVideoSender.java
new file mode 100644
index 0000000000000000000000000000000000000000..de89058b6b5fb5937b45442276b60c53f080c7da
--- /dev/null
+++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/SocketScreenVideoSender.java
@@ -0,0 +1,180 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.bigbluebutton.deskshare.common.CaptureEvents;
+
+public class SocketScreenVideoSender implements ScreenCaptureSender {
+	
+	private static final int PORT = 9123;
+	
+	private Socket socket = null;
+	
+	private DataOutputStream outStream = null;
+	private String room;
+	private int width, height;
+	
+	private BlockingQueue<ScreenVideo> screenQ = new LinkedBlockingQueue<ScreenVideo>(2);
+	private final Executor exec = Executors.newSingleThreadExecutor();
+	private Runnable capturedScreenSender;
+	private volatile boolean sendCapturedScreen = false;
+	
+	private static final byte[] HEADER = new byte[] {0x42, 0x42, 0x42, 0x2D, 0x44, 0x53}; /* BBB-DS */
+	
+	public void connect(String host, String room, int width, int height) throws ConnectionException {
+		this.room = room;
+		this.width = width;
+		this.height = height;
+		
+		try {
+			socket = new Socket(host, PORT);
+			outStream = new DataOutputStream(socket.getOutputStream());
+			sendHeaderEventAndRoom(CaptureEvents.CAPTURE_START.getEvent());
+			sendScreenCaptureInfo(width, height);
+			outStream.flush();
+		} catch (UnknownHostException e) {
+			e.printStackTrace();
+			throw new ConnectionException("UnknownHostException: " + host);
+		} catch (IOException e) {
+			e.printStackTrace();
+			throw new ConnectionException("IOException: " + host + ":" + PORT);
+		}
+
+		System.out.println("Starting capturedScreenSender ");
+		sendCapturedScreen = true;
+		capturedScreenSender = new Runnable() {
+			public void run() {
+				while (sendCapturedScreen) {
+					try {
+						//System.out.println("ScreenQueue size " + screenQ.size());
+						ScreenVideo newScreen = screenQ.take();
+						try {
+							sendCapturedScreen(newScreen);
+						} catch (ConnectionException e) {
+							// TODO Auto-generated catch block
+							e.printStackTrace();
+						}
+					} catch (InterruptedException e) {
+						System.out.println("InterruptedExeption while taking event.");
+					}
+				}
+			}
+		};
+		exec.execute(capturedScreenSender);
+	
+	}
+	
+	private void sendScreenCaptureInfo(int videoWidth, int videoHeight) throws IOException {
+		String videoInfo = Integer.toString(videoWidth)	+ "x" + Integer.toString(videoHeight);
+		System.out.println("Sending video info " + videoInfo);
+		outStream.writeInt(videoInfo.length());
+		outStream.writeBytes(videoInfo);
+	}
+	
+	private void sendCapturedScreen(ScreenVideo video) throws ConnectionException {
+
+		try {
+			long snapshotTime = System.currentTimeMillis();
+			ByteArrayOutputStream videoData = video.getVideoData();
+			sendHeaderEventAndRoom(CaptureEvents.CAPTURE_UPDATE.getEvent());
+			sendKeyFrame(video.isKeyFrame());
+			System.out.println("Sending videoData [length=" + videoData.size() + ", keyframe=" + video.isKeyFrame() + "]");
+			sendDataLength(videoData.size());
+			sendData(videoData);
+			outStream.flush();
+			long completeTime = System.currentTimeMillis();
+			System.out.println("Sending took " + (completeTime - snapshotTime) + "ms.");
+		} catch (IOException e) {
+			e.printStackTrace();
+			throw new ConnectionException("IOException while sending video data.");
+		}
+
+	}
+	
+	public void send(ByteArrayOutputStream videoData, boolean isKeyFrame) throws ConnectionException {
+
+		ScreenVideo sv = new ScreenVideo(videoData, isKeyFrame);
+		try {
+			screenQ.put(sv);
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}
+
+/*
+		try {
+			long snapshotTime = System.currentTimeMillis();
+			sendHeaderEventAndRoom(CaptureEvents.CAPTURE_UPDATE.getEvent());
+			sendKeyFrame(isKeyFrame);
+			System.out.println("Sending videoData [" + videoData.size() + "," + isKeyFrame + "]");
+			sendDataLength(videoData.size());
+			sendData(videoData);
+			long completeTime = System.currentTimeMillis();
+			System.out.println("Sending took " + (completeTime - snapshotTime) + "ms.");
+		} catch (IOException e) {
+			e.printStackTrace();
+			throw new ConnectionException("IOException while sending video data.");
+		}
+*/
+	}
+
+	private void sendHeaderEventAndRoom(int event) throws IOException {
+		outStream.write(HEADER);
+		outStream.writeByte(event);
+		outStream.writeInt(room.length());
+		outStream.writeBytes(room);
+	}
+	
+	private void sendKeyFrame(boolean isKeyFrame) throws IOException {
+		outStream.writeBoolean(isKeyFrame);
+	}
+	
+	private void sendDataLength(int length) throws IOException {
+		outStream.writeInt(length);
+	}
+	
+	private void sendData(ByteArrayOutputStream pixels) throws IOException {
+		//outStream.write(pixels.toByteArray());
+		pixels.writeTo(outStream);
+	}
+	
+	public void disconnect() throws ConnectionException {
+		System.out.println("Closing connection.");
+		sendCapturedScreen = false;
+		try{
+			sendHeaderEventAndRoom(CaptureEvents.CAPTURE_END.getEvent());
+			socket.close();
+		} catch(IOException e){
+			e.printStackTrace(System.out);
+			throw new ConnectionException("IOException while disconnecting from server.");
+		}
+	}
+}
diff --git a/deskshare/applet/src/test/java/org/bigbluebutton/deskshare/client/encode/ScreenVideoFlvEncoderTest.java b/deskshare/applet/src/test/java/org/bigbluebutton/deskshare/client/encode/ScreenVideoFlvEncoderTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..20ebc7bed6fe7c00c45936f84deb0e4564141ca5
--- /dev/null
+++ b/deskshare/applet/src/test/java/org/bigbluebutton/deskshare/client/encode/ScreenVideoFlvEncoderTest.java
@@ -0,0 +1,48 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+
+package org.bigbluebutton.deskshare.client.encode;
+
+import org.bigbluebutton.deskshare.client.encoder.ScreenVideoFlvEncoder;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class ScreenVideoFlvEncoderTest {
+	
+	@BeforeMethod 
+	public void setUp() {
+		
+	}
+	
+	@Test
+	public void testEncodeFlvHeader() {
+		final byte[] flvHeaderPlusPrevTagSize = {'F','L','V',0x01,0x01,0x00,0x00,0x00,0x09,0,0,0,0};
+		ScreenVideoFlvEncoder svf = new ScreenVideoFlvEncoder();
+		
+		byte[] header = svf.encodeHeader();
+		Assert.assertEquals(header, flvHeaderPlusPrevTagSize);
+	}
+	
+
+	
+}
diff --git a/deskshare/applet/src/test/java/org/bigbluebutton/deskshare/client/encoder/ScreenVideoFlvEncoderTest.java b/deskshare/applet/src/test/java/org/bigbluebutton/deskshare/client/encoder/ScreenVideoFlvEncoderTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f806965953658fd2c071def7e11a26613817aeed
--- /dev/null
+++ b/deskshare/applet/src/test/java/org/bigbluebutton/deskshare/client/encoder/ScreenVideoFlvEncoderTest.java
@@ -0,0 +1,48 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+
+package org.bigbluebutton.deskshare.client.encoder;
+
+import org.bigbluebutton.deskshare.client.encoder.ScreenVideoFlvEncoder;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class ScreenVideoFlvEncoderTest {
+	
+	@BeforeMethod 
+	public void setUp() {
+		
+	}
+	
+	@Test
+	public void testEncodeFlvHeader() {
+		final byte[] flvHeaderPlusPrevTagSize = {'F','L','V',0x01,0x01,0x00,0x00,0x00,0x09,0,0,0,0};
+		ScreenVideoFlvEncoder svf = new ScreenVideoFlvEncoder();
+		
+		byte[] header = svf.encodeHeader();
+		Assert.assertEquals(header, flvHeaderPlusPrevTagSize);
+	}
+	
+
+	
+}
diff --git a/deskshare/applet/src/test/java/org/bigbluebutton/deskshare/client/net/BlockStreamProtocolEncoderTest.java b/deskshare/applet/src/test/java/org/bigbluebutton/deskshare/client/net/BlockStreamProtocolEncoderTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3604c79a5c37bbd642b0d99a9bcb0172cc38547
--- /dev/null
+++ b/deskshare/applet/src/test/java/org/bigbluebutton/deskshare/client/net/BlockStreamProtocolEncoderTest.java
@@ -0,0 +1,48 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.client.net;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.bigbluebutton.deskshare.common.Dimension;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class BlockStreamProtocolEncoderTest {
+	
+	@BeforeMethod 
+	public void setUp() {
+		
+	}
+	
+	@Test
+	public void testEncodeFlvHeader() throws IOException {
+		ByteArrayOutputStream data = new ByteArrayOutputStream();
+		data.reset();
+		BlockStreamProtocolEncoder.encodeStartStreamMessage("testroom", new Dimension(64,64), new Dimension(32,32), data);
+		Assert.assertEquals(data.size(), 26);
+//		BlockStreamProtocolEncoder.encodeHeaderAndLength(data);
+		
+	}
+}
diff --git a/deskshare/applet/tstcert.crt b/deskshare/applet/tstcert.crt
new file mode 100644
index 0000000000000000000000000000000000000000..b3c6a7657645c50d8dd5396bbb5a7f44769ca3df
Binary files /dev/null and b/deskshare/applet/tstcert.crt differ
diff --git a/deskshare/build.gradle b/deskshare/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..2727b858156a52c3975aca2721d936facae2ea0b
--- /dev/null
+++ b/deskshare/build.gradle
@@ -0,0 +1,62 @@
+usePlugin 'java'
+usePlugin 'eclipse'
+
+task copyToLib(dependsOn: configurations.default.buildArtifacts, type: Copy) {
+    into('lib')
+    from configurations.default
+    from configurations.default.allArtifacts*.file
+}
+
+dependencies {	  
+    compile ':log4j-over-slf4j:1.5.6@jar', 'spring:spring-web:2.5.6@jar', 'javax.servlet:servlet-api:2.5@jar', 'org.apache.mina:mina-core:2.0.0-M6@jar'
+    compile 'spring:spring-aop:2.5.6@jar', 'spring:spring-beans:2.5.6@jar', 'spring:spring-context:2.5.6@jar', 'spring:spring-core:2.5.6@jar'
+	compile 'org/red5:red5:0.8@jar' 
+    compile 'commons-fileupload:commons-fileupload:1.2.1@jar', 'commons-io:commons-io:1.4@jar' 
+    compile ':logback-core:0.9.14@jar', ':logback-classic:0.9.14@jar', ':slf4j-api:1.5.6@jar'
+    compile 'spring:spring-webmvc:2.5.6@jar', 'org.apache.mina:mina-integration-spring:1.1.7@jar'
+	compile 'org.testng:testng:5.8@jar', 'net/jcip:jcip-annotations:1.0@jar'  
+}
+      
+subprojects {
+    usePlugin 'java'
+    usePlugin 'eclipse'
+
+    repositories {
+    	add(new org.apache.ivy.plugins.resolver.ChainResolver()) {
+        	name = 'remote'
+        	returnFirst = true
+        	add(new org.apache.ivy.plugins.resolver.URLResolver()) {
+        		name = "googlecode"
+        		addArtifactPattern "http://red5.googlecode.com/svn/repository/[artifact](-[revision]).[ext]"
+        		addArtifactPattern "http://red5.googlecode.com/svn/repository/[organisation]/[artifact](-[revision]).[ext]"
+			}
+	       	add(new org.apache.ivy.plugins.resolver.URLResolver()) {
+        		name = "blindside-repos"
+        		addArtifactPattern "http://blindside.googlecode.com/svn/repository/[artifact](-[revision]).[ext]"
+        		addArtifactPattern "http://blindside.googlecode.com/svn/repository/[organisation]/[artifact](-[revision]).[ext]"
+			}			 
+        	add(new org.apache.ivy.plugins.resolver.URLResolver()) {
+        		name = "maven2-central"
+        		m2compatible = true
+        		addArtifactPattern "http://repo1.maven.org/maven2/[organisation]/[module]/[revision]/[artifact](-[revision]).[ext]"
+        		addArtifactPattern "http://repo1.maven.org/maven2/[organisation]/[artifact]/[revision]/[artifact](-[revision]).[ext]"
+			}  
+        	add(new org.apache.ivy.plugins.resolver.URLResolver()) {
+        		name = "testng_ibiblio_maven2"
+        		m2compatible = true
+        		addArtifactPattern "http://repo1.maven.org/maven2/[organisation]/[module]/[revision]/[artifact](-[revision])-jdk15.[ext]"
+        		addArtifactPattern "http://repo1.maven.org/maven2/[organisation]/[artifact]/[revision]/[artifact](-[revision])-jdk15.[ext]"
+			}  
+    	}
+    }
+
+    dependencies {
+        testCompile 'org.testng:testng:5.8'
+    }
+
+    group = 'org.bigbluebutton'
+    version = '0.62'
+    manifest.mainAttributes(provider: 'bigbluebutton')
+}
+
+dependsOnChildren()
diff --git a/deskshare/common/build.gradle b/deskshare/common/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..0e18ceb9a7a92d36f888a27ea98bf08206761dd7
--- /dev/null
+++ b/deskshare/common/build.gradle
@@ -0,0 +1,2 @@
+
+archivesBaseName = 'bbb-deskshare-common'
\ No newline at end of file
diff --git a/deskshare/common/src/main/java/org/bigbluebutton/deskshare/common/CaptureEvents.java b/deskshare/common/src/main/java/org/bigbluebutton/deskshare/common/CaptureEvents.java
new file mode 100644
index 0000000000000000000000000000000000000000..e058456b9cdc7a247beb5876462c93e6a558b5b6
--- /dev/null
+++ b/deskshare/common/src/main/java/org/bigbluebutton/deskshare/common/CaptureEvents.java
@@ -0,0 +1,54 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.common;
+
+public enum CaptureEvents {
+	/**
+	 * WARNING: Must match corresponding values with deskshare-app on the server.
+	 * org.bigbluebutton.deskshare.CaptureEvents
+	 */
+	CAPTURE_START(0), CAPTURE_UPDATE(1), CAPTURE_END(2);
+	
+	private final int event;
+	
+	CaptureEvents(int event) {
+		this.event = event;
+	}
+	
+	public int getEvent() {
+		return event;
+	}
+	
+	@Override
+	public String toString() {
+		switch (event) {
+		case 0:
+			return "Capture Start Event";
+		case 1:
+			return "Capture Update Event";
+		case 2: 
+			return "Capture End Event";
+		}
+		
+		return "Unknown Capture Event";
+	}
+}
diff --git a/deskshare/common/src/main/java/org/bigbluebutton/deskshare/common/Dimension.java b/deskshare/common/src/main/java/org/bigbluebutton/deskshare/common/Dimension.java
new file mode 100644
index 0000000000000000000000000000000000000000..52ffd64277cb53ebeced28d271d0d5420b31ca22
--- /dev/null
+++ b/deskshare/common/src/main/java/org/bigbluebutton/deskshare/common/Dimension.java
@@ -0,0 +1,43 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.common;
+
+public final class Dimension {
+
+	private final int width;
+	private final int height;
+	
+	public Dimension(int width, int height) {
+		this.width = width;
+		this.height = height;
+	}
+
+	public int getWidth() {
+		return width;
+	}
+
+	public int getHeight() {
+		return height;
+	}
+
+	
+}
diff --git a/deskshare/common/src/main/java/org/bigbluebutton/deskshare/common/PixelExtractException.java b/deskshare/common/src/main/java/org/bigbluebutton/deskshare/common/PixelExtractException.java
new file mode 100644
index 0000000000000000000000000000000000000000..c637c0251476ad47c65ae139901f35eb6241bc4e
--- /dev/null
+++ b/deskshare/common/src/main/java/org/bigbluebutton/deskshare/common/PixelExtractException.java
@@ -0,0 +1,31 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.common;
+
+public class PixelExtractException extends Exception {
+
+	private static final long serialVersionUID = -8836714569259091334L;
+
+	public PixelExtractException(String message) {
+		super(message);
+	}
+}
diff --git a/deskshare/common/src/main/java/org/bigbluebutton/deskshare/common/ScreenVideoEncoder.java b/deskshare/common/src/main/java/org/bigbluebutton/deskshare/common/ScreenVideoEncoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..5956ccccf88df19aae6cf8b28b36fd1a5a250d50
--- /dev/null
+++ b/deskshare/common/src/main/java/org/bigbluebutton/deskshare/common/ScreenVideoEncoder.java
@@ -0,0 +1,233 @@
+/*
+ * BigBlueButton - http://www.bigbluebutton.org
+ * 
+ * Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+ * 
+ * BigBlueButton is free software; you can redistribute it and/or modify it under the 
+ * terms of the GNU Affero General Public License as published by the Free Software 
+ * Foundation; either version 3 of the License, or (at your option) any later 
+ * version. 
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License along 
+ * with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard Alam <ritzalam@gmail.com>
+ *
+ * $Id: $x
+ */
+package org.bigbluebutton.deskshare.common;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.util.zip.Deflater;
+
+public final class ScreenVideoEncoder {
+
+	private static byte FLV_KEYFRAME = 0x10;
+	private static byte FLV_INTERFRAME = 0x20;
+	private static byte SCREEN_VIDEO_CODEC_ID = 0x03;
+	
+	public static int[] getPixelsFromImage(BufferedImage image) {
+		int[] picpixels = ((DataBufferInt)(image).getRaster().getDataBuffer()).getData();
+		
+		return picpixels;
+	}
+	
+	public static byte encodeFlvVideoDataHeader(boolean isKeyFrame) {
+		if (isKeyFrame) return (byte) (FLV_KEYFRAME + SCREEN_VIDEO_CODEC_ID);
+		return (byte) (FLV_INTERFRAME + SCREEN_VIDEO_CODEC_ID);		
+	}
+	
+	public static byte[] encodeBlockAndScreenDimensions(int blockWidth, int imageWidth, int blockHeight, int imageHeight) {
+		byte[] dims = new byte[4];
+		
+		int bw = (((blockWidth/16) - 1) & 0xf) << 12;
+		int iw = (imageWidth & 0xfff);
+		int ew = (bw | iw);
+		
+		int bh = (((blockHeight/16) - 1) & 0xf) << 12;
+		int ih = (imageHeight & 0xfff);
+		int eh = (bh | ih);
+		
+		dims[0] = (byte) ((ew & 0xff00) >> 8);
+		dims[1] = (byte) (ew & 0xff);
+		dims[2] = (byte) ((eh & 0xff00) >> 8);
+		dims[3] = (byte) (eh & 0xff);
+		
+		return dims;
+	}
+	
+	public static int[] getPixels(BufferedImage image, int x, int y, int width, int height) throws PixelExtractException {
+		long start = System.currentTimeMillis();
+
+		/* Use this!!! Fast!!! (ralam Oct. 14, 2009) */
+		int[] pixels = image.getRGB(x, y, width, height, null, 0, width);
+		
+		/* DO NOT user this. Slow. 10 times slower than the other one. */
+/*		
+		PixelGrabber pg = new PixelGrabber(image, x, y, width, height, pixels, 0, width);
+		try {
+		    pg.grabPixels();
+		} catch (InterruptedException e) {
+		    throw new PixelExtractException("Interrupted waiting for pixels!");
+		}
+		if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
+		    throw new PixelExtractException("Aborted or error while fetching image.");
+		}
+*/
+		long end = System.currentTimeMillis();
+//		System.out.println("Grabbing pixels[" + pixels.length + "] took " + (end-start) + " ms.");
+		return pixels;	
+	}
+	
+	public static byte[] encodePixels(int pixels[], int width, int height, boolean isRedTile, boolean isKeyFrame) {
+		
+		changePixelScanFromBottomLeftToTopRight(pixels, width, height);
+		
+		byte[] bgrPixels = convertFromRGBtoBGR(pixels, isRedTile, isKeyFrame);
+		
+		byte[] compressedPixels = compressUsingZlib(bgrPixels);  
+		
+    	byte[] encodedDataLength = ScreenVideoEncoder.encodeCompressedPixelsDataLength(compressedPixels.length);
+    	byte[] encodedData = new byte[encodedDataLength.length + compressedPixels.length];
+    	
+    	System.arraycopy(encodedDataLength, 0, encodedData, 0, encodedDataLength.length);
+    	
+    	System.arraycopy(compressedPixels, 0, encodedData, encodedDataLength.length, compressedPixels.length);
+
+		return encodedData;
+	}
+	
+	private static byte[] encodeCompressedPixelsDataLength(int length) {
+		int byte1 =  ((length & 0xFF00) >> 8);
+		int byte2 =  (length & 0x0FFF);
+//		System.out.println("Block size = " + length + " hex=" + Integer.toHexString(length) + " bytes= " + Integer.toHexString(byte1) + " " + Integer.toHexString(byte2));
+		return new byte[] {(byte)byte1 , (byte) (byte2 &0xFFF) };
+	}
+	
+	public static byte[] encodeBlockUnchanged() {
+		return new byte[] { (byte) 0, (byte) 0 };
+	}
+	
+	/**
+	 * Screen capture pixels are arranged top-left to bottom-right. ScreenVideo encoding
+	 * expects pixels are arranged bottom-left to top-right.
+	 * @param pixels - contains pixels of the image
+	 * @param width - width of the image
+	 * @param height - height of the image
+	 */
+	private static void changePixelScanFromBottomLeftToTopRight(int[] pixels, int width, int height) {
+		int[] swap = new int[pixels.length];
+		
+		long start = System.currentTimeMillis();
+		for (int i = 0; i < height; i++) {
+			int sourcePos = i * width;
+			int destPos = (height - (i+1)) * width;
+			System.arraycopy(pixels, sourcePos, swap, destPos, width);
+		}
+		
+		System.arraycopy(swap, 0, pixels, 0, pixels.length);
+		long end = System.currentTimeMillis();
+//		System.out.println("Scanning pixels[" + pixels.length + "] took " + (end-start) + " ms.");
+	}
+	
+	
+	/**
+	 * Compress the byte array using Zlib.
+	 * @param pixels
+	 * @return a byte array of compressed data
+	 */
+	private static byte[] compressUsingZlib(byte[] pixels) {
+		long start = System.currentTimeMillis();
+	    // Create the compressed stream
+		 byte[] output = new byte[pixels.length];
+		 Deflater compresser = new Deflater(Deflater.BEST_COMPRESSION);
+		 compresser.setInput(pixels);
+		 compresser.finish();
+		 int compressedDataLength = compresser.deflate(output);
+
+		 byte[] zData = new byte[compressedDataLength] ;
+		 System.arraycopy(output, 0, zData, 0, compressedDataLength);
+
+		long end = System.currentTimeMillis();
+//		System.out.println("Compressing pixels[" + pixels.length + "] took " + (end-start) + " ms.");
+
+		// set the byte array to the newly compressed data
+		return zData;
+	}
+	
+	/**
+	 * Extracts the RGB bytes from a pixel represented by a 4-byte integer (ARGB).
+	 * @param pixels
+	 * @return pixels in BGR order
+	 */
+	private static byte[] convertFromRGBtoBGR(int[] pixels, boolean isRedTile, boolean isKeyFrame) {	
+		long start = System.currentTimeMillis();
+		byte[] rgbPixels = new byte[pixels.length * 3];
+		int position = 0;
+		
+		for (int i = 0; i < pixels.length; i++) {
+			byte red = (byte) ((pixels[i] >> 16) & 0xff);
+			byte green = (byte) ((pixels[i] >> 8) & 0xff);
+			byte blue = (byte) (pixels[i] & 0xff);
+			
+			if (isRedTile && !isKeyFrame) {
+				// Sequence should be BGR
+				rgbPixels[position++] = 0;
+				rgbPixels[position++] = 0;
+				rgbPixels[position++] = (byte) 0xff;				
+			} else if (isRedTile && isKeyFrame) {
+				rgbPixels[position++] = (byte) 0xff;
+				rgbPixels[position++] = 0;
+				rgbPixels[position++] = 0;					
+			}	else {
+				// Sequence should be BGR
+				rgbPixels[position++] = blue;
+				rgbPixels[position++] = green;
+				rgbPixels[position++] = red;				
+			}
+		}
+		
+		long end = System.currentTimeMillis();
+//		System.out.println("Extracting pixels[" + pixels.length + "] took " + (end-start) + " ms.");				
+		return rgbPixels;
+	}
+			
+	public static String toStringBits( int value )
+	{
+	    int displayMask = 1 << 31;
+	    StringBuffer buf = new StringBuffer( 35 );
+			   
+	    for ( int c = 1; c <= 32; c++ ) 
+	    {
+	        buf.append( ( value & displayMask ) == 0 ? '0' : '1' );
+	        value <<= 1;
+			       
+	        if ( c % 8 == 0 )
+		        buf.append( ' ' );
+		    }
+			   
+	    return buf.toString();
+	}
+		    
+	public static String toStringBits( byte value )
+	{
+	    int displayMask = 1 << 7;
+	    StringBuffer buf = new StringBuffer( 8 );
+			   
+	    for ( int c = 1; c <= 8; c++ ) 
+	    {
+	        buf.append( ( value & displayMask ) == 0 ? '0' : '1' );
+	        value <<= 1;
+			       
+	        if ( c % 8 == 0 )
+		        buf.append( ' ' );
+	    }
+			   
+	    return buf.toString();
+	}    
+}
diff --git a/deskshare/settings.gradle b/deskshare/settings.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..4b7f7a310cf41f42f8c33e6eb3f11f67af19d770
--- /dev/null
+++ b/deskshare/settings.gradle
@@ -0,0 +1 @@
+include 'applet', 'app', 'common'