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 index f1118b2381..4e87b59dc0 100644 --- a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/DeskShareApplet.java +++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/DeskShareApplet.java @@ -29,12 +29,11 @@ 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.EncodedBlockData; import org.bigbluebutton.deskshare.client.net.NetworkStreamSender; import org.bigbluebutton.deskshare.common.Dimension; -import netscape.javascript.*; public class DeskShareApplet extends Applet implements IScreenCaptureListener, ChangedBlocksListener { - private static final long serialVersionUID = 1L; private ScreenCaptureTaker captureTaker; private ScreenCapture capture; @@ -63,9 +62,6 @@ public class DeskShareApplet extends Applet implements IScreenCaptureListener, C y = Integer.parseInt(getParameter("Y")); room = getParameter("ROOM"); host = getParameter("IP"); - - String t = getParameter("TUNNEL"); - System.out.println("Tunnel param " + t); } public void stop() { @@ -76,15 +72,13 @@ public class DeskShareApplet extends Applet implements IScreenCaptureListener, C if (senderStarted) sender.stop(); } catch (ConnectionException e) { - // TODO Auto-generated catch block e.printStackTrace(); } } } public void start() { - System.out.println("RunnerApplet start()"); - + System.out.println("Deskshare Applet start"); startCapture(); } @@ -98,7 +92,7 @@ public class DeskShareApplet extends Applet implements IScreenCaptureListener, C blockManager.addListener(this); blockManager.initialize(screenDim, tileDim); - sender = new NetworkStreamSender(blockManager, host, room); + sender = new NetworkStreamSender(host, room, screenDim, tileDim); connected = sender.connect(); if (connected) { captureTaker.addListener(this); @@ -107,52 +101,31 @@ public class DeskShareApplet extends Applet implements IScreenCaptureListener, C captureTakerThread = new Thread(captureTaker, "ScreenCaptureTaker"); captureTakerThread.start(); } + sender.start(); } - - private void testFunctionCall() { - try { - System.out.println("testFunctionCall: test started"); - JSObject window = JSObject.getWindow(this); - System.out.println("Calling JavaScript getString();"); - if (window == null) System.out.println("WINDOW IS NULL"); - else System.out.println("WINDOW IS NOT NULL"); - - String res = (String) window.eval("getString();"); - System.out.println("Got string from JavaScript: \"" + res + "\""); - if (!res.equals("Hello, world!")) { - throw new RuntimeException("string value did not match expected value"); - } - Number num = (Number) window.eval("getNumber()"); - System.out.println("Got number from JavaScript: " + num); - if (num.intValue() != 5) { - throw new RuntimeException("number value did not match expected value"); - } - System.out.println("testFunctionCall: test passed."); - } catch (JSException e) { - e.printStackTrace(); - System.out.println("TEST FAILED"); - } catch (Exception e2) { - e2.printStackTrace(); - System.out.println("TEST FAILED"); - } - } - + /** * 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(){ + public void destroy() { + try { + sender.stop(); + } catch (ConnectionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } stop(); } - public void setScreenCoordinates(int x, int y){ + 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 onScreenCaptured(BufferedImage screen) { + blockManager.processCapturedScreen(screen); } @@ -161,11 +134,8 @@ public class DeskShareApplet extends Applet implements IScreenCaptureListener, C destroy(); } - public void onChangedTiles(ByteArrayOutputStream pixelData, boolean isKeyFrame) { - if (! senderStarted) { - sender.start(); - senderStarted = true; - } + public void onChangedBlock(EncodedBlockData encodedData) { + sender.send(encodedData); } static public void main (String argv[]) { 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 index 4875d98d06..eb73e26f06 100644 --- a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/IScreenCaptureListener.java +++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/IScreenCaptureListener.java @@ -25,5 +25,5 @@ import java.awt.image.BufferedImage; public interface IScreenCaptureListener { public void screenCaptureStopped(); - public void onScreenCaptured(BufferedImage screen, boolean isKeyFrame); + public void onScreenCaptured(BufferedImage screen); } 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 index 60d7a9d485..1eb8349a5a 100644 --- a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/ScreenCapture.java +++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/ScreenCapture.java @@ -42,7 +42,7 @@ public class ScreenCapture { private Rectangle screenBounds; private int width, height, x,y, videoWidth, videoHeight; - public ScreenCapture(int x, int y, int screenWidth, int screenHeight){ + public ScreenCapture(int x, int y, int screenWidth, int screenHeight) { this.width = screenWidth; this.height = screenHeight; try{ @@ -54,26 +54,26 @@ public class ScreenCapture { this.screenBounds = new Rectangle(x, y, this.width, this.height); } - public BufferedImage takeSingleSnapshot(){ + public BufferedImage takeSingleSnapshot() { return robot.createScreenCapture(this.screenBounds); } - public int getScreenshotWidth(){ + public int getScreenshotWidth() { return toolkit.getScreenSize().width; } - public int getScreenshotHeight(){ + public int getScreenshotHeight() { return toolkit.getScreenSize().height; } - public void setWidth(int width){ + 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){ + public void setHeight(int height) { int screenHeight = toolkit.getScreenSize().height; if (height > screenHeight) { this.height = screenHeight; @@ -84,29 +84,29 @@ public class ScreenCapture { updateBounds(); } - public void setX(int x){ + public void setX(int x) { this.x = x; updateBounds(); } - public void setY(int y){ + public void setY(int y) { this.y = y; updateBounds(); } - public void updateBounds(){ + public void updateBounds() { this.screenBounds = new Rectangle(x,y,width,height); } - public int getWidth(){ + public int getWidth() { return this.width; } - public int getHeight(){ + public int getHeight() { return this.height; } - public int getProperFrameRate(){ + public int getProperFrameRate() { long area = width*height; if (area > 1000000) return 1; else if (area > 600000) return 2; @@ -115,11 +115,11 @@ public class ScreenCapture { else return 10; } - public int getVideoWidth(){ + public int getVideoWidth() { return videoWidth; } - public int getVideoHeight(){ + 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 index ea564cc8a3..416a79fa60 100644 --- a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/ScreenCaptureTaker.java +++ b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/ScreenCaptureTaker.java @@ -23,11 +23,8 @@ package org.bigbluebutton.deskshare.client; import java.awt.image.BufferedImage; -public class ScreenCaptureTaker implements Runnable { - +public class ScreenCaptureTaker implements Runnable { private ScreenCapture capture; - private int timeBase; - private int frameCount = 0; private IScreenCaptureListener listeners; private volatile boolean startCapture = false; @@ -35,64 +32,34 @@ public class ScreenCaptureTaker implements Runnable { 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); + System.out.println("Going to sleeeeeep."); + Thread.sleep(1000); + System.out.println("Just woke up."); } catch (Exception e){ System.out.println("Exception sleeping."); System.exit(0); } } - System.out.println("Stopping screen capture."); - + System.out.println("Stopping screen capture."); listeners.screenCaptureStopped(); } private void notifyListeners(BufferedImage image) { - listeners.onScreenCaptured(image, isKeyFrame()); + listeners.onScreenCaptured(image); } - - 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 index a17bb899c8..15be0baa1d 100644 --- 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 @@ -36,16 +36,9 @@ 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 final Point location; private int[] pixels; - private EncodedBlockData encodedBlockData; - - private int nextForceUpdate = 10000; - private final static int MIN_DURATION = 5000; - private final static int MAX_DURATION = 10000; - private long lastChanged; + private boolean firstTime = true; Block(Dimension dim, int position, Point location) { checksum = new Adler32(); @@ -54,10 +47,8 @@ public final class Block { this.location = location; } - public void updateBlock(BufferedImage capturedScreen, boolean isKeyFrame) - { - synchronized(this) { - this.isKeyFrame = isKeyFrame; + public void updateBlock(BufferedImage capturedScreen) { + synchronized(this) { try { pixels = ScreenVideoEncoder.getPixels(capturedScreen, getX(), getY(), getWidth(), getHeight()); } catch (PixelExtractException e) { @@ -66,82 +57,44 @@ public final class Block { } } - public EncodedBlockData encode() { - int[] pixelsCopy = new int[pixels.length]; - synchronized (this) { - System.arraycopy(pixels, 0, pixelsCopy, 0, pixels.length); - } - - byte[] encodedBlock; - boolean hasChanged = false; - - /** Seems that this thing isn't working properly. - * The blocks only gets sent after forceUpdate. (ralam Oct 29, 2009) - */ - if (!checksumSame(pixelsCopy)) { - //if (!checksumSame(pixelsCopy) || isKeyFrame) { - 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; + public boolean hasChanged() { + if (firstTime) { + firstTime = false; + return true; + } + return ! checksumSame(); } - private boolean checksumSame(int[] pixelsCopy) { + public EncodedBlockData encode() { + byte[] encodedBlock = ScreenVideoEncoder.encodePixels(pixels, getWidth(), getHeight()); + return new EncodedBlockData(position, encodedBlock); + } + + private boolean checksumSame() { long oldsum; oldsum = checksum.getValue(); - calcChecksum(pixelsCopy); + calcChecksum(); return (oldsum == checksum.getValue()); } - - 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); - } - - public synchronized EncodedBlockData getEncodedBlockData() { - return encodedBlockData; - } - - private synchronized void calcChecksum(int pixelsCopy[]) - { + + private void calcChecksum() { 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]); + if ((i * width + j) % 5 == 0) + checksum.update(pixels[i * width + j]); } } } - public int getWidth() - { + public int getWidth() { return new Integer(dim.getWidth()).intValue(); } - public int getHeight() - { + public int getHeight() { return new Integer(dim.getHeight()).intValue(); } 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 deleted file mode 100644 index f30bc2757f..0000000000 --- a/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/blocks/BlockImp.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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 . - * - * Author: Richard Alam - * - * $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 index 4866034b53..1c1a20bd68 100644 --- 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 @@ -23,18 +23,11 @@ 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; +import org.bigbluebutton.deskshare.client.net.EncodedBlockData; public class BlockManager { private final Map blocksMap; @@ -48,12 +41,9 @@ public class BlockManager { private ByteArrayOutputStream encodedPixelStream = new ByteArrayOutputStream(); private Dimension screenDim, blockDim; -// private ScreenVideoBlockEncoder encoder; - public BlockManager() { blocksMap = new HashMap(); unmodifiableBlocksMap = Collections.unmodifiableMap(blocksMap); - // encoder = new ScreenVideoBlockEncoder(); } public void initialize(Dimension screen, Dimension tile) { @@ -72,62 +62,24 @@ public class BlockManager { } } - public void processCapturedScreen(BufferedImage capturedScreen, boolean isKeyFrame) - { + public void processCapturedScreen(BufferedImage capturedScreen) { 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; + block.updateBlock(capturedScreen); + if (block.hasChanged()) { + System.out.println("Block " + block.getPosition() + " has changed."); + notifyChangedBlockListener(block.encode()); + } } - 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); + + private void notifyChangedBlockListener(EncodedBlockData encodedData) { + listeners.onChangedBlock(encodedData); } @@ -135,9 +87,7 @@ public class BlockManager { listeners = listener; } - public void removeListener(ChangedBlocksListener listener) { - //listeners.remove(listener); listeners = null; } @@ -145,13 +95,11 @@ public class BlockManager { return (Block) blocksMap.get(Integer.valueOf(position)); } - public int getRowCount() - { + public int getRowCount() { return numRows; } - public int getColumnCount() - { + public int getColumnCount() { return numColumns; } @@ -162,11 +110,4 @@ public class BlockManager { public Dimension getBlockDim() { return blockDim; } - - /* - * Returns a read-only "live" view of the blocks; - */ - public Map 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 index c2d130e69b..1157ea231d 100644 --- 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 @@ -21,9 +21,8 @@ */ package org.bigbluebutton.deskshare.client.blocks; -import java.io.ByteArrayOutputStream; +import org.bigbluebutton.deskshare.client.net.EncodedBlockData; public interface ChangedBlocksListener { - - public void onChangedTiles(ByteArrayOutputStream pixelData, boolean isKeyFrame); + public void onChangedBlock(EncodedBlockData encodedData); } 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 index b30a9cffb0..69871c2fd4 100644 --- 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 @@ -22,18 +22,13 @@ 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) { + public EncodedBlockData(int position, byte[] videoData) { this.position = position; this.videoData = videoData; - this.keyFrame = keyFrame; - this.hasChanged = hasChanged; timestamp = System.currentTimeMillis(); } @@ -44,16 +39,8 @@ public class EncodedBlockData { 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/NetworkHttpStreamSender.java b/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/NetworkHttpStreamSender.java index 07ccfac63a..889ecdb9ea 100644 --- 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 @@ -40,12 +40,17 @@ public class NetworkHttpStreamSender implements Runnable { private URL url; URLConnection conn; private String room; + private Dimension screenDim; + private Dimension blockDim; private final NextBlockRetriever retriever; private volatile boolean processBlocks = false; - public NetworkHttpStreamSender(NextBlockRetriever retriever) { + public NetworkHttpStreamSender(NextBlockRetriever retriever, String room, Dimension screenDim, Dimension blockDim) { this.retriever = retriever; + this.room = room; + this.screenDim = screenDim; + this.blockDim = blockDim; } public void connect(String host) throws ConnectionException { @@ -74,11 +79,10 @@ public class NetworkHttpStreamSender implements Runnable { } } - public void sendStartStreamMessage(String room, Dimension screen, Dimension block) { - this.room = room; + public void sendStartStreamMessage() { try { openConnection(); - sendCaptureStartEvent(screen, block); + sendCaptureStartEvent(screenDim, blockDim); } catch (ConnectionException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -142,13 +146,15 @@ public class NetworkHttpStreamSender implements Runnable { 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); - } + EncodedBlockData block; + try { + block = retriever.fetchNextBlockToSend(); + BlockVideoData bv = new BlockVideoData(room, block.getPosition(), block.getVideoData(), false); + sendBlockData(bv); + } catch (InterruptedException 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 index fcb863eb34..4cf55b9044 100644 --- 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 @@ -26,8 +26,6 @@ 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 { @@ -42,8 +40,11 @@ public class NetworkSocketStreamSender implements Runnable { private final NextBlockRetriever retriever; private volatile boolean processBlocks = false; - public NetworkSocketStreamSender(NextBlockRetriever retriever) { + public NetworkSocketStreamSender(NextBlockRetriever retriever, String room, Dimension screenDim, Dimension blockDim) { this.retriever = retriever; + this.room = room; + this.screenDim = screenDim; + this.blockDim = blockDim; } public void connect(String host) throws ConnectionException { @@ -60,10 +61,7 @@ public class NetworkSocketStreamSender implements Runnable { } } - public void sendStartStreamMessage(String room, Dimension screen, Dimension block) { - this.room = room; - screenDim = screen; - blockDim = block; + public void sendStartStreamMessage() { try { ByteArrayOutputStream dataToSend = new ByteArrayOutputStream(); dataToSend.reset(); @@ -121,12 +119,16 @@ public class NetworkSocketStreamSender implements Runnable { 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()); + EncodedBlockData block; + try { + block = retriever.fetchNextBlockToSend(); + BlockVideoData bv = new BlockVideoData(room, block.getPosition(), block.getVideoData(), false /* should remove later */); + System.out.println("Sending block " + block.getPosition()); sendBlock(bv); - } + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } } 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 9b09b838d7..1d26bef8d2 100644 --- 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 @@ -21,36 +21,33 @@ */ package org.bigbluebutton.deskshare.client.net; -import java.util.Map; - +import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import net.jcip.annotations.GuardedBy; +import java.util.concurrent.LinkedBlockingQueue; import net.jcip.annotations.ThreadSafe; - -import org.bigbluebutton.deskshare.client.blocks.Block; -import org.bigbluebutton.deskshare.client.blocks.BlockManager; +import org.bigbluebutton.deskshare.common.Dimension; @ThreadSafe public class NetworkStreamSender implements NextBlockRetriever { - private BlockManager blockManager; - private ExecutorService executor; - - @GuardedBy("this") private int nextBlockToSend = 1; - private final Map blocksMap; + private ExecutorService executor; + private final BlockingQueue blockDataQ = new LinkedBlockingQueue(); + private final int numThreads; private final String host; private final String room; private NetworkSocketStreamSender[] senders; - private NetworkHttpStreamSender httpSender; + private NetworkHttpStreamSender[] httpSenders; private boolean tunneling = false; private int numRunningThreads = 0; - - public NetworkStreamSender(BlockManager blockManager, String host, String room) { - this.blockManager = blockManager; - blocksMap = blockManager.getBlocks(); + private Dimension screenDim; + private Dimension blockDim; + + public NetworkStreamSender(String host, String room, Dimension screenDim, Dimension blockDim) { this.host = host; this.room = room; + this.screenDim = screenDim; + this.blockDim = blockDim; numThreads = Runtime.getRuntime().availableProcessors(); System.out.println("Starting up " + numThreads + " sender threads."); @@ -73,6 +70,7 @@ public class NetworkStreamSender implements NextBlockRetriever { System.out.println("Trying http tunneling"); if (tryHttpTunneling()) { tunneling = true; + httpSenders = new NetworkHttpStreamSender[numThreads]; return true; } } else { @@ -83,28 +81,32 @@ public class NetworkStreamSender implements NextBlockRetriever { } private void createSender(int i) throws ConnectionException { - senders[i] = new NetworkSocketStreamSender(this); + senders[i] = new NetworkSocketStreamSender(this, room, screenDim, blockDim); senders[i].connect(host); } + public void send(EncodedBlockData data) { + blockDataQ.offer(data); + } + 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]); - } + for (int i = 0; i < numRunningThreads; i++) { + if (tunneling) { + httpSenders[i].sendStartStreamMessage(); + executor.execute(httpSenders[i]); + } else { + senders[i].sendStartStreamMessage(); + 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++) { + for (int i = 0; i < numRunningThreads; i++) { + if (tunneling) { + httpSenders[i].disconnect(); + } else { senders[i].disconnect(); } } @@ -113,7 +115,7 @@ public class NetworkStreamSender implements NextBlockRetriever { } private boolean tryHttpTunneling() { - httpSender = new NetworkHttpStreamSender(this); + NetworkHttpStreamSender httpSender = new NetworkHttpStreamSender(this, room, screenDim, blockDim); try { httpSender.connect(host); return true; @@ -123,14 +125,7 @@ public class NetworkStreamSender implements NextBlockRetriever { 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; - } + public EncodedBlockData fetchNextBlockToSend() throws InterruptedException { + return (EncodedBlockData) blockDataQ.take(); } } 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 3894e2b141..35eca6686d 100644 --- 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 @@ -21,9 +21,6 @@ */ package org.bigbluebutton.deskshare.client.net; -import org.bigbluebutton.deskshare.client.blocks.Block; - public interface NextBlockRetriever { - - public Block fetchNextBlockToSend(); + public EncodedBlockData fetchNextBlockToSend() throws InterruptedException; } 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 index 5956ccccf8..4ae439636d 100644 --- a/deskshare/common/src/main/java/org/bigbluebutton/deskshare/common/ScreenVideoEncoder.java +++ b/deskshare/common/src/main/java/org/bigbluebutton/deskshare/common/ScreenVideoEncoder.java @@ -84,11 +84,11 @@ public final class ScreenVideoEncoder { return pixels; } - public static byte[] encodePixels(int pixels[], int width, int height, boolean isRedTile, boolean isKeyFrame) { + public static byte[] encodePixels(int pixels[], int width, int height) { changePixelScanFromBottomLeftToTopRight(pixels, width, height); - byte[] bgrPixels = convertFromRGBtoBGR(pixels, isRedTile, isKeyFrame); + byte[] bgrPixels = convertFromRGBtoBGR(pixels); byte[] compressedPixels = compressUsingZlib(bgrPixels); @@ -165,7 +165,7 @@ public final class ScreenVideoEncoder { * @param pixels * @return pixels in BGR order */ - private static byte[] convertFromRGBtoBGR(int[] pixels, boolean isRedTile, boolean isKeyFrame) { + private static byte[] convertFromRGBtoBGR(int[] pixels) { long start = System.currentTimeMillis(); byte[] rgbPixels = new byte[pixels.length * 3]; int position = 0; @@ -175,21 +175,10 @@ public final class ScreenVideoEncoder { 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; - } + // Sequence should be BGR + rgbPixels[position++] = blue; + rgbPixels[position++] = green; + rgbPixels[position++] = red; } long end = System.currentTimeMillis();