mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-20 19:42:45 +00:00
Wake on LAN support. Many fixes for Limelight Android 2.5.
This commit is contained in:
parent
a4dceb0b74
commit
894110ba08
@ -35,6 +35,7 @@ public class NvConnection {
|
||||
private NvConnectionListener listener;
|
||||
private StreamConfiguration config;
|
||||
private LimelightCryptoProvider cryptoProvider;
|
||||
private String uniqueId;
|
||||
|
||||
private InetAddress hostAddr;
|
||||
private ControlStream controlStream;
|
||||
@ -52,12 +53,13 @@ public class NvConnection {
|
||||
|
||||
private ThreadPoolExecutor threadPool;
|
||||
|
||||
public NvConnection(String host, NvConnectionListener listener, StreamConfiguration config, LimelightCryptoProvider cryptoProvider)
|
||||
public NvConnection(String host, String uniqueId, NvConnectionListener listener, StreamConfiguration config, LimelightCryptoProvider cryptoProvider)
|
||||
{
|
||||
this.host = host;
|
||||
this.listener = listener;
|
||||
this.config = config;
|
||||
this.cryptoProvider = cryptoProvider;
|
||||
this.uniqueId = uniqueId;
|
||||
|
||||
try {
|
||||
// This is unique per connection
|
||||
@ -162,7 +164,7 @@ public class NvConnection {
|
||||
|
||||
private boolean startApp() throws XmlPullParserException, IOException
|
||||
{
|
||||
NvHTTP h = new NvHTTP(hostAddr, getMacAddressString(), localDeviceName, cryptoProvider);
|
||||
NvHTTP h = new NvHTTP(hostAddr, uniqueId, localDeviceName, cryptoProvider);
|
||||
|
||||
if (h.getServerVersion().startsWith("1.")) {
|
||||
listener.displayMessage("Limelight now requires GeForce Experience 2.0.1 or later. Please upgrade GFE on your PC and try again.");
|
||||
|
@ -0,0 +1,68 @@
|
||||
package com.limelight.nvstream.http;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
public class ComputerDetails {
|
||||
public enum State {
|
||||
ONLINE, OFFLINE, UNKNOWN
|
||||
}
|
||||
public enum Reachability {
|
||||
LOCAL, REMOTE, OFFLINE, UNKNOWN
|
||||
}
|
||||
|
||||
public State state;
|
||||
public Reachability reachability;
|
||||
public String name;
|
||||
public UUID uuid;
|
||||
public InetAddress localIp;
|
||||
public InetAddress remoteIp;
|
||||
public PairingManager.PairState pairState;
|
||||
public String macAddress;
|
||||
public int runningGameId;
|
||||
|
||||
public void update(ComputerDetails details) {
|
||||
this.state = details.state;
|
||||
this.name = details.name;
|
||||
this.uuid = details.uuid;
|
||||
this.localIp = details.localIp;
|
||||
this.remoteIp = details.remoteIp;
|
||||
this.macAddress = details.macAddress;
|
||||
this.pairState = details.pairState;
|
||||
this.runningGameId = details.runningGameId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof ComputerDetails) {
|
||||
ComputerDetails other = (ComputerDetails)o;
|
||||
|
||||
// Use UUIDs if they both have them
|
||||
if (other.uuid != null && this.uuid != null)
|
||||
{
|
||||
return other.uuid.equals(this.uuid);
|
||||
}
|
||||
|
||||
// Otherwise use local IP
|
||||
return other.localIp.equals(this.localIp);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append("State: ").append(state).append("\n");
|
||||
str.append("Reachability: ").append(reachability).append("\n");
|
||||
str.append("Name: ").append(name).append("\n");
|
||||
str.append("UUID: ").append(uuid).append("\n");
|
||||
str.append("Local IP: ").append(localIp).append("\n");
|
||||
str.append("Remote IP: ").append(remoteIp).append("\n");
|
||||
str.append("MAC Address: ").append(macAddress).append("\n");
|
||||
str.append("Pair State: ").append(pairState).append("\n");
|
||||
str.append("Running Game ID: ").append(runningGameId).append("\n");
|
||||
return str.toString();
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ import java.net.URLConnection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Scanner;
|
||||
import java.util.Stack;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
@ -20,6 +21,8 @@ import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlPullParserFactory;
|
||||
|
||||
import com.limelight.nvstream.http.PairingManager.PairState;
|
||||
|
||||
|
||||
public class NvHTTP {
|
||||
private String uniqueId;
|
||||
@ -27,7 +30,7 @@ public class NvHTTP {
|
||||
private LimelightCryptoProvider cryptoProvider;
|
||||
|
||||
public static final int PORT = 47984;
|
||||
public static final int CONNECTION_TIMEOUT = 5000;
|
||||
public static final int CONNECTION_TIMEOUT = 2000;
|
||||
|
||||
private final boolean verbose = false;
|
||||
|
||||
@ -97,6 +100,35 @@ public class NvHTTP {
|
||||
}
|
||||
}
|
||||
|
||||
public ComputerDetails getComputerDetails() throws MalformedURLException, IOException, XmlPullParserException {
|
||||
ComputerDetails details = new ComputerDetails();
|
||||
String serverInfo = openHttpConnectionToString(baseUrl + "/serverinfo?uniqueid=" + uniqueId);
|
||||
|
||||
details.name = getXmlString(serverInfo, "hostname");
|
||||
details.uuid = UUID.fromString(getXmlString(serverInfo, "uniqueid"));
|
||||
details.localIp = InetAddress.getByName(getXmlString(serverInfo, "LocalIP"));
|
||||
details.remoteIp = InetAddress.getByName(getXmlString(serverInfo, "ExternalIP"));
|
||||
details.macAddress = getXmlString(serverInfo, "mac");
|
||||
|
||||
try {
|
||||
details.pairState = Integer.parseInt(getXmlString(serverInfo, "PairStatus")) == 1 ?
|
||||
PairState.PAIRED : PairState.NOT_PAIRED;
|
||||
} catch (NumberFormatException e) {
|
||||
details.pairState = PairState.FAILED;
|
||||
}
|
||||
|
||||
try {
|
||||
details.runningGameId = Integer.parseInt(getXmlString(serverInfo, "currentgame"));
|
||||
} catch (NumberFormatException e) {
|
||||
details.runningGameId = 0;
|
||||
}
|
||||
|
||||
// We could reach it so it's online
|
||||
details.state = ComputerDetails.State.ONLINE;
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
private InputStream openHttpConnection(String url) throws IOException {
|
||||
URLConnection conn = new URL(url).openConnection();
|
||||
if (verbose) {
|
||||
@ -201,6 +233,10 @@ public class NvHTTP {
|
||||
return appList;
|
||||
}
|
||||
|
||||
public void unpair() throws IOException {
|
||||
openHttpConnection(baseUrl + "/unpair?uniqueid=" + uniqueId);
|
||||
}
|
||||
|
||||
public int launchApp(int appId, int width, int height, int refreshRate, SecretKey inputKey) throws IOException, XmlPullParserException {
|
||||
InputStream in = openHttpConnection(baseUrl +
|
||||
"/launch?uniqueid=" + uniqueId +
|
||||
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@ -127,7 +128,6 @@ public class MdnsDiscoveryAgent {
|
||||
|
||||
private MdnsDiscoveryAgent(MdnsDiscoveryListener listener) {
|
||||
computers = new HashMap<InetAddress, MdnsComputer>();
|
||||
discoveryTimer = new Timer();
|
||||
pendingResolution = new ArrayList<String>();
|
||||
this.listener = listener;
|
||||
}
|
||||
@ -135,7 +135,7 @@ public class MdnsDiscoveryAgent {
|
||||
public static MdnsDiscoveryAgent createDiscoveryAgent(MdnsDiscoveryListener listener) throws IOException {
|
||||
MdnsDiscoveryAgent agent = new MdnsDiscoveryAgent(listener);
|
||||
|
||||
agent.resolver = JmDNS.create();
|
||||
agent.resolver = JmDNS.create(new InetSocketAddress(0).getAddress());
|
||||
|
||||
return agent;
|
||||
}
|
||||
@ -143,6 +143,7 @@ public class MdnsDiscoveryAgent {
|
||||
public void startDiscovery(final int discoveryIntervalMs) {
|
||||
resolver.addServiceListener(SERVICE_TYPE, nvstreamListener);
|
||||
|
||||
discoveryTimer = new Timer();
|
||||
discoveryTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -162,7 +163,10 @@ public class MdnsDiscoveryAgent {
|
||||
public void stopDiscovery() {
|
||||
resolver.removeServiceListener(SERVICE_TYPE, nvstreamListener);
|
||||
|
||||
if (discoveryTimer != null) {
|
||||
discoveryTimer.cancel();
|
||||
discoveryTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<MdnsComputer> getComputerSet() {
|
||||
|
@ -0,0 +1,72 @@
|
||||
package com.limelight.nvstream.wol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Scanner;
|
||||
|
||||
import com.limelight.nvstream.http.ComputerDetails;
|
||||
|
||||
public class WakeOnLanSender {
|
||||
private static final int[] PORTS_TO_TRY = new int[] {
|
||||
7, 9, // Standard WOL ports
|
||||
47998, 47999, 48000 // Ports opened by GFE
|
||||
};
|
||||
|
||||
public static void sendWolPacket(ComputerDetails computer) throws IOException {
|
||||
DatagramSocket sock = new DatagramSocket(0);
|
||||
|
||||
byte[] payload = createWolPayload(computer);
|
||||
// Try both remote and local addresses
|
||||
for (int i = 0; i < 2; i++) {
|
||||
InetAddress addr;
|
||||
if (i == 0) {
|
||||
addr = computer.localIp;
|
||||
}
|
||||
else {
|
||||
addr = computer.remoteIp;
|
||||
}
|
||||
|
||||
// Try all the ports for each address
|
||||
for (int port : PORTS_TO_TRY) {
|
||||
DatagramPacket dp = new DatagramPacket(payload, payload.length);
|
||||
dp.setAddress(addr);
|
||||
dp.setPort(port);
|
||||
sock.send(dp);
|
||||
}
|
||||
}
|
||||
|
||||
sock.close();
|
||||
}
|
||||
|
||||
private static byte[] macStringToBytes(String macAddress) {
|
||||
byte[] macBytes = new byte[6];
|
||||
@SuppressWarnings("resource")
|
||||
Scanner scan = new Scanner(macAddress).useDelimiter(":");
|
||||
for (int i = 0; i < macBytes.length && scan.hasNext(); i++) {
|
||||
macBytes[i] = (byte) Integer.parseInt(scan.next(), 16);
|
||||
}
|
||||
scan.close();
|
||||
return macBytes;
|
||||
}
|
||||
|
||||
private static byte[] createWolPayload(ComputerDetails computer) {
|
||||
byte[] payload = new byte[102];
|
||||
byte[] macAddress = macStringToBytes(computer.macAddress);
|
||||
int i;
|
||||
|
||||
// 6 bytes of FF
|
||||
for (i = 0; i < 6; i++) {
|
||||
payload[i] = (byte)0xFF;
|
||||
}
|
||||
|
||||
// 16 repetitions of the MAC address
|
||||
for (int j = 0; j < 16; j++) {
|
||||
System.arraycopy(macAddress, 0, payload, i, macAddress.length);
|
||||
i += macAddress.length;
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user