From f09fbf4ba666e2e811bd73f84be233b30942aac1 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Fri, 23 Oct 2015 14:46:03 -0700 Subject: [PATCH 1/5] Fix incorrect usage of SeqParameterSet.read() by feeding it possibly escaped Annex B NALUs --- .../binding/video/MediaCodecDecoderRenderer.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java b/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java index 74818ae5..14011535 100644 --- a/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java +++ b/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java @@ -4,6 +4,7 @@ import java.nio.ByteBuffer; import java.util.Locale; import java.util.concurrent.locks.LockSupport; +import org.jcodec.codecs.h264.H264Utils; import org.jcodec.codecs.h264.io.model.SeqParameterSet; import org.jcodec.codecs.h264.io.model.VUIParameters; @@ -490,7 +491,9 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer { // Skip to the start of the NALU data spsBuf.position(header.offset+5); - SeqParameterSet sps = SeqParameterSet.read(spsBuf); + // The H264Utils.readSPS function safely handles + // Annex B NALUs (including NALUs with escape sequences) + SeqParameterSet sps = H264Utils.readSPS(spsBuf); // Some decoders rely on H264 level to decide how many buffers are needed // Since we only need one frame buffered, we'll set the level as low as we can @@ -571,8 +574,10 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer { // Write the annex B header buf.put(header.data, header.offset, 5); - // Write the modified SPS to the input buffer - sps.write(buf); + // The H264Utils.writeSPS function safely handles + // Annex B NALUs (including NALUs with escape sequences) + ByteBuffer escapedNalu = H264Utils.writeSPS(sps, header.length); + buf.put(escapedNalu); queueInputBuffer(inputBufferIndex, 0, buf.position(), From 080dc01c215ca39ab2666afe156bd3a77986c717 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 26 Oct 2015 23:59:53 -0700 Subject: [PATCH 2/5] Use a reference resolution rather than the actual stream resolution when scaling mouse movement --- app/src/main/java/com/limelight/Game.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 4f1ef88d..0b9af64f 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -1,7 +1,6 @@ package com.limelight; -import com.limelight.LimelightBuildProps; import com.limelight.binding.PlatformBinding; import com.limelight.binding.input.ControllerHandler; import com.limelight.binding.input.KeyboardTranslator; @@ -64,6 +63,9 @@ public class Game extends Activity implements SurfaceHolder.Callback, private final TouchContext[] touchContextMap = new TouchContext[2]; private long threeFingerDownTime = 0; + private static final double REFERENCE_HORIZ_RES = 1280; + private static final double REFERENCE_VERT_RES = 720; + private static final int THREE_FINGER_TAP_THRESHOLD = 300; private ControllerHandler controllerHandler; @@ -216,8 +218,8 @@ public class Game extends Activity implements SurfaceHolder.Callback, // Initialize touch contexts for (int i = 0; i < touchContextMap.length; i++) { touchContextMap[i] = new TouchContext(conn, i, - ((double)prefConfig.width / (double)screenSize.x), - ((double)prefConfig.height / (double)screenSize.y)); + (REFERENCE_HORIZ_RES / (double)screenSize.x), + (REFERENCE_VERT_RES / (double)screenSize.y)); } if (LimelightBuildProps.ROOT_BUILD) { @@ -681,8 +683,8 @@ public class Game extends Activity implements SurfaceHolder.Callback, // Scale the deltas if the device resolution is different // than the stream resolution - deltaX = (int)Math.round((double)deltaX * ((double)prefConfig.width / (double)screenSize.x)); - deltaY = (int)Math.round((double)deltaY * ((double)prefConfig.height / (double)screenSize.y)); + deltaX = (int)Math.round((double)deltaX * (REFERENCE_HORIZ_RES / (double)screenSize.x)); + deltaY = (int)Math.round((double)deltaY * (REFERENCE_VERT_RES / (double)screenSize.y)); conn.sendMouseMove((short)deltaX, (short)deltaY); } From 4c82da1f5c3305deb903f4f7a62660476c2b8460 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 28 Oct 2015 00:42:24 -0700 Subject: [PATCH 3/5] Update common with image quality improvements --- app/libs/limelight-common.jar | Bin 1016465 -> 1017393 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/app/libs/limelight-common.jar b/app/libs/limelight-common.jar index d00cd7214135a67dd1007daea999ce3c522eb4e6..6942d790b8ff609a3f70774fda83973424d2d555 100644 GIT binary patch delta 18052 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 UF>Otop5MeT!}c$YpMik^05%?)@Bjb+ delta 17105 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 Ti6&3yZ{wF?i%aHbU|;|M`gE%_ From 54eaee3f7902a2dfca84ce467d184034accafc1c Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 28 Oct 2015 01:15:09 -0700 Subject: [PATCH 4/5] Use a lock to prevent serverinfo polling on a machine while applist is pending --- .../computers/ComputerManagerService.java | 61 ++++++++++++++----- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/limelight/computers/ComputerManagerService.java b/app/src/main/java/com/limelight/computers/ComputerManagerService.java index 549d0dd8..fb9aaef5 100644 --- a/app/src/main/java/com/limelight/computers/ComputerManagerService.java +++ b/app/src/main/java/com/limelight/computers/ComputerManagerService.java @@ -119,7 +119,7 @@ public class ComputerManagerService extends Service { return true; } - private Thread createPollingThread(final ComputerDetails details) { + private Thread createPollingThread(final PollingTuple tuple) { Thread t = new Thread() { @Override public void run() { @@ -127,13 +127,15 @@ public class ComputerManagerService extends Service { int offlineCount = 0; while (!isInterrupted() && pollingActive) { try { - // Check if this poll has modified the details - if (!runPoll(details, false, offlineCount)) { - LimeLog.warning(details.name + " is offline (try " + offlineCount + ")"); - offlineCount++; - } - else { - offlineCount = 0; + // Only allow one request to the machine at a time + synchronized (tuple.networkLock) { + // Check if this poll has modified the details + if (!runPoll(tuple.computer, false, offlineCount)) { + LimeLog.warning(tuple.computer.name + " is offline (try " + offlineCount + ")"); + offlineCount++; + } else { + offlineCount = 0; + } } // Wait until the next polling interval @@ -144,7 +146,7 @@ public class ComputerManagerService extends Service { } } }; - t.setName("Polling thread for "+details.localIp.getHostAddress()); + t.setName("Polling thread for " + tuple.computer.localIp.getHostAddress()); return t; } @@ -166,7 +168,7 @@ public class ComputerManagerService extends Service { // Report this computer initially listener.notifyComputerUpdated(tuple.computer); - tuple.thread = createPollingThread(tuple.computer); + tuple.thread = createPollingThread(tuple); tuple.thread.start(); } } @@ -283,7 +285,7 @@ public class ComputerManagerService extends Service { // Start a polling thread if polling is active if (pollingActive && tuple.thread == null) { - tuple.thread = createPollingThread(details); + tuple.thread = createPollingThread(tuple); tuple.thread.start(); } @@ -293,7 +295,10 @@ public class ComputerManagerService extends Service { } // If we got here, we didn't find an entry - PollingTuple tuple = new PollingTuple(details, pollingActive ? createPollingThread(details) : null); + PollingTuple tuple = new PollingTuple(details, null); + if (pollingActive) { + tuple.thread = createPollingThread(tuple); + } pollingTuples.add(tuple); if (tuple.thread != null) { tuple.thread.start(); @@ -630,6 +635,18 @@ public class ComputerManagerService extends Service { return thread != null && !thread.isInterrupted(); } + private PollingTuple getPollingTuple(ComputerDetails details) { + synchronized (pollingTuples) { + for (PollingTuple tuple : pollingTuples) { + if (details.uuid.equals(tuple.computer.uuid)) { + return tuple; + } + } + } + + return null; + } + public void start() { thread = new Thread() { @Override @@ -660,9 +677,23 @@ public class ComputerManagerService extends Service { NvHTTP http = new NvHTTP(selectedAddr, idManager.getUniqueId(), null, PlatformBinding.getCryptoProvider(ComputerManagerService.this)); + PollingTuple tuple = getPollingTuple(computer); + try { - // Query the app list from the server - String appList = http.getAppListRaw(); + String appList; + if (tuple != null) { + // If we're polling this machine too, grab the network lock + // while doing the app list request to prevent other requests + // from being issued in the meantime. + synchronized (tuple.networkLock) { + appList = http.getAppListRaw(); + } + } + else { + // No polling is happening now, so we just call it directly + appList = http.getAppListRaw(); + } + List list = NvHTTP.getAppListByReader(new StringReader(appList)); if (appList != null && !appList.isEmpty() && !list.isEmpty()) { // Open the cache file @@ -718,10 +749,12 @@ public class ComputerManagerService extends Service { class PollingTuple { public Thread thread; public final ComputerDetails computer; + public final Object networkLock; public PollingTuple(ComputerDetails computer, Thread thread) { this.computer = computer; this.thread = thread; + this.networkLock = new Object(); } } From 5ef20aba2139bb3cee19e44cd5f953e32a20f1c8 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 28 Oct 2015 01:36:35 -0700 Subject: [PATCH 5/5] Decrease polling period and increase polls before declaring the machine offline. Try requesting the app list again every 2 seconds if the app list has not been received yet. --- .../computers/ComputerManagerService.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/limelight/computers/ComputerManagerService.java b/app/src/main/java/com/limelight/computers/ComputerManagerService.java index fb9aaef5..0ffd1a62 100644 --- a/app/src/main/java/com/limelight/computers/ComputerManagerService.java +++ b/app/src/main/java/com/limelight/computers/ComputerManagerService.java @@ -31,11 +31,12 @@ import android.os.IBinder; import org.xmlpull.v1.XmlPullParserException; public class ComputerManagerService extends Service { - private static final int SERVERINFO_POLLING_PERIOD_MS = 3000; + private static final int SERVERINFO_POLLING_PERIOD_MS = 1500; private static final int APPLIST_POLLING_PERIOD_MS = 30000; + private static final int APPLIST_FAILED_POLLING_RETRY_MS = 2000; private static final int MDNS_QUERY_PERIOD_MS = 1000; private static final int FAST_POLL_TIMEOUT = 500; - private static final int OFFLINE_POLL_TRIES = 3; + private static final int OFFLINE_POLL_TRIES = 5; private final ComputerManagerBinder binder = new ComputerManagerBinder(); @@ -139,7 +140,7 @@ public class ComputerManagerService extends Service { } // Wait until the next polling interval - Thread.sleep(SERVERINFO_POLLING_PERIOD_MS / ((offlineCount > 0) ? 2 : 1)); + Thread.sleep(SERVERINFO_POLLING_PERIOD_MS); } catch (InterruptedException e) { break; } @@ -612,6 +613,7 @@ public class ComputerManagerService extends Service { private Thread thread; private final ComputerDetails computer; private final Object pollEvent = new Object(); + private boolean receivedAppList = false; public ApplistPoller(ComputerDetails computer) { this.computer = computer; @@ -626,7 +628,15 @@ public class ComputerManagerService extends Service { private boolean waitPollingDelay() { try { synchronized (pollEvent) { - pollEvent.wait(APPLIST_POLLING_PERIOD_MS); + if (receivedAppList) { + // If we've already reported an app list successfully, + // wait the full polling period + pollEvent.wait(APPLIST_POLLING_PERIOD_MS); + } + else { + // If we've failed to get an app list so far, retry much earlier + pollEvent.wait(APPLIST_FAILED_POLLING_RETRY_MS); + } } } catch (InterruptedException e) { return false; @@ -713,6 +723,7 @@ public class ComputerManagerService extends Service { // Update the computer computer.rawAppList = appList; + receivedAppList = true; // Notify that the app list has been updated // and ensure that the thread is still active