Update control protocol for GFE 2.0.1

This commit is contained in:
Cameron Gutman 2014-05-06 23:31:09 -04:00
parent aadbc3dd01
commit 92adbe0983
5 changed files with 39 additions and 115 deletions

View File

@ -261,11 +261,6 @@ public class NvConnection {
success = startAudioStream(); success = startAudioStream();
break; break;
case CONTROL_START2:
controlStream.startJitterPackets();
success = true;
break;
case INPUT_START: case INPUT_START:
success = startInputConnection(); success = startInputConnection();
break; break;

View File

@ -8,7 +8,6 @@ public interface NvConnectionListener {
CONTROL_START("control connection"), CONTROL_START("control connection"),
VIDEO_START("video stream"), VIDEO_START("video stream"),
AUDIO_START("audio stream"), AUDIO_START("audio stream"),
CONTROL_START2("control connection"),
INPUT_START("input connection"); INPUT_START("input connection");
private String name; private String name;

View File

@ -6,4 +6,6 @@ public interface ConnectionStatusListener {
public void connectionDetectedFrameLoss(int firstLostFrame, int lastLostFrame); public void connectionDetectedFrameLoss(int firstLostFrame, int lastLostFrame);
public void connectionSinkTooSlow(int firstLostFrame, int lastLostFrame); public void connectionSinkTooSlow(int firstLostFrame, int lastLostFrame);
public void connectionReceivedFrame(int frameIndex);
} }

View File

@ -84,6 +84,8 @@ public class VideoDepacketizer {
decodedUnits.add(du); decodedUnits.add(du);
} }
controlListener.connectionReceivedFrame(frameNumber);
// Clear old state // Clear old state
clearAvcFrameState(); clearAvcFrameState();
} }

View File

@ -12,7 +12,6 @@ import java.util.concurrent.LinkedBlockingQueue;
import com.limelight.LimeLog; import com.limelight.LimeLog;
import com.limelight.nvstream.NvConnectionListener; import com.limelight.nvstream.NvConnectionListener;
import com.limelight.nvstream.StreamConfiguration;
import com.limelight.nvstream.av.ConnectionStatusListener; import com.limelight.nvstream.av.ConnectionStatusListener;
public class ControlStream implements ConnectionStatusListener { public class ControlStream implements ConnectionStatusListener {
@ -21,37 +20,27 @@ public class ControlStream implements ConnectionStatusListener {
public static final int CONTROL_TIMEOUT = 5000; public static final int CONTROL_TIMEOUT = 5000;
public static final short PTYPE_HELLO = 0x1201;
public static final short PPAYLEN_HELLO = 1;
public static final byte[] PPAYLOAD_HELLO = new byte[]{0};
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_START_STREAM_A = 0x140b; public static final short PTYPE_START_STREAM_A = 0x140b;
public static final short PPAYLEN_START_STREAM_A = 1; public static final short PPAYLEN_START_STREAM_A = 1;
public static final byte[] PPAYLOAD_START_STREAM_A = new byte[]{0}; public static final byte[] PPAYLOAD_START_STREAM_A = new byte[]{0};
public static final short PTYPE_START_STREAM_B = 0x1405; public static final short PTYPE_START_STREAM_B = 0x1410;
public static final short PPAYLEN_START_STREAM_B = 0; public static final short PPAYLEN_START_STREAM_B = 16;
public static final short PTYPE_START_STREAM_C = 0x1410;
public static final short PPAYLEN_START_STREAM_C = 16;
public static final short PTYPE_RESYNC = 0x1404; public static final short PTYPE_RESYNC = 0x1404;
public static final short PPAYLEN_RESYNC = 16; public static final short PPAYLEN_RESYNC = 24;
public static final short PTYPE_JITTER = 0x140c; public static final short PTYPE_LOSS_STATS = 0x140c;
public static final short PPAYLEN_JITTER = 16; public static final short PPAYLEN_LOSS_STATS = 20;
private int seqNum; // Currently unused
public static final short PTYPE_FRAME_STATS = 0x1417;
public static final short PPAYLEN_FRAME_STATS = 64;
private int currentFrame;
private NvConnectionListener listener; private NvConnectionListener listener;
private InetAddress host; private InetAddress host;
private Config config;
public static final int LOSS_PERIOD_MS = 15000; public static final int LOSS_PERIOD_MS = 15000;
public static final int MAX_LOSS_COUNT_IN_PERIOD = 2; public static final int MAX_LOSS_COUNT_IN_PERIOD = 2;
@ -66,17 +55,15 @@ public class ControlStream implements ConnectionStatusListener {
private InputStream in; private InputStream in;
private OutputStream out; private OutputStream out;
private Thread heartbeatThread; private Thread lossStatsThread;
private Thread jitterThread;
private Thread resyncThread; private Thread resyncThread;
private LinkedBlockingQueue<int[]> invalidReferenceFrameTuples = new LinkedBlockingQueue<int[]>(); private LinkedBlockingQueue<int[]> invalidReferenceFrameTuples = new LinkedBlockingQueue<int[]>();
private boolean aborting = false; private boolean aborting = false;
public ControlStream(InetAddress host, NvConnectionListener listener, StreamConfiguration streamConfig) public ControlStream(InetAddress host, NvConnectionListener listener)
{ {
this.listener = listener; this.listener = listener;
this.host = host; this.host = host;
this.config = new Config(streamConfig);
} }
public void initialize() throws IOException public void initialize() throws IOException
@ -100,21 +87,17 @@ public class ControlStream implements ConnectionStatusListener {
return new NvCtlResponse(in); return new NvCtlResponse(in);
} }
private void sendHello() throws IOException private void sendLossStats() throws IOException
{ {
sendPacket(new NvCtlPacket(PTYPE_HELLO, PPAYLEN_HELLO, PPAYLOAD_HELLO)); ByteBuffer bb = ByteBuffer.allocate(PPAYLEN_LOSS_STATS).order(ByteOrder.LITTLE_ENDIAN);
}
private void sendJitter() throws IOException
{
ByteBuffer bb = ByteBuffer.allocate(16).order(ByteOrder.LITTLE_ENDIAN);
bb.putInt(0); bb.putInt(0);
bb.putInt(77); bb.putInt(30);
bb.putInt(888); bb.putInt(1000);
bb.putInt(seqNum += 2); bb.putInt(currentFrame);
bb.putInt(0);
sendPacket(new NvCtlPacket(PTYPE_JITTER, PPAYLEN_JITTER, bb.array())); sendPacket(new NvCtlPacket(PTYPE_LOSS_STATS, PPAYLEN_LOSS_STATS, bb.array()));
} }
public void abort() public void abort()
@ -129,19 +112,11 @@ public class ControlStream implements ConnectionStatusListener {
s.close(); s.close();
} catch (IOException e) {} } catch (IOException e) {}
if (jitterThread != null) { if (lossStatsThread != null) {
jitterThread.interrupt(); lossStatsThread.interrupt();
try { try {
jitterThread.join(); lossStatsThread.join();
} catch (InterruptedException e) {}
}
if (heartbeatThread != null) {
heartbeatThread.interrupt();
try {
heartbeatThread.join();
} catch (InterruptedException e) {} } catch (InterruptedException e) {}
} }
@ -159,31 +134,26 @@ public class ControlStream implements ConnectionStatusListener {
// Use a finite timeout during the handshake process // Use a finite timeout during the handshake process
s.setSoTimeout(CONTROL_TIMEOUT); s.setSoTimeout(CONTROL_TIMEOUT);
sendHello();
sendConfig();
pingPong();
doStartA(); doStartA();
doStartB(); doStartB();
doStartC();
// Return to an infinte read timeout after the initial control handshake // Return to an infinte read timeout after the initial control handshake
s.setSoTimeout(0); s.setSoTimeout(0);
heartbeatThread = new Thread() { lossStatsThread = new Thread() {
@Override @Override
public void run() { public void run() {
while (!isInterrupted()) while (!isInterrupted())
{ {
try { try {
sendHeartbeat(); sendLossStats();
} catch (IOException e) { } catch (IOException e) {
listener.connectionTerminated(e); listener.connectionTerminated(e);
return; return;
} }
try { try {
Thread.sleep(3000); Thread.sleep(100);
} catch (InterruptedException e) { } catch (InterruptedException e) {
listener.connectionTerminated(e); listener.connectionTerminated(e);
return; return;
@ -191,8 +161,8 @@ public class ControlStream implements ConnectionStatusListener {
} }
} }
}; };
heartbeatThread.setName("Control - Heartbeat Thread"); lossStatsThread.setName("Control - Loss Stats Thread");
heartbeatThread.start(); lossStatsThread.start();
resyncThread = new Thread() { resyncThread = new Thread() {
@Override @Override
@ -243,54 +213,22 @@ public class ControlStream implements ConnectionStatusListener {
resyncThread.start(); 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.setName("Control - Jitter Thread");
jitterThread.start();
}
private ControlStream.NvCtlResponse doStartA() throws IOException private ControlStream.NvCtlResponse doStartA() throws IOException
{ {
return sendAndGetReply(new NvCtlPacket(PTYPE_START_STREAM_A, return sendAndGetReply(new NvCtlPacket(PTYPE_START_STREAM_A,
PPAYLEN_START_STREAM_A, PPAYLOAD_START_STREAM_A)); PPAYLEN_START_STREAM_A, PPAYLOAD_START_STREAM_A));
} }
private void doStartB() throws IOException private ControlStream.NvCtlResponse doStartB() throws IOException
{ {
sendPacket(new NvCtlPacket(PTYPE_START_STREAM_B, PPAYLEN_START_STREAM_B)); ByteBuffer payload = ByteBuffer.wrap(new byte[PPAYLEN_START_STREAM_B]).order(ByteOrder.LITTLE_ENDIAN);
}
private ControlStream.NvCtlResponse doStartC() throws IOException
{
ByteBuffer payload = ByteBuffer.wrap(new byte[PPAYLEN_START_STREAM_C]).order(ByteOrder.LITTLE_ENDIAN);
payload.putInt(0); payload.putInt(0);
payload.putInt(0); payload.putInt(0);
payload.putInt(0); payload.putInt(0);
payload.putInt(0xa); payload.putInt(0xa);
return sendAndGetReply(new NvCtlPacket(PTYPE_START_STREAM_C, PPAYLEN_START_STREAM_C, payload.array())); return sendAndGetReply(new NvCtlPacket(PTYPE_START_STREAM_B, PPAYLEN_START_STREAM_B, payload.array()));
} }
private void sendResync(int firstLostFrame, int nextSuccessfulFrame) throws IOException private void sendResync(int firstLostFrame, int nextSuccessfulFrame) throws IOException
@ -301,27 +239,11 @@ public class ControlStream implements ConnectionStatusListener {
//conf.putLong(nextSuccessfulFrame); //conf.putLong(nextSuccessfulFrame);
conf.putLong(0); conf.putLong(0);
conf.putLong(0xFFFFF); conf.putLong(0xFFFFF);
conf.putLong(0);
sendAndGetReply(new NvCtlPacket(PTYPE_RESYNC, PPAYLEN_RESYNC, conf.array())); sendAndGetReply(new NvCtlPacket(PTYPE_RESYNC, PPAYLEN_RESYNC, conf.array()));
} }
private void sendConfig() throws IOException
{
out.write(config.toWire());
out.flush();
}
private void sendHeartbeat() throws IOException
{
sendPacket(new NvCtlPacket(PTYPE_HEARTBEAT, PPAYLEN_HEARTBEAT));
}
private ControlStream.NvCtlResponse pingPong() throws IOException
{
sendPacket(new NvCtlPacket(PTYPE_KEEPALIVE, PPAYLEN_KEEPALIVE));
return new ControlStream.NvCtlResponse(in);
}
class NvCtlPacket { class NvCtlPacket {
public short type; public short type;
public short paylen; public short paylen;
@ -493,4 +415,8 @@ public class ControlStream implements ConnectionStatusListener {
resyncConnection(firstLostFrame, nextSuccessfulFrame); resyncConnection(firstLostFrame, nextSuccessfulFrame);
} }
public void connectionReceivedFrame(int frameIndex) {
currentFrame = frameIndex;
}
} }