diff --git a/bigbluebutton-client/resources/prod/bbb-deskshare-applet-0.64.jar b/bigbluebutton-client/resources/prod/bbb-deskshare-applet-0.64.jar index fdfa631e5da1df69911160572c9f20bbad08a290..62ecac0ba2d754f5b9c8abfacdeefc7da22930a0 100755 Binary files a/bigbluebutton-client/resources/prod/bbb-deskshare-applet-0.64.jar and b/bigbluebutton-client/resources/prod/bbb-deskshare-applet-0.64.jar differ 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 index 7e8c425e88f82ae61eedf06dc5e864cf62bda4b3..b30927b7f3fb6e587ad2acea9b1f397782df977d 100755 --- 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 @@ -22,12 +22,18 @@ package org.bigbluebutton.deskshare.server.events; public class CaptureEndBlockEvent { private final String room; + private final int sequenceNum; - public CaptureEndBlockEvent(String room) { + public CaptureEndBlockEvent(String room, int sequenceNum) { this.room = room; + this.sequenceNum = sequenceNum; } public String getRoom() { return room; } + + public int getSequenceNum() { + return sequenceNum; + } } 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 index 3cd629dc7d4e8c0efbd4667094d9ac499ff6a543..197ebcab0b426f710ca6b01ba68b42f89bc99a5c 100755 --- 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 @@ -26,11 +26,13 @@ public class CaptureStartBlockEvent { private final String room; private final Dimension screenDim; private final Dimension blockDim; + private final int sequenceNum; - public CaptureStartBlockEvent(String room, Dimension screen, Dimension block) { + public CaptureStartBlockEvent(String room, Dimension screen, Dimension block, int sequenceNum) { this.room = room; screenDim = screen; blockDim = block; + this.sequenceNum = sequenceNum; } public Dimension getScreenDimension() { @@ -44,4 +46,8 @@ public class CaptureStartBlockEvent { public String getRoom() { return room; } + + public int getSequenceNum() { + return sequenceNum; + } } 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 index 9dc15a0122d8383c6dc935f42c312963bc87b35d..afbce9461b256ef6d596ea53d4a199da0eb983b0 100755 --- 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 @@ -19,19 +19,19 @@ */ package org.bigbluebutton.deskshare.server.events; -import java.awt.Point; - 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) { + private final int sequenceNum; + + public CaptureUpdateBlockEvent(String room, int position, byte[] videoData, boolean isKeyFrame, int sequenceNum) { this.room = room; this.position = position; this.videoData = videoData; this.isKeyFrame = isKeyFrame; + this.sequenceNum = sequenceNum; } public String getRoom() { @@ -49,4 +49,8 @@ public class CaptureUpdateBlockEvent { public boolean isKeyFrame() { return isKeyFrame; } + + public int getSequenceNum() { + return sequenceNum; + } } diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/events/MouseLocationEvent.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/events/MouseLocationEvent.java index bfa7edd7fe0e7d93212d4b072b16f6c9df819eac..f8ce28c3af7f2e8ecba7fe1539f20a85b848ca4a 100755 --- a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/events/MouseLocationEvent.java +++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/events/MouseLocationEvent.java @@ -25,10 +25,12 @@ public class MouseLocationEvent { private String room; private Point loc; + private final int sequenceNum; - public MouseLocationEvent(String room, Point loc) { + public MouseLocationEvent(String room, Point loc, int sequenceNum) { this.room = room; this.loc = loc; + this.sequenceNum = sequenceNum; } public String getRoom() { @@ -38,4 +40,8 @@ public class MouseLocationEvent { public Point getLoc() { return loc; } + + public int getSequenceNum() { + return sequenceNum; + } } 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 index 50c2205c83c5a927d784efba9362e85cbc281909..83181403d4bbd6419ce394ce60df0ee084fe1509 100755 --- 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 @@ -60,19 +60,20 @@ public class HttpTunnelStreamController extends MultiActionController { private void handleUpdateMouseLocationRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { String room = request.getParameterValues("room")[0]; String mouseX = request.getParameterValues("mousex")[0]; - String mouseY = request.getParameterValues("mousey")[0]; - + String mouseY = request.getParameterValues("mousey")[0]; + String seqNum = request.getParameterValues("sequenceNumber")[0]; Point loc = new Point(Integer.parseInt(mouseX), Integer.parseInt(mouseY)); if (! hasSessionManager) { sessionManager = getSessionManager(); hasSessionManager = true; } - sessionManager.updateMouseLocation(room, loc); + sessionManager.updateMouseLocation(room, loc, Integer.parseInt(seqNum)); } private void handleCaptureStartRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { String room = request.getParameterValues("room")[0]; + String seqNum = request.getParameterValues("sequenceNumber")[0]; String screenInfo = request.getParameterValues("screenInfo")[0]; String blockInfo = request.getParameterValues("blockInfo")[0]; @@ -87,7 +88,7 @@ public class HttpTunnelStreamController extends MultiActionController { sessionManager = getSessionManager(); hasSessionManager = true; } - sessionManager.createSession(room, screenDim, blockDim); + sessionManager.createSession(room, screenDim, blockDim, Integer.parseInt(seqNum)); } private void handleCaptureUpdateRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { @@ -99,6 +100,7 @@ public class HttpTunnelStreamController extends MultiActionController { byte[] blockData = multipartFile.getBytes(); String room = request.getParameterValues("room")[0]; + String seqNum = request.getParameterValues("sequenceNumber")[0]; String keyframe = request.getParameterValues("keyframe")[0]; String position = request.getParameterValues("position")[0]; @@ -107,17 +109,18 @@ public class HttpTunnelStreamController extends MultiActionController { hasSessionManager = true; } - sessionManager.updateBlock(room, Integer.valueOf(position), blockData, Boolean.parseBoolean(keyframe)); + sessionManager.updateBlock(room, Integer.valueOf(position), blockData, Boolean.parseBoolean(keyframe), Integer.parseInt(seqNum)); } private void handleCaptureEndRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { String room = request.getParameterValues("room")[0]; + String seqNum = request.getParameterValues("sequenceNumber")[0]; if (! hasSessionManager) { sessionManager = getSessionManager(); hasSessionManager = true; } System.out.println("HttpTunnel: Received Capture Enfd Event."); - sessionManager.removeSession(room); + sessionManager.removeSession(room, Integer.parseInt(seqNum)); } private ISessionManagerGateway getSessionManager() { diff --git a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/ISessionManagerGateway.java b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/ISessionManagerGateway.java index 4a95a0d2951a39b525295c8b49438d891a9318ae..7303a4915e00b0b3c35c80d1eecf060505ea8cf9 100755 --- a/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/ISessionManagerGateway.java +++ b/deskshare/app/src/main/java/org/bigbluebutton/deskshare/server/session/ISessionManagerGateway.java @@ -29,11 +29,11 @@ import org.bigbluebutton.deskshare.common.Dimension; * */ public interface ISessionManagerGateway { - public void createSession(String room, Dimension screenDim, Dimension blockDim); + public void createSession(String room, Dimension screenDim, Dimension blockDim, int seqNum); - public void removeSession(String room); + public void removeSession(String room, int seqNum); - public void updateBlock(String room, int position, byte[] blockData, boolean keyframe); + public void updateBlock(String room, int position, byte[] blockData, boolean keyframe, int seqNum); - public void updateMouseLocation(String room, Point loc); + public void updateMouseLocation(String room, Point loc, int seqNum); } 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 index 0b2901e1d92bd96718d4d7b9167d7e2cee26c163..13dc0026e987f55c2f7013e59868a38de2cf47be 100755 --- 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 @@ -48,17 +48,17 @@ public class BlockStreamEventMessageHandler extends IoHandlerAdapter { if (message instanceof CaptureStartBlockEvent) { System.out.println("Got CaptureStartBlockEvent"); CaptureStartBlockEvent event = (CaptureStartBlockEvent) message; - sessionManager.createSession(event.getRoom(), event.getScreenDimension(), event.getBlockDimension()); + sessionManager.createSession(event.getRoom(), event.getScreenDimension(), event.getBlockDimension(), event.getSequenceNum()); } else if (message instanceof CaptureUpdateBlockEvent) { // System.out.println("Got CaptureUpdateBlockEvent"); CaptureUpdateBlockEvent event = (CaptureUpdateBlockEvent) message; - sessionManager.updateBlock(event.getRoom(), event.getPosition(), event.getVideoData(), event.isKeyFrame()); + sessionManager.updateBlock(event.getRoom(), event.getPosition(), event.getVideoData(), event.isKeyFrame(), event.getSequenceNum()); } else if (message instanceof CaptureEndBlockEvent) { CaptureEndBlockEvent event = (CaptureEndBlockEvent) message; - sessionManager.removeSession(event.getRoom()); + sessionManager.removeSession(event.getRoom(), event.getSequenceNum()); } else if (message instanceof MouseLocationEvent) { MouseLocationEvent event = (MouseLocationEvent) message; - sessionManager.updateMouseLocation(event.getRoom(), event.getLoc()); + sessionManager.updateMouseLocation(event.getRoom(), event.getLoc(), event.getSequenceNum()); } } @@ -88,7 +88,7 @@ public class BlockStreamEventMessageHandler extends IoHandlerAdapter { String room = (String) session.getAttribute("ROOM"); if (room != null) { log.debug("Session Closed for room " + room); - sessionManager.removeSession(room); + sessionManager.removeSession(room, 0); } else { log.warn("Closing session for a NULL room"); } 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 index affdd1aab3c8e027d3ae1a2bd6e192e0d0d59026..9550692673f1ec981e30763a90dba9b532f6dc6c 100755 --- 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 @@ -95,9 +95,10 @@ public class BlockStreamProtocolDecoder extends CumulativeProtocolDecoder { private void decodeMouseLocationEvent(IoSession session, IoBuffer in, ProtocolDecoderOutput out) { String room = decodeRoom(session, in); + int seqNum = in.getInt(); int mouseX = in.getInt(); int mouseY = in.getInt(); - MouseLocationEvent event = new MouseLocationEvent(room, new Point(mouseX, mouseY)); + MouseLocationEvent event = new MouseLocationEvent(room, new Point(mouseX, mouseY), seqNum); out.write(event); } @@ -106,7 +107,8 @@ public class BlockStreamProtocolDecoder extends CumulativeProtocolDecoder { if (! "".equals(room)) { log.info("CaptureEndEvent for " + room); - CaptureEndBlockEvent event = new CaptureEndBlockEvent(room); + int seqNum = in.getInt(); + CaptureEndBlockEvent event = new CaptureEndBlockEvent(room, seqNum); out.write(event); } else { log.warn("Room is empty."); @@ -116,13 +118,13 @@ public class BlockStreamProtocolDecoder extends CumulativeProtocolDecoder { private void decodeCaptureStartEvent(IoSession session, IoBuffer in, ProtocolDecoderOutput out) { String room = decodeRoom(session, in); session.setAttribute(ROOM, room); + int seqNum = in.getInt(); 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() + "]"); + log.info("CaptureStartEvent for " + room); - CaptureStartBlockEvent event = new CaptureStartBlockEvent(room, screenDim, blockDim); + CaptureStartBlockEvent event = new CaptureStartBlockEvent(room, screenDim, blockDim, seqNum); out.write(event); } @@ -153,15 +155,22 @@ public class BlockStreamProtocolDecoder extends CumulativeProtocolDecoder { 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); + int seqNum = in.getInt(); + int numBlocks = in.getShort(); +// System.out.println("Number of blocks changed " + numBlocks); + String blocksStr = "Blocks changed "; - CaptureUpdateBlockEvent event = new CaptureUpdateBlockEvent(room, position, data, isKeyFrame); - out.write(event); + for (int i = 0; i < numBlocks; i++) { + int position = in.getShort(); + blocksStr += " " + position; + + boolean isKeyFrame = (in.get() == 1) ? true : false; + int length = in.getInt(); + byte[] data = new byte[length]; + in.get(data, 0, length); + CaptureUpdateBlockEvent event = new CaptureUpdateBlockEvent(room, position, data, isKeyFrame, seqNum); + out.write(event); + } +// System.out.println(blocksStr); } } diff --git a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionManagerGateway.scala b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionManagerGateway.scala index 86bdb456a8d2159e91828832734acb44e0f25da7..0433acf05fb87cb53553e1ac7a655b0c465fcac8 100755 --- a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionManagerGateway.scala +++ b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionManagerGateway.scala @@ -34,24 +34,24 @@ class SessionManagerGateway(streamManager: StreamManager) extends ISessionManage val sessionManager: SessionManagerSVC = new SessionManagerSVC(streamManager) sessionManager.start - def createSession(room: String, screenDim: common.Dimension, blockDim: common.Dimension): Unit = { + def createSession(room: String, screenDim: common.Dimension, blockDim: common.Dimension, seqNum: Int): Unit = { log.info("SessionManagerGateway:createSession for %s", room) sessionManager ! new CreateSession(room, new svc1.Dimension(screenDim.getWidth(), screenDim.getHeight()), - new svc1.Dimension(blockDim.getWidth(), blockDim.getHeight())) + new svc1.Dimension(blockDim.getWidth(), blockDim.getHeight()), seqNum) log.info("SessionManagerGateway:Sent create session for %s", room) } - def removeSession(room: String): Unit = { + def removeSession(room: String, seqNum: Int): Unit = { log.info("SessionManagerGateway:removeSession for %s", room) sessionManager ! new RemoveSession(room) } - def updateBlock(room : String, position : Int, blockData : Array[Byte], keyframe : Boolean): Unit = { - sessionManager ! new UpdateBlock(room, position, blockData, keyframe) + def updateBlock(room : String, position : Int, blockData : Array[Byte], keyframe : Boolean, seqNum: Int): Unit = { + sessionManager ! new UpdateBlock(room, position, blockData, keyframe, seqNum) } - def updateMouseLocation(room: String, mouseLoc: Point): Unit = { - sessionManager ! new UpdateMouseLocation(room, mouseLoc) + def updateMouseLocation(room: String, mouseLoc: Point, seqNum: Int): Unit = { + sessionManager ! new UpdateMouseLocation(room, mouseLoc, seqNum) } def sendKeyFrame(room: String) { diff --git a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionManagerSVC.scala b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionManagerSVC.scala index d6dff319134c2212c0445563c39650f87b3c2736..58c62cbae8716169ec4d8bd51557d6b13f55aa7f 100755 --- a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionManagerSVC.scala +++ b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionManagerSVC.scala @@ -28,11 +28,11 @@ import org.bigbluebutton.deskshare.server.svc1.Dimension import org.bigbluebutton.deskshare.server.stream.StreamManager import java.awt.Point -case class CreateSession(room: String, screenDim: Dimension, blockDim: Dimension) +case class CreateSession(room: String, screenDim: Dimension, blockDim: Dimension, seqNum: Int) case class RemoveSession(room: String) case class SendKeyFrame(room: String) -case class UpdateBlock(room: String, position: Int, blockData: Array[Byte], keyframe: Boolean) -case class UpdateMouseLocation(room: String, mouseLoc:Point) +case class UpdateBlock(room: String, position: Int, blockData: Array[Byte], keyframe: Boolean, seqNum: Int) +case class UpdateMouseLocation(room: String, mouseLoc:Point, seqNum: Int) class SessionManagerSVC(streamManager: StreamManager) extends Actor { private val log = Logger.get @@ -45,8 +45,8 @@ class SessionManagerSVC(streamManager: StreamManager) extends Actor { case c: CreateSession => createSession(c); printMailbox("CreateSession") case r: RemoveSession => removeSession(r.room); printMailbox("RemoveSession") case k: SendKeyFrame => sendKeyFrame(k.room); printMailbox("SendKeyFrame") - case ub: UpdateBlock => updateBlock(ub.room, ub.position, ub.blockData, ub.keyframe) - case ml: UpdateMouseLocation => updateMouseLocation(ml.room, ml.mouseLoc) + case ub: UpdateBlock => updateBlock(ub.room, ub.position, ub.blockData, ub.keyframe, ub.seqNum) + case ml: UpdateMouseLocation => updateMouseLocation(ml.room, ml.mouseLoc, ml.seqNum) case m: Any => log.warning("SessionManager: Unknown message " + m); printMailbox("Any") } } @@ -98,16 +98,16 @@ class SessionManagerSVC(streamManager: StreamManager) extends Actor { } } - private def updateMouseLocation(room: String, mouseLoc: Point): Unit = { + private def updateMouseLocation(room: String, mouseLoc: Point, seqNum: Int): Unit = { sessions.get(room) match { - case Some(s) => s ! new UpdateSessionMouseLocation(mouseLoc) + case Some(s) => s ! new UpdateSessionMouseLocation(mouseLoc, seqNum) case None => log.warning("SessionManager: Could not update mouse loc for session %s. Does not exist.", room) } } - private def updateBlock(room: String, position: Int, blockData: Array[Byte], keyframe: Boolean): Unit = { + private def updateBlock(room: String, position: Int, blockData: Array[Byte], keyframe: Boolean, seqNum: Int): Unit = { sessions.get(room) match { - case Some(s) => s ! new UpdateSessionBlock(position, blockData, keyframe) + case Some(s) => s ! new UpdateSessionBlock(position, blockData, keyframe, seqNum) case None => log.warning("SessionManager: Could not update session %s. Does not exist.", room) } } diff --git a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionSVC.scala b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionSVC.scala index 6c0be6be23a84316d1c198fe172f27c7f29bc122..70abd974d098b8f31be3e75418af955ebed407fc 100755 --- a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionSVC.scala +++ b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionSVC.scala @@ -29,8 +29,8 @@ import net.lag.logging.Logger import java.awt.Point case object StartSession -case class UpdateSessionBlock(position: Int, blockData: Array[Byte], keyframe: Boolean) -case class UpdateSessionMouseLocation(loc: Point) +case class UpdateSessionBlock(position: Int, blockData: Array[Byte], keyframe: Boolean, seqNum: Int) +case class UpdateSessionMouseLocation(loc: Point, seqNum: Int) case object StopSession case object GenerateKeyFrame @@ -92,7 +92,7 @@ class SessionSVC(sessionManager:SessionManagerSVC, room: String, screenDim: Dime log.debug("Session: Generating Key Frame for room %s", room) generateFrame(true) } - case b: UpdateSessionBlock => updateBlock(b.position, b.blockData, b.keyframe) + case b: UpdateSessionBlock => updateBlock(b.position, b.blockData, b.keyframe, b.seqNum) case m: Any => log.warning("Session: Unknown message [%s]", m) } } @@ -121,9 +121,9 @@ class SessionSVC(sessionManager:SessionManagerSVC, room: String, screenDim: Dime streamManager.destroyStream(room) } - private def updateBlock(position: Int, videoData: Array[Byte], keyFrame: Boolean): Unit = { + private def updateBlock(position: Int, videoData: Array[Byte], keyFrame: Boolean, seqNum: Int): Unit = { lastUpdate = System.currentTimeMillis() - blockManager.updateBlock(position, videoData, keyFrame) + blockManager.updateBlock(position, videoData, keyFrame, seqNum) } private def generateFrame(keyframe:Boolean) { diff --git a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/svc1/Block.scala b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/svc1/Block.scala index a943ccc388d337e15703d7763ce246d6159df68b..8e1497e87d791ab56c3ef8caddbb50795f73a530 100755 --- a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/svc1/Block.scala +++ b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/svc1/Block.scala @@ -20,8 +20,10 @@ package org.bigbluebutton.deskshare.server.svc1 import java.util.Random +import net.lag.logging.Logger class Block(val dim: Dimension, val position: Int) { + private val log = Logger.get val nextForceUpdate = 10000 val MIN_DURATION = 5000 @@ -33,11 +35,17 @@ class Block(val dim: Dimension, val position: Int) { var encodedBlock: Array[Byte] = null val random: Random = new Random(); + private var sequenceNumber = 0; - def update(videoData: Array[Byte], isKeyFrame: Boolean): Unit = { - this.isKeyFrame = isKeyFrame; - encodedBlock = videoData; - hasChanged = true; + def update(videoData: Array[Byte], isKeyFrame: Boolean, seqNum: Int): Unit = { + if (seqNum >= sequenceNumber) { + sequenceNumber = seqNum + this.isKeyFrame = isKeyFrame; + encodedBlock = videoData; + hasChanged = true; + } else { + log.warning("Block[" + position + "[: Delayed sequence number [%s < %s]", seqNum, sequenceNumber) + } } def getEncodedBlock(): Array[Byte] = { diff --git a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/svc1/BlockManager.scala b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/svc1/BlockManager.scala index 0fe1a90a30871e2a5f6d7408df97fa69cf286065..9aff2e5d0b3468a2164f763b07361cd89e01ad90 100755 --- a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/svc1/BlockManager.scala +++ b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/svc1/BlockManager.scala @@ -48,14 +48,14 @@ class BlockManager(room: String, screenDim: Dimension, blockDim: Dimension) exte blankPixels(i) = 0xFFFF; } val encodedPixels = ScreenVideoEncoder.encodePixels(blankPixels, dim.width, dim.height) - block.update(encodedPixels, true) + block.update(encodedPixels, true, 0) blocksMap.put(position, block) } } - def updateBlock(position: Int, videoData: Array[Byte], keyFrame: Boolean): Unit = { + def updateBlock(position: Int, videoData: Array[Byte], keyFrame: Boolean, seqNum: Int): Unit = { val block: Block = blocksMap.get(position) - block.update(videoData, keyFrame) + block.update(videoData, keyFrame, seqNum) } def generateFrame(genKeyFrame: Boolean): Array[Byte] = { 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 index fed3cf6c5c88dbbe24c516cf2e27caa4e2edbe65..e812a1c67934c0bfe770f15ef77245011c978c22 100755 --- 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 @@ -83,11 +83,14 @@ public final class Block { return false; } + public void sent() { + dirtyBlock.set(false); + } + public EncodedBlockData encode() { int[] pixelsCopy = new int[capturedPixels.length]; - synchronized (pixelsLock) { - dirtyBlock.set(false); + synchronized (pixelsLock) { System.arraycopy(capturedPixels, 0, pixelsCopy, 0, capturedPixels.length); } 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 index 110855874370644ac17e4fb0a42891e45e26ae69..d5ab5b9a0c5aed1c3041fdb88c4aa5404ed3e272 100755 --- 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 @@ -22,6 +22,7 @@ package org.bigbluebutton.deskshare.client.blocks; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.Map; +import java.util.Vector; import org.bigbluebutton.deskshare.client.net.BlockMessage; import org.bigbluebutton.deskshare.common.Dimension; @@ -57,18 +58,42 @@ public class BlockManager { public void processCapturedScreen(BufferedImage capturedScreen) { long start = System.currentTimeMillis(); + + Vector<Integer> changedBlocks = new Vector<Integer>(); +/* int numberOfBlocks = numColumns * numRows; - for (int position = 1; position <= numberOfBlocks; position++) { - Block block = blocksMap.get(new Integer(position)); + for (int position = 1; position <= numberOfBlocks; position++) { + Block block = blocksMap.get(new Integer(position)); if (block.hasChanged(capturedScreen)) { - notifyChangedBlockListener(new BlockMessage(block.getPosition())); + changedBlocks.add(new Integer(position)); } - } - - long end = System.currentTimeMillis(); -// System.out.println("ProcessCapturedScreen took " + (end-start) + " ms."); + } + + if (changedBlocks.size() > 0) { + Integer[] bc = new Integer[changedBlocks.size()]; + System.arraycopy(changedBlocks.toArray(), 0, bc, 0, bc.length); + changedBlocks.clear(); + notifyChangedBlockListener(new BlockMessage(bc)); + } +*/ + + int numberOfBlocks = numColumns * numRows; + for (int position = 1; position <= numberOfBlocks; position++) { + Block block = blocksMap.get(new Integer(position)); + if (block.hasChanged(capturedScreen)) { + changedBlocks.add(new Integer(position)); + } + + if ((position % numColumns == 0) && (changedBlocks.size() > 0)) { + Integer[] bc = new Integer[changedBlocks.size()]; + System.arraycopy(changedBlocks.toArray(), 0, bc, 0, bc.length); + changedBlocks.clear(); + notifyChangedBlockListener(new BlockMessage(bc)); + } + } + } - + private void notifyChangedBlockListener(BlockMessage position) { listeners.onChangedBlock(position); } @@ -82,6 +107,11 @@ public class BlockManager { listeners = null; } + public void blockSent(int position) { + Block block = (Block) blocksMap.get(new Integer(position)); + block.sent(); + } + public Block getBlock(int position) { return (Block) blocksMap.get(new Integer(position)); } diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/BlockMessage.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/BlockMessage.java index 33a073a26f03fe40b8cbbf4b34bdbc1878ff8629..93f8d197c01ff3eec1164fc58bb6ac1531131358 100755 --- a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/BlockMessage.java +++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/BlockMessage.java @@ -21,10 +21,10 @@ package org.bigbluebutton.deskshare.client.net; public class BlockMessage implements Message { - private int position; + private Integer[] blocks; - public BlockMessage(int position) { - this.position = position; + public BlockMessage(Integer[] blocks) { + this.blocks = blocks; } @Override @@ -32,7 +32,7 @@ public class BlockMessage implements Message { return MessageType.BLOCK; } - public int getPosition() { - return position; + public Integer[] getBlocks() { + return blocks; } } 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 index e9036e39dbdcfa1bcab7931d5da00fa2fecfa92e..a035e3e96e1882f1f0afa2489b68e02e35788cfb 100755 --- 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 @@ -34,21 +34,24 @@ public class BlockStreamProtocolEncoder { private static final byte MOUSE_LOCATION_EVENT = 3; public static void encodeStartStreamMessage(String room, Dimension screen, Dimension block, - ByteArrayOutputStream data) throws IOException { + ByteArrayOutputStream data, int seqNum) throws IOException { + data.write(CAPTURE_START_EVENT); - data.write(room.length()); - data.write(room.getBytes()); + encodeRoom(data, room); + encodeSequenceNumber(data, seqNum); + 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 { + public static void encodeBlock(BlockVideoData block, ByteArrayOutputStream data, int seqNum) throws IOException { data.write(CAPTURE_UPDATE_EVENT); - data.write(block.getRoom().length()); - data.write(block.getRoom().getBytes()); - + encodeRoom(data, block.getRoom()); + + encodeSequenceNumber(data, seqNum); + byte[] position = new byte[2]; int pos = block.getPosition(); position[0] = (byte)((pos >> 8) & 0xff); @@ -58,19 +61,35 @@ public class BlockStreamProtocolEncoder { 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(intToBytes(length)); data.write(block.getVideoData()); } + + public static void numBlocksChanged(int numBlocks, ByteArrayOutputStream data) throws IOException{ + byte[] nb = new byte[2]; + nb[0] = (byte)((numBlocks >> 8) & 0xff); + nb[1] = (byte)(numBlocks & 0xff); + data.write(nb); + } - 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 void encodeRoomAndSequenceNumber(String room, int seqNum, ByteArrayOutputStream data) throws IOException{ + data.write(CAPTURE_UPDATE_EVENT); + encodeRoom(data, room); + encodeSequenceNumber(data, seqNum); + } + + public static void encodeBlock(BlockVideoData block, ByteArrayOutputStream data) throws IOException { + 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; + data.write(intToBytes(length)); + data.write(block.getVideoData()); } public static byte[] encodeHeaderAndLength(ByteArrayOutputStream data) throws IOException { @@ -80,17 +99,35 @@ public class BlockStreamProtocolEncoder { return header.toByteArray(); } - public static void encodeMouseLocation(Point mouseLoc, String room, ByteArrayOutputStream data) throws IOException { + public static void encodeMouseLocation(Point mouseLoc, String room, ByteArrayOutputStream data, int seqNum) throws IOException { data.write(MOUSE_LOCATION_EVENT); - data.write(room.length()); - data.write(room.getBytes()); + encodeRoom(data, room); + encodeSequenceNumber(data, seqNum); data.write(intToBytes(mouseLoc.x)); data.write(intToBytes(mouseLoc.y)); } - public static void encodeEndStreamMessage(String room, ByteArrayOutputStream data) throws IOException { + public static void encodeEndStreamMessage(String room, ByteArrayOutputStream data, int seqNum) throws IOException { data.write(CAPTURE_END_EVENT); + encodeRoom(data, room); + encodeSequenceNumber(data, seqNum); + } + + 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; + } + + private static void encodeRoom(ByteArrayOutputStream data, String room) throws IOException { data.write(room.length()); data.write(room.getBytes()); } + + private static void encodeSequenceNumber(ByteArrayOutputStream data, int seqNum) throws IOException { + data.write(intToBytes(seqNum)); + } } 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 index 22e9bafc5f496d262f2ebf5b30e3b6a7150f412f..f43f03b84692de2a961ec408e3a5a5b24e58e18f 100755 --- 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 @@ -33,7 +33,18 @@ import org.bigbluebutton.deskshare.common.Dimension; import com.myjavatools.web.ClientHttpRequest; -public class NetworkHttpStreamSender implements Runnable { +public class NetworkHttpStreamSender implements Runnable { + private static final String SEQ_NUM = "sequenceNumber"; + private static final String ROOM = "room"; + private static final String BLOCK = "blockInfo"; + private static final String EVENT = "event"; + private static final String SCREEN = "screenInfo"; + private static final String POSITION = "position"; + private static final String KEYFRAME = "keyframe"; + private static final String BLOCKDATA = "blockdata"; + private static final String MOUSEX = "mousex"; + private static final String MOUSEY = "mousey"; + private String host = "localhost"; private static final String SCREEN_CAPTURE__URL = "/deskshare/tunnel/screenCapture"; private URL url; @@ -45,13 +56,16 @@ public class NetworkHttpStreamSender implements Runnable { private volatile boolean processBlocks = false; private final int id; private NetworkStreamListener listener; + private final SequenceNumberGenerator seqNumGenerator; - public NetworkHttpStreamSender(int id, NextBlockRetriever retriever, String room, Dimension screenDim, Dimension blockDim) { + public NetworkHttpStreamSender(int id, NextBlockRetriever retriever, String room, + Dimension screenDim, Dimension blockDim, SequenceNumberGenerator seqNumGenerator) { this.id = id; this.retriever = retriever; this.room = room; this.screenDim = screenDim; this.blockDim = blockDim; + this.seqNumGenerator = seqNumGenerator; } public void addListener(NetworkStreamListener listener) { @@ -102,19 +116,18 @@ public class NetworkHttpStreamSender implements Runnable { ClientHttpRequest chr; try { chr = new ClientHttpRequest(conn); - chr.setParameter("room", room); + chr.setParameter(ROOM, room); + chr.setParameter(SEQ_NUM, seqNumGenerator.getNext()); String screenInfo = Integer.toString(screen.getWidth()) + "x" + Integer.toString(screen.getHeight()); - - chr.setParameter("screenInfo", screenInfo); + chr.setParameter(SCREEN, screenInfo); String blockInfo = Integer.toString(block.getWidth()) + "x" + Integer.toString(block.getHeight()); + chr.setParameter(BLOCK, blockInfo); - chr.setParameter("blockInfo", blockInfo); - - chr.setParameter("event", CaptureEvents.CAPTURE_START.getEvent()); + chr.setParameter(EVENT, CaptureEvents.CAPTURE_START.getEvent()); chr.post(); } catch (IOException e) { e.printStackTrace(); @@ -141,9 +154,9 @@ public class NetworkHttpStreamSender implements Runnable { ClientHttpRequest chr; try { chr = new ClientHttpRequest(conn); - chr.setParameter("room", room); - - chr.setParameter("event", CaptureEvents.CAPTURE_END.getEvent()); + chr.setParameter(ROOM, room); + chr.setParameter(SEQ_NUM, seqNumGenerator.getNext()); + chr.setParameter(EVENT, CaptureEvents.CAPTURE_END.getEvent()); chr.post(); } catch (IOException e) { e.printStackTrace(); @@ -153,9 +166,10 @@ public class NetworkHttpStreamSender implements Runnable { private void processNextMessageToSend(Message message) { if (message.getMessageType() == Message.MessageType.BLOCK) { - EncodedBlockData block = retriever.getBlockToSend(((BlockMessage)message).getPosition()); - BlockVideoData bv = new BlockVideoData(room, block.getPosition(), block.getVideoData(), false /* should remove later */); - sendBlockData(bv); +// EncodedBlockData block = retriever.getBlockToSend(((BlockMessage)message).getPosition()); +// BlockVideoData bv = new BlockVideoData(room, block.getPosition(), block.getVideoData(), false /* should remove later */); +// sendBlockData(bv); +// retriever.blockSent(block.getPosition()); } else if (message.getMessageType() == Message.MessageType.CURSOR) { CursorMessage msg = (CursorMessage)message; sendCursor(msg.getMouseLocation(), msg.getRoom()); @@ -183,10 +197,11 @@ public class NetworkHttpStreamSender implements Runnable { try { openConnection(); chr = new ClientHttpRequest(conn); - chr.setParameter("room", room); - chr.setParameter("event", CaptureEvents.MOUSE_LOCATION_EVENT.getEvent()); - chr.setParameter("mousex", mouseLoc.x); - chr.setParameter("mousey", mouseLoc.y); + chr.setParameter(ROOM, room); + chr.setParameter(SEQ_NUM, seqNumGenerator.getNext()); + chr.setParameter(EVENT, CaptureEvents.MOUSE_LOCATION_EVENT.getEvent()); + chr.setParameter(MOUSEX, mouseLoc.x); + chr.setParameter(MOUSEY, mouseLoc.y); chr.post(); } catch (IOException e) { e.printStackTrace(); @@ -200,12 +215,13 @@ public class NetworkHttpStreamSender implements Runnable { 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()); + chr.setParameter(ROOM, blockData.getRoom()); + chr.setParameter(SEQ_NUM, seqNumGenerator.getNext()); + 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.setParameter(BLOCKDATA, "block", block); chr.post(); } catch (IOException e) { 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 index 1cfa6fb614e452f7237efa434612e2ec96f5ff9d..fb36a6da8a13594a4e6a3c7dea2cd90d2c0f926b 100755 --- 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 @@ -25,6 +25,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; +import java.util.Vector; import org.bigbluebutton.deskshare.client.ExitCode; import org.bigbluebutton.deskshare.common.Dimension; @@ -40,13 +41,16 @@ public class NetworkSocketStreamSender implements Runnable { private volatile boolean processMessages = false; private final int id; private NetworkStreamListener listener; + private final SequenceNumberGenerator seqNumGenerator; - public NetworkSocketStreamSender(int id, NextBlockRetriever retriever, String room, Dimension screenDim, Dimension blockDim) { + public NetworkSocketStreamSender(int id, NextBlockRetriever retriever, String room, + Dimension screenDim, Dimension blockDim, SequenceNumberGenerator seqNumGenerator) { this.id = id; this.retriever = retriever; this.room = room; this.screenDim = screenDim; this.blockDim = blockDim; + this.seqNumGenerator = seqNumGenerator; } public void addListener(NetworkStreamListener listener) { @@ -58,7 +62,7 @@ public class NetworkSocketStreamSender implements Runnable { } public void connect(String host, int port) throws ConnectionException { - System.out.println("Starting NetworkSocketStreamSender "); + System.out.println("NetworkSocketStreamSender: connecting to " + host + ":" + port); try { socket = new Socket(host, port); outstream = new DataOutputStream(socket.getOutputStream()); @@ -75,7 +79,7 @@ public class NetworkSocketStreamSender implements Runnable { try { ByteArrayOutputStream dataToSend = new ByteArrayOutputStream(); dataToSend.reset(); - BlockStreamProtocolEncoder.encodeStartStreamMessage(room, screenDim, blockDim, dataToSend); + BlockStreamProtocolEncoder.encodeStartStreamMessage(room, screenDim, blockDim, dataToSend, seqNumGenerator.getNext()); sendHeader(BlockStreamProtocolEncoder.encodeHeaderAndLength(dataToSend)); sendToStream(dataToSend); } catch (IOException e) { @@ -87,7 +91,7 @@ public class NetworkSocketStreamSender implements Runnable { private void sendCursor(Point mouseLoc, String room) throws IOException { ByteArrayOutputStream dataToSend = new ByteArrayOutputStream(); dataToSend.reset(); - BlockStreamProtocolEncoder.encodeMouseLocation(mouseLoc, room, dataToSend); + BlockStreamProtocolEncoder.encodeMouseLocation(mouseLoc, room, dataToSend, seqNumGenerator.getNext()); sendHeader(BlockStreamProtocolEncoder.encodeHeaderAndLength(dataToSend)); sendToStream(dataToSend); } @@ -95,7 +99,7 @@ public class NetworkSocketStreamSender implements Runnable { private void sendBlock(BlockVideoData block) throws IOException { ByteArrayOutputStream dataToSend = new ByteArrayOutputStream(); dataToSend.reset(); - BlockStreamProtocolEncoder.encodeBlock(block, dataToSend); + BlockStreamProtocolEncoder.encodeBlock(block, dataToSend, seqNumGenerator.getNext()); sendHeader(BlockStreamProtocolEncoder.encodeHeaderAndLength(dataToSend)); sendToStream(dataToSend); } @@ -115,7 +119,7 @@ public class NetworkSocketStreamSender implements Runnable { try { ByteArrayOutputStream dataToSend = new ByteArrayOutputStream(); dataToSend.reset(); - BlockStreamProtocolEncoder.encodeEndStreamMessage(room, dataToSend); + BlockStreamProtocolEncoder.encodeEndStreamMessage(room, dataToSend, seqNumGenerator.getNext()); sendHeader(BlockStreamProtocolEncoder.encodeHeaderAndLength(dataToSend)); sendToStream(dataToSend); } catch (IOException e) { @@ -128,9 +132,29 @@ public class NetworkSocketStreamSender implements Runnable { private void processNextMessageToSend(Message message) throws IOException { if (message.getMessageType() == Message.MessageType.BLOCK) { - EncodedBlockData block = retriever.getBlockToSend(((BlockMessage)message).getPosition()); - BlockVideoData bv = new BlockVideoData(room, block.getPosition(), block.getVideoData(), false /* should remove later */); - sendBlock(bv); + ByteArrayOutputStream dataToSend = new ByteArrayOutputStream(); + dataToSend.reset(); + BlockStreamProtocolEncoder.encodeRoomAndSequenceNumber(room, seqNumGenerator.getNext(), dataToSend); + + Integer[] changedBlocks = ((BlockMessage)message).getBlocks(); + + BlockStreamProtocolEncoder.numBlocksChanged(changedBlocks.length, dataToSend); +// System.out.println("Number of blocks changed: " + changedBlocks.length); + String blocksStr = "Encoding "; + for (int i = 0; i < changedBlocks.length; i++) { + blocksStr += " " + (Integer)changedBlocks[i]; + EncodedBlockData block = retriever.getBlockToSend((Integer)changedBlocks[i]); + BlockVideoData bv = new BlockVideoData(room, block.getPosition(), block.getVideoData(), false /* should remove later */); + BlockStreamProtocolEncoder.encodeBlock(bv, dataToSend); + } + +// System.out.println(blocksStr); + + sendHeader(BlockStreamProtocolEncoder.encodeHeaderAndLength(dataToSend)); + sendToStream(dataToSend); + for (int i = 0; i< changedBlocks.length; i++) { + retriever.blockSent((Integer)changedBlocks[i]); + } } else if (message.getMessageType() == Message.MessageType.CURSOR) { CursorMessage msg = (CursorMessage)message; sendCursor(msg.getMouseLocation(), msg.getRoom()); 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 index 0c39ec80bfe686a3522946d37622e39ae71c5721..70a7fc1061f6df0e69beeb1d7a5081bee263f5a4 100755 --- 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 @@ -50,6 +50,7 @@ public class NetworkStreamSender implements NextBlockRetriever, NetworkStreamLis private Dimension blockDim; private BlockManager blockManager; private NetworkConnectionListener listener; + private final SequenceNumberGenerator seqNumGenerator = new SequenceNumberGenerator(); public NetworkStreamSender(BlockManager blockManager, String host, int port, String room, Dimension screenDim, Dimension blockDim, boolean httpTunnel) { @@ -126,13 +127,13 @@ public class NetworkStreamSender implements NextBlockRetriever, NetworkStreamLis } private void createSender(int i) throws ConnectionException { - socketSenders[i] = new NetworkSocketStreamSender(i, this, room, screenDim, blockDim); + socketSenders[i] = new NetworkSocketStreamSender(i, this, room, screenDim, blockDim, seqNumGenerator); socketSenders[i].addListener(this); socketSenders[i].connect(host, port); } private void createHttpSender(int i) throws ConnectionException { - httpSenders[i] = new NetworkHttpStreamSender(i, this, room, screenDim, blockDim); + httpSenders[i] = new NetworkHttpStreamSender(i, this, room, screenDim, blockDim, seqNumGenerator); httpSenders[i].addListener(this); httpSenders[i].connect(host); } @@ -181,7 +182,7 @@ public class NetworkStreamSender implements NextBlockRetriever, NetworkStreamLis } private boolean tryHttpTunneling() { - NetworkHttpStreamSender httpSender = new NetworkHttpStreamSender(0, this, room, screenDim, blockDim); + NetworkHttpStreamSender httpSender = new NetworkHttpStreamSender(0, this, room, screenDim, blockDim, seqNumGenerator); try { httpSender.connect(host); return true; @@ -191,6 +192,10 @@ public class NetworkStreamSender implements NextBlockRetriever, NetworkStreamLis return false; } + public void blockSent(int position) { + blockManager.blockSent(position); + } + public EncodedBlockData getBlockToSend(int position) { return blockManager.getBlock(position).encode(); } @@ -211,7 +216,10 @@ public class NetworkStreamSender implements NextBlockRetriever, NetworkStreamLis numRunningThreads--; if (tunneling) { - httpSenders[id].disconnect(); +// httpSenders[id].disconnect(); + System.out.println(NAME + "Failed to use http tunneling. Stopping."); + stop(); + notifyNetworkConnectionListener(reason); } else { socketSenders[id].disconnect(); } @@ -225,6 +233,12 @@ public class NetworkStreamSender implements NextBlockRetriever, NetworkStreamLis } catch (ConnectionException e) { // TODO Auto-generated catch block e.printStackTrace(); + if (numRunningThreads < 1) { + System.out.println(NAME + "No more sender threads. Stopping."); + notifyNetworkConnectionListener(reason); + } else { + System.out.println(NAME + "Sender thread stopped. " + numRunningThreads + " sender threads remaining."); + } } } 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 index 6fad08b9d80a30886b0da392e8be384023031d76..88adaf5febe200d7a7d065d1428b0660cc7943b7 100755 --- 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 @@ -20,6 +20,7 @@ package org.bigbluebutton.deskshare.client.net; public interface NextBlockRetriever { + public void blockSent(int position); public EncodedBlockData getBlockToSend(int position); public Message getNextMessageToSend() throws InterruptedException; } diff --git a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/SequenceNumberGenerator.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/SequenceNumberGenerator.java new file mode 100755 index 0000000000000000000000000000000000000000..de55e815f72590b6567a6007c954d7bcc5a27752 --- /dev/null +++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/SequenceNumberGenerator.java @@ -0,0 +1,17 @@ +package org.bigbluebutton.deskshare.client.net; + +import java.util.concurrent.atomic.AtomicInteger; + + +public class SequenceNumberGenerator { + + private final AtomicInteger sequenceNum; + + public SequenceNumberGenerator() { + sequenceNum = new AtomicInteger(0); + } + + public int getNext() { + return sequenceNum.incrementAndGet(); + } +}