Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c8f1f9325e | |||
| 658940d3fb | |||
| 51b4ca401e | |||
| 10e4ca4ef3 | |||
| 2bcc2bdfe5 | |||
| 6462b580bb | |||
| b83d91c944 | |||
| 07f842bc9e | |||
| 3913e845fa | |||
| 09f0913974 | |||
| aa9ca35115 | |||
| 010dfdf834 | |||
| 150fac9c09 | |||
| ec3aef13d8 | |||
| 2b56005bd2 | |||
| 9bc893b6ad | |||
| 3feb92e788 | |||
| 1265952814 | |||
| f5ad5d97db | |||
| 5ac0939731 | |||
| b653694860 | |||
| 49051a5095 | |||
| 7734de6465 | |||
| edac646434 | |||
| 51c7665fdc | |||
| 37545821fc | |||
| 8a1ed0f146 | |||
| 7a0228fb81 | |||
| 3aecf9e031 | |||
| c2d4d221af | |||
| 53f89fbe22 |
+2
-2
@@ -9,8 +9,8 @@ android {
|
||||
minSdk 16
|
||||
targetSdk 33
|
||||
|
||||
versionName "10.7"
|
||||
versionCode = 286
|
||||
versionName "10.8.1"
|
||||
versionCode = 288
|
||||
|
||||
// Generate native debug symbols to allow Google Play to symbolicate our native crashes
|
||||
ndk.debugSymbolLevel = 'FULL'
|
||||
|
||||
@@ -124,11 +124,9 @@
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="com.limelight.PcView" />
|
||||
</activity>
|
||||
<!-- This will fall back to sensorLandscape at runtime on Android 4.2 and below -->
|
||||
<activity
|
||||
android:name=".Game"
|
||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
|
||||
android:screenOrientation="userLandscape"
|
||||
android:noHistory="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:resizeableActivity="true"
|
||||
|
||||
@@ -199,12 +199,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
|
||||
}
|
||||
|
||||
// We specified userLandscape in the manifest which isn't supported until 4.3,
|
||||
// so we must fall back at runtime to sensorLandscape.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
||||
}
|
||||
|
||||
// Listen for UI visibility events
|
||||
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(this);
|
||||
|
||||
@@ -222,6 +216,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
prefConfig = PreferenceConfiguration.readPreferences(this);
|
||||
tombstonePrefs = Game.this.getSharedPreferences("DecoderTombstone", 0);
|
||||
|
||||
// Enter landscape unless we're on a square screen
|
||||
setPreferredOrientationForCurrentDisplay();
|
||||
|
||||
if (prefConfig.stretchVideo || shouldIgnoreInsetsForResolution(prefConfig.width, prefConfig.height)) {
|
||||
// Allow the activity to layout under notches if the fill-screen option
|
||||
// was turned on by the user or it's a full-screen native resolution
|
||||
@@ -241,6 +238,24 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
streamView.setOnTouchListener(this);
|
||||
streamView.setInputCallbacks(this);
|
||||
|
||||
boolean needsInputBatching = false;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
// Request unbuffered input event dispatching for all input classes we handle here.
|
||||
// Without this, input events are buffered to be delivered in lock-step with VBlank,
|
||||
// artificially increasing input latency while streaming.
|
||||
streamView.requestUnbufferedDispatch(
|
||||
InputDevice.SOURCE_CLASS_BUTTON | // Keyboards
|
||||
InputDevice.SOURCE_CLASS_JOYSTICK | // Gamepads
|
||||
InputDevice.SOURCE_CLASS_POINTER | // Touchscreens and mice (w/o pointer capture)
|
||||
InputDevice.SOURCE_CLASS_POSITION | // Touchpads
|
||||
InputDevice.SOURCE_CLASS_TRACKBALL // Mice (pointer capture)
|
||||
);
|
||||
|
||||
// Since the OS isn't going to batch for us, we have to batch mouse events to
|
||||
// avoid triggering a bug in GeForce Experience that can lead to massive latency.
|
||||
needsInputBatching = true;
|
||||
}
|
||||
|
||||
notificationOverlayView = findViewById(R.id.notificationOverlay);
|
||||
|
||||
performanceOverlayView = findViewById(R.id.performanceOverlay);
|
||||
@@ -453,7 +468,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
.build();
|
||||
|
||||
// Initialize the connection
|
||||
conn = new NvConnection(host, uniqueId, config, PlatformBinding.getCryptoProvider(this), serverCert);
|
||||
conn = new NvConnection(host, uniqueId, config, PlatformBinding.getCryptoProvider(this), serverCert, needsInputBatching);
|
||||
controllerHandler = new ControllerHandler(this, conn, this, prefConfig);
|
||||
keyboardTranslator = new KeyboardTranslator();
|
||||
|
||||
@@ -510,10 +525,72 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
streamView.getHolder().addCallback(this);
|
||||
}
|
||||
|
||||
private void setPreferredOrientationForCurrentDisplay() {
|
||||
Display display = getWindowManager().getDefaultDisplay();
|
||||
|
||||
// For semi-square displays, we use more complex logic to determine which orientation to use (if any)
|
||||
if (PreferenceConfiguration.isSquarishScreen(display)) {
|
||||
int desiredOrientation = Configuration.ORIENTATION_UNDEFINED;
|
||||
|
||||
// OSC doesn't properly support portrait displays, so don't use it in portrait mode by default
|
||||
if (prefConfig.onscreenController) {
|
||||
desiredOrientation = Configuration.ORIENTATION_LANDSCAPE;
|
||||
}
|
||||
|
||||
// For native resolution, we will lock the orientation to the one that matches the specified resolution
|
||||
if (PreferenceConfiguration.isNativeResolution(prefConfig.width, prefConfig.height)) {
|
||||
if (prefConfig.width > prefConfig.height) {
|
||||
desiredOrientation = Configuration.ORIENTATION_LANDSCAPE;
|
||||
}
|
||||
else {
|
||||
desiredOrientation = Configuration.ORIENTATION_PORTRAIT;
|
||||
}
|
||||
}
|
||||
|
||||
if (desiredOrientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
|
||||
}
|
||||
else {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
||||
}
|
||||
}
|
||||
else if (desiredOrientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT);
|
||||
}
|
||||
else {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If we don't have a reason to lock to portrait or landscape, allow any orientation
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
|
||||
}
|
||||
else {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// For regular displays, we always request landscape
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
|
||||
}
|
||||
else {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
// Set requested orientation for possible new screen size
|
||||
setPreferredOrientationForCurrentDisplay();
|
||||
|
||||
if (virtualController != null) {
|
||||
// Refresh layout of OSC for possible new screen size
|
||||
virtualController.refreshLayout();
|
||||
@@ -701,6 +778,12 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean mayReduceRefreshRate() {
|
||||
return prefConfig.framePacing == PreferenceConfiguration.FRAME_PACING_CAP_FPS ||
|
||||
prefConfig.framePacing == PreferenceConfiguration.FRAME_PACING_MAX_SMOOTHNESS ||
|
||||
(prefConfig.framePacing == PreferenceConfiguration.FRAME_PACING_BALANCED && prefConfig.reduceRefreshRate);
|
||||
}
|
||||
|
||||
private float prepareDisplayForRendering() {
|
||||
Display display = getWindowManager().getDefaultDisplay();
|
||||
WindowManager.LayoutParams windowLayoutParams = getWindow().getAttributes();
|
||||
@@ -712,7 +795,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
boolean isNativeResolutionStream = PreferenceConfiguration.isNativeResolution(prefConfig.width, prefConfig.height);
|
||||
boolean refreshRateIsGood = isRefreshRateGoodMatch(bestMode.getRefreshRate());
|
||||
boolean refreshRateIsEqual = isRefreshRateEqualMatch(bestMode.getRefreshRate());
|
||||
boolean isTelevision = getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
|
||||
|
||||
for (Display.Mode candidate : display.getSupportedModes()) {
|
||||
boolean refreshRateReduced = candidate.getRefreshRate() < bestMode.getRefreshRate();
|
||||
@@ -745,8 +827,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prefConfig.framePacing != PreferenceConfiguration.FRAME_PACING_MIN_LATENCY &&
|
||||
refreshRateIsEqual && !isRefreshRateEqualMatch(candidate.getRefreshRate())) {
|
||||
if (mayReduceRefreshRate() && refreshRateIsEqual && !isRefreshRateEqualMatch(candidate.getRefreshRate())) {
|
||||
// If we had an equal refresh rate and this one is not, skip it. In min latency
|
||||
// mode, we want to always prefer the highest frame rate even though it may cause
|
||||
// microstuttering.
|
||||
@@ -759,21 +840,17 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
continue;
|
||||
}
|
||||
|
||||
// We don't want ever reduce our refresh rate unless we found an exact
|
||||
// match and we're not in min latency mode.
|
||||
if (refreshRateReduced) {
|
||||
if (prefConfig.framePacing == PreferenceConfiguration.FRAME_PACING_MIN_LATENCY) {
|
||||
if (mayReduceRefreshRate()) {
|
||||
// User asked for the lowest possible refresh rate, so don't raise it if we
|
||||
// have a good match already
|
||||
if (candidate.getRefreshRate() > bestMode.getRefreshRate()) {
|
||||
continue;
|
||||
}
|
||||
else if (!isRefreshRateEqualMatch(candidate.getRefreshRate())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// For refresh rates lower than 50hz, we want to check if the device is a TV.
|
||||
// Some TV's may have issues when attempting to lower its refresh rate
|
||||
// As opposed to mobile devices, which are designed to lower refresh rate
|
||||
// for battery life reasons.
|
||||
else if(isTelevision && candidate.getRefreshRate() < 50) {
|
||||
}
|
||||
else {
|
||||
// User asked for the highest possible refresh rate, so don't reduce it if we
|
||||
// have a good match already
|
||||
if (refreshRateReduced) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1316,7 +1393,27 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
event.getToolType(0) == MotionEvent.TOOL_TYPE_ERASER)) ||
|
||||
eventSource == 12290) // 12290 = Samsung DeX mode desktop mouse
|
||||
{
|
||||
int changedButtons = event.getButtonState() ^ lastButtonState;
|
||||
int buttonState = event.getButtonState();
|
||||
int changedButtons = buttonState ^ lastButtonState;
|
||||
|
||||
// The DeX touchpad on the Fold 4 sends proper right click events using BUTTON_SECONDARY,
|
||||
// but doesn't send BUTTON_PRIMARY for a regular click. Instead it sends ACTION_DOWN/UP,
|
||||
// so we need to fix that up to look like a sane input event to process it correctly.
|
||||
if (eventSource == 12290) {
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
||||
buttonState |= MotionEvent.BUTTON_PRIMARY;
|
||||
}
|
||||
else if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||
buttonState &= ~MotionEvent.BUTTON_PRIMARY;
|
||||
}
|
||||
else {
|
||||
// We may be faking the primary button down from a previous event,
|
||||
// so be sure to add that bit back into the button state.
|
||||
buttonState |= (lastButtonState & MotionEvent.BUTTON_PRIMARY);
|
||||
}
|
||||
|
||||
changedButtons = buttonState ^ lastButtonState;
|
||||
}
|
||||
|
||||
// Ignore mouse input if we're not capturing from our input source
|
||||
if (!inputCaptureProvider.isCapturingActive()) {
|
||||
@@ -1379,7 +1476,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
}
|
||||
|
||||
if ((changedButtons & MotionEvent.BUTTON_PRIMARY) != 0) {
|
||||
if ((event.getButtonState() & MotionEvent.BUTTON_PRIMARY) != 0) {
|
||||
if ((buttonState & MotionEvent.BUTTON_PRIMARY) != 0) {
|
||||
conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_LEFT);
|
||||
}
|
||||
else {
|
||||
@@ -1389,7 +1486,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
|
||||
// Mouse secondary or stylus primary is right click (stylus down is left click)
|
||||
if ((changedButtons & (MotionEvent.BUTTON_SECONDARY | MotionEvent.BUTTON_STYLUS_PRIMARY)) != 0) {
|
||||
if ((event.getButtonState() & (MotionEvent.BUTTON_SECONDARY | MotionEvent.BUTTON_STYLUS_PRIMARY)) != 0) {
|
||||
if ((buttonState & (MotionEvent.BUTTON_SECONDARY | MotionEvent.BUTTON_STYLUS_PRIMARY)) != 0) {
|
||||
conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_RIGHT);
|
||||
}
|
||||
else {
|
||||
@@ -1399,7 +1496,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
|
||||
// Mouse tertiary or stylus secondary is middle click
|
||||
if ((changedButtons & (MotionEvent.BUTTON_TERTIARY | MotionEvent.BUTTON_STYLUS_SECONDARY)) != 0) {
|
||||
if ((event.getButtonState() & (MotionEvent.BUTTON_TERTIARY | MotionEvent.BUTTON_STYLUS_SECONDARY)) != 0) {
|
||||
if ((buttonState & (MotionEvent.BUTTON_TERTIARY | MotionEvent.BUTTON_STYLUS_SECONDARY)) != 0) {
|
||||
conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_MIDDLE);
|
||||
}
|
||||
else {
|
||||
@@ -1409,7 +1506,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
|
||||
if (prefConfig.mouseNavButtons) {
|
||||
if ((changedButtons & MotionEvent.BUTTON_BACK) != 0) {
|
||||
if ((event.getButtonState() & MotionEvent.BUTTON_BACK) != 0) {
|
||||
if ((buttonState & MotionEvent.BUTTON_BACK) != 0) {
|
||||
conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_X1);
|
||||
}
|
||||
else {
|
||||
@@ -1418,7 +1515,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
}
|
||||
|
||||
if ((changedButtons & MotionEvent.BUTTON_FORWARD) != 0) {
|
||||
if ((event.getButtonState() & MotionEvent.BUTTON_FORWARD) != 0) {
|
||||
if ((buttonState & MotionEvent.BUTTON_FORWARD) != 0) {
|
||||
conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_X2);
|
||||
}
|
||||
else {
|
||||
@@ -1465,7 +1562,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
}
|
||||
}
|
||||
|
||||
lastButtonState = event.getButtonState();
|
||||
lastButtonState = buttonState;
|
||||
}
|
||||
// This case is for fingers
|
||||
else
|
||||
@@ -1652,6 +1749,14 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent event) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
// Tell the OS not to buffer input events for us
|
||||
//
|
||||
// NB: This is still needed even when we call the newer requestUnbufferedDispatch()!
|
||||
view.requestUnbufferedDispatch(event);
|
||||
}
|
||||
}
|
||||
return handleMotionEvent(view, event);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
||||
private boolean submittedCsd;
|
||||
private boolean submitCsdNextCall;
|
||||
|
||||
private int nextInputBufferIndex = -1;
|
||||
private ByteBuffer nextInputBuffer;
|
||||
|
||||
private Context context;
|
||||
private MediaCodec videoDecoder;
|
||||
private Thread rendererThread;
|
||||
@@ -374,6 +377,8 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
||||
legacyInputBuffers = videoDecoder.getInputBuffers();
|
||||
}
|
||||
|
||||
fetchNextInputBuffer();
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -682,19 +687,37 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
||||
rendererThread.start();
|
||||
}
|
||||
|
||||
private int dequeueInputBuffer() {
|
||||
int index = -1;
|
||||
private boolean fetchNextInputBuffer() {
|
||||
long startTime;
|
||||
|
||||
if (nextInputBufferIndex >= 0) {
|
||||
// We already have an input buffer
|
||||
return true;
|
||||
}
|
||||
|
||||
startTime = SystemClock.uptimeMillis();
|
||||
|
||||
try {
|
||||
while (index < 0 && !stopping) {
|
||||
index = videoDecoder.dequeueInputBuffer(10000);
|
||||
while (nextInputBufferIndex < 0 && !stopping) {
|
||||
nextInputBufferIndex = videoDecoder.dequeueInputBuffer(10000);
|
||||
}
|
||||
|
||||
if (nextInputBufferIndex >= 0) {
|
||||
// Using the new getInputBuffer() API on Lollipop allows
|
||||
// the framework to do some performance optimizations for us
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
nextInputBuffer = videoDecoder.getInputBuffer(nextInputBufferIndex);
|
||||
}
|
||||
else {
|
||||
nextInputBuffer = legacyInputBuffers[nextInputBufferIndex];
|
||||
|
||||
// Clear old input data pre-Lollipop
|
||||
nextInputBuffer.clear();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
handleDecoderException(e, null, 0, true);
|
||||
return MediaCodec.INFO_TRY_AGAIN_LATER;
|
||||
return false;
|
||||
}
|
||||
|
||||
int deltaMs = (int)(SystemClock.uptimeMillis() - startTime);
|
||||
@@ -703,7 +726,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
||||
LimeLog.warning("Dequeue input buffer ran long: " + deltaMs + " ms");
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
if (nextInputBufferIndex < 0) {
|
||||
// We've been hung for 5 seconds and no other exception was reported,
|
||||
// so generate a decoder hung exception
|
||||
if (deltaMs >= 5000 && initialException == null) {
|
||||
@@ -714,10 +737,11 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
||||
}
|
||||
throw new RendererException(this, decoderHungException);
|
||||
}
|
||||
return index;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return index;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -793,39 +817,24 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
||||
// TODO: Set HDR metadata?
|
||||
}
|
||||
|
||||
private boolean queueInputBuffer(int inputBufferIndex, int offset, int length, long timestampUs, int codecFlags) {
|
||||
private boolean queueNextInputBuffer(long timestampUs, int codecFlags) {
|
||||
try {
|
||||
videoDecoder.queueInputBuffer(inputBufferIndex,
|
||||
offset, length,
|
||||
videoDecoder.queueInputBuffer(nextInputBufferIndex,
|
||||
0, nextInputBuffer.position(),
|
||||
timestampUs, codecFlags);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
handleDecoderException(e, null, codecFlags, true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Using the new getInputBuffer() API on Lollipop allows
|
||||
// the framework to do some performance optimizations for us
|
||||
private ByteBuffer getEmptyInputBuffer(int inputBufferIndex) {
|
||||
ByteBuffer buf;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
try {
|
||||
buf = videoDecoder.getInputBuffer(inputBufferIndex);
|
||||
} catch (Exception e) {
|
||||
handleDecoderException(e, null, 0, true);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
buf = legacyInputBuffers[inputBufferIndex];
|
||||
|
||||
// Clear old input data pre-Lollipop
|
||||
buf.clear();
|
||||
} finally {
|
||||
nextInputBufferIndex = -1;
|
||||
nextInputBuffer = null;
|
||||
}
|
||||
|
||||
return buf;
|
||||
// Fetch a new input buffer now while we have some time between frames
|
||||
// to have it ready immediately when the next frame arrives.
|
||||
fetchNextInputBuffer();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void doProfileSpecificSpsPatching(SeqParameterSet sps) {
|
||||
@@ -904,19 +913,18 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
||||
activeWindowVideoStats.measurementStartTimestamp = SystemClock.uptimeMillis();
|
||||
}
|
||||
|
||||
int inputBufferIndex;
|
||||
ByteBuffer buf;
|
||||
long timestampUs;
|
||||
int codecFlags = 0;
|
||||
|
||||
// H264 SPS
|
||||
if (decodeUnitData[4] == 0x67) {
|
||||
if (decodeUnitType == MoonBridge.BUFFER_TYPE_SPS && (videoFormat & MoonBridge.VIDEO_FORMAT_MASK_H264) != 0) {
|
||||
numSpsIn++;
|
||||
|
||||
ByteBuffer spsBuf = ByteBuffer.wrap(decodeUnitData);
|
||||
int startSeqLen = decodeUnitData[2] == 0x01 ? 3 : 4;
|
||||
|
||||
// Skip to the start of the NALU data
|
||||
spsBuf.position(5);
|
||||
spsBuf.position(startSeqLen + 1);
|
||||
|
||||
// The H264Utils.readSPS function safely handles
|
||||
// Annex B NALUs (including NALUs with escape sequences)
|
||||
@@ -1020,9 +1028,9 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
||||
ByteBuffer escapedNalu = H264Utils.writeSPS(sps, decodeUnitLength);
|
||||
|
||||
// Batch this to submit together with PPS
|
||||
spsBuffer = new byte[5 + escapedNalu.limit()];
|
||||
System.arraycopy(decodeUnitData, 0, spsBuffer, 0, 5);
|
||||
escapedNalu.get(spsBuffer, 5, escapedNalu.limit());
|
||||
spsBuffer = new byte[startSeqLen + 1 + escapedNalu.limit()];
|
||||
System.arraycopy(decodeUnitData, 0, spsBuffer, 0, startSeqLen + 1);
|
||||
escapedNalu.get(spsBuffer, startSeqLen + 1, escapedNalu.limit());
|
||||
return MoonBridge.DR_OK;
|
||||
}
|
||||
else if (decodeUnitType == MoonBridge.BUFFER_TYPE_VPS) {
|
||||
@@ -1049,25 +1057,17 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
||||
// fused IDR frames, we will submit the CSD blob in a
|
||||
// separate input buffer.
|
||||
if (!submittedCsd || !fusedIdrFrame) {
|
||||
inputBufferIndex = dequeueInputBuffer();
|
||||
if (inputBufferIndex < 0) {
|
||||
// We're being torn down now
|
||||
return MoonBridge.DR_NEED_IDR;
|
||||
}
|
||||
|
||||
buf = getEmptyInputBuffer(inputBufferIndex);
|
||||
if (buf == null) {
|
||||
// We're being torn down now
|
||||
if (!fetchNextInputBuffer()) {
|
||||
return MoonBridge.DR_NEED_IDR;
|
||||
}
|
||||
|
||||
// When we get the PPS, submit the VPS and SPS together with
|
||||
// the PPS, as required by AOSP docs on use of MediaCodec.
|
||||
if (vpsBuffer != null) {
|
||||
buf.put(vpsBuffer);
|
||||
nextInputBuffer.put(vpsBuffer);
|
||||
}
|
||||
if (spsBuffer != null) {
|
||||
buf.put(spsBuffer);
|
||||
nextInputBuffer.put(spsBuffer);
|
||||
}
|
||||
|
||||
// This is the CSD blob
|
||||
@@ -1096,27 +1096,19 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
||||
activeWindowVideoStats.totalTimeMs += enqueueTimeMs - receiveTimeMs;
|
||||
}
|
||||
|
||||
inputBufferIndex = dequeueInputBuffer();
|
||||
if (inputBufferIndex < 0) {
|
||||
// We're being torn down now
|
||||
return MoonBridge.DR_NEED_IDR;
|
||||
}
|
||||
|
||||
buf = getEmptyInputBuffer(inputBufferIndex);
|
||||
if (buf == null) {
|
||||
// We're being torn down now
|
||||
if (!fetchNextInputBuffer()) {
|
||||
return MoonBridge.DR_NEED_IDR;
|
||||
}
|
||||
|
||||
if (submitCsdNextCall) {
|
||||
if (vpsBuffer != null) {
|
||||
buf.put(vpsBuffer);
|
||||
nextInputBuffer.put(vpsBuffer);
|
||||
}
|
||||
if (spsBuffer != null) {
|
||||
buf.put(spsBuffer);
|
||||
nextInputBuffer.put(spsBuffer);
|
||||
}
|
||||
if (ppsBuffer != null) {
|
||||
buf.put(ppsBuffer);
|
||||
nextInputBuffer.put(ppsBuffer);
|
||||
}
|
||||
|
||||
submitCsdNextCall = false;
|
||||
@@ -1139,9 +1131,9 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
||||
numFramesIn++;
|
||||
}
|
||||
|
||||
if (decodeUnitLength > buf.limit() - buf.position()) {
|
||||
if (decodeUnitLength > nextInputBuffer.limit() - nextInputBuffer.position()) {
|
||||
IllegalArgumentException exception = new IllegalArgumentException(
|
||||
"Decode unit length "+decodeUnitLength+" too large for input buffer "+buf.limit());
|
||||
"Decode unit length "+decodeUnitLength+" too large for input buffer "+nextInputBuffer.limit());
|
||||
if (!reportedCrash) {
|
||||
reportedCrash = true;
|
||||
crashListener.notifyCrash(exception);
|
||||
@@ -1150,11 +1142,9 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
||||
}
|
||||
|
||||
// Copy data from our buffer list into the input buffer
|
||||
buf.put(decodeUnitData, 0, decodeUnitLength);
|
||||
nextInputBuffer.put(decodeUnitData, 0, decodeUnitLength);
|
||||
|
||||
if (!queueInputBuffer(inputBufferIndex,
|
||||
0, buf.position(),
|
||||
timestampUs, codecFlags)) {
|
||||
if (!queueNextInputBuffer(timestampUs, codecFlags)) {
|
||||
return MoonBridge.DR_NEED_IDR;
|
||||
}
|
||||
|
||||
@@ -1176,18 +1166,12 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
||||
}
|
||||
|
||||
private boolean replaySps() {
|
||||
int inputIndex = dequeueInputBuffer();
|
||||
if (inputIndex < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ByteBuffer inputBuffer = getEmptyInputBuffer(inputIndex);
|
||||
if (inputBuffer == null) {
|
||||
if (!fetchNextInputBuffer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the Annex B header
|
||||
inputBuffer.put(new byte[]{0x00, 0x00, 0x00, 0x01, 0x67});
|
||||
nextInputBuffer.put(new byte[]{0x00, 0x00, 0x00, 0x01, 0x67});
|
||||
|
||||
// Switch the H264 profile back to high
|
||||
savedSps.profileIdc = 100;
|
||||
@@ -1198,15 +1182,13 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
||||
// The H264Utils.writeSPS function safely handles
|
||||
// Annex B NALUs (including NALUs with escape sequences)
|
||||
ByteBuffer escapedNalu = H264Utils.writeSPS(savedSps, 128);
|
||||
inputBuffer.put(escapedNalu);
|
||||
nextInputBuffer.put(escapedNalu);
|
||||
|
||||
// No need for the SPS anymore
|
||||
savedSps = null;
|
||||
|
||||
// Queue the new SPS
|
||||
return queueInputBuffer(inputIndex,
|
||||
0, inputBuffer.position(),
|
||||
0, MediaCodec.BUFFER_FLAG_CODEC_CONFIG);
|
||||
return queueNextInputBuffer(0, MediaCodec.BUFFER_FLAG_CODEC_CONFIG);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -449,13 +449,17 @@ public class MediaCodecHelper {
|
||||
}
|
||||
}
|
||||
|
||||
if (tryNumber < 2) {
|
||||
if (tryNumber < 2 &&
|
||||
(!Build.MANUFACTURER.equalsIgnoreCase("xiaomi") || Build.VERSION.SDK_INT > Build.VERSION_CODES.M)) {
|
||||
// MediaTek decoders don't use vendor-defined keys for low latency mode. Instead, they have a modified
|
||||
// version of AOSP's ACodec.cpp which supports the "vdec-lowlatency" option. This option is passed down
|
||||
// to the decoder as OMX.MTK.index.param.video.LowLatencyDecode.
|
||||
//
|
||||
// This option is also plumbed for Amazon Amlogic-based devices like the Fire TV 3. Not only does it
|
||||
// reduce latency on Amlogic, it fixes the HEVC bug that causes the decoder to not output any frames.
|
||||
// Unfortunately, it does the exact opposite for the Xiaomi MITV4-ANSM0, breaking it in the way that
|
||||
// Fire TV was broken prior to vdec-lowlatency :(
|
||||
//
|
||||
// On Fire TV 3, vdec-lowlatency is translated to OMX.amazon.fireos.index.video.lowLatencyDecode.
|
||||
//
|
||||
// https://github.com/yuan1617/Framwork/blob/master/frameworks/av/media/libstagefright/ACodec.cpp
|
||||
|
||||
@@ -7,6 +7,8 @@ import java.nio.ByteBuffer;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import javax.crypto.KeyGenerator;
|
||||
@@ -33,12 +35,20 @@ public class NvConnection {
|
||||
private ConnectionContext context;
|
||||
private static Semaphore connectionAllowed = new Semaphore(1);
|
||||
private final boolean isMonkey;
|
||||
|
||||
public NvConnection(String host, String uniqueId, StreamConfiguration config, LimelightCryptoProvider cryptoProvider, X509Certificate serverCert)
|
||||
private final boolean batchMouseInput;
|
||||
|
||||
private static final int MOUSE_BATCH_PERIOD_MS = 5;
|
||||
private Timer mouseInputTimer;
|
||||
private final Object mouseInputLock = new Object();
|
||||
private short relMouseX, relMouseY, relMouseWidth, relMouseHeight;
|
||||
private short absMouseX, absMouseY, absMouseWidth, absMouseHeight;
|
||||
|
||||
public NvConnection(String host, String uniqueId, StreamConfiguration config, LimelightCryptoProvider cryptoProvider, X509Certificate serverCert, boolean batchMouseInput)
|
||||
{
|
||||
this.host = host;
|
||||
this.cryptoProvider = cryptoProvider;
|
||||
this.uniqueId = uniqueId;
|
||||
this.batchMouseInput = batchMouseInput;
|
||||
|
||||
this.context = new ConnectionContext();
|
||||
this.context.streamConfig = config;
|
||||
@@ -70,6 +80,11 @@ public class NvConnection {
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
// Stop sending additional input
|
||||
if (mouseInputTimer != null) {
|
||||
mouseInputTimer.cancel();
|
||||
}
|
||||
|
||||
// Interrupt any pending connection. This is thread-safe.
|
||||
MoonBridge.interruptConnection();
|
||||
|
||||
@@ -83,6 +98,24 @@ public class NvConnection {
|
||||
// Now a pending connection can be processed
|
||||
connectionAllowed.release();
|
||||
}
|
||||
|
||||
private void flushMousePosition() {
|
||||
synchronized (mouseInputLock) {
|
||||
if (relMouseX != 0 || relMouseY != 0) {
|
||||
if (relMouseWidth != 0 || relMouseHeight != 0) {
|
||||
MoonBridge.sendMouseMoveAsMousePosition(relMouseX, relMouseY, relMouseWidth, relMouseHeight);
|
||||
}
|
||||
else {
|
||||
MoonBridge.sendMouseMove(relMouseX, relMouseY);
|
||||
}
|
||||
relMouseX = relMouseY = relMouseWidth = relMouseHeight = 0;
|
||||
}
|
||||
if (absMouseX != 0 || absMouseY != 0 || absMouseWidth != 0 || absMouseHeight != 0) {
|
||||
MoonBridge.sendMousePosition(absMouseX, absMouseY, absMouseWidth, absMouseHeight);
|
||||
absMouseX = absMouseY = absMouseWidth = absMouseHeight = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean startApp() throws XmlPullParserException, IOException
|
||||
{
|
||||
@@ -292,6 +325,21 @@ public class NvConnection {
|
||||
// to stop the connection themselves. We need to release their
|
||||
// semaphore count for them.
|
||||
connectionAllowed.release();
|
||||
return;
|
||||
}
|
||||
|
||||
if (batchMouseInput) {
|
||||
// High polling rate mice can cause GeForce Experience's input queue to get backed up,
|
||||
// causing massive input latency. We counter this by limiting our mouse events to 200 Hz
|
||||
// which appears to avoid triggering the issue on all known configurations.
|
||||
mouseInputTimer = new Timer("MouseInput", true);
|
||||
mouseInputTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Flush the mouse position every 5 ms
|
||||
flushMousePosition();
|
||||
}
|
||||
}, MOUSE_BATCH_PERIOD_MS, MOUSE_BATCH_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -301,27 +349,65 @@ public class NvConnection {
|
||||
public void sendMouseMove(final short deltaX, final short deltaY)
|
||||
{
|
||||
if (!isMonkey) {
|
||||
MoonBridge.sendMouseMove(deltaX, deltaY);
|
||||
synchronized (mouseInputLock) {
|
||||
relMouseX += deltaX;
|
||||
relMouseY += deltaY;
|
||||
|
||||
// Reset these to ensure we don't send this as a position update
|
||||
relMouseWidth = 0;
|
||||
relMouseHeight = 0;
|
||||
}
|
||||
|
||||
if (!batchMouseInput) {
|
||||
flushMousePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMousePosition(short x, short y, short referenceWidth, short referenceHeight)
|
||||
{
|
||||
if (!isMonkey) {
|
||||
MoonBridge.sendMousePosition(x, y, referenceWidth, referenceHeight);
|
||||
synchronized (mouseInputLock) {
|
||||
absMouseX = x;
|
||||
absMouseY = y;
|
||||
absMouseWidth = referenceWidth;
|
||||
absMouseHeight = referenceHeight;
|
||||
}
|
||||
|
||||
if (!batchMouseInput) {
|
||||
flushMousePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMouseMoveAsMousePosition(short deltaX, short deltaY, short referenceWidth, short referenceHeight)
|
||||
{
|
||||
if (!isMonkey) {
|
||||
MoonBridge.sendMouseMoveAsMousePosition(deltaX, deltaY, referenceWidth, referenceHeight);
|
||||
synchronized (mouseInputLock) {
|
||||
// Only accumulate the delta if the reference size is the same
|
||||
if (relMouseWidth == referenceWidth && relMouseHeight == referenceHeight) {
|
||||
relMouseX += deltaX;
|
||||
relMouseY += deltaY;
|
||||
}
|
||||
else {
|
||||
relMouseX = deltaX;
|
||||
relMouseY = deltaY;
|
||||
}
|
||||
|
||||
relMouseWidth = referenceWidth;
|
||||
relMouseHeight = referenceHeight;
|
||||
}
|
||||
|
||||
if (!batchMouseInput) {
|
||||
flushMousePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMouseButtonDown(final byte mouseButton)
|
||||
{
|
||||
if (!isMonkey) {
|
||||
flushMousePosition();
|
||||
MoonBridge.sendMouseButton(MouseButtonPacket.PRESS_EVENT, mouseButton);
|
||||
}
|
||||
}
|
||||
@@ -329,6 +415,7 @@ public class NvConnection {
|
||||
public void sendMouseButtonUp(final byte mouseButton)
|
||||
{
|
||||
if (!isMonkey) {
|
||||
flushMousePosition();
|
||||
MoonBridge.sendMouseButton(MouseButtonPacket.RELEASE_EVENT, mouseButton);
|
||||
}
|
||||
}
|
||||
@@ -364,12 +451,14 @@ public class NvConnection {
|
||||
|
||||
public void sendMouseScroll(final byte scrollClicks) {
|
||||
if (!isMonkey) {
|
||||
flushMousePosition();
|
||||
MoonBridge.sendMouseScroll(scrollClicks);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMouseHighResScroll(final short scrollAmount) {
|
||||
if (!isMonkey) {
|
||||
flushMousePosition();
|
||||
MoonBridge.sendMouseHighResScroll(scrollAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.Display;
|
||||
|
||||
import com.limelight.nvstream.jni.MoonBridge;
|
||||
|
||||
@@ -46,6 +47,7 @@ public class PreferenceConfiguration {
|
||||
private static final String FRAME_PACING_PREF_STRING = "frame_pacing";
|
||||
private static final String ABSOLUTE_MOUSE_MODE_PREF_STRING = "checkbox_absolute_mouse_mode";
|
||||
private static final String ENABLE_AUDIO_FX_PREF_STRING = "checkbox_enable_audiofx";
|
||||
private static final String REDUCE_REFRESH_RATE_PREF_STRING = "checkbox_reduce_refresh_rate";
|
||||
|
||||
static final String DEFAULT_RESOLUTION = "1280x720";
|
||||
static final String DEFAULT_FPS = "60";
|
||||
@@ -77,6 +79,7 @@ public class PreferenceConfiguration {
|
||||
private static final String DEFAULT_FRAME_PACING = "latency";
|
||||
private static final boolean DEFAULT_ABSOLUTE_MOUSE_MODE = false;
|
||||
private static final boolean DEFAULT_ENABLE_AUDIO_FX = false;
|
||||
private static final boolean DEFAULT_REDUCE_REFRESH_RATE = false;
|
||||
|
||||
public static final int FORCE_H265_ON = -1;
|
||||
public static final int AUTOSELECT_H265 = 0;
|
||||
@@ -120,6 +123,7 @@ public class PreferenceConfiguration {
|
||||
public int framePacing;
|
||||
public boolean absoluteMouseMode;
|
||||
public boolean enableAudioFx;
|
||||
public boolean reduceRefreshRate;
|
||||
|
||||
public static boolean isNativeResolution(int width, int height) {
|
||||
// It's not a native resolution if it matches an existing resolution option
|
||||
@@ -145,6 +149,31 @@ public class PreferenceConfiguration {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we have a screen that has semi-square dimensions, we may want to change our behavior
|
||||
// to allow any orientation and vertical+horizontal resolutions.
|
||||
public static boolean isSquarishScreen(int width, int height) {
|
||||
float longDim = Math.max(width, height);
|
||||
float shortDim = Math.min(width, height);
|
||||
|
||||
// We just put the arbitrary cutoff for a square-ish screen at 1.3
|
||||
return longDim / shortDim < 1.3f;
|
||||
}
|
||||
|
||||
public static boolean isSquarishScreen(Display display) {
|
||||
int width, height;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
width = display.getMode().getPhysicalWidth();
|
||||
height = display.getMode().getPhysicalHeight();
|
||||
}
|
||||
else {
|
||||
width = display.getWidth();
|
||||
height = display.getHeight();
|
||||
}
|
||||
|
||||
return isSquarishScreen(width, height);
|
||||
}
|
||||
|
||||
private static String convertFromLegacyResolutionString(String resString) {
|
||||
if (resString.equalsIgnoreCase("360p")) {
|
||||
return RES_360P;
|
||||
@@ -475,6 +504,7 @@ public class PreferenceConfiguration {
|
||||
config.enableLatencyToast = prefs.getBoolean(LATENCY_TOAST_PREF_STRING, DEFAULT_LATENCY_TOAST);
|
||||
config.absoluteMouseMode = prefs.getBoolean(ABSOLUTE_MOUSE_MODE_PREF_STRING, DEFAULT_ABSOLUTE_MOUSE_MODE);
|
||||
config.enableAudioFx = prefs.getBoolean(ENABLE_AUDIO_FX_PREF_STRING, DEFAULT_ENABLE_AUDIO_FX);
|
||||
config.reduceRefreshRate = prefs.getBoolean(REDUCE_REFRESH_RATE_PREF_STRING, DEFAULT_REDUCE_REFRESH_RATE);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@@ -38,11 +39,16 @@ import java.util.Arrays;
|
||||
|
||||
public class StreamSettings extends Activity {
|
||||
private PreferenceConfiguration previousPrefs;
|
||||
private int previousDisplayPixelCount;
|
||||
|
||||
// HACK for Android 9
|
||||
static DisplayCutout displayCutoutP;
|
||||
|
||||
void reloadSettings() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
Display.Mode mode = getWindowManager().getDefaultDisplay().getMode();
|
||||
previousDisplayPixelCount = mode.getPhysicalWidth() * mode.getPhysicalHeight();
|
||||
}
|
||||
getFragmentManager().beginTransaction().replace(
|
||||
R.id.stream_settings, new SettingsFragment()
|
||||
).commitAllowingStateLoss();
|
||||
@@ -79,6 +85,24 @@ public class StreamSettings extends Activity {
|
||||
reloadSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
Display.Mode mode = getWindowManager().getDefaultDisplay().getMode();
|
||||
|
||||
// If the display's physical pixel count has changed, we consider that it's a new display
|
||||
// and we should reload our settings (which include display-dependent values).
|
||||
//
|
||||
// NB: We aren't using displayId here because that stays the same (DEFAULT_DISPLAY) when
|
||||
// switching between screens on a foldable device.
|
||||
if (mode.getPhysicalWidth() * mode.getPhysicalHeight() != previousDisplayPixelCount) {
|
||||
reloadSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
// NOTE: This will NOT be called on Android 13+ with android:enableOnBackInvokedCallback="true"
|
||||
public void onBackPressed() {
|
||||
@@ -106,7 +130,7 @@ public class StreamSettings extends Activity {
|
||||
pref.setValue(value);
|
||||
}
|
||||
|
||||
private void addNativeResolutionEntry(int nativeWidth, int nativeHeight, boolean insetsRemoved) {
|
||||
private void addNativeResolutionEntry(int nativeWidth, int nativeHeight, boolean insetsRemoved, boolean portrait) {
|
||||
ListPreference pref = (ListPreference) findPreference(PreferenceConfiguration.RESOLUTION_PREF_STRING);
|
||||
|
||||
String newName;
|
||||
@@ -118,6 +142,15 @@ public class StreamSettings extends Activity {
|
||||
newName = getResources().getString(R.string.resolution_prefix_native);
|
||||
}
|
||||
|
||||
if (PreferenceConfiguration.isSquarishScreen(nativeWidth, nativeHeight)) {
|
||||
if (portrait) {
|
||||
newName += " " + getResources().getString(R.string.resolution_prefix_native_portrait);
|
||||
}
|
||||
else {
|
||||
newName += " " + getResources().getString(R.string.resolution_prefix_native_landscape);
|
||||
}
|
||||
}
|
||||
|
||||
newName += " ("+nativeWidth+"x"+nativeHeight+")";
|
||||
|
||||
String newValue = nativeWidth+"x"+nativeHeight;
|
||||
@@ -147,6 +180,13 @@ public class StreamSettings extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
private void addNativeResolutionEntries(int nativeWidth, int nativeHeight, boolean insetsRemoved) {
|
||||
if (PreferenceConfiguration.isSquarishScreen(nativeWidth, nativeHeight)) {
|
||||
addNativeResolutionEntry(nativeHeight, nativeWidth, insetsRemoved, true);
|
||||
}
|
||||
addNativeResolutionEntry(nativeWidth, nativeHeight, insetsRemoved, false);
|
||||
}
|
||||
|
||||
private void removeValue(String preferenceKey, String value, Runnable onMatched) {
|
||||
int matchingCount = 0;
|
||||
|
||||
@@ -300,7 +340,7 @@ public class StreamSettings extends Activity {
|
||||
int width = Math.max(metrics.widthPixels - widthInsets, metrics.heightPixels - heightInsets);
|
||||
int height = Math.min(metrics.widthPixels - widthInsets, metrics.heightPixels - heightInsets);
|
||||
|
||||
addNativeResolutionEntry(width, height, false);
|
||||
addNativeResolutionEntries(width, height, false);
|
||||
hasInsets = true;
|
||||
}
|
||||
}
|
||||
@@ -325,7 +365,7 @@ public class StreamSettings extends Activity {
|
||||
// unless they report greater than 4K resolutions.
|
||||
if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION) ||
|
||||
(width > 3840 || height > 2160)) {
|
||||
addNativeResolutionEntry(width, height, hasInsets);
|
||||
addNativeResolutionEntries(width, height, hasInsets);
|
||||
}
|
||||
|
||||
if ((width >= 3840 || height >= 2160) && maxSupportedResW < 3840) {
|
||||
@@ -435,7 +475,7 @@ public class StreamSettings extends Activity {
|
||||
getActivity().getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
|
||||
int width = Math.max(metrics.widthPixels, metrics.heightPixels);
|
||||
int height = Math.min(metrics.widthPixels, metrics.heightPixels);
|
||||
addNativeResolutionEntry(width, height, false);
|
||||
addNativeResolutionEntries(width, height, false);
|
||||
}
|
||||
else {
|
||||
// On Android 4.1, we have to resort to reflection to invoke hidden APIs
|
||||
@@ -446,7 +486,7 @@ public class StreamSettings extends Activity {
|
||||
Method getRawWidthFunc = Display.class.getMethod("getRawWidth");
|
||||
int width = (Integer) getRawWidthFunc.invoke(display);
|
||||
int height = (Integer) getRawHeightFunc.invoke(display);
|
||||
addNativeResolutionEntry(Math.max(width, height), Math.min(width, height), false);
|
||||
addNativeResolutionEntries(Math.max(width, height), Math.min(width, height), false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Submodule app/src/main/jni/moonlight-core/moonlight-common-c updated: d247873ade...50603ac16e
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="256dp"
|
||||
android:height="256dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="256dp"
|
||||
android:height="256dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM17,13h-4v4h-2v-4L7,13v-2h4L11,7h2v4h4v2z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM17,13h-4v4h-2v-4L7,13v-2h4L11,7h2v4h4v2z" />
|
||||
</vector>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M21,2L3,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h7v2L8,20v2h8v-2h-2v-2h7c1.1,0 2,-0.9 2,-2L23,4c0,-1.1 -0.9,-2 -2,-2zM21,16L3,16L3,4h18v12z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M21,2L3,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h7v2L8,20v2h8v-2h-2v-2h7c1.1,0 2,-0.9 2,-2L23,4c0,-1.1 -0.9,-2 -2,-2zM21,16L3,16L3,4h18v12z" />
|
||||
</vector>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="256dp"
|
||||
android:height="256dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="256dp"
|
||||
android:height="256dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z"/>
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z" />
|
||||
</vector>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z" />
|
||||
</vector>
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<vector android:height="128dp" android:width="128dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z" />
|
||||
</vector>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,16.5v-9l6,4.5 -6,4.5z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM9.5,16.5v-9l7,4.5L9.5,16.5z" />
|
||||
</vector>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="256dp"
|
||||
android:height="256dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="256dp"
|
||||
android:height="256dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z" />
|
||||
</vector>
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
<string name="pcview_menu_header_offline">Offline</string>
|
||||
<string name="pcview_menu_header_online">Online</string>
|
||||
<!-- Array strings -->
|
||||
<string name="videoformat_hevcauto">Verwende HEVC so fern stabile Unterstützung vorhanden ist</string>
|
||||
<string name="videoformat_hevcauto">Automatisch</string>
|
||||
<string name="videoformat_hevcalways">Immer HEVC verwenden (könnte Crashes verursachen)</string>
|
||||
<string name="videoformat_hevcnever">Nie HEVC verwenden</string>
|
||||
<string name="title_frame_pacing">Video Frame-Pacing</string>
|
||||
@@ -242,4 +242,21 @@
|
||||
<string name="resolution_720p">720p</string>
|
||||
<string name="fps_60">60 FPS</string>
|
||||
<string name="fps_90">90 FPS</string>
|
||||
<string name="summary_troubleshooting">Tipps zur Diagnose und Behebung häufiger Streaming-Probleme anzeigen</string>
|
||||
<string name="pacing_balanced_alt">Ausbalanciert mit FPS-Limit</string>
|
||||
<string name="summary_checkbox_absolute_mouse_mode">Dies kann die Mausbeschleunigung für die Fernsteuerung natürlicher gestalten, ist aber mit vielen Spielen nicht kompatibel.</string>
|
||||
<string name="title_troubleshooting">Anleitung zur Fehlersuche</string>
|
||||
<string name="title_privacy_policy">Datenschutzbestimmungen</string>
|
||||
<string name="title_checkbox_enable_audiofx">Unterstützung des System-Equalizer aktivieren</string>
|
||||
<string name="summary_setup_guide">Zeige Anweisungen zum Einrichten Ihres Gaming-PCs für das Streaming an</string>
|
||||
<string name="title_checkbox_absolute_mouse_mode">Modus für ferngesteuerte Maus</string>
|
||||
<string name="category_help">Hilfe</string>
|
||||
<string name="title_setup_guide">Einstellungsanleitung</string>
|
||||
<string name="summary_privacy_policy">Moonlight\'s Datenschutzbestimmungen anzeigen</string>
|
||||
<string name="summary_seekbar_deadzone">Hinweis: Einige Spiele können eine größere Controller-Totzone erzwingen als die, die in Moonlight konfiguriert ist.</string>
|
||||
<string name="summary_checkbox_enable_audiofx">Ermöglicht das Funktionieren von Audioeffekten beim Streaming, kann aber die Audio-Latenz erhöhen</string>
|
||||
<string name="resolution_prefix_native_portrait">(Portrait)</string>
|
||||
<string name="title_checkbox_reduce_refresh_rate">Aktualisierungsrate verringern erlauben</string>
|
||||
<string name="summary_checkbox_reduce_refresh_rate">Durch das Verringern der Display Aktualisierungsrate, kann, auf Kosten der Video-Latenz, der Akkuverbrauch reduziert werden</string>
|
||||
<string name="resolution_prefix_native_landscape">(Landscape)</string>
|
||||
</resources>
|
||||
@@ -48,7 +48,9 @@
|
||||
<string name="conn_terminated_msg">La conexión ha finalizando</string>
|
||||
<!-- General strings -->
|
||||
<string name="ip_hint">Dirección IP del PC con GeForce</string>
|
||||
<string name="searching_pc">Buscando por PCs con GeForce Experience ejecutándose…</string>
|
||||
<string name="searching_pc">Buscando por PCs con GameStream ejecutándose...
|
||||
\n
|
||||
\nVerifica que GameStream esté activado en las opciones de SHIELD dentro de GeForce Experience.</string>
|
||||
<string name="yes">Si</string>
|
||||
<string name="no">No</string>
|
||||
<string name="lost_connection">Conexión perdida</string>
|
||||
@@ -75,7 +77,7 @@
|
||||
<!-- Preferences -->
|
||||
<string name="category_basic_settings">Configuración básica</string>
|
||||
<string name="title_resolution_list">Seleccionar resolución y FPS</string>
|
||||
<string name="summary_resolution_list">Establecer unos valores demasiado altos puede causar lag o cierres inesperados</string>
|
||||
<string name="summary_resolution_list">Establecer unos valores demasiado altos puede causar retraso o cierres inesperados.</string>
|
||||
<string name="title_seekbar_bitrate">Seleccionar bitrate de vídeo</string>
|
||||
<string name="summary_seekbar_bitrate">Usa bitrate bajo para reducir "parpadeo". Incrementa el bitrate para mayor calidad de imagen.</string>
|
||||
<string name="title_checkbox_stretch_video">Ajustar vídeo a pantalla completa</string>
|
||||
@@ -87,7 +89,7 @@
|
||||
<string name="title_seekbar_deadzone">Ajustar zona muerta del stick analógico</string>
|
||||
<string name="suffix_seekbar_deadzone">%</string>
|
||||
<string name="title_checkbox_xb1_driver">Driver para mando Xbox 360/One</string>
|
||||
<string name="summary_checkbox_xb1_driver">Activa el driver USB incluido para dispositivos sin soporte nativo para mandos de Xbox.</string>
|
||||
<string name="summary_checkbox_xb1_driver">Activa el driver USB incluido para dispositivos sin soporte nativo para mandos de Xbox</string>
|
||||
<string name="category_on_screen_controls_settings">Configuración de controles en pantalla</string>
|
||||
<string name="title_checkbox_show_onscreen_controls">Mostrar controles en pantalla</string>
|
||||
<string name="summary_checkbox_show_onscreen_controls">Muestra controles virtuales superpuestos en la pantalla táctil</string>
|
||||
@@ -105,17 +107,17 @@
|
||||
<string name="summary_checkbox_host_audio">Reproducir audio en el ordenador y en este dispositivo</string>
|
||||
<string name="category_advanced_settings">Configuración avanzada</string>
|
||||
<string name="title_video_format">Cambiar configuración HEVC</string>
|
||||
<string name="summary_video_format">HEVC reduce el ancho de banda de vídeo, pero requiere un dispositivo bastante actual.</string>
|
||||
<string name="summary_video_format">HEVC reduce el ancho de banda de vídeo, pero requiere un dispositivo reciente</string>
|
||||
<!-- Array strings -->
|
||||
<string name="videoformat_hevcauto">Usar HEVC solo si es estable</string>
|
||||
<string name="videoformat_hevcauto">Usar HEVC sólo si es estable</string>
|
||||
<string name="videoformat_hevcalways">Siempre usar HEVC (puede fallar)</string>
|
||||
<string name="videoformat_hevcnever">Nunca usar HEVC</string>
|
||||
<string name="nettest_title_done">Prueba de Red Completada</string>
|
||||
<string name="scut_not_paired">PC no emparejado</string>
|
||||
<string name="scut_invalid_uuid">PC proporcionado no es válido</string>
|
||||
<string name="scut_invalid_app_id">App proporcionada no es válida</string>
|
||||
<string name="help_loading_title">Visor de Ayuda</string>
|
||||
<string name="pcview_menu_header_online">En Línea</string>
|
||||
<string name="scut_invalid_uuid">El PC proporcionado no es válido</string>
|
||||
<string name="scut_invalid_app_id">La App proporcionada no es válida</string>
|
||||
<string name="help_loading_title">Visor de ayuda</string>
|
||||
<string name="pcview_menu_header_online">En línea</string>
|
||||
<string name="pcview_menu_header_unknown">Actualizando</string>
|
||||
<string name="pcview_menu_test_network">Probar Conexión de Red</string>
|
||||
<string name="pcview_menu_details">Ver Detalles</string>
|
||||
@@ -131,11 +133,127 @@
|
||||
<string name="title_decoding_error">Falló el Decodificador de Video</string>
|
||||
<string name="scut_deleted_pc">PC eliminado</string>
|
||||
<string name="scut_pc_not_found">PC no encontrado</string>
|
||||
<string name="help_loading_msg">Cargando página de ayuda …</string>
|
||||
<string name="help_loading_msg">Cargando página de ayuda…</string>
|
||||
<string name="pcview_menu_header_offline">Fuera de línea</string>
|
||||
<string name="nettest_text_success">Tu red parece no estar bloqueando Moonlight. Si aun tienes problemas de conexión, comprueba la configuración del firewall de tu PC.
|
||||
\n
|
||||
\nSi estas intentado transmitir mediante Internet, instala en tu pc la Moonlight Internet Hosting Tool y ejecuta el Internet Streaming Tester incluido para comprobar la conexión de tu PC a internet.</string>
|
||||
<string name="nettest_text_blocked">La conexión de red actual de tu dispositivo esta bloqueando Moonlight. La Transmisión mediante Internet puede no funcionar mientras estés conectado a esta red.</string>
|
||||
<string name="pair_already_in_progress">Emparejamiento ya en progreso</string>
|
||||
<string name="resolution_prefix_native_fullscreen">Pantalla Completa Nativa</string>
|
||||
<string name="title_audio_config_list">Configuración de Sonido Envolvente</string>
|
||||
<string name="title_decoding_reset">Reiniciar Opciones de Video</string>
|
||||
<string name="no_video_received_error">No se recibe video desde el equipo anfitrión.</string>
|
||||
<string name="applist_details_id">ID de Aplicación:</string>
|
||||
<string name="title_checkbox_mouse_emulation">Emulación de ratón usando el mando</string>
|
||||
<string name="pacing_latency">Preferir la menor latencia posible</string>
|
||||
<string name="pacing_balanced">Equilibrado</string>
|
||||
<string name="pacing_smoothness">Preferir mayor fluidez de video (puede incrementar significativamente la latencia)</string>
|
||||
<string name="perf_overlay_decoder">Decodificador: %1$s</string>
|
||||
<string name="perf_overlay_incomingfps">Tasa de cuadros obtenida de la red: %1$.2f FPS</string>
|
||||
<string name="perf_overlay_renderingfps">Tasa de Cuadros Renderizada: %1$.2f FPS</string>
|
||||
<string name="perf_overlay_netdrops">Cuadros perdidos por tu conexión de internet: %1$.2f%%</string>
|
||||
<string name="perf_overlay_netlatency">Latencia promedio de red:%1$d ms (variación: %2$d ms)</string>
|
||||
<string name="perf_overlay_dectime">Tiempo promedio de descodificado: %1$.2f ms</string>
|
||||
<string name="perf_overlay_streamdetails">Transmisión video: %1$s %2$.2f FPS</string>
|
||||
<string name="title_fps_list">Tasa de cuadros en el video</string>
|
||||
<string name="summary_fps_list">Incrementar para una experiencia mas fluida en la transmisión. Disminuir para una mejoría en el rendimiento en dispositivos de gama de entrada.</string>
|
||||
<string name="summary_reset_osc">Reiniciar toda la configuración a las predeterminadas de tamaño y posición para los controles en pantalla</string>
|
||||
<string name="summary_troubleshooting">Mostrar consejos para diagnosticar y corregir errores comunes respecto a la transmisión</string>
|
||||
<string name="title_privacy_policy">Política de Privacidad</string>
|
||||
<string name="resolution_360p">360p</string>
|
||||
<string name="resolution_1440p">1440p</string>
|
||||
<string name="resolution_4k">4K</string>
|
||||
<string name="suffix_osc_opacity">%</string>
|
||||
<string name="title_checkbox_enable_pip">Actividad modo Pantalla-en-Pantalla para observador</string>
|
||||
<string name="resolution_720p">720p</string>
|
||||
<string name="fps_120">120 FPS</string>
|
||||
<string name="audioconf_71surround">7.1 Sonido Envolvente</string>
|
||||
<string name="title_troubleshooting">Guía de Solución de Errores</string>
|
||||
<string name="resolution_1080p">1080p</string>
|
||||
<string name="summary_frame_pacing">Especificar como balancear la latencia de video y la fluidez</string>
|
||||
<string name="pacing_balanced_alt">Equilibrado con limitador de FPS (Cuadros por Segundo)</string>
|
||||
<string name="audioconf_51surround">5.1 Sonido Envolvente</string>
|
||||
<string name="audioconf_stereo">Estéreo</string>
|
||||
<string name="check_ports_msg">Revisa la configuración de tu firewall, así como, las reglas de redireccionamiento para él(los) puerto(s):</string>
|
||||
<string name="error_usb_prohibited">El acceso a USB está restringido en tu dispositivo por el administrador. Revisar tus ajustes en MDM o Knox.</string>
|
||||
<string name="message_decoding_error">Moonlight se ha cerrado debido a una incompatibilidad con el decodificador de vídeo de este dispositivo. Asegúrate de que GeForce Experience está actualizado a la última versión en tu PC. Intenta ajustar la configuración de streaming si los bloqueos continúan.</string>
|
||||
<string name="message_decoding_reset">La decodificación de video de tu equipo sigue fallando con las opciones elegidas. Las opciones de la transmisión han sido revertidas a las predeterminadas.</string>
|
||||
<string name="video_decoder_init_failed">El descodificador de video no pudo ser iniciado. Tu dispositivo puede no soportar la resolución elegida o la tasa de cuadros por segundo.</string>
|
||||
<string name="no_frame_received_error">La conexión de internet no está teniendo un buen desempeño. Reduce la tasa de bits de video o prueba en una conexión de mayor velocidad.</string>
|
||||
<string name="unable_to_pin_shortcut">Tu lanzador predeterminado no permite la creación de accesos directos anclados.</string>
|
||||
<string name="early_termination_error">Algo ha salido mal en el PC anfitrión cuando se inicio la transmisión.
|
||||
\n
|
||||
\nVerifica que no tengas ningún contenido protegido por DRM abierto en el equipo. También prueba reiniciando el equipo anfitrión.
|
||||
\n
|
||||
\nSi el problema persiste, intenta reinstalar los controladores de la tarjeta de video (GPU) además de GeForce Experience.</string>
|
||||
<string name="title_details">Detalles</string>
|
||||
<string name="poor_connection_msg">Conexión pobre al PC</string>
|
||||
<string name="applist_menu_details">Ver Detalles</string>
|
||||
<string name="applist_menu_scut">Crear Acceso Directo</string>
|
||||
<string name="applist_menu_tv_channel">Agregar al Canal</string>
|
||||
<string name="applist_menu_hide_app">Esconder Aplicación</string>
|
||||
<string name="applist_connect_msg">Conectando al Equipo…</string>
|
||||
<string name="summary_checkbox_mouse_nav_buttons">Activar esta opción puede desconfigurar la función de clic derecho en algunos dispositivos inestables</string>
|
||||
<string name="text_native_res_dialog">Modos de resolución nativa no son oficialmente soportados por GeForce Experience, así que no se no se aplicarán por su cuenta en la pantalla del equipo anfitrión. Vas a necesitar ajustarlos manualmente en el juego.
|
||||
\n
|
||||
\nSi eliges crear una resolución personalizada en el Panel de Control de Nvidia para ajustarse a la resolución de tu dispositivo, por favor considera haber leído y entendido la advertencia de NVIDIA respectivo a cualquier daño posible a tu monitor, inestabilidad del equipo, y otros problemas potencialmente posibles.
|
||||
\n
|
||||
\nNo somos responsables de cualquier problema por haber creador una resolución personalizada en tu PC.
|
||||
\n
|
||||
\nFinalmente, tu dispositivo o tu Pc anfitrión, podrían no soportar la transmisión a resolución nativa. Si no funciona en tu equipo, puede que solo no tengas suerte de momento.</string>
|
||||
<string name="resolution_prefix_native">Nativo</string>
|
||||
<string name="summary_audio_config_list">Activar sonido envolvente de 5.1 o 7.1 canales para sistemas de teatro en casa</string>
|
||||
<string name="title_checkbox_vibrate_fallback">Emular la vibración del mando con vibración del equipo</string>
|
||||
<string name="summary_checkbox_enable_audiofx">Permitir funcionar efectos de sonido durante la transmisión, pero podría incrementar la latencia del sonido</string>
|
||||
<string name="summary_checkbox_usb_bind_all">Usar el controlador de USB de Moonlight para todos los mandos soportados, incluso si el control de Xbox se encuentra presente</string>
|
||||
<string name="summary_checkbox_mouse_emulation">Presionar por un periodo largo el botón de inicio hará cambiar el mando a modo de ratón</string>
|
||||
<string name="title_checkbox_mouse_nav_buttons">Activar los botones atrás y adelante del ratón</string>
|
||||
<string name="title_unlock_fps">Desbloquear todas las opciones de tasa de cuadros disponibles</string>
|
||||
<string name="summary_unlock_fps">Transmitir a 90 o 120 FPS puede reducir latencia en dispositivos de gama alta pero puede causar retrasos en dispositivos que no lo soporten</string>
|
||||
<string name="title_enable_perf_overlay">Mostrar estadísticas de rendimiento mientras la transmisión está activa</string>
|
||||
<string name="summary_enable_post_stream_toast">Mostrar un mensaje sobre la información de latencia cuando la transmisión termine</string>
|
||||
<string name="help">Ayuda</string>
|
||||
<string name="delete_pc_msg">¿Estás seguro de eliminar este PC\?</string>
|
||||
<string name="slow_connection_msg">Conexión lenta al PC
|
||||
\nReduce la tasa de bits</string>
|
||||
<string name="addpc_wrong_sitelocal">La dirección no luce correcta. Debes usar la dirección IP Pública de tu Rúter para la transmisión por Internet.</string>
|
||||
<string name="title_native_res_dialog">Advertencia Resolución Nativa</string>
|
||||
<string name="suffix_seekbar_bitrate_mbps">Mbps</string>
|
||||
<string name="category_input_settings">Opciones de Entrada</string>
|
||||
<string name="title_checkbox_touchscreen_trackpad">Usa la pantalla táctil como panel táctil</string>
|
||||
<string name="summary_checkbox_touchscreen_trackpad">Si está activo, la pantalla táctil funcionará como panel táctil. Si está desactivado, la pantalla táctil directamente controlará el cursor del ratón.</string>
|
||||
<string name="summary_seekbar_deadzone">Nota: Algunos juegos pueden forzar una zona muerta mayor a la que Moonlight esta configurada a usar.</string>
|
||||
<string name="title_checkbox_flip_face_buttons">Invertir botones frontales</string>
|
||||
<string name="summary_checkbox_absolute_mouse_mode">Esto puede hacer que la aceleración de mouse se comporte mas natural para uso de escritorio remoto, pero es incompatible con muchos juegos.</string>
|
||||
<string name="title_checkbox_enable_audiofx">Activar el soporte para ecualizador de sistema</string>
|
||||
<string name="summary_checkbox_vibrate_fallback">Vibrar el dispositivo para emular el retumbe si tu mando de control no lo soporta</string>
|
||||
<string name="title_checkbox_usb_bind_all">Sobrescribir el soporte nativo del control de Xbox</string>
|
||||
<string name="summary_checkbox_flip_face_buttons">Invertir botones frontales A/B y X/Y para los mandos y los botones sobre la pantalla</string>
|
||||
<string name="title_checkbox_absolute_mouse_mode">Modo de ratón para escritorio remoto</string>
|
||||
<string name="title_checkbox_vibrate_osc">Activar vibración</string>
|
||||
<string name="summary_checkbox_vibrate_osc">Hacer vibrar tu dispositivo para emular la vibración del juego para los controles en pantalla</string>
|
||||
<string name="title_reset_osc">Borrar la configuración guardada de la plantilla para el control en pantalla</string>
|
||||
<string name="dialog_title_reset_osc">Reiniciar a Plantilla Predeterminada</string>
|
||||
<string name="dialog_text_reset_osc">¿Estás seguro de que quieres eliminar tus configuraciones guardadas para las plantillas de los controles en pantalla\?</string>
|
||||
<string name="toast_reset_osc_success">Establecer Controles en Pantalla en modo Predeterminado</string>
|
||||
<string name="title_osc_opacity">Cambiar la transparencia de los controles en pantalla</string>
|
||||
<string name="summary_osc_opacity">Hacer los controles en pantalla más/menos transparentes</string>
|
||||
<string name="dialog_title_osc_opacity">Cambiar opacidad</string>
|
||||
<string name="summary_checkbox_enable_pip">Permite que la transmisión sea vista (pero no controlable) mientras se usa la multitarea</string>
|
||||
<string name="title_disable_frame_drop">Nunca disminuir cuadros</string>
|
||||
<string name="summary_disable_frame_drop">Puede reducir micro-tartamudeos (Stuttering) en algunos dispositivos , pero puede incrementar latencia</string>
|
||||
<string name="title_enable_hdr">Activar HDR (Alto Rango Dinámico / Experimental)</string>
|
||||
<string name="summary_enable_hdr">Transmitir HDR (Alto Rango Dinámico) cuando el juego, el PC y la Tarjeta de Video (GPU) lo soporten. HDR requiere de una Tarjeta de Video de la serie GTX 1000 o superior.</string>
|
||||
<string name="summary_enable_perf_overlay">Mostrar en tiempo real la información del desempeño de la transmisión mientras está activa la misma</string>
|
||||
<string name="title_enable_post_stream_toast">Mostrar mensajes sobre latencia mientras se transmite</string>
|
||||
<string name="category_help">Ayuda</string>
|
||||
<string name="title_setup_guide">Guía para la Configuración</string>
|
||||
<string name="summary_setup_guide">Mostrar instrucciones para como configurar tu PC para juegos para la transmisión</string>
|
||||
<string name="summary_privacy_policy">Mostrar la política de privacidad de Moonlight</string>
|
||||
<string name="resolution_480p">480p</string>
|
||||
<string name="fps_30">30 FPS</string>
|
||||
<string name="fps_60">60 FPS</string>
|
||||
<string name="fps_90">90 FPS</string>
|
||||
<string name="title_frame_pacing">Ritmo de cuadros por segundo en video</string>
|
||||
</resources>
|
||||
@@ -254,4 +254,5 @@
|
||||
<string name="audioconf_71surround">7.1 서라운드 사운드</string>
|
||||
<string name="title_frame_pacing">비디오 프레임 처리방식</string>
|
||||
<string name="pacing_smoothness">가장 부드러운 비디오 선호(대기 시간이 크게 증가할 수 있음)</string>
|
||||
<string name="category_help">도움말</string>
|
||||
</resources>
|
||||
@@ -239,4 +239,10 @@
|
||||
<string name="pacing_balanced_alt">Equilibrado com limite de FPS</string>
|
||||
<string name="summary_seekbar_deadzone">Nota: Alguns jogos podem impor uma zona morta maior do que o Moonlight está configurado para usar.</string>
|
||||
<string name="title_checkbox_absolute_mouse_mode">Modo de mouse para área de trabalho remota</string>
|
||||
<string name="resolution_prefix_native_landscape">(Paisagem)</string>
|
||||
<string name="title_checkbox_reduce_refresh_rate">Permitir redução de taxa de atualização</string>
|
||||
<string name="summary_checkbox_reduce_refresh_rate">Taxas menores de atualização do display podem salvar energia ao custo de latência de video adicional</string>
|
||||
<string name="resolution_prefix_native_portrait">(Retrato)</string>
|
||||
<string name="title_checkbox_enable_audiofx">Habilitar sistema de suporte à equalização</string>
|
||||
<string name="summary_checkbox_enable_audiofx">Permitir que efeitos de audio funcionem durante o streaming, pode acrescentar latência de audio</string>
|
||||
</resources>
|
||||
@@ -12,9 +12,15 @@
|
||||
<string name="pcview_menu_header_online">Online</string>
|
||||
<string name="pcview_menu_header_offline">Offline</string>
|
||||
<string name="pcview_menu_app_list">Veja todos aplicativos</string>
|
||||
<string name="pcview_menu_pair_pc">Sincronize com o PC</string>
|
||||
<string name="pcview_menu_pair_pc">Parear com o PC</string>
|
||||
<string name="pcview_menu_details">Ver Detalhes</string>
|
||||
<string name="pair_pairing_title">Pareando</string>
|
||||
<string name="pair_fail">Falha no pareamento</string>
|
||||
<string name="nettest_title_waiting">Testar Conexão com a Internet</string>
|
||||
<string name="pcview_menu_send_wol">Enviar requisição Wake-On-LAN</string>
|
||||
<string name="pcview_menu_delete_pc">Deletar PC</string>
|
||||
<string name="pcview_menu_test_network">Testar Conexão com a Internet</string>
|
||||
<string name="nettest_text_waiting">Moonlight está testando sua conexão com a rede para determinar se o NVIDIA GameStream está bloqueado.
|
||||
\n
|
||||
\nEste processo pode demorar alguns segundos…</string>
|
||||
</resources>
|
||||
@@ -80,7 +80,7 @@
|
||||
<string name="perf_overlay_dectime">平均解碼時間:%1$.2f ms</string>
|
||||
<!-- AppList activity -->
|
||||
<string name="applist_connect_msg">正在連線電腦…</string>
|
||||
<string name="applist_menu_resume">恢復工作階段</string>
|
||||
<string name="applist_menu_resume">繼續工作階段</string>
|
||||
<string name="applist_menu_quit">結束工作階段</string>
|
||||
<string name="applist_menu_quit_and_start">結束目前遊戲並開始這個遊戲</string>
|
||||
<string name="applist_menu_cancel"> 取消 </string>
|
||||
@@ -146,7 +146,7 @@
|
||||
<string name="summary_checkbox_show_onscreen_controls">在觸控式螢幕上顯示一層虛擬控制器</string>
|
||||
<string name="title_checkbox_vibrate_osc"> 啟用震動 </string>
|
||||
<string name="summary_checkbox_vibrate_osc">使用螢幕控制按鈕時震動裝置以仿真遊戲低頻音</string>
|
||||
<string name="title_only_l3r3">只顯示 L3 和 R3</string>
|
||||
<string name="title_only_l3r3">僅顯示 L3 和 R3</string>
|
||||
<string name="summary_only_l3r3">隱藏除 L3 和 R3 外的所有虛擬按鈕</string>
|
||||
<string name="title_reset_osc">重設已儲存的螢幕控制按鈕版面配置</string>
|
||||
<string name="summary_reset_osc">重設所有螢幕控制按鈕為預設大小和位置</string>
|
||||
@@ -170,9 +170,9 @@
|
||||
<string name="summary_video_format">HEVC 能降低視訊頻寬需求,但需要較新的裝置才能支援</string>
|
||||
<string name="title_enable_hdr">啟用 HDR (實驗性)</string>
|
||||
<string name="summary_enable_hdr">當遊戲和顯示卡支援時以 HDR 模式串流。 HDR 需要 GTX 1000 系列或更高規格顯示卡。</string>
|
||||
<string name="title_enable_perf_overlay">顯示效能資訊</string>
|
||||
<string name="title_enable_perf_overlay">串流時顯示效能資訊</string>
|
||||
<string name="summary_enable_perf_overlay">在串流中顯示即時效能資訊</string>
|
||||
<string name="title_enable_post_stream_toast">串流完畢顯示延時資訊</string>
|
||||
<string name="title_enable_post_stream_toast">串流後顯示延時資訊</string>
|
||||
<string name="summary_enable_post_stream_toast">串流結束後顯示延時資訊</string>
|
||||
<string name="title_osc_opacity">變更螢幕按鈕透明度</string>
|
||||
<string name="dialog_title_osc_opacity">變更不透明度</string>
|
||||
|
||||
@@ -152,6 +152,8 @@
|
||||
<string name="title_checkbox_stretch_video">Stretch video to full-screen</string>
|
||||
<string name="resolution_prefix_native">Native</string>
|
||||
<string name="resolution_prefix_native_fullscreen">Native Full-Screen</string>
|
||||
<string name="resolution_prefix_native_landscape">(Landscape)</string>
|
||||
<string name="resolution_prefix_native_portrait">(Portrait)</string>
|
||||
|
||||
<string name="category_audio_settings">Audio Settings</string>
|
||||
<string name="title_audio_config_list">Surround sound configuration</string>
|
||||
@@ -216,6 +218,8 @@
|
||||
<string name="category_advanced_settings">Advanced Settings</string>
|
||||
<string name="title_unlock_fps">Unlock all possible frame rates</string>
|
||||
<string name="summary_unlock_fps">Streaming at 90 or 120 FPS may reduce latency on high-end devices but can cause lag or instability on devices that can\'t support it</string>
|
||||
<string name="title_checkbox_reduce_refresh_rate">Allow refresh rate reduction</string>
|
||||
<string name="summary_checkbox_reduce_refresh_rate">Lower display refresh rates can save power at the expense of some additional video latency</string>
|
||||
<string name="title_checkbox_disable_warnings">Disable warning messages</string>
|
||||
<string name="summary_checkbox_disable_warnings">Disable on-screen connection warning messages while streaming</string>
|
||||
<string name="title_disable_frame_drop">Never drop frames</string>
|
||||
|
||||
@@ -189,6 +189,11 @@
|
||||
android:title="@string/title_unlock_fps"
|
||||
android:summary="@string/summary_unlock_fps"
|
||||
android:defaultValue="false" />
|
||||
<CheckBoxPreference
|
||||
android:key="checkbox_reduce_refresh_rate"
|
||||
android:title="@string/title_checkbox_reduce_refresh_rate"
|
||||
android:summary="@string/summary_checkbox_reduce_refresh_rate"
|
||||
android:defaultValue="false" />
|
||||
<CheckBoxPreference
|
||||
android:key="checkbox_disable_warnings"
|
||||
android:title="@string/title_checkbox_disable_warnings"
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ buildscript {
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.2.1'
|
||||
classpath 'com.android.tools.build:gradle:7.2.2'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
- Reduced input latency on devices running Android 11 or later
|
||||
- Refresh rate reduction is now off by default to reduce display latency
|
||||
- Adjusted video decoder buffer processing to slightly reduce decoding latency
|
||||
- Added support for portrait and landscape native resolutions on foldables
|
||||
- Streaming is no longer locked to landscape orientation on foldables
|
||||
- Fixed left clicking using the virtual trackpad on Samsung foldables
|
||||
- Updated community contributed translations from Weblate
|
||||
@@ -0,0 +1,2 @@
|
||||
- Fixed streaming from hosts running Sunshine
|
||||
- Updated community contributed translations from Weblate
|
||||
Reference in New Issue
Block a user