diff --git a/libs/limelight-common.jar b/libs/limelight-common.jar index dafe56ad..78eb0bd4 100644 Binary files a/libs/limelight-common.jar and b/libs/limelight-common.jar differ diff --git a/src/com/limelight/Game.java b/src/com/limelight/Game.java index 61aafba6..65d82a24 100644 --- a/src/com/limelight/Game.java +++ b/src/com/limelight/Game.java @@ -287,7 +287,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, Dialog.closeDialogs(); displayedFailureDialog = true; - conn.stop(); + stopConnection(); int averageEndToEndLat = decoderRenderer.getAverageEndToEndLatency(); int averageDecoderLat = decoderRenderer.getAverageDecoderLatency(); @@ -305,10 +305,6 @@ public class Game extends Activity implements SurfaceHolder.Callback, if (message != null) { Toast.makeText(this, message, Toast.LENGTH_LONG).show(); } - - if (evdevWatcher != null) { - evdevWatcher.shutdown(); - } finish(); } @@ -573,6 +569,19 @@ public class Game extends Activity implements SurfaceHolder.Callback, @Override public void stageComplete(Stage stage) { } + + private void stopConnection() { + if (connecting || connected) { + conn.stop(); + connecting = connected = false; + } + + // Close the Evdev watcher to allow use of captured input devices + if (evdevWatcher != null) { + evdevWatcher.shutdown(); + evdevWatcher = null; + } + } @Override public void stageFailed(Stage stage) { @@ -584,8 +593,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, if (!displayedFailureDialog) { displayedFailureDialog = true; Dialog.displayDialog(this, "Connection Error", "Starting "+stage.getName()+" failed", true); - conn.stop(); - connecting = false; + stopConnection(); } } @@ -594,9 +602,9 @@ public class Game extends Activity implements SurfaceHolder.Callback, if (!displayedFailureDialog) { displayedFailureDialog = true; e.printStackTrace(); + Dialog.displayDialog(this, "Connection Terminated", "The connection failed unexpectedly", true); - conn.stop(); - connected = false; + stopConnection(); } } @@ -658,8 +666,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, @Override public void surfaceDestroyed(SurfaceHolder holder) { if (connected) { - conn.stop(); - connected = false; + stopConnection(); } } diff --git a/src/com/limelight/PcView.java b/src/com/limelight/PcView.java index e277afcd..a2ce8171 100644 --- a/src/com/limelight/PcView.java +++ b/src/com/limelight/PcView.java @@ -6,6 +6,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import com.limelight.binding.PlatformBinding; +import com.limelight.binding.crypto.AndroidCryptoProvider; import com.limelight.computers.ComputerManagerListener; import com.limelight.computers.ComputerManagerService; import com.limelight.nvstream.http.ComputerDetails; @@ -60,6 +61,9 @@ public class PcView extends Activity { // Start updates startComputerUpdates(); + + // Force a keypair to be generated early to avoid discovery delays + new AndroidCryptoProvider(PcView.this).getClientCertificate(); } }.start(); } diff --git a/src/com/limelight/binding/crypto/AndroidCryptoProvider.java b/src/com/limelight/binding/crypto/AndroidCryptoProvider.java index 4df63dca..242749f3 100644 --- a/src/com/limelight/binding/crypto/AndroidCryptoProvider.java +++ b/src/com/limelight/binding/crypto/AndroidCryptoProvider.java @@ -51,6 +51,8 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider { private RSAPrivateKey key; private byte[] pemCertBytes; + private static Object globalCryptoLock = new Object(); + static { // Install the Bouncy Castle provider Security.addProvider(new BouncyCastleProvider()); @@ -208,7 +210,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider { public X509Certificate getClientCertificate() { // Use a lock here to ensure only one guy will be generating or loading // the certificate and key at a time - synchronized (this) { + synchronized (globalCryptoLock) { // Return a loaded cert if we have one if (cert != null) { return cert; @@ -235,7 +237,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider { public RSAPrivateKey getClientPrivateKey() { // Use a lock here to ensure only one guy will be generating or loading // the certificate and key at a time - synchronized (this) { + synchronized (globalCryptoLock) { // Return a loaded key if we have one if (key != null) { return key; @@ -260,7 +262,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider { } public byte[] getPemEncodedClientCertificate() { - synchronized (this) { + synchronized (globalCryptoLock) { // Call our helper function to do the cert loading/generation for us getClientCertificate(); diff --git a/src/com/limelight/binding/video/AndroidCpuDecoderRenderer.java b/src/com/limelight/binding/video/AndroidCpuDecoderRenderer.java index 7521ad0c..498bb114 100644 --- a/src/com/limelight/binding/video/AndroidCpuDecoderRenderer.java +++ b/src/com/limelight/binding/video/AndroidCpuDecoderRenderer.java @@ -38,6 +38,7 @@ public class AndroidCpuDecoderRenderer implements VideoDecoderRenderer { private int cpuCount = Runtime.getRuntime().availableProcessors(); + @SuppressWarnings("unused") private int findOptimalPerformanceLevel() { StringBuilder cpuInfo = new StringBuilder(); BufferedReader br = null; @@ -93,7 +94,7 @@ public class AndroidCpuDecoderRenderer implements VideoDecoderRenderer { public boolean setup(int width, int height, int redrawRate, Object renderTarget, int drFlags) { this.targetFps = redrawRate; - int perfLevel = findOptimalPerformanceLevel(); + int perfLevel = LOW_PERF; //findOptimalPerformanceLevel(); int threadCount; int avcFlags = 0; diff --git a/src/com/limelight/computers/ComputerManagerService.java b/src/com/limelight/computers/ComputerManagerService.java index c82596c0..456d32df 100644 --- a/src/com/limelight/computers/ComputerManagerService.java +++ b/src/com/limelight/computers/ComputerManagerService.java @@ -342,7 +342,7 @@ public class ComputerManagerService extends Service { polledDetails = tryPollIp(details.remoteIp); } - if (polledDetails == null) { + if (polledDetails == null && !details.localIp.equals(details.remoteIp)) { // Failed, so let's try the fallback if (!localFirst) { polledDetails = tryPollIp(details.localIp); @@ -356,7 +356,8 @@ public class ComputerManagerService extends Service { polledDetails.reachability = !localFirst ? ComputerDetails.Reachability.LOCAL : ComputerDetails.Reachability.REMOTE; } - } else { + } + else if (polledDetails != null) { polledDetails.reachability = localFirst ? ComputerDetails.Reachability.LOCAL : ComputerDetails.Reachability.REMOTE; } @@ -401,7 +402,12 @@ public class ComputerManagerService extends Service { public void run() { boolean newPc = (details.name == null); - if (stopped) { + // This is called from addComputerManually() where we don't + // want to block the initial poll if polling is disabled, so + // we explicitly let this through if we've never seen this + // PC before. This path won't be triggered normally when polling + // is disabled because the mDNS discovery is stopped. + if (stopped && !newPc) { return; }