Compare commits

..
9 Commits
8 changed files with 86 additions and 22 deletions

No files matched your search

+3 -3
View File
@@ -5,14 +5,14 @@ apply plugin: 'com.android.application'
android { android {
compileSdkVersion 27 compileSdkVersion 27
buildToolsVersion '27.0.2' buildToolsVersion '27.0.3'
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 27 targetSdkVersion 27
versionName "5.6.2" versionName "5.6.4"
versionCode = 140 versionCode = 143
} }
flavorDimensions "root" flavorDimensions "root"
+12 -1
View File
@@ -294,6 +294,16 @@ public class Game extends Activity implements SurfaceHolder.Callback,
if (prefConfig.videoFormat == PreferenceConfiguration.FORCE_H265_ON && !decoderRenderer.isHevcSupported()) { if (prefConfig.videoFormat == PreferenceConfiguration.FORCE_H265_ON && !decoderRenderer.isHevcSupported()) {
Toast.makeText(this, "No H.265 decoder found.\nFalling back to H.264.", Toast.LENGTH_LONG).show(); Toast.makeText(this, "No H.265 decoder found.\nFalling back to H.264.", Toast.LENGTH_LONG).show();
} }
int gamepadMask = ControllerHandler.getAttachedControllerMask(this);
if (!prefConfig.multiController && gamepadMask != 0) {
// If any gamepads are present in non-MC mode, set only gamepad 1.
gamepadMask = 1;
}
if (prefConfig.onscreenController) {
// If we're using OSC, always set at least gamepad 1.
gamepadMask |= 1;
}
StreamConfiguration config = new StreamConfiguration.Builder() StreamConfiguration config = new StreamConfiguration.Builder()
.setResolution(prefConfig.width, prefConfig.height) .setResolution(prefConfig.width, prefConfig.height)
@@ -302,11 +312,12 @@ public class Game extends Activity implements SurfaceHolder.Callback,
.setBitrate(prefConfig.bitrate * 1000) .setBitrate(prefConfig.bitrate * 1000)
.setEnableSops(prefConfig.enableSops) .setEnableSops(prefConfig.enableSops)
.enableLocalAudioPlayback(prefConfig.playHostAudio) .enableLocalAudioPlayback(prefConfig.playHostAudio)
.setMaxPacketSize(remote ? 1024 : 1292) .setMaxPacketSize((remote || prefConfig.width <= 1920) ? 1024 : 1292)
.setRemote(remote) .setRemote(remote)
.setHevcBitratePercentageMultiplier(75) .setHevcBitratePercentageMultiplier(75)
.setHevcSupported(decoderRenderer.isHevcSupported()) .setHevcSupported(decoderRenderer.isHevcSupported())
.setEnableHdr(willStreamHdr) .setEnableHdr(willStreamHdr)
.setAttachedGamepadMask(gamepadMask)
.setAudioConfiguration(prefConfig.enable51Surround ? .setAudioConfiguration(prefConfig.enable51Surround ?
MoonBridge.AUDIO_CONFIGURATION_51_SURROUND : MoonBridge.AUDIO_CONFIGURATION_51_SURROUND :
MoonBridge.AUDIO_CONFIGURATION_STEREO) MoonBridge.AUDIO_CONFIGURATION_STEREO)
@@ -2,6 +2,8 @@ package com.limelight.binding.input;
import android.content.Context; import android.content.Context;
import android.hardware.input.InputManager; import android.hardware.input.InputManager;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.InputDevice; import android.view.InputDevice;
@@ -12,6 +14,7 @@ import android.widget.Toast;
import com.limelight.LimeLog; import com.limelight.LimeLog;
import com.limelight.binding.input.driver.UsbDriverListener; import com.limelight.binding.input.driver.UsbDriverListener;
import com.limelight.binding.input.driver.UsbDriverService;
import com.limelight.nvstream.NvConnection; import com.limelight.nvstream.NvConnection;
import com.limelight.nvstream.input.ControllerPacket; import com.limelight.nvstream.input.ControllerPacket;
import com.limelight.nvstream.input.MouseButtonPacket; import com.limelight.nvstream.input.MouseButtonPacket;
@@ -48,7 +51,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
private boolean hasGameController; private boolean hasGameController;
private final boolean multiControllerEnabled; private final boolean multiControllerEnabled;
private short currentControllers; private short currentControllers, initialControllers;
public ControllerHandler(Context activityContext, NvConnection conn, GameGestures gestures, boolean multiControllerEnabled, int deadzonePercentage) { public ControllerHandler(Context activityContext, NvConnection conn, GameGestures gestures, boolean multiControllerEnabled, int deadzonePercentage) {
this.activityContext = activityContext; this.activityContext = activityContext;
@@ -102,6 +105,12 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
// consume these. Instead, let's ignore them since that's probably the // consume these. Instead, let's ignore them since that's probably the
// most likely case. // most likely case.
defaultContext.ignoreBack = true; defaultContext.ignoreBack = true;
// Get the initially attached set of gamepads. As each gamepad receives
// its initial InputEvent, we will move these from this set onto the
// currentControllers set which will allow them to properly unplug
// if they are removed.
initialControllers = getAttachedControllerMask(activityContext);
} }
private static InputDevice.MotionRange getMotionRangeForJoystickAxis(InputDevice dev, int axis) { private static InputDevice.MotionRange getMotionRangeForJoystickAxis(InputDevice dev, int axis) {
@@ -139,8 +148,47 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
onInputDeviceAdded(deviceId); onInputDeviceAdded(deviceId);
} }
public static short getAttachedControllerMask(Context context) {
int count = 0;
short mask = 0;
// Count all input devices that are gamepads
InputManager im = (InputManager) context.getSystemService(Context.INPUT_SERVICE);
for (int id : im.getInputDeviceIds()) {
InputDevice dev = im.getInputDevice(id);
if (dev == null) {
continue;
}
if ((dev.getSources() & InputDevice.SOURCE_JOYSTICK) != 0) {
LimeLog.info("Counting InputDevice: "+dev.getName());
mask |= 1 << count++;
}
}
// Count all USB devices that match our drivers
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
for (UsbDevice dev : usbManager.getDeviceList().values()) {
if (UsbDriverService.shouldClaimDevice(dev)) {
LimeLog.info("Counting UsbDevice: "+dev.getDeviceName());
mask |= 1 << count++;
}
}
LimeLog.info("Enumerated "+count+" gamepads");
return mask;
}
private void releaseControllerNumber(GenericControllerContext context) { private void releaseControllerNumber(GenericControllerContext context) {
// If this device sent data as a gamepad, zero the values before removing // If we reserved a controller number, remove that reservation
if (context.reservedControllerNumber) {
LimeLog.info("Controller number "+context.controllerNumber+" is now available");
currentControllers &= ~(1 << context.controllerNumber);
}
// If this device sent data as a gamepad, zero the values before removing.
// We must do this after clearing the currentControllers entry so this
// causes the device to be removed on the server PC.
if (context.assignedControllerNumber) { if (context.assignedControllerNumber) {
conn.sendControllerInput(context.controllerNumber, getActiveControllerMask(), conn.sendControllerInput(context.controllerNumber, getActiveControllerMask(),
(short) 0, (short) 0,
@@ -148,12 +196,6 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
(short) 0, (short) 0, (short) 0, (short) 0,
(short) 0, (short) 0); (short) 0, (short) 0);
} }
// If we reserved a controller number, remove that reservation
if (context.reservedControllerNumber) {
LimeLog.info("Controller number "+context.controllerNumber+" is now available");
currentControllers &= ~(1 << context.controllerNumber);
}
} }
// Called before sending input but after we've determined that this // Called before sending input but after we've determined that this
@@ -181,6 +223,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
if ((currentControllers & (1 << i)) == 0) { if ((currentControllers & (1 << i)) == 0) {
// Found an unused controller value // Found an unused controller value
currentControllers |= (1 << i); currentControllers |= (1 << i);
// Take this value out of the initial gamepad set
initialControllers &= ~(1 << i);
context.controllerNumber = i; context.controllerNumber = i;
context.reservedControllerNumber = true; context.reservedControllerNumber = true;
break; break;
@@ -201,6 +247,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
if ((currentControllers & (1 << i)) == 0) { if ((currentControllers & (1 << i)) == 0) {
// Found an unused controller value // Found an unused controller value
currentControllers |= (1 << i); currentControllers |= (1 << i);
// Take this value out of the initial gamepad set
initialControllers &= ~(1 << i);
context.controllerNumber = i; context.controllerNumber = i;
context.reservedControllerNumber = true; context.reservedControllerNumber = true;
break; break;
@@ -473,7 +523,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
private short getActiveControllerMask() { private short getActiveControllerMask() {
if (multiControllerEnabled) { if (multiControllerEnabled) {
return currentControllers; return (short)(currentControllers | initialControllers);
} }
else { else {
// Only Player 1 is active with multi-controller disabled // Only Player 1 is active with multi-controller disabled
@@ -3,6 +3,7 @@ package com.limelight.binding.input.capture;
import android.app.Activity; import android.app.Activity;
import com.limelight.LimeLog; import com.limelight.LimeLog;
import com.limelight.LimelightBuildProps;
import com.limelight.R; import com.limelight.R;
import com.limelight.binding.input.evdev.EvdevCaptureProviderShim; import com.limelight.binding.input.evdev.EvdevCaptureProviderShim;
import com.limelight.binding.input.evdev.EvdevListener; import com.limelight.binding.input.evdev.EvdevListener;
@@ -13,7 +14,9 @@ public class InputCaptureManager {
LimeLog.info("Using Android O+ native mouse capture"); LimeLog.info("Using Android O+ native mouse capture");
return new AndroidNativePointerCaptureProvider(activity.findViewById(R.id.surfaceView)); return new AndroidNativePointerCaptureProvider(activity.findViewById(R.id.surfaceView));
} }
else if (ShieldCaptureProvider.isCaptureProviderSupported()) { // LineageOS implemented broken NVIDIA capture extensions, so avoid using them on root builds.
// See https://github.com/LineageOS/android_frameworks_base/commit/d304f478a023430f4712dbdc3ee69d9ad02cebd3
else if (!LimelightBuildProps.ROOT_BUILD && ShieldCaptureProvider.isCaptureProviderSupported()) {
LimeLog.info("Using NVIDIA mouse capture extension"); LimeLog.info("Using NVIDIA mouse capture extension");
return new ShieldCaptureProvider(activity); return new ShieldCaptureProvider(activity);
} }
@@ -157,7 +157,7 @@ public class UsbDriverService extends Service implements UsbDriverListener {
} }
} }
private boolean isRecognizedInputDevice(UsbDevice device) { private static boolean isRecognizedInputDevice(UsbDevice device) {
// On KitKat and later, we can determine if this VID and PID combo // On KitKat and later, we can determine if this VID and PID combo
// matches an existing input device and defer to the built-in controller // matches an existing input device and defer to the built-in controller
// support in that case. Prior to KitKat, we'll always return true to be safe. // support in that case. Prior to KitKat, we'll always return true to be safe.
@@ -182,7 +182,7 @@ public class UsbDriverService extends Service implements UsbDriverListener {
} }
} }
private boolean shouldClaimDevice(UsbDevice device) { public static boolean shouldClaimDevice(UsbDevice device) {
// We always bind to XB1 controllers but only bind to XB360 controllers // We always bind to XB1 controllers but only bind to XB360 controllers
// if we know the kernel isn't already driving this device. // if we know the kernel isn't already driving this device.
return XboxOneController.canClaimDevice(device) || return XboxOneController.canClaimDevice(device) ||
@@ -134,7 +134,7 @@ public class ComputerManagerService extends Service {
public void run() { public void run() {
int offlineCount = 0; int offlineCount = 0;
while (!isInterrupted() && pollingActive) { while (!isInterrupted() && pollingActive && tuple.thread == this) {
try { try {
// Only allow one request to the machine at a time // Only allow one request to the machine at a time
synchronized (tuple.networkLock) { synchronized (tuple.networkLock) {
@@ -392,6 +392,7 @@ public class ComputerManagerService extends Service {
if (tuple.thread != null) { if (tuple.thread != null) {
// Interrupt the thread on this entry // Interrupt the thread on this entry
tuple.thread.interrupt(); tuple.thread.interrupt();
tuple.thread = null;
} }
pollingTuples.remove(tuple); pollingTuples.remove(tuple);
break; break;
@@ -840,6 +841,7 @@ public class ComputerManagerService extends Service {
} while (waitPollingDelay()); } while (waitPollingDelay());
} }
}; };
thread.setName("App list polling thread for " + computer.localAddress);
thread.start(); thread.start();
} }
+2 -4
View File
@@ -2,8 +2,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Non-root application name --> <!-- Non-root application name -->
<!-- No need to extract libraries for the non-root version --> <!-- FIXME: We should set extractNativeLibs=false but this breaks installation on the Fire TV 3 -->
<application <application android:label="Moonlight" />
android:label="Moonlight"
android:extractNativeLibs="false" />
</manifest> </manifest>