From 0c8c108bd1ed82c0ce58354b9f858dc38812a619 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 11 May 2014 18:49:20 -0500 Subject: [PATCH] Add support for sending proper packet loss statistics for server-side bandwidth scaling --- .../nvstream/av/ConnectionStatusListener.java | 2 ++ .../nvstream/av/video/VideoDepacketizer.java | 8 ++++++++ .../nvstream/av/video/VideoPacket.java | 7 +++++++ .../nvstream/control/ControlStream.java | 18 +++++++++++++----- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/moonlight-common/src/com/limelight/nvstream/av/ConnectionStatusListener.java b/moonlight-common/src/com/limelight/nvstream/av/ConnectionStatusListener.java index 91bcc0ce..d74cf8f5 100644 --- a/moonlight-common/src/com/limelight/nvstream/av/ConnectionStatusListener.java +++ b/moonlight-common/src/com/limelight/nvstream/av/ConnectionStatusListener.java @@ -8,4 +8,6 @@ public interface ConnectionStatusListener { public void connectionSinkTooSlow(int firstLostFrame, int lastLostFrame); public void connectionReceivedFrame(int frameIndex); + + public void connectionLostPackets(int lastReceivedPacket, int nextReceivedPacket); } diff --git a/moonlight-common/src/com/limelight/nvstream/av/video/VideoDepacketizer.java b/moonlight-common/src/com/limelight/nvstream/av/video/VideoDepacketizer.java index 45ef973c..32e6fc32 100644 --- a/moonlight-common/src/com/limelight/nvstream/av/video/VideoDepacketizer.java +++ b/moonlight-common/src/com/limelight/nvstream/av/video/VideoDepacketizer.java @@ -17,6 +17,7 @@ public class VideoDepacketizer { private int currentlyDecoding = DecodeUnit.TYPE_UNKNOWN; // Sequencing state + private int lastPacketInStream = 0; private int nextFrameNumber = 1; private int nextPacketNumber; private int startFrameNumber = 1; @@ -287,6 +288,13 @@ public class VideoDepacketizer { } } + int streamPacketIndex = packet.getStreamPacketIndex(); + if (streamPacketIndex != (int)(lastPacketInStream + 1)) { + // Packets were lost so report this to the server + controlListener.connectionLostPackets(lastPacketInStream, streamPacketIndex); + } + lastPacketInStream = streamPacketIndex; + nextPacketNumber++; // Remove extra padding diff --git a/moonlight-common/src/com/limelight/nvstream/av/video/VideoPacket.java b/moonlight-common/src/com/limelight/nvstream/av/video/VideoPacket.java index 78b21c97..051cf3c7 100644 --- a/moonlight-common/src/com/limelight/nvstream/av/video/VideoPacket.java +++ b/moonlight-common/src/com/limelight/nvstream/av/video/VideoPacket.java @@ -13,6 +13,7 @@ public class VideoPacket { private int totalPackets; private int payloadLength; private int flags; + private int streamPacketIndex; public static final int FLAG_EOF = 0x2; public static final int FLAG_SOF = 0x4; @@ -29,6 +30,7 @@ public class VideoPacket { totalPackets = bb.getInt(); flags = bb.getInt(); payloadLength = bb.getInt(); + streamPacketIndex = bb.getInt(); } public int getFlags() @@ -56,6 +58,11 @@ public class VideoPacket { return totalPackets; } + public int getStreamPacketIndex() + { + return streamPacketIndex; + } + public ByteBufferDescriptor getNewPayloadDescriptor() { return new ByteBufferDescriptor(buffer.data, buffer.offset+56, buffer.length-56); diff --git a/moonlight-common/src/com/limelight/nvstream/control/ControlStream.java b/moonlight-common/src/com/limelight/nvstream/control/ControlStream.java index e51219c3..e5b21739 100644 --- a/moonlight-common/src/com/limelight/nvstream/control/ControlStream.java +++ b/moonlight-common/src/com/limelight/nvstream/control/ControlStream.java @@ -37,7 +37,10 @@ public class ControlStream implements ConnectionStatusListener { public static final short PTYPE_FRAME_STATS = 0x1417; public static final short PPAYLEN_FRAME_STATS = 64; + public static final int LOSS_REPORT_INTERVAL_MS = 50; + private int currentFrame; + private int lossCountSinceLastReport; private NvConnectionListener listener; private InetAddress host; @@ -91,11 +94,10 @@ public class ControlStream implements ConnectionStatusListener { { ByteBuffer bb = ByteBuffer.allocate(PPAYLEN_LOSS_STATS).order(ByteOrder.LITTLE_ENDIAN); - bb.putInt(0); - bb.putInt(30); + bb.putInt(lossCountSinceLastReport); // Packet loss count + bb.putInt(LOSS_REPORT_INTERVAL_MS); // Time since last report in milliseconds bb.putInt(1000); - bb.putInt(currentFrame); - bb.putInt(0); + bb.putLong(currentFrame); // Last successfully received frame sendPacket(new NvCtlPacket(PTYPE_LOSS_STATS, PPAYLEN_LOSS_STATS, bb.array())); } @@ -147,13 +149,14 @@ public class ControlStream implements ConnectionStatusListener { { try { sendLossStats(); + lossCountSinceLastReport = 0; } catch (IOException e) { listener.connectionTerminated(e); return; } try { - Thread.sleep(100); + Thread.sleep(LOSS_REPORT_INTERVAL_MS); } catch (InterruptedException e) { listener.connectionTerminated(e); return; @@ -419,4 +422,9 @@ public class ControlStream implements ConnectionStatusListener { public void connectionReceivedFrame(int frameIndex) { currentFrame = frameIndex; } + + public void connectionLostPackets(int lastReceivedPacket, int nextReceivedPacket) { + // Update the loss count for the next loss report + lossCountSinceLastReport += (nextReceivedPacket - lastReceivedPacket) - 1; + } }