Compare commits

..
11 Commits
8 changed files with 132 additions and 34 deletions

No files matched your search

+4 -1
View File
@@ -1,6 +1,9 @@
#built application files # built application files
*.apk *.apk
*.ap_ *.ap_
*.aab
output.json
out/
# files for the dex VM # files for the dex VM
*.dex *.dex
+2 -2
View File
@@ -8,8 +8,8 @@ android {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 28 targetSdkVersion 28
versionName "5.8.1" versionName "5.8.2"
versionCode = 166 versionCode = 167
} }
flavorDimensions "root" flavorDimensions "root"
+18 -9
View File
@@ -834,8 +834,12 @@ public class Game extends Activity implements SurfaceHolder.Callback,
} }
// Handle a synthetic back button event that some Android OS versions // Handle a synthetic back button event that some Android OS versions
// create as a result of a right-click. // create as a result of a right-click. This event WILL repeat if
if (event.getSource() == InputDevice.SOURCE_MOUSE && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { // the right mouse button is held down, so we ignore those.
if ((event.getSource() == InputDevice.SOURCE_MOUSE ||
event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE) &&
event.getKeyCode() == KeyEvent.KEYCODE_BACK &&
event.getRepeatCount() == 0) {
conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_RIGHT); conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_RIGHT);
return true; return true;
} }
@@ -885,7 +889,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
// Handle a synthetic back button event that some Android OS versions // Handle a synthetic back button event that some Android OS versions
// create as a result of a right-click. // create as a result of a right-click.
if (event.getSource() == InputDevice.SOURCE_MOUSE && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { if ((event.getSource() == InputDevice.SOURCE_MOUSE ||
event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE) &&
event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_RIGHT); conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_RIGHT);
return true; return true;
} }
@@ -953,6 +959,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
{ {
// This case is for mice // This case is for mice
if (event.getSource() == InputDevice.SOURCE_MOUSE || if (event.getSource() == InputDevice.SOURCE_MOUSE ||
event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE ||
(event.getPointerCount() >= 1 && (event.getPointerCount() >= 1 &&
event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE)) event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE))
{ {
@@ -968,6 +975,13 @@ public class Game extends Activity implements SurfaceHolder.Callback,
byte vScrollClicks = (byte) event.getAxisValue(MotionEvent.AXIS_VSCROLL); byte vScrollClicks = (byte) event.getAxisValue(MotionEvent.AXIS_VSCROLL);
conn.sendMouseScroll(vScrollClicks); conn.sendMouseScroll(vScrollClicks);
} }
else if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER ||
event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
// On some devices (Galaxy S8 without Oreo pointer capture), we can
// get spurious ACTION_HOVER_ENTER events when right clicking with
// incorrect X and Y coordinates. Just eat this event without processing it.
return true;
}
if ((changedButtons & MotionEvent.BUTTON_PRIMARY) != 0) { if ((changedButtons & MotionEvent.BUTTON_PRIMARY) != 0) {
if ((event.getButtonState() & MotionEvent.BUTTON_PRIMARY) != 0) { if ((event.getButtonState() & MotionEvent.BUTTON_PRIMARY) != 0) {
@@ -1014,12 +1028,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
lastMouseY = (int)event.getY(); lastMouseY = (int)event.getY();
} }
else { else {
// First process the history // Don't process the history. We just want the current position now.
for (int i = 0; i < event.getHistorySize(); i++) {
updateMousePosition((int)event.getHistoricalX(i), (int)event.getHistoricalY(i));
}
// Now process the current values
updateMousePosition((int)event.getX(), (int)event.getY()); updateMousePosition((int)event.getX(), (int)event.getY());
} }
@@ -4,6 +4,7 @@ import android.content.Context;
import android.hardware.input.InputManager; import android.hardware.input.InputManager;
import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager; import android.hardware.usb.UsbManager;
import android.os.Build;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.InputDevice; import android.view.InputDevice;
@@ -22,6 +23,7 @@ import com.limelight.preferences.PreferenceConfiguration;
import com.limelight.ui.GameGestures; import com.limelight.ui.GameGestures;
import com.limelight.utils.Vector2d; import com.limelight.utils.Vector2d;
import java.lang.reflect.InvocationTargetException;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@@ -308,6 +310,79 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
return context; return context;
} }
private static boolean isExternal(InputDevice dev) {
try {
// Landroid/view/InputDevice;->isExternal()Z is on the light graylist in Android P
return (Boolean)dev.getClass().getMethod("isExternal").invoke(dev);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (ClassCastException e) {
e.printStackTrace();
}
// Answer true if we don't know
return true;
}
private boolean shouldIgnoreBack(InputDevice dev) {
String devName = dev.getName();
// The Serval has a Select button but the framework doesn't
// know about that because it uses a non-standard scancode.
if (devName.contains("Razer Serval")) {
return true;
}
// Classify this device as a remote by name if it has no joystick axes
if (getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_X) == null &&
getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_Y) == null &&
devName.toLowerCase().contains("remote")) {
return true;
}
// Otherwise, dynamically try to determine whether we should allow this
// back button to function for navigation.
//
// First, check if this is an internal device we're being called on.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && !isExternal(dev)) {
InputManager im = (InputManager) activityContext.getSystemService(Context.INPUT_SERVICE);
boolean foundInternalGamepad = false;
boolean foundInternalSelect = false;
for (int id : im.getInputDeviceIds()) {
InputDevice currentDev = im.getInputDevice(id);
// Ignore external devices
if (currentDev == null || isExternal(currentDev)) {
continue;
}
// Note that we are explicitly NOT excluding the current device we're examining here,
// since the other gamepad buttons may be on our current device and that's fine.
boolean[] keys = currentDev.hasKeys(KeyEvent.KEYCODE_BUTTON_SELECT, KeyEvent.KEYCODE_BUTTON_A);
if (keys[0]) {
foundInternalSelect = true;
}
if (keys[1]) {
foundInternalGamepad = true;
}
}
// Allow the back button to function for navigation if we either:
// a) have no internal gamepad (most phones)
// b) have an internal gamepad but also have an internal select button (GPD XD)
// but not:
// c) have an internal gamepad but no internal select button (NVIDIA SHIELD Portable)
return !foundInternalGamepad || foundInternalSelect;
}
return false;
}
private InputDeviceContext createInputDeviceContextForDevice(InputDevice dev) { private InputDeviceContext createInputDeviceContextForDevice(InputDevice dev) {
InputDeviceContext context = new InputDeviceContext(); InputDeviceContext context = new InputDeviceContext();
String devName = dev.getName(); String devName = dev.getName();
@@ -440,6 +515,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
} }
} }
context.ignoreBack = shouldIgnoreBack(dev);
if (devName != null) { if (devName != null) {
// For the Nexus Player (and probably other ATV devices), we should // For the Nexus Player (and probably other ATV devices), we should
// use the back button as start since it doesn't have a start/menu button // use the back button as start since it doesn't have a start/menu button
@@ -459,30 +536,15 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
// so we increase the deadzone on them to minimize this // so we increase the deadzone on them to minimize this
context.triggerDeadzone = 0.30f; context.triggerDeadzone = 0.30f;
} }
// Classify this device as a remote by name
else if (devName.toLowerCase().contains("remote")) {
// It's only a remote if it doesn't any sticks
if (!context.hasJoystickAxes) {
context.ignoreBack = true;
}
}
// SHIELD controllers will use small stick deadzones // SHIELD controllers will use small stick deadzones
else if (devName.contains("SHIELD")) { else if (devName.contains("SHIELD")) {
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 explicitly ignore
// back presses on this device. The Goodix buttons on the Nokia 6 also appear
// non-virtual so we'll ignore those too.
else if (devName.equals("sec_touchscreen") || devName.equals("sec_touchkey") ||
devName.equals("goodix_fp")) {
context.ignoreBack = true;
}
// The Serval has a couple of unknown buttons that are start and select. It also has // The Serval has a couple of unknown buttons that are start and select. It also has
// a back button which we want to ignore since there's already a select button. // a back button which we want to ignore since there's already a select button.
else if (devName.contains("Razer Serval")) { else if (devName.contains("Razer Serval")) {
context.isServal = true; context.isServal = true;
context.ignoreBack = true;
} }
// The Xbox One S Bluetooth controller has some mappings that need fixing up. // The Xbox One S Bluetooth controller has some mappings that need fixing up.
// However, Microsoft released a firmware update with no change to VID/PID // However, Microsoft released a firmware update with no change to VID/PID
@@ -43,11 +43,19 @@ public class AndroidNativePointerCaptureProvider extends InputCaptureProvider {
@Override @Override
public float getRelativeAxisX(MotionEvent event) { public float getRelativeAxisX(MotionEvent event) {
return event.getX(); float x = event.getX();
for (int i = 0; i < event.getHistorySize(); i++) {
x += event.getHistoricalX(i);
}
return x;
} }
@Override @Override
public float getRelativeAxisY(MotionEvent event) { public float getRelativeAxisY(MotionEvent event) {
return event.getY(); float y = event.getY();
for (int i = 0; i < event.getHistorySize(); i++) {
y += event.getHistoricalY(i);
}
return y;
} }
} }
@@ -131,8 +131,8 @@ public class MediaCodecHelper {
} }
// Sony ATVs have broken MediaTek codecs (decoder hangs after rendering the first frame). // Sony ATVs have broken MediaTek codecs (decoder hangs after rendering the first frame).
// I know the Fire TV 2 works, so I'll just whitelist Amazon devices which seem // I know the Fire TV 2 and 3 works, so I'll just whitelist Amazon devices which seem
// to actually be tested. Ugh... // to actually be tested.
if (Build.MANUFACTURER.equalsIgnoreCase("Amazon")) { if (Build.MANUFACTURER.equalsIgnoreCase("Amazon")) {
whitelistedHevcDecoders.add("omx.mtk"); whitelistedHevcDecoders.add("omx.mtk");
whitelistedHevcDecoders.add("omx.amlogic"); whitelistedHevcDecoders.add("omx.amlogic");
@@ -166,6 +166,10 @@ public class MediaCodecHelper {
} }
} }
private static boolean isPowerVR(String glRenderer) {
return glRenderer.toLowerCase().contains("powervr");
}
private static String getAdrenoVersionString(String glRenderer) { private static String getAdrenoVersionString(String glRenderer) {
glRenderer = glRenderer.toLowerCase().trim(); glRenderer = glRenderer.toLowerCase().trim();
@@ -259,6 +263,18 @@ public class MediaCodecHelper {
else { else {
blacklistedDecoderPrefixes.add("OMX.qcom.video.decoder.hevc"); blacklistedDecoderPrefixes.add("OMX.qcom.video.decoder.hevc");
} }
// Older MediaTek SoCs have issues with HEVC rendering but the newer chips with
// PowerVR GPUs have good HEVC support.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && isPowerVR(glRenderer)) {
LimeLog.info("Added omx.mtk to HEVC decoders based on PowerVR GPU");
whitelistedHevcDecoders.add("omx.mtk");
// This SoC (MT8176 in GPD XD+) supports AVC RFI too, but the maxNumReferenceFrames setting
// required to make it work adds a huge amount of latency.
LimeLog.info("Added omx.mtk to RFI list for HEVC");
refFrameInvalidationHevcPrefixes.add("omx.mtk");
}
} }
initialized = true; initialized = true;
+1 -1
View File
@@ -5,7 +5,7 @@ buildscript {
google() google()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.2.0-alpha17' classpath 'com.android.tools.build:gradle:3.2.0-alpha18'
} }
} }
+2 -2
View File
@@ -1,9 +1,9 @@
This file serves to document some of the decoder errata when using MediaCodec hardware decoders on certain devices. This file serves to document some of the decoder errata when using MediaCodec hardware decoders on certain devices.
1. num_ref_frames is set to 16 by NVENC which causes decoders to allocate 16+ buffers. This can cause an error or lag on some devices. 1. num_ref_frames is set to 16 by NVENC which causes decoders to allocate 16+ buffers. This can cause an error or lag on some devices.
- Affected decoders: TI OMAP4, Allwinner A20 - Affected decoders: TI OMAP4 crashes, Allwinner A20, MT8176 lags (HEVC not affected)
2. Some decoders have a huge per-frame latency with the unmodified SPS sent from NVENC. Setting max_dec_frame_buffering fixes this latency issue. 2. Some H.264 decoders have a huge per-frame latency with the unmodified SPS sent from NVENC. Setting max_dec_frame_buffering=1 fixes this latency issue.
- Affected decoders: NVIDIA Tegra 3 and 4, Broadcom VideoCore IV - Affected decoders: NVIDIA Tegra 3 and 4, Broadcom VideoCore IV
3. Some decoders strictly require that you pass BUFFER_FLAG_CODEC_CONFIG and crash upon the IDR frame if you don't 3. Some decoders strictly require that you pass BUFFER_FLAG_CODEC_CONFIG and crash upon the IDR frame if you don't