From 537a50bee5556816822f70a14f7cf32532bbc160 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 21 Apr 2016 13:28:55 -0400 Subject: [PATCH 1/5] Revert "Some Java crypto providers don't allow IvParameterSpec objects for GCM ciphers, so use GCMParameterSpec instead" This reverts commit b37d46fae9b89f5435990c75ce540d64efe374f7. --- .../src/com/limelight/nvstream/input/ControllerStream.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/moonlight-common/src/com/limelight/nvstream/input/ControllerStream.java b/moonlight-common/src/com/limelight/nvstream/input/ControllerStream.java index 62af62ca..88a19afa 100644 --- a/moonlight-common/src/com/limelight/nvstream/input/ControllerStream.java +++ b/moonlight-common/src/com/limelight/nvstream/input/ControllerStream.java @@ -19,7 +19,6 @@ import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.ShortBufferException; -import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.IvParameterSpec; import com.limelight.nvstream.ConnectionContext; @@ -403,7 +402,7 @@ public class ControllerStream { Cipher cipher; try { cipher = Cipher.getInstance("AES/GCM/NoPadding"); - cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, iv)); + cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); // This is also non-ideal. Java gives us but we want to send // so we'll take the output and arraycopy it into the right spot in the output buffer From 3c11ff63a7f502a6da42e86460e434ac9a884f57 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 7 May 2016 20:26:44 -0400 Subject: [PATCH 2/5] Return the oldest packet instead of removing it upon RTP queue constraint violation --- .../nvstream/av/RtpReorderQueue.java | 32 ++++++------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/moonlight-common/src/com/limelight/nvstream/av/RtpReorderQueue.java b/moonlight-common/src/com/limelight/nvstream/av/RtpReorderQueue.java index a50d310a..81756c13 100644 --- a/moonlight-common/src/com/limelight/nvstream/av/RtpReorderQueue.java +++ b/moonlight-common/src/com/limelight/nvstream/av/RtpReorderQueue.java @@ -14,7 +14,6 @@ public class RtpReorderQueue { private short nextRtpSequenceNumber; private long oldestQueuedTime; - private RtpQueueEntry oldestQueuedEntry; public enum RtpQueueStatus { HANDLE_IMMEDIATELY, @@ -65,7 +64,6 @@ public class RtpReorderQueue { if (oldestQueuedTime == Long.MAX_VALUE) { oldestQueuedTime = entry.queueTime; - oldestQueuedEntry = entry; } // Add a reference to the packet while it's in the queue @@ -83,10 +81,8 @@ public class RtpReorderQueue { private void updateOldestQueued() { oldestQueuedTime = Long.MAX_VALUE; - oldestQueuedEntry = null; for (RtpQueueEntry entry : queue) { if (entry.queueTime < oldestQueuedTime) { - oldestQueuedEntry = entry; oldestQueuedTime = entry.queueTime; } } @@ -114,36 +110,28 @@ public class RtpReorderQueue { return lowestSeqEntry; } - private void removeEntry(RtpQueueEntry entry) { - queue.remove(entry); - entry.packet.dereferencePacket(); - } - private RtpQueueEntry validateQueueConstraints() { if (queue.isEmpty()) { return null; } - boolean needsUpdate = false; + boolean dequeuePacket = false; // Check that the queue's time constraint is satisfied if (TimeHelper.getMonotonicMillis() - oldestQueuedTime > maxQueueTime) { - LimeLog.info("Discarding RTP packet queued for too long: "+(TimeHelper.getMonotonicMillis() - oldestQueuedTime)); - removeEntry(oldestQueuedEntry); - needsUpdate = true; + LimeLog.info("Returning RTP packet queued for too long: "+(TimeHelper.getMonotonicMillis() - oldestQueuedTime)); + dequeuePacket = true; } - - // Check that the queue's size constraint is satisfied - if (queue.size() == maxSize) { + + // Check that the queue's size constraint is satisfied. We subtract one + // because this is validating that the queue will meet constraints _after_ + // the current packet is enqueued. + if (!dequeuePacket && queue.size() == maxSize - 1) { LimeLog.info("Discarding RTP packet after queue overgrowth"); - removeEntry(oldestQueuedEntry); - needsUpdate = true; + dequeuePacket = true; } - if (needsUpdate) { - // Recalculate the oldest entry if needed - updateOldestQueued(); - + if (dequeuePacket) { // Return the lowest seq queued return getEntryByLowestSeq(); } From 4ef1b8dc4ca3dfce3be16a7d154729e312e0f0ec Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 7 May 2016 20:55:41 -0400 Subject: [PATCH 3/5] Fix debug message --- .../src/com/limelight/nvstream/av/RtpReorderQueue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonlight-common/src/com/limelight/nvstream/av/RtpReorderQueue.java b/moonlight-common/src/com/limelight/nvstream/av/RtpReorderQueue.java index 81756c13..398850f7 100644 --- a/moonlight-common/src/com/limelight/nvstream/av/RtpReorderQueue.java +++ b/moonlight-common/src/com/limelight/nvstream/av/RtpReorderQueue.java @@ -127,7 +127,7 @@ public class RtpReorderQueue { // because this is validating that the queue will meet constraints _after_ // the current packet is enqueued. if (!dequeuePacket && queue.size() == maxSize - 1) { - LimeLog.info("Discarding RTP packet after queue overgrowth"); + LimeLog.info("Returning RTP packet after queue overgrowth"); dequeuePacket = true; } From 439afd15fa14e92cb7204ce589d93e10789b6a4d Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Fri, 27 May 2016 12:38:09 -0500 Subject: [PATCH 4/5] Cancel the pending IDR frame request if we got a spurious IDR frame after a stream discontinuity --- .../src/com/limelight/nvstream/av/video/VideoDepacketizer.java | 3 +++ 1 file changed, 3 insertions(+) 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 45d344fd..224d5484 100644 --- a/moonlight-common/src/com/limelight/nvstream/av/video/VideoDepacketizer.java +++ b/moonlight-common/src/com/limelight/nvstream/av/video/VideoDepacketizer.java @@ -277,6 +277,9 @@ public class VideoDepacketizer { if (isReferencePictureNalu(cachedSpecialDesc.data[cachedSpecialDesc.offset+cachedSpecialDesc.length])) { // This is the NALU code for I-frame data waitingForIdrFrame = false; + + // Cancel any pending IDR frame request + waitingForNextSuccessfulFrame = false; } } From b5e89e47b674694d35e678e331becbac424c5927 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 29 May 2016 16:04:55 -0500 Subject: [PATCH 5/5] Improve mDNS for multi-homed systems --- .../nvstream/mdns/MdnsDiscoveryAgent.java | 41 ++++++++----------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/moonlight-common/src/com/limelight/nvstream/mdns/MdnsDiscoveryAgent.java b/moonlight-common/src/com/limelight/nvstream/mdns/MdnsDiscoveryAgent.java index 7d60ab5b..2bee06b8 100644 --- a/moonlight-common/src/com/limelight/nvstream/mdns/MdnsDiscoveryAgent.java +++ b/moonlight-common/src/com/limelight/nvstream/mdns/MdnsDiscoveryAgent.java @@ -106,41 +106,32 @@ public class MdnsDiscoveryAgent implements ServiceListener { } private void handleResolvedServiceInfo(ServiceInfo info) { - MdnsComputer computer; - pendingResolution.remove(info.getName()); try { - computer = parseServerInfo(info); - if (computer == null) { - LimeLog.info("mDNS: Invalid response for machine: "+info.getName()); - return; - } + handleServiceInfo(info); } catch (UnsupportedEncodingException e) { // Invalid DNS response LimeLog.info("mDNS: Invalid response for machine: "+info.getName()); return; } - - synchronized (computers) { - if (computers.put(computer.getAddress(), computer) == null) { - // This was a new entry - listener.notifyComputerAdded(computer); - } - } } - private static MdnsComputer parseServerInfo(ServiceInfo info) throws UnsupportedEncodingException { + private void handleServiceInfo(ServiceInfo info) throws UnsupportedEncodingException { Inet4Address addrs[] = info.getInet4Addresses(); - if (addrs.length == 0) { - LimeLog.info("mDNS: "+info.getName()+" is missing addresses"); - return null; + + LimeLog.info("mDNS: "+info.getName()+" has "+addrs.length+" addresses"); + + // Add a computer object for each IPv4 address reported by the PC + for (Inet4Address addr : addrs) { + synchronized (computers) { + MdnsComputer computer = new MdnsComputer(info.getName(), addr); + if (computers.put(computer.getAddress(), computer) == null) { + // This was a new entry + listener.notifyComputerAdded(computer); + } + } } - - Inet4Address address = addrs[0]; - String name = info.getName(); - - return new MdnsComputer(name, address); } public void startDiscovery(final int discoveryIntervalMs) { @@ -171,7 +162,9 @@ public class MdnsDiscoveryAgent implements ServiceListener { ServiceInfo[] infos = resolver.getServiceInfos(SERVICE_TYPE, name, 500); if (infos != null && infos.length != 0) { LimeLog.info("mDNS: Resolved (retry) with "+infos.length+" service entries"); - handleResolvedServiceInfo(infos[0]); + for (ServiceInfo svcinfo : infos) { + handleResolvedServiceInfo(svcinfo); + } } }