Create a proper class hierarchy for the input packets. Implement MouseButton and MouseMove packets. Fix DNS resolution bug in NvConnection. Mouse move events are working.

This commit is contained in:
Cameron Gutman 2013-09-27 18:59:51 -04:00
parent b256f41a25
commit b4de9cbf50
7 changed files with 327 additions and 137 deletions

View File

@ -1,26 +1,10 @@
package com.limelight; package com.limelight;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import org.xmlpull.v1.XmlPullParserException;
import com.limelight.nvstream.NvConnection; import com.limelight.nvstream.NvConnection;
import com.limelight.nvstream.input.NvController; import com.limelight.nvstream.input.NvControllerPacket;
import com.limelight.nvstream.input.NvInputPacket;
import tv.ouya.console.api.OuyaController; import tv.ouya.console.api.OuyaController;
import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.media.AudioManager;
import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.KeyEvent; import android.view.KeyEvent;
@ -28,8 +12,6 @@ import android.view.MotionEvent;
import android.view.SurfaceView; import android.view.SurfaceView;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.MediaController;
import android.widget.VideoView;
public class Game extends Activity { public class Game extends Activity {
@ -40,6 +22,8 @@ public class Game extends Activity {
private short rightStickY = 0x0000; private short rightStickY = 0x0000;
private short leftStickX = 0x0000; private short leftStickX = 0x0000;
private short leftStickY = 0x0000; private short leftStickY = 0x0000;
private int lastMouseX = Integer.MIN_VALUE;
private int lastMouseY = Integer.MIN_VALUE;
private NvConnection conn; private NvConnection conn;
@ -71,48 +55,48 @@ public class Game extends Activity {
switch (keyCode) { switch (keyCode) {
case OuyaController.BUTTON_MENU: case OuyaController.BUTTON_MENU:
System.out.println("Menu Pressed"); System.out.println("Menu Pressed");
inputMap |= NvInputPacket.BACK_FLAG; inputMap |= NvControllerPacket.BACK_FLAG;
break; break;
case OuyaController.BUTTON_DPAD_LEFT: case OuyaController.BUTTON_DPAD_LEFT:
inputMap |= NvInputPacket.LEFT_FLAG; inputMap |= NvControllerPacket.LEFT_FLAG;
break; break;
case OuyaController.BUTTON_DPAD_RIGHT: case OuyaController.BUTTON_DPAD_RIGHT:
inputMap |= NvInputPacket.RIGHT_FLAG; inputMap |= NvControllerPacket.RIGHT_FLAG;
break; break;
case OuyaController.BUTTON_DPAD_UP: case OuyaController.BUTTON_DPAD_UP:
inputMap |= NvInputPacket.UP_FLAG; inputMap |= NvControllerPacket.UP_FLAG;
break; break;
case OuyaController.BUTTON_DPAD_DOWN: case OuyaController.BUTTON_DPAD_DOWN:
inputMap |= NvInputPacket.DOWN_FLAG; inputMap |= NvControllerPacket.DOWN_FLAG;
break; break;
case OuyaController.BUTTON_A: case OuyaController.BUTTON_A:
inputMap |= NvInputPacket.B_FLAG; inputMap |= NvControllerPacket.B_FLAG;
break; break;
case OuyaController.BUTTON_O: case OuyaController.BUTTON_O:
inputMap |= NvInputPacket.A_FLAG; inputMap |= NvControllerPacket.A_FLAG;
break; break;
case OuyaController.BUTTON_U: case OuyaController.BUTTON_U:
inputMap |= NvInputPacket.X_FLAG; inputMap |= NvControllerPacket.X_FLAG;
break; break;
case OuyaController.BUTTON_Y: case OuyaController.BUTTON_Y:
inputMap |= NvInputPacket.Y_FLAG; inputMap |= NvControllerPacket.Y_FLAG;
break; break;
case OuyaController.BUTTON_L1: case OuyaController.BUTTON_L1:
inputMap |= NvInputPacket.LB_FLAG; inputMap |= NvControllerPacket.LB_FLAG;
break; break;
case OuyaController.BUTTON_R1: case OuyaController.BUTTON_R1:
inputMap |= NvInputPacket.RB_FLAG; inputMap |= NvControllerPacket.RB_FLAG;
break; break;
case OuyaController.BUTTON_L3: case OuyaController.BUTTON_L3:
inputMap |= NvInputPacket.LS_CLK_FLAG; inputMap |= NvControllerPacket.LS_CLK_FLAG;
break; break;
case OuyaController.BUTTON_R3: case OuyaController.BUTTON_R3:
inputMap |= NvInputPacket.RS_CLK_FLAG; inputMap |= NvControllerPacket.RS_CLK_FLAG;
break; break;
default: default:
return super.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event);
} }
sendInputPacket(); sendControllerInputPacket();
return true; return true;
} }
@ -120,48 +104,48 @@ public class Game extends Activity {
public boolean onKeyUp(int keyCode, KeyEvent event) { public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) { switch (keyCode) {
case OuyaController.BUTTON_MENU: case OuyaController.BUTTON_MENU:
inputMap &= ~NvInputPacket.BACK_FLAG; inputMap &= ~NvControllerPacket.BACK_FLAG;
break; break;
case OuyaController.BUTTON_DPAD_LEFT: case OuyaController.BUTTON_DPAD_LEFT:
inputMap &= ~NvInputPacket.LEFT_FLAG; inputMap &= ~NvControllerPacket.LEFT_FLAG;
break; break;
case OuyaController.BUTTON_DPAD_RIGHT: case OuyaController.BUTTON_DPAD_RIGHT:
inputMap &= ~NvInputPacket.RIGHT_FLAG; inputMap &= ~NvControllerPacket.RIGHT_FLAG;
break; break;
case OuyaController.BUTTON_DPAD_UP: case OuyaController.BUTTON_DPAD_UP:
inputMap &= ~NvInputPacket.UP_FLAG; inputMap &= ~NvControllerPacket.UP_FLAG;
break; break;
case OuyaController.BUTTON_DPAD_DOWN: case OuyaController.BUTTON_DPAD_DOWN:
inputMap &= ~NvInputPacket.DOWN_FLAG; inputMap &= ~NvControllerPacket.DOWN_FLAG;
break; break;
case OuyaController.BUTTON_A: case OuyaController.BUTTON_A:
inputMap &= ~NvInputPacket.B_FLAG; inputMap &= ~NvControllerPacket.B_FLAG;
break; break;
case OuyaController.BUTTON_O: case OuyaController.BUTTON_O:
inputMap &= ~NvInputPacket.A_FLAG; inputMap &= ~NvControllerPacket.A_FLAG;
break; break;
case OuyaController.BUTTON_U: case OuyaController.BUTTON_U:
inputMap &= ~NvInputPacket.X_FLAG; inputMap &= ~NvControllerPacket.X_FLAG;
break; break;
case OuyaController.BUTTON_Y: case OuyaController.BUTTON_Y:
inputMap &= ~NvInputPacket.Y_FLAG; inputMap &= ~NvControllerPacket.Y_FLAG;
break; break;
case OuyaController.BUTTON_L1: case OuyaController.BUTTON_L1:
inputMap &= ~NvInputPacket.LB_FLAG; inputMap &= ~NvControllerPacket.LB_FLAG;
break; break;
case OuyaController.BUTTON_R1: case OuyaController.BUTTON_R1:
inputMap &= ~NvInputPacket.RB_FLAG; inputMap &= ~NvControllerPacket.RB_FLAG;
break; break;
case OuyaController.BUTTON_L3: case OuyaController.BUTTON_L3:
inputMap &= ~NvInputPacket.LS_CLK_FLAG; inputMap &= ~NvControllerPacket.LS_CLK_FLAG;
break; break;
case OuyaController.BUTTON_R3: case OuyaController.BUTTON_R3:
inputMap &= ~NvInputPacket.RS_CLK_FLAG; inputMap &= ~NvControllerPacket.RS_CLK_FLAG;
break; break;
default: default:
return super.onKeyUp(keyCode, event); return super.onKeyUp(keyCode, event);
} }
sendInputPacket(); sendControllerInputPacket();
return true; return true;
} }
@ -187,7 +171,6 @@ public class Game extends Activity {
rightStickX = (short)Math.round(RS_X * 0x7FFF); rightStickX = (short)Math.round(RS_X * 0x7FFF);
rightStickY = (short)Math.round(-RS_Y * 0x7FFF); rightStickY = (short)Math.round(-RS_Y * 0x7FFF);
}
float L2 = event.getAxisValue(OuyaController.AXIS_L2); float L2 = event.getAxisValue(OuyaController.AXIS_L2);
float R2 = event.getAxisValue(OuyaController.AXIS_R2); float R2 = event.getAxisValue(OuyaController.AXIS_R2);
@ -195,13 +178,41 @@ public class Game extends Activity {
leftTrigger = (byte)Math.round(L2 * 0xFF); leftTrigger = (byte)Math.round(L2 * 0xFF);
rightTrigger = (byte)Math.round(R2 * 0xFF); rightTrigger = (byte)Math.round(R2 * 0xFF);
sendInputPacket(); sendControllerInputPacket();
return true;
}
else if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0)
{
int eventX = (int)event.getX();
int eventY = (int)event.getY();
// Send a mouse move update (if neccessary)
updateMousePosition(eventX, eventY);
// Update pointer location for delta calculation next time
lastMouseX = eventX;
lastMouseY = eventY;
return true; return true;
} }
return super.onGenericMotionEvent(event);
}
private void sendInputPacket() { private void updateMousePosition(int eventX, int eventY) {
// Send a mouse move if we already have a mouse location
// and the mouse coordinates change
if (lastMouseX != Integer.MIN_VALUE &&
lastMouseY != Integer.MIN_VALUE &&
!(lastMouseX == eventX && lastMouseY == eventY))
{
System.out.printf("Delta X: 0x%x Delta Y: 0x%x\n",
(short)(eventX - lastMouseX), (short)(eventY - lastMouseY));
conn.sendMouseMove((short)(eventX - lastMouseX),
(short)(eventY - lastMouseY));
}
}
private void sendControllerInputPacket() {
conn.sendControllerInput(inputMap, leftTrigger, rightTrigger, conn.sendControllerInput(inputMap, leftTrigger, rightTrigger,
leftStickX, leftStickY, rightStickX, rightStickY); leftStickX, leftStickY, rightStickX, rightStickY);
} }

View File

@ -40,7 +40,7 @@ public class NvConnection {
@Override @Override
public void run() { public void run() {
try { try {
host = InetAddress.getByName(host).toString().substring(1); host = InetAddress.getByName(host).getHostAddress();
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
e.printStackTrace(); e.printStackTrace();
displayToast(e.getMessage()); displayToast(e.getMessage());
@ -70,6 +70,60 @@ public class NvConnection {
new NvVideoStream().startVideoStream(host, surface); new NvVideoStream().startVideoStream(host, surface);
} }
public void sendMouseMove(final short deltaX, final short deltaY)
{
if (inputStream == null)
return;
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
inputStream.sendMouseMove(deltaX, deltaY);
} catch (IOException e) {
e.printStackTrace();
displayToast(e.getMessage());
}
}
});
}
public void sendMouseButtonDown()
{
if (inputStream == null)
return;
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
inputStream.sendMouseButtonDown();
} catch (IOException e) {
e.printStackTrace();
displayToast(e.getMessage());
}
}
});
}
public void sendMouseButtonUp()
{
if (inputStream == null)
return;
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
inputStream.sendMouseButtonUp();
} catch (IOException e) {
e.printStackTrace();
displayToast(e.getMessage());
}
}
});
}
public void sendControllerInput(final short buttonFlags, public void sendControllerInput(final short buttonFlags,
final byte leftTrigger, final byte rightTrigger, final byte leftTrigger, final byte rightTrigger,
final short leftStickX, final short leftStickY, final short leftStickX, final short leftStickY,

View File

@ -22,9 +22,27 @@ public class NvController {
public void sendControllerInput(short buttonFlags, byte leftTrigger, byte rightTrigger, public void sendControllerInput(short buttonFlags, byte leftTrigger, byte rightTrigger,
short leftStickX, short leftStickY, short rightStickX, short rightStickY) throws IOException short leftStickX, short leftStickY, short rightStickX, short rightStickY) throws IOException
{ {
out.write(new NvInputPacket(buttonFlags, leftTrigger, out.write(new NvControllerPacket(buttonFlags, leftTrigger,
rightTrigger, leftStickX, leftStickY, rightTrigger, leftStickX, leftStickY,
rightStickX, rightStickY).toWire()); rightStickX, rightStickY).toWire());
out.flush(); out.flush();
} }
public void sendMouseButtonDown() throws IOException
{
out.write(new NvMouseButtonPacket(true).toWire());
out.flush();
}
public void sendMouseButtonUp() throws IOException
{
out.write(new NvMouseButtonPacket(false).toWire());
out.flush();
}
public void sendMouseMove(short deltaX, short deltaY) throws IOException
{
out.write(new NvMouseMovePacket(deltaX, deltaY).toWire());
out.flush();
}
} }

View File

@ -0,0 +1,88 @@
package com.limelight.nvstream.input;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class NvControllerPacket extends NvInputPacket {
public static final byte[] HEADER =
{
0x0A,
0x00,
0x00,
0x00,
0x00,
0x14
};
public static final byte[] TAIL =
{
(byte)0x9C,
0x00,
0x00,
0x00,
0x55,
0x00
};
public static final int PACKET_TYPE = 0x18;
public static final short A_FLAG = 0x1000;
public static final short B_FLAG = 0x2000;
public static final short X_FLAG = 0x4000;
public static final short Y_FLAG = (short)0x8000;
public static final short UP_FLAG = 0x0001;
public static final short DOWN_FLAG = 0x0002;
public static final short LEFT_FLAG = 0x0004;
public static final short RIGHT_FLAG = 0x0008;
public static final short LB_FLAG = 0x0100;
public static final short RB_FLAG = 0x0200;
public static final short PLAY_FLAG = 0x0010;
public static final short BACK_FLAG = 0x0020;
public static final short LS_CLK_FLAG = 0x0040;
public static final short RS_CLK_FLAG = 0x0080;
public static final short PAYLOAD_LENGTH = 24;
public static final short PACKET_LENGTH = PAYLOAD_LENGTH +
NvInputPacket.HEADER_LENGTH;
private short buttonFlags;
private byte leftTrigger;
private byte rightTrigger;
private short leftStickX;
private short leftStickY;
private short rightStickX;
private short rightStickY;
public NvControllerPacket(short buttonFlags, byte leftTrigger, byte rightTrigger,
short leftStickX, short leftStickY,
short rightStickX, short rightStickY)
{
super(PACKET_TYPE);
this.buttonFlags = buttonFlags;
this.leftTrigger = leftTrigger;
this.rightTrigger = rightTrigger;
this.leftStickX = leftStickX;
this.leftStickY = leftStickY;
this.rightStickX = rightStickX;
this.rightStickY = rightStickY;
}
public byte[] toWire()
{
ByteBuffer bb = ByteBuffer.allocate(PACKET_LENGTH).order(ByteOrder.LITTLE_ENDIAN);
bb.put(toWireHeader());
bb.put(HEADER);
bb.putShort(buttonFlags);
bb.put(leftTrigger);
bb.put(rightTrigger);
bb.putShort(leftStickX);
bb.putShort(leftStickY);
bb.putShort(rightStickX);
bb.putShort(rightStickY);
bb.put(TAIL);
return bb.array();
}
}

View File

@ -3,83 +3,24 @@ package com.limelight.nvstream.input;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
public class NvInputPacket { public abstract class NvInputPacket {
public static final byte[] HEADER = public static final int HEADER_LENGTH = 0x4;
protected int packetType;
public NvInputPacket(int packetType)
{ {
0x00, this.packetType = packetType;
0x00,
0x00,
0x18,
0x0A,
0x00,
0x00,
0x00,
0x00,
0x14
};
public static final byte[] TAIL =
{
(byte)0x9C,
0x00,
0x00,
0x00,
0x55,
0x00
};
public static final short A_FLAG = 0x1000;
public static final short B_FLAG = 0x2000;
public static final short X_FLAG = 0x4000;
public static final short Y_FLAG = (short)0x8000;
public static final short UP_FLAG = 0x0001;
public static final short DOWN_FLAG = 0x0002;
public static final short LEFT_FLAG = 0x0004;
public static final short RIGHT_FLAG = 0x0008;
public static final short LB_FLAG = 0x0100;
public static final short RB_FLAG = 0x0200;
public static final short PLAY_FLAG = 0x0010;
public static final short BACK_FLAG = 0x0020;
public static final short LS_CLK_FLAG = 0x0040;
public static final short RS_CLK_FLAG = 0x0080;
public static final short PACKET_LENGTH = 28;
private short buttonFlags;
private byte leftTrigger;
private byte rightTrigger;
private short leftStickX;
private short leftStickY;
private short rightStickX;
private short rightStickY;
public NvInputPacket(short buttonFlags, byte leftTrigger, byte rightTrigger,
short leftStickX, short leftStickY,
short rightStickX, short rightStickY)
{
this.buttonFlags = buttonFlags;
this.leftTrigger = leftTrigger;
this.rightTrigger = rightTrigger;
this.leftStickX = leftStickX;
this.leftStickY = leftStickY;
this.rightStickX = rightStickX;
this.rightStickY = rightStickY;
} }
public byte[] toWire() public abstract byte[] toWire();
{
ByteBuffer bb = ByteBuffer.allocate(PACKET_LENGTH).order(ByteOrder.LITTLE_ENDIAN);
bb.put(HEADER); public byte[] toWireHeader()
bb.putShort(buttonFlags); {
bb.put(leftTrigger); ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
bb.put(rightTrigger);
bb.putShort(leftStickX); bb.putInt(packetType);
bb.putShort(leftStickY);
bb.putShort(rightStickX);
bb.putShort(rightStickY);
bb.put(TAIL);
return bb.array(); return bb.array();
} }
} }

View File

@ -0,0 +1,36 @@
package com.limelight.nvstream.input;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class NvMouseButtonPacket extends NvInputPacket {
private byte buttonEventType;
public static final int PACKET_TYPE = 0x5;
public static final int PAYLOAD_LENGTH = 5;
public static final int PACKET_LENGTH = PAYLOAD_LENGTH +
NvInputPacket.HEADER_LENGTH;
public static final byte PRESS_EVENT = 0x07;
public static final byte RELEASE_EVENT = 0x08;
public NvMouseButtonPacket(boolean leftButtonDown)
{
super(PACKET_TYPE);
buttonEventType = leftButtonDown ?
PRESS_EVENT : RELEASE_EVENT;
}
@Override
public byte[] toWire() {
ByteBuffer bb = ByteBuffer.allocate(PACKET_LENGTH).order(ByteOrder.BIG_ENDIAN);
bb.put(toWireHeader());
bb.put(buttonEventType);
bb.putInt(1); // FIXME: button index?
return bb.array();
}
}

View File

@ -0,0 +1,42 @@
package com.limelight.nvstream.input;
import java.nio.ByteBuffer;
public class NvMouseMovePacket extends NvInputPacket {
private static final byte[] HEADER =
{
0x06,
0x00,
0x00,
0x00
};
public static final int PACKET_TYPE = 0x8;
public static final int PAYLOAD_LENGTH = 8;
public static final int PACKET_LENGTH = PAYLOAD_LENGTH +
NvInputPacket.HEADER_LENGTH;
private short deltaX;
private short deltaY;
public NvMouseMovePacket(short deltaX, short deltaY)
{
super(PACKET_TYPE);
this.deltaX = deltaX;
this.deltaY = deltaY;
}
@Override
public byte[] toWire() {
ByteBuffer bb = ByteBuffer.allocate(PACKET_LENGTH);
bb.put(toWireHeader());
bb.put(HEADER);
bb.putShort(deltaX);
bb.putShort(deltaY);
return bb.array();
}
}