Remove unnecessary byte buffer allocations in the input path

This commit is contained in:
Cameron Gutman 2014-09-14 23:58:42 -07:00
parent 50f8f78b8d
commit 4377808896
7 changed files with 115 additions and 59 deletions

View File

@ -68,12 +68,14 @@ public class ControllerPacket extends InputPacket {
this.rightStickX = rightStickX; this.rightStickX = rightStickX;
this.rightStickY = rightStickY; this.rightStickY = rightStickY;
} }
public byte[] toWire() @Override
{ public ByteOrder getPayloadByteOrder() {
ByteBuffer bb = ByteBuffer.allocate(PACKET_LENGTH).order(ByteOrder.LITTLE_ENDIAN); return ByteOrder.LITTLE_ENDIAN;
}
bb.put(toWireHeader());
@Override
public void toWirePayload(ByteBuffer bb) {
bb.put(HEADER); bb.put(HEADER);
bb.putShort(buttonFlags); bb.putShort(buttonFlags);
bb.put(leftTrigger); bb.put(leftTrigger);
@ -83,7 +85,10 @@ public class ControllerPacket extends InputPacket {
bb.putShort(rightStickX); bb.putShort(rightStickX);
bb.putShort(rightStickY); bb.putShort(rightStickY);
bb.put(TAIL); bb.put(TAIL);
}
return bb.array();
@Override
public int getPacketLength() {
return PACKET_LENGTH;
} }
} }

View File

@ -6,10 +6,10 @@ import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
@ -35,6 +35,10 @@ public class ControllerStream {
private Thread inputThread; private Thread inputThread;
private LinkedBlockingQueue<InputPacket> inputQueue = new LinkedBlockingQueue<InputPacket>(); private LinkedBlockingQueue<InputPacket> inputQueue = new LinkedBlockingQueue<InputPacket>();
private ByteBuffer littleEndianBuffer = ByteBuffer.allocate(128).order(ByteOrder.LITTLE_ENDIAN);
private ByteBuffer bigEndianBuffer = ByteBuffer.allocate(128).order(ByteOrder.BIG_ENDIAN);
private ByteBuffer sendBuffer = ByteBuffer.allocate(128).order(ByteOrder.BIG_ENDIAN);
public ControllerStream(InetAddress host, SecretKey riKey, int riKeyId, NvConnectionListener listener) public ControllerStream(InetAddress host, SecretKey riKey, int riKeyId, NvConnectionListener listener)
{ {
this.host = host; this.host = host;
@ -205,39 +209,53 @@ public class ControllerStream {
return ((length + 15) / 16) * 16; return ((length + 15) / 16) * 16;
} }
private static byte[] padData(byte[] data) { private static int inPlacePadData(byte[] data, int length) {
// This implements the PKCS7 padding algorithm // This implements the PKCS7 padding algorithm
if ((data.length % 16) == 0) { if ((length % 16) == 0) {
// Already a multiple of 16 // Already a multiple of 16
return data; return length;
} }
byte[] padded = Arrays.copyOf(data, getPaddedSize(data.length)); int paddedLength = getPaddedSize(length);
byte paddingByte = (byte)(16 - (data.length % 16)); byte paddingByte = (byte)(16 - (length % 16));
for (int i = data.length; i < padded.length; i++) { for (int i = length; i < paddedLength; i++) {
padded[i] = paddingByte; data[i] = paddingByte;
} }
return padded; return paddedLength;
} }
private byte[] encryptAesInputData(byte[] data) throws Exception { private int encryptAesInputData(byte[] inputData, int inputLength, byte[] outputData, int outputOffset) throws Exception {
return riCipher.update(padData(data)); int encryptedLength = inPlacePadData(inputData, inputLength);
riCipher.update(inputData, 0, encryptedLength, outputData, outputOffset);
return encryptedLength;
} }
private void sendPacket(InputPacket packet) throws IOException { private void sendPacket(InputPacket packet) throws IOException {
byte[] toWire = packet.toWire(); ByteBuffer toWireBuffer;
// Choose which byte order we'll be using for converting to wire form
if (packet.getPayloadByteOrder() == ByteOrder.BIG_ENDIAN) {
toWireBuffer = bigEndianBuffer;
}
else {
toWireBuffer = littleEndianBuffer;
}
// Store the packet in wire form in the byte buffer
packet.toWire(toWireBuffer);
int packetLen = packet.getPacketLength();
// Pad to 16 byte chunks // Pad to 16 byte chunks
int paddedLength = getPaddedSize(toWire.length); int paddedLength = getPaddedSize(packetLen);
// Allocate a byte buffer to represent the final packet // Allocate a byte buffer to represent the final packet
ByteBuffer bb = ByteBuffer.allocate(4 + paddedLength); sendBuffer.rewind();
bb.putInt(paddedLength); sendBuffer.putInt(paddedLength);
try { try {
bb.put(encryptAesInputData(toWire)); encryptAesInputData(toWireBuffer.array(), packetLen, sendBuffer.array(), 4);
} catch (Exception e) { } catch (Exception e) {
// Should never happen // Should never happen
e.printStackTrace(); e.printStackTrace();
@ -245,7 +263,7 @@ public class ControllerStream {
} }
// Send the packet // Send the packet
out.write(bb.array()); out.write(sendBuffer.array(), 0, paddedLength + 4);
out.flush(); out.flush();
} }

View File

@ -13,14 +13,26 @@ public abstract class InputPacket {
this.packetType = packetType; this.packetType = packetType;
} }
public abstract byte[] toWire(); public abstract ByteOrder getPayloadByteOrder();
public byte[] toWireHeader() public abstract void toWirePayload(ByteBuffer bb);
public abstract int getPacketLength();
public void toWireHeader(ByteBuffer bb)
{ {
ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN); // We don't use putInt() here because it will be subject to the byte order
// of the byte buffer. We just write it as a big endian int.
bb.putInt(packetType); bb.put((byte)(packetType >> 24));
bb.put((byte)(packetType >> 16));
return bb.array(); bb.put((byte)(packetType >> 8));
bb.put((byte)(packetType & 0xFF));
}
public void toWire(ByteBuffer bb)
{
bb.rewind();
toWireHeader(bb);
toWirePayload(bb);
} }
} }

View File

@ -5,7 +5,7 @@ import java.nio.ByteOrder;
public class KeyboardPacket extends InputPacket { public class KeyboardPacket extends InputPacket {
private static final int PACKET_TYPE = 0x0A; private static final int PACKET_TYPE = 0x0A;
private static final int PACKET_LENGTH = 14; public static final int PACKET_LENGTH = 14;
public static final byte KEY_DOWN = 0x03; public static final byte KEY_DOWN = 0x03;
public static final byte KEY_UP = 0x04; public static final byte KEY_UP = 0x04;
@ -14,7 +14,6 @@ public class KeyboardPacket extends InputPacket {
public static final byte MODIFIER_CTRL = 0x02; public static final byte MODIFIER_CTRL = 0x02;
public static final byte MODIFIER_ALT = 0x04; public static final byte MODIFIER_ALT = 0x04;
short keyCode; short keyCode;
byte keyDirection; byte keyDirection;
byte modifier; byte modifier;
@ -25,12 +24,14 @@ public class KeyboardPacket extends InputPacket {
this.keyDirection = keyDirection; this.keyDirection = keyDirection;
this.modifier = modifier; this.modifier = modifier;
} }
@Override @Override
public byte[] toWire() { public ByteOrder getPayloadByteOrder() {
ByteBuffer bb = ByteBuffer.allocate(PACKET_LENGTH).order(ByteOrder.LITTLE_ENDIAN); return ByteOrder.LITTLE_ENDIAN;
}
bb.put(toWireHeader());
@Override
public void toWirePayload(ByteBuffer bb) {
bb.put(keyDirection); bb.put(keyDirection);
bb.putShort((short)0); bb.putShort((short)0);
bb.putShort((short)0); bb.putShort((short)0);
@ -38,7 +39,10 @@ public class KeyboardPacket extends InputPacket {
bb.put(modifier); bb.put(modifier);
bb.put((byte)0); bb.put((byte)0);
bb.put((byte)0); bb.put((byte)0);
}
return bb.array(); @Override
public int getPacketLength() {
return PACKET_LENGTH;
} }
} }

View File

@ -31,13 +31,18 @@ public class MouseButtonPacket extends InputPacket {
} }
@Override @Override
public byte[] toWire() { public ByteOrder getPayloadByteOrder() {
ByteBuffer bb = ByteBuffer.allocate(PACKET_LENGTH).order(ByteOrder.BIG_ENDIAN); return ByteOrder.BIG_ENDIAN;
}
bb.put(toWireHeader());
@Override
public void toWirePayload(ByteBuffer bb) {
bb.put(buttonEventType); bb.put(buttonEventType);
bb.putInt(mouseButton); bb.putInt(mouseButton);
}
return bb.array();
@Override
public int getPacketLength() {
return PACKET_LENGTH;
} }
} }

View File

@ -1,6 +1,7 @@
package com.limelight.nvstream.input; package com.limelight.nvstream.input;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class MouseMovePacket extends InputPacket { public class MouseMovePacket extends InputPacket {
@ -29,14 +30,19 @@ public class MouseMovePacket extends InputPacket {
} }
@Override @Override
public byte[] toWire() { public ByteOrder getPayloadByteOrder() {
ByteBuffer bb = ByteBuffer.allocate(PACKET_LENGTH); return ByteOrder.BIG_ENDIAN;
}
bb.put(toWireHeader());
@Override
public void toWirePayload(ByteBuffer bb) {
bb.put(HEADER); bb.put(HEADER);
bb.putShort(deltaX); bb.putShort(deltaX);
bb.putShort(deltaY); bb.putShort(deltaY);
}
return bb.array();
@Override
public int getPacketLength() {
return PACKET_LENGTH;
} }
} }

View File

@ -1,6 +1,7 @@
package com.limelight.nvstream.input; package com.limelight.nvstream.input;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class MouseScrollPacket extends InputPacket { public class MouseScrollPacket extends InputPacket {
public static final int PACKET_TYPE = 0xa; public static final int PACKET_TYPE = 0xa;
@ -17,10 +18,12 @@ public class MouseScrollPacket extends InputPacket {
} }
@Override @Override
public byte[] toWire() { public ByteOrder getPayloadByteOrder() {
ByteBuffer bb = ByteBuffer.allocate(PACKET_LENGTH); return ByteOrder.BIG_ENDIAN;
}
bb.put(toWireHeader());
@Override
public void toWirePayload(ByteBuffer bb) {
bb.put((byte) 0x09); bb.put((byte) 0x09);
bb.put((byte) 0); bb.put((byte) 0);
bb.put((byte) 0); bb.put((byte) 0);
@ -30,7 +33,10 @@ public class MouseScrollPacket extends InputPacket {
bb.putShort(scroll); bb.putShort(scroll);
bb.putShort((short) 0); bb.putShort((short) 0);
}
return bb.array();
@Override
public int getPacketLength() {
return PACKET_LENGTH;
} }
} }