diff --git a/.classpath b/.classpath
index 7bc01d9a..fbf44eae 100644
--- a/.classpath
+++ b/.classpath
@@ -5,5 +5,6 @@
+
diff --git a/libs/limelight-common.jar b/libs/limelight-common.jar
new file mode 100644
index 00000000..a6546181
Binary files /dev/null and b/libs/limelight-common.jar differ
diff --git a/src/com/limelight/Connection.java b/src/com/limelight/Connection.java
index b8cf3416..d7f57734 100644
--- a/src/com/limelight/Connection.java
+++ b/src/com/limelight/Connection.java
@@ -8,12 +8,11 @@ import java.net.UnknownHostException;
import org.xmlpull.v1.XmlPullParserException;
+import com.limelight.binding.PlatformBinding;
import com.limelight.nvstream.NvConnection;
-import com.limelight.nvstream.NvHTTP;
-import com.limelight.nvstream.NvmDNS;
+import com.limelight.nvstream.http.NvHTTP;
import android.os.Bundle;
-import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
@@ -50,13 +49,6 @@ public class Connection extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Log.v("NvmDNS", "onCreate");
-
-
- NvmDNS dns = new NvmDNS();
- dns.execute();
-
-
setContentView(R.layout.activity_connection);
this.statusButton = (Button) findViewById(R.id.statusButton);
@@ -109,7 +101,8 @@ public class Connection extends Activity {
NvHTTP httpConn;
String message;
try {
- httpConn = new NvHTTP(InetAddress.getByName(hostText.getText().toString()), macAddress);
+ httpConn = new NvHTTP(InetAddress.getByName(hostText.getText().toString()),
+ macAddress, PlatformBinding.getDeviceName());
try {
if (httpConn.getPairState()) {
message = "Already paired";
diff --git a/src/com/limelight/Game.java b/src/com/limelight/Game.java
index e0ebf889..66da1f29 100644
--- a/src/com/limelight/Game.java
+++ b/src/com/limelight/Game.java
@@ -1,9 +1,10 @@
package com.limelight;
+import com.limelight.binding.PlatformBinding;
import com.limelight.nvstream.NvConnection;
import com.limelight.nvstream.NvConnectionListener;
-import com.limelight.nvstream.av.video.DecoderRenderer;
-import com.limelight.nvstream.input.NvControllerPacket;
+import com.limelight.nvstream.av.video.VideoDecoderRenderer;
+import com.limelight.nvstream.input.ControllerPacket;
import com.limelight.utils.Dialog;
import com.limelight.utils.SpinnerDialog;
@@ -11,6 +12,7 @@ import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.PixelFormat;
+import android.net.ConnectivityManager;
import android.os.Bundle;
import android.view.InputDevice;
import android.view.KeyEvent;
@@ -22,6 +24,7 @@ import android.view.View.OnGenericMotionListener;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
+import android.widget.Toast;
public class Game extends Activity implements OnGenericMotionListener, OnTouchListener, NvConnectionListener {
@@ -77,15 +80,27 @@ public class Game extends Activity implements OnGenericMotionListener, OnTouchLi
SharedPreferences prefs = getSharedPreferences(PREFS_FILE_NAME, Context.MODE_MULTI_PROCESS);
int drFlags = 0;
if (prefs.getBoolean(QUALITY_PREF_STRING, false)) {
- drFlags |= DecoderRenderer.FLAG_PREFER_QUALITY;
+ drFlags |= VideoDecoderRenderer.FLAG_PREFER_QUALITY;
}
+
+ // Warn the user if they're on a metered connection
+ checkDataConnection();
// Start the connection
- conn = new NvConnection(Game.this.getIntent().getStringExtra("host"), Game.this, sv.getHolder(), drFlags);
- conn.start();
+ conn = new NvConnection(Game.this.getIntent().getStringExtra("host"), Game.this);
+ conn.start(PlatformBinding.getDeviceName(), sv.getHolder(), drFlags,
+ PlatformBinding.getAudioRenderer(), PlatformBinding.chooseDecoderRenderer());
+ }
+
+ private void checkDataConnection()
+ {
+ ConnectivityManager mgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (mgr.isActiveNetworkMetered()) {
+ displayMessage("Warning: Your active network connection is metered!");
+ }
}
- public void hideSystemUi() {
+ private void hideSystemUi() {
runOnUiThread(new Runnable() {
@Override
public void run() {
@@ -128,58 +143,58 @@ public class Game extends Activity implements OnGenericMotionListener, OnTouchLi
switch (keyCode) {
case KeyEvent.KEYCODE_BUTTON_START:
case KeyEvent.KEYCODE_MENU:
- inputMap |= NvControllerPacket.PLAY_FLAG;
+ inputMap |= ControllerPacket.PLAY_FLAG;
break;
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_BUTTON_SELECT:
- inputMap |= NvControllerPacket.BACK_FLAG;
+ inputMap |= ControllerPacket.BACK_FLAG;
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
- inputMap |= NvControllerPacket.LEFT_FLAG;
+ inputMap |= ControllerPacket.LEFT_FLAG;
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
- inputMap |= NvControllerPacket.RIGHT_FLAG;
+ inputMap |= ControllerPacket.RIGHT_FLAG;
break;
case KeyEvent.KEYCODE_DPAD_UP:
- inputMap |= NvControllerPacket.UP_FLAG;
+ inputMap |= ControllerPacket.UP_FLAG;
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
- inputMap |= NvControllerPacket.DOWN_FLAG;
+ inputMap |= ControllerPacket.DOWN_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_B:
- inputMap |= NvControllerPacket.B_FLAG;
+ inputMap |= ControllerPacket.B_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_A:
- inputMap |= NvControllerPacket.A_FLAG;
+ inputMap |= ControllerPacket.A_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_X:
- inputMap |= NvControllerPacket.X_FLAG;
+ inputMap |= ControllerPacket.X_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_Y:
- inputMap |= NvControllerPacket.Y_FLAG;
+ inputMap |= ControllerPacket.Y_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_L1:
- inputMap |= NvControllerPacket.LB_FLAG;
+ inputMap |= ControllerPacket.LB_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_R1:
- inputMap |= NvControllerPacket.RB_FLAG;
+ inputMap |= ControllerPacket.RB_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_THUMBL:
- inputMap |= NvControllerPacket.LS_CLK_FLAG;
+ inputMap |= ControllerPacket.LS_CLK_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_THUMBR:
- inputMap |= NvControllerPacket.RS_CLK_FLAG;
+ inputMap |= ControllerPacket.RS_CLK_FLAG;
break;
default:
return super.onKeyDown(keyCode, event);
}
// We detect back+start as the special button combo
- if ((inputMap & NvControllerPacket.BACK_FLAG) != 0 &&
- (inputMap & NvControllerPacket.PLAY_FLAG) != 0)
+ if ((inputMap & ControllerPacket.BACK_FLAG) != 0 &&
+ (inputMap & ControllerPacket.PLAY_FLAG) != 0)
{
- inputMap &= ~(NvControllerPacket.BACK_FLAG | NvControllerPacket.PLAY_FLAG);
- inputMap |= NvControllerPacket.SPECIAL_BUTTON_FLAG;
+ inputMap &= ~(ControllerPacket.BACK_FLAG | ControllerPacket.PLAY_FLAG);
+ inputMap |= ControllerPacket.SPECIAL_BUTTON_FLAG;
}
sendControllerInputPacket();
@@ -191,57 +206,57 @@ public class Game extends Activity implements OnGenericMotionListener, OnTouchLi
switch (keyCode) {
case KeyEvent.KEYCODE_BUTTON_START:
case KeyEvent.KEYCODE_MENU:
- inputMap &= ~NvControllerPacket.PLAY_FLAG;
+ inputMap &= ~ControllerPacket.PLAY_FLAG;
break;
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_BUTTON_SELECT:
- inputMap &= ~NvControllerPacket.BACK_FLAG;
+ inputMap &= ~ControllerPacket.BACK_FLAG;
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
- inputMap &= ~NvControllerPacket.LEFT_FLAG;
+ inputMap &= ~ControllerPacket.LEFT_FLAG;
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
- inputMap &= ~NvControllerPacket.RIGHT_FLAG;
+ inputMap &= ~ControllerPacket.RIGHT_FLAG;
break;
case KeyEvent.KEYCODE_DPAD_UP:
- inputMap &= ~NvControllerPacket.UP_FLAG;
+ inputMap &= ~ControllerPacket.UP_FLAG;
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
- inputMap &= ~NvControllerPacket.DOWN_FLAG;
+ inputMap &= ~ControllerPacket.DOWN_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_B:
- inputMap &= ~NvControllerPacket.B_FLAG;
+ inputMap &= ~ControllerPacket.B_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_A:
- inputMap &= ~NvControllerPacket.A_FLAG;
+ inputMap &= ~ControllerPacket.A_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_X:
- inputMap &= ~NvControllerPacket.X_FLAG;
+ inputMap &= ~ControllerPacket.X_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_Y:
- inputMap &= ~NvControllerPacket.Y_FLAG;
+ inputMap &= ~ControllerPacket.Y_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_L1:
- inputMap &= ~NvControllerPacket.LB_FLAG;
+ inputMap &= ~ControllerPacket.LB_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_R1:
- inputMap &= ~NvControllerPacket.RB_FLAG;
+ inputMap &= ~ControllerPacket.RB_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_THUMBL:
- inputMap &= ~NvControllerPacket.LS_CLK_FLAG;
+ inputMap &= ~ControllerPacket.LS_CLK_FLAG;
break;
case KeyEvent.KEYCODE_BUTTON_THUMBR:
- inputMap &= ~NvControllerPacket.RS_CLK_FLAG;
+ inputMap &= ~ControllerPacket.RS_CLK_FLAG;
break;
default:
return super.onKeyUp(keyCode, event);
}
// If one of the two is up, the special button comes up too
- if ((inputMap & NvControllerPacket.BACK_FLAG) == 0 ||
- (inputMap & NvControllerPacket.PLAY_FLAG) == 0)
+ if ((inputMap & ControllerPacket.BACK_FLAG) == 0 ||
+ (inputMap & ControllerPacket.PLAY_FLAG) == 0)
{
- inputMap &= ~NvControllerPacket.SPECIAL_BUTTON_FLAG;
+ inputMap &= ~ControllerPacket.SPECIAL_BUTTON_FLAG;
}
sendControllerInputPacket();
@@ -398,19 +413,19 @@ public class Game extends Activity implements OnGenericMotionListener, OnTouchLi
hatX = event.getAxisValue(MotionEvent.AXIS_HAT_X);
hatY = event.getAxisValue(MotionEvent.AXIS_HAT_Y);
- inputMap &= ~(NvControllerPacket.LEFT_FLAG | NvControllerPacket.RIGHT_FLAG);
- inputMap &= ~(NvControllerPacket.UP_FLAG | NvControllerPacket.DOWN_FLAG);
+ inputMap &= ~(ControllerPacket.LEFT_FLAG | ControllerPacket.RIGHT_FLAG);
+ inputMap &= ~(ControllerPacket.UP_FLAG | ControllerPacket.DOWN_FLAG);
if (hatX < -0.5) {
- inputMap |= NvControllerPacket.LEFT_FLAG;
+ inputMap |= ControllerPacket.LEFT_FLAG;
}
if (hatX > 0.5) {
- inputMap |= NvControllerPacket.RIGHT_FLAG;
+ inputMap |= ControllerPacket.RIGHT_FLAG;
}
if (hatY < -0.5) {
- inputMap |= NvControllerPacket.UP_FLAG;
+ inputMap |= ControllerPacket.UP_FLAG;
}
if (hatY > 0.5) {
- inputMap |= NvControllerPacket.DOWN_FLAG;
+ inputMap |= ControllerPacket.DOWN_FLAG;
}
}
@@ -506,5 +521,17 @@ public class Game extends Activity implements OnGenericMotionListener, OnTouchLi
public void connectionStarted() {
spinner.dismiss();
spinner = null;
+
+ hideSystemUi();
+ }
+
+ @Override
+ public void displayMessage(final String message) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(Game.this, message, Toast.LENGTH_LONG).show();
+ }
+ });
}
}
diff --git a/src/com/limelight/binding/PlatformBinding.java b/src/com/limelight/binding/PlatformBinding.java
new file mode 100644
index 00000000..3544d429
--- /dev/null
+++ b/src/com/limelight/binding/PlatformBinding.java
@@ -0,0 +1,36 @@
+package com.limelight.binding;
+
+import android.os.Build;
+
+import com.limelight.binding.audio.AndroidAudioRenderer;
+import com.limelight.binding.video.AndroidCpuDecoderRenderer;
+import com.limelight.binding.video.MediaCodecDecoderRenderer;
+import com.limelight.nvstream.av.audio.AudioRenderer;
+import com.limelight.nvstream.av.video.VideoDecoderRenderer;
+
+public class PlatformBinding {
+ public static VideoDecoderRenderer chooseDecoderRenderer() {
+ if (Build.HARDWARE.equals("goldfish")) {
+ // Emulator - don't render video (it's slow!)
+ return null;
+ }
+ /*else if (MediaCodecDecoderRenderer.findSafeDecoder() != null) {
+ // Hardware decoding
+ return new MediaCodecDecoderRenderer();
+ }*/
+ else {
+ // Software decoding
+ return new AndroidCpuDecoderRenderer();
+ }
+ }
+
+ public static String getDeviceName() {
+ String deviceName = android.os.Build.MODEL;
+ deviceName = deviceName.replace(" ", "");
+ return deviceName;
+ }
+
+ public static AudioRenderer getAudioRenderer() {
+ return new AndroidAudioRenderer();
+ }
+}
diff --git a/src/com/limelight/binding/audio/AndroidAudioRenderer.java b/src/com/limelight/binding/audio/AndroidAudioRenderer.java
new file mode 100644
index 00000000..d02e3cd6
--- /dev/null
+++ b/src/com/limelight/binding/audio/AndroidAudioRenderer.java
@@ -0,0 +1,50 @@
+package com.limelight.binding.audio;
+
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+
+import com.limelight.nvstream.av.audio.AudioRenderer;
+
+public class AndroidAudioRenderer implements AudioRenderer {
+
+ private AudioTrack track;
+
+ @Override
+ public void streamInitialized(int channelCount, int sampleRate) {
+ int channelConfig;
+
+ switch (channelCount)
+ {
+ case 1:
+ channelConfig = AudioFormat.CHANNEL_OUT_MONO;
+ break;
+ case 2:
+ channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
+ break;
+ default:
+ throw new IllegalArgumentException("Decoder returned unhandled channel count");
+ }
+
+ track = new AudioTrack(AudioManager.STREAM_MUSIC,
+ sampleRate,
+ channelConfig,
+ AudioFormat.ENCODING_PCM_16BIT,
+ 1024, // 1KB buffer
+ AudioTrack.MODE_STREAM);
+
+ track.play();
+ }
+
+ @Override
+ public void playDecodedAudio(short[] audioData, int offset, int length) {
+ track.write(audioData, offset, length);
+ }
+
+ @Override
+ public void streamClosing() {
+ if (track != null) {
+ track.release();
+ }
+ }
+}
diff --git a/src/com/limelight/nvstream/av/video/cpu/CpuDecoderRenderer.java b/src/com/limelight/binding/video/AndroidCpuDecoderRenderer.java
similarity index 80%
rename from src/com/limelight/nvstream/av/video/cpu/CpuDecoderRenderer.java
rename to src/com/limelight/binding/video/AndroidCpuDecoderRenderer.java
index a749c019..4f4adb5f 100644
--- a/src/com/limelight/nvstream/av/video/cpu/CpuDecoderRenderer.java
+++ b/src/com/limelight/binding/video/AndroidCpuDecoderRenderer.java
@@ -1,4 +1,4 @@
-package com.limelight.nvstream.av.video.cpu;
+package com.limelight.binding.video;
import java.io.BufferedReader;
import java.io.File;
@@ -6,14 +6,14 @@ import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
-import android.content.Context;
import android.view.SurfaceHolder;
-import com.limelight.nvstream.av.AvByteBufferDescriptor;
-import com.limelight.nvstream.av.AvDecodeUnit;
-import com.limelight.nvstream.av.video.DecoderRenderer;
+import com.limelight.nvstream.av.ByteBufferDescriptor;
+import com.limelight.nvstream.av.DecodeUnit;
+import com.limelight.nvstream.av.video.VideoDecoderRenderer;
+import com.limelight.nvstream.av.video.cpu.AvcDecoder;
-public class CpuDecoderRenderer implements DecoderRenderer {
+public class AndroidCpuDecoderRenderer implements VideoDecoderRenderer {
private Thread rendererThread;
private int targetFps;
@@ -21,9 +21,6 @@ public class CpuDecoderRenderer implements DecoderRenderer {
private static final int DECODER_BUFFER_SIZE = 92*1024;
private ByteBuffer decoderBuffer;
- private RsRenderer rsRenderer;
- private byte[] frameBuffer;
-
// Only sleep if the difference is above this value
private static final int WAIT_CEILING_MS = 8;
@@ -81,7 +78,7 @@ public class CpuDecoderRenderer implements DecoderRenderer {
}
@Override
- public void setup(Context context, int width, int height, SurfaceHolder renderTarget, int drFlags) {
+ public void setup(int width, int height, Object renderTarget, int drFlags) {
this.targetFps = 30;
int perfLevel = findOptimalPerformanceLevel();
@@ -115,14 +112,8 @@ public class CpuDecoderRenderer implements DecoderRenderer {
break;
}
- // Create and initialize the RenderScript intrinsic we'll be using
- rsRenderer = new RsRenderer(context, width, height, renderTarget.getSurface());
-
- // Allocate the frame buffer that the RGBA frame will be copied into
- frameBuffer = new byte[width*height*4];
-
// If the user wants quality, we'll remove the low IQ flags
- if ((drFlags & DecoderRenderer.FLAG_PREFER_QUALITY) != 0) {
+ if ((drFlags & VideoDecoderRenderer.FLAG_PREFER_QUALITY) != 0) {
// Make sure the loop filter is enabled
avcFlags &= ~AvcDecoder.DISABLE_LOOP_FILTER;
@@ -137,6 +128,8 @@ public class CpuDecoderRenderer implements DecoderRenderer {
throw new IllegalStateException("AVC decoder initialization failure: "+err);
}
+ AvcDecoder.setRenderTarget(((SurfaceHolder)renderTarget).getSurface());
+
decoderBuffer = ByteBuffer.allocate(DECODER_BUFFER_SIZE + AvcDecoder.getInputPaddingSize());
System.out.println("Using software decoding (performance level: "+perfLevel+")");
@@ -162,9 +155,7 @@ public class CpuDecoderRenderer implements DecoderRenderer {
}
nextFrameTime = computePresentationTimeMs(targetFps);
- if (AvcDecoder.getRgbFrame(frameBuffer, frameBuffer.length)) {
- rsRenderer.render(frameBuffer);
- }
+ AvcDecoder.redraw();
}
}
};
@@ -187,22 +178,18 @@ public class CpuDecoderRenderer implements DecoderRenderer {
@Override
public void release() {
- if (rsRenderer != null) {
- rsRenderer.release();
- }
-
AvcDecoder.destroy();
}
@Override
- public boolean submitDecodeUnit(AvDecodeUnit decodeUnit) {
+ public boolean submitDecodeUnit(DecodeUnit decodeUnit) {
byte[] data;
// Use the reserved decoder buffer if this decode unit will fit
if (decodeUnit.getDataLength() <= DECODER_BUFFER_SIZE) {
decoderBuffer.clear();
- for (AvByteBufferDescriptor bbd : decodeUnit.getBufferList()) {
+ for (ByteBufferDescriptor bbd : decodeUnit.getBufferList()) {
decoderBuffer.put(bbd.data, bbd.offset, bbd.length);
}
@@ -212,7 +199,7 @@ public class CpuDecoderRenderer implements DecoderRenderer {
data = new byte[decodeUnit.getDataLength()+AvcDecoder.getInputPaddingSize()];
int offset = 0;
- for (AvByteBufferDescriptor bbd : decodeUnit.getBufferList()) {
+ for (ByteBufferDescriptor bbd : decodeUnit.getBufferList()) {
System.arraycopy(bbd.data, bbd.offset, data, offset, bbd.length);
offset += bbd.length;
}
diff --git a/src/com/limelight/nvstream/av/video/MediaCodecDecoderRenderer.java b/src/com/limelight/binding/video/MediaCodecDecoderRenderer.java
similarity index 85%
rename from src/com/limelight/nvstream/av/video/MediaCodecDecoderRenderer.java
rename to src/com/limelight/binding/video/MediaCodecDecoderRenderer.java
index c4226085..9aa450fb 100644
--- a/src/com/limelight/nvstream/av/video/MediaCodecDecoderRenderer.java
+++ b/src/com/limelight/binding/video/MediaCodecDecoderRenderer.java
@@ -1,24 +1,21 @@
-package com.limelight.nvstream.av.video;
+package com.limelight.binding.video;
import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.List;
-import com.limelight.nvstream.av.AvByteBufferDescriptor;
-import com.limelight.nvstream.av.AvDecodeUnit;
+import com.limelight.nvstream.av.ByteBufferDescriptor;
+import com.limelight.nvstream.av.DecodeUnit;
+import com.limelight.nvstream.av.video.VideoDecoderRenderer;
-import android.annotation.TargetApi;
-import android.content.Context;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.media.MediaCodec.BufferInfo;
-import android.os.Build;
import android.view.SurfaceHolder;
-@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
-public class MediaCodecDecoderRenderer implements DecoderRenderer {
+public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
private ByteBuffer[] videoDecoderInputBuffers;
private MediaCodec videoDecoder;
@@ -74,11 +71,11 @@ public class MediaCodecDecoderRenderer implements DecoderRenderer {
}
@Override
- public void setup(Context context, int width, int height, SurfaceHolder renderTarget, int drFlags) {
+ public void setup(int width, int height, Object renderTarget, int drFlags) {
videoDecoder = MediaCodec.createByCodecName(findSafeDecoder().getName());
MediaFormat videoFormat = MediaFormat.createVideoFormat("video/avc", width, height);
- videoDecoder.configure(videoFormat, renderTarget.getSurface(), null, 0);
+ videoDecoder.configure(videoFormat, ((SurfaceHolder)renderTarget).getSurface(), null, 0);
videoDecoder.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);
@@ -157,8 +154,8 @@ public class MediaCodecDecoderRenderer implements DecoderRenderer {
}
@Override
- public boolean submitDecodeUnit(AvDecodeUnit decodeUnit) {
- if (decodeUnit.getType() != AvDecodeUnit.TYPE_H264) {
+ public boolean submitDecodeUnit(DecodeUnit decodeUnit) {
+ if (decodeUnit.getType() != DecodeUnit.TYPE_H264) {
System.err.println("Unknown decode unit type");
return false;
}
@@ -172,7 +169,7 @@ public class MediaCodecDecoderRenderer implements DecoderRenderer {
buf.clear();
// Copy data from our buffer list into the input buffer
- for (AvByteBufferDescriptor desc : decodeUnit.getBufferList())
+ for (ByteBufferDescriptor desc : decodeUnit.getBufferList())
{
buf.put(desc.data, desc.offset, desc.length);
}
diff --git a/src/com/limelight/nvstream/av/video/cpu/RsRenderer.java b/src/com/limelight/binding/video/RsRenderer.java
similarity index 95%
rename from src/com/limelight/nvstream/av/video/cpu/RsRenderer.java
rename to src/com/limelight/binding/video/RsRenderer.java
index d461e13d..7491bfed 100644
--- a/src/com/limelight/nvstream/av/video/cpu/RsRenderer.java
+++ b/src/com/limelight/binding/video/RsRenderer.java
@@ -1,4 +1,4 @@
-package com.limelight.nvstream.av.video.cpu;
+package com.limelight.binding.video;
import android.content.Context;
import android.renderscript.Allocation;
diff --git a/src/com/limelight/nvstream/NvApp.java b/src/com/limelight/nvstream/NvApp.java
deleted file mode 100644
index e30c7820..00000000
--- a/src/com/limelight/nvstream/NvApp.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.limelight.nvstream;
-
-public class NvApp {
- private String appName;
- private int appId;
- private boolean isRunning;
-
- public void setAppName(String appName) {
- this.appName = appName;
- }
-
- public void setAppId(String appId) {
- this.appId = Integer.parseInt(appId);
- }
-
- public void setIsRunning(String isRunning) {
- this.isRunning = isRunning.equals("1");
- }
-
- public String getAppName() {
- return this.appName;
- }
-
- public int getAppId() {
- return this.appId;
- }
-
- public boolean getIsRunning() {
- return this.isRunning;
- }
-}
diff --git a/src/com/limelight/nvstream/NvAudioStream.java b/src/com/limelight/nvstream/NvAudioStream.java
deleted file mode 100644
index 9c722924..00000000
--- a/src/com/limelight/nvstream/NvAudioStream.java
+++ /dev/null
@@ -1,250 +0,0 @@
-package com.limelight.nvstream;
-
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketException;
-import java.util.LinkedList;
-import java.util.concurrent.LinkedBlockingQueue;
-
-import com.limelight.nvstream.av.AvByteBufferDescriptor;
-import com.limelight.nvstream.av.AvRtpPacket;
-import com.limelight.nvstream.av.AvShortBufferDescriptor;
-import com.limelight.nvstream.av.audio.AvAudioDepacketizer;
-import com.limelight.nvstream.av.audio.OpusDecoder;
-
-import android.media.AudioFormat;
-import android.media.AudioManager;
-import android.media.AudioTrack;
-
-public class NvAudioStream {
- public static final int RTP_PORT = 48000;
- public static final int RTCP_PORT = 47999;
-
- private LinkedBlockingQueue packets = new LinkedBlockingQueue(100);
-
- private AudioTrack track;
-
- private DatagramSocket rtp;
-
- private AvAudioDepacketizer depacketizer = new AvAudioDepacketizer();
-
- private LinkedList threads = new LinkedList();
-
- private boolean aborting = false;
-
- private InetAddress host;
- private NvConnectionListener listener;
-
- public NvAudioStream(InetAddress host, NvConnectionListener listener)
- {
- this.host = host;
- this.listener = listener;
- }
-
- public void abort()
- {
- if (aborting) {
- return;
- }
-
- aborting = true;
-
- for (Thread t : threads) {
- t.interrupt();
- }
-
- // Close the socket to interrupt the receive thread
- if (rtp != null) {
- rtp.close();
- }
-
- // Wait for threads to terminate
- for (Thread t : threads) {
- try {
- t.join();
- } catch (InterruptedException e) { }
- }
-
- if (track != null) {
- track.release();
- }
-
- threads.clear();
- }
-
- public void startAudioStream() throws SocketException
- {
- setupRtpSession();
-
- setupAudio();
-
- startReceiveThread();
-
- startDepacketizerThread();
-
- startDecoderThread();
-
- startUdpPingThread();
- }
-
- private void setupRtpSession() throws SocketException
- {
- rtp = new DatagramSocket(RTP_PORT);
- }
-
- private void setupAudio()
- {
- int channelConfig;
- int err;
-
- err = OpusDecoder.init();
- if (err != 0) {
- throw new IllegalStateException("Opus decoder failed to initialize");
- }
-
- switch (OpusDecoder.getChannelCount())
- {
- case 1:
- channelConfig = AudioFormat.CHANNEL_OUT_MONO;
- break;
- case 2:
- channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
- break;
- default:
- throw new IllegalStateException("Opus decoder returned unhandled channel count");
- }
-
- track = new AudioTrack(AudioManager.STREAM_MUSIC,
- OpusDecoder.getSampleRate(),
- channelConfig,
- AudioFormat.ENCODING_PCM_16BIT,
- 1024, // 1KB buffer
- AudioTrack.MODE_STREAM);
-
- track.play();
- }
-
- private void startDepacketizerThread()
- {
- // This thread lessens the work on the receive thread
- // so it can spend more time waiting for data
- Thread t = new Thread() {
- @Override
- public void run() {
- while (!isInterrupted())
- {
- AvRtpPacket packet;
-
- try {
- packet = packets.take();
- } catch (InterruptedException e) {
- listener.connectionTerminated(e);
- return;
- }
-
- depacketizer.decodeInputData(packet);
- }
- }
- };
- threads.add(t);
- t.setName("Audio - Depacketizer");
- t.start();
- }
-
- private void startDecoderThread()
- {
- // Decoder thread
- Thread t = new Thread() {
- @Override
- public void run() {
- while (!isInterrupted())
- {
- AvShortBufferDescriptor samples;
-
- try {
- samples = depacketizer.getNextDecodedData();
- } catch (InterruptedException e) {
- listener.connectionTerminated(e);
- return;
- }
-
- track.write(samples.data, samples.offset, samples.length);
- }
- }
- };
- threads.add(t);
- t.setName("Audio - Player");
- t.start();
- }
-
- private void startReceiveThread()
- {
- // Receive thread
- Thread t = new Thread() {
- @Override
- public void run() {
- AvByteBufferDescriptor desc = new AvByteBufferDescriptor(new byte[1500], 0, 1500);
- DatagramPacket packet = new DatagramPacket(desc.data, desc.length);
-
- while (!isInterrupted())
- {
- try {
- rtp.receive(packet);
- } catch (IOException e) {
- listener.connectionTerminated(e);
- return;
- }
-
- // Give the packet to the depacketizer thread
- desc.length = packet.getLength();
- if (packets.offer(new AvRtpPacket(desc))) {
- desc.reinitialize(new byte[1500], 0, 1500);
- packet.setData(desc.data, desc.offset, desc.length);
- }
- }
- }
- };
- threads.add(t);
- t.setName("Audio - Receive");
- t.start();
- }
-
- private void startUdpPingThread()
- {
- // Ping thread
- Thread t = new Thread() {
- @Override
- public void run() {
- // PING in ASCII
- final byte[] pingPacketData = new byte[] {0x50, 0x49, 0x4E, 0x47};
- DatagramPacket pingPacket = new DatagramPacket(pingPacketData, pingPacketData.length);
- pingPacket.setSocketAddress(new InetSocketAddress(host, RTP_PORT));
-
- // Send PING every 100 ms
- while (!isInterrupted())
- {
- try {
- rtp.send(pingPacket);
- } catch (IOException e) {
- listener.connectionTerminated(e);
- return;
- }
-
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- listener.connectionTerminated(e);
- return;
- }
- }
- }
- };
- threads.add(t);
- t.setPriority(Thread.MIN_PRIORITY);
- t.setName("Audio - Ping");
- t.start();
- }
-}
diff --git a/src/com/limelight/nvstream/NvComputer.java b/src/com/limelight/nvstream/NvComputer.java
deleted file mode 100644
index 3fb6d57f..00000000
--- a/src/com/limelight/nvstream/NvComputer.java
+++ /dev/null
@@ -1,164 +0,0 @@
-package com.limelight.nvstream;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.SocketException;
-import java.util.Locale;
-import java.util.UUID;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import android.util.Log;
-
-public class NvComputer {
- private String hostname;
- private InetAddress ipAddress;
- private String ipAddressString;
- private int state;
- private int numOfApps;
- private String gpuType;
- private String mac;
- private UUID uniqueID;
-
- private NvHTTP nvHTTP;
-
-
- private int sessionID;
- private boolean pairState;
- private boolean isBusy;
-
- public NvComputer(String hostname, InetAddress ipAddress, int state, int numOfApps, String gpuType, String mac, UUID uniqueID) {
- this.hostname = hostname;
- this.ipAddress = ipAddress;
- this.ipAddressString = this.ipAddress.getHostAddress();
- this.state = state;
- this.numOfApps = numOfApps;
- this.gpuType = gpuType;
- this.mac = mac;
- this.uniqueID = uniqueID;
-
- try {
- this.nvHTTP = new NvHTTP(this.ipAddress, NvConnection.getMacAddressString());
- } catch (SocketException e) {
- Log.e("NvComputer Constructor", "Unable to get MAC Address " + e.getMessage());
- this.nvHTTP = new NvHTTP(this.ipAddress, "00:00:00:00:00:00");
- }
-
- this.updatePairState();
- }
-
- public String getHostname() {
- return this.hostname;
- }
-
- public InetAddress getIpAddress() {
- return this.ipAddress;
- }
-
- public String getIpAddressString() {
- return this.ipAddressString;
- }
-
- public int getState() {
- return this.state;
- }
-
- public int getNumOfApps() {
- return this.numOfApps;
- }
-
- public String getGpuType() {
- return this.gpuType;
- }
-
- public String getMac() {
- return this.mac;
- }
-
- public UUID getUniqueID() {
- return this.uniqueID;
- }
-
- public void updateAfterPairQuery(int sessionID, boolean paired, boolean isBusy) {
- this.sessionID = sessionID;
- this.pairState = paired;
- this.isBusy = isBusy;
- }
-
- public int getSessionID() {
- return this.sessionID;
- }
-
- public void updatePairState() {
- try {
- this.pairState = this.nvHTTP.getPairState();
- } catch (IOException e) {
- Log.e("NvComputer UpdatePaired", "Unable to get Pair State " + e.getMessage());
- this.pairState = false;
- } catch (XmlPullParserException e) {
- Log.e("NvComputer UpdatePaired", "Unable to get Pair State " + e.getMessage());
- this.pairState = false;
- }
-
- /*if (this.pairState == true) {
- try {
- this.sessionID = this.nvHTTP.getSessionId();
- } catch (IOException e) {
- Log.e("NvComputer UpdatePaired", "Unable to get Session ID " + e.getMessage());
- this.sessionID = 0;
- } catch (XmlPullParserException e) {
- Log.e("NvComputer UpdatePaired", "Unable to get Session ID " + e.getMessage());
- this.sessionID = 0;
- }
-
- }*/
- }
-
- public boolean getPairState() {
- return this.pairState;
- }
-
- public boolean getIsBusy() {
- return this.isBusy;
- }
-
- public int hashCode() {
- if (this.ipAddress == null) {
- return -1;
- } else {
- return this.ipAddressString.hashCode();
- }
- }
-
- public String toString() {
- StringBuilder returnStringBuilder = new StringBuilder();
- returnStringBuilder.append("NvComputer 0x");
- returnStringBuilder.append(Integer.toHexString(this.hashCode()).toUpperCase(Locale.getDefault()));
- returnStringBuilder.append("\n|- Hostname: ");
- returnStringBuilder.append(this.hostname);
- returnStringBuilder.append("\n|- IP Address: ");
- returnStringBuilder.append(this.ipAddressString);
- returnStringBuilder.append("\n|- Computer State: ");
- returnStringBuilder.append(this.state);
- returnStringBuilder.append("\n|- Number of Apps: ");
- returnStringBuilder.append(this.numOfApps);
- returnStringBuilder.append("\n|- GPU: ");
- returnStringBuilder.append(this.gpuType);
- returnStringBuilder.append("\n|- MAC: ");
- returnStringBuilder.append(this.mac);
- returnStringBuilder.append("\n|- UniqueID: ");
- returnStringBuilder.append(this.uniqueID);
- returnStringBuilder.append("\n\\- Pair State: ");
- returnStringBuilder.append(this.pairState);
- returnStringBuilder.append("\n");
- return returnStringBuilder.toString();
- }
-
- public boolean equals(Object obj) {
- if (obj instanceof UUID) {
- return this.uniqueID.equals(obj);
- } else {
- return false;
- }
- }
-}
\ No newline at end of file
diff --git a/src/com/limelight/nvstream/NvConnection.java b/src/com/limelight/nvstream/NvConnection.java
deleted file mode 100644
index 5f044722..00000000
--- a/src/com/limelight/nvstream/NvConnection.java
+++ /dev/null
@@ -1,338 +0,0 @@
-package com.limelight.nvstream;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.Enumeration;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.view.SurfaceHolder;
-import android.widget.Toast;
-
-import com.limelight.Game;
-import com.limelight.nvstream.input.NvController;
-
-public class NvConnection {
- private String host;
- private Game activity;
- private NvConnectionListener listener;
- private int drFlags;
-
- private InetAddress hostAddr;
- private NvControl controlStream;
- private NvController inputStream;
- private SurfaceHolder video;
- private NvVideoStream videoStream;
- private NvAudioStream audioStream;
-
- private ThreadPoolExecutor threadPool;
-
- public NvConnection(String host, Game activity, SurfaceHolder video, int drFlags)
- {
- this.host = host;
- this.listener = activity;
- this.activity = activity;
- this.video = video;
- this.drFlags = drFlags;
- this.threadPool = new ThreadPoolExecutor(1, 1, Long.MAX_VALUE, TimeUnit.DAYS, new LinkedBlockingQueue());
- }
-
- public static String getMacAddressString() throws SocketException {
- Enumeration ifaceList;
- NetworkInterface selectedIface = null;
-
- // First look for a WLAN interface (since those generally aren't removable)
- ifaceList = NetworkInterface.getNetworkInterfaces();
- while (selectedIface == null && ifaceList.hasMoreElements()) {
- NetworkInterface iface = ifaceList.nextElement();
-
- if (iface.getName().startsWith("wlan") &&
- iface.getHardwareAddress() != null) {
- selectedIface = iface;
- }
- }
-
- // If we didn't find that, look for an Ethernet interface
- ifaceList = NetworkInterface.getNetworkInterfaces();
- while (selectedIface == null && ifaceList.hasMoreElements()) {
- NetworkInterface iface = ifaceList.nextElement();
-
- if (iface.getName().startsWith("eth") &&
- iface.getHardwareAddress() != null) {
- selectedIface = iface;
- }
- }
-
- // Now just find something with a MAC address
- ifaceList = NetworkInterface.getNetworkInterfaces();
- while (selectedIface == null && ifaceList.hasMoreElements()) {
- NetworkInterface iface = ifaceList.nextElement();
-
- if (iface.getHardwareAddress() != null) {
- selectedIface = ifaceList.nextElement();
- break;
- }
- }
-
- if (selectedIface == null) {
- return null;
- }
-
- byte[] macAddress = selectedIface.getHardwareAddress();
- if (macAddress != null) {
- StringBuilder addrStr = new StringBuilder();
- for (int i = 0; i < macAddress.length; i++) {
- addrStr.append(String.format("%02x", macAddress[i]));
- if (i != macAddress.length - 1) {
- addrStr.append(':');
- }
- }
- return addrStr.toString();
- }
-
- return null;
- }
-
- public void stop()
- {
- threadPool.shutdownNow();
-
- if (videoStream != null) {
- videoStream.abort();
- }
- if (audioStream != null) {
- audioStream.abort();
- }
-
- if (controlStream != null) {
- controlStream.abort();
- }
-
- if (inputStream != null) {
- inputStream.close();
- inputStream = null;
- }
- }
-
- private boolean startSteamBigPicture() throws XmlPullParserException, IOException
- {
- NvHTTP h = new NvHTTP(hostAddr, getMacAddressString());
-
- if (!h.getPairState()) {
- displayToast("Device not paired with computer");
- return false;
- }
-
- int sessionId = h.getSessionId();
- int appId = h.getSteamAppId(sessionId);
-
- h.launchApp(sessionId, appId);
-
- return true;
- }
-
- private boolean startControlStream() throws IOException
- {
- controlStream = new NvControl(hostAddr, listener);
- controlStream.initialize();
- controlStream.start();
- return true;
- }
-
- private boolean startVideoStream() throws IOException
- {
- videoStream = new NvVideoStream(hostAddr, listener, controlStream);
- videoStream.startVideoStream(activity, video, drFlags);
- return true;
- }
-
- private boolean startAudioStream() throws IOException
- {
- audioStream = new NvAudioStream(hostAddr, listener);
- audioStream.startAudioStream();
- return true;
- }
-
- private boolean startInputConnection() throws IOException
- {
- inputStream = new NvController(hostAddr);
- inputStream.initialize();
- return true;
- }
-
- private void establishConnection() {
- for (NvConnectionListener.Stage currentStage : NvConnectionListener.Stage.values())
- {
- boolean success = false;
-
- listener.stageStarting(currentStage);
- try {
- switch (currentStage)
- {
- case LAUNCH_APP:
- success = startSteamBigPicture();
- break;
-
- case HANDSHAKE:
- success = NvHandshake.performHandshake(hostAddr);
- break;
-
- case CONTROL_START:
- success = startControlStream();
- break;
-
- case VIDEO_START:
- success = startVideoStream();
- break;
-
- case AUDIO_START:
- success = startAudioStream();
- break;
-
- case CONTROL_START2:
- controlStream.startJitterPackets();
- success = true;
- break;
-
- case INPUT_START:
- success = startInputConnection();
- break;
- }
- } catch (Exception e) {
- e.printStackTrace();
- success = false;
- }
-
- if (success) {
- listener.stageComplete(currentStage);
- }
- else {
- listener.stageFailed(currentStage);
- return;
- }
- }
-
- listener.connectionStarted();
- }
-
- public void start()
- {
- new Thread(new Runnable() {
- @Override
- public void run() {
- checkDataConnection();
-
- try {
- hostAddr = InetAddress.getByName(host);
- } catch (UnknownHostException e) {
- displayToast(e.getMessage());
- listener.connectionTerminated(e);
- return;
- }
-
- establishConnection();
-
- activity.hideSystemUi();
- }
- }).start();
- }
-
- private void checkDataConnection()
- {
- ConnectivityManager mgr = (ConnectivityManager) activity.getSystemService(Context.CONNECTIVITY_SERVICE);
- if (mgr.isActiveNetworkMetered()) {
- displayToast("Warning: Your active network connection is metered!");
- }
- }
-
- 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) {
- listener.connectionTerminated(e);
- }
- }
- });
- }
-
- public void sendMouseButtonDown()
- {
- if (inputStream == null)
- return;
-
- threadPool.execute(new Runnable() {
- @Override
- public void run() {
- try {
- inputStream.sendMouseButtonDown();
- } catch (IOException e) {
- listener.connectionTerminated(e);
- }
- }
- });
- }
-
- public void sendMouseButtonUp()
- {
- if (inputStream == null)
- return;
-
- threadPool.execute(new Runnable() {
- @Override
- public void run() {
- try {
- inputStream.sendMouseButtonUp();
- } catch (IOException e) {
- listener.connectionTerminated(e);
- }
- }
- });
- }
-
- public void sendControllerInput(final short buttonFlags,
- final byte leftTrigger, final byte rightTrigger,
- final short leftStickX, final short leftStickY,
- final short rightStickX, final short rightStickY)
- {
- if (inputStream == null)
- return;
-
- threadPool.execute(new Runnable() {
- @Override
- public void run() {
- try {
- inputStream.sendControllerInput(buttonFlags, leftTrigger,
- rightTrigger, leftStickX, leftStickY,
- rightStickX, rightStickY);
- } catch (IOException e) {
- listener.connectionTerminated(e);
- }
- }
- });
- }
-
- private void displayToast(final String message)
- {
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(activity, message, Toast.LENGTH_LONG).show();
- }
- });
- }
-}
diff --git a/src/com/limelight/nvstream/NvConnectionListener.java b/src/com/limelight/nvstream/NvConnectionListener.java
deleted file mode 100644
index c929423b..00000000
--- a/src/com/limelight/nvstream/NvConnectionListener.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.limelight.nvstream;
-
-public interface NvConnectionListener {
-
- public enum Stage {
- LAUNCH_APP("app"),
- HANDSHAKE("handshake"),
- CONTROL_START("control connection"),
- VIDEO_START("video stream"),
- AUDIO_START("audio stream"),
- CONTROL_START2("control connection"),
- INPUT_START("input connection");
-
- private String name;
- private Stage(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
- };
-
- public void stageStarting(Stage stage);
- public void stageComplete(Stage stage);
- public void stageFailed(Stage stage);
-
- public void connectionStarted();
- public void connectionTerminated(Exception e);
-}
diff --git a/src/com/limelight/nvstream/NvControl.java b/src/com/limelight/nvstream/NvControl.java
deleted file mode 100644
index ba76045a..00000000
--- a/src/com/limelight/nvstream/NvControl.java
+++ /dev/null
@@ -1,505 +0,0 @@
-package com.limelight.nvstream;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-import com.limelight.nvstream.av.ConnectionStatusListener;
-
-public class NvControl implements ConnectionStatusListener {
-
- public static final int PORT = 47995;
-
- public static final int CONTROL_TIMEOUT = 5000;
-
- public static final short PTYPE_HELLO = 0x1204;
- public static final short PPAYLEN_HELLO = 0x0004;
- public static final byte[] PPAYLOAD_HELLO =
- {
- (byte)0x00,
- (byte)0x05,
- (byte)0x00,
- (byte)0x00
- };
-
- public static final short PTYPE_KEEPALIVE = 0x13ff;
- public static final short PPAYLEN_KEEPALIVE = 0x0000;
-
- public static final short PTYPE_HEARTBEAT = 0x1401;
- public static final short PPAYLEN_HEARTBEAT = 0x0000;
-
- public static final short PTYPE_1405 = 0x1405;
- public static final short PPAYLEN_1405 = 0x0000;
-
- public static final short PTYPE_RESYNC = 0x1404;
- public static final short PPAYLEN_RESYNC = 16;
-
- public static final short PTYPE_CONFIG = 0x1205;
- public static final short PPAYLEN_CONFIG = 0x0004;
- public static final int[] PPAYLOAD_CONFIG =
- {
- 720,
- 266758,
- 1,
- 266762,
- 30,
- 70151,
- 68291329,
- 1280,
- 68291584,
- 1280,
- 68291840,
- 15360,
- 68292096,
- 25600,
- 68292352,
- 2048,
- 68292608,
- 1024,
- 68289024,
- 262144,
- 17957632,
- 302055424,
- 134217729,
- 16777490,
- 70153,
- 68293120,
- 768000,
- 17961216,
- 303235072,
- 335609857,
- 838861842,
- 352321536,
- 1006634002,
- 369098752,
- 335545362,
- 385875968,
- 1042,
- 402653184,
- 134218770,
- 419430400,
- 167773202,
- 436207616,
- 855638290,
- 266779,
- 7000,
- 266780,
- 2000,
- 266781,
- 50,
- 266782,
- 3000,
- 266783,
- 2,
- 266794,
- 5000,
- 266795,
- 500,
- 266784,
- 75,
- 266785,
- 25,
- 266786,
- 10,
- 266787,
- 60,
- 266788,
- 30,
- 266789,
- 3,
- 266790,
- 1000,
- 266791,
- 5000,
- 266792,
- 5000,
- 266793,
- 5000,
- 70190,
- 68301063,
- 10240,
- 68301312,
- 6400,
- 68301568,
- 768000,
- 68299776,
- 768,
- 68300032,
- 2560,
- 68300544,
- 0,
- 34746368,
- (int)0xFE000000
- };
-
-
- public static final short PTYPE_JITTER = 0x140c;
- public static final short PPAYLEN_JITTER = 0x10;
-
- private int seqNum;
-
- private NvConnectionListener listener;
- private InetAddress host;
-
- private Socket s;
- private InputStream in;
- private OutputStream out;
-
- private Thread heartbeatThread;
- private Thread jitterThread;
- private Thread resyncThread;
- private Object resyncNeeded = new Object();
- private boolean aborting = false;
-
- public NvControl(InetAddress host, NvConnectionListener listener)
- {
- this.listener = listener;
- this.host = host;
- }
-
- public void initialize() throws IOException
- {
- s = new Socket();
- s.setSoTimeout(CONTROL_TIMEOUT);
- s.setTcpNoDelay(true);
- s.connect(new InetSocketAddress(host, PORT), CONTROL_TIMEOUT);
- in = s.getInputStream();
- out = s.getOutputStream();
- }
-
- private void sendPacket(NvCtlPacket packet) throws IOException
- {
- out.write(packet.toWire());
- out.flush();
- }
-
- private NvControl.NvCtlResponse sendAndGetReply(NvCtlPacket packet) throws IOException
- {
- sendPacket(packet);
- return new NvCtlResponse(in);
- }
-
- private void sendJitter() throws IOException
- {
- ByteBuffer bb = ByteBuffer.allocate(16).order(ByteOrder.LITTLE_ENDIAN);
-
- bb.putInt(0);
- bb.putInt(77);
- bb.putInt(888);
- bb.putInt(seqNum += 2);
-
- sendPacket(new NvCtlPacket(PTYPE_JITTER, PPAYLEN_JITTER, bb.array()));
- }
-
- public void abort()
- {
- if (aborting) {
- return;
- }
-
- aborting = true;
-
- if (jitterThread != null) {
- jitterThread.interrupt();
- }
-
- if (heartbeatThread != null) {
- heartbeatThread.interrupt();
- }
-
- try {
- s.close();
- } catch (IOException e) {}
- }
-
- public void requestResync() throws IOException
- {
- System.out.println("CTL: Requesting IDR frame");
- sendResync();
- }
-
- public void start() throws IOException
- {
- sendHello();
- sendConfig();
- pingPong();
- send1405AndGetResponse();
-
- heartbeatThread = new Thread() {
- @Override
- public void run() {
- while (!isInterrupted())
- {
- try {
- sendHeartbeat();
- } catch (IOException e) {
- listener.connectionTerminated(e);
- return;
- }
-
-
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- listener.connectionTerminated(e);
- return;
- }
- }
- }
- };
- heartbeatThread.start();
-
- resyncThread = new Thread() {
- @Override
- public void run() {
- while (!isInterrupted())
- {
- try {
- // Wait for notification of a resync needed
- synchronized (resyncNeeded) {
- resyncNeeded.wait();
- }
- } catch (InterruptedException e) {
- listener.connectionTerminated(e);
- return;
- }
-
- try {
- requestResync();
- } catch (IOException e) {
- listener.connectionTerminated(e);
- return;
- }
- }
- }
- };
- resyncThread.start();
- }
-
- public void startJitterPackets()
- {
- jitterThread = new Thread() {
- @Override
- public void run() {
- while (!isInterrupted())
- {
- try {
- sendJitter();
- } catch (IOException e) {
- listener.connectionTerminated(e);
- return;
- }
-
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- listener.connectionTerminated(e);
- return;
- }
- }
- }
- };
- jitterThread.start();
- }
-
- private NvControl.NvCtlResponse send1405AndGetResponse() throws IOException
- {
- return sendAndGetReply(new NvCtlPacket(PTYPE_1405, PPAYLEN_1405));
- }
-
- private void sendHello() throws IOException
- {
- sendPacket(new NvCtlPacket(PTYPE_HELLO, PPAYLEN_HELLO, PPAYLOAD_HELLO));
- }
-
- private void sendResync() throws IOException
- {
- ByteBuffer conf = ByteBuffer.wrap(new byte[PPAYLEN_RESYNC]).order(ByteOrder.LITTLE_ENDIAN);
-
- conf.putLong(0);
- conf.putLong(0xFFFF);
-
- sendAndGetReply(new NvCtlPacket(PTYPE_RESYNC, PPAYLEN_RESYNC, conf.array()));
- }
-
- private void sendConfig() throws IOException
- {
- ByteBuffer conf = ByteBuffer.wrap(new byte[PPAYLOAD_CONFIG.length * 4 + 3]).order(ByteOrder.LITTLE_ENDIAN);
-
- for (int i : PPAYLOAD_CONFIG)
- conf.putInt(i);
-
- conf.putShort((short)0x0013);
- conf.put((byte) 0x00);
-
- sendPacket(new NvCtlPacket(PTYPE_CONFIG, PPAYLEN_CONFIG, conf.array()));
- }
-
- private void sendHeartbeat() throws IOException
- {
- sendPacket(new NvCtlPacket(PTYPE_HEARTBEAT, PPAYLEN_HEARTBEAT));
- }
-
- private NvControl.NvCtlResponse pingPong() throws IOException
- {
- sendPacket(new NvCtlPacket(PTYPE_KEEPALIVE, PPAYLEN_KEEPALIVE));
- return new NvControl.NvCtlResponse(in);
- }
-
- class NvCtlPacket {
- public short type;
- public short paylen;
- public byte[] payload;
-
- public NvCtlPacket(InputStream in) throws IOException
- {
- byte[] header = new byte[4];
-
- int offset = 0;
- do
- {
- int bytesRead = in.read(header, offset, header.length - offset);
- if (bytesRead < 0) {
- break;
- }
- offset += bytesRead;
- } while (offset != header.length);
-
- if (offset != header.length) {
- throw new IOException("Socket closed prematurely");
- }
-
- ByteBuffer bb = ByteBuffer.wrap(header).order(ByteOrder.LITTLE_ENDIAN);
-
- type = bb.getShort();
- paylen = bb.getShort();
-
- if (paylen != 0)
- {
- payload = new byte[paylen];
-
- offset = 0;
- do
- {
- int bytesRead = in.read(payload, offset, payload.length - offset);
- if (bytesRead < 0) {
- break;
- }
- offset += bytesRead;
- } while (offset != payload.length);
-
- if (offset != payload.length) {
- throw new IOException("Socket closed prematurely");
- }
- }
- }
-
- public NvCtlPacket(byte[] payload)
- {
- ByteBuffer bb = ByteBuffer.wrap(payload).order(ByteOrder.LITTLE_ENDIAN);
-
- type = bb.getShort();
- paylen = bb.getShort();
-
- if (bb.hasRemaining())
- {
- payload = new byte[bb.remaining()];
- bb.get(payload);
- }
- }
-
- public NvCtlPacket(short type, short paylen)
- {
- this.type = type;
- this.paylen = paylen;
- }
-
- public NvCtlPacket(short type, short paylen, byte[] payload)
- {
- this.type = type;
- this.paylen = paylen;
- this.payload = payload;
- }
-
- public short getType()
- {
- return type;
- }
-
- public short getPaylen()
- {
- return paylen;
- }
-
- public void setType(short type)
- {
- this.type = type;
- }
-
- public void setPaylen(short paylen)
- {
- this.paylen = paylen;
- }
-
- public byte[] toWire()
- {
- ByteBuffer bb = ByteBuffer.allocate(4 + (payload != null ? payload.length : 0)).order(ByteOrder.LITTLE_ENDIAN);
-
- bb.putShort(type);
- bb.putShort(paylen);
-
- if (payload != null)
- bb.put(payload);
-
- return bb.array();
- }
- }
-
- class NvCtlResponse extends NvCtlPacket {
- public short status;
-
- public NvCtlResponse(InputStream in) throws IOException {
- super(in);
- }
-
- public NvCtlResponse(short type, short paylen) {
- super(type, paylen);
- }
-
- public NvCtlResponse(short type, short paylen, byte[] payload) {
- super(type, paylen, payload);
- }
-
- public NvCtlResponse(byte[] payload) {
- super(payload);
- }
-
- public void setStatusCode(short status)
- {
- this.status = status;
- }
-
- public short getStatusCode()
- {
- return status;
- }
- }
-
- @Override
- public void connectionTerminated() {
- abort();
- }
-
- @Override
- public void connectionNeedsResync() {
- synchronized (resyncNeeded) {
- // Wake up the resync thread
- resyncNeeded.notify();
- }
- }
-}
diff --git a/src/com/limelight/nvstream/NvHTTP.java b/src/com/limelight/nvstream/NvHTTP.java
deleted file mode 100644
index 65757e32..00000000
--- a/src/com/limelight/nvstream/NvHTTP.java
+++ /dev/null
@@ -1,147 +0,0 @@
-package com.limelight.nvstream;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.InetAddress;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.LinkedList;
-import java.util.Stack;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
-public class NvHTTP {
- private String macAddress;
-
- public static final int PORT = 47989;
-
- public static final int CONNECTION_TIMEOUT = 5000;
-
-
- public String baseUrl;
-
- public NvHTTP(InetAddress host, String macAddress) {
- this.macAddress = macAddress;
- this.baseUrl = "http://" + host.getHostAddress() + ":" + PORT;
- }
-
- private String getXmlString(InputStream in, String tagname)
- throws XmlPullParserException, IOException {
- XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
- factory.setNamespaceAware(true);
- XmlPullParser xpp = factory.newPullParser();
-
- xpp.setInput(new InputStreamReader(in));
- int eventType = xpp.getEventType();
- Stack currentTag = new Stack();
-
- while (eventType != XmlPullParser.END_DOCUMENT) {
- switch (eventType) {
- case (XmlPullParser.START_TAG):
- currentTag.push(xpp.getName());
- break;
- case (XmlPullParser.END_TAG):
- currentTag.pop();
- break;
- case (XmlPullParser.TEXT):
- if (currentTag.peek().equals(tagname)) {
- return xpp.getText();
- }
- break;
- }
- eventType = xpp.next();
- }
-
- return null;
- }
-
- private InputStream openHttpConnection(String url) throws IOException {
- URLConnection conn = new URL(url).openConnection();
- conn.setConnectTimeout(CONNECTION_TIMEOUT);
- conn.setDefaultUseCaches(false);
- conn.connect();
- return conn.getInputStream();
- }
-
- public String getAppVersion() throws XmlPullParserException, IOException {
- InputStream in = openHttpConnection(baseUrl + "/appversion");
- return getXmlString(in, "appversion");
- }
-
- public boolean getPairState() throws IOException, XmlPullParserException {
- InputStream in = openHttpConnection(baseUrl + "/pairstate?mac=" + macAddress);
- String paired = getXmlString(in, "paired");
- return Integer.valueOf(paired) != 0;
- }
-
- public int getSessionId() throws IOException, XmlPullParserException {
- /* Pass the model (minus spaces) as the device name */
- String deviceName = android.os.Build.MODEL;
- deviceName = deviceName.replace(" ", "");
- InputStream in = openHttpConnection(baseUrl + "/pair?mac=" + macAddress
- + "&devicename=" + deviceName);
- String sessionId = getXmlString(in, "sessionid");
- return Integer.parseInt(sessionId);
- }
-
- public int getSteamAppId(int sessionId) throws IOException,
- XmlPullParserException {
- LinkedList appList = getAppList(sessionId);
- for (NvApp app : appList) {
- if (app.getAppName().equals("Steam")) {
- return app.getAppId();
- }
- }
- return 0;
- }
-
- public LinkedList getAppList(int sessionId) throws IOException, XmlPullParserException {
- InputStream in = openHttpConnection(baseUrl + "/applist?session=" + sessionId);
- XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
- factory.setNamespaceAware(true);
- XmlPullParser xpp = factory.newPullParser();
-
- xpp.setInput(new InputStreamReader(in));
- int eventType = xpp.getEventType();
- LinkedList appList = new LinkedList();
- Stack currentTag = new Stack();
-
- while (eventType != XmlPullParser.END_DOCUMENT) {
- switch (eventType) {
- case (XmlPullParser.START_TAG):
- currentTag.push(xpp.getName());
- if (xpp.getName().equals("App")) {
- appList.addLast(new NvApp());
- }
- break;
- case (XmlPullParser.END_TAG):
- currentTag.pop();
- break;
- case (XmlPullParser.TEXT):
- NvApp app = appList.getLast();
- if (currentTag.peek().equals("AppTitle")) {
- app.setAppName(xpp.getText());
- } else if (currentTag.peek().equals("ID")) {
- app.setAppId(xpp.getText());
- } else if (currentTag.peek().equals("IsRunning")) {
- app.setIsRunning(xpp.getText());
- }
- break;
- }
- eventType = xpp.next();
- }
- return appList;
- }
-
- // Returns gameSession XML attribute
- public int launchApp(int sessionId, int appId) throws IOException,
- XmlPullParserException {
- InputStream in = openHttpConnection(baseUrl + "/launch?session="
- + sessionId + "&appid=" + appId);
- String gameSession = getXmlString(in, "gamesession");
- return Integer.parseInt(gameSession);
- }
-}
diff --git a/src/com/limelight/nvstream/NvHandshake.java b/src/com/limelight/nvstream/NvHandshake.java
deleted file mode 100644
index db111d16..00000000
--- a/src/com/limelight/nvstream/NvHandshake.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package com.limelight.nvstream;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-
-public class NvHandshake {
- public static final int PORT = 47991;
-
- public static final int HANDSHAKE_TIMEOUT = 5000;
-
- public static final byte[] PLATFORM_HELLO =
- {
- (byte)0x07,
- (byte)0x00,
- (byte)0x00,
- (byte)0x00,
-
- // android in ASCII
- (byte)0x61,
- (byte)0x6e,
- (byte)0x64,
- (byte)0x72,
- (byte)0x6f,
- (byte)0x69,
- (byte)0x64,
-
- (byte)0x03,
- (byte)0x01,
- (byte)0x00,
- (byte)0x00
- };
-
- public static final byte[] PACKET_2 =
- {
- (byte)0x01,
- (byte)0x03,
- (byte)0x02,
- (byte)0x00,
- (byte)0x08,
- (byte)0x00
- };
-
- public static final byte[] PACKET_3 =
- {
- (byte)0x04,
- (byte)0x01,
- (byte)0x00,
- (byte)0x00,
-
- (byte)0x00,
- (byte)0x00,
- (byte)0x00,
- (byte)0x00
- };
-
- public static final byte[] PACKET_4 =
- {
- (byte)0x01,
- (byte)0x01,
- (byte)0x00,
- (byte)0x00
- };
-
- private static boolean waitAndDiscardResponse(InputStream in)
- {
- // Wait for response and discard response
- try {
- in.read();
-
- // Wait for the full response to come in
- Thread.sleep(250);
-
- for (int i = 0; i < in.available(); i++)
- in.read();
-
- } catch (IOException e1) {
- return false;
- } catch (InterruptedException e) {
- return false;
- }
-
- return true;
- }
-
- public static boolean performHandshake(InetAddress host) throws IOException
- {
- Socket s = new Socket();
- s.connect(new InetSocketAddress(host, PORT), HANDSHAKE_TIMEOUT);
- s.setSoTimeout(HANDSHAKE_TIMEOUT);
- OutputStream out = s.getOutputStream();
- InputStream in = s.getInputStream();
-
- // First packet
- out.write(PLATFORM_HELLO);
- out.flush();
-
- if (!waitAndDiscardResponse(in)) {
- s.close();
- return false;
- }
-
- // Second packet
- out.write(PACKET_2);
- out.flush();
-
- if (!waitAndDiscardResponse(in)) {
- s.close();
- return false;
- }
-
- // Third packet
- out.write(PACKET_3);
- out.flush();
-
- if (!waitAndDiscardResponse(in)) {
- s.close();
- return false;
- }
-
- // Fourth packet
- out.write(PACKET_4);
- out.flush();
-
- // Done
- s.close();
-
- return true;
- }
-}
diff --git a/src/com/limelight/nvstream/NvVideoStream.java b/src/com/limelight/nvstream/NvVideoStream.java
deleted file mode 100644
index 801bca52..00000000
--- a/src/com/limelight/nvstream/NvVideoStream.java
+++ /dev/null
@@ -1,310 +0,0 @@
-package com.limelight.nvstream;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.SocketException;
-import java.util.LinkedList;
-import java.util.concurrent.LinkedBlockingQueue;
-
-import com.limelight.nvstream.av.AvByteBufferDescriptor;
-import com.limelight.nvstream.av.AvDecodeUnit;
-import com.limelight.nvstream.av.AvRtpPacket;
-import com.limelight.nvstream.av.ConnectionStatusListener;
-import com.limelight.nvstream.av.video.AvVideoDepacketizer;
-import com.limelight.nvstream.av.video.AvVideoPacket;
-import com.limelight.nvstream.av.video.DecoderRenderer;
-import com.limelight.nvstream.av.video.MediaCodecDecoderRenderer;
-import com.limelight.nvstream.av.video.cpu.CpuDecoderRenderer;
-
-import android.content.Context;
-import android.os.Build;
-import android.view.SurfaceHolder;
-
-public class NvVideoStream {
- public static final int RTP_PORT = 47998;
- public static final int RTCP_PORT = 47999;
- public static final int FIRST_FRAME_PORT = 47996;
-
- public static final int FIRST_FRAME_TIMEOUT = 5000;
-
- private LinkedBlockingQueue packets = new LinkedBlockingQueue(100);
-
- private InetAddress host;
- private DatagramSocket rtp;
- private Socket firstFrameSocket;
-
- private LinkedList threads = new LinkedList();
-
- private NvConnectionListener listener;
- private AvVideoDepacketizer depacketizer;
-
- private DecoderRenderer decrend;
- private boolean startedRendering;
-
- private boolean aborting = false;
-
- public NvVideoStream(InetAddress host, NvConnectionListener listener, ConnectionStatusListener avConnListener)
- {
- this.host = host;
- this.listener = listener;
- this.depacketizer = new AvVideoDepacketizer(avConnListener);
- }
-
- public void abort()
- {
- if (aborting) {
- return;
- }
-
- aborting = true;
-
- // Interrupt threads
- for (Thread t : threads) {
- t.interrupt();
- }
-
- // Close the socket to interrupt the receive thread
- if (rtp != null) {
- rtp.close();
- }
- if (firstFrameSocket != null) {
- try {
- firstFrameSocket.close();
- } catch (IOException e) {}
- }
-
- // Wait for threads to terminate
- for (Thread t : threads) {
- try {
- t.join();
- } catch (InterruptedException e) { }
- }
-
- if (startedRendering) {
- decrend.stop();
- }
-
- if (decrend != null) {
- decrend.release();
- }
-
- threads.clear();
- }
-
- private void readFirstFrame() throws IOException
- {
- byte[] firstFrame = new byte[1500];
-
- firstFrameSocket = new Socket();
- firstFrameSocket.setSoTimeout(FIRST_FRAME_TIMEOUT);
-
- try {
- firstFrameSocket.connect(new InetSocketAddress(host, FIRST_FRAME_PORT), FIRST_FRAME_TIMEOUT);
- InputStream firstFrameStream = firstFrameSocket.getInputStream();
-
- int offset = 0;
- for (;;)
- {
- int bytesRead = firstFrameStream.read(firstFrame, offset, firstFrame.length-offset);
-
- if (bytesRead == -1)
- break;
-
- offset += bytesRead;
- }
-
- depacketizer.addInputData(new AvVideoPacket(new AvByteBufferDescriptor(firstFrame, 0, offset)));
- } finally {
- firstFrameSocket.close();
- firstFrameSocket = null;
- }
- }
-
- public void setupRtpSession() throws SocketException
- {
- rtp = new DatagramSocket(RTP_PORT);
- }
-
- public void setupDecoderRenderer(Context context, SurfaceHolder renderTarget, int drFlags) {
- if (Build.HARDWARE.equals("goldfish")) {
- // Emulator - don't render video (it's slow!)
- decrend = null;
- }
- else if (MediaCodecDecoderRenderer.findSafeDecoder() != null) {
- // Hardware decoding
- decrend = new MediaCodecDecoderRenderer();
- }
- else {
- // Software decoding
- decrend = new CpuDecoderRenderer();
- }
-
- if (decrend != null) {
- decrend.setup(context, 1280, 720, renderTarget, drFlags);
- }
- }
-
- public void startVideoStream(Context context, SurfaceHolder surface, int drFlags) throws IOException
- {
- // Setup the decoder and renderer
- setupDecoderRenderer(context, surface, drFlags);
-
- // Open RTP sockets and start session
- setupRtpSession();
-
- // Start pinging before reading the first frame
- // so Shield Proxy knows we're here and sends us
- // the reference frame
- startUdpPingThread();
-
- // Read the first frame to start the UDP video stream
- // This MUST be called before the normal UDP receive thread
- // starts in order to avoid state corruption caused by two
- // threads simultaneously adding input data.
- readFirstFrame();
-
- if (decrend != null) {
- // Start the receive thread early to avoid missing
- // early packets
- startReceiveThread();
-
- // Start the depacketizer thread to deal with the RTP data
- startDepacketizerThread();
-
- // Start decoding the data we're receiving
- startDecoderThread();
-
- // Start the renderer
- decrend.start();
- startedRendering = true;
- }
- }
-
- private void startDecoderThread()
- {
- Thread t = new Thread() {
- @Override
- public void run() {
- // Read the decode units generated from the RTP stream
- while (!isInterrupted())
- {
- AvDecodeUnit du;
-
- try {
- du = depacketizer.getNextDecodeUnit();
- } catch (InterruptedException e) {
- listener.connectionTerminated(e);
- return;
- }
-
- decrend.submitDecodeUnit(du);
- }
- }
- };
- threads.add(t);
- t.setName("Video - Decoder");
- t.setPriority(Thread.MAX_PRIORITY);
- t.start();
- }
-
- private void startDepacketizerThread()
- {
- // This thread lessens the work on the receive thread
- // so it can spend more time waiting for data
- Thread t = new Thread() {
- @Override
- public void run() {
- while (!isInterrupted())
- {
- AvRtpPacket packet;
-
- try {
- packet = packets.take();
- } catch (InterruptedException e) {
- listener.connectionTerminated(e);
- return;
- }
-
- // !!! We no longer own the data buffer at this point !!!
- depacketizer.addInputData(packet);
- }
- }
- };
- threads.add(t);
- t.setName("Video - Depacketizer");
- t.start();
- }
-
- private void startReceiveThread()
- {
- // Receive thread
- Thread t = new Thread() {
- @Override
- public void run() {
- AvByteBufferDescriptor desc = new AvByteBufferDescriptor(new byte[1500], 0, 1500);
- DatagramPacket packet = new DatagramPacket(desc.data, desc.length);
-
- while (!isInterrupted())
- {
- try {
- rtp.receive(packet);
- } catch (IOException e) {
- listener.connectionTerminated(e);
- return;
- }
-
- // Give the packet to the depacketizer thread
- desc.length = packet.getLength();
- if (packets.offer(new AvRtpPacket(desc))) {
- desc.reinitialize(new byte[1500], 0, 1500);
- packet.setData(desc.data, desc.offset, desc.length);
- }
- }
- }
- };
- threads.add(t);
- t.setName("Video - Receive");
- t.start();
- }
-
- private void startUdpPingThread()
- {
- // Ping thread
- Thread t = new Thread() {
- @Override
- public void run() {
- // PING in ASCII
- final byte[] pingPacketData = new byte[] {0x50, 0x49, 0x4E, 0x47};
- DatagramPacket pingPacket = new DatagramPacket(pingPacketData, pingPacketData.length);
- pingPacket.setSocketAddress(new InetSocketAddress(host, RTP_PORT));
-
- // Send PING every 100 ms
- while (!isInterrupted())
- {
- try {
- rtp.send(pingPacket);
- } catch (IOException e) {
- listener.connectionTerminated(e);
- return;
- }
-
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- listener.connectionTerminated(e);
- return;
- }
- }
- }
- };
- threads.add(t);
- t.setName("Video - Ping");
- t.setPriority(Thread.MIN_PRIORITY);
- t.start();
- }
-}
diff --git a/src/com/limelight/nvstream/NvmDNS.java b/src/com/limelight/nvstream/NvmDNS.java
deleted file mode 100644
index 65a5b2a4..00000000
--- a/src/com/limelight/nvstream/NvmDNS.java
+++ /dev/null
@@ -1,282 +0,0 @@
-package com.limelight.nvstream;
-
-import java.io.IOException;
-
-import java.net.DatagramPacket;
-import java.net.InetAddress;
-import java.net.MulticastSocket;
-
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.UUID;
-
-import org.xbill.DNS.DClass;
-import org.xbill.DNS.Header;
-import org.xbill.DNS.Message;
-import org.xbill.DNS.Name;
-import org.xbill.DNS.Record;
-import org.xbill.DNS.Section;
-import org.xbill.DNS.TXTRecord;
-import org.xbill.DNS.TextParseException;
-import org.xbill.DNS.Type;
-
-import android.os.AsyncTask;
-import android.util.Log;
-
-public class NvmDNS extends AsyncTask {
-
- public static String MDNS_QUERY = "_nvstream._tcp.local.";
- public static String MDNS_MULTICAST_GROUP = "224.0.0.251";
- public static InetAddress MDNS_MULTICAST_ADDRESS;
- public static final short MDNS_PORT = 5353;
-
- public static final int WAIT_MS = 1000;
-
- private HashSet responses;
- private MulticastSocket socket;
-
- static {
- try {
- MDNS_MULTICAST_ADDRESS = InetAddress.getByName(NvmDNS.MDNS_MULTICAST_GROUP);
- } catch (UnknownHostException e) {
- MDNS_MULTICAST_ADDRESS = null;
- }
- }
-
- public NvmDNS() {
- this.responses = new HashSet();
-
- // Create our Socket Connection
- try {
- this.socket = new MulticastSocket(NvmDNS.MDNS_PORT);
- this.socket.setLoopbackMode(false);
- this.socket.joinGroup(NvmDNS.MDNS_MULTICAST_ADDRESS);
- Log.v("NvmDNS Socket Constructor", "Created mDNS listening socket");
- } catch (IOException e) {
- Log.e("NvmDNS Socket Constructor", "There was an error creating the DNS socket.");
- Log.e("NvmDNS Socket Constructor", e.getMessage());
- }
- }
-
- public Set getComputers() {
- return Collections.unmodifiableSet(this.responses);
- }
-
- private void sendQuery() {
- Header queryHeader = new Header();
-
- // If we set the RA (Recursion Available) flag and our message ID to 0
- // then the packet matches the real mDNS query packet as displayed in Wireshark
- queryHeader.setFlag(org.xbill.DNS.Flags.RA);
- queryHeader.setID(0);
-
- Record question = null;
- try {
- // We need to create our "Question" DNS query that is a pointer record to
- // the mDNS Query "Name"
- question = Record.newRecord(new Name(NvmDNS.MDNS_QUERY), Type.PTR, DClass.IN);
- } catch (TextParseException e) {
- Log.e("NvmDNS Query", e.getMessage());
- return;
- }
-
- // We combine our header and our question into a single message
- Message query = new Message();
- query.setHeader(queryHeader);
- query.addRecord(question, Section.QUESTION);
-
- // Convert the message into Network Byte Order
- byte[] wireQuery = query.toWire();
- Log.i("NvmDNS Query", query.toString());
-
- // Convert our byte array into a Packet
- DatagramPacket transmitPacket = new DatagramPacket(wireQuery, wireQuery.length);
- transmitPacket.setAddress(NvmDNS.MDNS_MULTICAST_ADDRESS);
- transmitPacket.setPort(NvmDNS.MDNS_PORT);
-
- // And (attempt) to send the packet
- try {
- Log.d("NvmDNS Query", "Blocking on this.nvstream_socket.send(transmitPacket)");
- this.socket.send(transmitPacket);
- Log.d("NvmDNS Query", "Passed this.nvstream_socket.send(transmitPacket)");
- } catch (IOException e) {
- Log.e("NvmDNS Query", "There was an error sending the DNS query.");
- Log.e("NvmDNS Query", e.getMessage());
- }
- }
-
- public void waitForResponses() {
- Log.v("NvmDNS Response", "mDNS Loop Started");
-
- // We support up to 1500 byte packets
- byte[] data = new byte[1500];
- DatagramPacket packet = new DatagramPacket(data, data.length);
-
- Message message = null;
-
- while (!this.socket.isClosed()) {
- // Attempt to receive a packet/response
- try {
- Log.d("NvmDNS Response", "Blocking on this.nvstream_query_socket.recieve()");
- this.socket.receive(packet);
- Log.d("NvmDNS Response", "Blocking passed on this.nvstream_query_socket.recieve()");
- message = new Message(packet.getData());
- this.parseRecord(message, packet.getAddress());
- } catch (IOException e) {
- if (this.socket.isClosed()) {
- Log.e("NvmDNS Response", "The socket was closed on us. The timer must have been reached.");
- return;
- } else {
- Log.e("NvmDNS Response", "There was an error receiving the response.");
- Log.e("NvmDNS Response", e.getMessage());
- continue;
- }
- }
- }
- }
-
- private void parseRecord(Message message, InetAddress address) {
- // We really only care about the ADDITIONAL section (specifically the text records)
- Record[] responses = message.getSectionArray(Section.ADDITIONAL);
- // We only want to process records that actually have a length, have an ANSWER
- // section that has stuff in it and that the ANSWER to our query is what we sent
- if (responses.length != 0 &&
- message.getSectionArray(Section.ANSWER).length != 0 &&
- message.getSectionArray(Section.ANSWER)[0].getName().toString().equals(NvmDNS.MDNS_QUERY)) {
-
- Log.v("NvmDNS Response", "Got a packet from " + address.getCanonicalHostName());
- Log.v("NvmDNS Response", "Question: " + message.getSectionArray(Section.ANSWER)[0].getName().toString());
- Log.v("NvmDNS Response", "Response: " + responses[0].getName().toString());
-
-
- // TODO: The DNS entry we get is "XENITH._nvstream._tcp.local."
- // And the .'s in there are not actually periods. Or something.
- String hostname = responses[0].getName().toString();
-
- // The records can be returned in any order, so we need to figure out which one is the TXTRecord
- // We get three records back: A TXTRecord, a SRVRecord and an ARecord
- TXTRecord txtRecord = null;
-
- for (Record record : responses) {
- Log.v("NvmDNS Response", "We recieved a DNS repsonse with a " + record.getClass().getName() + " record.");
- if (record instanceof TXTRecord) {
- txtRecord = (TXTRecord)record;
- }
- }
-
- if (txtRecord == null) {
- Log.e("NvmDNS Response", "We recieved a malformed DNS repsonse with no TXTRecord");
- return;
- }
-
- this.parseTXTRecord(txtRecord, address, hostname);
- }
- }
-
- private void parseTXTRecord(TXTRecord txtRecord, InetAddress address, String hostname) {
- // The DNS library we are using does not use inferred generics :(
- @SuppressWarnings("unchecked")
- ArrayList txtRecordStringList = new ArrayList(txtRecord.getStrings());
-
- if (txtRecordStringList.size() != 5) {
- Log.e("NvmDNS Response", "We recieved a malformed DNS repsonse with the improper amount of TXTRecord Entries.");
- return;
- }
-
- // The general format of the text records is:
- // SERVICE_STATE=1
- // SERVICE_NUMOFAPPS=5
- // SERVICE_GPUTYPE=GeForce GTX 760 x2
- // SERVICE_MAC=DE:AD:BE:EF:CA:FE
- // SERVICE_UNIQUEID={A Wild UUID Appeared!}
- // Every single record I've seen so far has been in this format
- try {
- int serviceState = Integer.parseInt(this.parseTXTRecordField(txtRecordStringList.get(0), "SERVICE_STATE"));
- int numberOfApps = Integer.parseInt(this.parseTXTRecordField(txtRecordStringList.get(1), "SERVICE_NUMOFAPPS"));
- String gpuType = this.parseTXTRecordField(txtRecordStringList.get(2), "SERVICE_GPUTYPE");
- String mac = this.parseTXTRecordField(txtRecordStringList.get(3), "SERVICE_MAC");
- UUID uniqueID = UUID.fromString(this.parseTXTRecordField(txtRecordStringList.get(4), "SERVICE_UNIQUEID"));
-
- // We need to resolve the hostname in this thread so that we can use it in the GUI
- address.getCanonicalHostName();
-
- NvComputer computer = new NvComputer(hostname, address, serviceState, numberOfApps, gpuType, mac, uniqueID);
- this.responses.add(computer);
- } catch (ArrayIndexOutOfBoundsException e) {
- Log.e("NvmDNS Response", "We recieved a malformed DNS repsonse.");
- }
- }
-
- private String parseTXTRecordField(String field, String key) {
- // Make sure that our key=value pair actually has our key in it
- if (!field.contains(key)) {
- return "";
- }
-
- // Make sure that our key=value pair only has one "=" in it.
- if (field.indexOf('=') != field.lastIndexOf('=')) {
- return "";
- }
-
- String[] split = field.split("=");
-
- if (split.length != 2) {
- return "";
- }
-
- return split[1];
- }
-
- // What follows is an implementation of Android's AsyncTask.
- // The first step is to send our query, then we start our
- // RX thread to parse responses. However we only want to accept
- // responses for a limited amount of time so we start a new thread
- // to kill the socket after a set amount of time
- // Then we return control to the foreground thread
-
- @Override
- protected Void doInBackground(Void... thisParameterIsUseless) {
- Log.v("NvmDNS ASync", "doInBackground entered");
-
- this.sendQuery();
-
-
- // We want to run our wait thread for an amount of time then close the socket.
- new Thread(new Runnable() {
- @Override
- public void run() {
- Log.v("NvmDNS Wait", "Going to sleep for " + NvmDNS.WAIT_MS + "ms");
- try {
- Thread.sleep(NvmDNS.WAIT_MS);
- } catch (InterruptedException e) {
- Log.e("NvmDNS Wait", "Woke up from sleep before time.");
- Log.e("NvmDNS Wait", e.getMessage());
- }
- Log.v("NvmDNS Wait", "Woke up from sleep");
- NvmDNS.this.socket.close();
- Log.v("NvmDNS Wait", "Socket Closed");
- }
- }).start();
-
- this.waitForResponses();
-
- Log.v("NvmDNS ASync", "doInBackground exit");
- return null;
- }
-
- @Override
- protected void onProgressUpdate(Integer... progress) {
- Log.v("NvmDNS ASync", "onProgressUpdate");
- }
-
- @Override
- protected void onPostExecute(Void moreUselessParameters) {
- Log.v("NvmDNS ASync", "onPostExecute");
- for (NvComputer computer : this.responses) {
- Log.i("NvmDNS NvComputer", computer.toString());
- }
- }
-}
diff --git a/src/com/limelight/nvstream/av/AvByteBufferDescriptor.java b/src/com/limelight/nvstream/av/AvByteBufferDescriptor.java
deleted file mode 100644
index 8f11a956..00000000
--- a/src/com/limelight/nvstream/av/AvByteBufferDescriptor.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.limelight.nvstream.av;
-
-public class AvByteBufferDescriptor {
- public byte[] data;
- public int offset;
- public int length;
-
- public AvByteBufferDescriptor(byte[] data, int offset, int length)
- {
- this.data = data;
- this.offset = offset;
- this.length = length;
- }
-
- public AvByteBufferDescriptor(AvByteBufferDescriptor desc)
- {
- this.data = desc.data;
- this.offset = desc.offset;
- this.length = desc.length;
- }
-
- public void reinitialize(byte[] data, int offset, int length)
- {
- this.data = data;
- this.offset = offset;
- this.length = length;
- }
-
- public void print()
- {
- print(offset, length);
- }
-
- public void print(int length)
- {
- print(this.offset, length);
- }
-
- public void print(int offset, int length)
- {
- for (int i = offset; i < offset+length; i++) {
- System.out.printf("%d: %02x \n", i, data[i]);
- }
- System.out.println();
- }
-}
diff --git a/src/com/limelight/nvstream/av/AvDecodeUnit.java b/src/com/limelight/nvstream/av/AvDecodeUnit.java
deleted file mode 100644
index 69300b83..00000000
--- a/src/com/limelight/nvstream/av/AvDecodeUnit.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.limelight.nvstream.av;
-
-import java.util.List;
-
-public class AvDecodeUnit {
- public static final int TYPE_UNKNOWN = 0;
- public static final int TYPE_H264 = 1;
- public static final int TYPE_OPUS = 2;
-
- private int type;
- private List bufferList;
- private int dataLength;
- private int flags;
-
- public AvDecodeUnit(int type, List bufferList, int dataLength, int flags)
- {
- this.type = type;
- this.bufferList = bufferList;
- this.dataLength = dataLength;
- this.flags = flags;
- }
-
- public int getType()
- {
- return type;
- }
-
- public int getFlags()
- {
- return flags;
- }
-
- public List getBufferList()
- {
- return bufferList;
- }
-
- public int getDataLength()
- {
- return dataLength;
- }
-}
diff --git a/src/com/limelight/nvstream/av/AvRtpPacket.java b/src/com/limelight/nvstream/av/AvRtpPacket.java
deleted file mode 100644
index 8e4250e7..00000000
--- a/src/com/limelight/nvstream/av/AvRtpPacket.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.limelight.nvstream.av;
-
-import java.nio.ByteBuffer;
-
-public class AvRtpPacket {
-
- private byte packetType;
- private short seqNum;
- private AvByteBufferDescriptor buffer;
-
- public AvRtpPacket(AvByteBufferDescriptor buffer)
- {
- this.buffer = new AvByteBufferDescriptor(buffer);
-
- ByteBuffer bb = ByteBuffer.wrap(buffer.data, buffer.offset, buffer.length);
-
- // Discard the first byte
- bb.position(bb.position()+1);
-
- // Get the packet type
- packetType = bb.get();
-
- // Get the sequence number
- seqNum = bb.getShort();
- }
-
- public byte getPacketType()
- {
- return packetType;
- }
-
- public short getSequenceNumber()
- {
- return seqNum;
- }
-
- public byte[] getBackingBuffer()
- {
- return buffer.data;
- }
-
- public AvByteBufferDescriptor getNewPayloadDescriptor()
- {
- return new AvByteBufferDescriptor(buffer.data, buffer.offset+12, buffer.length-12);
- }
-}
diff --git a/src/com/limelight/nvstream/av/AvShortBufferDescriptor.java b/src/com/limelight/nvstream/av/AvShortBufferDescriptor.java
deleted file mode 100644
index 901783f4..00000000
--- a/src/com/limelight/nvstream/av/AvShortBufferDescriptor.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.limelight.nvstream.av;
-
-public class AvShortBufferDescriptor {
- public short[] data;
- public int offset;
- public int length;
-
- public AvShortBufferDescriptor(short[] data, int offset, int length)
- {
- this.data = data;
- this.offset = offset;
- this.length = length;
- }
-
- public AvShortBufferDescriptor(AvShortBufferDescriptor desc)
- {
- this.data = desc.data;
- this.offset = desc.offset;
- this.length = desc.length;
- }
-
- public void reinitialize(short[] data, int offset, int length)
- {
- this.data = data;
- this.offset = offset;
- this.length = length;
- }
-}
diff --git a/src/com/limelight/nvstream/av/ConnectionStatusListener.java b/src/com/limelight/nvstream/av/ConnectionStatusListener.java
deleted file mode 100644
index 35262ddf..00000000
--- a/src/com/limelight/nvstream/av/ConnectionStatusListener.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.limelight.nvstream.av;
-
-public interface ConnectionStatusListener {
- public void connectionTerminated();
-
- public void connectionNeedsResync();
-}
diff --git a/src/com/limelight/nvstream/av/audio/AvAudioDepacketizer.java b/src/com/limelight/nvstream/av/audio/AvAudioDepacketizer.java
deleted file mode 100644
index a13cf3ef..00000000
--- a/src/com/limelight/nvstream/av/audio/AvAudioDepacketizer.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.limelight.nvstream.av.audio;
-
-import java.util.concurrent.LinkedBlockingQueue;
-
-import com.limelight.nvstream.av.AvByteBufferDescriptor;
-import com.limelight.nvstream.av.AvRtpPacket;
-import com.limelight.nvstream.av.AvShortBufferDescriptor;
-
-public class AvAudioDepacketizer {
-
- private static final int DU_LIMIT = 15;
- private LinkedBlockingQueue decodedUnits =
- new LinkedBlockingQueue(DU_LIMIT);
-
- // Sequencing state
- private short lastSequenceNumber;
-
- private void decodeData(byte[] data, int off, int len)
- {
- // Submit this data to the decoder
- short[] pcmData = new short[OpusDecoder.getMaxOutputShorts()];
- int decodeLen = OpusDecoder.decode(data, off, len, pcmData);
-
- if (decodeLen > 0) {
- // Return value of decode is frames decoded per channel
- decodeLen *= OpusDecoder.getChannelCount();
-
- // Put it on the decoded queue
- if (!decodedUnits.offer(new AvShortBufferDescriptor(pcmData, 0, decodeLen))) {
- // Clear out the queue
- decodedUnits.clear();
- }
- }
- }
-
- public void decodeInputData(AvRtpPacket packet)
- {
- short seq = packet.getSequenceNumber();
-
- if (packet.getPacketType() != 97) {
- // Only type 97 is audio
- return;
- }
-
- // Toss out the current NAL if we receive a packet that is
- // out of sequence
- if (lastSequenceNumber != 0 &&
- (short)(lastSequenceNumber + 1) != seq)
- {
- System.out.println("Received OOS audio data (expected "+(lastSequenceNumber + 1)+", got "+seq+")");
- decodeData(null, 0, 0);
- }
-
- lastSequenceNumber = seq;
-
- // This is all the depacketizing we need to do
- AvByteBufferDescriptor rtpPayload = packet.getNewPayloadDescriptor();
- decodeData(rtpPayload.data, rtpPayload.offset, rtpPayload.length);
- }
-
- public AvShortBufferDescriptor getNextDecodedData() throws InterruptedException
- {
- return decodedUnits.take();
- }
-}
diff --git a/src/com/limelight/nvstream/av/audio/OpusDecoder.java b/src/com/limelight/nvstream/av/audio/OpusDecoder.java
deleted file mode 100644
index c01f7fa5..00000000
--- a/src/com/limelight/nvstream/av/audio/OpusDecoder.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.limelight.nvstream.av.audio;
-
-public class OpusDecoder {
- static {
- System.loadLibrary("nv_opus_dec");
- }
-
- public static native int init();
- public static native void destroy();
- public static native int getChannelCount();
- public static native int getMaxOutputShorts();
- public static native int getSampleRate();
- public static native int decode(byte[] indata, int inoff, int inlen, short[] outpcmdata);
-}
diff --git a/src/com/limelight/nvstream/av/video/AvVideoDepacketizer.java b/src/com/limelight/nvstream/av/video/AvVideoDepacketizer.java
deleted file mode 100644
index d6867d70..00000000
--- a/src/com/limelight/nvstream/av/video/AvVideoDepacketizer.java
+++ /dev/null
@@ -1,213 +0,0 @@
-package com.limelight.nvstream.av.video;
-
-import java.util.LinkedList;
-import java.util.concurrent.LinkedBlockingQueue;
-
-import com.limelight.nvstream.av.AvByteBufferDescriptor;
-import com.limelight.nvstream.av.AvDecodeUnit;
-import com.limelight.nvstream.av.AvRtpPacket;
-import com.limelight.nvstream.av.ConnectionStatusListener;
-
-public class AvVideoDepacketizer {
-
- // Current NAL state
- private LinkedList avcNalDataChain = null;
- private int avcNalDataLength = 0;
-
- // Sequencing state
- private short lastSequenceNumber;
-
- private ConnectionStatusListener controlListener;
-
- private static final int DU_LIMIT = 15;
- private LinkedBlockingQueue decodedUnits = new LinkedBlockingQueue(DU_LIMIT);
-
- public AvVideoDepacketizer(ConnectionStatusListener controlListener)
- {
- this.controlListener = controlListener;
- }
-
- private void clearAvcNalState()
- {
- avcNalDataChain = null;
- avcNalDataLength = 0;
- }
-
- private void reassembleAvcNal()
- {
- // This is the start of a new NAL
- if (avcNalDataChain != null && avcNalDataLength != 0) {
- // Construct the H264 decode unit
- AvDecodeUnit du = new AvDecodeUnit(AvDecodeUnit.TYPE_H264, avcNalDataChain, avcNalDataLength, 0);
- if (!decodedUnits.offer(du)) {
- // We need a new IDR frame since we're discarding data now
- decodedUnits.clear();
- controlListener.connectionNeedsResync();
- }
-
- // Clear old state
- clearAvcNalState();
- }
- }
-
- public void addInputData(AvVideoPacket packet)
- {
- AvByteBufferDescriptor location = packet.getNewPayloadDescriptor();
-
- // SPS and PPS packet doesn't have standard headers, so submit it as is
- if (location.length < 968) {
- avcNalDataChain = new LinkedList();
- avcNalDataLength = 0;
-
- avcNalDataChain.add(location);
- avcNalDataLength += location.length;
-
- reassembleAvcNal();
- }
- else {
- int packetIndex = packet.getPacketIndex();
- int packetsInFrame = packet.getTotalPackets();
-
- // Check if this is the first packet for a frame
- if (packetIndex == 0) {
- // Setup state for the new frame
- avcNalDataChain = new LinkedList();
- avcNalDataLength = 0;
- }
-
- // Check if this packet falls in the range of packets in frame
- if (packetIndex >= packetsInFrame) {
- // This isn't H264 frame data
- return;
- }
-
- // Adjust the length to only contain valid data
- location.length = packet.getPayloadLength();
-
- // Add the payload data to the chain
- if (avcNalDataChain != null) {
- avcNalDataChain.add(location);
- avcNalDataLength += location.length;
- }
-
- // Reassemble the NALs if this was the last packet for this frame
- if (packetIndex + 1 == packetsInFrame) {
- reassembleAvcNal();
- }
- }
- }
-
- public void addInputData(AvRtpPacket packet)
- {
- short seq = packet.getSequenceNumber();
-
- // Toss out the current NAL if we receive a packet that is
- // out of sequence
- if (lastSequenceNumber != 0 &&
- (short)(lastSequenceNumber + 1) != seq)
- {
- System.out.println("Received OOS video data (expected "+(lastSequenceNumber + 1)+", got "+seq+")");
-
- // Reset the depacketizer state
- clearAvcNalState();
-
- // Request an IDR frame
- controlListener.connectionNeedsResync();
- }
-
- lastSequenceNumber = seq;
-
- // Pass the payload to the non-sequencing parser
- AvByteBufferDescriptor rtpPayload = packet.getNewPayloadDescriptor();
- addInputData(new AvVideoPacket(rtpPayload));
- }
-
- public AvDecodeUnit getNextDecodeUnit() throws InterruptedException
- {
- return decodedUnits.take();
- }
-}
-
-class NAL {
-
- // This assumes that the buffer passed in is already a special sequence
- public static boolean isAvcStartSequence(AvByteBufferDescriptor specialSeq)
- {
- // The start sequence is 00 00 01 or 00 00 00 01
- return (specialSeq.data[specialSeq.offset+specialSeq.length-1] == 0x01);
- }
-
- // This assumes that the buffer passed in is already a special sequence
- public static boolean isAvcFrameStart(AvByteBufferDescriptor specialSeq)
- {
- if (specialSeq.length != 4)
- return false;
-
- // The frame start sequence is 00 00 00 01
- return (specialSeq.data[specialSeq.offset+specialSeq.length-1] == 0x01);
- }
-
- // Returns a buffer descriptor describing the start sequence
- public static boolean getSpecialSequenceDescriptor(AvByteBufferDescriptor buffer, AvByteBufferDescriptor outputDesc)
- {
- // NAL start sequence is 00 00 00 01 or 00 00 01
- if (buffer.length < 3)
- return false;
-
- // 00 00 is magic
- if (buffer.data[buffer.offset] == 0x00 &&
- buffer.data[buffer.offset+1] == 0x00)
- {
- // Another 00 could be the end of the special sequence
- // 00 00 00 or the middle of 00 00 00 01
- if (buffer.data[buffer.offset+2] == 0x00)
- {
- if (buffer.length >= 4 &&
- buffer.data[buffer.offset+3] == 0x01)
- {
- // It's the AVC start sequence 00 00 00 01
- outputDesc.reinitialize(buffer.data, buffer.offset, 4);
- }
- else
- {
- // It's 00 00 00
- outputDesc.reinitialize(buffer.data, buffer.offset, 3);
- }
- return true;
- }
- else if (buffer.data[buffer.offset+2] == 0x01 ||
- buffer.data[buffer.offset+2] == 0x02)
- {
- // These are easy: 00 00 01 or 00 00 02
- outputDesc.reinitialize(buffer.data, buffer.offset, 3);
- return true;
- }
- else if (buffer.data[buffer.offset+2] == 0x03)
- {
- // 00 00 03 is special because it's a subsequence of the
- // NAL wrapping substitute for 00 00 00, 00 00 01, 00 00 02,
- // or 00 00 03 in the RBSP sequence. We need to check the next
- // byte to see whether it's 00, 01, 02, or 03 (a valid RBSP substitution)
- // or whether it's something else
-
- if (buffer.length < 4)
- return false;
-
- if (buffer.data[buffer.offset+3] >= 0x00 &&
- buffer.data[buffer.offset+3] <= 0x03)
- {
- // It's not really a special sequence after all
- return false;
- }
- else
- {
- // It's not a standard replacement so it's a special sequence
- outputDesc.reinitialize(buffer.data, buffer.offset, 3);
- return true;
- }
- }
- }
-
- return false;
- }
-}
diff --git a/src/com/limelight/nvstream/av/video/AvVideoPacket.java b/src/com/limelight/nvstream/av/video/AvVideoPacket.java
deleted file mode 100644
index 0113f344..00000000
--- a/src/com/limelight/nvstream/av/video/AvVideoPacket.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.limelight.nvstream.av.video;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-import com.limelight.nvstream.av.AvByteBufferDescriptor;
-
-public class AvVideoPacket {
- private AvByteBufferDescriptor buffer;
-
- private int frameIndex;
- private int packetIndex;
- private int totalPackets;
- private int payloadLength;
-
- public AvVideoPacket(AvByteBufferDescriptor rtpPayload)
- {
- buffer = new AvByteBufferDescriptor(rtpPayload);
-
- ByteBuffer bb = ByteBuffer.wrap(buffer.data).order(ByteOrder.LITTLE_ENDIAN);
- bb.position(buffer.offset);
-
- frameIndex = bb.getInt();
- packetIndex = bb.getInt();
- totalPackets = bb.getInt();
-
- bb.position(bb.position()+4);
-
- payloadLength = bb.getInt();
- }
-
- public int getFrameIndex()
- {
- return frameIndex;
- }
-
- public int getPacketIndex()
- {
- return packetIndex;
- }
-
- public int getPayloadLength()
- {
- return payloadLength;
- }
-
- public int getTotalPackets()
- {
- return totalPackets;
- }
-
- public AvByteBufferDescriptor getNewPayloadDescriptor()
- {
- return new AvByteBufferDescriptor(buffer.data, buffer.offset+56, buffer.length-56);
- }
-}
diff --git a/src/com/limelight/nvstream/av/video/DecoderRenderer.java b/src/com/limelight/nvstream/av/video/DecoderRenderer.java
deleted file mode 100644
index 486d0f18..00000000
--- a/src/com/limelight/nvstream/av/video/DecoderRenderer.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.limelight.nvstream.av.video;
-
-import com.limelight.nvstream.av.AvDecodeUnit;
-
-import android.content.Context;
-import android.view.SurfaceHolder;
-
-public interface DecoderRenderer {
- public static int FLAG_PREFER_QUALITY = 0x1;
-
- public void setup(Context context, int width, int height, SurfaceHolder renderTarget, int drFlags);
-
- public void start();
-
- public void stop();
-
- public void release();
-
- public boolean submitDecodeUnit(AvDecodeUnit decodeUnit);
-}
diff --git a/src/com/limelight/nvstream/av/video/cpu/AvcDecoder.java b/src/com/limelight/nvstream/av/video/cpu/AvcDecoder.java
deleted file mode 100644
index d9cbcf31..00000000
--- a/src/com/limelight/nvstream/av/video/cpu/AvcDecoder.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.limelight.nvstream.av.video.cpu;
-
-import android.view.Surface;
-
-public class AvcDecoder {
- static {
- // FFMPEG dependencies
- System.loadLibrary("avutil-52");
- System.loadLibrary("swresample-0");
- System.loadLibrary("swscale-2");
- System.loadLibrary("avcodec-55");
- System.loadLibrary("avformat-55");
- System.loadLibrary("avfilter-3");
-
- System.loadLibrary("nv_avc_dec");
- }
-
- /** Disables the deblocking filter at the cost of image quality */
- public static final int DISABLE_LOOP_FILTER = 0x1;
- /** Uses the low latency decode flag (disables multithreading) */
- public static final int LOW_LATENCY_DECODE = 0x2;
- /** Threads process each slice, rather than each frame */
- public static final int SLICE_THREADING = 0x4;
- /** Uses nonstandard speedup tricks */
- public static final int FAST_DECODE = 0x8;
- /** Uses bilinear filtering instead of bicubic */
- public static final int BILINEAR_FILTERING = 0x10;
- /** Uses a faster bilinear filtering with lower image quality */
- public static final int FAST_BILINEAR_FILTERING = 0x20;
- /** Disables color conversion (output is NV21) */
- public static final int NO_COLOR_CONVERSION = 0x40;
-
- public static native int init(int width, int height, int perflvl, int threadcount);
- public static native void destroy();
-
- // Rendering API when NO_COLOR_CONVERSION == 0
- public static native boolean setRenderTarget(Surface surface);
- public static native boolean getRgbFrame(byte[] rgbFrame, int bufferSize);
- public static native boolean redraw();
-
- // Rendering API when NO_COLOR_CONVERSION == 1
- public static native boolean getRawFrame(byte[] yuvFrame, int bufferSize);
-
- public static native int getInputPaddingSize();
- public static native int decode(byte[] indata, int inoff, int inlen);
-}
diff --git a/src/com/limelight/nvstream/input/NvController.java b/src/com/limelight/nvstream/input/NvController.java
deleted file mode 100644
index b1b273e7..00000000
--- a/src/com/limelight/nvstream/input/NvController.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.limelight.nvstream.input;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-
-public class NvController {
-
- public final static int PORT = 35043;
-
- public final static int CONTROLLER_TIMEOUT = 3000;
-
- private InetAddress host;
- private Socket s;
- private OutputStream out;
-
- public NvController(InetAddress host)
- {
- this.host = host;
- }
-
- public void initialize() throws IOException
- {
- s = new Socket();
- s.connect(new InetSocketAddress(host, PORT), CONTROLLER_TIMEOUT);
- s.setTcpNoDelay(true);
- out = s.getOutputStream();
- }
-
- public void close()
- {
- try {
- s.close();
- } catch (IOException e) {}
- }
-
- public void sendControllerInput(short buttonFlags, byte leftTrigger, byte rightTrigger,
- short leftStickX, short leftStickY, short rightStickX, short rightStickY) throws IOException
- {
- out.write(new NvControllerPacket(buttonFlags, leftTrigger,
- rightTrigger, leftStickX, leftStickY,
- rightStickX, rightStickY).toWire());
- 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();
- }
-}
diff --git a/src/com/limelight/nvstream/input/NvControllerPacket.java b/src/com/limelight/nvstream/input/NvControllerPacket.java
deleted file mode 100644
index 06ab0061..00000000
--- a/src/com/limelight/nvstream/input/NvControllerPacket.java
+++ /dev/null
@@ -1,89 +0,0 @@
-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 SPECIAL_BUTTON_FLAG = 0x0400;
-
- 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();
- }
- }
\ No newline at end of file
diff --git a/src/com/limelight/nvstream/input/NvInputPacket.java b/src/com/limelight/nvstream/input/NvInputPacket.java
deleted file mode 100644
index ec98b2de..00000000
--- a/src/com/limelight/nvstream/input/NvInputPacket.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.limelight.nvstream.input;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-public abstract class NvInputPacket {
- public static final int HEADER_LENGTH = 0x4;
-
- protected int packetType;
-
- public NvInputPacket(int packetType)
- {
- this.packetType = packetType;
- }
-
- public abstract byte[] toWire();
-
- public byte[] toWireHeader()
- {
- ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
-
- bb.putInt(packetType);
-
- return bb.array();
- }
-}
diff --git a/src/com/limelight/nvstream/input/NvMouseButtonPacket.java b/src/com/limelight/nvstream/input/NvMouseButtonPacket.java
deleted file mode 100644
index 8cb87ac7..00000000
--- a/src/com/limelight/nvstream/input/NvMouseButtonPacket.java
+++ /dev/null
@@ -1,36 +0,0 @@
-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();
- }
-}
diff --git a/src/com/limelight/nvstream/input/NvMouseMovePacket.java b/src/com/limelight/nvstream/input/NvMouseMovePacket.java
deleted file mode 100644
index edafa9c7..00000000
--- a/src/com/limelight/nvstream/input/NvMouseMovePacket.java
+++ /dev/null
@@ -1,42 +0,0 @@
-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();
- }
-}