Compare commits

..
13 Commits
15 changed files with 63 additions and 45 deletions

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
#Moonlight #Moonlight
Moonlight is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield. [Moonlight](http://moonlight-stream.com) is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield.
We reverse engineered the Shield streaming software and created a version that can be run on any Android device. We reverse engineered the Shield streaming software and created a version that can be run on any Android device.
Moonlight will allow you to stream your full collection of games from your Windows PC to your Android device, Moonlight will allow you to stream your full collection of games from your Windows PC to your Android device,
+3 -3
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="moonlight-android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4"> <module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="moonlight-android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager"> <component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle"> <facet type="android-gradle" name="Android-Gradle">
<configuration> <configuration>
@@ -12,8 +12,9 @@
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" /> <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
<option name="ASSEMBLE_TASK_NAME" value="assembleNonRootDebug" /> <option name="ASSEMBLE_TASK_NAME" value="assembleNonRootDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileNonRootDebugSources" /> <option name="COMPILE_JAVA_TASK_NAME" value="compileNonRootDebugSources" />
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleNonRootDebugAndroidTest" />
<option name="SOURCE_GEN_TASK_NAME" value="generateNonRootDebugSources" /> <option name="SOURCE_GEN_TASK_NAME" value="generateNonRootDebugSources" />
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleNonRootDebugAndroidTest" />
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileNonRootDebugAndroidTestSources" />
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateNonRootDebugAndroidTestSources" /> <option name="TEST_SOURCE_GEN_TASK_NAME" value="generateNonRootDebugAndroidTestSources" />
<option name="ALLOW_USER_CONFIGURATION" value="false" /> <option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" /> <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
@@ -115,4 +116,3 @@
<orderEntry type="library" exported="" name="okio-1.2.0" level="project" /> <orderEntry type="library" exported="" name="okio-1.2.0" level="project" />
</component> </component>
</module> </module>
+2 -2
View File
@@ -11,8 +11,8 @@ android {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 22 targetSdkVersion 22
versionName "3.1.5" versionName "3.1.7"
versionCode = 60 versionCode = 62
} }
productFlavors { productFlavors {
Binary file not shown.
+5
View File
@@ -17,6 +17,10 @@
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
android:theme="@style/AppTheme" > android:theme="@style/AppTheme" >
<!-- Samsung multi-window support -->
<uses-library android:name="com.sec.android.app.multiwindow" android:required="false" />
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
<!-- Launcher for traditional devices --> <!-- Launcher for traditional devices -->
<activity <activity
android:name=".PcView" android:name=".PcView"
@@ -24,6 +28,7 @@
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.MULTIWINDOW_LAUNCHER" />
<category android:name="tv.ouya.intent.category.APP" /> <category android:name="tv.ouya.intent.category.APP" />
</intent-filter> </intent-filter>
</activity> </activity>
@@ -1,19 +1,14 @@
package com.limelight; package com.limelight;
import java.io.FileNotFoundException;
import java.io.StringReader; import java.io.StringReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.UUID; import java.util.UUID;
import com.limelight.binding.PlatformBinding;
import com.limelight.computers.ComputerManagerListener; import com.limelight.computers.ComputerManagerListener;
import com.limelight.computers.ComputerManagerService; import com.limelight.computers.ComputerManagerService;
import com.limelight.grid.AppGridAdapter; import com.limelight.grid.AppGridAdapter;
import com.limelight.nvstream.http.ComputerDetails; import com.limelight.nvstream.http.ComputerDetails;
import com.limelight.nvstream.http.GfeHttpResponseException;
import com.limelight.nvstream.http.NvApp; import com.limelight.nvstream.http.NvApp;
import com.limelight.nvstream.http.NvHTTP; import com.limelight.nvstream.http.NvHTTP;
import com.limelight.preferences.PreferenceConfiguration; import com.limelight.preferences.PreferenceConfiguration;
@@ -26,10 +21,8 @@ import com.limelight.utils.SpinnerDialog;
import com.limelight.utils.UiHelper; import com.limelight.utils.UiHelper;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog;
import android.app.Service; import android.app.Service;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.content.res.Configuration; import android.content.res.Configuration;
@@ -306,6 +306,10 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
else if (computer.reachability == ComputerDetails.Reachability.REMOTE) { else if (computer.reachability == ComputerDetails.Reachability.REMOTE) {
addr = computer.remoteIp; addr = computer.remoteIp;
} }
else {
LimeLog.warning("Unknown reachability - using local IP");
addr = computer.localIp;
}
httpConn = new NvHTTP(addr, httpConn = new NvHTTP(addr,
managerBinder.getUniqueId(), managerBinder.getUniqueId(),
@@ -431,6 +435,10 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
else if (computer.reachability == ComputerDetails.Reachability.REMOTE) { else if (computer.reachability == ComputerDetails.Reachability.REMOTE) {
addr = computer.remoteIp; addr = computer.remoteIp;
} }
else {
LimeLog.warning("Unknown reachability - using local IP");
addr = computer.localIp;
}
httpConn = new NvHTTP(addr, httpConn = new NvHTTP(addr,
managerBinder.getUniqueId(), managerBinder.getUniqueId(),
@@ -1,10 +1,8 @@
package com.limelight.binding.input; package com.limelight.binding.input;
import java.util.HashMap;
import java.util.Map;
import android.hardware.input.InputManager; import android.hardware.input.InputManager;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.SparseArray;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
@@ -31,7 +29,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
private final Vector2d inputVector = new Vector2d(); private final Vector2d inputVector = new Vector2d();
private final HashMap<String, ControllerContext> contexts = new HashMap<String, ControllerContext>(); private final SparseArray<ControllerContext> contexts = new SparseArray<ControllerContext>();
private final NvConnection conn; private final NvConnection conn;
private final double stickDeadzone; private final double stickDeadzone;
@@ -52,8 +50,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
deadzonePercentage = 10; deadzonePercentage = 10;
int[] ids = InputDevice.getDeviceIds(); int[] ids = InputDevice.getDeviceIds();
for (int i = 0; i < ids.length; i++) { for (int id : ids) {
InputDevice dev = InputDevice.getDevice(ids[i]); InputDevice dev = InputDevice.getDevice(id);
if ((dev.getSources() & InputDevice.SOURCE_JOYSTICK) != 0 || if ((dev.getSources() & InputDevice.SOURCE_JOYSTICK) != 0 ||
(dev.getSources() & InputDevice.SOURCE_GAMEPAD) != 0) { (dev.getSources() & InputDevice.SOURCE_GAMEPAD) != 0) {
// This looks like a gamepad, but we'll check X and Y to be sure // This looks like a gamepad, but we'll check X and Y to be sure
@@ -104,13 +102,11 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
@Override @Override
public void onInputDeviceRemoved(int deviceId) { public void onInputDeviceRemoved(int deviceId) {
for (Map.Entry<String, ControllerContext> device : contexts.entrySet()) { ControllerContext context = contexts.get(deviceId);
if (device.getValue().id == deviceId) { if (context != null) {
LimeLog.info("Removed controller: "+device.getValue().name); LimeLog.info("Removed controller: "+context.name+" ("+deviceId+")");
releaseControllerNumber(device.getValue()); releaseControllerNumber(context);
contexts.remove(device.getKey()); contexts.remove(deviceId);
return;
}
} }
} }
@@ -135,7 +131,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
return; return;
} }
LimeLog.info(context.name+" needs a controller number assigned"); LimeLog.info(context.name+" ("+context.id+") needs a controller number assigned");
if (context.name != null && context.name.contains("gpio-keys")) { if (context.name != null && context.name.contains("gpio-keys")) {
// This is the back button on Shield portable consoles // This is the back button on Shield portable consoles
LimeLog.info("Built-in buttons hardcoded as controller 0"); LimeLog.info("Built-in buttons hardcoded as controller 0");
@@ -308,6 +304,11 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
context.leftStickDeadzoneRadius = 0.07f; context.leftStickDeadzoneRadius = 0.07f;
context.rightStickDeadzoneRadius = 0.07f; context.rightStickDeadzoneRadius = 0.07f;
} }
// Samsung's face buttons appear as a non-virtual button so we'll classify them as remotes
// so the back button gets passed through to exit streaming
else if (devName.equals("sec_touchscreen")) {
context.isRemote = true;
}
} }
LimeLog.info("Analog stick deadzone: "+context.leftStickDeadzoneRadius+" "+context.rightStickDeadzoneRadius); LimeLog.info("Analog stick deadzone: "+context.leftStickDeadzoneRadius+" "+context.rightStickDeadzoneRadius);
@@ -322,17 +323,15 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
return defaultContext; return defaultContext;
} }
String descriptor = dev.getDescriptor();
// Return the existing context if it exists // Return the existing context if it exists
ControllerContext context = contexts.get(descriptor); ControllerContext context = contexts.get(dev.getId());
if (context != null) { if (context != null) {
return context; return context;
} }
// Otherwise create a new context // Otherwise create a new context
context = createContextForDevice(dev); context = createContextForDevice(dev);
contexts.put(descriptor, context); contexts.put(dev.getId(), context);
return context; return context;
} }
@@ -134,11 +134,14 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer {
} }
} }
if (buf != null || codecFlags != 0) { // Only throw if this happens at the beginning of a stream
throw new RendererException(this, e, buf, codecFlags); if (totalFrames < 60) {
} if (buf != null || codecFlags != 0) {
else { throw new RendererException(this, e, buf, codecFlags);
throw new RendererException(this, e); }
else {
throw new RendererException(this, e);
}
} }
} }
@@ -393,7 +393,7 @@ public class ComputerManagerService extends Service {
private boolean fastPollIp(InetAddress addr) { private boolean fastPollIp(InetAddress addr) {
Socket s = new Socket(); Socket s = new Socket();
try { try {
s.connect(new InetSocketAddress(addr, NvHTTP.PORT), FAST_POLL_TIMEOUT); s.connect(new InetSocketAddress(addr, NvHTTP.HTTPS_PORT), FAST_POLL_TIMEOUT);
s.close(); s.close();
return true; return true;
} catch (IOException e) { } catch (IOException e) {
@@ -639,7 +639,7 @@ public class ComputerManagerService extends Service {
if (cacheOut != null) { if (cacheOut != null) {
cacheOut.close(); cacheOut.close();
} }
} catch (IOException e) {} } catch (IOException ignored) {}
} }
// Update the computer // Update the computer
@@ -27,7 +27,7 @@ public class AppGridAdapter extends GenericGridAdapter<AppView.AppObject> {
private final CachedAppAssetLoader loader; private final CachedAppAssetLoader loader;
public AppGridAdapter(Activity activity, boolean listMode, boolean small, ComputerDetails computer, String uniqueId) throws KeyManagementException, NoSuchAlgorithmException { public AppGridAdapter(Activity activity, boolean listMode, boolean small, ComputerDetails computer, String uniqueId) {
super(activity, listMode ? R.layout.simple_row : (small ? R.layout.app_grid_item_small : R.layout.app_grid_item), R.drawable.image_loading); super(activity, listMode ? R.layout.simple_row : (small ? R.layout.app_grid_item_small : R.layout.app_grid_item), R.drawable.image_loading);
int dpi = activity.getResources().getDisplayMetrics().densityDpi; int dpi = activity.getResources().getDisplayMetrics().densityDpi;
@@ -26,7 +26,7 @@ public class NetworkAssetLoader {
InputStream in = null; InputStream in = null;
try { try {
in = http.getBoxArt(tuple.app); in = http.getBoxArt(tuple.app);
} catch (IOException e) {} } catch (IOException ignored) {}
if (in != null) { if (in != null) {
LimeLog.info("Network asset load complete: " + tuple); LimeLog.info("Network asset load complete: " + tuple);
@@ -3,6 +3,7 @@ package com.limelight.preferences;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Build;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
public class PreferenceConfiguration { public class PreferenceConfiguration {
@@ -69,9 +70,18 @@ public class PreferenceConfiguration {
public static boolean getDefaultSmallMode(Context context) { public static boolean getDefaultSmallMode(Context context) {
PackageManager manager = context.getPackageManager(); PackageManager manager = context.getPackageManager();
if (manager != null && manager.hasSystemFeature(PackageManager.FEATURE_TELEVISION)) { if (manager != null) {
// TVs shouldn't use small mode by default // TVs shouldn't use small mode by default
return false; if (manager.hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
return false;
}
// API 21 uses LEANBACK instead of TELEVISION
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
if (manager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
return false;
}
}
} }
// Use small mode on anything smaller than a 7" tablet // Use small mode on anything smaller than a 7" tablet
+1 -1
View File
@@ -4,7 +4,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:1.1.0' classpath 'com.android.tools.build:gradle:1.2.3'
} }
} }
+2 -2
View File
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4"> <module external.linked.project.id="moonlight-android" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager"> <component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle"> <facet type="java-gradle" name="Java-Gradle">
<configuration> <configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" /> <option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration> </configuration>
</facet> </facet>
</component> </component>
@@ -16,4 +17,3 @@
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
</module> </module>