mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2026-10-20 23:36:53 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35bd9ecda3 | ||
|
|
ca89849dd2 | ||
|
|
ac1cb6d56b | ||
|
|
dfbffea0fc | ||
|
|
7ae9c993f1 | ||
|
|
91d739f8d6 | ||
|
|
f0c625d85c | ||
|
|
b5f5e73076 | ||
|
|
1fb5eff7f1 | ||
|
|
5116cfd141 | ||
|
|
e53a1f90b0 | ||
|
|
766c9628b0 | ||
|
|
6a4abdd74c |
No files matched your search
+5
-5
@@ -7,8 +7,8 @@ android {
|
|||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
|
|
||||||
versionName "9.7.4"
|
versionName "9.7.7"
|
||||||
versionCode = 244
|
versionCode = 247
|
||||||
}
|
}
|
||||||
|
|
||||||
flavorDimensions "root"
|
flavorDimensions "root"
|
||||||
@@ -114,10 +114,10 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.bouncycastle:bcprov-jdk15on:1.64'
|
implementation 'org.bouncycastle:bcprov-jdk15on:1.66'
|
||||||
implementation 'org.bouncycastle:bcpkix-jdk15on:1.64'
|
implementation 'org.bouncycastle:bcpkix-jdk15on:1.66'
|
||||||
implementation 'org.jcodec:jcodec:0.2.3'
|
implementation 'org.jcodec:jcodec:0.2.3'
|
||||||
implementation 'com.squareup.okhttp3:okhttp:3.12.10'
|
implementation 'com.squareup.okhttp3:okhttp:3.12.12'
|
||||||
implementation 'com.squareup.okio:okio:1.17.5'
|
implementation 'com.squareup.okio:okio:1.17.5'
|
||||||
implementation 'org.jmdns:jmdns:3.5.5'
|
implementation 'org.jmdns:jmdns:3.5.5'
|
||||||
}
|
}
|
||||||
@@ -126,6 +126,15 @@
|
|||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="com.limelight.AppView" />
|
android:value="com.limelight.AppView" />
|
||||||
|
|
||||||
|
<!-- Special metadata for NVIDIA Shield devices to prevent input buffering
|
||||||
|
and most importantly, opt out of mouse acceleration while streaming -->
|
||||||
|
<meta-data
|
||||||
|
android:name="com.nvidia.immediateInput"
|
||||||
|
android:value="true" />
|
||||||
|
<meta-data
|
||||||
|
android:name="com.nvidia.rawCursorInput"
|
||||||
|
android:value="true" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
|
|
||||||
private static final int MINIMUM_BUTTON_DOWN_TIME_MS = 25;
|
private static final int MINIMUM_BUTTON_DOWN_TIME_MS = 25;
|
||||||
|
|
||||||
|
private static final int EMULATING_SPECIAL = 0x1;
|
||||||
|
private static final int EMULATING_SELECT = 0x2;
|
||||||
|
|
||||||
|
private static final int EMULATED_SPECIAL_UP_DELAY_MS = 100;
|
||||||
|
private static final int EMULATED_SELECT_UP_DELAY_MS = 30;
|
||||||
|
|
||||||
private final Vector2d inputVector = new Vector2d();
|
private final Vector2d inputVector = new Vector2d();
|
||||||
|
|
||||||
private final SparseArray<InputDeviceContext> inputDeviceContexts = new SparseArray<>();
|
private final SparseArray<InputDeviceContext> inputDeviceContexts = new SparseArray<>();
|
||||||
@@ -461,6 +467,14 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
context.vibrator = dev.getVibrator();
|
context.vibrator = dev.getVibrator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detect if the gamepad has Mode and Select buttons according to the Android key layouts.
|
||||||
|
// We do this first because other codepaths below may override these defaults.
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
|
boolean[] buttons = dev.hasKeys(KeyEvent.KEYCODE_BUTTON_MODE, KeyEvent.KEYCODE_BUTTON_SELECT, KeyEvent.KEYCODE_BACK, 0);
|
||||||
|
context.hasMode = buttons[0];
|
||||||
|
context.hasSelect = buttons[1] || buttons[2];
|
||||||
|
}
|
||||||
|
|
||||||
context.leftStickXAxis = MotionEvent.AXIS_X;
|
context.leftStickXAxis = MotionEvent.AXIS_X;
|
||||||
context.leftStickYAxis = MotionEvent.AXIS_Y;
|
context.leftStickYAxis = MotionEvent.AXIS_Y;
|
||||||
if (getMotionRangeForJoystickAxis(dev, context.leftStickXAxis) != null &&
|
if (getMotionRangeForJoystickAxis(dev, context.leftStickXAxis) != null &&
|
||||||
@@ -519,6 +533,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
// The old DS4 driver uses RX and RY for triggers
|
// The old DS4 driver uses RX and RY for triggers
|
||||||
context.leftTriggerAxis = MotionEvent.AXIS_RX;
|
context.leftTriggerAxis = MotionEvent.AXIS_RX;
|
||||||
context.rightTriggerAxis = MotionEvent.AXIS_RY;
|
context.rightTriggerAxis = MotionEvent.AXIS_RY;
|
||||||
|
|
||||||
|
// DS4 has Select and Mode buttons (possibly mapped non-standard)
|
||||||
|
context.hasSelect = true;
|
||||||
|
context.hasMode = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If it's not a non-standard DS4 controller, it's probably an Xbox controller or
|
// If it's not a non-standard DS4 controller, it's probably an Xbox controller or
|
||||||
@@ -600,6 +618,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
context.backIsStart = true;
|
context.backIsStart = true;
|
||||||
context.modeIsSelect = true;
|
context.modeIsSelect = true;
|
||||||
context.triggerDeadzone = 0.30f;
|
context.triggerDeadzone = 0.30f;
|
||||||
|
context.hasSelect = true;
|
||||||
|
context.hasMode = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,6 +637,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
if (!hasStartKey[0] && !hasStartKey[1]) {
|
if (!hasStartKey[0] && !hasStartKey[1]) {
|
||||||
context.backIsStart = true;
|
context.backIsStart = true;
|
||||||
context.modeIsSelect = true;
|
context.modeIsSelect = true;
|
||||||
|
context.hasSelect = true;
|
||||||
|
context.hasMode = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -625,14 +647,26 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
context.triggerDeadzone = 0.30f;
|
context.triggerDeadzone = 0.30f;
|
||||||
}
|
}
|
||||||
// SHIELD controllers will use small stick deadzones
|
// SHIELD controllers will use small stick deadzones
|
||||||
else if (devName.contains("SHIELD")) {
|
else if (devName.contains("SHIELD") || devName.contains("NVIDIA Controller")) {
|
||||||
context.leftStickDeadzoneRadius = 0.07f;
|
context.leftStickDeadzoneRadius = 0.07f;
|
||||||
context.rightStickDeadzoneRadius = 0.07f;
|
context.rightStickDeadzoneRadius = 0.07f;
|
||||||
|
|
||||||
|
// The big Nvidia button on the Shield controllers acts like a Search button. It
|
||||||
|
// summons the Google Assistant on the Shield TV. On my Pixel 4, it seems to do
|
||||||
|
// nothing, so we can hijack it to act like a mode button.
|
||||||
|
if (devName.contains("NVIDIA Controller v01.03") || devName.contains("NVIDIA Controller v01.04")) {
|
||||||
|
context.searchIsMode = true;
|
||||||
|
context.hasMode = 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;
|
||||||
|
|
||||||
|
// Serval has Select and Mode buttons (possibly mapped non-standard)
|
||||||
|
context.hasMode = true;
|
||||||
|
context.hasSelect = 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
|
||||||
@@ -643,6 +677,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
else if (devName.equals("Xbox Wireless Controller")) {
|
else if (devName.equals("Xbox Wireless Controller")) {
|
||||||
if (gasRange == null) {
|
if (gasRange == null) {
|
||||||
context.isNonStandardXboxBtController = true;
|
context.isNonStandardXboxBtController = true;
|
||||||
|
|
||||||
|
// Xbox One S has Select and Mode buttons (possibly mapped non-standard)
|
||||||
|
context.hasMode = true;
|
||||||
|
context.hasSelect = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1018,6 +1056,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
// Emulate the select button with mode
|
// Emulate the select button with mode
|
||||||
return KeyEvent.KEYCODE_BUTTON_SELECT;
|
return KeyEvent.KEYCODE_BUTTON_SELECT;
|
||||||
}
|
}
|
||||||
|
else if (context.searchIsMode && keyCode == KeyEvent.KEYCODE_SEARCH) {
|
||||||
|
// Emulate the mode button with search
|
||||||
|
return KeyEvent.KEYCODE_BUTTON_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
return keyCode;
|
return keyCode;
|
||||||
}
|
}
|
||||||
@@ -1416,6 +1458,41 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if we're emulating the select button
|
||||||
|
if ((context.emulatingButtonFlags & ControllerHandler.EMULATING_SELECT) != 0)
|
||||||
|
{
|
||||||
|
// If either start or LB is up, select comes up too
|
||||||
|
if ((context.inputMap & ControllerPacket.PLAY_FLAG) == 0 ||
|
||||||
|
(context.inputMap & ControllerPacket.LB_FLAG) == 0)
|
||||||
|
{
|
||||||
|
context.inputMap &= ~ControllerPacket.BACK_FLAG;
|
||||||
|
|
||||||
|
context.emulatingButtonFlags &= ~ControllerHandler.EMULATING_SELECT;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(EMULATED_SELECT_UP_DELAY_MS);
|
||||||
|
} catch (InterruptedException ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we're emulating the special button
|
||||||
|
if ((context.emulatingButtonFlags & ControllerHandler.EMULATING_SPECIAL) != 0)
|
||||||
|
{
|
||||||
|
// If either start or select and RB is up, the special button comes up too
|
||||||
|
if ((context.inputMap & ControllerPacket.PLAY_FLAG) == 0 ||
|
||||||
|
((context.inputMap & ControllerPacket.BACK_FLAG) == 0 &&
|
||||||
|
(context.inputMap & ControllerPacket.RB_FLAG) == 0))
|
||||||
|
{
|
||||||
|
context.inputMap &= ~ControllerPacket.SPECIAL_BUTTON_FLAG;
|
||||||
|
|
||||||
|
context.emulatingButtonFlags &= ~ControllerHandler.EMULATING_SPECIAL;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(EMULATED_SPECIAL_UP_DELAY_MS);
|
||||||
|
} catch (InterruptedException ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sendControllerInputPacket(context);
|
sendControllerInputPacket(context);
|
||||||
|
|
||||||
if (context.pendingExit && context.inputMap == 0) {
|
if (context.pendingExit && context.inputMap == 0) {
|
||||||
@@ -1444,6 +1521,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
|
|
||||||
switch (keyCode) {
|
switch (keyCode) {
|
||||||
case KeyEvent.KEYCODE_BUTTON_MODE:
|
case KeyEvent.KEYCODE_BUTTON_MODE:
|
||||||
|
context.hasMode = true;
|
||||||
context.inputMap |= ControllerPacket.SPECIAL_BUTTON_FLAG;
|
context.inputMap |= ControllerPacket.SPECIAL_BUTTON_FLAG;
|
||||||
break;
|
break;
|
||||||
case KeyEvent.KEYCODE_BUTTON_START:
|
case KeyEvent.KEYCODE_BUTTON_START:
|
||||||
@@ -1455,6 +1533,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
break;
|
break;
|
||||||
case KeyEvent.KEYCODE_BACK:
|
case KeyEvent.KEYCODE_BACK:
|
||||||
case KeyEvent.KEYCODE_BUTTON_SELECT:
|
case KeyEvent.KEYCODE_BUTTON_SELECT:
|
||||||
|
context.hasSelect = true;
|
||||||
context.inputMap |= ControllerPacket.BACK_FLAG;
|
context.inputMap |= ControllerPacket.BACK_FLAG;
|
||||||
break;
|
break;
|
||||||
case KeyEvent.KEYCODE_DPAD_LEFT:
|
case KeyEvent.KEYCODE_DPAD_LEFT:
|
||||||
@@ -1535,6 +1614,43 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
context.pendingExit = true;
|
context.pendingExit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start+LB acts like select for controllers with one button
|
||||||
|
if (!context.hasSelect) {
|
||||||
|
if (context.inputMap == (ControllerPacket.PLAY_FLAG | ControllerPacket.LB_FLAG) ||
|
||||||
|
(context.inputMap == ControllerPacket.PLAY_FLAG &&
|
||||||
|
SystemClock.uptimeMillis() - context.lastLbUpTime <= MAXIMUM_BUMPER_UP_DELAY_MS))
|
||||||
|
{
|
||||||
|
context.inputMap &= ~(ControllerPacket.PLAY_FLAG | ControllerPacket.LB_FLAG);
|
||||||
|
context.inputMap |= ControllerPacket.BACK_FLAG;
|
||||||
|
|
||||||
|
context.emulatingButtonFlags |= ControllerHandler.EMULATING_SELECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a physical select button, we'll use Start+Select as the special button combo
|
||||||
|
// otherwise we'll use Start+RB.
|
||||||
|
if (!context.hasMode) {
|
||||||
|
if (context.hasSelect) {
|
||||||
|
if (context.inputMap == (ControllerPacket.PLAY_FLAG | ControllerPacket.BACK_FLAG)) {
|
||||||
|
context.inputMap &= ~(ControllerPacket.PLAY_FLAG | ControllerPacket.BACK_FLAG);
|
||||||
|
context.inputMap |= ControllerPacket.SPECIAL_BUTTON_FLAG;
|
||||||
|
|
||||||
|
context.emulatingButtonFlags |= ControllerHandler.EMULATING_SPECIAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (context.inputMap == (ControllerPacket.PLAY_FLAG | ControllerPacket.RB_FLAG) ||
|
||||||
|
(context.inputMap == ControllerPacket.PLAY_FLAG &&
|
||||||
|
SystemClock.uptimeMillis() - context.lastRbUpTime <= MAXIMUM_BUMPER_UP_DELAY_MS))
|
||||||
|
{
|
||||||
|
context.inputMap &= ~(ControllerPacket.PLAY_FLAG | ControllerPacket.RB_FLAG);
|
||||||
|
context.inputMap |= ControllerPacket.SPECIAL_BUTTON_FLAG;
|
||||||
|
|
||||||
|
context.emulatingButtonFlags |= ControllerHandler.EMULATING_SPECIAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We don't need to send repeat key down events, but the platform
|
// We don't need to send repeat key down events, but the platform
|
||||||
// sends us events that claim to be repeats but they're from different
|
// sends us events that claim to be repeats but they're from different
|
||||||
// devices, so we just send them all and deal with some duplicates.
|
// devices, so we just send them all and deal with some duplicates.
|
||||||
@@ -1676,10 +1792,15 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
public boolean isServal;
|
public boolean isServal;
|
||||||
public boolean backIsStart;
|
public boolean backIsStart;
|
||||||
public boolean modeIsSelect;
|
public boolean modeIsSelect;
|
||||||
|
public boolean searchIsMode;
|
||||||
public boolean ignoreBack;
|
public boolean ignoreBack;
|
||||||
public boolean hasJoystickAxes;
|
public boolean hasJoystickAxes;
|
||||||
public boolean pendingExit;
|
public boolean pendingExit;
|
||||||
|
|
||||||
|
public int emulatingButtonFlags = 0;
|
||||||
|
public boolean hasSelect;
|
||||||
|
public boolean hasMode;
|
||||||
|
|
||||||
// Used for OUYA bumper state tracking since they force all buttons
|
// Used for OUYA bumper state tracking since they force all buttons
|
||||||
// up when the OUYA button goes down. We watch the last time we get
|
// up when the OUYA button goes down. We watch the last time we get
|
||||||
// a bumper up and compare that to our maximum delay when we receive
|
// a bumper up and compare that to our maximum delay when we receive
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import android.content.Context;
|
|||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -270,7 +271,7 @@ public class AnalogStick extends VirtualControllerElement {
|
|||||||
// We also release the deadzone if the user keeps the stick pressed for a bit to allow
|
// We also release the deadzone if the user keeps the stick pressed for a bit to allow
|
||||||
// them to make precise movements.
|
// them to make precise movements.
|
||||||
stick_state = (stick_state == STICK_STATE.MOVED_ACTIVE ||
|
stick_state = (stick_state == STICK_STATE.MOVED_ACTIVE ||
|
||||||
System.currentTimeMillis() - timeLastClick > timeoutDeadzone ||
|
SystemClock.uptimeMillis() - timeLastClick > timeoutDeadzone ||
|
||||||
movement_radius > radius_dead_zone) ?
|
movement_radius > radius_dead_zone) ?
|
||||||
STICK_STATE.MOVED_ACTIVE : STICK_STATE.MOVED_IN_DEAD_ZONE;
|
STICK_STATE.MOVED_ACTIVE : STICK_STATE.MOVED_IN_DEAD_ZONE;
|
||||||
|
|
||||||
@@ -311,7 +312,7 @@ public class AnalogStick extends VirtualControllerElement {
|
|||||||
stick_state = STICK_STATE.MOVED_IN_DEAD_ZONE;
|
stick_state = STICK_STATE.MOVED_IN_DEAD_ZONE;
|
||||||
// check for double click
|
// check for double click
|
||||||
if (lastClickState == CLICK_STATE.SINGLE &&
|
if (lastClickState == CLICK_STATE.SINGLE &&
|
||||||
timeLastClick + timeoutDoubleClick > System.currentTimeMillis()) {
|
timeLastClick + timeoutDoubleClick > SystemClock.uptimeMillis()) {
|
||||||
click_state = CLICK_STATE.DOUBLE;
|
click_state = CLICK_STATE.DOUBLE;
|
||||||
notifyOnDoubleClick();
|
notifyOnDoubleClick();
|
||||||
} else {
|
} else {
|
||||||
@@ -319,7 +320,7 @@ public class AnalogStick extends VirtualControllerElement {
|
|||||||
notifyOnClick();
|
notifyOnClick();
|
||||||
}
|
}
|
||||||
// reset last click timestamp
|
// reset last click timestamp
|
||||||
timeLastClick = System.currentTimeMillis();
|
timeLastClick = SystemClock.uptimeMillis();
|
||||||
// set item pressed and update
|
// set item pressed and update
|
||||||
setPressed(true);
|
setPressed(true);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import android.media.MediaFormat;
|
|||||||
import android.media.MediaCodec.BufferInfo;
|
import android.media.MediaCodec.BufferInfo;
|
||||||
import android.media.MediaCodec.CodecException;
|
import android.media.MediaCodec.CodecException;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.util.Range;
|
import android.util.Range;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
|
|
||||||
@@ -410,7 +411,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
|
|||||||
//
|
//
|
||||||
if (initialException != null) {
|
if (initialException != null) {
|
||||||
// This isn't the first time we've had an exception processing video
|
// This isn't the first time we've had an exception processing video
|
||||||
if (System.currentTimeMillis() - initialExceptionTimestamp >= EXCEPTION_REPORT_DELAY_MS) {
|
if (SystemClock.uptimeMillis() - initialExceptionTimestamp >= EXCEPTION_REPORT_DELAY_MS) {
|
||||||
// It's been over 3 seconds and we're still getting exceptions. Throw the original now.
|
// It's been over 3 seconds and we're still getting exceptions. Throw the original now.
|
||||||
if (!reportedCrash) {
|
if (!reportedCrash) {
|
||||||
reportedCrash = true;
|
reportedCrash = true;
|
||||||
@@ -427,7 +428,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
|
|||||||
else {
|
else {
|
||||||
initialException = new RendererException(this, e);
|
initialException = new RendererException(this, e);
|
||||||
}
|
}
|
||||||
initialExceptionTimestamp = System.currentTimeMillis();
|
initialExceptionTimestamp = SystemClock.uptimeMillis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -637,7 +638,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lastFrameNumber == 0) {
|
if (lastFrameNumber == 0) {
|
||||||
activeWindowVideoStats.measurementStartTimestamp = System.currentTimeMillis();
|
activeWindowVideoStats.measurementStartTimestamp = SystemClock.uptimeMillis();
|
||||||
} else if (frameNumber != lastFrameNumber && frameNumber != lastFrameNumber + 1) {
|
} else if (frameNumber != lastFrameNumber && frameNumber != lastFrameNumber + 1) {
|
||||||
// We can receive the same "frame" multiple times if it's an IDR frame.
|
// We can receive the same "frame" multiple times if it's an IDR frame.
|
||||||
// In that case, each frame start NALU is submitted independently.
|
// In that case, each frame start NALU is submitted independently.
|
||||||
@@ -649,7 +650,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
|
|||||||
lastFrameNumber = frameNumber;
|
lastFrameNumber = frameNumber;
|
||||||
|
|
||||||
// Flip stats windows roughly every second
|
// Flip stats windows roughly every second
|
||||||
if (System.currentTimeMillis() >= activeWindowVideoStats.measurementStartTimestamp + 1000) {
|
if (SystemClock.uptimeMillis() >= activeWindowVideoStats.measurementStartTimestamp + 1000) {
|
||||||
if (prefs.enablePerfOverlay) {
|
if (prefs.enablePerfOverlay) {
|
||||||
VideoStats lastTwo = new VideoStats();
|
VideoStats lastTwo = new VideoStats();
|
||||||
lastTwo.add(lastWindowVideoStats);
|
lastTwo.add(lastWindowVideoStats);
|
||||||
@@ -682,7 +683,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
|
|||||||
globalVideoStats.add(activeWindowVideoStats);
|
globalVideoStats.add(activeWindowVideoStats);
|
||||||
lastWindowVideoStats.copy(activeWindowVideoStats);
|
lastWindowVideoStats.copy(activeWindowVideoStats);
|
||||||
activeWindowVideoStats.clear();
|
activeWindowVideoStats.clear();
|
||||||
activeWindowVideoStats.measurementStartTimestamp = System.currentTimeMillis();
|
activeWindowVideoStats.measurementStartTimestamp = SystemClock.uptimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
activeWindowVideoStats.totalFramesReceived++;
|
activeWindowVideoStats.totalFramesReceived++;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.limelight.binding.video;
|
package com.limelight.binding.video;
|
||||||
|
|
||||||
|
import android.os.SystemClock;
|
||||||
|
|
||||||
class VideoStats {
|
class VideoStats {
|
||||||
|
|
||||||
long decoderTimeMs;
|
long decoderTimeMs;
|
||||||
@@ -24,7 +26,7 @@ class VideoStats {
|
|||||||
this.measurementStartTimestamp = other.measurementStartTimestamp;
|
this.measurementStartTimestamp = other.measurementStartTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert other.measurementStartTimestamp <= this.measurementStartTimestamp;
|
assert other.measurementStartTimestamp >= this.measurementStartTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void copy(VideoStats other) {
|
void copy(VideoStats other) {
|
||||||
@@ -50,7 +52,7 @@ class VideoStats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VideoStatsFps getFps() {
|
VideoStatsFps getFps() {
|
||||||
float elapsed = (System.currentTimeMillis() - this.measurementStartTimestamp) / (float) 1000;
|
float elapsed = (SystemClock.uptimeMillis() - this.measurementStartTimestamp) / (float) 1000;
|
||||||
|
|
||||||
VideoStatsFps fps = new VideoStatsFps();
|
VideoStatsFps fps = new VideoStatsFps();
|
||||||
if (elapsed > 0) {
|
if (elapsed > 0) {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import android.net.NetworkCapabilities;
|
|||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
@@ -176,7 +177,7 @@ public class ComputerManagerService extends Service {
|
|||||||
LimeLog.warning(tuple.computer.name + " is offline (try " + offlineCount + ")");
|
LimeLog.warning(tuple.computer.name + " is offline (try " + offlineCount + ")");
|
||||||
offlineCount++;
|
offlineCount++;
|
||||||
} else {
|
} else {
|
||||||
tuple.lastSuccessfulPollMs = System.currentTimeMillis();
|
tuple.lastSuccessfulPollMs = SystemClock.elapsedRealtime();
|
||||||
offlineCount = 0;
|
offlineCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,7 +208,7 @@ public class ComputerManagerService extends Service {
|
|||||||
synchronized (pollingTuples) {
|
synchronized (pollingTuples) {
|
||||||
for (PollingTuple tuple : pollingTuples) {
|
for (PollingTuple tuple : pollingTuples) {
|
||||||
// Enforce the poll data TTL
|
// Enforce the poll data TTL
|
||||||
if (System.currentTimeMillis() - tuple.lastSuccessfulPollMs > POLL_DATA_TTL_MS) {
|
if (SystemClock.elapsedRealtime() - tuple.lastSuccessfulPollMs > POLL_DATA_TTL_MS) {
|
||||||
LimeLog.info("Timing out polled state for "+tuple.computer.name);
|
LimeLog.info("Timing out polled state for "+tuple.computer.name);
|
||||||
tuple.computer.state = ComputerDetails.State.UNKNOWN;
|
tuple.computer.state = ComputerDetails.State.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|||||||
Submodule app/src/main/jni/moonlight-core/moonlight-common-c updated: 128c1503f2...dbf81dcb63.
+1
-1
@@ -5,7 +5,7 @@ buildscript {
|
|||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.0.2'
|
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
- Gamepad button combos to emulate missing Select and Guide buttons have been reintroduced
|
||||||
|
- For gamepads without a Select button, LB+Start will trigger the Select button and RB+Start will trigger the Guide button
|
||||||
|
- For gamepads with a Select button, Start+Select will trigger the Guide button
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
- Enabled raw mouse input on the Nvidia Shield TV to avoid mouse acceleration
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
- Fixed missing video or audio when streaming over some Internet connections
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
#Thu May 28 11:41:09 PDT 2020
|
#Mon Oct 12 13:42:18 CDT 2020
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
|
||||||
Reference in new issue
Block a user