Merge branch 'master' into root

Conflicts:
	libs/limelight-common.jar
This commit is contained in:
Cameron Gutman 2014-10-10 22:46:25 -07:00
commit f07e927103
9 changed files with 80 additions and 157 deletions

Binary file not shown.

View File

@ -23,15 +23,16 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.Locale;
import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder; import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle; import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509v3CertificateBuilder; import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMWriter; import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
@ -152,7 +153,8 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
nameBuilder.addRDN(BCStyle.CN, "NVIDIA GameStream Client"); nameBuilder.addRDN(BCStyle.CN, "NVIDIA GameStream Client");
X500Name name = nameBuilder.build(); X500Name name = nameBuilder.build();
X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(name, serial, now, expirationDate, name, keyPair.getPublic()); X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(name, serial, now, expirationDate, Locale.ENGLISH, name,
SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()));
try { try {
ContentSigner sigGen = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BouncyCastleProvider.PROVIDER_NAME).build(keyPair.getPrivate()); ContentSigner sigGen = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BouncyCastleProvider.PROVIDER_NAME).build(keyPair.getPrivate());
@ -179,7 +181,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
// Write the certificate in OpenSSL PEM format (important for the server) // Write the certificate in OpenSSL PEM format (important for the server)
StringWriter strWriter = new StringWriter(); StringWriter strWriter = new StringWriter();
PEMWriter pemWriter = new PEMWriter(strWriter); JcaPEMWriter pemWriter = new JcaPEMWriter(strWriter);
pemWriter.writeObject(cert); pemWriter.writeObject(cert);
pemWriter.close(); pemWriter.close();

View File

@ -3,6 +3,7 @@ package com.limelight.binding.input.evdev;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Locale;
import com.limelight.LimeLog; import com.limelight.LimeLog;
@ -20,7 +21,7 @@ public class EvdevReader {
OutputStream stdin = p.getOutputStream(); OutputStream stdin = p.getOutputStream();
for (String file : files) { for (String file : files) {
stdin.write(String.format("chmod %o %s\n", octalPermissions, file).getBytes("UTF-8")); stdin.write(String.format((Locale)null, "chmod %o %s\n", octalPermissions, file).getBytes("UTF-8"));
} }
stdin.write("exit\n".getBytes("UTF-8")); stdin.write("exit\n".getBytes("UTF-8"));
stdin.flush(); stdin.flush();

View File

@ -3,6 +3,7 @@ package com.limelight.binding.video;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.LockSupport;
import org.jcodec.codecs.h264.io.model.SeqParameterSet; import org.jcodec.codecs.h264.io.model.SeqParameterSet;
@ -53,9 +54,6 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
static { static {
preferredDecoders = new LinkedList<String>(); preferredDecoders = new LinkedList<String>();
// This is the most reliable of Samsung's decoders
preferredDecoders.add("OMX.SEC.AVC.Decoder");
} }
static { static {
@ -317,21 +315,62 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
@Override @Override
public void run() { public void run() {
BufferInfo info = new BufferInfo(); BufferInfo info = new BufferInfo();
DecodeUnit du; DecodeUnit du = null;
int inputIndex = -1;
while (!isInterrupted()) while (!isInterrupted())
{ {
// In order to get as much data to the decoder as early as possible,
// try to submit up to 5 decode units at once without blocking.
if (inputIndex == -1 && du == null) {
for (int i = 0; i < 5; i++) {
inputIndex = videoDecoder.dequeueInputBuffer(0);
du = depacketizer.pollNextDecodeUnit(); du = depacketizer.pollNextDecodeUnit();
if (du != null) {
if (!submitDecodeUnit(du)) { // Stop if we can't get a DU or input buffer
// Thread was interrupted if (du == null || inputIndex == -1) {
depacketizer.freeDecodeUnit(du); break;
return;
} }
else {
depacketizer.freeDecodeUnit(du); submitDecodeUnit(du, inputIndex);
du = null;
inputIndex = -1;
} }
} }
// Grab an input buffer if we don't have one already.
// This way we can have one ready hopefully by the time
// the depacketizer is done with this frame. It's important
// that this can timeout because it's possible that we could exhaust
// the decoder's input buffers and deadlocks because aren't pulling
// frames out of the other end.
if (inputIndex == -1) {
try {
// If we've got a DU waiting to be given to the decoder,
// wait a full 3 ms for an input buffer. Otherwise
// just see if we can get one immediately.
inputIndex = videoDecoder.dequeueInputBuffer(du != null ? 3000 : 0);
} catch (Exception e) {
throw new RendererException(MediaCodecDecoderRenderer.this, e);
}
}
// Grab a decode unit if we don't have one already
if (du == null) {
du = depacketizer.pollNextDecodeUnit();
}
// If we've got both a decode unit and an input buffer, we'll
// submit now. Otherwise, we wait until we have one.
if (du != null && inputIndex >= 0) {
submitDecodeUnit(du, inputIndex);
// DU and input buffer have both been consumed
du = null;
inputIndex = -1;
}
// Try to output a frame
try { try {
int outIndex = videoDecoder.dequeueOutputBuffer(info, 0); int outIndex = videoDecoder.dequeueOutputBuffer(info, 0);
@ -358,7 +397,11 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
} else { } else {
switch (outIndex) { switch (outIndex) {
case MediaCodec.INFO_TRY_AGAIN_LATER: case MediaCodec.INFO_TRY_AGAIN_LATER:
// Getting an input buffer may already block
// so don't park if we still need to do that
if (inputIndex >= 0) {
LockSupport.parkNanos(1); LockSupport.parkNanos(1);
}
break; break;
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
LimeLog.info("Output buffers changed"); LimeLog.info("Output buffers changed");
@ -414,22 +457,8 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
} }
} }
private boolean submitDecodeUnit(DecodeUnit decodeUnit) { private void submitDecodeUnit(DecodeUnit decodeUnit, int inputBufferIndex) {
int inputIndex; ByteBuffer buf = videoDecoderInputBuffers[inputBufferIndex];
do {
if (Thread.interrupted()) {
return false;
}
try {
inputIndex = videoDecoder.dequeueInputBuffer(100000);
} catch (Exception e) {
throw new RendererException(this, e);
}
} while (inputIndex < 0);
ByteBuffer buf = videoDecoderInputBuffers[inputIndex];
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
long delta = currentTime-decodeUnit.getReceiveTimestamp(); long delta = currentTime-decodeUnit.getReceiveTimestamp();
@ -492,13 +521,15 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
sps.write(buf); sps.write(buf);
try { try {
videoDecoder.queueInputBuffer(inputIndex, videoDecoder.queueInputBuffer(inputBufferIndex,
0, buf.position(), 0, buf.position(),
currentTime * 1000, codecFlags); currentTime * 1000, codecFlags);
} catch (Exception e) { } catch (Exception e) {
throw new RendererException(this, e, buf, codecFlags); throw new RendererException(this, e, buf, codecFlags);
} }
return true;
depacketizer.freeDecodeUnit(decodeUnit);
return;
} }
} else if (header.data[header.offset+4] == 0x68) { } else if (header.data[header.offset+4] == 0x68) {
numPpsIn++; numPpsIn++;
@ -512,14 +543,15 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
} }
try { try {
videoDecoder.queueInputBuffer(inputIndex, videoDecoder.queueInputBuffer(inputBufferIndex,
0, decodeUnit.getDataLength(), 0, decodeUnit.getDataLength(),
currentTime * 1000, codecFlags); currentTime * 1000, codecFlags);
} catch (Exception e) { } catch (Exception e) {
throw new RendererException(this, e, buf, codecFlags); throw new RendererException(this, e, buf, codecFlags);
} }
return true; depacketizer.freeDecodeUnit(decodeUnit);
return;
} }
@Override @Override
@ -575,7 +607,7 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
str += "Current buffer: "; str += "Current buffer: ";
currentBuffer.flip(); currentBuffer.flip();
while (currentBuffer.hasRemaining() && currentBuffer.position() < 10) { while (currentBuffer.hasRemaining() && currentBuffer.position() < 10) {
str += String.format("%02x ", currentBuffer.get()); str += String.format((Locale)null, "%02x ", currentBuffer.get());
} }
str += "\n"; str += "\n";
str += "Buffer codec flags: "+currentCodecFlags+"\n"; str += "Buffer codec flags: "+currentCodecFlags+"\n";

View File

@ -4,6 +4,7 @@ import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.UUID; import java.util.UUID;
import com.limelight.LimeLog; import com.limelight.LimeLog;
@ -44,7 +45,7 @@ public class ComputerDatabaseManager {
private void initializeDb() { private void initializeDb() {
// Create tables if they aren't already there // Create tables if they aren't already there
computerDb.execSQL(String.format("CREATE TABLE IF NOT EXISTS %s(%s TEXT PRIMARY KEY," + computerDb.execSQL(String.format((Locale)null, "CREATE TABLE IF NOT EXISTS %s(%s TEXT PRIMARY KEY," +
" %s TEXT NOT NULL, %s TEXT NOT NULL, %s TEXT NOT NULL, %s TEXT NOT NULL)", " %s TEXT NOT NULL, %s TEXT NOT NULL, %s TEXT NOT NULL, %s TEXT NOT NULL)",
COMPUTER_TABLE_NAME, COMPUTER_TABLE_NAME,
COMPUTER_NAME_COLUMN_NAME, COMPUTER_UUID_COLUMN_NAME, LOCAL_IP_COLUMN_NAME, COMPUTER_NAME_COLUMN_NAME, COMPUTER_UUID_COLUMN_NAME, LOCAL_IP_COLUMN_NAME,

View File

@ -1,11 +1,6 @@
package com.limelight.computers; package com.limelight.computers;
import java.net.Inet4Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@ -24,11 +19,8 @@ import com.limelight.nvstream.mdns.MdnsDiscoveryListener;
import android.app.Service; import android.app.Service;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
@ -234,93 +226,6 @@ public class ComputerManagerService extends Service {
}; };
} }
private int getActiveNetworkType() {
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo();
if (activeNetworkInfo == null) {
return -1;
}
return activeNetworkInfo.getType();
}
private InterfaceAddress getActiveInterfaceAddress() {
String matchingPrefix;
switch (getActiveNetworkType())
{
case ConnectivityManager.TYPE_ETHERNET:
matchingPrefix = "eth";
break;
case ConnectivityManager.TYPE_WIFI:
matchingPrefix = "wlan";
break;
default:
// Must be on Ethernet or Wifi to consider that we can send large packets
return null;
}
// Try to find the interface that corresponds to the active network
try {
Enumeration<NetworkInterface> ifaceList = NetworkInterface.getNetworkInterfaces();
while (ifaceList.hasMoreElements()) {
NetworkInterface iface = ifaceList.nextElement();
// Look for an interface that matches the prefix we expect
if (iface.isUp() && iface.getName().startsWith(matchingPrefix)) {
// Find the IPv4 address for the interface
for (InterfaceAddress addr : iface.getInterfaceAddresses()) {
if (!(addr.getAddress() instanceof Inet4Address)) {
// Skip non-IPv4 addresses
continue;
}
// Found the right address on the right interface
return addr;
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
// We didn't find the interface or something else went wrong
return null;
}
private boolean isOnSameSubnet(InetAddress targetAddress, InetAddress localAddress, short networkPrefixLength) {
byte[] targetBytes = targetAddress.getAddress();
byte[] localBytes = localAddress.getAddress();
for (int byteIndex = 0; networkPrefixLength > 0; byteIndex++) {
byte target = targetBytes[byteIndex];
byte local = localBytes[byteIndex];
if (networkPrefixLength >= 8) {
// Do a full byte comparison
if (target != local) {
return false;
}
networkPrefixLength -= 8;
}
else {
target &= (byte)(0xFF << (8 - networkPrefixLength));
local &= (byte)(0xFF << (8 - networkPrefixLength));
// Do a masked comparison
if (target != local) {
return false;
}
networkPrefixLength = 0;
}
}
return true;
}
private ComputerDetails tryPollIp(InetAddress ipAddr) { private ComputerDetails tryPollIp(InetAddress ipAddr) {
try { try {
NvHTTP http = new NvHTTP(ipAddr, idManager.getUniqueId(), NvHTTP http = new NvHTTP(ipAddr, idManager.getUniqueId(),
@ -373,27 +278,8 @@ public class ComputerManagerService extends Service {
} }
private boolean doPollMachine(ComputerDetails details) { private boolean doPollMachine(ComputerDetails details) {
// Get the network type
int networkType = getActiveNetworkType();
switch (networkType) {
// We'll check local first on these if we find
// we're on the same subnet
case ConnectivityManager.TYPE_ETHERNET:
case ConnectivityManager.TYPE_WIFI:
InterfaceAddress ifaceAddr = getActiveInterfaceAddress();
if (ifaceAddr != null) {
if (isOnSameSubnet(details.localIp, ifaceAddr.getAddress(), ifaceAddr.getNetworkPrefixLength())) {
// It's on the same subnet, so poll local first
LimeLog.info("Machine looks local; trying local IP first");
return pollComputer(details, true); return pollComputer(details, true);
} }
}
// Fall through to remote first
default:
LimeLog.info("Machine looks remote; trying remote IP first");
return pollComputer(details, false);
}
}
private Runnable getPollingRunnable(final ComputerDetails details) { private Runnable getPollingRunnable(final ComputerDetails details) {
return new Runnable() { return new Runnable() {

View File

@ -4,6 +4,7 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.util.Locale;
import java.util.Random; import java.util.Random;
import com.limelight.LimeLog; import com.limelight.LimeLog;
@ -61,7 +62,7 @@ public class IdentityManager {
private static String generateNewUniqueId(Context c) { private static String generateNewUniqueId(Context c) {
// Generate a new UID hex string // Generate a new UID hex string
LimeLog.info("Generating new UID"); LimeLog.info("Generating new UID");
String uidStr = String.format("%016x", new Random().nextLong()); String uidStr = String.format((Locale)null, "%016x", new Random().nextLong());
OutputStreamWriter writer = null; OutputStreamWriter writer = null;
try { try {