From 6993051529f20fa29ceac6638131014271c58568 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Fri, 30 Nov 2018 21:17:12 -0800 Subject: [PATCH] Retransmit OSC gamepad packets every 100 ms to recover from dropped events in GFE --- app/src/main/java/com/limelight/Game.java | 5 ++++ .../input/virtual_controller/AnalogStick.java | 9 ------- .../virtual_controller/VirtualController.java | 24 ++++++++++++++----- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index e0fccc8d..87b9bbad 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -406,6 +406,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, (FrameLayout)streamView.getParent(), this); virtualController.refreshLayout(); + virtualController.show(); } if (prefConfig.usbDriver) { @@ -692,6 +693,10 @@ public class Game extends Activity implements SurfaceHolder.Callback, SpinnerDialog.closeDialogs(this); Dialog.closeDialogs(); + if (virtualController != null) { + virtualController.hide(); + } + if (conn != null) { int videoFormat = decoderRenderer.getActiveVideoFormat(); diff --git a/app/src/main/java/com/limelight/binding/input/virtual_controller/AnalogStick.java b/app/src/main/java/com/limelight/binding/input/virtual_controller/AnalogStick.java index c5b95774..103466bf 100644 --- a/app/src/main/java/com/limelight/binding/input/virtual_controller/AnalogStick.java +++ b/app/src/main/java/com/limelight/binding/input/virtual_controller/AnalogStick.java @@ -339,15 +339,6 @@ public class AnalogStick extends VirtualControllerElement { stick_state = STICK_STATE.NO_MOVEMENT; notifyOnRevoke(); - // HACK: We can sometimes generate back-to-back controller events - // that cause GFE to drop newer data. Dropping zeroing events would - // be disastrous because we may not get a follow-up joystick event to - // correct the dropped zeroing packet. Delay 5 ms when raising the - // analog stick to ensure this doesn't happen. - try { - Thread.sleep(5); - } catch (InterruptedException e) {} - // not longer pressed reset analog stick notifyOnMovement(0, 0); } diff --git a/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualController.java b/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualController.java index 0783c044..39d26f03 100644 --- a/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualController.java +++ b/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualController.java @@ -17,6 +17,8 @@ import com.limelight.nvstream.NvConnection; import java.util.ArrayList; import java.util.List; +import java.util.Timer; +import java.util.TimerTask; public class VirtualController { public class ControllerInputContext { @@ -42,6 +44,8 @@ public class VirtualController { private FrameLayout frame_layout = null; private RelativeLayout relative_layout = null; + private Timer retransmitTimer; + ControllerMode currentMode = ControllerMode.Active; ControllerInputContext inputContext = new ControllerInputContext(); @@ -88,11 +92,24 @@ public class VirtualController { } public void hide() { + retransmitTimer.cancel(); relative_layout.setVisibility(View.INVISIBLE); } public void show() { relative_layout.setVisibility(View.VISIBLE); + + // HACK: GFE sometimes discards gamepad packets when they are received + // very shortly after another. This can be critical if an axis zeroing packet + // is lost and causes an analog stick to get stuck. To avoid this, we send + // a gamepad input packet every 100 ms to ensure any loss can be recovered. + retransmitTimer = new Timer("OSC timer", true); + retransmitTimer.schedule(new TimerTask() { + @Override + public void run() { + sendControllerInputContext(); + } + }, 100, 100); } public void removeElements() { @@ -149,18 +166,13 @@ public class VirtualController { return inputContext; } - public void sendControllerInputContext() { - sendControllerInputPacket(); - } - - private void sendControllerInputPacket() { + void sendControllerInputContext() { try { _DBG("INPUT_MAP + " + inputContext.inputMap); _DBG("LEFT_TRIGGER " + inputContext.leftTrigger); _DBG("RIGHT_TRIGGER " + inputContext.rightTrigger); _DBG("LEFT STICK X: " + inputContext.leftStickX + " Y: " + inputContext.leftStickY); _DBG("RIGHT STICK X: " + inputContext.rightStickX + " Y: " + inputContext.rightStickY); - _DBG("RIGHT STICK X: " + inputContext.rightStickX + " Y: " + inputContext.rightStickY); if (connection != null) { connection.sendControllerInput(