mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-01 23:35:28 +00:00
Compare commits
77 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f10085f552 | ||
|
eb7f0887bf | ||
|
34a9132d60 | ||
|
24d3fb000a | ||
|
b7b6adaff7 | ||
|
85ed72802f | ||
|
f54f8c83e7 | ||
|
124bfdf418 | ||
|
01507d9995 | ||
|
070c82bc44 | ||
|
17df15293f | ||
|
6551076613 | ||
|
1b1b100e63 | ||
|
e70014bb28 | ||
|
082cc84a71 | ||
|
2ba7f0d989 | ||
|
9a7381b35f | ||
|
613ecfff44 | ||
|
f638548a02 | ||
|
224bab68bf | ||
|
6aca18bd76 | ||
|
3c58e2fbba | ||
|
aaaebde05e | ||
|
8ff9f70bd7 | ||
|
523ca862b9 | ||
|
78b8d1e9f3 | ||
|
83c698b36d | ||
|
27fe37f221 | ||
|
3722106daf | ||
|
3ea9ef1ef2 | ||
|
fcd27b48b2 | ||
|
6ff37a17ec | ||
|
f2c6e9e32e | ||
|
dbf1b88a3d | ||
|
3aab9eb13b | ||
|
3f9f8f7b3b | ||
|
f7520ba40c | ||
|
7b13f12817 | ||
|
57e19d75e2 | ||
|
4330a223c6 | ||
|
69387c32ad | ||
|
a102ec4ee8 | ||
|
2a094437dd | ||
|
4142907376 | ||
|
e63dc9a93b | ||
|
1fe19e912e | ||
|
56ad48446e | ||
|
a18aa26985 | ||
|
5443cc014a | ||
|
7d77e1c1f2 | ||
|
ca82cd9752 | ||
|
dbd86bb861 | ||
|
0af56b4981 | ||
|
f1be5365bb | ||
|
c356862ac1 | ||
|
fc77322f59 | ||
|
032e944d49 | ||
|
0da47da8d8 | ||
|
ebfe843299 | ||
|
827d2362b7 | ||
|
4fa1eb4088 | ||
|
885b59fd52 | ||
|
ff5d9f72aa | ||
|
030bb91789 | ||
|
34788b2808 | ||
|
abc4123c52 | ||
|
26f8c0842e | ||
|
d430d83ba8 | ||
|
a52f189fb1 | ||
|
dc1045b69e | ||
|
3a89dbf4ab | ||
|
d69b4eca1e | ||
|
568bba82f0 | ||
|
b52e6c88ec | ||
|
720595091e | ||
|
fe929c8e58 | ||
|
9ecec1eb3c |
@ -1,18 +1,18 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
ndkVersion "23.2.8568313"
|
ndkVersion "27.0.12077973"
|
||||||
|
|
||||||
compileSdk 34
|
compileSdk 34
|
||||||
|
|
||||||
namespace 'com.limelight'
|
namespace 'com.limelight'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk 16
|
minSdk 21
|
||||||
targetSdk 34
|
targetSdk 34
|
||||||
|
|
||||||
versionName "12.0"
|
versionName "12.1"
|
||||||
versionCode = 311
|
versionCode = 314
|
||||||
|
|
||||||
// Generate native debug symbols to allow Google Play to symbolicate our native crashes
|
// Generate native debug symbols to allow Google Play to symbolicate our native crashes
|
||||||
ndk.debugSymbolLevel = 'FULL'
|
ndk.debugSymbolLevel = 'FULL'
|
||||||
@ -136,12 +136,10 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
|
implementation 'org.bouncycastle:bcprov-jdk18on:1.77'
|
||||||
implementation 'org.bouncycastle:bcpkix-jdk15on:1.70'
|
implementation 'org.bouncycastle:bcpkix-jdk18on:1.77'
|
||||||
implementation 'org.jcodec:jcodec:0.2.3'
|
implementation 'org.jcodec:jcodec:0.2.5'
|
||||||
implementation 'com.squareup.okhttp3:okhttp:3.12.13'
|
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
|
||||||
implementation 'com.squareup.okio:okio:1.17.5'
|
implementation 'org.jmdns:jmdns:3.5.9'
|
||||||
// 3.5.8 requires minSdk 19, uses StandardCharsets.UTF_8 internally
|
implementation 'com.github.cgutman:ShieldControllerExtensions:1.0.1'
|
||||||
implementation 'org.jmdns:jmdns:3.5.7'
|
|
||||||
implementation 'com.github.cgutman:ShieldControllerExtensions:1.0'
|
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,6 @@
|
|||||||
android:banner="@drawable/atv_banner"
|
android:banner="@drawable/atv_banner"
|
||||||
android:appCategory="game"
|
android:appCategory="game"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:roundIcon="@mipmap/ic_launcher"
|
|
||||||
android:installLocation="auto"
|
android:installLocation="auto"
|
||||||
android:gwpAsanMode="always"
|
android:gwpAsanMode="always"
|
||||||
android:localeConfig="@xml/locales_config"
|
android:localeConfig="@xml/locales_config"
|
||||||
@ -77,6 +76,11 @@
|
|||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.android.graphics.intervention.wm.allowDownscale"
|
android:name="com.android.graphics.intervention.wm.allowDownscale"
|
||||||
android:value="false"/>
|
android:value="false"/>
|
||||||
|
|
||||||
|
<!-- Game Mode configuration -->
|
||||||
|
<meta-data
|
||||||
|
android:name="android.game_mode_config"
|
||||||
|
android:resource="@xml/game_mode_config" />
|
||||||
|
|
||||||
<!-- Samsung DeX support requires explicit placement of android:resizeableActivity="true"
|
<!-- Samsung DeX support requires explicit placement of android:resizeableActivity="true"
|
||||||
in each activity even though it is implied by targeting API 24+ -->
|
in each activity even though it is implied by targeting API 24+ -->
|
||||||
|
@ -127,6 +127,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
private int suppressPipRefCount = 0;
|
private int suppressPipRefCount = 0;
|
||||||
private String pcName;
|
private String pcName;
|
||||||
private String appName;
|
private String appName;
|
||||||
|
private NvApp app;
|
||||||
private float desiredRefreshRate;
|
private float desiredRefreshRate;
|
||||||
|
|
||||||
private InputCaptureProvider inputCaptureProvider;
|
private InputCaptureProvider inputCaptureProvider;
|
||||||
@ -146,8 +147,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
private int requestedNotificationOverlayVisibility = View.GONE;
|
private int requestedNotificationOverlayVisibility = View.GONE;
|
||||||
private TextView performanceOverlayView;
|
private TextView performanceOverlayView;
|
||||||
|
|
||||||
private ShortcutHelper shortcutHelper;
|
|
||||||
|
|
||||||
private MediaCodecDecoderRenderer decoderRenderer;
|
private MediaCodecDecoderRenderer decoderRenderer;
|
||||||
private boolean reportedCrash;
|
private boolean reportedCrash;
|
||||||
|
|
||||||
@ -196,14 +195,12 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
// If we're going to use immersive mode, we want to have
|
// If we're going to use immersive mode, we want to have
|
||||||
// the entire screen
|
// the entire screen
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
|
getWindow().getDecorView().setSystemUiVisibility(
|
||||||
getWindow().getDecorView().setSystemUiVisibility(
|
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
|
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
|
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
|
|
||||||
|
|
||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
|
||||||
}
|
|
||||||
|
|
||||||
// Listen for UI visibility events
|
// Listen for UI visibility events
|
||||||
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(this);
|
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(this);
|
||||||
@ -318,10 +315,11 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
int httpsPort = Game.this.getIntent().getIntExtra(EXTRA_HTTPS_PORT, 0); // 0 is treated as unknown
|
int httpsPort = Game.this.getIntent().getIntExtra(EXTRA_HTTPS_PORT, 0); // 0 is treated as unknown
|
||||||
int appId = Game.this.getIntent().getIntExtra(EXTRA_APP_ID, StreamConfiguration.INVALID_APP_ID);
|
int appId = Game.this.getIntent().getIntExtra(EXTRA_APP_ID, StreamConfiguration.INVALID_APP_ID);
|
||||||
String uniqueId = Game.this.getIntent().getStringExtra(EXTRA_UNIQUEID);
|
String uniqueId = Game.this.getIntent().getStringExtra(EXTRA_UNIQUEID);
|
||||||
String uuid = Game.this.getIntent().getStringExtra(EXTRA_PC_UUID);
|
|
||||||
boolean appSupportsHdr = Game.this.getIntent().getBooleanExtra(EXTRA_APP_HDR, false);
|
boolean appSupportsHdr = Game.this.getIntent().getBooleanExtra(EXTRA_APP_HDR, false);
|
||||||
byte[] derCertData = Game.this.getIntent().getByteArrayExtra(EXTRA_SERVER_CERT);
|
byte[] derCertData = Game.this.getIntent().getByteArrayExtra(EXTRA_SERVER_CERT);
|
||||||
|
|
||||||
|
app = new NvApp(appName != null ? appName : "app", appId, appSupportsHdr);
|
||||||
|
|
||||||
X509Certificate serverCert = null;
|
X509Certificate serverCert = null;
|
||||||
try {
|
try {
|
||||||
if (derCertData != null) {
|
if (derCertData != null) {
|
||||||
@ -337,17 +335,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report this shortcut being used
|
|
||||||
ComputerDetails computer = new ComputerDetails();
|
|
||||||
computer.name = pcName;
|
|
||||||
computer.uuid = uuid;
|
|
||||||
shortcutHelper = new ShortcutHelper(this);
|
|
||||||
shortcutHelper.reportComputerShortcutUsed(computer);
|
|
||||||
if (appName != null) {
|
|
||||||
// This may be null if launched from the "Resume Session" PC context menu item
|
|
||||||
shortcutHelper.reportGameLaunched(computer, new NvApp(appName, appId, appSupportsHdr));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the MediaCodec helper before creating the decoder
|
// Initialize the MediaCodec helper before creating the decoder
|
||||||
GlPreferences glPrefs = GlPreferences.readPreferences(this);
|
GlPreferences glPrefs = GlPreferences.readPreferences(this);
|
||||||
MediaCodecHelper.initialize(this, glPrefs.glRenderer);
|
MediaCodecHelper.initialize(this, glPrefs.glRenderer);
|
||||||
@ -479,19 +466,16 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
.setResolution(prefConfig.width, prefConfig.height)
|
.setResolution(prefConfig.width, prefConfig.height)
|
||||||
.setLaunchRefreshRate(prefConfig.fps)
|
.setLaunchRefreshRate(prefConfig.fps)
|
||||||
.setRefreshRate(chosenFrameRate)
|
.setRefreshRate(chosenFrameRate)
|
||||||
.setApp(new NvApp(appName != null ? appName : "app", appId, appSupportsHdr))
|
.setApp(app)
|
||||||
.setBitrate(prefConfig.bitrate)
|
.setBitrate(prefConfig.bitrate)
|
||||||
.setEnableSops(prefConfig.enableSops)
|
.setEnableSops(prefConfig.enableSops)
|
||||||
.enableLocalAudioPlayback(prefConfig.playHostAudio)
|
.enableLocalAudioPlayback(prefConfig.playHostAudio)
|
||||||
.setMaxPacketSize(1392)
|
.setMaxPacketSize(1392)
|
||||||
.setRemoteConfiguration(StreamConfiguration.STREAM_CFG_AUTO) // NvConnection will perform LAN and VPN detection
|
.setRemoteConfiguration(StreamConfiguration.STREAM_CFG_AUTO) // NvConnection will perform LAN and VPN detection
|
||||||
.setHevcBitratePercentageMultiplier(75)
|
|
||||||
.setAv1BitratePercentageMultiplier(60)
|
|
||||||
.setSupportedVideoFormats(supportedVideoFormats)
|
.setSupportedVideoFormats(supportedVideoFormats)
|
||||||
.setAttachedGamepadMask(gamepadMask)
|
.setAttachedGamepadMask(gamepadMask)
|
||||||
.setClientRefreshRateX100((int)(displayRefreshRate * 100))
|
.setClientRefreshRateX100((int)(displayRefreshRate * 100))
|
||||||
.setAudioConfiguration(prefConfig.audioConfiguration)
|
.setAudioConfiguration(prefConfig.audioConfiguration)
|
||||||
.setAudioEncryption(true)
|
|
||||||
.setColorSpace(decoderRenderer.getPreferredColorSpace())
|
.setColorSpace(decoderRenderer.getPreferredColorSpace())
|
||||||
.setColorRange(decoderRenderer.getPreferredColorRange())
|
.setColorRange(decoderRenderer.getPreferredColorRange())
|
||||||
.setPersistGamepadsAfterDisconnect(!prefConfig.multiController)
|
.setPersistGamepadsAfterDisconnect(!prefConfig.multiController)
|
||||||
@ -506,7 +490,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
keyboardTranslator = new KeyboardTranslator();
|
keyboardTranslator = new KeyboardTranslator();
|
||||||
|
|
||||||
InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE);
|
InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE);
|
||||||
inputManager.registerInputDeviceListener(controllerHandler, null);
|
|
||||||
inputManager.registerInputDeviceListener(keyboardTranslator, null);
|
inputManager.registerInputDeviceListener(keyboardTranslator, null);
|
||||||
|
|
||||||
// Initialize touch contexts
|
// Initialize touch contexts
|
||||||
@ -521,12 +504,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use sustained performance mode on N+ to ensure consistent
|
|
||||||
// CPU availability
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
||||||
getWindow().setSustainedPerformanceMode(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prefConfig.onscreenController) {
|
if (prefConfig.onscreenController) {
|
||||||
// create virtual onscreen controller
|
// create virtual onscreen controller
|
||||||
virtualController = new VirtualController(controllerHandler,
|
virtualController = new VirtualController(controllerHandler,
|
||||||
@ -581,39 +558,19 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (desiredOrientation == Configuration.ORIENTATION_LANDSCAPE) {
|
if (desiredOrientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (desiredOrientation == Configuration.ORIENTATION_PORTRAIT) {
|
else if (desiredOrientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT);
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If we don't have a reason to lock to portrait or landscape, allow any orientation
|
// 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);
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// For regular displays, we always request landscape
|
// For regular displays, we always request landscape
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -941,7 +898,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
displayRefreshRate = bestMode.getRefreshRate();
|
displayRefreshRate = bestMode.getRefreshRate();
|
||||||
}
|
}
|
||||||
// On L, we can at least tell the OS that we want a refresh rate
|
// On L, we can at least tell the OS that we want a refresh rate
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
else {
|
||||||
float bestRefreshRate = display.getRefreshRate();
|
float bestRefreshRate = display.getRefreshRate();
|
||||||
for (float candidate : display.getSupportedRefreshRates()) {
|
for (float candidate : display.getSupportedRefreshRates()) {
|
||||||
LimeLog.info("Examining refresh rate: "+candidate);
|
LimeLog.info("Examining refresh rate: "+candidate);
|
||||||
@ -965,19 +922,12 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
// Apply the refresh rate change
|
// Apply the refresh rate change
|
||||||
getWindow().setAttributes(windowLayoutParams);
|
getWindow().setAttributes(windowLayoutParams);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// Otherwise, the active display refresh rate is just
|
|
||||||
// whatever is currently in use.
|
|
||||||
displayRefreshRate = display.getRefreshRate();
|
|
||||||
}
|
|
||||||
|
|
||||||
// From 4.4 to 5.1 we can't ask for a 4K display mode, so we'll
|
// Until Marshmallow, we can't ask for a 4K display mode, so we'll
|
||||||
// need to hint the OS to provide one.
|
// need to hint the OS to provide one.
|
||||||
boolean aspectRatioMatch = false;
|
boolean aspectRatioMatch = false;
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT &&
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||||
Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
// We'll calculate whether we need to scale by aspect ratio. If not, we'll use
|
||||||
// On KitKat and later (where we can use the whole screen via immersive mode), we'll
|
|
||||||
// calculate whether we need to scale by aspect ratio or not. If not, we'll use
|
|
||||||
// setFixedSize so we can handle 4K properly. The only known devices that have
|
// setFixedSize so we can handle 4K properly. The only known devices that have
|
||||||
// >= 4K screens have exactly 4K screens, so we'll be able to hit this good path
|
// >= 4K screens have exactly 4K screens, so we'll be able to hit this good path
|
||||||
// on these devices. On Marshmallow, we can start changing to 4K manually but no
|
// on these devices. On Marshmallow, we can start changing to 4K manually but no
|
||||||
@ -1032,8 +982,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
Game.this.getWindow().getDecorView().setSystemUiVisibility(
|
Game.this.getWindow().getDecorView().setSystemUiVisibility(
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||||
}
|
}
|
||||||
// Use immersive mode on 4.4+ or standard low profile on previous builds
|
else {
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
// Use immersive mode
|
||||||
Game.this.getWindow().getDecorView().setSystemUiVisibility(
|
Game.this.getWindow().getDecorView().setSystemUiVisibility(
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
|
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
|
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
|
||||||
@ -1042,11 +992,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
View.SYSTEM_UI_FLAG_FULLSCREEN |
|
View.SYSTEM_UI_FLAG_FULLSCREEN |
|
||||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
|
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
Game.this.getWindow().getDecorView().setSystemUiVisibility(
|
|
||||||
View.SYSTEM_UI_FLAG_FULLSCREEN |
|
|
||||||
View.SYSTEM_UI_FLAG_LOW_PROFILE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1069,16 +1014,10 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
// that case here too.
|
// that case here too.
|
||||||
if (isInMultiWindowMode) {
|
if (isInMultiWindowMode) {
|
||||||
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
|
|
||||||
// Disable performance optimizations for foreground
|
|
||||||
getWindow().setSustainedPerformanceMode(false);
|
|
||||||
decoderRenderer.notifyVideoBackground();
|
decoderRenderer.notifyVideoBackground();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
|
|
||||||
// Enable performance optimizations for foreground
|
|
||||||
getWindow().setSustainedPerformanceMode(true);
|
|
||||||
decoderRenderer.notifyVideoForeground();
|
decoderRenderer.notifyVideoForeground();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1090,12 +1029,11 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
|
||||||
InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE);
|
|
||||||
if (controllerHandler != null) {
|
if (controllerHandler != null) {
|
||||||
inputManager.unregisterInputDeviceListener(controllerHandler);
|
|
||||||
controllerHandler.destroy();
|
controllerHandler.destroy();
|
||||||
}
|
}
|
||||||
if (keyboardTranslator != null) {
|
if (keyboardTranslator != null) {
|
||||||
|
InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE);
|
||||||
inputManager.unregisterInputDeviceListener(keyboardTranslator);
|
inputManager.unregisterInputDeviceListener(keyboardTranslator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1115,6 +1053,21 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
inputCaptureProvider.destroy();
|
inputCaptureProvider.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
if (isFinishing()) {
|
||||||
|
// Stop any further input device notifications before we lose focus (and pointer capture)
|
||||||
|
if (controllerHandler != null) {
|
||||||
|
controllerHandler.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ungrab input to prevent further input device notifications
|
||||||
|
setInputGrabState(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
@ -1300,10 +1253,20 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
else if ((modifierFlags & (KeyboardPacket.MODIFIER_CTRL | KeyboardPacket.MODIFIER_ALT | KeyboardPacket.MODIFIER_SHIFT)) ==
|
else if ((modifierFlags & (KeyboardPacket.MODIFIER_CTRL | KeyboardPacket.MODIFIER_ALT | KeyboardPacket.MODIFIER_SHIFT)) ==
|
||||||
(KeyboardPacket.MODIFIER_CTRL | KeyboardPacket.MODIFIER_ALT | KeyboardPacket.MODIFIER_SHIFT) &&
|
(KeyboardPacket.MODIFIER_CTRL | KeyboardPacket.MODIFIER_ALT | KeyboardPacket.MODIFIER_SHIFT) &&
|
||||||
(down && nonModifierKeyCode != KeyEvent.KEYCODE_UNKNOWN)) {
|
(down && nonModifierKeyCode != KeyEvent.KEYCODE_UNKNOWN)) {
|
||||||
// Remember that a special key combo was activated, so we can consume all key events until the modifiers come up
|
switch (androidKeyCode) {
|
||||||
specialKeyCode = androidKeyCode;
|
case KeyEvent.KEYCODE_Z:
|
||||||
waitingForAllModifiersUp = true;
|
case KeyEvent.KEYCODE_Q:
|
||||||
return true;
|
case KeyEvent.KEYCODE_C:
|
||||||
|
// Remember that a special key combo was activated, so we can consume all key
|
||||||
|
// events until the modifiers come up
|
||||||
|
specialKeyCode = androidKeyCode;
|
||||||
|
waitingForAllModifiersUp = true;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// This isn't a special combo that we consume on the client side
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not a special combo
|
// Not a special combo
|
||||||
@ -1869,7 +1832,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
if (deltaX != 0 || deltaY != 0) {
|
if (deltaX != 0 || deltaY != 0) {
|
||||||
if (prefConfig.absoluteMouseMode) {
|
if (prefConfig.absoluteMouseMode) {
|
||||||
conn.sendMouseMoveAsMousePosition(deltaX, deltaY, (short)view.getWidth(), (short)view.getHeight());
|
// NB: view may be null, but we can unconditionally use streamView because we don't need to adjust
|
||||||
|
// relative axis deltas for the position of the streamView within the parent's coordinate system.
|
||||||
|
conn.sendMouseMoveAsMousePosition(deltaX, deltaY, (short)streamView.getWidth(), (short)streamView.getHeight());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
conn.sendMouseMove(deltaX, deltaY);
|
conn.sendMouseMove(deltaX, deltaY);
|
||||||
@ -2215,13 +2180,11 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouch(View view, MotionEvent event) {
|
public boolean onTouch(View view, MotionEvent event) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
// Tell the OS not to buffer input events for us
|
||||||
// Tell the OS not to buffer input events for us
|
//
|
||||||
//
|
// NB: This is still needed even when we call the newer requestUnbufferedDispatch()!
|
||||||
// NB: This is still needed even when we call the newer requestUnbufferedDispatch()!
|
view.requestUnbufferedDispatch(event);
|
||||||
view.requestUnbufferedDispatch(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return handleMotionEvent(view, event);
|
return handleMotionEvent(view, event);
|
||||||
@ -2319,6 +2282,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
// Let the display go to sleep now
|
// Let the display go to sleep now
|
||||||
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||||
|
|
||||||
|
// Stop processing controller input
|
||||||
|
controllerHandler.stop();
|
||||||
|
|
||||||
// Ungrab input
|
// Ungrab input
|
||||||
setInputGrabState(false);
|
setInputGrabState(false);
|
||||||
|
|
||||||
@ -2356,7 +2322,16 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
message = getResources().getString(R.string.conn_terminated_msg);
|
String errorCodeString;
|
||||||
|
// We'll assume large errors are hex values
|
||||||
|
if (Math.abs(errorCode) > 1000) {
|
||||||
|
errorCodeString = Integer.toHexString(errorCode);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errorCodeString = Integer.toString(errorCode);
|
||||||
|
}
|
||||||
|
message = getResources().getString(R.string.conn_terminated_msg) + "\n\n" +
|
||||||
|
getResources().getString(R.string.error_code_prefix) + " " + errorCodeString;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2443,6 +2418,17 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
hideSystemUi(1000);
|
hideSystemUi(1000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Report this shortcut being used (off the main thread to prevent ANRs)
|
||||||
|
ComputerDetails computer = new ComputerDetails();
|
||||||
|
computer.name = pcName;
|
||||||
|
computer.uuid = Game.this.getIntent().getStringExtra(EXTRA_PC_UUID);
|
||||||
|
ShortcutHelper shortcutHelper = new ShortcutHelper(this);
|
||||||
|
shortcutHelper.reportComputerShortcutUsed(computer);
|
||||||
|
if (appName != null) {
|
||||||
|
// This may be null if launched from the "Resume Session" PC context menu item
|
||||||
|
shortcutHelper.reportGameLaunched(computer, app);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -2645,14 +2631,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
|
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
|
||||||
hideSystemUi(2000);
|
hideSystemUi(2000);
|
||||||
}
|
}
|
||||||
// This flag is only set on 4.4+
|
else if ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
|
||||||
else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT &&
|
|
||||||
(visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
|
|
||||||
hideSystemUi(2000);
|
|
||||||
}
|
|
||||||
// This flag is only set before 4.4+
|
|
||||||
else if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT &&
|
|
||||||
(visibility & View.SYSTEM_UI_FLAG_LOW_PROFILE) == 0) {
|
|
||||||
hideSystemUi(2000);
|
hideSystemUi(2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,6 +260,11 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
updateComputer(details);
|
updateComputer(details);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add a launcher shortcut for this PC (off the main thread to prevent ANRs)
|
||||||
|
if (details.pairState == PairState.PAIRED) {
|
||||||
|
shortcutHelper.createAppViewShortcutForOnlineHost(details);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -720,11 +725,6 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a launcher shortcut for this PC
|
|
||||||
if (details.pairState == PairState.PAIRED) {
|
|
||||||
shortcutHelper.createAppViewShortcutForOnlineHost(details);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existingEntry != null) {
|
if (existingEntry != null) {
|
||||||
// Replace the information in the existing entry
|
// Replace the information in the existing entry
|
||||||
existingEntry.details = details;
|
existingEntry.details = details;
|
||||||
|
@ -8,19 +8,26 @@ import android.content.ServiceConnection;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
import com.limelight.computers.ComputerDatabaseManager;
|
||||||
import com.limelight.computers.ComputerManagerListener;
|
import com.limelight.computers.ComputerManagerListener;
|
||||||
import com.limelight.computers.ComputerManagerService;
|
import com.limelight.computers.ComputerManagerService;
|
||||||
import com.limelight.nvstream.http.ComputerDetails;
|
import com.limelight.nvstream.http.ComputerDetails;
|
||||||
import com.limelight.nvstream.http.NvApp;
|
import com.limelight.nvstream.http.NvApp;
|
||||||
|
import com.limelight.nvstream.http.NvHTTP;
|
||||||
import com.limelight.nvstream.http.PairingManager;
|
import com.limelight.nvstream.http.PairingManager;
|
||||||
import com.limelight.nvstream.wol.WakeOnLanSender;
|
import com.limelight.nvstream.wol.WakeOnLanSender;
|
||||||
|
import com.limelight.utils.CacheHelper;
|
||||||
import com.limelight.utils.Dialog;
|
import com.limelight.utils.Dialog;
|
||||||
import com.limelight.utils.ServerHelper;
|
import com.limelight.utils.ServerHelper;
|
||||||
import com.limelight.utils.SpinnerDialog;
|
import com.limelight.utils.SpinnerDialog;
|
||||||
import com.limelight.utils.UiHelper;
|
import com.limelight.utils.UiHelper;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class ShortcutTrampoline extends Activity {
|
public class ShortcutTrampoline extends Activity {
|
||||||
@ -33,6 +40,7 @@ public class ShortcutTrampoline extends Activity {
|
|||||||
private SpinnerDialog blockingLoadSpinner;
|
private SpinnerDialog blockingLoadSpinner;
|
||||||
|
|
||||||
private ComputerManagerService.ComputerManagerBinder managerBinder;
|
private ComputerManagerService.ComputerManagerBinder managerBinder;
|
||||||
|
|
||||||
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
||||||
public void onServiceConnected(ComponentName className, IBinder binder) {
|
public void onServiceConnected(ComponentName className, IBinder binder) {
|
||||||
final ComputerManagerService.ComputerManagerBinder localBinder =
|
final ComputerManagerService.ComputerManagerBinder localBinder =
|
||||||
@ -214,9 +222,9 @@ public class ShortcutTrampoline extends Activity {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
protected boolean validateInput(String uuidString, String appIdString) {
|
protected boolean validateInput(String uuidString, String appIdString, String nameString) {
|
||||||
// Validate UUID
|
// Validate PC UUID/Name
|
||||||
if (uuidString == null) {
|
if (uuidString == null && nameString == null) {
|
||||||
Dialog.displayDialog(ShortcutTrampoline.this,
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
getResources().getString(R.string.conn_error_title),
|
getResources().getString(R.string.conn_error_title),
|
||||||
getResources().getString(R.string.scut_invalid_uuid),
|
getResources().getString(R.string.scut_invalid_uuid),
|
||||||
@ -224,14 +232,25 @@ public class ShortcutTrampoline extends Activity {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (uuidString != null && !uuidString.isEmpty()) {
|
||||||
UUID.fromString(uuidString);
|
try {
|
||||||
} catch (IllegalArgumentException ex) {
|
UUID.fromString(uuidString);
|
||||||
Dialog.displayDialog(ShortcutTrampoline.this,
|
} catch (IllegalArgumentException ex) {
|
||||||
getResources().getString(R.string.conn_error_title),
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
getResources().getString(R.string.scut_invalid_uuid),
|
getResources().getString(R.string.conn_error_title),
|
||||||
true);
|
getResources().getString(R.string.scut_invalid_uuid),
|
||||||
return false;
|
true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// UUID is null, so fallback to Name
|
||||||
|
if (nameString == null || nameString.isEmpty()) {
|
||||||
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
|
getResources().getString(R.string.conn_error_title),
|
||||||
|
getResources().getString(R.string.scut_invalid_uuid),
|
||||||
|
true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate App ID (if provided)
|
// Validate App ID (if provided)
|
||||||
@ -255,24 +274,93 @@ public class ShortcutTrampoline extends Activity {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
UiHelper.notifyNewRootView(this);
|
UiHelper.notifyNewRootView(this);
|
||||||
|
ComputerDatabaseManager dbManager = new ComputerDatabaseManager(this);
|
||||||
|
ComputerDetails _computer = null;
|
||||||
|
|
||||||
String appIdString = getIntent().getStringExtra(Game.EXTRA_APP_ID);
|
// PC arguments, both are optional, but at least one must be provided
|
||||||
uuidString = getIntent().getStringExtra(AppView.UUID_EXTRA);
|
uuidString = getIntent().getStringExtra(AppView.UUID_EXTRA);
|
||||||
|
String nameString = getIntent().getStringExtra(AppView.NAME_EXTRA);
|
||||||
|
|
||||||
if (validateInput(uuidString, appIdString)) {
|
// App arguments, both are optional, but one must be provided in order to start an app
|
||||||
if (appIdString != null && !appIdString.isEmpty()) {
|
String appIdString = getIntent().getStringExtra(Game.EXTRA_APP_ID);
|
||||||
app = new NvApp(getIntent().getStringExtra(Game.EXTRA_APP_NAME),
|
String appNameString = getIntent().getStringExtra(Game.EXTRA_APP_NAME);
|
||||||
Integer.parseInt(appIdString),
|
|
||||||
getIntent().getBooleanExtra(Game.EXTRA_APP_HDR, false));
|
if (!validateInput(uuidString, appIdString, nameString)) {
|
||||||
|
// Invalid input, so just return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuidString == null || uuidString.isEmpty()) {
|
||||||
|
// Use nameString to find the corresponding UUID
|
||||||
|
_computer = dbManager.getComputerByName(nameString);
|
||||||
|
|
||||||
|
if (_computer == null) {
|
||||||
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
|
getResources().getString(R.string.conn_error_title),
|
||||||
|
getResources().getString(R.string.scut_pc_not_found),
|
||||||
|
true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind to the computer manager service
|
uuidString = _computer.uuid;
|
||||||
bindService(new Intent(this, ComputerManagerService.class), serviceConnection,
|
|
||||||
Service.BIND_AUTO_CREATE);
|
|
||||||
|
|
||||||
blockingLoadSpinner = SpinnerDialog.displayDialog(this, getResources().getString(R.string.conn_establishing_title),
|
// Set the AppView UUID intent, since it wasn't provided
|
||||||
getResources().getString(R.string.applist_connect_msg), true);
|
setIntent(new Intent(getIntent()).putExtra(AppView.UUID_EXTRA, uuidString));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (appIdString != null && !appIdString.isEmpty()) {
|
||||||
|
app = new NvApp(getIntent().getStringExtra(Game.EXTRA_APP_NAME),
|
||||||
|
Integer.parseInt(appIdString),
|
||||||
|
getIntent().getBooleanExtra(Game.EXTRA_APP_HDR, false));
|
||||||
|
}
|
||||||
|
else if (appNameString != null && !appNameString.isEmpty()) {
|
||||||
|
// Use appNameString to find the corresponding AppId
|
||||||
|
try {
|
||||||
|
int appId = -1;
|
||||||
|
String rawAppList = CacheHelper.readInputStreamToString(CacheHelper.openCacheFileForInput(getCacheDir(), "applist", uuidString));
|
||||||
|
|
||||||
|
if (rawAppList.isEmpty()) {
|
||||||
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
|
getResources().getString(R.string.conn_error_title),
|
||||||
|
getResources().getString(R.string.scut_invalid_app_id),
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<NvApp> applist = NvHTTP.getAppListByReader(new StringReader(rawAppList));
|
||||||
|
|
||||||
|
for (NvApp _app : applist) {
|
||||||
|
if (_app.getAppName().equals(appNameString)) {
|
||||||
|
appId = _app.getAppId();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (appId < 0) {
|
||||||
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
|
getResources().getString(R.string.conn_error_title),
|
||||||
|
getResources().getString(R.string.scut_invalid_app_id),
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIntent(new Intent(getIntent()).putExtra(Game.EXTRA_APP_ID, appId));
|
||||||
|
app = new NvApp(
|
||||||
|
appNameString,
|
||||||
|
appId,
|
||||||
|
getIntent().getBooleanExtra(Game.EXTRA_APP_HDR, false));
|
||||||
|
} catch (IOException | XmlPullParserException e) {
|
||||||
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
|
getResources().getString(R.string.conn_error_title),
|
||||||
|
getResources().getString(R.string.scut_invalid_app_id),
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind to the computer manager service
|
||||||
|
bindService(new Intent(this, ComputerManagerService.class), serviceConnection,
|
||||||
|
Service.BIND_AUTO_CREATE);
|
||||||
|
|
||||||
|
blockingLoadSpinner = SpinnerDialog.displayDialog(this, getResources().getString(R.string.conn_establishing_title),
|
||||||
|
getResources().getString(R.string.applist_connect_msg), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -26,51 +26,41 @@ public class AndroidAudioRenderer implements AudioRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private AudioTrack createAudioTrack(int channelConfig, int sampleRate, int bufferSize, boolean lowLatency) {
|
private AudioTrack createAudioTrack(int channelConfig, int sampleRate, int bufferSize, boolean lowLatency) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
AudioAttributes.Builder attributesBuilder = new AudioAttributes.Builder()
|
||||||
return new AudioTrack(AudioManager.STREAM_MUSIC,
|
.setUsage(AudioAttributes.USAGE_GAME);
|
||||||
sampleRate,
|
AudioFormat format = new AudioFormat.Builder()
|
||||||
channelConfig,
|
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
|
||||||
AudioFormat.ENCODING_PCM_16BIT,
|
.setSampleRate(sampleRate)
|
||||||
bufferSize,
|
.setChannelMask(channelConfig)
|
||||||
AudioTrack.MODE_STREAM);
|
.build();
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||||
|
// Use FLAG_LOW_LATENCY on L through N
|
||||||
|
if (lowLatency) {
|
||||||
|
attributesBuilder.setFlags(AudioAttributes.FLAG_LOW_LATENCY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
AudioTrack.Builder trackBuilder = new AudioTrack.Builder()
|
||||||
|
.setAudioFormat(format)
|
||||||
|
.setAudioAttributes(attributesBuilder.build())
|
||||||
|
.setTransferMode(AudioTrack.MODE_STREAM)
|
||||||
|
.setBufferSizeInBytes(bufferSize);
|
||||||
|
|
||||||
|
// Use PERFORMANCE_MODE_LOW_LATENCY on O and later
|
||||||
|
if (lowLatency) {
|
||||||
|
trackBuilder.setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return trackBuilder.build();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
AudioAttributes.Builder attributesBuilder = new AudioAttributes.Builder()
|
return new AudioTrack(attributesBuilder.build(),
|
||||||
.setUsage(AudioAttributes.USAGE_GAME);
|
format,
|
||||||
AudioFormat format = new AudioFormat.Builder()
|
bufferSize,
|
||||||
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
|
AudioTrack.MODE_STREAM,
|
||||||
.setSampleRate(sampleRate)
|
AudioManager.AUDIO_SESSION_ID_GENERATE);
|
||||||
.setChannelMask(channelConfig)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
|
||||||
// Use FLAG_LOW_LATENCY on L through N
|
|
||||||
if (lowLatency) {
|
|
||||||
attributesBuilder.setFlags(AudioAttributes.FLAG_LOW_LATENCY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
AudioTrack.Builder trackBuilder = new AudioTrack.Builder()
|
|
||||||
.setAudioFormat(format)
|
|
||||||
.setAudioAttributes(attributesBuilder.build())
|
|
||||||
.setTransferMode(AudioTrack.MODE_STREAM)
|
|
||||||
.setBufferSizeInBytes(bufferSize);
|
|
||||||
|
|
||||||
// Use PERFORMANCE_MODE_LOW_LATENCY on O and later
|
|
||||||
if (lowLatency) {
|
|
||||||
trackBuilder.setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY);
|
|
||||||
}
|
|
||||||
|
|
||||||
return trackBuilder.build();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return new AudioTrack(attributesBuilder.build(),
|
|
||||||
format,
|
|
||||||
bufferSize,
|
|
||||||
AudioTrack.MODE_STREAM,
|
|
||||||
AudioManager.AUDIO_SESSION_ID_GENERATE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,20 +81,10 @@ public class AndroidAudioRenderer implements AudioRenderer {
|
|||||||
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1;
|
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1;
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
// AudioFormat.CHANNEL_OUT_7POINT1_SURROUND isn't available until Android 6.0,
|
||||||
// AudioFormat.CHANNEL_OUT_7POINT1_SURROUND isn't available until Android 6.0,
|
// yet the CHANNEL_OUT_SIDE_LEFT and CHANNEL_OUT_SIDE_RIGHT constants were added
|
||||||
// yet the CHANNEL_OUT_SIDE_LEFT and CHANNEL_OUT_SIDE_RIGHT constants were added
|
// in 5.0, so just hardcode the constant so we can work on Lollipop.
|
||||||
// in 5.0, so just hardcode the constant so we can work on Lollipop.
|
channelConfig = 0x000018fc; // AudioFormat.CHANNEL_OUT_7POINT1_SURROUND
|
||||||
channelConfig = 0x000018fc; // AudioFormat.CHANNEL_OUT_7POINT1_SURROUND
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// On KitKat and lower, creation of the AudioTrack will fail if we specify
|
|
||||||
// CHANNEL_OUT_SIDE_LEFT or CHANNEL_OUT_SIDE_RIGHT. That leaves us with
|
|
||||||
// the old CHANNEL_OUT_7POINT1 which uses left-of-center and right-of-center
|
|
||||||
// speakers instead of side-left and side-right. This non-standard layout
|
|
||||||
// is probably not what the user wants, but we don't really have a choice.
|
|
||||||
channelConfig = AudioFormat.CHANNEL_OUT_7POINT1;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LimeLog.severe("Decoder returned unhandled channel count");
|
LimeLog.severe("Decoder returned unhandled channel count");
|
||||||
|
@ -12,12 +12,12 @@ import java.security.KeyFactory;
|
|||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.KeyPairGenerator;
|
import java.security.KeyPairGenerator;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.PrivateKey;
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.interfaces.RSAPrivateKey;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
import java.security.spec.PKCS8EncodedKeySpec;
|
import java.security.spec.PKCS8EncodedKeySpec;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
@ -48,7 +48,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
|||||||
private final File keyFile;
|
private final File keyFile;
|
||||||
|
|
||||||
private X509Certificate cert;
|
private X509Certificate cert;
|
||||||
private RSAPrivateKey key;
|
private PrivateKey key;
|
||||||
private byte[] pemCertBytes;
|
private byte[] pemCertBytes;
|
||||||
|
|
||||||
private static final Object globalCryptoLock = new Object();
|
private static final Object globalCryptoLock = new Object();
|
||||||
@ -94,7 +94,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
|||||||
cert = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(certBytes));
|
cert = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(certBytes));
|
||||||
pemCertBytes = certBytes;
|
pemCertBytes = certBytes;
|
||||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA", bcProvider);
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA", bcProvider);
|
||||||
key = (RSAPrivateKey) keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
|
key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
|
||||||
} catch (CertificateException e) {
|
} catch (CertificateException e) {
|
||||||
// May happen if the cert is corrupt
|
// May happen if the cert is corrupt
|
||||||
LimeLog.warning("Corrupted certificate");
|
LimeLog.warning("Corrupted certificate");
|
||||||
@ -144,7 +144,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
|||||||
try {
|
try {
|
||||||
ContentSigner sigGen = new JcaContentSignerBuilder("SHA256withRSA").setProvider(bcProvider).build(keyPair.getPrivate());
|
ContentSigner sigGen = new JcaContentSignerBuilder("SHA256withRSA").setProvider(bcProvider).build(keyPair.getPrivate());
|
||||||
cert = new JcaX509CertificateConverter().setProvider(bcProvider).getCertificate(certBuilder.build(sigGen));
|
cert = new JcaX509CertificateConverter().setProvider(bcProvider).getCertificate(certBuilder.build(sigGen));
|
||||||
key = (RSAPrivateKey) keyPair.getPrivate();
|
key = keyPair.getPrivate();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -215,7 +215,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public RSAPrivateKey getClientPrivateKey() {
|
public PrivateKey getClientPrivateKey() {
|
||||||
// Use a lock here to ensure only one guy will be generating or loading
|
// Use a lock here to ensure only one guy will be generating or loading
|
||||||
// the certificate and key at a time
|
// the certificate and key at a time
|
||||||
synchronized (globalCryptoLock) {
|
synchronized (globalCryptoLock) {
|
||||||
|
@ -63,6 +63,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
|
|
||||||
private static final int EMULATING_SPECIAL = 0x1;
|
private static final int EMULATING_SPECIAL = 0x1;
|
||||||
private static final int EMULATING_SELECT = 0x2;
|
private static final int EMULATING_SELECT = 0x2;
|
||||||
|
private static final int EMULATING_TOUCHPAD = 0x4;
|
||||||
|
|
||||||
private static final short MAX_GAMEPADS = 16; // Limited by bits in activeGamepadMask
|
private static final short MAX_GAMEPADS = 16; // Limited by bits in activeGamepadMask
|
||||||
|
|
||||||
@ -113,6 +114,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
private final double stickDeadzone;
|
private final double stickDeadzone;
|
||||||
private final InputDeviceContext defaultContext = new InputDeviceContext();
|
private final InputDeviceContext defaultContext = new InputDeviceContext();
|
||||||
private final GameGestures gestures;
|
private final GameGestures gestures;
|
||||||
|
private final InputManager inputManager;
|
||||||
private final Vibrator deviceVibrator;
|
private final Vibrator deviceVibrator;
|
||||||
private final VibratorManager deviceVibratorManager;
|
private final VibratorManager deviceVibratorManager;
|
||||||
private final SensorManager deviceSensorManager;
|
private final SensorManager deviceSensorManager;
|
||||||
@ -133,6 +135,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
this.prefConfig = prefConfig;
|
this.prefConfig = prefConfig;
|
||||||
this.deviceVibrator = (Vibrator) activityContext.getSystemService(Context.VIBRATOR_SERVICE);
|
this.deviceVibrator = (Vibrator) activityContext.getSystemService(Context.VIBRATOR_SERVICE);
|
||||||
this.deviceSensorManager = (SensorManager) activityContext.getSystemService(Context.SENSOR_SERVICE);
|
this.deviceSensorManager = (SensorManager) activityContext.getSystemService(Context.SENSOR_SERVICE);
|
||||||
|
this.inputManager = (InputManager) activityContext.getSystemService(Context.INPUT_SERVICE);
|
||||||
this.mainThreadHandler = new Handler(Looper.getMainLooper());
|
this.mainThreadHandler = new Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
// Create a HandlerThread to process battery state updates. These can be slow enough
|
// Create a HandlerThread to process battery state updates. These can be slow enough
|
||||||
@ -204,6 +207,9 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
// currentControllers set which will allow them to properly unplug
|
// currentControllers set which will allow them to properly unplug
|
||||||
// if they are removed.
|
// if they are removed.
|
||||||
initialControllers = getAttachedControllerMask(activityContext);
|
initialControllers = getAttachedControllerMask(activityContext);
|
||||||
|
|
||||||
|
// Register ourselves for input device notifications
|
||||||
|
inputManager.registerInputDeviceListener(this, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputDevice.MotionRange getMotionRangeForJoystickAxis(InputDevice dev, int axis) {
|
private static InputDevice.MotionRange getMotionRangeForJoystickAxis(InputDevice dev, int axis) {
|
||||||
@ -259,9 +265,16 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
|
if (stopped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Stop new device contexts from being created or used
|
// Stop new device contexts from being created or used
|
||||||
stopped = true;
|
stopped = true;
|
||||||
|
|
||||||
|
// Unregister our input device callbacks
|
||||||
|
inputManager.unregisterInputDeviceListener(this);
|
||||||
|
|
||||||
for (int i = 0; i < inputDeviceContexts.size(); i++) {
|
for (int i = 0; i < inputDeviceContexts.size(); i++) {
|
||||||
InputDeviceContext deviceContext = inputDeviceContexts.valueAt(i);
|
InputDeviceContext deviceContext = inputDeviceContexts.valueAt(i);
|
||||||
deviceContext.destroy();
|
deviceContext.destroy();
|
||||||
@ -292,6 +305,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void enableSensors() {
|
public void enableSensors() {
|
||||||
|
if (stopped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < inputDeviceContexts.size(); i++) {
|
for (int i = 0; i < inputDeviceContexts.size(); i++) {
|
||||||
InputDeviceContext deviceContext = inputDeviceContexts.valueAt(i);
|
InputDeviceContext deviceContext = inputDeviceContexts.valueAt(i);
|
||||||
deviceContext.enableSensors();
|
deviceContext.enableSensors();
|
||||||
@ -649,7 +666,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
// back button to function for navigation.
|
// back button to function for navigation.
|
||||||
//
|
//
|
||||||
// First, check if this is an internal device we're being called on.
|
// First, check if this is an internal device we're being called on.
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && !isExternal(dev)) {
|
if (!isExternal(dev)) {
|
||||||
InputManager im = (InputManager) activityContext.getSystemService(Context.INPUT_SERVICE);
|
InputManager im = (InputManager) activityContext.getSystemService(Context.INPUT_SERVICE);
|
||||||
|
|
||||||
boolean foundInternalGamepad = false;
|
boolean foundInternalGamepad = false;
|
||||||
@ -695,10 +712,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
String devName = dev.getName();
|
String devName = dev.getName();
|
||||||
|
|
||||||
LimeLog.info("Creating controller context for device: "+devName);
|
LimeLog.info("Creating controller context for device: "+devName);
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
LimeLog.info("Vendor ID: " + dev.getVendorId());
|
||||||
LimeLog.info("Vendor ID: "+dev.getVendorId());
|
LimeLog.info("Product ID: "+dev.getProductId());
|
||||||
LimeLog.info("Product ID: "+dev.getProductId());
|
|
||||||
}
|
|
||||||
LimeLog.info(dev.toString());
|
LimeLog.info(dev.toString());
|
||||||
|
|
||||||
context.inputDevice = dev;
|
context.inputDevice = dev;
|
||||||
@ -706,15 +721,13 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
context.id = dev.getId();
|
context.id = dev.getId();
|
||||||
context.external = isExternal(dev);
|
context.external = isExternal(dev);
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
context.vendorId = dev.getVendorId();
|
||||||
context.vendorId = dev.getVendorId();
|
context.productId = dev.getProductId();
|
||||||
context.productId = dev.getProductId();
|
|
||||||
|
|
||||||
// These aren't always present in the Android key layout files, so they won't show up
|
// These aren't always present in the Android key layout files, so they won't show up
|
||||||
// in our normal InputDevice.hasKeys() probing.
|
// in our normal InputDevice.hasKeys() probing.
|
||||||
context.hasPaddles = MoonBridge.guessControllerHasPaddles(context.vendorId, context.productId);
|
context.hasPaddles = MoonBridge.guessControllerHasPaddles(context.vendorId, context.productId);
|
||||||
context.hasShare = MoonBridge.guessControllerHasShareButton(context.vendorId, context.productId);
|
context.hasShare = MoonBridge.guessControllerHasShareButton(context.vendorId, context.productId);
|
||||||
}
|
|
||||||
|
|
||||||
// Try to use the InputDevice's associated vibrators first
|
// Try to use the InputDevice's associated vibrators first
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && hasQuadAmplitudeControlledRumbleVibrators(dev.getVibratorManager())) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && hasQuadAmplitudeControlledRumbleVibrators(dev.getVibratorManager())) {
|
||||||
@ -761,13 +774,21 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if this device has a usable RGB LED and cache that result
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
for (Light light : dev.getLightsManager().getLights()) {
|
||||||
|
if (light.hasRgbControl()) {
|
||||||
|
context.hasRgbLed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Detect if the gamepad has Mode and Select buttons according to the Android key layouts.
|
// 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.
|
// 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);
|
||||||
boolean[] buttons = dev.hasKeys(KeyEvent.KEYCODE_BUTTON_MODE, KeyEvent.KEYCODE_BUTTON_SELECT, KeyEvent.KEYCODE_BACK, 0);
|
context.hasMode = buttons[0];
|
||||||
context.hasMode = buttons[0];
|
context.hasSelect = buttons[1] || buttons[2];
|
||||||
context.hasSelect = buttons[1] || buttons[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
context.touchpadXRange = dev.getMotionRange(MotionEvent.AXIS_X, InputDevice.SOURCE_TOUCHPAD);
|
context.touchpadXRange = dev.getMotionRange(MotionEvent.AXIS_X, InputDevice.SOURCE_TOUCHPAD);
|
||||||
context.touchpadYRange = dev.getMotionRange(MotionEvent.AXIS_Y, InputDevice.SOURCE_TOUCHPAD);
|
context.touchpadYRange = dev.getMotionRange(MotionEvent.AXIS_Y, InputDevice.SOURCE_TOUCHPAD);
|
||||||
@ -817,22 +838,15 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
InputDevice.MotionRange rxRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_RX);
|
InputDevice.MotionRange rxRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_RX);
|
||||||
InputDevice.MotionRange ryRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_RY);
|
InputDevice.MotionRange ryRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_RY);
|
||||||
if (rxRange != null && ryRange != null && devName != null) {
|
if (rxRange != null && ryRange != null && devName != null) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
if (dev.getVendorId() == 0x054c) { // Sony
|
||||||
if (dev.getVendorId() == 0x054c) { // Sony
|
if (dev.hasKeys(KeyEvent.KEYCODE_BUTTON_C)[0]) {
|
||||||
if (dev.hasKeys(KeyEvent.KEYCODE_BUTTON_C)[0]) {
|
LimeLog.info("Detected non-standard DualShock 4 mapping");
|
||||||
LimeLog.info("Detected non-standard DualShock 4 mapping");
|
context.isNonStandardDualShock4 = true;
|
||||||
context.isNonStandardDualShock4 = true;
|
} else {
|
||||||
}
|
LimeLog.info("Detected DualShock 4 (Linux standard mapping)");
|
||||||
else {
|
context.usesLinuxGamepadStandardFaceButtons = true;
|
||||||
LimeLog.info("Detected DualShock 4 (Linux standard mapping)");
|
|
||||||
context.usesLinuxGamepadStandardFaceButtons = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!devName.contains("Xbox") && !devName.contains("XBox") && !devName.contains("X-Box")) {
|
|
||||||
LimeLog.info("Assuming non-standard DualShock 4 mapping on < 4.4");
|
|
||||||
context.isNonStandardDualShock4 = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.isNonStandardDualShock4) {
|
if (context.isNonStandardDualShock4) {
|
||||||
// The old DS4 driver uses RX and RY for triggers
|
// The old DS4 driver uses RX and RY for triggers
|
||||||
@ -916,16 +930,12 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The ADT-1 controller needs a similar fixup to the ASUS Gamepad
|
// The ADT-1 controller needs a similar fixup to the ASUS Gamepad
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
if (dev.getVendorId() == 0x18d1 && dev.getProductId() == 0x2c40) {
|
||||||
// The device name provided is just "Gamepad" which is pretty useless, so we
|
context.backIsStart = true;
|
||||||
// use VID/PID instead
|
context.modeIsSelect = true;
|
||||||
if (dev.getVendorId() == 0x18d1 && dev.getProductId() == 0x2c40) {
|
context.triggerDeadzone = 0.30f;
|
||||||
context.backIsStart = true;
|
context.hasSelect = true;
|
||||||
context.modeIsSelect = true;
|
context.hasMode = false;
|
||||||
context.triggerDeadzone = 0.30f;
|
|
||||||
context.hasSelect = true;
|
|
||||||
context.hasMode = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.ignoreBack = shouldIgnoreBack(dev);
|
context.ignoreBack = shouldIgnoreBack(dev);
|
||||||
@ -935,16 +945,12 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
// use the back button as start since it doesn't have a start/menu button
|
// use the back button as start since it doesn't have a start/menu button
|
||||||
// on the controller
|
// on the controller
|
||||||
if (devName.contains("ASUS Gamepad")) {
|
if (devName.contains("ASUS Gamepad")) {
|
||||||
// We can only do this check on KitKat or higher, but it doesn't matter since ATV
|
boolean[] hasStartKey = dev.hasKeys(KeyEvent.KEYCODE_BUTTON_START, KeyEvent.KEYCODE_MENU, 0);
|
||||||
// is Android 5.0 anyway
|
if (!hasStartKey[0] && !hasStartKey[1]) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
context.backIsStart = true;
|
||||||
boolean[] hasStartKey = dev.hasKeys(KeyEvent.KEYCODE_BUTTON_START, KeyEvent.KEYCODE_MENU, 0);
|
context.modeIsSelect = true;
|
||||||
if (!hasStartKey[0] && !hasStartKey[1]) {
|
context.hasSelect = true;
|
||||||
context.backIsStart = true;
|
context.hasMode = false;
|
||||||
context.modeIsSelect = true;
|
|
||||||
context.hasSelect = true;
|
|
||||||
context.hasMode = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The ASUS Gamepad has triggers that sit far forward and are prone to false presses
|
// The ASUS Gamepad has triggers that sit far forward and are prone to false presses
|
||||||
@ -987,6 +993,12 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Thrustmaster Score A gamepad home button reports directly to android as
|
||||||
|
// KEY_HOMEPAGE event on another event channel
|
||||||
|
if (dev.getVendorId() == 0x044f && dev.getProductId() == 0xb328) {
|
||||||
|
context.hasMode = false;
|
||||||
|
}
|
||||||
|
|
||||||
LimeLog.info("Analog stick deadzone: "+context.leftStickDeadzoneRadius+" "+context.rightStickDeadzoneRadius);
|
LimeLog.info("Analog stick deadzone: "+context.leftStickDeadzoneRadius+" "+context.rightStickDeadzoneRadius);
|
||||||
LimeLog.info("Trigger deadzone: "+context.triggerDeadzone);
|
LimeLog.info("Trigger deadzone: "+context.triggerDeadzone);
|
||||||
|
|
||||||
@ -1822,21 +1834,30 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private short scaleRawStickAxis(float stickValue) {
|
private Vector2d convertRawStickAxisToPixelMovement(short stickX, short stickY) {
|
||||||
return (short)Math.pow(stickValue, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendEmulatedMouseEvent(short x, short y) {
|
|
||||||
Vector2d vector = new Vector2d();
|
Vector2d vector = new Vector2d();
|
||||||
vector.initialize(x, y);
|
vector.initialize(stickX, stickY);
|
||||||
vector.scalarMultiply(1 / 32766.0f);
|
vector.scalarMultiply(1 / 32766.0f);
|
||||||
vector.scalarMultiply(4);
|
vector.scalarMultiply(4);
|
||||||
if (vector.getMagnitude() > 0) {
|
if (vector.getMagnitude() > 0) {
|
||||||
// Move faster as the stick is pressed further from center
|
// Move faster as the stick is pressed further from center
|
||||||
vector.scalarMultiply(Math.pow(vector.getMagnitude(), 2));
|
vector.scalarMultiply(Math.pow(vector.getMagnitude(), 2));
|
||||||
if (vector.getMagnitude() >= 1) {
|
}
|
||||||
conn.sendMouseMove((short)vector.getX(), (short)-vector.getY());
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendEmulatedMouseMove(short x, short y) {
|
||||||
|
Vector2d vector = convertRawStickAxisToPixelMovement(x, y);
|
||||||
|
if (vector.getMagnitude() >= 1) {
|
||||||
|
conn.sendMouseMove((short)vector.getX(), (short)-vector.getY());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendEmulatedMouseScroll(short x, short y) {
|
||||||
|
Vector2d vector = convertRawStickAxisToPixelMovement(x, y);
|
||||||
|
if (vector.getMagnitude() >= 1) {
|
||||||
|
conn.sendMouseHighResScroll((short)vector.getY());
|
||||||
|
conn.sendMouseHighResHScroll((short)vector.getX());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2004,21 +2025,22 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
.build();
|
.build();
|
||||||
vibrator.vibrate(VibrationEffect.createWaveform(new long[]{0, onTime, offTime}, 0), vibrationAttributes);
|
vibrator.vibrate(VibrationEffect.createWaveform(new long[]{0, onTime, offTime}, 0), vibrationAttributes);
|
||||||
}
|
}
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
else {
|
||||||
AudioAttributes audioAttributes = new AudioAttributes.Builder()
|
AudioAttributes audioAttributes = new AudioAttributes.Builder()
|
||||||
.setUsage(AudioAttributes.USAGE_GAME)
|
.setUsage(AudioAttributes.USAGE_GAME)
|
||||||
.build();
|
.build();
|
||||||
vibrator.vibrate(new long[]{0, onTime, offTime}, 0, audioAttributes);
|
vibrator.vibrate(new long[]{0, onTime, offTime}, 0, audioAttributes);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
vibrator.vibrate(new long[]{0, onTime, offTime}, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleRumble(short controllerNumber, short lowFreqMotor, short highFreqMotor) {
|
public void handleRumble(short controllerNumber, short lowFreqMotor, short highFreqMotor) {
|
||||||
boolean foundMatchingDevice = false;
|
boolean foundMatchingDevice = false;
|
||||||
boolean vibrated = false;
|
boolean vibrated = false;
|
||||||
|
|
||||||
|
if (stopped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < inputDeviceContexts.size(); i++) {
|
for (int i = 0; i < inputDeviceContexts.size(); i++) {
|
||||||
InputDeviceContext deviceContext = inputDeviceContexts.valueAt(i);
|
InputDeviceContext deviceContext = inputDeviceContexts.valueAt(i);
|
||||||
|
|
||||||
@ -2073,12 +2095,25 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
else if (foundMatchingDevice && !vibrated && prefConfig.vibrateFallbackToDevice) {
|
else if (foundMatchingDevice && !vibrated && prefConfig.vibrateFallbackToDevice) {
|
||||||
// We found a device to vibrate but it didn't have rumble support. The user
|
// We found a device to vibrate but it didn't have rumble support. The user
|
||||||
// has requested us to vibrate the device in this case.
|
// has requested us to vibrate the device in this case.
|
||||||
rumbleSingleVibrator(deviceVibrator, lowFreqMotor, highFreqMotor);
|
|
||||||
|
// We cast the unsigned short value to a signed int before multiplying by
|
||||||
|
// the preferred strength. The resulting value is capped at 65534 before
|
||||||
|
// we cast it back to a short so it doesn't go above 100%.
|
||||||
|
short lowFreqMotorAdjusted = (short)(Math.min((((lowFreqMotor & 0xffff)
|
||||||
|
* prefConfig.vibrateFallbackToDeviceStrength) / 100), Short.MAX_VALUE*2));
|
||||||
|
short highFreqMotorAdjusted = (short)(Math.min((((highFreqMotor & 0xffff)
|
||||||
|
* prefConfig.vibrateFallbackToDeviceStrength) / 100), Short.MAX_VALUE*2));
|
||||||
|
|
||||||
|
rumbleSingleVibrator(deviceVibrator, lowFreqMotorAdjusted, highFreqMotorAdjusted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleRumbleTriggers(short controllerNumber, short leftTrigger, short rightTrigger) {
|
public void handleRumbleTriggers(short controllerNumber, short leftTrigger, short rightTrigger) {
|
||||||
|
if (stopped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
for (int i = 0; i < inputDeviceContexts.size(); i++) {
|
for (int i = 0; i < inputDeviceContexts.size(); i++) {
|
||||||
InputDeviceContext deviceContext = inputDeviceContexts.valueAt(i);
|
InputDeviceContext deviceContext = inputDeviceContexts.valueAt(i);
|
||||||
@ -2190,6 +2225,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void handleSetMotionEventState(final short controllerNumber, final byte motionType, short reportRateHz) {
|
public void handleSetMotionEventState(final short controllerNumber, final byte motionType, short reportRateHz) {
|
||||||
|
if (stopped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Report rate is restricted to <= 200 Hz without the HIGH_SAMPLING_RATE_SENSORS permission
|
// Report rate is restricted to <= 200 Hz without the HIGH_SAMPLING_RATE_SENSORS permission
|
||||||
reportRateHz = (short) Math.min(200, reportRateHz);
|
reportRateHz = (short) Math.min(200, reportRateHz);
|
||||||
|
|
||||||
@ -2251,11 +2290,16 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void handleSetControllerLED(short controllerNumber, byte r, byte g, byte b) {
|
public void handleSetControllerLED(short controllerNumber, byte r, byte g, byte b) {
|
||||||
|
if (stopped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
for (int i = 0; i < inputDeviceContexts.size(); i++) {
|
for (int i = 0; i < inputDeviceContexts.size(); i++) {
|
||||||
InputDeviceContext deviceContext = inputDeviceContexts.valueAt(i);
|
InputDeviceContext deviceContext = inputDeviceContexts.valueAt(i);
|
||||||
|
|
||||||
if (deviceContext.controllerNumber == controllerNumber) {
|
// Ignore input devices without an RGB LED
|
||||||
|
if (deviceContext.controllerNumber == controllerNumber && deviceContext.hasRgbLed) {
|
||||||
// Create a new light session if one doesn't already exist
|
// Create a new light session if one doesn't already exist
|
||||||
if (deviceContext.lightsSession == null) {
|
if (deviceContext.lightsSession == null) {
|
||||||
deviceContext.lightsSession = deviceContext.inputDevice.getLightsManager().openSession();
|
deviceContext.lightsSession = deviceContext.inputDevice.getLightsManager().openSession();
|
||||||
@ -2494,6 +2538,19 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if we're emulating the touchpad button
|
||||||
|
if ((context.emulatingButtonFlags & ControllerHandler.EMULATING_TOUCHPAD) != 0)
|
||||||
|
{
|
||||||
|
// If either select or LB is up, touchpad comes up too
|
||||||
|
if ((context.inputMap & ControllerPacket.BACK_FLAG) == 0 ||
|
||||||
|
(context.inputMap & ControllerPacket.LB_FLAG) == 0)
|
||||||
|
{
|
||||||
|
context.inputMap &= ~ControllerPacket.TOUCHPAD_FLAG;
|
||||||
|
|
||||||
|
context.emulatingButtonFlags &= ~ControllerHandler.EMULATING_TOUCHPAD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sendControllerInputPacket(context);
|
sendControllerInputPacket(context);
|
||||||
|
|
||||||
if (context.pendingExit && context.inputMap == 0) {
|
if (context.pendingExit && context.inputMap == 0) {
|
||||||
@ -2685,6 +2742,18 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
context.emulatingButtonFlags |= ControllerHandler.EMULATING_SELECT;
|
context.emulatingButtonFlags |= ControllerHandler.EMULATING_SELECT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (context.needsClickpadEmulation) {
|
||||||
|
// Select+LB acts like the clickpad when we're faking a PS4 controller for motion support
|
||||||
|
if (context.inputMap == (ControllerPacket.BACK_FLAG | ControllerPacket.LB_FLAG) ||
|
||||||
|
(context.inputMap == ControllerPacket.BACK_FLAG &&
|
||||||
|
event.getEventTime() - context.lastLbUpTime <= MAXIMUM_BUMPER_UP_DELAY_MS))
|
||||||
|
{
|
||||||
|
context.inputMap &= ~(ControllerPacket.BACK_FLAG | ControllerPacket.LB_FLAG);
|
||||||
|
context.inputMap |= ControllerPacket.TOUCHPAD_FLAG;
|
||||||
|
|
||||||
|
context.emulatingButtonFlags |= ControllerHandler.EMULATING_TOUCHPAD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If there is a physical select button, we'll use Start+Select as the special button combo
|
// If there is a physical select button, we'll use Start+Select as the special button combo
|
||||||
// otherwise we'll use Start+RB.
|
// otherwise we'll use Start+RB.
|
||||||
@ -2829,9 +2898,19 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send mouse movement events from analog sticks
|
// Send mouse events from analog sticks
|
||||||
sendEmulatedMouseEvent(leftStickX, leftStickY);
|
if (prefConfig.analogStickForScrolling == PreferenceConfiguration.AnalogStickForScrolling.RIGHT) {
|
||||||
sendEmulatedMouseEvent(rightStickX, rightStickY);
|
sendEmulatedMouseMove(leftStickX, leftStickY);
|
||||||
|
sendEmulatedMouseScroll(rightStickX, rightStickY);
|
||||||
|
}
|
||||||
|
else if (prefConfig.analogStickForScrolling == PreferenceConfiguration.AnalogStickForScrolling.LEFT) {
|
||||||
|
sendEmulatedMouseMove(rightStickX, rightStickY);
|
||||||
|
sendEmulatedMouseScroll(leftStickX, leftStickY);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sendEmulatedMouseMove(leftStickX, leftStickY);
|
||||||
|
sendEmulatedMouseMove(rightStickX, rightStickY);
|
||||||
|
}
|
||||||
|
|
||||||
// Requeue the callback
|
// Requeue the callback
|
||||||
mainThreadHandler.postDelayed(this, mouseEmulationReportPeriod);
|
mainThreadHandler.postDelayed(this, mouseEmulationReportPeriod);
|
||||||
@ -2872,6 +2951,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
|
|
||||||
public InputDevice inputDevice;
|
public InputDevice inputDevice;
|
||||||
|
|
||||||
|
public boolean hasRgbLed;
|
||||||
public LightsManager.LightsSession lightsSession;
|
public LightsManager.LightsSession lightsSession;
|
||||||
|
|
||||||
// These are BatteryState values, not Moonlight values
|
// These are BatteryState values, not Moonlight values
|
||||||
@ -2914,6 +2994,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
public boolean hasMode;
|
public boolean hasMode;
|
||||||
public boolean hasPaddles;
|
public boolean hasPaddles;
|
||||||
public boolean hasShare;
|
public boolean hasShare;
|
||||||
|
public boolean needsClickpadEmulation;
|
||||||
|
|
||||||
// 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
|
||||||
@ -2979,12 +3060,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendControllerArrival() {
|
public void sendControllerArrival() {
|
||||||
// Below KitKat we can't get enough information to report controller details accurately
|
byte type;
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte type = MoonBridge.LI_CTYPE_UNKNOWN;
|
|
||||||
switch (inputDevice.getVendorId()) {
|
switch (inputDevice.getVendorId()) {
|
||||||
case 0x045e: // Microsoft
|
case 0x045e: // Microsoft
|
||||||
type = MoonBridge.LI_CTYPE_XBOX;
|
type = MoonBridge.LI_CTYPE_XBOX;
|
||||||
@ -3038,19 +3114,20 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
capabilities |= MoonBridge.LI_CCAP_RUMBLE;
|
capabilities |= MoonBridge.LI_CCAP_RUMBLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputDevice.getBatteryState().isPresent()) {
|
// Calling InputDevice.getBatteryState() to see if a battery is present
|
||||||
|
// performs a Binder transaction that can cause ANRs on some devices.
|
||||||
|
// To avoid this, we will just claim we can report battery state for all
|
||||||
|
// external gamepad devices on Android S. If it turns out that no battery
|
||||||
|
// is actually present, we'll just report unknown battery state to the host.
|
||||||
|
if (external) {
|
||||||
capabilities |= MoonBridge.LI_CCAP_BATTERY_STATE;
|
capabilities |= MoonBridge.LI_CCAP_BATTERY_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Light light : inputDevice.getLightsManager().getLights()) {
|
// Light.hasRgbControl() was totally broken prior to Android 14.
|
||||||
if (light.hasRgbControl()) {
|
// It always returned true because LIGHT_CAPABILITY_RGB was defined as 0,
|
||||||
// Light.hasRgbControl() was totally broken prior to Android 14.
|
// so we will just guess RGB is supported if it's a PlayStation controller.
|
||||||
// It always returned true because LIGHT_CAPABILITY_RGB was defined as 0,
|
if (hasRgbLed && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE || type == MoonBridge.LI_CTYPE_PS)) {
|
||||||
// so we will just guess RGB is supported if it's a PlayStation controller.
|
capabilities |= MoonBridge.LI_CCAP_RGB_LED;
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE || type == MoonBridge.LI_CTYPE_PS) {
|
|
||||||
capabilities |= MoonBridge.LI_CCAP_RGB_LED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3067,10 +3144,18 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
capabilities |= MoonBridge.LI_CCAP_GYRO;
|
capabilities |= MoonBridge.LI_CCAP_GYRO;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override the detected controller type if we're emulating motion sensors on an Xbox controller
|
byte reportedType;
|
||||||
if (type != MoonBridge.LI_CTYPE_PS && sensorManager != null) {
|
if (type != MoonBridge.LI_CTYPE_PS && sensorManager != null) {
|
||||||
|
// Override the detected controller type if we're emulating motion sensors on an Xbox controller
|
||||||
Toast.makeText(activityContext, activityContext.getResources().getText(R.string.toast_controller_type_changed), Toast.LENGTH_LONG).show();
|
Toast.makeText(activityContext, activityContext.getResources().getText(R.string.toast_controller_type_changed), Toast.LENGTH_LONG).show();
|
||||||
type = MoonBridge.LI_CTYPE_UNKNOWN;
|
reportedType = MoonBridge.LI_CTYPE_UNKNOWN;
|
||||||
|
|
||||||
|
// Remember that we should enable the clickpad emulation combo (Select+LB) for this device
|
||||||
|
needsClickpadEmulation = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Report the true type to the host PC if we're not emulating motion sensors
|
||||||
|
reportedType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can perform basic rumble with any vibrator
|
// We can perform basic rumble with any vibrator
|
||||||
@ -3093,7 +3178,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
}
|
}
|
||||||
|
|
||||||
conn.sendControllerArrivalEvent((byte)controllerNumber, getActiveControllerMask(),
|
conn.sendControllerArrivalEvent((byte)controllerNumber, getActiveControllerMask(),
|
||||||
type, supportedButtonFlags, capabilities);
|
reportedType, supportedButtonFlags, capabilities);
|
||||||
|
|
||||||
// After reporting arrival to the host, send initial battery state and begin monitoring
|
// After reporting arrival to the host, send initial battery state and begin monitoring
|
||||||
backgroundThreadHandler.post(batteryStateUpdateRunnable);
|
backgroundThreadHandler.post(batteryStateUpdateRunnable);
|
||||||
@ -3123,6 +3208,9 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
this.sensorManager = deviceSensorManager;
|
this.sensorManager = deviceSensorManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy state initialized in reportControllerArrival()
|
||||||
|
this.needsClickpadEmulation = oldContext.needsClickpadEmulation;
|
||||||
|
|
||||||
// Re-enable sensors on the new context
|
// Re-enable sensors on the new context
|
||||||
enableSensors();
|
enableSensors();
|
||||||
|
|
||||||
|
@ -65,6 +65,9 @@ public class AndroidNativePointerCaptureProvider extends AndroidPointerIconCaptu
|
|||||||
public void showCursor() {
|
public void showCursor() {
|
||||||
super.showCursor();
|
super.showCursor();
|
||||||
|
|
||||||
|
// It is important to unregister the listener *before* releasing pointer capture,
|
||||||
|
// because releasing pointer capture can cause an onInputDeviceChanged() callback
|
||||||
|
// for devices with a touchpad (like a DS4 controller).
|
||||||
inputManager.unregisterInputDeviceListener(this);
|
inputManager.unregisterInputDeviceListener(this);
|
||||||
targetView.releasePointerCapture();
|
targetView.releasePointerCapture();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.limelight.binding.input.driver;
|
package com.limelight.binding.input.driver;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
@ -210,28 +211,22 @@ public class UsbDriverService extends Service implements UsbDriverListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isRecognizedInputDevice(UsbDevice device) {
|
public static boolean isRecognizedInputDevice(UsbDevice device) {
|
||||||
// On KitKat and later, we can determine if this VID and PID combo
|
// Determine if this VID and PID combo matches an existing input device
|
||||||
// matches an existing input device and defer to the built-in controller
|
// and defer to the built-in controller support in that case.
|
||||||
// support in that case. Prior to KitKat, we'll always return true to be safe.
|
for (int id : InputDevice.getDeviceIds()) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
InputDevice inputDev = InputDevice.getDevice(id);
|
||||||
for (int id : InputDevice.getDeviceIds()) {
|
if (inputDev == null) {
|
||||||
InputDevice inputDev = InputDevice.getDevice(id);
|
// Device was removed while looping
|
||||||
if (inputDev == null) {
|
continue;
|
||||||
// Device was removed while looping
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputDev.getVendorId() == device.getVendorId() &&
|
|
||||||
inputDev.getProductId() == device.getProductId()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
if (inputDev.getVendorId() == device.getVendorId() &&
|
||||||
}
|
inputDev.getProductId() == device.getProductId()) {
|
||||||
else {
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean kernelSupportsXboxOne() {
|
public static boolean kernelSupportsXboxOne() {
|
||||||
@ -286,6 +281,7 @@ public class UsbDriverService extends Service implements UsbDriverListener {
|
|||||||
((!kernelSupportsXbox360W() || claimAllAvailable) && Xbox360WirelessDongle.canClaimDevice(device));
|
((!kernelSupportsXbox360W() || claimAllAvailable) && Xbox360WirelessDongle.canClaimDevice(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
||||||
private void start() {
|
private void start() {
|
||||||
if (started || usbManager == null) {
|
if (started || usbManager == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -39,6 +39,7 @@ public class Xbox360Controller extends AbstractXboxController {
|
|||||||
0x20d6, // PowerA
|
0x20d6, // PowerA
|
||||||
0x24c6, // PowerA
|
0x24c6, // PowerA
|
||||||
0x2f24, // GameSir
|
0x2f24, // GameSir
|
||||||
|
0x2dc8, // 8BitDo
|
||||||
};
|
};
|
||||||
|
|
||||||
public static boolean canClaimDevice(UsbDevice device) {
|
public static boolean canClaimDevice(UsbDevice device) {
|
||||||
|
@ -89,28 +89,26 @@ public class Xbox360WirelessDongle extends AbstractController {
|
|||||||
public boolean start() {
|
public boolean start() {
|
||||||
int controllerIndex = 0;
|
int controllerIndex = 0;
|
||||||
|
|
||||||
// On KitKat, there is a controller number associated with input devices.
|
// On Android, there is a controller number associated with input devices.
|
||||||
// We can use this to approximate the likely controller number. This won't
|
// We can use this to approximate the likely controller number. This won't
|
||||||
// be completely accurate because there's no guarantee the order of interfaces
|
// be completely accurate because there's no guarantee the order of interfaces
|
||||||
// matches the order that devices were enumerated by xpad, but it's probably
|
// matches the order that devices were enumerated by xpad, but it's probably
|
||||||
// better than nothing.
|
// better than nothing.
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
for (int id : InputDevice.getDeviceIds()) {
|
||||||
for (int id : InputDevice.getDeviceIds()) {
|
InputDevice inputDev = InputDevice.getDevice(id);
|
||||||
InputDevice inputDev = InputDevice.getDevice(id);
|
if (inputDev == null) {
|
||||||
if (inputDev == null) {
|
// Device was removed while looping
|
||||||
// Device was removed while looping
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Newer xpad versions use a special product ID (0x02a1) for controllers
|
// Newer xpad versions use a special product ID (0x02a1) for controllers
|
||||||
// rather than copying the product ID of the dongle itself.
|
// rather than copying the product ID of the dongle itself.
|
||||||
if (inputDev.getVendorId() == device.getVendorId() &&
|
if (inputDev.getVendorId() == device.getVendorId() &&
|
||||||
(inputDev.getProductId() == device.getProductId() ||
|
(inputDev.getProductId() == device.getProductId() ||
|
||||||
inputDev.getProductId() == 0x02a1) &&
|
inputDev.getProductId() == 0x02a1) &&
|
||||||
inputDev.getControllerNumber() > 0) {
|
inputDev.getControllerNumber() > 0) {
|
||||||
controllerIndex = inputDev.getControllerNumber() - 1;
|
controllerIndex = inputDev.getControllerNumber() - 1;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +185,10 @@ public class VirtualControllerConfigurationLoader {
|
|||||||
private static final int START_BACK_WIDTH = 12;
|
private static final int START_BACK_WIDTH = 12;
|
||||||
private static final int START_BACK_HEIGHT = 7;
|
private static final int START_BACK_HEIGHT = 7;
|
||||||
|
|
||||||
|
// Make the Guide Menu be in the center of START and BACK menu
|
||||||
|
private static final int GUIDE_X = START_X-BACK_X;
|
||||||
|
private static final int GUIDE_Y = START_BACK_Y;
|
||||||
|
|
||||||
public static void createDefaultLayout(final VirtualController controller, final Context context) {
|
public static void createDefaultLayout(final VirtualController controller, final Context context) {
|
||||||
|
|
||||||
DisplayMetrics screen = context.getResources().getDisplayMetrics();
|
DisplayMetrics screen = context.getResources().getDisplayMetrics();
|
||||||
@ -333,6 +337,16 @@ public class VirtualControllerConfigurationLoader {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(config.showGuideButton){
|
||||||
|
controller.addElement(createDigitalButton(VirtualControllerElement.EID_GDB,
|
||||||
|
ControllerPacket.SPECIAL_BUTTON_FLAG, 0, 1, "GUIDE", -1, controller, context),
|
||||||
|
screenScale(GUIDE_X, height)+ rightDisplacement,
|
||||||
|
screenScale(GUIDE_Y, height),
|
||||||
|
screenScale(START_BACK_WIDTH, height),
|
||||||
|
screenScale(START_BACK_HEIGHT, height)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
controller.setOpacity(config.oscOpacity);
|
controller.setOpacity(config.oscOpacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ public abstract class VirtualControllerElement extends View {
|
|||||||
public static final int EID_RS = 13;
|
public static final int EID_RS = 13;
|
||||||
public static final int EID_LSB = 14;
|
public static final int EID_LSB = 14;
|
||||||
public static final int EID_RSB = 15;
|
public static final int EID_RSB = 15;
|
||||||
|
public static final int EID_GDB = 16;
|
||||||
|
|
||||||
protected VirtualController virtualController;
|
protected VirtualController virtualController;
|
||||||
protected final int elementId;
|
protected final int elementId;
|
||||||
|
@ -3,6 +3,7 @@ package com.limelight.binding.video;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
@ -48,11 +49,10 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
|||||||
private MediaCodecInfo hevcDecoder;
|
private MediaCodecInfo hevcDecoder;
|
||||||
private MediaCodecInfo av1Decoder;
|
private MediaCodecInfo av1Decoder;
|
||||||
|
|
||||||
private byte[] vpsBuffer;
|
private final ArrayList<byte[]> vpsBuffers = new ArrayList<>();
|
||||||
private byte[] spsBuffer;
|
private final ArrayList<byte[]> spsBuffers = new ArrayList<>();
|
||||||
private byte[] ppsBuffer;
|
private final ArrayList<byte[]> ppsBuffers = new ArrayList<>();
|
||||||
private boolean submittedCsd;
|
private boolean submittedCsd;
|
||||||
private boolean submitCsdNextCall;
|
|
||||||
private byte[] currentHdrMetadata;
|
private byte[] currentHdrMetadata;
|
||||||
|
|
||||||
private int nextInputBufferIndex = -1;
|
private int nextInputBufferIndex = -1;
|
||||||
@ -471,9 +471,8 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
|||||||
videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, refreshRate);
|
videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, refreshRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adaptive playback can also be enabled by the whitelist on pre-KitKat devices
|
// Populate keys for adaptive playback
|
||||||
// so we don't fill these pre-KitKat
|
if (adaptivePlayback) {
|
||||||
if (adaptivePlayback && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
|
||||||
videoFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, initialWidth);
|
videoFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, initialWidth);
|
||||||
videoFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, initialHeight);
|
videoFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, initialHeight);
|
||||||
}
|
}
|
||||||
@ -486,7 +485,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
|||||||
|
|
||||||
// If the stream is HDR-capable, the decoder will detect transitions in color standards
|
// If the stream is HDR-capable, the decoder will detect transitions in color standards
|
||||||
// rather than us hardcoding them into the MediaFormat.
|
// rather than us hardcoding them into the MediaFormat.
|
||||||
if (getActiveVideoFormat() != MoonBridge.VIDEO_FORMAT_H265_MAIN10) {
|
if ((getActiveVideoFormat() & MoonBridge.VIDEO_FORMAT_MASK_10BIT) == 0) {
|
||||||
// Set color format keys when not in HDR mode, since we know they won't change
|
// Set color format keys when not in HDR mode, since we know they won't change
|
||||||
videoFormat.setInteger(MediaFormat.KEY_COLOR_TRANSFER, MediaFormat.COLOR_TRANSFER_SDR_VIDEO);
|
videoFormat.setInteger(MediaFormat.KEY_COLOR_TRANSFER, MediaFormat.COLOR_TRANSFER_SDR_VIDEO);
|
||||||
switch (getPreferredColorSpace()) {
|
switch (getPreferredColorSpace()) {
|
||||||
@ -544,10 +543,9 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
|||||||
|
|
||||||
// After reconfiguration, we must resubmit CSD buffers
|
// After reconfiguration, we must resubmit CSD buffers
|
||||||
submittedCsd = false;
|
submittedCsd = false;
|
||||||
submitCsdNextCall = false;
|
vpsBuffers.clear();
|
||||||
vpsBuffer = null;
|
spsBuffers.clear();
|
||||||
spsBuffer = null;
|
ppsBuffers.clear();
|
||||||
ppsBuffer = null;
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
// This will contain the actual accepted input format attributes
|
// This will contain the actual accepted input format attributes
|
||||||
@ -1414,6 +1412,13 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
|||||||
activeWindowVideoStats.frameLossEvents++;
|
activeWindowVideoStats.frameLossEvents++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset CSD data for each IDR frame
|
||||||
|
if (lastFrameNumber != frameNumber && frameType == MoonBridge.FRAME_TYPE_IDR) {
|
||||||
|
vpsBuffers.clear();
|
||||||
|
spsBuffers.clear();
|
||||||
|
ppsBuffers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
lastFrameNumber = frameNumber;
|
lastFrameNumber = frameNumber;
|
||||||
|
|
||||||
// Flip stats windows roughly every second
|
// Flip stats windows roughly every second
|
||||||
@ -1462,250 +1467,270 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
|||||||
activeWindowVideoStats.measurementStartTimestamp = SystemClock.uptimeMillis();
|
activeWindowVideoStats.measurementStartTimestamp = SystemClock.uptimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
long timestampUs;
|
boolean csdSubmittedForThisFrame = false;
|
||||||
int codecFlags = 0;
|
|
||||||
|
|
||||||
// H264 SPS
|
// IDR frames require special handling for CSD buffer submission
|
||||||
if (decodeUnitType == MoonBridge.BUFFER_TYPE_SPS && (videoFormat & MoonBridge.VIDEO_FORMAT_MASK_H264) != 0) {
|
if (frameType == MoonBridge.FRAME_TYPE_IDR) {
|
||||||
numSpsIn++;
|
// H264 SPS
|
||||||
|
if (decodeUnitType == MoonBridge.BUFFER_TYPE_SPS && (videoFormat & MoonBridge.VIDEO_FORMAT_MASK_H264) != 0) {
|
||||||
|
numSpsIn++;
|
||||||
|
|
||||||
ByteBuffer spsBuf = ByteBuffer.wrap(decodeUnitData);
|
ByteBuffer spsBuf = ByteBuffer.wrap(decodeUnitData);
|
||||||
int startSeqLen = decodeUnitData[2] == 0x01 ? 3 : 4;
|
int startSeqLen = decodeUnitData[2] == 0x01 ? 3 : 4;
|
||||||
|
|
||||||
// Skip to the start of the NALU data
|
// Skip to the start of the NALU data
|
||||||
spsBuf.position(startSeqLen + 1);
|
spsBuf.position(startSeqLen + 1);
|
||||||
|
|
||||||
// The H264Utils.readSPS function safely handles
|
// The H264Utils.readSPS function safely handles
|
||||||
// Annex B NALUs (including NALUs with escape sequences)
|
// Annex B NALUs (including NALUs with escape sequences)
|
||||||
SeqParameterSet sps = H264Utils.readSPS(spsBuf);
|
SeqParameterSet sps = H264Utils.readSPS(spsBuf);
|
||||||
|
|
||||||
// Some decoders rely on H264 level to decide how many buffers are needed
|
// Some decoders rely on H264 level to decide how many buffers are needed
|
||||||
// Since we only need one frame buffered, we'll set the level as low as we can
|
// Since we only need one frame buffered, we'll set the level as low as we can
|
||||||
// for known resolution combinations. Reference frame invalidation may need
|
// for known resolution combinations. Reference frame invalidation may need
|
||||||
// these, so leave them be for those decoders.
|
// these, so leave them be for those decoders.
|
||||||
if (!refFrameInvalidationActive) {
|
if (!refFrameInvalidationActive) {
|
||||||
if (initialWidth <= 720 && initialHeight <= 480 && refreshRate <= 60) {
|
if (initialWidth <= 720 && initialHeight <= 480 && refreshRate <= 60) {
|
||||||
// Max 5 buffered frames at 720x480x60
|
// Max 5 buffered frames at 720x480x60
|
||||||
LimeLog.info("Patching level_idc to 31");
|
LimeLog.info("Patching level_idc to 31");
|
||||||
sps.levelIdc = 31;
|
sps.levelIdc = 31;
|
||||||
}
|
}
|
||||||
else if (initialWidth <= 1280 && initialHeight <= 720 && refreshRate <= 60) {
|
else if (initialWidth <= 1280 && initialHeight <= 720 && refreshRate <= 60) {
|
||||||
// Max 5 buffered frames at 1280x720x60
|
// Max 5 buffered frames at 1280x720x60
|
||||||
LimeLog.info("Patching level_idc to 32");
|
LimeLog.info("Patching level_idc to 32");
|
||||||
sps.levelIdc = 32;
|
sps.levelIdc = 32;
|
||||||
}
|
}
|
||||||
else if (initialWidth <= 1920 && initialHeight <= 1080 && refreshRate <= 60) {
|
else if (initialWidth <= 1920 && initialHeight <= 1080 && refreshRate <= 60) {
|
||||||
// Max 4 buffered frames at 1920x1080x64
|
// Max 4 buffered frames at 1920x1080x64
|
||||||
LimeLog.info("Patching level_idc to 42");
|
LimeLog.info("Patching level_idc to 42");
|
||||||
sps.levelIdc = 42;
|
sps.levelIdc = 42;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Leave the profile alone (currently 5.0)
|
// Leave the profile alone (currently 5.0)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// TI OMAP4 requires a reference frame count of 1 to decode successfully. Exynos 4
|
|
||||||
// also requires this fixup.
|
|
||||||
//
|
|
||||||
// I'm doing this fixup for all devices because I haven't seen any devices that
|
|
||||||
// this causes issues for. At worst, it seems to do nothing and at best it fixes
|
|
||||||
// issues with video lag, hangs, and crashes.
|
|
||||||
//
|
|
||||||
// It does break reference frame invalidation, so we will not do that for decoders
|
|
||||||
// where we've enabled reference frame invalidation.
|
|
||||||
if (!refFrameInvalidationActive) {
|
|
||||||
LimeLog.info("Patching num_ref_frames in SPS");
|
|
||||||
sps.numRefFrames = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GFE 2.5.11 changed the SPS to add additional extensions. Some devices don't like these
|
|
||||||
// so we remove them here on old devices unless these devices also support HEVC.
|
|
||||||
// See getPreferredColorSpace() for further information.
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O &&
|
|
||||||
sps.vuiParams != null &&
|
|
||||||
hevcDecoder == null &&
|
|
||||||
av1Decoder == null) {
|
|
||||||
sps.vuiParams.videoSignalTypePresentFlag = false;
|
|
||||||
sps.vuiParams.colourDescriptionPresentFlag = false;
|
|
||||||
sps.vuiParams.chromaLocInfoPresentFlag = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some older devices used to choke on a bitstream restrictions, so we won't provide them
|
|
||||||
// unless explicitly whitelisted. For newer devices, leave the bitstream restrictions present.
|
|
||||||
if (needsSpsBitstreamFixup || isExynos4 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
// The SPS that comes in the current H264 bytestream doesn't set bitstream_restriction_flag
|
|
||||||
// or max_dec_frame_buffering which increases decoding latency on Tegra.
|
|
||||||
|
|
||||||
// If the encoder didn't include VUI parameters in the SPS, add them now
|
|
||||||
if (sps.vuiParams == null) {
|
|
||||||
LimeLog.info("Adding VUI parameters");
|
|
||||||
sps.vuiParams = new VUIParameters();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GFE 2.5.11 started sending bitstream restrictions
|
// TI OMAP4 requires a reference frame count of 1 to decode successfully. Exynos 4
|
||||||
if (sps.vuiParams.bitstreamRestriction == null) {
|
// also requires this fixup.
|
||||||
LimeLog.info("Adding bitstream restrictions");
|
//
|
||||||
sps.vuiParams.bitstreamRestriction = new VUIParameters.BitstreamRestriction();
|
// I'm doing this fixup for all devices because I haven't seen any devices that
|
||||||
sps.vuiParams.bitstreamRestriction.motionVectorsOverPicBoundariesFlag = true;
|
// this causes issues for. At worst, it seems to do nothing and at best it fixes
|
||||||
sps.vuiParams.bitstreamRestriction.maxBytesPerPicDenom = 2;
|
// issues with video lag, hangs, and crashes.
|
||||||
sps.vuiParams.bitstreamRestriction.maxBitsPerMbDenom = 1;
|
//
|
||||||
sps.vuiParams.bitstreamRestriction.log2MaxMvLengthHorizontal = 16;
|
// It does break reference frame invalidation, so we will not do that for decoders
|
||||||
sps.vuiParams.bitstreamRestriction.log2MaxMvLengthVertical = 16;
|
// where we've enabled reference frame invalidation.
|
||||||
sps.vuiParams.bitstreamRestriction.numReorderFrames = 0;
|
if (!refFrameInvalidationActive) {
|
||||||
}
|
LimeLog.info("Patching num_ref_frames in SPS");
|
||||||
else {
|
sps.numRefFrames = 1;
|
||||||
LimeLog.info("Patching bitstream restrictions");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some devices throw errors if maxDecFrameBuffering < numRefFrames
|
// GFE 2.5.11 changed the SPS to add additional extensions. Some devices don't like these
|
||||||
sps.vuiParams.bitstreamRestriction.maxDecFrameBuffering = sps.numRefFrames;
|
// so we remove them here on old devices unless these devices also support HEVC.
|
||||||
|
// See getPreferredColorSpace() for further information.
|
||||||
// These values are the defaults for the fields, but they are more aggressive
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O &&
|
||||||
// than what GFE sends in 2.5.11, but it doesn't seem to cause picture problems.
|
sps.vuiParams != null &&
|
||||||
// We'll leave these alone for "modern" devices just in case they care.
|
hevcDecoder == null &&
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
av1Decoder == null) {
|
||||||
sps.vuiParams.bitstreamRestriction.maxBytesPerPicDenom = 2;
|
sps.vuiParams.videoSignalTypePresentFlag = false;
|
||||||
sps.vuiParams.bitstreamRestriction.maxBitsPerMbDenom = 1;
|
sps.vuiParams.colourDescriptionPresentFlag = false;
|
||||||
|
sps.vuiParams.chromaLocInfoPresentFlag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// log2_max_mv_length_horizontal and log2_max_mv_length_vertical are set to more
|
// Some older devices used to choke on a bitstream restrictions, so we won't provide them
|
||||||
// conservative values by GFE 2.5.11. We'll let those values stand.
|
// unless explicitly whitelisted. For newer devices, leave the bitstream restrictions present.
|
||||||
}
|
if (needsSpsBitstreamFixup || isExynos4 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
else if (sps.vuiParams != null) {
|
// The SPS that comes in the current H264 bytestream doesn't set bitstream_restriction_flag
|
||||||
// Devices that didn't/couldn't get bitstream restrictions before GFE 2.5.11
|
// or max_dec_frame_buffering which increases decoding latency on Tegra.
|
||||||
// will continue to not receive them now
|
|
||||||
sps.vuiParams.bitstreamRestriction = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we need to hack this SPS to say we're baseline, do so now
|
// If the encoder didn't include VUI parameters in the SPS, add them now
|
||||||
if (needsBaselineSpsHack) {
|
if (sps.vuiParams == null) {
|
||||||
LimeLog.info("Hacking SPS to baseline");
|
LimeLog.info("Adding VUI parameters");
|
||||||
sps.profileIdc = 66;
|
sps.vuiParams = new VUIParameters();
|
||||||
savedSps = sps;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Patch the SPS constraint flags
|
// GFE 2.5.11 started sending bitstream restrictions
|
||||||
doProfileSpecificSpsPatching(sps);
|
if (sps.vuiParams.bitstreamRestriction == null) {
|
||||||
|
LimeLog.info("Adding bitstream restrictions");
|
||||||
|
sps.vuiParams.bitstreamRestriction = new VUIParameters.BitstreamRestriction();
|
||||||
|
sps.vuiParams.bitstreamRestriction.motionVectorsOverPicBoundariesFlag = true;
|
||||||
|
sps.vuiParams.bitstreamRestriction.maxBytesPerPicDenom = 2;
|
||||||
|
sps.vuiParams.bitstreamRestriction.maxBitsPerMbDenom = 1;
|
||||||
|
sps.vuiParams.bitstreamRestriction.log2MaxMvLengthHorizontal = 16;
|
||||||
|
sps.vuiParams.bitstreamRestriction.log2MaxMvLengthVertical = 16;
|
||||||
|
sps.vuiParams.bitstreamRestriction.numReorderFrames = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LimeLog.info("Patching bitstream restrictions");
|
||||||
|
}
|
||||||
|
|
||||||
// The H264Utils.writeSPS function safely handles
|
// Some devices throw errors if maxDecFrameBuffering < numRefFrames
|
||||||
// Annex B NALUs (including NALUs with escape sequences)
|
sps.vuiParams.bitstreamRestriction.maxDecFrameBuffering = sps.numRefFrames;
|
||||||
ByteBuffer escapedNalu = H264Utils.writeSPS(sps, decodeUnitLength);
|
|
||||||
|
|
||||||
// Batch this to submit together with PPS
|
// These values are the defaults for the fields, but they are more aggressive
|
||||||
spsBuffer = new byte[startSeqLen + 1 + escapedNalu.limit()];
|
// than what GFE sends in 2.5.11, but it doesn't seem to cause picture problems.
|
||||||
System.arraycopy(decodeUnitData, 0, spsBuffer, 0, startSeqLen + 1);
|
// We'll leave these alone for "modern" devices just in case they care.
|
||||||
escapedNalu.get(spsBuffer, startSeqLen + 1, escapedNalu.limit());
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||||
return MoonBridge.DR_OK;
|
sps.vuiParams.bitstreamRestriction.maxBytesPerPicDenom = 2;
|
||||||
}
|
sps.vuiParams.bitstreamRestriction.maxBitsPerMbDenom = 1;
|
||||||
else if (decodeUnitType == MoonBridge.BUFFER_TYPE_VPS) {
|
}
|
||||||
numVpsIn++;
|
|
||||||
|
|
||||||
// Batch this to submit together with SPS and PPS per AOSP docs
|
// log2_max_mv_length_horizontal and log2_max_mv_length_vertical are set to more
|
||||||
vpsBuffer = new byte[decodeUnitLength];
|
// conservative values by GFE 2.5.11. We'll let those values stand.
|
||||||
System.arraycopy(decodeUnitData, 0, vpsBuffer, 0, decodeUnitLength);
|
}
|
||||||
return MoonBridge.DR_OK;
|
else if (sps.vuiParams != null) {
|
||||||
}
|
// Devices that didn't/couldn't get bitstream restrictions before GFE 2.5.11
|
||||||
// Only the HEVC SPS hits this path (H.264 is handled above)
|
// will continue to not receive them now
|
||||||
else if (decodeUnitType == MoonBridge.BUFFER_TYPE_SPS) {
|
sps.vuiParams.bitstreamRestriction = null;
|
||||||
numSpsIn++;
|
|
||||||
|
|
||||||
// Batch this to submit together with VPS and PPS per AOSP docs
|
|
||||||
spsBuffer = new byte[decodeUnitLength];
|
|
||||||
System.arraycopy(decodeUnitData, 0, spsBuffer, 0, decodeUnitLength);
|
|
||||||
return MoonBridge.DR_OK;
|
|
||||||
}
|
|
||||||
else if (decodeUnitType == MoonBridge.BUFFER_TYPE_PPS) {
|
|
||||||
numPpsIn++;
|
|
||||||
|
|
||||||
// If this is the first CSD blob or we aren't supporting
|
|
||||||
// fused IDR frames, we will submit the CSD blob in a
|
|
||||||
// separate input buffer.
|
|
||||||
if (!submittedCsd || !fusedIdrFrame) {
|
|
||||||
if (!fetchNextInputBuffer()) {
|
|
||||||
return MoonBridge.DR_NEED_IDR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// When we get the PPS, submit the VPS and SPS together with
|
// If we need to hack this SPS to say we're baseline, do so now
|
||||||
// the PPS, as required by AOSP docs on use of MediaCodec.
|
if (needsBaselineSpsHack) {
|
||||||
if (vpsBuffer != null) {
|
LimeLog.info("Hacking SPS to baseline");
|
||||||
nextInputBuffer.put(vpsBuffer);
|
sps.profileIdc = 66;
|
||||||
}
|
savedSps = sps;
|
||||||
if (spsBuffer != null) {
|
|
||||||
nextInputBuffer.put(spsBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the CSD blob
|
// Patch the SPS constraint flags
|
||||||
codecFlags |= MediaCodec.BUFFER_FLAG_CODEC_CONFIG;
|
doProfileSpecificSpsPatching(sps);
|
||||||
timestampUs = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Batch this to submit together with the next I-frame
|
|
||||||
ppsBuffer = new byte[decodeUnitLength];
|
|
||||||
System.arraycopy(decodeUnitData, 0, ppsBuffer, 0, decodeUnitLength);
|
|
||||||
|
|
||||||
// Next call will be I-frame data
|
// The H264Utils.writeSPS function safely handles
|
||||||
submitCsdNextCall = true;
|
// Annex B NALUs (including NALUs with escape sequences)
|
||||||
|
ByteBuffer escapedNalu = H264Utils.writeSPS(sps, decodeUnitLength);
|
||||||
|
|
||||||
|
// Construct the patched SPS
|
||||||
|
byte[] naluBuffer = new byte[startSeqLen + 1 + escapedNalu.limit()];
|
||||||
|
System.arraycopy(decodeUnitData, 0, naluBuffer, 0, startSeqLen + 1);
|
||||||
|
escapedNalu.get(naluBuffer, startSeqLen + 1, escapedNalu.limit());
|
||||||
|
|
||||||
|
// Batch this to submit together with other CSD per AOSP docs
|
||||||
|
spsBuffers.add(naluBuffer);
|
||||||
return MoonBridge.DR_OK;
|
return MoonBridge.DR_OK;
|
||||||
}
|
}
|
||||||
}
|
else if (decodeUnitType == MoonBridge.BUFFER_TYPE_VPS) {
|
||||||
else {
|
numVpsIn++;
|
||||||
if (frameHostProcessingLatency != 0) {
|
|
||||||
if (activeWindowVideoStats.minHostProcessingLatency != 0) {
|
// Batch this to submit together with other CSD per AOSP docs
|
||||||
activeWindowVideoStats.minHostProcessingLatency = (char) Math.min(activeWindowVideoStats.minHostProcessingLatency, frameHostProcessingLatency);
|
byte[] naluBuffer = new byte[decodeUnitLength];
|
||||||
} else {
|
System.arraycopy(decodeUnitData, 0, naluBuffer, 0, decodeUnitLength);
|
||||||
activeWindowVideoStats.minHostProcessingLatency = frameHostProcessingLatency;
|
vpsBuffers.add(naluBuffer);
|
||||||
|
return MoonBridge.DR_OK;
|
||||||
|
}
|
||||||
|
// Only the HEVC SPS hits this path (H.264 is handled above)
|
||||||
|
else if (decodeUnitType == MoonBridge.BUFFER_TYPE_SPS) {
|
||||||
|
numSpsIn++;
|
||||||
|
|
||||||
|
// Batch this to submit together with other CSD per AOSP docs
|
||||||
|
byte[] naluBuffer = new byte[decodeUnitLength];
|
||||||
|
System.arraycopy(decodeUnitData, 0, naluBuffer, 0, decodeUnitLength);
|
||||||
|
spsBuffers.add(naluBuffer);
|
||||||
|
return MoonBridge.DR_OK;
|
||||||
|
}
|
||||||
|
else if (decodeUnitType == MoonBridge.BUFFER_TYPE_PPS) {
|
||||||
|
numPpsIn++;
|
||||||
|
|
||||||
|
// Batch this to submit together with other CSD per AOSP docs
|
||||||
|
byte[] naluBuffer = new byte[decodeUnitLength];
|
||||||
|
System.arraycopy(decodeUnitData, 0, naluBuffer, 0, decodeUnitLength);
|
||||||
|
ppsBuffers.add(naluBuffer);
|
||||||
|
return MoonBridge.DR_OK;
|
||||||
|
}
|
||||||
|
else if ((videoFormat & (MoonBridge.VIDEO_FORMAT_MASK_H264 | MoonBridge.VIDEO_FORMAT_MASK_H265)) != 0) {
|
||||||
|
// If this is the first CSD blob or we aren't supporting fused IDR frames, we will
|
||||||
|
// submit the CSD blob in a separate input buffer for each IDR frame.
|
||||||
|
if (!submittedCsd || !fusedIdrFrame) {
|
||||||
|
if (!fetchNextInputBuffer()) {
|
||||||
|
return MoonBridge.DR_NEED_IDR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Submit all CSD when we receive the first non-CSD blob in an IDR frame
|
||||||
|
for (byte[] vpsBuffer : vpsBuffers) {
|
||||||
|
nextInputBuffer.put(vpsBuffer);
|
||||||
|
}
|
||||||
|
for (byte[] spsBuffer : spsBuffers) {
|
||||||
|
nextInputBuffer.put(spsBuffer);
|
||||||
|
}
|
||||||
|
for (byte[] ppsBuffer : ppsBuffers) {
|
||||||
|
nextInputBuffer.put(ppsBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!queueNextInputBuffer(0, MediaCodec.BUFFER_FLAG_CODEC_CONFIG)) {
|
||||||
|
return MoonBridge.DR_NEED_IDR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember that we already submitted CSD for this frame, so we don't do it
|
||||||
|
// again in the fused IDR case below.
|
||||||
|
csdSubmittedForThisFrame = true;
|
||||||
|
|
||||||
|
// Remember that we submitted CSD globally for this MediaCodec instance
|
||||||
|
submittedCsd = true;
|
||||||
|
|
||||||
|
if (needsBaselineSpsHack) {
|
||||||
|
needsBaselineSpsHack = false;
|
||||||
|
|
||||||
|
if (!replaySps()) {
|
||||||
|
return MoonBridge.DR_NEED_IDR;
|
||||||
|
}
|
||||||
|
|
||||||
|
LimeLog.info("SPS replay complete");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
activeWindowVideoStats.framesWithHostProcessingLatency += 1;
|
|
||||||
}
|
}
|
||||||
activeWindowVideoStats.maxHostProcessingLatency = (char) Math.max(activeWindowVideoStats.maxHostProcessingLatency, frameHostProcessingLatency);
|
}
|
||||||
activeWindowVideoStats.totalHostProcessingLatency += frameHostProcessingLatency;
|
|
||||||
|
|
||||||
activeWindowVideoStats.totalFramesReceived++;
|
if (frameHostProcessingLatency != 0) {
|
||||||
activeWindowVideoStats.totalFrames++;
|
if (activeWindowVideoStats.minHostProcessingLatency != 0) {
|
||||||
|
activeWindowVideoStats.minHostProcessingLatency = (char) Math.min(activeWindowVideoStats.minHostProcessingLatency, frameHostProcessingLatency);
|
||||||
if (!FRAME_RENDER_TIME_ONLY) {
|
} else {
|
||||||
// Count time from first packet received to enqueue time as receive time
|
activeWindowVideoStats.minHostProcessingLatency = frameHostProcessingLatency;
|
||||||
// We will count DU queue time as part of decoding, because it is directly
|
|
||||||
// caused by a slow decoder.
|
|
||||||
activeWindowVideoStats.totalTimeMs += enqueueTimeMs - receiveTimeMs;
|
|
||||||
}
|
}
|
||||||
|
activeWindowVideoStats.framesWithHostProcessingLatency += 1;
|
||||||
|
}
|
||||||
|
activeWindowVideoStats.maxHostProcessingLatency = (char) Math.max(activeWindowVideoStats.maxHostProcessingLatency, frameHostProcessingLatency);
|
||||||
|
activeWindowVideoStats.totalHostProcessingLatency += frameHostProcessingLatency;
|
||||||
|
|
||||||
if (!fetchNextInputBuffer()) {
|
activeWindowVideoStats.totalFramesReceived++;
|
||||||
return MoonBridge.DR_NEED_IDR;
|
activeWindowVideoStats.totalFrames++;
|
||||||
}
|
|
||||||
|
|
||||||
if (submitCsdNextCall) {
|
if (!FRAME_RENDER_TIME_ONLY) {
|
||||||
if (vpsBuffer != null) {
|
// Count time from first packet received to enqueue time as receive time
|
||||||
|
// We will count DU queue time as part of decoding, because it is directly
|
||||||
|
// caused by a slow decoder.
|
||||||
|
activeWindowVideoStats.totalTimeMs += enqueueTimeMs - receiveTimeMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fetchNextInputBuffer()) {
|
||||||
|
return MoonBridge.DR_NEED_IDR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int codecFlags = 0;
|
||||||
|
|
||||||
|
if (frameType == MoonBridge.FRAME_TYPE_IDR) {
|
||||||
|
codecFlags |= MediaCodec.BUFFER_FLAG_SYNC_FRAME;
|
||||||
|
|
||||||
|
// If we are using fused IDR frames, submit the CSD with each IDR frame
|
||||||
|
if (fusedIdrFrame && !csdSubmittedForThisFrame) {
|
||||||
|
for (byte[] vpsBuffer : vpsBuffers) {
|
||||||
nextInputBuffer.put(vpsBuffer);
|
nextInputBuffer.put(vpsBuffer);
|
||||||
}
|
}
|
||||||
if (spsBuffer != null) {
|
for (byte[] spsBuffer : spsBuffers) {
|
||||||
nextInputBuffer.put(spsBuffer);
|
nextInputBuffer.put(spsBuffer);
|
||||||
}
|
}
|
||||||
if (ppsBuffer != null) {
|
for (byte[] ppsBuffer : ppsBuffers) {
|
||||||
nextInputBuffer.put(ppsBuffer);
|
nextInputBuffer.put(ppsBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
submitCsdNextCall = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frameType == MoonBridge.FRAME_TYPE_IDR) {
|
|
||||||
codecFlags |= MediaCodec.BUFFER_FLAG_SYNC_FRAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
timestampUs = enqueueTimeMs * 1000;
|
|
||||||
|
|
||||||
if (timestampUs <= lastTimestampUs) {
|
|
||||||
// We can't submit multiple buffers with the same timestamp
|
|
||||||
// so bump it up by one before queuing
|
|
||||||
timestampUs = lastTimestampUs + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastTimestampUs = timestampUs;
|
|
||||||
|
|
||||||
numFramesIn++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long timestampUs = enqueueTimeMs * 1000;
|
||||||
|
if (timestampUs <= lastTimestampUs) {
|
||||||
|
// We can't submit multiple buffers with the same timestamp
|
||||||
|
// so bump it up by one before queuing
|
||||||
|
timestampUs = lastTimestampUs + 1;
|
||||||
|
}
|
||||||
|
lastTimestampUs = timestampUs;
|
||||||
|
|
||||||
|
numFramesIn++;
|
||||||
|
|
||||||
if (decodeUnitLength > nextInputBuffer.limit() - nextInputBuffer.position()) {
|
if (decodeUnitLength > nextInputBuffer.limit() - nextInputBuffer.position()) {
|
||||||
IllegalArgumentException exception = new IllegalArgumentException(
|
IllegalArgumentException exception = new IllegalArgumentException(
|
||||||
"Decode unit length "+decodeUnitLength+" too large for input buffer "+nextInputBuffer.limit());
|
"Decode unit length "+decodeUnitLength+" too large for input buffer "+nextInputBuffer.limit());
|
||||||
@ -1723,20 +1748,6 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements C
|
|||||||
return MoonBridge.DR_NEED_IDR;
|
return MoonBridge.DR_NEED_IDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((codecFlags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
|
|
||||||
submittedCsd = true;
|
|
||||||
|
|
||||||
if (needsBaselineSpsHack) {
|
|
||||||
needsBaselineSpsHack = false;
|
|
||||||
|
|
||||||
if (!replaySps()) {
|
|
||||||
return MoonBridge.DR_NEED_IDR;
|
|
||||||
}
|
|
||||||
|
|
||||||
LimeLog.info("SPS replay complete");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return MoonBridge.DR_OK;
|
return MoonBridge.DR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -596,45 +596,39 @@ public class MediaCodecHelper {
|
|||||||
|
|
||||||
public static boolean decoderSupportsFusedIdrFrame(MediaCodecInfo decoderInfo, String mimeType) {
|
public static boolean decoderSupportsFusedIdrFrame(MediaCodecInfo decoderInfo, String mimeType) {
|
||||||
// If adaptive playback is supported, we can submit new CSD together with a keyframe
|
// If adaptive playback is supported, we can submit new CSD together with a keyframe
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
try {
|
||||||
try {
|
if (decoderInfo.getCapabilitiesForType(mimeType).
|
||||||
if (decoderInfo.getCapabilitiesForType(mimeType).
|
isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback)) {
|
||||||
isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback))
|
LimeLog.info("Decoder supports fused IDR frames (FEATURE_AdaptivePlayback)");
|
||||||
{
|
return true;
|
||||||
LimeLog.info("Decoder supports fused IDR frames (FEATURE_AdaptivePlayback)");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Tolerate buggy codecs
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Tolerate buggy codecs
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean decoderSupportsAdaptivePlayback(MediaCodecInfo decoderInfo, String mimeType) {
|
public static boolean decoderSupportsAdaptivePlayback(MediaCodecInfo decoderInfo, String mimeType) {
|
||||||
// Possibly enable adaptive playback on KitKat and above
|
if (isDecoderInList(blacklistedAdaptivePlaybackPrefixes, decoderInfo.getName())) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
LimeLog.info("Decoder blacklisted for adaptive playback");
|
||||||
if (isDecoderInList(blacklistedAdaptivePlaybackPrefixes, decoderInfo.getName())) {
|
return false;
|
||||||
LimeLog.info("Decoder blacklisted for adaptive playback");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (decoderInfo.getCapabilitiesForType(mimeType).
|
|
||||||
isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback))
|
|
||||||
{
|
|
||||||
// This will make getCapabilities() return that adaptive playback is supported
|
|
||||||
LimeLog.info("Adaptive playback supported (FEATURE_AdaptivePlayback)");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Tolerate buggy codecs
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (decoderInfo.getCapabilitiesForType(mimeType).
|
||||||
|
isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback))
|
||||||
|
{
|
||||||
|
// This will make getCapabilities() return that adaptive playback is supported
|
||||||
|
LimeLog.info("Adaptive playback supported (FEATURE_AdaptivePlayback)");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Tolerate buggy codecs
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -709,13 +703,6 @@ public class MediaCodecHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean decoderIsWhitelistedForHevc(MediaCodecInfo decoderInfo) {
|
public static boolean decoderIsWhitelistedForHevc(MediaCodecInfo decoderInfo) {
|
||||||
// Google didn't have official support for HEVC (or more importantly, a CTS test) until
|
|
||||||
// Lollipop. I've seen some MediaTek devices on 4.4 crash when attempting to use HEVC,
|
|
||||||
// so I'm restricting HEVC usage to Lollipop and higher.
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Software decoders are terrible and we never want to use them.
|
// Software decoders are terrible and we never want to use them.
|
||||||
// We want to catch decoders like:
|
// We want to catch decoders like:
|
||||||
@ -784,17 +771,10 @@ public class MediaCodecHelper {
|
|||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
private static LinkedList<MediaCodecInfo> getMediaCodecList() {
|
private static LinkedList<MediaCodecInfo> getMediaCodecList() {
|
||||||
LinkedList<MediaCodecInfo> infoList = new LinkedList<>();
|
LinkedList<MediaCodecInfo> infoList = new LinkedList<>();
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
|
||||||
MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
|
Collections.addAll(infoList, mcl.getCodecInfos());
|
||||||
Collections.addAll(infoList, mcl.getCodecInfos());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
|
||||||
infoList.add(MediaCodecList.getCodecInfoAt(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return infoList;
|
return infoList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,6 +190,35 @@ public class ComputerDatabaseManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a computer by name
|
||||||
|
* NOTE: It is perfectly valid for multiple computers to have the same name,
|
||||||
|
* this function will only return the first one it finds.
|
||||||
|
* Consider using getComputerByUUID instead.
|
||||||
|
* @param name The name of the computer
|
||||||
|
* @see ComputerDatabaseManager#getComputerByUUID(String) for alternative.
|
||||||
|
* @return The computer details, or null if no computer with that name exists
|
||||||
|
*/
|
||||||
|
public ComputerDetails getComputerByName(String name) {
|
||||||
|
try (final Cursor c = computerDb.query(
|
||||||
|
COMPUTER_TABLE_NAME, null, COMPUTER_NAME_COLUMN_NAME+"=?",
|
||||||
|
new String[]{ name }, null, null, null)
|
||||||
|
) {
|
||||||
|
if (!c.moveToFirst()) {
|
||||||
|
// No matching computer
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getComputerFromCursor(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a computer by UUID
|
||||||
|
* @param uuid The UUID of the computer
|
||||||
|
* @see ComputerDatabaseManager#getComputerByName(String) for alternative.
|
||||||
|
* @return The computer details, or null if no computer with that UUID exists
|
||||||
|
*/
|
||||||
public ComputerDetails getComputerByUUID(String uuid) {
|
public ComputerDetails getComputerByUUID(String uuid) {
|
||||||
try (final Cursor c = computerDb.query(
|
try (final Cursor c = computerDb.query(
|
||||||
COMPUTER_TABLE_NAME, null, COMPUTER_UUID_COLUMN_NAME+"=?",
|
COMPUTER_TABLE_NAME, null, COMPUTER_UUID_COLUMN_NAME+"=?",
|
||||||
|
@ -341,57 +341,53 @@ public class ComputerManagerService extends Service {
|
|||||||
// Acquire the default network lock since we could be changing global process state
|
// Acquire the default network lock since we could be changing global process state
|
||||||
defaultNetworkLock.lock();
|
defaultNetworkLock.lock();
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
// On Lollipop or later, we can bind our process to the underlying interface
|
||||||
// On Lollipop or later, we can bind our process to the underlying interface
|
// to ensure our STUN request goes out on that interface or not at all (which is
|
||||||
// to ensure our STUN request goes out on that interface or not at all (which is
|
// preferable to getting a VPN endpoint address back).
|
||||||
// preferable to getting a VPN endpoint address back).
|
Network[] networks = connMgr.getAllNetworks();
|
||||||
Network[] networks = connMgr.getAllNetworks();
|
for (Network net : networks) {
|
||||||
for (Network net : networks) {
|
NetworkCapabilities netCaps = connMgr.getNetworkCapabilities(net);
|
||||||
NetworkCapabilities netCaps = connMgr.getNetworkCapabilities(net);
|
if (netCaps != null) {
|
||||||
if (netCaps != null) {
|
if (!netCaps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) &&
|
||||||
if (!netCaps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) &&
|
!netCaps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
|
||||||
!netCaps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
|
// This network looks like an underlying multicast-capable transport,
|
||||||
// This network looks like an underlying multicast-capable transport,
|
// so let's guess that it's probably where our mDNS response came from.
|
||||||
// so let's guess that it's probably where our mDNS response came from.
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (connMgr.bindProcessToNetwork(net)) {
|
||||||
if (connMgr.bindProcessToNetwork(net)) {
|
|
||||||
boundToNetwork = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ConnectivityManager.setProcessDefaultNetwork(net)) {
|
|
||||||
boundToNetwork = true;
|
boundToNetwork = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else if (ConnectivityManager.setProcessDefaultNetwork(net)) {
|
||||||
|
boundToNetwork = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Perform the STUN request if we're not on a VPN or if we bound to a network
|
// Perform the STUN request if we're not on a VPN or if we bound to a network
|
||||||
if (!activeNetworkIsVpn || boundToNetwork) {
|
if (!activeNetworkIsVpn || boundToNetwork) {
|
||||||
String stunResolvedAddress = NvConnection.findExternalAddressForMdns("stun.moonlight-stream.org", 3478);
|
String stunResolvedAddress = NvConnection.findExternalAddressForMdns("stun.moonlight-stream.org", 3478);
|
||||||
if (stunResolvedAddress != null) {
|
if (stunResolvedAddress != null) {
|
||||||
// We don't know for sure what the external port is, so we will have to guess.
|
// We don't know for sure what the external port is, so we will have to guess.
|
||||||
// When we contact the PC (if we haven't already), it will update the port.
|
// When we contact the PC (if we haven't already), it will update the port.
|
||||||
details.remoteAddress = new ComputerDetails.AddressTuple(stunResolvedAddress, details.guessExternalPort());
|
details.remoteAddress = new ComputerDetails.AddressTuple(stunResolvedAddress, details.guessExternalPort());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Unbind from the network
|
// Unbind from the network
|
||||||
if (boundToNetwork) {
|
if (boundToNetwork) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
connMgr.bindProcessToNetwork(null);
|
connMgr.bindProcessToNetwork(null);
|
||||||
|
} else {
|
||||||
|
ConnectivityManager.setProcessDefaultNetwork(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
ConnectivityManager.setProcessDefaultNetwork(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unlock the network state
|
// Unlock the network state
|
||||||
if (activeNetworkIsVpn) {
|
if (activeNetworkIsVpn) {
|
||||||
defaultNetworkLock.unlock();
|
defaultNetworkLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,14 +28,8 @@ public class DiskAssetLoader {
|
|||||||
|
|
||||||
public DiskAssetLoader(Context context) {
|
public DiskAssetLoader(Context context) {
|
||||||
this.cacheDir = context.getCacheDir();
|
this.cacheDir = context.getCacheDir();
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
this.isLowRamDevice =
|
||||||
this.isLowRamDevice =
|
((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).isLowRamDevice();
|
||||||
((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).isLowRamDevice();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Use conservative low RAM behavior on very old devices
|
|
||||||
this.isLowRamDevice = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkCacheExists(CachedAppAssetLoader.LoaderTuple tuple) {
|
public boolean checkCacheExists(CachedAppAssetLoader.LoaderTuple tuple) {
|
||||||
|
@ -198,7 +198,7 @@ public class NvConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
else {
|
||||||
NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo();
|
NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo();
|
||||||
if (activeNetworkInfo != null) {
|
if (activeNetworkInfo != null) {
|
||||||
switch (activeNetworkInfo.getType()) {
|
switch (activeNetworkInfo.getType()) {
|
||||||
@ -433,10 +433,7 @@ public class NvConnection {
|
|||||||
context.negotiatedPacketSize, context.negotiatedRemoteStreaming,
|
context.negotiatedPacketSize, context.negotiatedRemoteStreaming,
|
||||||
context.streamConfig.getAudioConfiguration().toInt(),
|
context.streamConfig.getAudioConfiguration().toInt(),
|
||||||
context.streamConfig.getSupportedVideoFormats(),
|
context.streamConfig.getSupportedVideoFormats(),
|
||||||
context.streamConfig.getHevcBitratePercentageMultiplier(),
|
|
||||||
context.streamConfig.getAv1BitratePercentageMultiplier(),
|
|
||||||
context.streamConfig.getClientRefreshRateX100(),
|
context.streamConfig.getClientRefreshRateX100(),
|
||||||
context.streamConfig.getEncryptionFlags(),
|
|
||||||
context.riKey.getEncoded(), ib.array(),
|
context.riKey.getEncoded(), ib.array(),
|
||||||
context.videoCapabilities,
|
context.videoCapabilities,
|
||||||
context.streamConfig.getColorSpace(),
|
context.streamConfig.getColorSpace(),
|
||||||
|
@ -23,8 +23,6 @@ public class StreamConfiguration {
|
|||||||
private int remote;
|
private int remote;
|
||||||
private MoonBridge.AudioConfiguration audioConfiguration;
|
private MoonBridge.AudioConfiguration audioConfiguration;
|
||||||
private int supportedVideoFormats;
|
private int supportedVideoFormats;
|
||||||
private int hevcBitratePercentageMultiplier;
|
|
||||||
private int av1BitratePercentageMultiplier;
|
|
||||||
private int attachedGamepadMask;
|
private int attachedGamepadMask;
|
||||||
private int encryptionFlags;
|
private int encryptionFlags;
|
||||||
private int colorRange;
|
private int colorRange;
|
||||||
@ -85,16 +83,6 @@ public class StreamConfiguration {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StreamConfiguration.Builder setHevcBitratePercentageMultiplier(int multiplier) {
|
|
||||||
config.hevcBitratePercentageMultiplier = multiplier;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public StreamConfiguration.Builder setAv1BitratePercentageMultiplier(int multiplier) {
|
|
||||||
config.av1BitratePercentageMultiplier = multiplier;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public StreamConfiguration.Builder setAttachedGamepadMask(int attachedGamepadMask) {
|
public StreamConfiguration.Builder setAttachedGamepadMask(int attachedGamepadMask) {
|
||||||
config.attachedGamepadMask = attachedGamepadMask;
|
config.attachedGamepadMask = attachedGamepadMask;
|
||||||
return this;
|
return this;
|
||||||
@ -120,16 +108,6 @@ public class StreamConfiguration {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StreamConfiguration.Builder setAudioEncryption(boolean enable) {
|
|
||||||
if (enable) {
|
|
||||||
config.encryptionFlags |= MoonBridge.ENCFLG_AUDIO;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
config.encryptionFlags &= ~MoonBridge.ENCFLG_AUDIO;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public StreamConfiguration.Builder setAudioConfiguration(MoonBridge.AudioConfiguration audioConfig) {
|
public StreamConfiguration.Builder setAudioConfiguration(MoonBridge.AudioConfiguration audioConfig) {
|
||||||
config.audioConfiguration = audioConfig;
|
config.audioConfiguration = audioConfig;
|
||||||
return this;
|
return this;
|
||||||
@ -224,14 +202,6 @@ public class StreamConfiguration {
|
|||||||
return supportedVideoFormats;
|
return supportedVideoFormats;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getHevcBitratePercentageMultiplier() {
|
|
||||||
return hevcBitratePercentageMultiplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getAv1BitratePercentageMultiplier() {
|
|
||||||
return av1BitratePercentageMultiplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getAttachedGamepadMask() {
|
public int getAttachedGamepadMask() {
|
||||||
return attachedGamepadMask;
|
return attachedGamepadMask;
|
||||||
}
|
}
|
||||||
@ -244,10 +214,6 @@ public class StreamConfiguration {
|
|||||||
return clientRefreshRateX100;
|
return clientRefreshRateX100;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getEncryptionFlags() {
|
|
||||||
return encryptionFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getColorRange() {
|
public int getColorRange() {
|
||||||
return colorRange;
|
return colorRange;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package com.limelight.nvstream.http;
|
package com.limelight.nvstream.http;
|
||||||
|
|
||||||
|
import java.security.PrivateKey;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.interfaces.RSAPrivateKey;
|
|
||||||
|
|
||||||
public interface LimelightCryptoProvider {
|
public interface LimelightCryptoProvider {
|
||||||
X509Certificate getClientCertificate();
|
X509Certificate getClientCertificate();
|
||||||
RSAPrivateKey getClientPrivateKey();
|
PrivateKey getClientPrivateKey();
|
||||||
byte[] getPemEncodedClientCertificate();
|
byte[] getPemEncodedClientCertificate();
|
||||||
String encodeBase64String(byte[] data);
|
String encodeBase64String(byte[] data);
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ import com.limelight.BuildConfig;
|
|||||||
import com.limelight.LimeLog;
|
import com.limelight.LimeLog;
|
||||||
import com.limelight.nvstream.ConnectionContext;
|
import com.limelight.nvstream.ConnectionContext;
|
||||||
import com.limelight.nvstream.http.PairingManager.PairState;
|
import com.limelight.nvstream.http.PairingManager.PairState;
|
||||||
|
import com.limelight.nvstream.jni.MoonBridge;
|
||||||
|
|
||||||
import okhttp3.ConnectionPool;
|
import okhttp3.ConnectionPool;
|
||||||
import okhttp3.HttpUrl;
|
import okhttp3.HttpUrl;
|
||||||
@ -402,16 +403,7 @@ public class NvHTTP {
|
|||||||
try {
|
try {
|
||||||
SSLContext sc = SSLContext.getInstance("TLS");
|
SSLContext sc = SSLContext.getInstance("TLS");
|
||||||
sc.init(new KeyManager[] { keyManager }, new TrustManager[] { trustManager }, new SecureRandom());
|
sc.init(new KeyManager[] { keyManager }, new TrustManager[] { trustManager }, new SecureRandom());
|
||||||
|
return client.newBuilder().sslSocketFactory(sc.getSocketFactory(), trustManager).build();
|
||||||
// TLS 1.2 is not enabled by default prior to Android 5.0, so we'll need a custom
|
|
||||||
// SSLSocketFactory in order to connect to GFE 3.20.4 which requires TLSv1.2 or later.
|
|
||||||
// We don't just always use TLSv12SocketFactory because explicitly specifying TLS versions
|
|
||||||
// prevents later TLS versions from being negotiated even if client and server otherwise
|
|
||||||
// support them.
|
|
||||||
return client.newBuilder().sslSocketFactory(
|
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ?
|
|
||||||
sc.getSocketFactory() : new TLSv12SocketFactory(sc),
|
|
||||||
trustManager).build();
|
|
||||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -594,6 +586,12 @@ public class NvHTTP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an app by ID
|
||||||
|
* @param appId The ID of the app
|
||||||
|
* @see #getAppByName(String) for alternative.
|
||||||
|
* @return app details, or null if no app with that ID exists
|
||||||
|
*/
|
||||||
public NvApp getAppById(int appId) throws IOException, XmlPullParserException {
|
public NvApp getAppById(int appId) throws IOException, XmlPullParserException {
|
||||||
LinkedList<NvApp> appList = getAppList();
|
LinkedList<NvApp> appList = getAppList();
|
||||||
for (NvApp appFromList : appList) {
|
for (NvApp appFromList : appList) {
|
||||||
@ -603,11 +601,16 @@ public class NvHTTP {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: Only use this function if you know what you're doing.
|
/**
|
||||||
* It's totally valid to have two apps named the same thing,
|
* Get an app by name
|
||||||
* or even nothing at all! Look apps up by ID if at all possible
|
* NOTE: It is perfectly valid for multiple apps to have the same name,
|
||||||
* using the above function */
|
* this function will only return the first one it finds.
|
||||||
|
* Consider using getAppById instead.
|
||||||
|
* @param appName The name of the app
|
||||||
|
* @see #getAppById(int) for alternative.
|
||||||
|
* @return app details, or null if no app with that name exists
|
||||||
|
*/
|
||||||
public NvApp getAppByName(String appName) throws IOException, XmlPullParserException {
|
public NvApp getAppByName(String appName) throws IOException, XmlPullParserException {
|
||||||
LinkedList<NvApp> appList = getAppList();
|
LinkedList<NvApp> appList = getAppList();
|
||||||
for (NvApp appFromList : appList) {
|
for (NvApp appFromList : appList) {
|
||||||
@ -784,7 +787,8 @@ public class NvHTTP {
|
|||||||
"&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo() +
|
"&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo() +
|
||||||
"&remoteControllersBitmap=" + context.streamConfig.getAttachedGamepadMask() +
|
"&remoteControllersBitmap=" + context.streamConfig.getAttachedGamepadMask() +
|
||||||
"&gcmap=" + context.streamConfig.getAttachedGamepadMask() +
|
"&gcmap=" + context.streamConfig.getAttachedGamepadMask() +
|
||||||
"&gcpersist="+(context.streamConfig.getPersistGamepadsAfterDisconnect() ? 1 : 0));
|
"&gcpersist="+(context.streamConfig.getPersistGamepadsAfterDisconnect() ? 1 : 0) +
|
||||||
|
MoonBridge.getLaunchUrlQueryParameters());
|
||||||
if ((verb.equals("launch") && !getXmlString(xmlStr, "gamesession", true).equals("0") ||
|
if ((verb.equals("launch") && !getXmlString(xmlStr, "gamesession", true).equals("0") ||
|
||||||
(verb.equals("resume") && !getXmlString(xmlStr, "resume", true).equals("0")))) {
|
(verb.equals("resume") && !getXmlString(xmlStr, "resume", true).equals("0")))) {
|
||||||
// sessionUrl0 will be missing for older GFE versions
|
// sessionUrl0 will be missing for older GFE versions
|
||||||
@ -812,62 +816,4 @@ public class NvHTTP {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on example code from https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
|
|
||||||
private static class TLSv12SocketFactory extends SSLSocketFactory {
|
|
||||||
private SSLSocketFactory internalSSLSocketFactory;
|
|
||||||
|
|
||||||
public TLSv12SocketFactory(SSLContext context) {
|
|
||||||
internalSSLSocketFactory = context.getSocketFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getDefaultCipherSuites() {
|
|
||||||
return internalSSLSocketFactory.getDefaultCipherSuites();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getSupportedCipherSuites() {
|
|
||||||
return internalSSLSocketFactory.getSupportedCipherSuites();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket() throws IOException {
|
|
||||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
|
|
||||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(String host, int port) throws IOException {
|
|
||||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(host, port));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
|
|
||||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
|
||||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(host, port));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
|
|
||||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Socket enableTLSv12OnSocket(Socket socket) {
|
|
||||||
if (socket instanceof SSLSocket) {
|
|
||||||
// TLS 1.2 is not enabled by default prior to Android 5.0. We must enable it
|
|
||||||
// explicitly to ensure we can communicate with GFE 3.20.4 which blocks TLS 1.0.
|
|
||||||
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2"});
|
|
||||||
}
|
|
||||||
return socket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -98,10 +98,21 @@ public class PairingManager {
|
|||||||
System.arraycopy(pin.getBytes("UTF-8"), 0, saltedPin, salt.length, pin.length());
|
System.arraycopy(pin.getBytes("UTF-8"), 0, saltedPin, salt.length, pin.length());
|
||||||
return saltedPin;
|
return saltedPin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Signature getSha256SignatureInstanceForKey(Key key) throws NoSuchAlgorithmException {
|
||||||
|
switch (key.getAlgorithm()) {
|
||||||
|
case "RSA":
|
||||||
|
return Signature.getInstance("SHA256withRSA");
|
||||||
|
case "EC":
|
||||||
|
return Signature.getInstance("SHA256withECDSA");
|
||||||
|
default:
|
||||||
|
throw new NoSuchAlgorithmException("Unhandled key algorithm: " + key.getAlgorithm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean verifySignature(byte[] data, byte[] signature, Certificate cert) {
|
private static boolean verifySignature(byte[] data, byte[] signature, Certificate cert) {
|
||||||
try {
|
try {
|
||||||
Signature sig = Signature.getInstance("SHA256withRSA");
|
Signature sig = PairingManager.getSha256SignatureInstanceForKey(cert.getPublicKey());
|
||||||
sig.initVerify(cert.getPublicKey());
|
sig.initVerify(cert.getPublicKey());
|
||||||
sig.update(data);
|
sig.update(data);
|
||||||
return sig.verify(signature);
|
return sig.verify(signature);
|
||||||
@ -113,12 +124,10 @@ public class PairingManager {
|
|||||||
|
|
||||||
private static byte[] signData(byte[] data, PrivateKey key) {
|
private static byte[] signData(byte[] data, PrivateKey key) {
|
||||||
try {
|
try {
|
||||||
Signature sig = Signature.getInstance("SHA256withRSA");
|
Signature sig = PairingManager.getSha256SignatureInstanceForKey(key);
|
||||||
sig.initSign(key);
|
sig.initSign(key);
|
||||||
sig.update(data);
|
sig.update(data);
|
||||||
byte[] signature = new byte[256];
|
return sig.sign();
|
||||||
sig.sign(signature, 0, signature.length);
|
|
||||||
return signature;
|
|
||||||
} catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) {
|
} catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@ -245,7 +254,7 @@ public class PairingManager {
|
|||||||
// Get the server's signed secret
|
// Get the server's signed secret
|
||||||
byte[] serverSecretResp = hexToBytes(NvHTTP.getXmlString(secretResp, "pairingsecret", true));
|
byte[] serverSecretResp = hexToBytes(NvHTTP.getXmlString(secretResp, "pairingsecret", true));
|
||||||
byte[] serverSecret = Arrays.copyOfRange(serverSecretResp, 0, 16);
|
byte[] serverSecret = Arrays.copyOfRange(serverSecretResp, 0, 16);
|
||||||
byte[] serverSignature = Arrays.copyOfRange(serverSecretResp, 16, 272);
|
byte[] serverSignature = Arrays.copyOfRange(serverSecretResp, 16, serverSecretResp.length);
|
||||||
|
|
||||||
// Ensure the authenticity of the data
|
// Ensure the authenticity of the data
|
||||||
if (!verifySignature(serverSecret, serverSignature, serverCert)) {
|
if (!verifySignature(serverSecret, serverSignature, serverCert)) {
|
||||||
|
@ -22,10 +22,6 @@ public class MoonBridge {
|
|||||||
public static final int VIDEO_FORMAT_MASK_AV1 = 0xF000;
|
public static final int VIDEO_FORMAT_MASK_AV1 = 0xF000;
|
||||||
public static final int VIDEO_FORMAT_MASK_10BIT = 0x2200;
|
public static final int VIDEO_FORMAT_MASK_10BIT = 0x2200;
|
||||||
|
|
||||||
public static final int ENCFLG_NONE = 0;
|
|
||||||
public static final int ENCFLG_AUDIO = 1;
|
|
||||||
public static final int ENCFLG_ALL = 0xFFFFFFFF;
|
|
||||||
|
|
||||||
public static final int BUFFER_TYPE_PICDATA = 0;
|
public static final int BUFFER_TYPE_PICDATA = 0;
|
||||||
public static final int BUFFER_TYPE_SPS = 1;
|
public static final int BUFFER_TYPE_SPS = 1;
|
||||||
public static final int BUFFER_TYPE_PPS = 2;
|
public static final int BUFFER_TYPE_PPS = 2;
|
||||||
@ -347,10 +343,7 @@ public class MoonBridge {
|
|||||||
int width, int height, int fps,
|
int width, int height, int fps,
|
||||||
int bitrate, int packetSize, int streamingRemotely,
|
int bitrate, int packetSize, int streamingRemotely,
|
||||||
int audioConfiguration, int supportedVideoFormats,
|
int audioConfiguration, int supportedVideoFormats,
|
||||||
int hevcBitratePercentageMultiplier,
|
|
||||||
int av1BitratePercentageMultiplier,
|
|
||||||
int clientRefreshRateX100,
|
int clientRefreshRateX100,
|
||||||
int encryptionFlags,
|
|
||||||
byte[] riAesKey, byte[] riAesIv,
|
byte[] riAesKey, byte[] riAesIv,
|
||||||
int videoCapabilities,
|
int videoCapabilities,
|
||||||
int colorSpace, int colorRange);
|
int colorSpace, int colorRange);
|
||||||
@ -415,6 +408,8 @@ public class MoonBridge {
|
|||||||
// The RTT is in the top 32 bits, and the RTT variance is in the bottom 32 bits
|
// The RTT is in the top 32 bits, and the RTT variance is in the bottom 32 bits
|
||||||
public static native long getEstimatedRttInfo();
|
public static native long getEstimatedRttInfo();
|
||||||
|
|
||||||
|
public static native String getLaunchUrlQueryParameters();
|
||||||
|
|
||||||
public static native byte guessControllerType(int vendorId, int productId);
|
public static native byte guessControllerType(int vendorId, int productId);
|
||||||
|
|
||||||
public static native boolean guessControllerHasPaddles(int vendorId, int productId);
|
public static native boolean guessControllerHasPaddles(int vendorId, int productId);
|
||||||
|
@ -13,7 +13,6 @@ import com.limelight.R;
|
|||||||
import static com.limelight.binding.input.virtual_controller.VirtualControllerConfigurationLoader.OSC_PREFERENCE;
|
import static com.limelight.binding.input.virtual_controller.VirtualControllerConfigurationLoader.OSC_PREFERENCE;
|
||||||
|
|
||||||
public class ConfirmDeleteOscPreference extends DialogPreference {
|
public class ConfirmDeleteOscPreference extends DialogPreference {
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
public ConfirmDeleteOscPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
public ConfirmDeleteOscPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
}
|
}
|
||||||
@ -26,7 +25,6 @@ public class ConfirmDeleteOscPreference extends DialogPreference {
|
|||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
public ConfirmDeleteOscPreference(Context context) {
|
public ConfirmDeleteOscPreference(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,10 @@ import android.provider.Settings;
|
|||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
public class LanguagePreference extends ListPreference {
|
public class LanguagePreference extends ListPreference {
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
public LanguagePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
public LanguagePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
public LanguagePreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
public LanguagePreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,12 @@ public class PreferenceConfiguration {
|
|||||||
FORCE_H264,
|
FORCE_H264,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public enum AnalogStickForScrolling {
|
||||||
|
NONE,
|
||||||
|
RIGHT,
|
||||||
|
LEFT
|
||||||
|
}
|
||||||
|
|
||||||
private static final String LEGACY_RES_FPS_PREF_STRING = "list_resolution_fps";
|
private static final String LEGACY_RES_FPS_PREF_STRING = "list_resolution_fps";
|
||||||
private static final String LEGACY_ENABLE_51_SURROUND_PREF_STRING = "checkbox_51_surround";
|
private static final String LEGACY_ENABLE_51_SURROUND_PREF_STRING = "checkbox_51_surround";
|
||||||
|
|
||||||
@ -38,16 +44,19 @@ public class PreferenceConfiguration {
|
|||||||
private static final String VIDEO_FORMAT_PREF_STRING = "video_format";
|
private static final String VIDEO_FORMAT_PREF_STRING = "video_format";
|
||||||
private static final String ONSCREEN_CONTROLLER_PREF_STRING = "checkbox_show_onscreen_controls";
|
private static final String ONSCREEN_CONTROLLER_PREF_STRING = "checkbox_show_onscreen_controls";
|
||||||
private static final String ONLY_L3_R3_PREF_STRING = "checkbox_only_show_L3R3";
|
private static final String ONLY_L3_R3_PREF_STRING = "checkbox_only_show_L3R3";
|
||||||
|
private static final String SHOW_GUIDE_BUTTON_PREF_STRING = "checkbox_show_guide_button";
|
||||||
private static final String LEGACY_DISABLE_FRAME_DROP_PREF_STRING = "checkbox_disable_frame_drop";
|
private static final String LEGACY_DISABLE_FRAME_DROP_PREF_STRING = "checkbox_disable_frame_drop";
|
||||||
private static final String ENABLE_HDR_PREF_STRING = "checkbox_enable_hdr";
|
private static final String ENABLE_HDR_PREF_STRING = "checkbox_enable_hdr";
|
||||||
private static final String ENABLE_PIP_PREF_STRING = "checkbox_enable_pip";
|
private static final String ENABLE_PIP_PREF_STRING = "checkbox_enable_pip";
|
||||||
private static final String ENABLE_PERF_OVERLAY_STRING = "checkbox_enable_perf_overlay";
|
private static final String ENABLE_PERF_OVERLAY_STRING = "checkbox_enable_perf_overlay";
|
||||||
private static final String BIND_ALL_USB_STRING = "checkbox_usb_bind_all";
|
private static final String BIND_ALL_USB_STRING = "checkbox_usb_bind_all";
|
||||||
private static final String MOUSE_EMULATION_STRING = "checkbox_mouse_emulation";
|
private static final String MOUSE_EMULATION_STRING = "checkbox_mouse_emulation";
|
||||||
|
private static final String ANALOG_SCROLLING_PREF_STRING = "analog_scrolling";
|
||||||
private static final String MOUSE_NAV_BUTTONS_STRING = "checkbox_mouse_nav_buttons";
|
private static final String MOUSE_NAV_BUTTONS_STRING = "checkbox_mouse_nav_buttons";
|
||||||
static final String UNLOCK_FPS_STRING = "checkbox_unlock_fps";
|
static final String UNLOCK_FPS_STRING = "checkbox_unlock_fps";
|
||||||
private static final String VIBRATE_OSC_PREF_STRING = "checkbox_vibrate_osc";
|
private static final String VIBRATE_OSC_PREF_STRING = "checkbox_vibrate_osc";
|
||||||
private static final String VIBRATE_FALLBACK_PREF_STRING = "checkbox_vibrate_fallback";
|
private static final String VIBRATE_FALLBACK_PREF_STRING = "checkbox_vibrate_fallback";
|
||||||
|
private static final String VIBRATE_FALLBACK_STRENGTH_PREF_STRING = "seekbar_vibrate_fallback_strength";
|
||||||
private static final String FLIP_FACE_BUTTONS_PREF_STRING = "checkbox_flip_face_buttons";
|
private static final String FLIP_FACE_BUTTONS_PREF_STRING = "checkbox_flip_face_buttons";
|
||||||
private static final String TOUCHSCREEN_TRACKPAD_PREF_STRING = "checkbox_touchscreen_trackpad";
|
private static final String TOUCHSCREEN_TRACKPAD_PREF_STRING = "checkbox_touchscreen_trackpad";
|
||||||
private static final String LATENCY_TOAST_PREF_STRING = "checkbox_enable_post_stream_toast";
|
private static final String LATENCY_TOAST_PREF_STRING = "checkbox_enable_post_stream_toast";
|
||||||
@ -75,15 +84,18 @@ public class PreferenceConfiguration {
|
|||||||
|
|
||||||
private static final boolean ONSCREEN_CONTROLLER_DEFAULT = false;
|
private static final boolean ONSCREEN_CONTROLLER_DEFAULT = false;
|
||||||
private static final boolean ONLY_L3_R3_DEFAULT = false;
|
private static final boolean ONLY_L3_R3_DEFAULT = false;
|
||||||
|
private static final boolean SHOW_GUIDE_BUTTON_DEFAULT = true;
|
||||||
private static final boolean DEFAULT_ENABLE_HDR = false;
|
private static final boolean DEFAULT_ENABLE_HDR = false;
|
||||||
private static final boolean DEFAULT_ENABLE_PIP = false;
|
private static final boolean DEFAULT_ENABLE_PIP = false;
|
||||||
private static final boolean DEFAULT_ENABLE_PERF_OVERLAY = false;
|
private static final boolean DEFAULT_ENABLE_PERF_OVERLAY = false;
|
||||||
private static final boolean DEFAULT_BIND_ALL_USB = false;
|
private static final boolean DEFAULT_BIND_ALL_USB = false;
|
||||||
private static final boolean DEFAULT_MOUSE_EMULATION = true;
|
private static final boolean DEFAULT_MOUSE_EMULATION = true;
|
||||||
|
private static final String DEFAULT_ANALOG_STICK_FOR_SCROLLING = "right";
|
||||||
private static final boolean DEFAULT_MOUSE_NAV_BUTTONS = false;
|
private static final boolean DEFAULT_MOUSE_NAV_BUTTONS = false;
|
||||||
private static final boolean DEFAULT_UNLOCK_FPS = false;
|
private static final boolean DEFAULT_UNLOCK_FPS = false;
|
||||||
private static final boolean DEFAULT_VIBRATE_OSC = true;
|
private static final boolean DEFAULT_VIBRATE_OSC = true;
|
||||||
private static final boolean DEFAULT_VIBRATE_FALLBACK = false;
|
private static final boolean DEFAULT_VIBRATE_FALLBACK = false;
|
||||||
|
private static final int DEFAULT_VIBRATE_FALLBACK_STRENGTH = 100;
|
||||||
private static final boolean DEFAULT_FLIP_FACE_BUTTONS = false;
|
private static final boolean DEFAULT_FLIP_FACE_BUTTONS = false;
|
||||||
private static final boolean DEFAULT_TOUCHSCREEN_TRACKPAD = true;
|
private static final boolean DEFAULT_TOUCHSCREEN_TRACKPAD = true;
|
||||||
private static final String DEFAULT_AUDIO_CONFIG = "2"; // Stereo
|
private static final String DEFAULT_AUDIO_CONFIG = "2"; // Stereo
|
||||||
@ -120,16 +132,19 @@ public class PreferenceConfiguration {
|
|||||||
public boolean smallIconMode, multiController, usbDriver, flipFaceButtons;
|
public boolean smallIconMode, multiController, usbDriver, flipFaceButtons;
|
||||||
public boolean onscreenController;
|
public boolean onscreenController;
|
||||||
public boolean onlyL3R3;
|
public boolean onlyL3R3;
|
||||||
|
public boolean showGuideButton;
|
||||||
public boolean enableHdr;
|
public boolean enableHdr;
|
||||||
public boolean enablePip;
|
public boolean enablePip;
|
||||||
public boolean enablePerfOverlay;
|
public boolean enablePerfOverlay;
|
||||||
public boolean enableLatencyToast;
|
public boolean enableLatencyToast;
|
||||||
public boolean bindAllUsb;
|
public boolean bindAllUsb;
|
||||||
public boolean mouseEmulation;
|
public boolean mouseEmulation;
|
||||||
|
public AnalogStickForScrolling analogStickForScrolling;
|
||||||
public boolean mouseNavButtons;
|
public boolean mouseNavButtons;
|
||||||
public boolean unlockFps;
|
public boolean unlockFps;
|
||||||
public boolean vibrateOsc;
|
public boolean vibrateOsc;
|
||||||
public boolean vibrateFallbackToDevice;
|
public boolean vibrateFallbackToDevice;
|
||||||
|
public int vibrateFallbackToDeviceStrength;
|
||||||
public boolean touchscreenTrackpad;
|
public boolean touchscreenTrackpad;
|
||||||
public MoonBridge.AudioConfiguration audioConfiguration;
|
public MoonBridge.AudioConfiguration audioConfiguration;
|
||||||
public int framePacing;
|
public int framePacing;
|
||||||
@ -384,6 +399,21 @@ public class PreferenceConfiguration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static AnalogStickForScrolling getAnalogStickForScrollingValue(Context context) {
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
|
||||||
|
String str = prefs.getString(ANALOG_SCROLLING_PREF_STRING, DEFAULT_ANALOG_STICK_FOR_SCROLLING);
|
||||||
|
if (str.equals("right")) {
|
||||||
|
return AnalogStickForScrolling.RIGHT;
|
||||||
|
}
|
||||||
|
else if (str.equals("left")) {
|
||||||
|
return AnalogStickForScrolling.LEFT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return AnalogStickForScrolling.NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void resetStreamingSettings(Context context) {
|
public static void resetStreamingSettings(Context context) {
|
||||||
// We consider resolution, FPS, bitrate, HDR, and video format as "streaming settings" here
|
// We consider resolution, FPS, bitrate, HDR, and video format as "streaming settings" here
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
@ -503,6 +533,15 @@ public class PreferenceConfiguration {
|
|||||||
prefs.edit().putBoolean(SMALL_ICONS_PREF_STRING, getDefaultSmallMode(context)).apply();
|
prefs.edit().putBoolean(SMALL_ICONS_PREF_STRING, getDefaultSmallMode(context)).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!prefs.contains(GAMEPAD_MOTION_SENSORS_PREF_STRING) && Build.VERSION.SDK_INT == Build.VERSION_CODES.S) {
|
||||||
|
// Android 12 has a nasty bug that causes crashes when the app touches the InputDevice's
|
||||||
|
// associated InputDeviceSensorManager (just calling getSensorManager() is enough).
|
||||||
|
// As a workaround, we will override the default value for the gamepad motion sensor
|
||||||
|
// option to disabled on Android 12 to reduce the impact of this bug.
|
||||||
|
// https://cs.android.com/android/_/android/platform/frameworks/base/+/8970010a5e9f3dc5c069f56b4147552accfcbbeb
|
||||||
|
prefs.edit().putBoolean(GAMEPAD_MOTION_SENSORS_PREF_STRING, false).apply();
|
||||||
|
}
|
||||||
|
|
||||||
// This must happen after the preferences migration to ensure the preferences are populated
|
// This must happen after the preferences migration to ensure the preferences are populated
|
||||||
config.bitrate = prefs.getInt(BITRATE_PREF_STRING, prefs.getInt(BITRATE_PREF_OLD_STRING, 0) * 1000);
|
config.bitrate = prefs.getInt(BITRATE_PREF_STRING, prefs.getInt(BITRATE_PREF_OLD_STRING, 0) * 1000);
|
||||||
if (config.bitrate == 0) {
|
if (config.bitrate == 0) {
|
||||||
@ -523,6 +562,8 @@ public class PreferenceConfiguration {
|
|||||||
config.videoFormat = getVideoFormatValue(context);
|
config.videoFormat = getVideoFormatValue(context);
|
||||||
config.framePacing = getFramePacingValue(context);
|
config.framePacing = getFramePacingValue(context);
|
||||||
|
|
||||||
|
config.analogStickForScrolling = getAnalogStickForScrollingValue(context);
|
||||||
|
|
||||||
config.deadzonePercentage = prefs.getInt(DEADZONE_PREF_STRING, DEFAULT_DEADZONE);
|
config.deadzonePercentage = prefs.getInt(DEADZONE_PREF_STRING, DEFAULT_DEADZONE);
|
||||||
|
|
||||||
config.oscOpacity = prefs.getInt(OSC_OPACITY_PREF_STRING, DEFAULT_OPACITY);
|
config.oscOpacity = prefs.getInt(OSC_OPACITY_PREF_STRING, DEFAULT_OPACITY);
|
||||||
@ -539,6 +580,7 @@ public class PreferenceConfiguration {
|
|||||||
config.usbDriver = prefs.getBoolean(USB_DRIVER_PREF_SRING, DEFAULT_USB_DRIVER);
|
config.usbDriver = prefs.getBoolean(USB_DRIVER_PREF_SRING, DEFAULT_USB_DRIVER);
|
||||||
config.onscreenController = prefs.getBoolean(ONSCREEN_CONTROLLER_PREF_STRING, ONSCREEN_CONTROLLER_DEFAULT);
|
config.onscreenController = prefs.getBoolean(ONSCREEN_CONTROLLER_PREF_STRING, ONSCREEN_CONTROLLER_DEFAULT);
|
||||||
config.onlyL3R3 = prefs.getBoolean(ONLY_L3_R3_PREF_STRING, ONLY_L3_R3_DEFAULT);
|
config.onlyL3R3 = prefs.getBoolean(ONLY_L3_R3_PREF_STRING, ONLY_L3_R3_DEFAULT);
|
||||||
|
config.showGuideButton = prefs.getBoolean(SHOW_GUIDE_BUTTON_PREF_STRING, SHOW_GUIDE_BUTTON_DEFAULT);
|
||||||
config.enableHdr = prefs.getBoolean(ENABLE_HDR_PREF_STRING, DEFAULT_ENABLE_HDR) && !isShieldAtvFirmwareWithBrokenHdr();
|
config.enableHdr = prefs.getBoolean(ENABLE_HDR_PREF_STRING, DEFAULT_ENABLE_HDR) && !isShieldAtvFirmwareWithBrokenHdr();
|
||||||
config.enablePip = prefs.getBoolean(ENABLE_PIP_PREF_STRING, DEFAULT_ENABLE_PIP);
|
config.enablePip = prefs.getBoolean(ENABLE_PIP_PREF_STRING, DEFAULT_ENABLE_PIP);
|
||||||
config.enablePerfOverlay = prefs.getBoolean(ENABLE_PERF_OVERLAY_STRING, DEFAULT_ENABLE_PERF_OVERLAY);
|
config.enablePerfOverlay = prefs.getBoolean(ENABLE_PERF_OVERLAY_STRING, DEFAULT_ENABLE_PERF_OVERLAY);
|
||||||
@ -548,6 +590,7 @@ public class PreferenceConfiguration {
|
|||||||
config.unlockFps = prefs.getBoolean(UNLOCK_FPS_STRING, DEFAULT_UNLOCK_FPS);
|
config.unlockFps = prefs.getBoolean(UNLOCK_FPS_STRING, DEFAULT_UNLOCK_FPS);
|
||||||
config.vibrateOsc = prefs.getBoolean(VIBRATE_OSC_PREF_STRING, DEFAULT_VIBRATE_OSC);
|
config.vibrateOsc = prefs.getBoolean(VIBRATE_OSC_PREF_STRING, DEFAULT_VIBRATE_OSC);
|
||||||
config.vibrateFallbackToDevice = prefs.getBoolean(VIBRATE_FALLBACK_PREF_STRING, DEFAULT_VIBRATE_FALLBACK);
|
config.vibrateFallbackToDevice = prefs.getBoolean(VIBRATE_FALLBACK_PREF_STRING, DEFAULT_VIBRATE_FALLBACK);
|
||||||
|
config.vibrateFallbackToDeviceStrength = prefs.getInt(VIBRATE_FALLBACK_STRENGTH_PREF_STRING, DEFAULT_VIBRATE_FALLBACK_STRENGTH);
|
||||||
config.flipFaceButtons = prefs.getBoolean(FLIP_FACE_BUTTONS_PREF_STRING, DEFAULT_FLIP_FACE_BUTTONS);
|
config.flipFaceButtons = prefs.getBoolean(FLIP_FACE_BUTTONS_PREF_STRING, DEFAULT_FLIP_FACE_BUTTONS);
|
||||||
config.touchscreenTrackpad = prefs.getBoolean(TOUCHSCREEN_TRACKPAD_PREF_STRING, DEFAULT_TOUCHSCREEN_TRACKPAD);
|
config.touchscreenTrackpad = prefs.getBoolean(TOUCHSCREEN_TRACKPAD_PREF_STRING, DEFAULT_TOUCHSCREEN_TRACKPAD);
|
||||||
config.enableLatencyToast = prefs.getBoolean(LATENCY_TOAST_PREF_STRING, DEFAULT_LATENCY_TOAST);
|
config.enableLatencyToast = prefs.getBoolean(LATENCY_TOAST_PREF_STRING, DEFAULT_LATENCY_TOAST);
|
||||||
|
@ -190,8 +190,13 @@ public class StreamSettings extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addNativeFrameRateEntry(float framerate) {
|
private void addNativeFrameRateEntry(float framerate) {
|
||||||
|
int frameRateRounded = Math.round(framerate);
|
||||||
|
if (frameRateRounded == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ListPreference pref = (ListPreference) findPreference(PreferenceConfiguration.FPS_PREF_STRING);
|
ListPreference pref = (ListPreference) findPreference(PreferenceConfiguration.FPS_PREF_STRING);
|
||||||
String fpsValue = Integer.toString(Math.round(framerate));
|
String fpsValue = Integer.toString(frameRateRounded);
|
||||||
String fpsName = getResources().getString(R.string.resolution_prefix_native) +
|
String fpsName = getResources().getString(R.string.resolution_prefix_native) +
|
||||||
" (" + fpsValue + " " + getResources().getString(R.string.fps_suffix_fps) + ")";
|
" (" + fpsValue + " " + getResources().getString(R.string.fps_suffix_fps) + ")";
|
||||||
|
|
||||||
@ -328,26 +333,29 @@ public class StreamSettings extends Activity {
|
|||||||
(PreferenceCategory) findPreference("category_help");
|
(PreferenceCategory) findPreference("category_help");
|
||||||
screen.removePreference(category);
|
screen.removePreference(category);
|
||||||
}*/
|
}*/
|
||||||
|
PreferenceCategory category_gamepad_settings =
|
||||||
|
(PreferenceCategory) findPreference("category_gamepad_settings");
|
||||||
// Remove the vibration options if the device can't vibrate
|
// Remove the vibration options if the device can't vibrate
|
||||||
if (!((Vibrator)getActivity().getSystemService(Context.VIBRATOR_SERVICE)).hasVibrator()) {
|
if (!((Vibrator)getActivity().getSystemService(Context.VIBRATOR_SERVICE)).hasVibrator()) {
|
||||||
PreferenceCategory category =
|
category_gamepad_settings.removePreference(findPreference("checkbox_vibrate_fallback"));
|
||||||
(PreferenceCategory) findPreference("category_gamepad_settings");
|
category_gamepad_settings.removePreference(findPreference("seekbar_vibrate_fallback_strength"));
|
||||||
category.removePreference(findPreference("checkbox_vibrate_fallback"));
|
|
||||||
|
|
||||||
// The entire OSC category may have already been removed by the touchscreen check above
|
// The entire OSC category may have already been removed by the touchscreen check above
|
||||||
category = (PreferenceCategory) findPreference("category_onscreen_controls");
|
PreferenceCategory category = (PreferenceCategory) findPreference("category_onscreen_controls");
|
||||||
if (category != null) {
|
if (category != null) {
|
||||||
category.removePreference(findPreference("checkbox_vibrate_osc"));
|
category.removePreference(findPreference("checkbox_vibrate_osc"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
|
||||||
|
!((Vibrator)getActivity().getSystemService(Context.VIBRATOR_SERVICE)).hasAmplitudeControl() ) {
|
||||||
|
// Remove the vibration strength selector of the device doesn't have amplitude control
|
||||||
|
category_gamepad_settings.removePreference(findPreference("seekbar_vibrate_fallback_strength"));
|
||||||
|
}
|
||||||
|
|
||||||
int maxSupportedFps = 0;
|
Display display = getActivity().getWindowManager().getDefaultDisplay();
|
||||||
|
float maxSupportedFps = display.getRefreshRate();
|
||||||
|
|
||||||
// Hide non-supported resolution/FPS combinations
|
// Hide non-supported resolution/FPS combinations
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
Display display = getActivity().getWindowManager().getDefaultDisplay();
|
|
||||||
|
|
||||||
int maxSupportedResW = 0;
|
int maxSupportedResW = 0;
|
||||||
|
|
||||||
// Add a native resolution with any insets included for users that don't want content
|
// Add a native resolution with any insets included for users that don't want content
|
||||||
@ -415,7 +423,7 @@ public class StreamSettings extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (candidate.getRefreshRate() > maxSupportedFps) {
|
if (candidate.getRefreshRate() > maxSupportedFps) {
|
||||||
maxSupportedFps = (int)candidate.getRefreshRate();
|
maxSupportedFps = candidate.getRefreshRate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,30 +511,15 @@ public class StreamSettings extends Activity {
|
|||||||
// Never remove 720p
|
// Never remove 720p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
else {
|
||||||
// On Android 4.2 and later, we can get the true metrics via the
|
// We can get the true metrics via the getRealMetrics() function (unlike the lies
|
||||||
// getRealMetrics() function (unlike the lies that getWidth() and getHeight()
|
// that getWidth() and getHeight() tell to us).
|
||||||
// tell to us).
|
|
||||||
DisplayMetrics metrics = new DisplayMetrics();
|
DisplayMetrics metrics = new DisplayMetrics();
|
||||||
getActivity().getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
|
display.getRealMetrics(metrics);
|
||||||
int width = Math.max(metrics.widthPixels, metrics.heightPixels);
|
int width = Math.max(metrics.widthPixels, metrics.heightPixels);
|
||||||
int height = Math.min(metrics.widthPixels, metrics.heightPixels);
|
int height = Math.min(metrics.widthPixels, metrics.heightPixels);
|
||||||
addNativeResolutionEntries(width, height, false);
|
addNativeResolutionEntries(width, height, false);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// On Android 4.1, we have to resort to reflection to invoke hidden APIs
|
|
||||||
// to get the real screen dimensions.
|
|
||||||
Display display = getActivity().getWindowManager().getDefaultDisplay();
|
|
||||||
try {
|
|
||||||
Method getRawHeightFunc = Display.class.getMethod("getRawHeight");
|
|
||||||
Method getRawWidthFunc = Display.class.getMethod("getRawWidth");
|
|
||||||
int width = (Integer) getRawWidthFunc.invoke(display);
|
|
||||||
int height = (Integer) getRawHeightFunc.invoke(display);
|
|
||||||
addNativeResolutionEntries(Math.max(width, height), Math.min(width, height), false);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PreferenceConfiguration.readPreferences(this.getActivity()).unlockFps) {
|
if (!PreferenceConfiguration.readPreferences(this.getActivity()).unlockFps) {
|
||||||
// We give some extra room in case the FPS is rounded down
|
// We give some extra room in case the FPS is rounded down
|
||||||
@ -555,49 +548,29 @@ public class StreamSettings extends Activity {
|
|||||||
}
|
}
|
||||||
addNativeFrameRateEntry(maxSupportedFps);
|
addNativeFrameRateEntry(maxSupportedFps);
|
||||||
|
|
||||||
// Android L introduces proper 7.1 surround sound support. Remove the 7.1 option
|
|
||||||
// for earlier versions of Android to prevent AudioTrack initialization issues.
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
LimeLog.info("Excluding 7.1 surround sound option based on OS");
|
|
||||||
removeValue(PreferenceConfiguration.AUDIO_CONFIG_PREF_STRING, "71", new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
setValue(PreferenceConfiguration.AUDIO_CONFIG_PREF_STRING, "51");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Android L introduces the drop duplicate behavior of releaseOutputBuffer()
|
// Android L introduces the drop duplicate behavior of releaseOutputBuffer()
|
||||||
// that the unlock FPS option relies on to not massively increase latency.
|
// that the unlock FPS option relies on to not massively increase latency.
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
findPreference(PreferenceConfiguration.UNLOCK_FPS_STRING).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
LimeLog.info("Excluding unlock FPS toggle based on OS");
|
@Override
|
||||||
PreferenceCategory category =
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
(PreferenceCategory) findPreference("category_advanced_settings");
|
// HACK: We need to let the preference change succeed before reinitializing to ensure
|
||||||
category.removePreference(findPreference("checkbox_unlock_fps"));
|
// it's reflected in the new layout.
|
||||||
}
|
final Handler h = new Handler();
|
||||||
else {
|
h.postDelayed(new Runnable() {
|
||||||
findPreference(PreferenceConfiguration.UNLOCK_FPS_STRING).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
@Override
|
||||||
@Override
|
public void run() {
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
// Ensure the activity is still open when this timeout expires
|
||||||
// HACK: We need to let the preference change succeed before reinitializing to ensure
|
StreamSettings settingsActivity = (StreamSettings) SettingsFragment.this.getActivity();
|
||||||
// it's reflected in the new layout.
|
if (settingsActivity != null) {
|
||||||
final Handler h = new Handler();
|
settingsActivity.reloadSettings();
|
||||||
h.postDelayed(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// Ensure the activity is still open when this timeout expires
|
|
||||||
StreamSettings settingsActivity = (StreamSettings)SettingsFragment.this.getActivity();
|
|
||||||
if (settingsActivity != null) {
|
|
||||||
settingsActivity.reloadSettings();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, 500);
|
}
|
||||||
|
}, 500);
|
||||||
|
|
||||||
// Allow the original preference change to take place
|
// Allow the original preference change to take place
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Remove HDR preference for devices below Nougat
|
// Remove HDR preference for devices below Nougat
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||||
@ -607,7 +580,6 @@ public class StreamSettings extends Activity {
|
|||||||
category.removePreference(findPreference("checkbox_enable_hdr"));
|
category.removePreference(findPreference("checkbox_enable_hdr"));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Display display = getActivity().getWindowManager().getDefaultDisplay();
|
|
||||||
Display.HdrCapabilities hdrCaps = display.getHdrCapabilities();
|
Display.HdrCapabilities hdrCaps = display.getHdrCapabilities();
|
||||||
|
|
||||||
// We must now ensure our display is compatible with HDR10
|
// We must now ensure our display is compatible with HDR10
|
||||||
@ -617,6 +589,7 @@ public class StreamSettings extends Activity {
|
|||||||
for (int hdrType : hdrCaps.getSupportedHdrTypes()) {
|
for (int hdrType : hdrCaps.getSupportedHdrTypes()) {
|
||||||
if (hdrType == Display.HdrCapabilities.HDR_TYPE_HDR10) {
|
if (hdrType == Display.HdrCapabilities.HDR_TYPE_HDR10) {
|
||||||
foundHdr10 = true;
|
foundHdr10 = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@ public class WebLauncherPreference extends Preference {
|
|||||||
initialize(attrs);
|
initialize(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
public WebLauncherPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
public WebLauncherPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
initialize(attrs);
|
initialize(attrs);
|
||||||
|
@ -30,6 +30,6 @@ public class AdapterFragment extends Fragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
super.onActivityCreated(savedInstanceState);
|
super.onActivityCreated(savedInstanceState);
|
||||||
callbacks.receiveAbsListView((AbsListView) getView().findViewById(R.id.fragmentView));
|
callbacks.receiveAbsListView(getView().findViewById(R.id.fragmentView));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ public class StreamView extends SurfaceView {
|
|||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(21)
|
|
||||||
public StreamView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
public StreamView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ public class NetHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
else {
|
||||||
NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo();
|
NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo();
|
||||||
if (activeNetworkInfo != null) {
|
if (activeNetworkInfo != null) {
|
||||||
return activeNetworkInfo.getType() == ConnectivityManager.TYPE_VPN;
|
return activeNetworkInfo.getType() == ConnectivityManager.TYPE_VPN;
|
||||||
|
@ -2,15 +2,12 @@ package com.limelight.utils;
|
|||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.ShortcutInfo;
|
import android.content.pm.ShortcutInfo;
|
||||||
import android.content.pm.ShortcutManager;
|
import android.content.pm.ShortcutManager;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import com.limelight.AppView;
|
|
||||||
import com.limelight.ShortcutTrampoline;
|
|
||||||
import com.limelight.R;
|
import com.limelight.R;
|
||||||
import com.limelight.nvstream.http.ComputerDetails;
|
import com.limelight.nvstream.http.ComputerDetails;
|
||||||
import com.limelight.nvstream.http.NvApp;
|
import com.limelight.nvstream.http.NvApp;
|
||||||
|
@ -53,7 +53,11 @@ public class TvChannelHelper {
|
|||||||
intent.putExtra(TvContract.EXTRA_CHANNEL_ID, getChannelId(computer.uuid));
|
intent.putExtra(TvContract.EXTRA_CHANNEL_ID, getChannelId(computer.uuid));
|
||||||
try {
|
try {
|
||||||
context.startActivityForResult(intent, 0);
|
context.startActivityForResult(intent, 0);
|
||||||
} catch (ActivityNotFoundException e) {
|
} catch (Exception ignored) {
|
||||||
|
// ActivityNotFoundException is the only officially documented
|
||||||
|
// exception that can result from this call. However some buggy
|
||||||
|
// devices throw others.
|
||||||
|
// See https://github.com/moonlight-stream/moonlight-android/issues/1302
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
# Application.mk for Moonlight
|
# Application.mk for Moonlight
|
||||||
|
|
||||||
# Our minimum version is Android 4.1
|
# Our minimum version is Android 5.0
|
||||||
APP_PLATFORM := android-16
|
APP_PLATFORM := android-21
|
||||||
|
|
||||||
|
# We support 16KB pages
|
||||||
|
APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true
|
||||||
|
@ -55,7 +55,11 @@ endif
|
|||||||
|
|
||||||
LOCAL_LDLIBS := -llog
|
LOCAL_LDLIBS := -llog
|
||||||
|
|
||||||
LOCAL_STATIC_LIBRARIES := libopus libssl libcrypto
|
LOCAL_STATIC_LIBRARIES := libopus libssl libcrypto cpufeatures
|
||||||
LOCAL_LDFLAGS += -Wl,--exclude-libs,ALL
|
LOCAL_LDFLAGS += -Wl,--exclude-libs,ALL
|
||||||
|
|
||||||
|
LOCAL_BRANCH_PROTECTION := standard
|
||||||
|
|
||||||
include $(BUILD_SHARED_LIBRARY)
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
|
|
||||||
|
$(call import-module,android/cpufeatures)
|
1
app/src/main/jni/moonlight-core/Build.txt
Normal file
1
app/src/main/jni/moonlight-core/Build.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Static libraries were built from https://github.com/cgutman/moonlight-mobile-deps using AppVeyor CI
|
@ -8,6 +8,8 @@
|
|||||||
#include <opus_multistream.h>
|
#include <opus_multistream.h>
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
|
||||||
|
#include <cpu-features.h>
|
||||||
|
|
||||||
static OpusMSDecoder* Decoder;
|
static OpusMSDecoder* Decoder;
|
||||||
static OPUS_MULTISTREAM_CONFIGURATION OpusConfig;
|
static OPUS_MULTISTREAM_CONFIGURATION OpusConfig;
|
||||||
|
|
||||||
@ -426,6 +428,29 @@ static CONNECTION_LISTENER_CALLBACKS BridgeConnListenerCallbacks = {
|
|||||||
.setControllerLED = BridgeClSetControllerLED,
|
.setControllerLED = BridgeClSetControllerLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool
|
||||||
|
hasFastAes() {
|
||||||
|
if (android_getCpuCount() <= 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (android_getCpuFamily()) {
|
||||||
|
case ANDROID_CPU_FAMILY_ARM:
|
||||||
|
return !!(android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_AES);
|
||||||
|
case ANDROID_CPU_FAMILY_ARM64:
|
||||||
|
return !!(android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_AES);
|
||||||
|
case ANDROID_CPU_FAMILY_X86:
|
||||||
|
case ANDROID_CPU_FAMILY_X86_64:
|
||||||
|
return !!(android_getCpuFeatures() & ANDROID_CPU_X86_FEATURE_AES_NI);
|
||||||
|
case ANDROID_CPU_FAMILY_MIPS:
|
||||||
|
case ANDROID_CPU_FAMILY_MIPS64:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
// Assume new architectures will all have crypto acceleration (RISC-V will)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass clazz,
|
Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass clazz,
|
||||||
jstring address, jstring appVersion, jstring gfeVersion,
|
jstring address, jstring appVersion, jstring gfeVersion,
|
||||||
@ -433,10 +458,7 @@ Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass c
|
|||||||
jint width, jint height, jint fps,
|
jint width, jint height, jint fps,
|
||||||
jint bitrate, jint packetSize, jint streamingRemotely,
|
jint bitrate, jint packetSize, jint streamingRemotely,
|
||||||
jint audioConfiguration, jint supportedVideoFormats,
|
jint audioConfiguration, jint supportedVideoFormats,
|
||||||
jint hevcBitratePercentageMultiplier,
|
|
||||||
jint av1BitratePercentageMultiplier,
|
|
||||||
jint clientRefreshRateX100,
|
jint clientRefreshRateX100,
|
||||||
jint encryptionFlags,
|
|
||||||
jbyteArray riAesKey, jbyteArray riAesIv,
|
jbyteArray riAesKey, jbyteArray riAesIv,
|
||||||
jint videoCapabilities,
|
jint videoCapabilities,
|
||||||
jint colorSpace, jint colorRange) {
|
jint colorSpace, jint colorRange) {
|
||||||
@ -456,10 +478,8 @@ Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass c
|
|||||||
.streamingRemotely = streamingRemotely,
|
.streamingRemotely = streamingRemotely,
|
||||||
.audioConfiguration = audioConfiguration,
|
.audioConfiguration = audioConfiguration,
|
||||||
.supportedVideoFormats = supportedVideoFormats,
|
.supportedVideoFormats = supportedVideoFormats,
|
||||||
.hevcBitratePercentageMultiplier = hevcBitratePercentageMultiplier,
|
|
||||||
.av1BitratePercentageMultiplier = av1BitratePercentageMultiplier,
|
|
||||||
.clientRefreshRateX100 = clientRefreshRateX100,
|
.clientRefreshRateX100 = clientRefreshRateX100,
|
||||||
.encryptionFlags = encryptionFlags,
|
.encryptionFlags = ENCFLG_AUDIO,
|
||||||
.colorSpace = colorSpace,
|
.colorSpace = colorSpace,
|
||||||
.colorRange = colorRange
|
.colorRange = colorRange
|
||||||
};
|
};
|
||||||
@ -474,6 +494,11 @@ Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass c
|
|||||||
|
|
||||||
BridgeVideoRendererCallbacks.capabilities = videoCapabilities;
|
BridgeVideoRendererCallbacks.capabilities = videoCapabilities;
|
||||||
|
|
||||||
|
// Enable all encryption features if the platform has fast AES support
|
||||||
|
if (hasFastAes()) {
|
||||||
|
streamConfig.encryptionFlags = ENCFLG_ALL;
|
||||||
|
}
|
||||||
|
|
||||||
int ret = LiStartConnection(&serverInfo,
|
int ret = LiStartConnection(&serverInfo,
|
||||||
&streamConfig,
|
&streamConfig,
|
||||||
&BridgeConnListenerCallbacks,
|
&BridgeConnListenerCallbacks,
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -1,100 +0,0 @@
|
|||||||
ANDROID_API_TARGET=21
|
|
||||||
PARALLEL_JOBS=$(nproc)
|
|
||||||
|
|
||||||
rm -r ./android
|
|
||||||
mkdir android
|
|
||||||
|
|
||||||
function build_one
|
|
||||||
{
|
|
||||||
PREFIX=$(pwd)/android/$CPU
|
|
||||||
SYSROOT=$NDK/platforms/android-$ANDROID_API_TARGET/arch-$SYSROOT_CPU
|
|
||||||
TOOLCHAIN_PATH=$NDK/toolchains/$TOOLCHAIN_DIR/prebuilt/linux-x86_64
|
|
||||||
export PATH=$PATH:$TOOLCHAIN_PATH/bin
|
|
||||||
./configure \
|
|
||||||
--build=x86_64-unknown-linux-gnu \
|
|
||||||
--host=$TOOLCHAIN_BIN_PREFIX \
|
|
||||||
--target=$TOOLCHAIN_BIN_PREFIX \
|
|
||||||
CFLAGS="--sysroot=$SYSROOT -O2 $ADDI_CFLAGS" \
|
|
||||||
$ADDI_CONFIGURE_FLAGS
|
|
||||||
make clean
|
|
||||||
make -j$PARALLEL_JOBS
|
|
||||||
mkdir android/$CPU
|
|
||||||
cp .libs/libopus.a android/$CPU
|
|
||||||
}
|
|
||||||
|
|
||||||
function build_mips
|
|
||||||
{
|
|
||||||
CPU=mips
|
|
||||||
SYSROOT_CPU=mips
|
|
||||||
TOOLCHAIN_BIN_PREFIX=mipsel-linux-android
|
|
||||||
TOOLCHAIN_DIR=mipsel-linux-android-4.9
|
|
||||||
ADDI_CFLAGS="-mips32 -mhard-float -EL -mno-dsp"
|
|
||||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point" # fixed point
|
|
||||||
build_one
|
|
||||||
}
|
|
||||||
|
|
||||||
function build_mips64
|
|
||||||
{
|
|
||||||
CPU=mips64
|
|
||||||
SYSROOT_CPU=mips64
|
|
||||||
TOOLCHAIN_BIN_PREFIX=mips64el-linux-android
|
|
||||||
TOOLCHAIN_DIR=mips64el-linux-android-4.9
|
|
||||||
ADDI_CFLAGS="-mips64r6"
|
|
||||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point" # fixed point
|
|
||||||
build_one
|
|
||||||
}
|
|
||||||
|
|
||||||
function build_x86
|
|
||||||
{
|
|
||||||
CPU=x86
|
|
||||||
SYSROOT_CPU=x86
|
|
||||||
TOOLCHAIN_BIN_PREFIX=i686-linux-android
|
|
||||||
TOOLCHAIN_DIR=x86-4.9
|
|
||||||
ADDI_CFLAGS="-march=i686 -mtune=atom -mstackrealign -msse -msse2 -msse3 -mssse3 -mfpmath=sse -m32"
|
|
||||||
ADDI_CONFIGURE_FLAGS="" # floating point for SSE optimizations
|
|
||||||
build_one
|
|
||||||
}
|
|
||||||
|
|
||||||
function build_x86_64
|
|
||||||
{
|
|
||||||
CPU=x86_64
|
|
||||||
SYSROOT_CPU=x86_64
|
|
||||||
TOOLCHAIN_BIN_PREFIX=x86_64-linux-android
|
|
||||||
TOOLCHAIN_DIR=x86_64-4.9
|
|
||||||
ADDI_CFLAGS="-msse -msse2 -msse3 -mssse3 -msse4 -msse4.1 -msse4.2 -mpopcnt -m64"
|
|
||||||
ADDI_CONFIGURE_FLAGS="" # floating point for SSE optimizations
|
|
||||||
build_one
|
|
||||||
}
|
|
||||||
|
|
||||||
function build_armv7
|
|
||||||
{
|
|
||||||
CPU=arm
|
|
||||||
SYSROOT_CPU=arm
|
|
||||||
TOOLCHAIN_BIN_PREFIX=arm-linux-androideabi
|
|
||||||
TOOLCHAIN_DIR=arm-linux-androideabi-4.9
|
|
||||||
ADDI_CFLAGS="-marm -mfpu=vfpv3-d16"
|
|
||||||
ADDI_LDFLAGS=""
|
|
||||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point" # fixed point for NEON, EDSP, Media
|
|
||||||
build_one
|
|
||||||
}
|
|
||||||
|
|
||||||
# ARMv8 doesn't currently have assembly in the opus project. We still use fixed point
|
|
||||||
# anyway in the hopes that it will be more performant even without assembly.
|
|
||||||
function build_armv8
|
|
||||||
{
|
|
||||||
CPU=aarch64
|
|
||||||
SYSROOT_CPU=arm64
|
|
||||||
TOOLCHAIN_BIN_PREFIX=aarch64-linux-android
|
|
||||||
TOOLCHAIN_DIR=aarch64-linux-android-4.9
|
|
||||||
ADDI_CFLAGS=""
|
|
||||||
ADDI_LDFLAGS=""
|
|
||||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point"
|
|
||||||
build_one
|
|
||||||
}
|
|
||||||
|
|
||||||
build_mips
|
|
||||||
build_mips64
|
|
||||||
build_x86
|
|
||||||
build_x86_64
|
|
||||||
build_armv7
|
|
||||||
build_armv8
|
|
@ -103,7 +103,7 @@ extern "C" {
|
|||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
* where opus_encoder_get_size() returns the required size for the encoder state. Note that
|
* where opus_encoder_get_size() returns the required size for the encoder state. Note that
|
||||||
* future versions of this code may change the size, so no assuptions should be made about it.
|
* future versions of this code may change the size, so no assumptions should be made about it.
|
||||||
*
|
*
|
||||||
* The encoder state is always continuous in memory and only a shallow copy is sufficient
|
* The encoder state is always continuous in memory and only a shallow copy is sufficient
|
||||||
* to copy it (e.g. memcpy())
|
* to copy it (e.g. memcpy())
|
||||||
@ -198,7 +198,7 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels);
|
|||||||
* This must be one of 8000, 12000, 16000,
|
* This must be one of 8000, 12000, 16000,
|
||||||
* 24000, or 48000.
|
* 24000, or 48000.
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
|
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
|
||||||
* @param [in] application <tt>int</tt>: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
|
* @param [in] application <tt>int</tt>: Coding mode (one of @ref OPUS_APPLICATION_VOIP, @ref OPUS_APPLICATION_AUDIO, or @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
|
||||||
* @param [out] error <tt>int*</tt>: @ref opus_errorcodes
|
* @param [out] error <tt>int*</tt>: @ref opus_errorcodes
|
||||||
* @note Regardless of the sampling rate and number channels selected, the Opus encoder
|
* @note Regardless of the sampling rate and number channels selected, the Opus encoder
|
||||||
* can switch to a lower audio bandwidth or number of channels if the bitrate
|
* can switch to a lower audio bandwidth or number of channels if the bitrate
|
||||||
@ -222,7 +222,7 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create(
|
|||||||
* This must be one of 8000, 12000, 16000,
|
* This must be one of 8000, 12000, 16000,
|
||||||
* 24000, or 48000.
|
* 24000, or 48000.
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
|
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
|
||||||
* @param [in] application <tt>int</tt>: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY)
|
* @param [in] application <tt>int</tt>: Coding mode (one of OPUS_APPLICATION_VOIP, OPUS_APPLICATION_AUDIO, or OPUS_APPLICATION_RESTRICTED_LOWDELAY)
|
||||||
* @retval #OPUS_OK Success or @ref opus_errorcodes
|
* @retval #OPUS_OK Success or @ref opus_errorcodes
|
||||||
*/
|
*/
|
||||||
OPUS_EXPORT int opus_encoder_init(
|
OPUS_EXPORT int opus_encoder_init(
|
||||||
@ -357,7 +357,7 @@ OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NON
|
|||||||
* error = opus_decoder_init(dec, Fs, channels);
|
* error = opus_decoder_init(dec, Fs, channels);
|
||||||
* @endcode
|
* @endcode
|
||||||
* where opus_decoder_get_size() returns the required size for the decoder state. Note that
|
* where opus_decoder_get_size() returns the required size for the decoder state. Note that
|
||||||
* future versions of this code may change the size, so no assuptions should be made about it.
|
* future versions of this code may change the size, so no assumptions should be made about it.
|
||||||
*
|
*
|
||||||
* The decoder state is always continuous in memory and only a shallow copy is sufficient
|
* The decoder state is always continuous in memory and only a shallow copy is sufficient
|
||||||
* to copy it (e.g. memcpy())
|
* to copy it (e.g. memcpy())
|
||||||
@ -398,6 +398,21 @@ OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NON
|
|||||||
*/
|
*/
|
||||||
typedef struct OpusDecoder OpusDecoder;
|
typedef struct OpusDecoder OpusDecoder;
|
||||||
|
|
||||||
|
/** Opus DRED decoder.
|
||||||
|
* This contains the complete state of an Opus DRED decoder.
|
||||||
|
* It is position independent and can be freely copied.
|
||||||
|
* @see opus_dred_decoder_create,opus_dred_decoder_init
|
||||||
|
*/
|
||||||
|
typedef struct OpusDREDDecoder OpusDREDDecoder;
|
||||||
|
|
||||||
|
|
||||||
|
/** Opus DRED state.
|
||||||
|
* This contains the complete state of an Opus DRED packet.
|
||||||
|
* It is position independent and can be freely copied.
|
||||||
|
* @see opus_dred_create,opus_dred_init
|
||||||
|
*/
|
||||||
|
typedef struct OpusDRED OpusDRED;
|
||||||
|
|
||||||
/** Gets the size of an <code>OpusDecoder</code> structure.
|
/** Gets the size of an <code>OpusDecoder</code> structure.
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels.
|
* @param [in] channels <tt>int</tt>: Number of channels.
|
||||||
* This must be 1 or 2.
|
* This must be 1 or 2.
|
||||||
@ -511,6 +526,101 @@ OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NON
|
|||||||
*/
|
*/
|
||||||
OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);
|
OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);
|
||||||
|
|
||||||
|
/** Gets the size of an <code>OpusDREDDecoder</code> structure.
|
||||||
|
* @returns The size in bytes.
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_dred_decoder_get_size(void);
|
||||||
|
|
||||||
|
/** Allocates and initializes an OpusDREDDecoder state.
|
||||||
|
* @param [out] error <tt>int*</tt>: #OPUS_OK Success or @ref opus_errorcodes
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT OpusDREDDecoder *opus_dred_decoder_create(int *error);
|
||||||
|
|
||||||
|
/** Initializes an <code>OpusDREDDecoder</code> state.
|
||||||
|
* @param[in] dec <tt>OpusDREDDecoder*</tt>: State to be initialized.
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_dred_decoder_init(OpusDREDDecoder *dec);
|
||||||
|
|
||||||
|
/** Frees an <code>OpusDREDDecoder</code> allocated by opus_dred_decoder_create().
|
||||||
|
* @param[in] dec <tt>OpusDREDDecoder*</tt>: State to be freed.
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT void opus_dred_decoder_destroy(OpusDREDDecoder *dec);
|
||||||
|
|
||||||
|
/** Perform a CTL function on an Opus DRED decoder.
|
||||||
|
*
|
||||||
|
* Generally the request and subsequent arguments are generated
|
||||||
|
* by a convenience macro.
|
||||||
|
* @param dred_dec <tt>OpusDREDDecoder*</tt>: DRED Decoder state.
|
||||||
|
* @param request This and all remaining parameters should be replaced by one
|
||||||
|
* of the convenience macros in @ref opus_genericctls or
|
||||||
|
* @ref opus_decoderctls.
|
||||||
|
* @see opus_genericctls
|
||||||
|
* @see opus_decoderctls
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_dred_decoder_ctl(OpusDREDDecoder *dred_dec, int request, ...);
|
||||||
|
|
||||||
|
/** Gets the size of an <code>OpusDRED</code> structure.
|
||||||
|
* @returns The size in bytes.
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_dred_get_size(void);
|
||||||
|
|
||||||
|
/** Allocates and initializes a DRED state.
|
||||||
|
* @param [out] error <tt>int*</tt>: #OPUS_OK Success or @ref opus_errorcodes
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT OpusDRED *opus_dred_alloc(int *error);
|
||||||
|
|
||||||
|
/** Frees an <code>OpusDRED</code> allocated by opus_dred_create().
|
||||||
|
* @param[in] dec <tt>OpusDRED*</tt>: State to be freed.
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT void opus_dred_free(OpusDRED *dec);
|
||||||
|
|
||||||
|
/** Decode an Opus DRED packet.
|
||||||
|
* @param [in] dred_dec <tt>OpusDRED*</tt>: DRED Decoder state
|
||||||
|
* @param [in] dred <tt>OpusDRED*</tt>: DRED state
|
||||||
|
* @param [in] data <tt>char*</tt>: Input payload
|
||||||
|
* @param [in] len <tt>opus_int32</tt>: Number of bytes in payload
|
||||||
|
* @param [in] max_dred_samples <tt>opus_int32</tt>: Maximum number of DRED samples that may be needed (if available in the packet).
|
||||||
|
* @param [in] sampling_rate <tt>opus_int32</tt>: Sampling rate used for max_dred_samples argument. Needs not match the actual sampling rate of the decoder.
|
||||||
|
* @param [out] dred_end <tt>opus_int32*</tt>: Number of non-encoded (silence) samples between the DRED timestamp and the last DRED sample.
|
||||||
|
* @param [in] defer_processing <tt>int</tt>: Flag (0 or 1). If set to one, the CPU-intensive part of the DRED decoding is deferred until opus_dred_process() is called.
|
||||||
|
* @returns Offset (positive) of the first decoded DRED samples, zero if no DRED is present, or @ref opus_errorcodes
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_dred_parse(OpusDREDDecoder *dred_dec, OpusDRED *dred, const unsigned char *data, opus_int32 len, opus_int32 max_dred_samples, opus_int32 sampling_rate, int *dred_end, int defer_processing) OPUS_ARG_NONNULL(1);
|
||||||
|
|
||||||
|
/** Finish decoding an Opus DRED packet. The function only needs to be called if opus_dred_parse() was called with defer_processing=1.
|
||||||
|
* The source and destination will often be the same DRED state.
|
||||||
|
* @param [in] dred_dec <tt>OpusDRED*</tt>: DRED Decoder state
|
||||||
|
* @param [in] src <tt>OpusDRED*</tt>: Source DRED state to start the processing from.
|
||||||
|
* @param [out] dst <tt>OpusDRED*</tt>: Destination DRED state to store the updated state after processing.
|
||||||
|
* @returns @ref opus_errorcodes
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_dred_process(OpusDREDDecoder *dred_dec, const OpusDRED *src, OpusDRED *dst);
|
||||||
|
|
||||||
|
/** Decode audio from an Opus DRED packet with floating point output.
|
||||||
|
* @param [in] st <tt>OpusDecoder*</tt>: Decoder state
|
||||||
|
* @param [in] dred <tt>OpusDRED*</tt>: DRED state
|
||||||
|
* @param [in] dred_offset <tt>opus_int32</tt>: position of the redundancy to decode (in samples before the beginning of the real audio data in the packet).
|
||||||
|
* @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
|
||||||
|
* is frame_size*channels*sizeof(opus_int16)
|
||||||
|
* @param [in] frame_size Number of samples per channel to decode in \a pcm.
|
||||||
|
* frame_size <b>must</b> be a multiple of 2.5 ms.
|
||||||
|
* @returns Number of decoded samples or @ref opus_errorcodes
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_decoder_dred_decode(OpusDecoder *st, const OpusDRED *dred, opus_int32 dred_offset, opus_int16 *pcm, opus_int32 frame_size);
|
||||||
|
|
||||||
|
/** Decode audio from an Opus DRED packet with floating point output.
|
||||||
|
* @param [in] st <tt>OpusDecoder*</tt>: Decoder state
|
||||||
|
* @param [in] dred <tt>OpusDRED*</tt>: DRED state
|
||||||
|
* @param [in] dred_offset <tt>opus_int32</tt>: position of the redundancy to decode (in samples before the beginning of the real audio data in the packet).
|
||||||
|
* @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
|
||||||
|
* is frame_size*channels*sizeof(float)
|
||||||
|
* @param [in] frame_size Number of samples per channel to decode in \a pcm.
|
||||||
|
* frame_size <b>must</b> be a multiple of 2.5 ms.
|
||||||
|
* @returns Number of decoded samples or @ref opus_errorcodes
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT int opus_decoder_dred_decode_float(OpusDecoder *st, const OpusDRED *dred, opus_int32 dred_offset, float *pcm, opus_int32 frame_size);
|
||||||
|
|
||||||
|
|
||||||
/** Parse an opus packet into one or more frames.
|
/** Parse an opus packet into one or more frames.
|
||||||
* Opus_decode will perform this operation internally so most applications do
|
* Opus_decode will perform this operation internally so most applications do
|
||||||
* not need to use this function.
|
* not need to use this function.
|
||||||
@ -583,6 +693,14 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned
|
|||||||
*/
|
*/
|
||||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);
|
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);
|
||||||
|
|
||||||
|
/** Checks whether an Opus packet has LBRR.
|
||||||
|
* @param [in] packet <tt>char*</tt>: Opus packet
|
||||||
|
* @param [in] len <tt>opus_int32</tt>: Length of packet
|
||||||
|
* @returns 1 is LBRR is present, 0 otherwise
|
||||||
|
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
|
||||||
|
*/
|
||||||
|
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_has_lbrr(const unsigned char packet[], opus_int32 len);
|
||||||
|
|
||||||
/** Gets the number of samples of an Opus packet.
|
/** Gets the number of samples of an Opus packet.
|
||||||
* @param [in] dec <tt>OpusDecoder*</tt>: Decoder state
|
* @param [in] dec <tt>OpusDecoder*</tt>: Decoder state
|
||||||
* @param [in] packet <tt>char*</tt>: Opus packet
|
* @param [in] packet <tt>char*</tt>: Opus packet
|
||||||
|
@ -1,342 +0,0 @@
|
|||||||
/* Copyright (c) 2007-2008 CSIRO
|
|
||||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
|
||||||
Copyright (c) 2008-2012 Gregory Maxwell
|
|
||||||
Written by Jean-Marc Valin and Gregory Maxwell */
|
|
||||||
/*
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions
|
|
||||||
are met:
|
|
||||||
|
|
||||||
- Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
- Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
|
||||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
@file opus_custom.h
|
|
||||||
@brief Opus-Custom reference implementation API
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef OPUS_CUSTOM_H
|
|
||||||
#define OPUS_CUSTOM_H
|
|
||||||
|
|
||||||
#include "opus_defines.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CUSTOM_MODES
|
|
||||||
# define OPUS_CUSTOM_EXPORT OPUS_EXPORT
|
|
||||||
# define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT
|
|
||||||
#else
|
|
||||||
# define OPUS_CUSTOM_EXPORT
|
|
||||||
# ifdef OPUS_BUILD
|
|
||||||
# define OPUS_CUSTOM_EXPORT_STATIC static OPUS_INLINE
|
|
||||||
# else
|
|
||||||
# define OPUS_CUSTOM_EXPORT_STATIC
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** @defgroup opus_custom Opus Custom
|
|
||||||
* @{
|
|
||||||
* Opus Custom is an optional part of the Opus specification and
|
|
||||||
* reference implementation which uses a distinct API from the regular
|
|
||||||
* API and supports frame sizes that are not normally supported.\ Use
|
|
||||||
* of Opus Custom is discouraged for all but very special applications
|
|
||||||
* for which a frame size different from 2.5, 5, 10, or 20 ms is needed
|
|
||||||
* (for either complexity or latency reasons) and where interoperability
|
|
||||||
* is less important.
|
|
||||||
*
|
|
||||||
* In addition to the interoperability limitations the use of Opus custom
|
|
||||||
* disables a substantial chunk of the codec and generally lowers the
|
|
||||||
* quality available at a given bitrate. Normally when an application needs
|
|
||||||
* a different frame size from the codec it should buffer to match the
|
|
||||||
* sizes but this adds a small amount of delay which may be important
|
|
||||||
* in some very low latency applications. Some transports (especially
|
|
||||||
* constant rate RF transports) may also work best with frames of
|
|
||||||
* particular durations.
|
|
||||||
*
|
|
||||||
* Libopus only supports custom modes if they are enabled at compile time.
|
|
||||||
*
|
|
||||||
* The Opus Custom API is similar to the regular API but the
|
|
||||||
* @ref opus_encoder_create and @ref opus_decoder_create calls take
|
|
||||||
* an additional mode parameter which is a structure produced by
|
|
||||||
* a call to @ref opus_custom_mode_create. Both the encoder and decoder
|
|
||||||
* must create a mode using the same sample rate (fs) and frame size
|
|
||||||
* (frame size) so these parameters must either be signaled out of band
|
|
||||||
* or fixed in a particular implementation.
|
|
||||||
*
|
|
||||||
* Similar to regular Opus the custom modes support on the fly frame size
|
|
||||||
* switching, but the sizes available depend on the particular frame size in
|
|
||||||
* use. For some initial frame sizes on a single on the fly size is available.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Contains the state of an encoder. One encoder state is needed
|
|
||||||
for each stream. It is initialized once at the beginning of the
|
|
||||||
stream. Do *not* re-initialize the state for every frame.
|
|
||||||
@brief Encoder state
|
|
||||||
*/
|
|
||||||
typedef struct OpusCustomEncoder OpusCustomEncoder;
|
|
||||||
|
|
||||||
/** State of the decoder. One decoder state is needed for each stream.
|
|
||||||
It is initialized once at the beginning of the stream. Do *not*
|
|
||||||
re-initialize the state for every frame.
|
|
||||||
@brief Decoder state
|
|
||||||
*/
|
|
||||||
typedef struct OpusCustomDecoder OpusCustomDecoder;
|
|
||||||
|
|
||||||
/** The mode contains all the information necessary to create an
|
|
||||||
encoder. Both the encoder and decoder need to be initialized
|
|
||||||
with exactly the same mode, otherwise the output will be
|
|
||||||
corrupted.
|
|
||||||
@brief Mode configuration
|
|
||||||
*/
|
|
||||||
typedef struct OpusCustomMode OpusCustomMode;
|
|
||||||
|
|
||||||
/** Creates a new mode struct. This will be passed to an encoder or
|
|
||||||
* decoder. The mode MUST NOT BE DESTROYED until the encoders and
|
|
||||||
* decoders that use it are destroyed as well.
|
|
||||||
* @param [in] Fs <tt>int</tt>: Sampling rate (8000 to 96000 Hz)
|
|
||||||
* @param [in] frame_size <tt>int</tt>: Number of samples (per channel) to encode in each
|
|
||||||
* packet (64 - 1024, prime factorization must contain zero or more 2s, 3s, or 5s and no other primes)
|
|
||||||
* @param [out] error <tt>int*</tt>: Returned error code (if NULL, no error will be returned)
|
|
||||||
* @return A newly created mode
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error);
|
|
||||||
|
|
||||||
/** Destroys a mode struct. Only call this after all encoders and
|
|
||||||
* decoders using this mode are destroyed as well.
|
|
||||||
* @param [in] mode <tt>OpusCustomMode*</tt>: Mode to be freed.
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode);
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(OPUS_BUILD) || defined(CELT_ENCODER_C)
|
|
||||||
|
|
||||||
/* Encoder */
|
|
||||||
/** Gets the size of an OpusCustomEncoder structure.
|
|
||||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
|
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels
|
|
||||||
* @returns size
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_size(
|
|
||||||
const OpusCustomMode *mode,
|
|
||||||
int channels
|
|
||||||
) OPUS_ARG_NONNULL(1);
|
|
||||||
|
|
||||||
# ifdef CUSTOM_MODES
|
|
||||||
/** Initializes a previously allocated encoder state
|
|
||||||
* The memory pointed to by st must be the size returned by opus_custom_encoder_get_size.
|
|
||||||
* This is intended for applications which use their own allocator instead of malloc.
|
|
||||||
* @see opus_custom_encoder_create(),opus_custom_encoder_get_size()
|
|
||||||
* To reset a previously initialized state use the OPUS_RESET_STATE CTL.
|
|
||||||
* @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
|
|
||||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
|
|
||||||
* the stream (must be the same characteristics as used for the
|
|
||||||
* decoder)
|
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels
|
|
||||||
* @return OPUS_OK Success or @ref opus_errorcodes
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT int opus_custom_encoder_init(
|
|
||||||
OpusCustomEncoder *st,
|
|
||||||
const OpusCustomMode *mode,
|
|
||||||
int channels
|
|
||||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/** Creates a new encoder state. Each stream needs its own encoder
|
|
||||||
* state (can't be shared across simultaneous streams).
|
|
||||||
* @param [in] mode <tt>OpusCustomMode*</tt>: Contains all the information about the characteristics of
|
|
||||||
* the stream (must be the same characteristics as used for the
|
|
||||||
* decoder)
|
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels
|
|
||||||
* @param [out] error <tt>int*</tt>: Returns an error code
|
|
||||||
* @return Newly created encoder state.
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encoder_create(
|
|
||||||
const OpusCustomMode *mode,
|
|
||||||
int channels,
|
|
||||||
int *error
|
|
||||||
) OPUS_ARG_NONNULL(1);
|
|
||||||
|
|
||||||
|
|
||||||
/** Destroys a an encoder state.
|
|
||||||
* @param[in] st <tt>OpusCustomEncoder*</tt>: State to be freed.
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st);
|
|
||||||
|
|
||||||
/** Encodes a frame of audio.
|
|
||||||
* @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
|
|
||||||
* @param [in] pcm <tt>float*</tt>: PCM audio in float format, with a normal range of +/-1.0.
|
|
||||||
* Samples with a range beyond +/-1.0 are supported but will
|
|
||||||
* be clipped by decoders using the integer API and should
|
|
||||||
* only be used if it is known that the far end supports
|
|
||||||
* extended dynamic range. There must be exactly
|
|
||||||
* frame_size samples per channel.
|
|
||||||
* @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal
|
|
||||||
* @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.
|
|
||||||
* @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame
|
|
||||||
* (can change from one frame to another)
|
|
||||||
* @return Number of bytes written to "compressed".
|
|
||||||
* If negative, an error has occurred (see error codes). It is IMPORTANT that
|
|
||||||
* the length returned be somehow transmitted to the decoder. Otherwise, no
|
|
||||||
* decoding is possible.
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode_float(
|
|
||||||
OpusCustomEncoder *st,
|
|
||||||
const float *pcm,
|
|
||||||
int frame_size,
|
|
||||||
unsigned char *compressed,
|
|
||||||
int maxCompressedBytes
|
|
||||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
|
|
||||||
|
|
||||||
/** Encodes a frame of audio.
|
|
||||||
* @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
|
|
||||||
* @param [in] pcm <tt>opus_int16*</tt>: PCM audio in signed 16-bit format (native endian).
|
|
||||||
* There must be exactly frame_size samples per channel.
|
|
||||||
* @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal
|
|
||||||
* @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.
|
|
||||||
* @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame
|
|
||||||
* (can change from one frame to another)
|
|
||||||
* @return Number of bytes written to "compressed".
|
|
||||||
* If negative, an error has occurred (see error codes). It is IMPORTANT that
|
|
||||||
* the length returned be somehow transmitted to the decoder. Otherwise, no
|
|
||||||
* decoding is possible.
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode(
|
|
||||||
OpusCustomEncoder *st,
|
|
||||||
const opus_int16 *pcm,
|
|
||||||
int frame_size,
|
|
||||||
unsigned char *compressed,
|
|
||||||
int maxCompressedBytes
|
|
||||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
|
|
||||||
|
|
||||||
/** Perform a CTL function on an Opus custom encoder.
|
|
||||||
*
|
|
||||||
* Generally the request and subsequent arguments are generated
|
|
||||||
* by a convenience macro.
|
|
||||||
* @see opus_encoderctls
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(OPUS_BUILD) || defined(CELT_DECODER_C)
|
|
||||||
/* Decoder */
|
|
||||||
|
|
||||||
/** Gets the size of an OpusCustomDecoder structure.
|
|
||||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
|
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels
|
|
||||||
* @returns size
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_size(
|
|
||||||
const OpusCustomMode *mode,
|
|
||||||
int channels
|
|
||||||
) OPUS_ARG_NONNULL(1);
|
|
||||||
|
|
||||||
/** Initializes a previously allocated decoder state
|
|
||||||
* The memory pointed to by st must be the size returned by opus_custom_decoder_get_size.
|
|
||||||
* This is intended for applications which use their own allocator instead of malloc.
|
|
||||||
* @see opus_custom_decoder_create(),opus_custom_decoder_get_size()
|
|
||||||
* To reset a previously initialized state use the OPUS_RESET_STATE CTL.
|
|
||||||
* @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
|
|
||||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
|
|
||||||
* the stream (must be the same characteristics as used for the
|
|
||||||
* encoder)
|
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels
|
|
||||||
* @return OPUS_OK Success or @ref opus_errorcodes
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init(
|
|
||||||
OpusCustomDecoder *st,
|
|
||||||
const OpusCustomMode *mode,
|
|
||||||
int channels
|
|
||||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/** Creates a new decoder state. Each stream needs its own decoder state (can't
|
|
||||||
* be shared across simultaneous streams).
|
|
||||||
* @param [in] mode <tt>OpusCustomMode</tt>: Contains all the information about the characteristics of the
|
|
||||||
* stream (must be the same characteristics as used for the encoder)
|
|
||||||
* @param [in] channels <tt>int</tt>: Number of channels
|
|
||||||
* @param [out] error <tt>int*</tt>: Returns an error code
|
|
||||||
* @return Newly created decoder state.
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create(
|
|
||||||
const OpusCustomMode *mode,
|
|
||||||
int channels,
|
|
||||||
int *error
|
|
||||||
) OPUS_ARG_NONNULL(1);
|
|
||||||
|
|
||||||
/** Destroys a an decoder state.
|
|
||||||
* @param[in] st <tt>OpusCustomDecoder*</tt>: State to be freed.
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st);
|
|
||||||
|
|
||||||
/** Decode an opus custom frame with floating point output
|
|
||||||
* @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
|
|
||||||
* @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
|
|
||||||
* @param [in] len <tt>int</tt>: Number of bytes in payload
|
|
||||||
* @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
|
|
||||||
* is frame_size*channels*sizeof(float)
|
|
||||||
* @param [in] frame_size Number of samples per channel of available space in *pcm.
|
|
||||||
* @returns Number of decoded samples or @ref opus_errorcodes
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode_float(
|
|
||||||
OpusCustomDecoder *st,
|
|
||||||
const unsigned char *data,
|
|
||||||
int len,
|
|
||||||
float *pcm,
|
|
||||||
int frame_size
|
|
||||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
|
||||||
|
|
||||||
/** Decode an opus custom frame
|
|
||||||
* @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
|
|
||||||
* @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
|
|
||||||
* @param [in] len <tt>int</tt>: Number of bytes in payload
|
|
||||||
* @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
|
|
||||||
* is frame_size*channels*sizeof(opus_int16)
|
|
||||||
* @param [in] frame_size Number of samples per channel of available space in *pcm.
|
|
||||||
* @returns Number of decoded samples or @ref opus_errorcodes
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode(
|
|
||||||
OpusCustomDecoder *st,
|
|
||||||
const unsigned char *data,
|
|
||||||
int len,
|
|
||||||
opus_int16 *pcm,
|
|
||||||
int frame_size
|
|
||||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
|
||||||
|
|
||||||
/** Perform a CTL function on an Opus custom decoder.
|
|
||||||
*
|
|
||||||
* Generally the request and subsequent arguments are generated
|
|
||||||
* by a convenience macro.
|
|
||||||
* @see opus_genericctls
|
|
||||||
*/
|
|
||||||
OPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
|
|
||||||
|
|
||||||
/**@}*/
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* OPUS_CUSTOM_H */
|
|
@ -64,7 +64,7 @@ extern "C" {
|
|||||||
/**Export control for opus functions */
|
/**Export control for opus functions */
|
||||||
|
|
||||||
#ifndef OPUS_EXPORT
|
#ifndef OPUS_EXPORT
|
||||||
# if defined(WIN32)
|
# if defined(_WIN32)
|
||||||
# if defined(OPUS_BUILD) && defined(DLL_EXPORT)
|
# if defined(OPUS_BUILD) && defined(DLL_EXPORT)
|
||||||
# define OPUS_EXPORT __declspec(dllexport)
|
# define OPUS_EXPORT __declspec(dllexport)
|
||||||
# else
|
# else
|
||||||
@ -168,15 +168,33 @@ extern "C" {
|
|||||||
/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
|
/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
|
||||||
#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046
|
#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046
|
||||||
#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047
|
#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047
|
||||||
|
#define OPUS_GET_IN_DTX_REQUEST 4049
|
||||||
|
#define OPUS_SET_DRED_DURATION_REQUEST 4050
|
||||||
|
#define OPUS_GET_DRED_DURATION_REQUEST 4051
|
||||||
|
#define OPUS_SET_DNN_BLOB_REQUEST 4052
|
||||||
|
/*#define OPUS_GET_DNN_BLOB_REQUEST 4053 */
|
||||||
|
|
||||||
/** Defines for the presence of extended APIs. */
|
/** Defines for the presence of extended APIs. */
|
||||||
#define OPUS_HAVE_OPUS_PROJECTION_H
|
#define OPUS_HAVE_OPUS_PROJECTION_H
|
||||||
|
|
||||||
/* Macros to trigger compilation errors when the wrong types are provided to a CTL */
|
/* Macros to trigger compilation errors when the wrong types are provided to a CTL */
|
||||||
#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
|
#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
|
||||||
|
|
||||||
|
#ifdef DISABLE_PTR_CHECK
|
||||||
|
/* Disable checks to prevent ubsan from complaining about NULL checks
|
||||||
|
in test_opus_api. */
|
||||||
|
#define __opus_check_int_ptr(ptr) (ptr)
|
||||||
|
#define __opus_check_uint_ptr(ptr) (ptr)
|
||||||
|
#define __opus_check_uint8_ptr(ptr) (ptr)
|
||||||
|
#define __opus_check_val16_ptr(ptr) (ptr)
|
||||||
|
#define __opus_check_void_ptr(ptr) (ptr)
|
||||||
|
#else
|
||||||
#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr)))
|
#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr)))
|
||||||
#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr)))
|
#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr)))
|
||||||
|
#define __opus_check_uint8_ptr(ptr) ((ptr) + ((ptr) - (opus_uint8*)(ptr)))
|
||||||
#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr)))
|
#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr)))
|
||||||
|
#define __opus_check_void_ptr(x) ((void)((void *)0 == (x)), (x))
|
||||||
|
#endif
|
||||||
/** @endcond */
|
/** @endcond */
|
||||||
|
|
||||||
/** @defgroup opus_ctlvalues Pre-defined values for CTL interface
|
/** @defgroup opus_ctlvalues Pre-defined values for CTL interface
|
||||||
@ -481,7 +499,8 @@ extern "C" {
|
|||||||
* @param[in] x <tt>opus_int32</tt>: Allowed values:
|
* @param[in] x <tt>opus_int32</tt>: Allowed values:
|
||||||
* <dl>
|
* <dl>
|
||||||
* <dt>0</dt><dd>Disable inband FEC (default).</dd>
|
* <dt>0</dt><dd>Disable inband FEC (default).</dd>
|
||||||
* <dt>1</dt><dd>Enable inband FEC.</dd>
|
* <dt>1</dt><dd>Inband FEC enabled. If the packet loss rate is sufficiently high, Opus will automatically switch to SILK even at high rates to enable use of that FEC.</dd>
|
||||||
|
* <dt>2</dt><dd>Inband FEC enabled, but does not necessarily switch to SILK if we have music.</dd>
|
||||||
* </dl>
|
* </dl>
|
||||||
* @hideinitializer */
|
* @hideinitializer */
|
||||||
#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x)
|
#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x)
|
||||||
@ -490,7 +509,8 @@ extern "C" {
|
|||||||
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
|
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
|
||||||
* <dl>
|
* <dl>
|
||||||
* <dt>0</dt><dd>Inband FEC disabled (default).</dd>
|
* <dt>0</dt><dd>Inband FEC disabled (default).</dd>
|
||||||
* <dt>1</dt><dd>Inband FEC enabled.</dd>
|
* <dt>1</dt><dd>Inband FEC enabled. If the packet loss rate is sufficiently high, Opus will automatically switch to SILK even at high rates to enable use of that FEC.</dd>
|
||||||
|
* <dt>2</dt><dd>Inband FEC enabled, but does not necessarily switch to SILK if we have music.</dd>
|
||||||
* </dl>
|
* </dl>
|
||||||
* @hideinitializer */
|
* @hideinitializer */
|
||||||
#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x)
|
#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x)
|
||||||
@ -617,6 +637,18 @@ extern "C" {
|
|||||||
* @hideinitializer */
|
* @hideinitializer */
|
||||||
#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x)
|
#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x)
|
||||||
|
|
||||||
|
/** If non-zero, enables Deep Redundancy (DRED) and use the specified maximum number of 10-ms redundant frames
|
||||||
|
* @hideinitializer */
|
||||||
|
#define OPUS_SET_DRED_DURATION(x) OPUS_SET_DRED_DURATION_REQUEST, __opus_check_int(x)
|
||||||
|
/** Gets the encoder's configured Deep Redundancy (DRED) maximum number of frames.
|
||||||
|
* @hideinitializer */
|
||||||
|
#define OPUS_GET_DRED_DURATION(x) OPUS_GET_DRED_DURATION_REQUEST, __opus_check_int_ptr(x)
|
||||||
|
|
||||||
|
/** Provide external DNN weights from binary object (only when explicitly built without the weights)
|
||||||
|
* @hideinitializer */
|
||||||
|
#define OPUS_SET_DNN_BLOB(data, len) OPUS_SET_DNN_BLOB_REQUEST, __opus_check_void_ptr(data), __opus_check_int(len)
|
||||||
|
|
||||||
|
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
/** @defgroup opus_genericctls Generic CTLs
|
/** @defgroup opus_genericctls Generic CTLs
|
||||||
@ -715,6 +747,16 @@ extern "C" {
|
|||||||
* </dl>
|
* </dl>
|
||||||
* @hideinitializer */
|
* @hideinitializer */
|
||||||
#define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x)
|
#define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x)
|
||||||
|
/** Gets the DTX state of the encoder.
|
||||||
|
* Returns whether the last encoded frame was either a comfort noise update
|
||||||
|
* during DTX or not encoded because of DTX.
|
||||||
|
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
|
||||||
|
* <dl>
|
||||||
|
* <dt>0</dt><dd>The encoder is not in DTX.</dd>
|
||||||
|
* <dt>1</dt><dd>The encoder is in DTX.</dd>
|
||||||
|
* </dl>
|
||||||
|
* @hideinitializer */
|
||||||
|
#define OPUS_GET_IN_DTX(x) OPUS_GET_IN_DTX_REQUEST, __opus_check_int_ptr(x)
|
||||||
|
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ extern "C" {
|
|||||||
* <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9">Vorbis
|
* <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9">Vorbis
|
||||||
* channel ordering</a>. A decoder may wish to apply an additional permutation
|
* channel ordering</a>. A decoder may wish to apply an additional permutation
|
||||||
* to the mapping the encoder used to achieve a different output channel
|
* to the mapping the encoder used to achieve a different output channel
|
||||||
* order (e.g. for outputing in WAV order).
|
* order (e.g. for outputting in WAV order).
|
||||||
*
|
*
|
||||||
* Each multistream packet contains an Opus packet for each stream, and all of
|
* Each multistream packet contains an Opus packet for each stream, and all of
|
||||||
* the Opus packets in a single multistream packet must have the same
|
* the Opus packets in a single multistream packet must have the same
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
|||||||
Subproject commit 5e844aad080f39e6ef1ce1f4d626f31027a2daed
|
Subproject commit 8af4562af672dd6b9ed28553ead172984fd9a683
|
@ -212,6 +212,11 @@ Java_com_limelight_nvstream_jni_MoonBridge_getEstimatedRttInfo(JNIEnv *env, jcla
|
|||||||
return ((uint64_t)rtt << 32U) | variance;
|
return ((uint64_t)rtt << 32U) | variance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_com_limelight_nvstream_jni_MoonBridge_getLaunchUrlQueryParameters(JNIEnv *env, jclass clazz) {
|
||||||
|
return (*env)->NewStringUTF(env, LiGetLaunchUrlQueryParameters());
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jbyte JNICALL
|
JNIEXPORT jbyte JNICALL
|
||||||
Java_com_limelight_nvstream_jni_MoonBridge_guessControllerType(JNIEnv *env, jclass clazz, jint vendorId, jint productId) {
|
Java_com_limelight_nvstream_jni_MoonBridge_guessControllerType(JNIEnv *env, jclass clazz, jint vendorId, jint productId) {
|
||||||
unsigned int unDeviceID = MAKE_CONTROLLER_ID(vendorId, productId);
|
unsigned int unDeviceID = MAKE_CONTROLLER_ID(vendorId, productId);
|
||||||
|
@ -79,7 +79,7 @@
|
|||||||
<string name="conn_terminated_title">Verbindung beendet</string>
|
<string name="conn_terminated_title">Verbindung beendet</string>
|
||||||
<string name="conn_terminated_msg">Die Verbindung wurde beendet</string>
|
<string name="conn_terminated_msg">Die Verbindung wurde beendet</string>
|
||||||
<!-- General strings -->
|
<!-- General strings -->
|
||||||
<string name="ip_hint">IP-Adresse des GeForce Host</string>
|
<string name="ip_hint">IP-Adresse des GeForce Hosts</string>
|
||||||
<string name="searching_pc">Suche nach Hosts auf denen GeForce Experience aktiv ist…
|
<string name="searching_pc">Suche nach Hosts auf denen GeForce Experience aktiv ist…
|
||||||
\n
|
\n
|
||||||
\nStelle sicher, dass GameStream in den GeForce Experience SHIELD-Einstellungen aktiviert ist.</string>
|
\nStelle sicher, dass GameStream in den GeForce Experience SHIELD-Einstellungen aktiviert ist.</string>
|
||||||
@ -261,4 +261,18 @@
|
|||||||
<string name="frame_conversion_error">Der Host-PC hat einen schwerwiegenden Videocodierungsfehler gemeldet.
|
<string name="frame_conversion_error">Der Host-PC hat einen schwerwiegenden Videocodierungsfehler gemeldet.
|
||||||
\n
|
\n
|
||||||
\nVersuchen Sie, den HDR-Modus zu deaktivieren, die Streaming-Auflösung zu ändern oder die Bildschirmauflösung des Host-PCs zu ändern.</string>
|
\nVersuchen Sie, den HDR-Modus zu deaktivieren, die Streaming-Auflösung zu ändern oder die Bildschirmauflösung des Host-PCs zu ändern.</string>
|
||||||
|
<string name="title_native_fps_dialog">Native FPS Warnung</string>
|
||||||
|
<string name="videoformat_av1always">Immer AV1 verwenden (Experimentell)</string>
|
||||||
|
<string name="title_checkbox_gamepad_motion_sensors">Erlaube Benutzen von Gamepad Bewegungssensoren</string>
|
||||||
|
<string name="videoformat_h264always">Immer H.264 verwenden</string>
|
||||||
|
<string name="fps_suffix_fps">FPS</string>
|
||||||
|
<string name="category_gamepad_settings">Gamepad Einstellungen</string>
|
||||||
|
<string name="pair_pairing_help">Wenn dein Host PC Sunshine verwendet, navigiere zur Sunshine Web UI und gebe dort die PIN ein.</string>
|
||||||
|
<string name="title_checkbox_gamepad_touchpad_as_mouse">Die Maus immer mit dem Touchpad steuern</string>
|
||||||
|
<string name="perf_overlay_hostprocessinglatency">Host Verarbeitungslatenz min/max/avg: %1$.1f/%2$.1f/%3$.1f ms</string>
|
||||||
|
<string name="title_analog_scrolling">Verwenden Sie zum Scrollen einen Analogstick</string>
|
||||||
|
<string name="summary_analog_scrolling">Wählen Sie einen Analogstick aus, der zum scrollen im Mausemulationsmodus verwendet werden soll</string>
|
||||||
|
<string name="analogscroll_none">Keine (beide Sticks bewegen die Maus)</string>
|
||||||
|
<string name="analogscroll_right">Rechter Analogstick</string>
|
||||||
|
<string name="analogscroll_left">Linker Analogstick</string>
|
||||||
</resources>
|
</resources>
|
@ -112,7 +112,8 @@
|
|||||||
<string name="scut_not_paired">Ο υπολογιστής δεν έχει συζευχθεί</string>
|
<string name="scut_not_paired">Ο υπολογιστής δεν έχει συζευχθεί</string>
|
||||||
<string name="pcview_menu_header_offline">Εκτός σύνδεσης</string>
|
<string name="pcview_menu_header_offline">Εκτός σύνδεσης</string>
|
||||||
<string name="pcview_menu_test_network">Δοκιμή σύνδεσης δικτύου</string>
|
<string name="pcview_menu_test_network">Δοκιμή σύνδεσης δικτύου</string>
|
||||||
<string name="nettest_text_waiting">Το Moonlight δοκιμάζει τη σύνδεση δικτύου σας για να καθορίσει εάν το NVIDIA GameStream είναι αποκλεισμένο.
|
<string name="nettest_text_waiting">Το Moonlight δοκιμάζει τη σύνδεση δικτύου σας για να διαπιστώσει εάν κάποια θύρα είναι αποκλεισμένη.
|
||||||
|
\n
|
||||||
\n
|
\n
|
||||||
\nΑυτό μπορεί να πάρει μερικά δευτερόλεπτα…</string>
|
\nΑυτό μπορεί να πάρει μερικά δευτερόλεπτα…</string>
|
||||||
<string name="pair_fail">Η σύζευξη απέτυχε</string>
|
<string name="pair_fail">Η σύζευξη απέτυχε</string>
|
||||||
@ -205,4 +206,10 @@
|
|||||||
<string name="title_video_format">Αλλαγή ρυθμίσεων HEVC</string>
|
<string name="title_video_format">Αλλαγή ρυθμίσεων HEVC</string>
|
||||||
<string name="title_enable_post_stream_toast">Εμφάνιση μηνύματος λανθάνοντος χρόνου μετά τη ροή</string>
|
<string name="title_enable_post_stream_toast">Εμφάνιση μηνύματος λανθάνοντος χρόνου μετά τη ροή</string>
|
||||||
<string name="summary_video_format">Το HEVC μειώνει τις απαιτήσεις εύρους ζώνης βίντεο, αλλά απαιτεί μια νεότερη συσκευή</string>
|
<string name="summary_video_format">Το HEVC μειώνει τις απαιτήσεις εύρους ζώνης βίντεο, αλλά απαιτεί μια νεότερη συσκευή</string>
|
||||||
|
<string name="error_code_prefix">Κωδικός σφάλματος:</string>
|
||||||
|
<string name="frame_conversion_error">Ο υπολογιστής φιλοξενίας ανέφερε ένα σφάλμα κωδικοποίησης βίντεο.
|
||||||
|
\n
|
||||||
|
\nΔοκιμάστε να απενεργοποιήσετε τη λειτουργία HDR, να αλλάξετε την ανάλυση ροής ή να αλλάξετε την ανάλυση οθόνης του υπολογιστή φιλοξενίας.</string>
|
||||||
|
<string name="pcview_menu_eol">Λήξη Υποστήριξης NVIDA GameStream</string>
|
||||||
|
<string name="pair_pairing_help">Εάν ο υπολογιστής οικοδεσπότης χρησιμοποιεί το Sunshine, πλοηγηθείτε στην διαδικτυακή διεπαφή χρήστη του Sunshine για να εισάγετε το PIN.</string>
|
||||||
</resources>
|
</resources>
|
@ -45,7 +45,7 @@
|
|||||||
<string name="conn_error_title">Error de conexión</string>
|
<string name="conn_error_title">Error de conexión</string>
|
||||||
<string name="conn_error_msg">Fallo al iniciar</string>
|
<string name="conn_error_msg">Fallo al iniciar</string>
|
||||||
<string name="conn_terminated_title">Conexión finalizada</string>
|
<string name="conn_terminated_title">Conexión finalizada</string>
|
||||||
<string name="conn_terminated_msg">La conexión ha finalizando</string>
|
<string name="conn_terminated_msg">La conexión ha finalizado.</string>
|
||||||
<!-- General strings -->
|
<!-- General strings -->
|
||||||
<string name="ip_hint">Dirección IP del host del ordenador</string>
|
<string name="ip_hint">Dirección IP del host del ordenador</string>
|
||||||
<string name="searching_pc">Buscando el hostal del PC en tu red local...
|
<string name="searching_pc">Buscando el hostal del PC en tu red local...
|
||||||
@ -278,4 +278,13 @@
|
|||||||
<string name="summary_checkbox_gamepad_motion_fallback">Utiliza los sensores de movimiento integrados de tu dispositivo si el gamepad conectado o tu versión de Android no admiten los sensores del gamepad.
|
<string name="summary_checkbox_gamepad_motion_fallback">Utiliza los sensores de movimiento integrados de tu dispositivo si el gamepad conectado o tu versión de Android no admiten los sensores del gamepad.
|
||||||
\nNota: Activar esta opción puede hacer que tu gamepad aparezca como un mando de PlayStation en el host.</string>
|
\nNota: Activar esta opción puede hacer que tu gamepad aparezca como un mando de PlayStation en el host.</string>
|
||||||
<string name="title_checkbox_gamepad_motion_fallback">Emular el sensor de movimiento del gamepad</string>
|
<string name="title_checkbox_gamepad_motion_fallback">Emular el sensor de movimiento del gamepad</string>
|
||||||
|
<string name="analogscroll_none">Ninguno (ambos joysticks mueven el mouse)</string>
|
||||||
|
<string name="analogscroll_right">Joystick analógico derecho</string>
|
||||||
|
<string name="analogscroll_left">Joystick analógico izquierdo</string>
|
||||||
|
<string name="title_analog_scrolling">Usa un joystick analógico para hacer scroll</string>
|
||||||
|
<string name="summary_analog_scrolling">Selecciona un joystick analógico para scroll cuando la emulación del mouse está habilitada</string>
|
||||||
|
<string name="error_code_prefix">Código del error:</string>
|
||||||
|
<string name="title_seekbar_vibrate_fallback_strength">Ajustar la intensidad del ruido emulado</string>
|
||||||
|
<string name="summary_seekbar_vibrate_fallback_strength">Amplifica o reduce la intensidad de la vibración de tu dispositivo</string>
|
||||||
|
<string name="suffix_seekbar_vibrate_fallback_strength">%</string>
|
||||||
</resources>
|
</resources>
|
@ -10,11 +10,11 @@
|
|||||||
<string name="help_loading_title">Visionneuse d\'aide</string>
|
<string name="help_loading_title">Visionneuse d\'aide</string>
|
||||||
<string name="help_loading_msg">Chargement de la page d\'aide…</string>
|
<string name="help_loading_msg">Chargement de la page d\'aide…</string>
|
||||||
<!-- PC view menu entries -->
|
<!-- PC view menu entries -->
|
||||||
<string name="pcview_menu_app_list">Afficher la liste des jeux</string>
|
<string name="pcview_menu_app_list">Afficher toutes les applis</string>
|
||||||
<string name="pcview_menu_pair_pc">Appairer avec PC</string>
|
<string name="pcview_menu_pair_pc">Appairer avec ce PC</string>
|
||||||
<string name="pcview_menu_unpair_pc">Désappairer</string>
|
<string name="pcview_menu_unpair_pc">Désappairer</string>
|
||||||
<string name="pcview_menu_send_wol">Envoyer la requête Wake-On-LAN</string>
|
<string name="pcview_menu_send_wol">Envoyer une requête Wake-On-LAN</string>
|
||||||
<string name="pcview_menu_delete_pc">Supprimer PC</string>
|
<string name="pcview_menu_delete_pc">Supprimer le PC</string>
|
||||||
<string name="pcview_menu_details">Voir les détails</string>
|
<string name="pcview_menu_details">Voir les détails</string>
|
||||||
<!-- Network test strings -->
|
<!-- Network test strings -->
|
||||||
<string name="nettest_title_waiting">Test de la connexion réseau</string>
|
<string name="nettest_title_waiting">Test de la connexion réseau</string>
|
||||||
@ -22,19 +22,21 @@
|
|||||||
\n
|
\n
|
||||||
\nCela peut prendre quelques secondes…</string>
|
\nCela peut prendre quelques secondes…</string>
|
||||||
<string name="nettest_title_done">Test du réseau terminé</string>
|
<string name="nettest_title_done">Test du réseau terminé</string>
|
||||||
<string name="nettest_text_success">Votre réseau ne semble pas bloquer Moonlight. Si vous avez encore de la difficulté à vous connecter, vérifiez les paramètres du pare-feu de votre PC.\n\nSi vous essayez de diffuser sur Internet, installez l\'outil d\'hébergement Internet Moonlight sur votre PC et exécutez le testeur de streaming Internet inclus pour vérifier la connexion Internet de votre PC.</string>
|
<string name="nettest_text_success">Votre réseau ne semble pas bloquer Moonlight. Si vous avez encore des difficultés à vous connecter, vérifiez les paramètres du pare-feu de votre PC.
|
||||||
<string name="nettest_text_inconclusive">Le test réseau n’a pas pu être effectué car aucun des serveurs de test de connexion Moonlight n’était accessible. Vérifiez votre connexion Internet ou réessayez plus tard.</string>
|
\n
|
||||||
<string name="nettest_text_failure">La connexion réseau actuelle de votre appareil semble bloquer Moonlight. Le streaming sur Internet peut ne pas fonctionner lorsqu’il est connecté à ce réseau.
|
\nSi vous essayez de streamer depuis Internet, installez l\'outil Moonlight Internet Hosting Tool sur votre PC et exécutez le testeur de streaming Internet inclus pour vérifier la connexion Internet de votre PC.</string>
|
||||||
|
<string name="nettest_text_inconclusive">Le test réseau n\'a pas pu être effectué car aucun des serveurs de test de connexion de Moonlight n\'était accessible. Vérifiez votre connexion Internet ou réessayez plus tard.</string>
|
||||||
|
<string name="nettest_text_failure">La connexion réseau actuelle de votre appareil semble bloquer Moonlight. Le streaming sur Internet peut ne pas fonctionner lorsque vous êtes connecté à ce réseau.
|
||||||
\n
|
\n
|
||||||
\nLes ports réseau suivants ont été bloqués :
|
\nLes ports réseau suivants ont été bloqués :
|
||||||
\n</string>
|
\n</string>
|
||||||
<string name="nettest_text_blocked">La connexion réseau actuelle de votre appareil bloque Moonlight. Le streaming sur Internet peut ne pas fonctionner lorsqu’il est connecté à ce réseau.</string>
|
<string name="nettest_text_blocked">La connexion réseau actuelle de votre appareil bloque Moonlight. Le streaming sur Internet peut ne pas fonctionner lorsque vous êtes connecté à ce réseau.</string>
|
||||||
<!-- Pair messages -->
|
<!-- Pair messages -->
|
||||||
<string name="pairing">Appariement…</string>
|
<string name="pairing">Appariement…</string>
|
||||||
<string name="pair_pc_offline">L\'ordinateur est hors ligne</string>
|
<string name="pair_pc_offline">L\'ordinateur est hors ligne</string>
|
||||||
<string name="pair_pc_ingame">L\'ordinateur est actuellement dans un jeu. Vous devez fermer le jeu avant l\'appariement.</string>
|
<string name="pair_pc_ingame">L\'ordinateur est actuellement dans un jeu. Vous devez fermer le jeu avant l’appairage.</string>
|
||||||
<string name="pair_pairing_title">Appariement</string>
|
<string name="pair_pairing_title">Appariement</string>
|
||||||
<string name="pair_pairing_msg">SVP entrer le code PIN suivant sur le PC concerné :</string>
|
<string name="pair_pairing_msg">Veuillez saisir le code PIN suivant sur le PC cible :</string>
|
||||||
<string name="pair_incorrect_pin">Code PIN incorrect</string>
|
<string name="pair_incorrect_pin">Code PIN incorrect</string>
|
||||||
<string name="pair_fail">Échec de l\'appariement</string>
|
<string name="pair_fail">Échec de l\'appariement</string>
|
||||||
<string name="pair_already_in_progress">Appariement déjà en cours</string>
|
<string name="pair_already_in_progress">Appariement déjà en cours</string>
|
||||||
@ -42,40 +44,36 @@
|
|||||||
<string name="wol_pc_online">L\'ordinateur est en ligne</string>
|
<string name="wol_pc_online">L\'ordinateur est en ligne</string>
|
||||||
<string name="wol_no_mac">Impossible de réveiller le PC car il n\'y a pas d\'addresse MAC enregistrée pour ce PC</string>
|
<string name="wol_no_mac">Impossible de réveiller le PC car il n\'y a pas d\'addresse MAC enregistrée pour ce PC</string>
|
||||||
<string name="wol_waking_pc">Réveil PC…</string>
|
<string name="wol_waking_pc">Réveil PC…</string>
|
||||||
<string name="wol_waking_msg">Votre PC peut prendre quelques secondes pour se réveiller.
|
<string name="wol_waking_msg">Votre PC peut prendre quelques secondes pour démarrer. S\'il ne démarre toujours pas, assurez-vous qu\'il est correctement configuré pour le Wake-On-LAN.</string>
|
||||||
Si ce n\'est pas le cas, assurez-vous qu\'il est correctement configuré pour Wake-On-LAN.
|
|
||||||
</string>
|
|
||||||
<string name="wol_fail">Échec de l\'envoi des paquets Wake-On-LAN</string>
|
<string name="wol_fail">Échec de l\'envoi des paquets Wake-On-LAN</string>
|
||||||
<!-- Unpair messages -->
|
<!-- Unpair messages -->
|
||||||
<string name="unpairing">Désappariage…</string>
|
<string name="unpairing">Désappariage…</string>
|
||||||
<string name="unpair_success">Désapparié avec succès</string>
|
<string name="unpair_success">Désapparié avec succès</string>
|
||||||
<string name="unpair_fail">Échec de désappariement</string>
|
<string name="unpair_fail">Échec du désappairage</string>
|
||||||
<string name="unpair_error">Le périphérique n\'a pas été appareillé</string>
|
<string name="unpair_error">Le périphérique n\'est appareillé</string>
|
||||||
<!-- Errors -->
|
<!-- Errors -->
|
||||||
<string name="error_pc_offline">L\'ordinateur est déconnecté</string>
|
<string name="error_pc_offline">L\'ordinateur est hors ligne</string>
|
||||||
<string name="error_manager_not_running">Le service ComputerManager n\'est pas en cours d\'exécution. Veuillez patienter quelques secondes ou redémarrer l\'application.</string>
|
<string name="error_manager_not_running">Le service ComputerManager n\'est pas en cours d\'exécution. Veuillez attendre quelques secondes ou redémarrez l\'application.</string>
|
||||||
<string name="error_unknown_host">Échec de la résolution de l\'hôte</string>
|
<string name="error_unknown_host">Échec de la résolution de l\'hôte</string>
|
||||||
<string name="error_404">GFE renvoi une erreur HTTP 404. Assurez-vous que votre PC exécute un GPU pris en charge.
|
<string name="error_404">GFE renvoie une erreur HTTP 404. Assurez-vous que votre PC possède un GPU pris en charge. L\'utilisation d\'un logiciel de bureau à distance peut également provoquer cette erreur. Essayez de redémarrer votre machine ou de réinstaller GFE.</string>
|
||||||
L\'utilisation d\'un logiciel de bureau à distance peut également provoquer cette erreur. Essayez de redémarrer votre machine ou de réinstaller GFE.
|
<string name="title_decoding_error">Le décodeur vidéo a planté</string>
|
||||||
</string>
|
<string name="message_decoding_error">Moonlight a planté en raison d\'une incompatibilité avec le décodeur vidéo de cet appareil. Essayez d\'ajuster les paramètres de streaming si les plantages continuent.</string>
|
||||||
<string name="title_decoding_error">Le décodeur vidéo s\'est écrasé</string>
|
<string name="title_decoding_reset">Réinitialiser les paramètres vidéo</string>
|
||||||
<string name="message_decoding_error">Moonlight s\'est arrêté en raison d\'une incompatibilité avec le décodeur vidéo de cet appareil. Essayez d\'ajuster les paramètres de diffusion si les plantages continuent.</string>
|
<string name="message_decoding_reset">Le décodeur vidéo de votre appareil continue de planter avec les paramètres de streaming sélectionnés. Vos paramètres de streaming ont été réinitialisés à ceux par défaut.</string>
|
||||||
<string name="title_decoding_reset">Paramètres vidéo réinitialiser</string>
|
<string name="error_usb_prohibited">L\'accès USB est interdit par l\'administrateur de votre appareil. Vérifiez vos paramètres Knox ou MDM.</string>
|
||||||
<string name="message_decoding_reset">Le décodeur vidéo de votre appareil continue de planter avec les paramètres de diffusion sélectionnés. Vos paramètres de diffusion ont été réinitialisés par défaut.</string>
|
<string name="unable_to_pin_shortcut">Votre launcher actuel ne permet pas de créer des raccourcis épinglés.</string>
|
||||||
<string name="error_usb_prohibited">L\'accès USB est interdit par votre appareil. Vérifiez vos paramètres Knox ou MDM.</string>
|
|
||||||
<string name="unable_to_pin_shortcut">Votre lanceur actuel ne permet pas de créer des raccourcis épinglés.</string>
|
|
||||||
<!-- Start application messages -->
|
<!-- Start application messages -->
|
||||||
<string name="conn_establishing_title">Établissement de la connexion</string>
|
<string name="conn_establishing_title">Établissement de la connexion</string>
|
||||||
<string name="conn_establishing_msg">Démarrage de la connection</string>
|
<string name="conn_establishing_msg">Démarrage de la connection</string>
|
||||||
<string name="conn_metered">Attention : Votre connexion réseau active est mesurée !</string>
|
<string name="conn_metered">Attention : Votre connexion réseau active est limitée !</string>
|
||||||
<string name="conn_client_latency">Latence moyenne de décodage de trame :</string>
|
<string name="conn_client_latency">Latence moyenne de décodage de trame :</string>
|
||||||
<string name="conn_client_latency_hw">Latence du décodeur matériel :</string>
|
<string name="conn_client_latency_hw">Latence du décodeur matériel :</string>
|
||||||
<string name="conn_hardware_latency">Latence moyenne du décodage matériel :</string>
|
<string name="conn_hardware_latency">Latence moyenne du décodage matériel :</string>
|
||||||
<string name="conn_starting">Démarrage</string>
|
<string name="conn_starting">Démarrage</string>
|
||||||
<string name="conn_error_title">Erreur de connexion</string>
|
<string name="conn_error_title">Erreur de connexion</string>
|
||||||
<string name="conn_error_msg">Impossible de démarrer</string>
|
<string name="conn_error_msg">Impossible de démarrer</string>
|
||||||
<string name="conn_terminated_title">Connexion terminée</string>
|
<string name="conn_terminated_title">Connexion interrompue</string>
|
||||||
<string name="conn_terminated_msg">La connexion a été interrompue</string>
|
<string name="conn_terminated_msg">La connexion a été interrompue.</string>
|
||||||
<!-- General strings -->
|
<!-- General strings -->
|
||||||
<string name="ip_hint">Adresse IP du PC hôte</string>
|
<string name="ip_hint">Adresse IP du PC hôte</string>
|
||||||
<string name="searching_pc">Recherche de PC hôtes sur votre réseau local…
|
<string name="searching_pc">Recherche de PC hôtes sur votre réseau local…
|
||||||
@ -83,7 +81,7 @@
|
|||||||
\n Assurez-vous que Sunshine est en cours d\'execution ou que GameStream est activé dans les paramètres GeForce Experience SHIELD.</string>
|
\n Assurez-vous que Sunshine est en cours d\'execution ou que GameStream est activé dans les paramètres GeForce Experience SHIELD.</string>
|
||||||
<string name="yes">Oui</string>
|
<string name="yes">Oui</string>
|
||||||
<string name="no">Non</string>
|
<string name="no">Non</string>
|
||||||
<string name="lost_connection">Perte de connexion avec le PC</string>
|
<string name="lost_connection">Connexion perdue avec le PC</string>
|
||||||
<string name="title_details">Détails</string>
|
<string name="title_details">Détails</string>
|
||||||
<string name="help">Aide</string>
|
<string name="help">Aide</string>
|
||||||
<string name="delete_pc_msg">Êtes-vous sûr de vouloir supprimer ce PC \?</string>
|
<string name="delete_pc_msg">Êtes-vous sûr de vouloir supprimer ce PC \?</string>
|
||||||
@ -96,105 +94,105 @@
|
|||||||
<string name="perf_overlay_dectime">Temps moyen de décodage : %1$.2f ms</string>
|
<string name="perf_overlay_dectime">Temps moyen de décodage : %1$.2f ms</string>
|
||||||
<!-- AppList activity -->
|
<!-- AppList activity -->
|
||||||
<string name="applist_connect_msg">Connexion au PC…</string>
|
<string name="applist_connect_msg">Connexion au PC…</string>
|
||||||
<string name="applist_menu_resume">Reprise de la session</string>
|
<string name="applist_menu_resume">Reprendre la session</string>
|
||||||
<string name="applist_menu_quit">Quitter la session</string>
|
<string name="applist_menu_quit">Quitter la session</string>
|
||||||
<string name="applist_menu_quit_and_start">Quitter le jeu actuel et démarrer</string>
|
<string name="applist_menu_quit_and_start">Quitter le jeu actuel et démarrer</string>
|
||||||
<string name="applist_menu_cancel">Annuler</string>
|
<string name="applist_menu_cancel">Annuler</string>
|
||||||
<string name="applist_menu_details">Voir les détails</string>
|
<string name="applist_menu_details">Voir les détails</string>
|
||||||
<string name="applist_menu_scut">Créer un raccourci</string>
|
<string name="applist_menu_scut">Créer un raccourci</string>
|
||||||
<string name="applist_menu_tv_channel">Ajouter à la chaîne</string>
|
<string name="applist_menu_tv_channel">Ajouter à la liste de chaînes</string>
|
||||||
<string name="applist_refresh_title">Liste des applications</string>
|
<string name="applist_refresh_title">Liste des applications</string>
|
||||||
<string name="applist_refresh_msg">Actualisation des applications…</string>
|
<string name="applist_refresh_msg">Actualisation des applications…</string>
|
||||||
<string name="applist_refresh_error_title">Erreur</string>
|
<string name="applist_refresh_error_title">Erreur</string>
|
||||||
<string name="applist_refresh_error_msg">Impossible d\'obtenir la liste des applications</string>
|
<string name="applist_refresh_error_msg">Impossible d\'obtenir la liste des applications</string>
|
||||||
<string name="applist_quit_app">Fermeture</string>
|
<string name="applist_quit_app">Fermeture</string>
|
||||||
<string name="applist_quit_success">Fermeture avec succès</string>
|
<string name="applist_quit_success">Application fermée avec succès</string>
|
||||||
<string name="applist_quit_fail">Échec de la fermeture</string>
|
<string name="applist_quit_fail">Échec de la fermeture</string>
|
||||||
<string name="applist_quit_confirmation">Voulez-vous vraiment quitter l\'application en cours d\'exécution \? Toutes les données non enregistrées seront perdues.</string>
|
<string name="applist_quit_confirmation">Voulez-vous vraiment quitter l\'application en cours d\'exécution \? Toutes les données non enregistrées seront perdues.</string>
|
||||||
<string name="applist_details_id">ID de l\'appli :</string>
|
<string name="applist_details_id">ID de l\'appli :</string>
|
||||||
<!-- Add computer manually activity -->
|
<!-- Add computer manually activity -->
|
||||||
<string name="title_add_pc">Ajouter un PC manuellement</string>
|
<string name="title_add_pc">Ajouter un PC manuellement</string>
|
||||||
<string name="msg_add_pc">Connexion au PC…</string>
|
<string name="msg_add_pc">Connexion au PC…</string>
|
||||||
<string name="addpc_fail">Impossible de se connecter à l\'ordinateur spécifié. Assurez-vous que les ports requis sont autorisés par le pare-feu.</string>
|
<string name="addpc_fail">Impossible de se connecter à l\'ordinateur spécifié. Assurez-vous que les ports requis sont autorisés via le pare-feu.</string>
|
||||||
<string name="addpc_success">Ajouté avec succès de l\'ordinateur</string>
|
<string name="addpc_success">Ordinateur ajouté avec succès</string>
|
||||||
<string name="addpc_unknown_host">Impossible de résoudre l\'adresse du PC. Assurez-vous que vous n\'avez pas fait une faute de frappe dans l\'adresse.</string>
|
<string name="addpc_unknown_host">Impossible de résoudre l\'adresse du PC. Assurez-vous que vous n\'avez pas fait de faute de frappe dans l\'adresse.</string>
|
||||||
<string name="addpc_enter_ip">Vous devez entrer une adresse IP</string>
|
<string name="addpc_enter_ip">Vous devez entrer une adresse IP</string>
|
||||||
<string name="addpc_wrong_sitelocal">Cette adresse ne semble pas correcte. Vous devez utiliser l\'adresse IP publique de votre routeur pour la diffusion en continu sur Internet..</string>
|
<string name="addpc_wrong_sitelocal">Cette adresse ne semble pas correcte. Vous devez utiliser l\'adresse IP publique de votre routeur pour le streaming depuis Internet.</string>
|
||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="category_basic_settings">Paramètres de base</string>
|
<string name="category_basic_settings">Paramètres de base</string>
|
||||||
<string name="title_resolution_list">Résolution vidéo</string>
|
<string name="title_resolution_list">Résolution vidéo</string>
|
||||||
<string name="summary_resolution_list">Le réglage de valeurs trop élevées pour votre appareil peut provoquer un retard ou un plantage.</string>
|
<string name="summary_resolution_list">Augmentez pour une meilleure clarté de l\'image. Réduisez pour de meilleures performances sur les appareils bas de gamme et les réseaux lents.</string>
|
||||||
<string name="title_fps_list">Fréquence d\'images vidéo</string>
|
<string name="title_fps_list">Fréquence d\'images vidéo</string>
|
||||||
<string name="summary_fps_list">Augmenter pour un flux vidéo plus lisse. Diminution pour de meilleures performances sur les périphériques bas de gamme.</string>
|
<string name="summary_fps_list">Augmentez pour un flux vidéo plus fluide. Diminuez pour de meilleures performances sur les appareils bas de gamme.</string>
|
||||||
<string name="title_seekbar_bitrate">Sélectionnez le bitrate vidéo à obtenir</string>
|
<string name="title_seekbar_bitrate">Bitrate vidéo</string>
|
||||||
<string name="summary_seekbar_bitrate">Bitrate inférieur pour réduire la saccade. Augmentez le bitrate pour augmenter la qualité de l\'image.</string>
|
<string name="summary_seekbar_bitrate">Augmentez-le pour une meilleure qualité d’image. Diminuez-le pour améliorer les performances sur les connexions plus lentes.</string>
|
||||||
<string name="title_checkbox_stretch_video">Étirez la vidéo en plein écran</string>
|
<string name="title_checkbox_stretch_video">Étirer la vidéo en plein écran</string>
|
||||||
<string name="title_checkbox_disable_warnings">Désactiver les messages d\'avertissement</string>
|
<string name="title_checkbox_disable_warnings">Désactiver les messages d\'avertissement</string>
|
||||||
<string name="title_checkbox_enable_pip">Activer le mode observateur dans l\'image</string>
|
<string name="title_checkbox_enable_pip">Activer le mode observateur</string>
|
||||||
<string name="summary_checkbox_enable_pip">Permet de visualiser le flux (sans le contrôleur) tout en multitâche</string>
|
<string name="summary_checkbox_enable_pip">Permet de visualiser le stream (sans le contrôler) tout en utilisant une autre appli</string>
|
||||||
<string name="category_audio_settings">Paramètres audio</string>
|
<string name="category_audio_settings">Paramètres audio</string>
|
||||||
<string name="title_audio_config_list">Configuration son surround</string>
|
<string name="title_audio_config_list">Configuration son surround</string>
|
||||||
<string name="summary_audio_config_list">Activer le son surround 5.1 ou 7.1 pour les systèmes home cinéma</string>
|
<string name="summary_audio_config_list">Activer le son surround 5.1 ou 7.1 pour les systèmes home cinéma</string>
|
||||||
<string name="category_input_settings">Paramètres d\'entrée</string>
|
<string name="category_input_settings">Paramètres d\'entrée</string>
|
||||||
<string name="title_checkbox_touchscreen_trackpad">Utilisez l\'écran tactile comme trackpad</string>
|
<string name="title_checkbox_touchscreen_trackpad">Utiliser l\'écran tactile comme trackpad</string>
|
||||||
<string name="summary_checkbox_touchscreen_trackpad">S\'il est activé, l\'écran tactile agit comme un trackpad. S\'il est désactivé, l\'écran tactile contrôle directement le curseur de la souris.</string>
|
<string name="summary_checkbox_touchscreen_trackpad">Si activé, l\'écran tactile agit comme un trackpad. Si désactivé, l\'écran tactile contrôle directement le curseur de la souris.</string>
|
||||||
<string name="title_checkbox_multi_controller">Forcer la présence d\'un contrôleur</string>
|
<string name="title_checkbox_multi_controller">Forcer la présence d\'une manette</string>
|
||||||
<string name="summary_checkbox_multi_controller">Lorsqu\'elle n\'est pas cochée, tous les contrôleurs sont regroupés</string>
|
<string name="summary_checkbox_multi_controller">Décocher cette option force une manette à toujours être présente</string>
|
||||||
<string name="title_checkbox_vibrate_fallback">Emuler support vibration de secours</string>
|
<string name="title_checkbox_vibrate_fallback">Émuler les vibrations de la manette avec l\'appareil</string>
|
||||||
<string name="summary_checkbox_vibrate_fallback">Emuler des tremblements si votre manette ne le prend pas en charge</string>
|
<string name="summary_checkbox_vibrate_fallback">Fait vibrer votre appareil pour émuler les vibrations de la manette si elle ne le supporte pas</string>
|
||||||
<string name="title_seekbar_deadzone">Régler la zone morte du stick analogique</string>
|
<string name="title_seekbar_deadzone">Régler la zone morte du stick analogique</string>
|
||||||
<string name="suffix_seekbar_deadzone">%</string>
|
<string name="suffix_seekbar_deadzone">%</string>
|
||||||
<string name="title_checkbox_xb1_driver">Pilote de contrôleur Xbox 360/One</string>
|
<string name="title_checkbox_xb1_driver">Pilote USB pour manette Xbox 360/One</string>
|
||||||
<string name="summary_checkbox_xb1_driver">Active un pilote USB intégré pour les périphériques sans prise en charge du contrôleur Xbox natif</string>
|
<string name="summary_checkbox_xb1_driver">Active un pilote USB intégré pour les appareils qui ne prennent pas nativement en charge les manettes Xbox</string>
|
||||||
<string name="title_checkbox_usb_bind_all">Ignorer le support du contrôleur Android</string>
|
<string name="title_checkbox_usb_bind_all">Remplacer le support natif des manettes Xbox</string>
|
||||||
<string name="summary_checkbox_usb_bind_all">Force le pilote USB de Moonlight à prendre en charge tous les gamepads Xbox pris en charge</string>
|
<string name="summary_checkbox_usb_bind_all">Utilise le pilote USB de Moonlight pour toutes les manettes prises en charge, même si l\'appareil supporte nativement celles-ci</string>
|
||||||
<string name="title_checkbox_mouse_emulation">Emulation de la souris via le gamepad</string>
|
<string name="title_checkbox_mouse_emulation">Émuler la souris avec la manette</string>
|
||||||
<string name="summary_checkbox_mouse_emulation">Appuyez longuement sur le bouton Start pour faire basculer la manette en mode souris</string>
|
<string name="summary_checkbox_mouse_emulation">Appuyez longuement sur le bouton Start pour faire basculer la manette en mode souris</string>
|
||||||
<string name="title_checkbox_mouse_nav_buttons">Activer les boutons de la souris arrière et avant</string>
|
<string name="title_checkbox_mouse_nav_buttons">Activer les boutons de la souris arrière et avant</string>
|
||||||
<string name="summary_checkbox_mouse_nav_buttons">L\' activation de cette option peut casser le clic droit sur certains appareils bogués</string>
|
<string name="summary_checkbox_mouse_nav_buttons">L\' activation de cette option peut casser le clic droit sur certains appareils bogués</string>
|
||||||
<string name="title_checkbox_flip_face_buttons">Boutons de face inversé</string>
|
<string name="title_checkbox_flip_face_buttons">Inverser les boutons en façade</string>
|
||||||
<string name="summary_checkbox_flip_face_buttons">Commute les boutons de face A/B et X/Y pour les manettes de jeu et les commandes à l\'écran</string>
|
<string name="summary_checkbox_flip_face_buttons">Commute les boutons de face A/B et X/Y pour les manettes et les commandes à l\'écran</string>
|
||||||
<string name="category_on_screen_controls_settings">Paramètres des contrôles à l\'écran</string>
|
<string name="category_on_screen_controls_settings">Paramètres des commandes à l\'écran</string>
|
||||||
<string name="title_checkbox_show_onscreen_controls">Afficher les commandes à l\'écran</string>
|
<string name="title_checkbox_show_onscreen_controls">Afficher les commandes à l\'écran</string>
|
||||||
<string name="summary_checkbox_show_onscreen_controls">Afficher la superposition du contrôleur virtuel sur l\'écran tactile</string>
|
<string name="summary_checkbox_show_onscreen_controls">Affiche une manette virtuelle sur l\'écran tacile</string>
|
||||||
<string name="title_checkbox_vibrate_osc">Activer les vibrations</string>
|
<string name="title_checkbox_vibrate_osc">Activer les vibrations</string>
|
||||||
<string name="summary_checkbox_vibrate_osc">Emuler des tremblements des commandes à l\'écran</string>
|
<string name="summary_checkbox_vibrate_osc">Fait vibrer votre appareil pour émuler les vibrations des commandes à l\'écran</string>
|
||||||
<string name="title_only_l3r3">Montre seulement L3 et R3</string>
|
<string name="title_only_l3r3">Montrer seulement L3 et R3</string>
|
||||||
<string name="summary_only_l3r3">Cacher tout sauf L3 et R3</string>
|
<string name="summary_only_l3r3">Cacher tous les boutons sauf L3 et R3</string>
|
||||||
<string name="title_reset_osc">Effacer la disposition des commandes à l\'écran sauvegardée</string>
|
<string name="title_reset_osc">Réinitialiser la disposition des commandes</string>
|
||||||
<string name="summary_reset_osc">Rétablit la taille et la position par défaut de tous les contrôles à l\'écran</string>
|
<string name="summary_reset_osc">Rétablit la taille et la position par défaut de tous les contrôles à l\'écran</string>
|
||||||
<string name="dialog_title_reset_osc">Réinitialiser la mise en page</string>
|
<string name="dialog_title_reset_osc">Réinitialiser la disposition</string>
|
||||||
<string name="dialog_text_reset_osc">Êtes-vous sûr de vouloir supprimer la disposition des commandes à l\'écran que vous avez sauvegardée \?</string>
|
<string name="dialog_text_reset_osc">Êtes-vous sûr de vouloir supprimer votre disposition de commandes à l\'écran ?</string>
|
||||||
<string name="toast_reset_osc_success">Les contrôles à l\'écran sont réinitialisés</string>
|
<string name="toast_reset_osc_success">Les contrôles à l\'écran ont été réinitialisés</string>
|
||||||
<string name="title_osc_opacity">Modifier l\'opacité des contrôles à l\'écran</string>
|
<string name="title_osc_opacity">Modifier l\'opacité des contrôles à l\'écran</string>
|
||||||
<string name="summary_osc_opacity">Rendre les contrôles à l\'écran plus/moins transparents</string>
|
<string name="summary_osc_opacity">Permet de rendre les contrôles à l\'écran plus ou moins transparents</string>
|
||||||
<string name="dialog_title_osc_opacity">Modifiez l\'opacité</string>
|
<string name="dialog_title_osc_opacity">Modifier l\'opacité</string>
|
||||||
<string name="suffix_osc_opacity">%</string>
|
<string name="suffix_osc_opacity">%</string>
|
||||||
<string name="category_ui_settings">Paramètres de l\'interface utilisateur</string>
|
<string name="category_ui_settings">Paramètres de l\'interface utilisateur</string>
|
||||||
<string name="title_language_list">Langue</string>
|
<string name="title_language_list">Langue</string>
|
||||||
<string name="summary_language_list">Langue à utiliser pour Moonlight</string>
|
<string name="summary_language_list">Langue à utiliser pour Moonlight</string>
|
||||||
<string name="title_checkbox_small_icon_mode">Utiliser des petites icônes</string>
|
<string name="title_checkbox_small_icon_mode">Utiliser des petites icônes</string>
|
||||||
<string name="summary_checkbox_small_icon_mode">Utilisez les petites icônes dans les éléments de la grille pour permettre plus d\'éléments à l\'écran</string>
|
<string name="summary_checkbox_small_icon_mode">Des icônes plus petites permettent d\'afficher plus d\'applications en même temps</string>
|
||||||
<string name="category_host_settings">Paramètres de l\'hôte</string>
|
<string name="category_host_settings">Paramètres de l\'hôte</string>
|
||||||
<string name="title_checkbox_enable_sops">Optimiser les paramètres de jeu</string>
|
<string name="title_checkbox_enable_sops">Optimiser les paramètres du jeu</string>
|
||||||
<string name="summary_checkbox_enable_sops">Autoriser GFE à modifier les paramètres de jeu pour une diffusion optimale</string>
|
<string name="summary_checkbox_enable_sops">Autoriser GFE à modifier les paramètres du jeu pour un streaming optimal</string>
|
||||||
<string name="title_checkbox_host_audio">Jouer l\'audio sur le PC</string>
|
<string name="title_checkbox_host_audio">Jouer l\'audio sur le PC</string>
|
||||||
<string name="summary_checkbox_host_audio">Lire l\'audio de l\'ordinateur et de ce périphérique</string>
|
<string name="summary_checkbox_host_audio">Lire l\'audio sur l\'ordinateur et sur cet appareil</string>
|
||||||
<string name="category_advanced_settings">Réglages avancés</string>
|
<string name="category_advanced_settings">Réglages avancés</string>
|
||||||
<string name="title_unlock_fps">Débloquez toutes les fréquences d\'images possibles</string>
|
<string name="title_unlock_fps">Débloquer toutes les fréquences d\'images possibles</string>
|
||||||
<string name="summary_unlock_fps">Le streaming à 90 ou 120 FPS peut réduire la latence sur les appareils haut de gamme, mais peut entraîner un décalage ou une instabilité sur les appareils qui ne peuvent pas le prendre en charge</string>
|
<string name="summary_unlock_fps">Le streaming à 90 ou 120 FPS peut réduire la latence sur les appareils haut de gamme, mais peut entraîner un décalage ou une instabilité sur les appareils qui ne le supporte pas</string>
|
||||||
<string name="summary_checkbox_disable_warnings">Désactiver les messages d\'avertissement de connexion à l\'écran pendant la diffusion</string>
|
<string name="summary_checkbox_disable_warnings">Désactive les messages d\'avertissement sur la connexion pendant le stream</string>
|
||||||
<string name="title_disable_frame_drop">Ne jamais laisser tomber les frames</string>
|
<string name="title_disable_frame_drop">Ne jamais perdre d\'images</string>
|
||||||
<string name="summary_disable_frame_drop">Peut réduire les micro-saccades sur certains appareils, mais peut augmenter la latence</string>
|
<string name="summary_disable_frame_drop">Peut réduire les micro-saccades sur certains appareils, mais peut augmenter la latence</string>
|
||||||
<string name="title_video_format">Modifier les paramètres de codec</string>
|
<string name="title_video_format">Modifier les paramètres de codec</string>
|
||||||
<string name="summary_video_format">Les nouveaux codecs peuvent réduire la bande passante vidéo requise si votre appareil les prend en charge. Les codecs séléctionnés peuvent être ignorés si ils ne sont pas prises en charge par le logiciel hôte ou le GPU.</string>
|
<string name="summary_video_format">Les nouveaux codecs peuvent réduire la bande passante vidéo requise si votre appareil les prend en charge. Les codecs séléctionnés peuvent être ignorés si ils ne sont pas prises en charge par le logiciel hôte ou le GPU.</string>
|
||||||
<string name="title_enable_hdr">Activer le HDR (expérimental)</string>
|
<string name="title_enable_hdr">Activer le HDR (expérimental)</string>
|
||||||
<string name="summary_enable_hdr">Diffuser du HDR lorsque le jeu et le processeur graphique du PC le prennent en charge. Le HDR nécessite un GPU pouvant encoder en HEVC Main 10.</string>
|
<string name="summary_enable_hdr">Streamer en HDR lorsque le jeu et le GPU du PC le prennent en charge. Le HDR nécessite un GPU pouvant encoder en HEVC Main 10.</string>
|
||||||
<string name="title_enable_perf_overlay">Activer la superposition de performance</string>
|
<string name="title_enable_perf_overlay">Afficher les statistiques de peformance lors du stream</string>
|
||||||
<string name="summary_enable_perf_overlay">Afficher une superposition à l\'écran avec des informations de performance en temps réel pendant la lecture en continu</string>
|
<string name="summary_enable_perf_overlay">Affiche des informations sur les performances du stream en temps réel pendant le stream</string>
|
||||||
<string name="title_enable_post_stream_toast">Afficher le message de latence après la diffusion en continu</string>
|
<string name="title_enable_post_stream_toast">Afficher la latence moyenne après un stream</string>
|
||||||
<string name="summary_enable_post_stream_toast">Afficher un message d’informations de latence après la fin du flux</string>
|
<string name="summary_enable_post_stream_toast">Affiche un message d’information sur la latence après la fin du stream</string>
|
||||||
<string name="no_video_received_error">Aucune vidéo reçue depuis l\'hôte.</string>
|
<string name="no_video_received_error">Aucune vidéo reçue de l\'hôte.</string>
|
||||||
<string name="video_decoder_init_failed">Le décodeur vidéo n\'a pas pu démarrer. Vérifiez que votre appareil supporte la résolution ou la fréquence d\'images choisie.</string>
|
<string name="video_decoder_init_failed">Le décodeur vidéo n\'a pas pu démarrer. Vérifiez que votre appareil supporte la résolution ou la fréquence d\'images choisie.</string>
|
||||||
<string name="pcview_menu_test_network">Tester la connection réseau</string>
|
<string name="pcview_menu_test_network">Tester la connection réseau</string>
|
||||||
<string name="pcview_menu_header_unknown">Actualisation</string>
|
<string name="pcview_menu_header_unknown">Actualisation</string>
|
||||||
@ -209,13 +207,13 @@
|
|||||||
\nNous ne sommes pas responsables des problèmes résultant de la création d\'une résolution personnalisée sur votre PC.
|
\nNous ne sommes pas responsables des problèmes résultant de la création d\'une résolution personnalisée sur votre PC.
|
||||||
\n
|
\n
|
||||||
\nIl se peut que votre moniteur ne prenne pas en charge la configuration d\'affichage requise. Si c\'est le cas, vous pouvez essayer de configurer un moniteur virtuel. Enfin, si votre appareil ou votre PC hôte ne prend pas en charge le streaming à une résolution ou à un taux de rafraîchissement spécifique, vous ne pourrez pas y faire grand chose malheureusement.</string>
|
\nIl se peut que votre moniteur ne prenne pas en charge la configuration d\'affichage requise. Si c\'est le cas, vous pouvez essayer de configurer un moniteur virtuel. Enfin, si votre appareil ou votre PC hôte ne prend pas en charge le streaming à une résolution ou à un taux de rafraîchissement spécifique, vous ne pourrez pas y faire grand chose malheureusement.</string>
|
||||||
<string name="title_native_res_dialog">Avertissement résolution native</string>
|
<string name="title_native_res_dialog">Avertissement sur la résolution native</string>
|
||||||
<string name="applist_menu_hide_app">Cacher l\'application</string>
|
<string name="applist_menu_hide_app">Cacher l\'application</string>
|
||||||
<string name="check_ports_msg">Vérifiez vos règles de pare-feu pour les ports suivants :</string>
|
<string name="check_ports_msg">Vérifiez vos règles de pare-feu pour les ports suivants :</string>
|
||||||
<string name="early_termination_error">Quelque chose s\'est mal passé sur votre PC hôte en démarrant le flux.
|
<string name="early_termination_error">Quelque chose s\'est mal passé sur votre PC hôte en démarrant le stream.
|
||||||
\n
|
\n
|
||||||
\nVérifiez qu\'aucune application utilisant un DRM n\'est ouverte sur votre PC hôte. Vous pouvez aussi essayer de redémarrer votre PC hôte.</string>
|
\nVérifiez qu\'aucune application utilisant un DRM n\'est ouverte sur votre PC hôte. Vous pouvez aussi essayer de redémarrer votre PC hôte.</string>
|
||||||
<string name="no_frame_received_error">Votre connexion ne fonctionne pas bien. Baissez votre paramètres de débit ou utilisez une connexion plus rapide.</string>
|
<string name="no_frame_received_error">Votre connexion réseau ne fonctionne pas bien. Baissez votre débit ou utilisez une connexion plus rapide.</string>
|
||||||
<string name="resolution_prefix_native_fullscreen">Plein-écran natif</string>
|
<string name="resolution_prefix_native_fullscreen">Plein-écran natif</string>
|
||||||
<string name="perf_overlay_netlatency">Latence réseau moyenne : %1$d ms (variance : %2$d ms)</string>
|
<string name="perf_overlay_netlatency">Latence réseau moyenne : %1$d ms (variance : %2$d ms)</string>
|
||||||
<string name="perf_overlay_streamdetails">Stream vidéo : %1$s %2$.2f FPS</string>
|
<string name="perf_overlay_streamdetails">Stream vidéo : %1$s %2$.2f FPS</string>
|
||||||
@ -228,7 +226,7 @@
|
|||||||
<string name="audioconf_51surround">Son surround 5.1</string>
|
<string name="audioconf_51surround">Son surround 5.1</string>
|
||||||
<string name="audioconf_71surround">Son surround 7.1</string>
|
<string name="audioconf_71surround">Son surround 7.1</string>
|
||||||
<string name="videoformat_auto">Automatique (recommandé)</string>
|
<string name="videoformat_auto">Automatique (recommandé)</string>
|
||||||
<string name="videoformat_hevcalways">Préférez le HEVC</string>
|
<string name="videoformat_hevcalways">Préférer HEVC</string>
|
||||||
<string name="title_frame_pacing">Frame-pacing vidéo</string>
|
<string name="title_frame_pacing">Frame-pacing vidéo</string>
|
||||||
<string name="summary_frame_pacing">Spécifiez comment équilibrer latence et fluidité de la vidéo</string>
|
<string name="summary_frame_pacing">Spécifiez comment équilibrer latence et fluidité de la vidéo</string>
|
||||||
<string name="pacing_latency">Préférer une latence plus faible</string>
|
<string name="pacing_latency">Préférer une latence plus faible</string>
|
||||||
@ -245,12 +243,12 @@
|
|||||||
<string name="title_troubleshooting">Guide de dépannage</string>
|
<string name="title_troubleshooting">Guide de dépannage</string>
|
||||||
<string name="title_privacy_policy">Politique de confidentialité</string>
|
<string name="title_privacy_policy">Politique de confidentialité</string>
|
||||||
<string name="summary_privacy_policy">Voir la politique de confidentialité de Moonlight</string>
|
<string name="summary_privacy_policy">Voir la politique de confidentialité de Moonlight</string>
|
||||||
<string name="summary_setup_guide">Afficher les instructions sur la façon de configurer votre PC de jeu pour le streaming</string>
|
<string name="summary_setup_guide">Voir les instructions sur la façon de configurer votre PC de jeu pour le streaming</string>
|
||||||
<string name="summary_troubleshooting">Afficher des conseils pour diagnostiquer et résoudre les problèmes de streaming courants</string>
|
<string name="summary_troubleshooting">Voir des conseils pour diagnostiquer et résoudre les problèmes de streaming courants</string>
|
||||||
<string name="pacing_balanced_alt">Équilibré avec limite FPS</string>
|
<string name="pacing_balanced_alt">Équilibré avec limite FPS</string>
|
||||||
<string name="title_checkbox_absolute_mouse_mode">Mode souris pour bureau à distance</string>
|
<string name="title_checkbox_absolute_mouse_mode">Mode souris pour bureau à distance</string>
|
||||||
<string name="summary_seekbar_deadzone">Remarque : Certains jeux peuvent imposer une zone morte plus grande que celle que Moonlight est configuré pour utiliser.</string>
|
<string name="summary_seekbar_deadzone">Remarque : Certains jeux peuvent imposer une zone morte plus grande que celle que Moonlight est configuré pour utiliser.</string>
|
||||||
<string name="summary_checkbox_absolute_mouse_mode">Cela peut rendre l\'accélération de la souris plus naturelle pour l\'utilisation du bureau à distance, mais elle est incompatible avec de nombreux jeux.</string>
|
<string name="summary_checkbox_absolute_mouse_mode">Cela peut rendre l\'accélération de la souris plus naturelle pour l\'utilisation du bureau à distance, mais il est incompatible avec de nombreux jeux.</string>
|
||||||
<string name="resolution_prefix_native_landscape">(Paysage)</string>
|
<string name="resolution_prefix_native_landscape">(Paysage)</string>
|
||||||
<string name="resolution_prefix_native_portrait">(Portrait)</string>
|
<string name="resolution_prefix_native_portrait">(Portrait)</string>
|
||||||
<string name="title_checkbox_reduce_refresh_rate">Autoriser la réduction du taux de rafraîchissement</string>
|
<string name="title_checkbox_reduce_refresh_rate">Autoriser la réduction du taux de rafraîchissement</string>
|
||||||
@ -259,23 +257,32 @@
|
|||||||
<string name="title_checkbox_enable_audiofx">Activer le support de l\'égalisateur système</string>
|
<string name="title_checkbox_enable_audiofx">Activer le support de l\'égalisateur système</string>
|
||||||
<string name="frame_conversion_error">Le PC hôte a signalé une erreur d\'encodage fatale.
|
<string name="frame_conversion_error">Le PC hôte a signalé une erreur d\'encodage fatale.
|
||||||
\n
|
\n
|
||||||
\nEssayez de désactiver le mode HDR, de changer la résolution du flux ou la résolution de votre PC hôte.</string>
|
\nEssayez de désactiver le mode HDR, de changer la résolution du stream ou la résolution de votre PC hôte.</string>
|
||||||
<string name="title_full_range">Forcer la vidéo sur toute la gamme de couleurs (expérimental)</string>
|
<string name="title_full_range">Forcer la vidéo sur toute la gamme de couleurs (expérimental)</string>
|
||||||
<string name="summary_full_range">Ceci entraînera une perte de détails dans les zones claires et sombres si votre appareil n\'affiche pas correctement le contenu vidéo de la gamme complète de couleurs.</string>
|
<string name="summary_full_range">Cela causera une perte de détails dans les zones claires et sombres si votre appareil n\'affiche pas correctement la vidéo avec une gamme de couleurs complète.</string>
|
||||||
<string name="pcview_menu_eol">NVIDIA GameStream : fin de service</string>
|
<string name="pcview_menu_eol">NVIDIA GameStream : fin de service</string>
|
||||||
<string name="pair_pairing_help">Si votre PC hôte utilise Sunshine, accédez à l\'interface web de Sunshine pour saisir le code PIN.</string>
|
<string name="pair_pairing_help">Si votre PC hôte utilise Sunshine, accédez à l\'interface web de Sunshine pour saisir le code PIN.</string>
|
||||||
<string name="category_gamepad_settings">Paramètres manette</string>
|
<string name="category_gamepad_settings">Paramètres manette</string>
|
||||||
<string name="perf_overlay_hostprocessinglatency">Latence de traitement de l\'hôte min/max/moyenne : %1$.1f/%2$.1f/%3$.1f ms</string>
|
<string name="perf_overlay_hostprocessinglatency">Latence de traitement de l\'hôte min/max/moyenne : %1$.1f/%2$.1f/%3$.1f ms</string>
|
||||||
<string name="fps_suffix_fps">FPS</string>
|
<string name="fps_suffix_fps">FPS</string>
|
||||||
<string name="title_native_fps_dialog">Avertissement FPS natif</string>
|
<string name="title_native_fps_dialog">Avertissement sur le FPS natif</string>
|
||||||
<string name="title_checkbox_gamepad_motion_sensors">Autoriser l\'utilisation des capteurs de mouvement de la manette</string>
|
<string name="title_checkbox_gamepad_motion_sensors">Autoriser l\'utilisation des capteurs de mouvement de la manette</string>
|
||||||
<string name="videoformat_av1always">Préférer AV1 (expérimental)</string>
|
<string name="videoformat_av1always">Préférer AV1 (expérimental)</string>
|
||||||
<string name="videoformat_h264always">Préférer H.264</string>
|
<string name="videoformat_h264always">Préférer H.264</string>
|
||||||
<string name="title_checkbox_gamepad_touchpad_as_mouse">Toujours controller la souris avec le pavé tactile</string>
|
<string name="title_checkbox_gamepad_touchpad_as_mouse">Toujours controller la souris avec le pavé tactile</string>
|
||||||
<string name="summary_checkbox_gamepad_touchpad_as_mouse">Force le pavé tactile de la manette à contrôler la souris de l\'hôte, même quand l\'émulation d\'une manette par le pavé tactile est activée.</string>
|
<string name="summary_checkbox_gamepad_touchpad_as_mouse">Force le pavé tactile de la manette à contrôler la souris de l\'hôte, même quand une manette avec pavé tactile est émulée.</string>
|
||||||
<string name="summary_checkbox_gamepad_motion_sensors">Permet aux hôtes pris en charge de demander des données de capteur de mouvement lors de l\'émulation d\'une manette avec des capteurs de mouvement. Désactiver ce paramètre peut réduire légèrement l\'utilisation de l\'alimentation et du réseau si les capteurs de mouvement ne sont pas utilisés en jeu.</string>
|
<string name="summary_checkbox_gamepad_motion_sensors">Permet aux hôtes pris en charge de demander les données du capteur de mouvement lors de l\'émulation d\'une manette compatible. Désactiver ce paramètre peut réduire légèrement l\'utilisation de la batterie et du réseau si les capteurs de mouvement ne sont pas utilisés en jeu.</string>
|
||||||
<string name="toast_controller_type_changed">Le type de manette peut être modifié en raison de l\'émulation du capteur de mouvement</string>
|
<string name="toast_controller_type_changed">Le type de manette peut être différent dû à l\'émulation du capteur de mouvement</string>
|
||||||
<string name="summary_checkbox_gamepad_motion_fallback">Utilise les capteurs de mouvement de votre appareil si la manette connéctée n\'en a pas, ou qu\'ils ne sont pas pris en charge par votre version d\'Android.
|
<string name="summary_checkbox_gamepad_motion_fallback">Utilise les capteurs de mouvement de votre appareil si la manette connéctée n\'en a pas, ou qu\'ils ne sont pas pris en charge par votre version d\'Android.
|
||||||
\nRemarque : l\'activation de cette option peut faire apparaître votre manette de jeu comme une manette PlayStation du côté hôte.</string>
|
\nRemarque : activer cette option peut faire apparaître votre manette côté hôte comme une manette PlayStation.</string>
|
||||||
<string name="title_checkbox_gamepad_motion_fallback">Émuler les capteurs de mouvement de la manette</string>
|
<string name="title_checkbox_gamepad_motion_fallback">Émuler les capteurs de mouvement de la manette</string>
|
||||||
|
<string name="title_analog_scrolling">Utiliser un stick analogique pour faire défiler</string>
|
||||||
|
<string name="summary_analog_scrolling">Séléctionner un stick analogique à utiliser pour faire défiler lors de l\'émulation de la souris</string>
|
||||||
|
<string name="analogscroll_none">Aucun (les deux sticks déplacent la souris)</string>
|
||||||
|
<string name="analogscroll_right">Stick analogique droit</string>
|
||||||
|
<string name="analogscroll_left">Stick analogique gauche</string>
|
||||||
|
<string name="error_code_prefix">Code d\'erreur :</string>
|
||||||
|
<string name="title_seekbar_vibrate_fallback_strength">Ajuster l\'intensité de la vibration émulée</string>
|
||||||
|
<string name="summary_seekbar_vibrate_fallback_strength">Amplifie ou réduit l\'intensité de la vibration sur votre appareil</string>
|
||||||
|
<string name="suffix_seekbar_vibrate_fallback_strength">%</string>
|
||||||
</resources>
|
</resources>
|
@ -23,7 +23,7 @@
|
|||||||
<string name="pair_already_in_progress">Accoppiamento già in corso</string>
|
<string name="pair_already_in_progress">Accoppiamento già in corso</string>
|
||||||
<!-- WOL messages -->
|
<!-- WOL messages -->
|
||||||
<string name="wol_pc_online">PC già avviato</string>
|
<string name="wol_pc_online">PC già avviato</string>
|
||||||
<string name="wol_no_mac">Impossibile risvegliare il PC perché GFE non ha inviato nessun indirizzo MAC</string>
|
<string name="wol_no_mac">Impossibile risvegliare il PC perché non è stato salvato nessun indirizzo MAC</string>
|
||||||
<string name="wol_waking_pc">Risveglio PC…</string>
|
<string name="wol_waking_pc">Risveglio PC…</string>
|
||||||
<string name="wol_waking_msg">Il PC potrebbe impiegare qualche secondo per risvegliarsi.
|
<string name="wol_waking_msg">Il PC potrebbe impiegare qualche secondo per risvegliarsi.
|
||||||
Se non succede niente, assicurati che l\'opzione Wake-On-LAN sia configurata correttamente.
|
Se non succede niente, assicurati che l\'opzione Wake-On-LAN sia configurata correttamente.
|
||||||
@ -33,7 +33,7 @@
|
|||||||
<string name="unpairing">Disaccoppiamento…</string>
|
<string name="unpairing">Disaccoppiamento…</string>
|
||||||
<string name="unpair_success">Disaccoppiato con successo</string>
|
<string name="unpair_success">Disaccoppiato con successo</string>
|
||||||
<string name="unpair_fail">Disaccoppiamento fallito</string>
|
<string name="unpair_fail">Disaccoppiamento fallito</string>
|
||||||
<string name="unpair_error">PC non accoppiato</string>
|
<string name="unpair_error">Il dispositivo non è stato accoppiato</string>
|
||||||
<!-- Errors -->
|
<!-- Errors -->
|
||||||
<string name="error_pc_offline">PC offline</string>
|
<string name="error_pc_offline">PC offline</string>
|
||||||
<string name="error_manager_not_running">Il servizio ComputerManager non è avviato. Attendi qualche secondo o riavvia l\'applicazione.</string>
|
<string name="error_manager_not_running">Il servizio ComputerManager non è avviato. Attendi qualche secondo o riavvia l\'applicazione.</string>
|
||||||
@ -60,8 +60,9 @@
|
|||||||
<string name="conn_terminated_msg">La connessione è stata interrotta</string>
|
<string name="conn_terminated_msg">La connessione è stata interrotta</string>
|
||||||
<!-- General strings -->
|
<!-- General strings -->
|
||||||
<string name="ip_hint">Indirizzo IP del PC</string>
|
<string name="ip_hint">Indirizzo IP del PC</string>
|
||||||
<string name="searching_pc">Ricerca di PC con GameStream avviato…\n\n
|
<string name="searching_pc">Ricerca di PC nella rete locale…
|
||||||
Assicurati che GameStream sia abilitato nelle impostazioni SHIELD di GeForce Experience.</string>
|
\n
|
||||||
|
\n Assicurati che Sunshine sia avviato o che GameStream sia abilitato nelle impostazioni SHIELD di GeForce Experience.</string>
|
||||||
<string name="yes">Sì</string>
|
<string name="yes">Sì</string>
|
||||||
<string name="no">No</string>
|
<string name="no">No</string>
|
||||||
<string name="lost_connection">Connessione con il PC persa</string>
|
<string name="lost_connection">Connessione con il PC persa</string>
|
||||||
@ -90,7 +91,7 @@
|
|||||||
<string name="addpc_wrong_sitelocal">Quell\'indirizzo non sembra corretto. È necessario utilizzare l\'indirizzo IP pubblico del router per lo streaming su Internet.</string>
|
<string name="addpc_wrong_sitelocal">Quell\'indirizzo non sembra corretto. È necessario utilizzare l\'indirizzo IP pubblico del router per lo streaming su Internet.</string>
|
||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="category_basic_settings">Impostazioni generali</string>
|
<string name="category_basic_settings">Impostazioni generali</string>
|
||||||
<string name="title_resolution_list">Risoluzione e FPS</string>
|
<string name="title_resolution_list">Risoluzione video</string>
|
||||||
<string name="summary_resolution_list">Aumentare per migliorare la nitidezza dell\'immagine. Diminuire per aumentare le prestazioni su dispositivi di fascia più bassa e reti più lente.</string>
|
<string name="summary_resolution_list">Aumentare per migliorare la nitidezza dell\'immagine. Diminuire per aumentare le prestazioni su dispositivi di fascia più bassa e reti più lente.</string>
|
||||||
<string name="title_seekbar_bitrate">Velocità di trasmissione video</string>
|
<string name="title_seekbar_bitrate">Velocità di trasmissione video</string>
|
||||||
<string name="summary_seekbar_bitrate">Aumentare per migliorare la qualità dell\'immagine. Diminuire per aumentare le prestazioni su reti più lente.</string>
|
<string name="summary_seekbar_bitrate">Aumentare per migliorare la qualità dell\'immagine. Diminuire per aumentare le prestazioni su reti più lente.</string>
|
||||||
@ -133,10 +134,10 @@
|
|||||||
<string name="category_advanced_settings">Impostazioni avanzate</string>
|
<string name="category_advanced_settings">Impostazioni avanzate</string>
|
||||||
<string name="title_disable_frame_drop">Non saltare i fotogrammi</string>
|
<string name="title_disable_frame_drop">Non saltare i fotogrammi</string>
|
||||||
<string name="summary_disable_frame_drop">Potrebbe ridurre il micro-stuttering su alcuni dispositivi, ma può aumentare la latenza</string>
|
<string name="summary_disable_frame_drop">Potrebbe ridurre il micro-stuttering su alcuni dispositivi, ma può aumentare la latenza</string>
|
||||||
<string name="title_video_format">Modifica impostazioni HEVC</string>
|
<string name="title_video_format">Modifica impostazioni del codec</string>
|
||||||
<string name="summary_video_format">HEVC riduce i requisiti di larghezza di banda video ma richiede un dispositivo molto recente</string>
|
<string name="summary_video_format">I nuovi codec possono ridurre i requisiti di larghezza di banda video se il tuo dispositivo li supporta. La scelta del codec può essere ignorata se non è supportato dal software dell\'host o dalla GPU.</string>
|
||||||
<string name="title_enable_hdr">Abilita HDR (sperimentale)</string>
|
<string name="title_enable_hdr">Abilita HDR (sperimentale)</string>
|
||||||
<string name="summary_enable_hdr">Utilizza l\'HDR quando il gioco e la scheda video del PC lo supportano. L\'HDR richiede una scheda video serie GTX 1000 o sucessive.</string>
|
<string name="summary_enable_hdr">Utilizza l\'HDR quando il gioco e la scheda video del PC lo supportano. L\'HDR richiede una scheda video col supporto dell\'encoding HEVC Main 10.</string>
|
||||||
<string name="suffix_osc_opacity">%</string>
|
<string name="suffix_osc_opacity">%</string>
|
||||||
<string name="pcview_menu_header_online">Online</string>
|
<string name="pcview_menu_header_online">Online</string>
|
||||||
<string name="scut_pc_not_found">PC non trovato</string>
|
<string name="scut_pc_not_found">PC non trovato</string>
|
||||||
@ -161,7 +162,7 @@
|
|||||||
<string name="perf_overlay_dectime">Tempo medio di decodifica: %1$.2f ms</string>
|
<string name="perf_overlay_dectime">Tempo medio di decodifica: %1$.2f ms</string>
|
||||||
<string name="perf_overlay_streamdetails">Flusso video: %1$s %2$.2f FPS</string>
|
<string name="perf_overlay_streamdetails">Flusso video: %1$s %2$.2f FPS</string>
|
||||||
<string name="nettest_title_waiting">Prova della Connessione di Rete</string>
|
<string name="nettest_title_waiting">Prova della Connessione di Rete</string>
|
||||||
<string name="nettest_text_waiting">Moonlight sta testando la tua connessione di rete per controllare se NVIDIA GameStream sia bloccato.
|
<string name="nettest_text_waiting">Moonlight sta testando la tua connessione di rete per controllare se ogni porta richiesta sia bloccata.
|
||||||
\n
|
\n
|
||||||
\nPotrebbero volerci alcuni secondi…</string>
|
\nPotrebbero volerci alcuni secondi…</string>
|
||||||
<string name="nettest_title_done">Test della Rete Completato</string>
|
<string name="nettest_title_done">Test della Rete Completato</string>
|
||||||
@ -226,18 +227,16 @@
|
|||||||
<string name="no_frame_received_error">La tua connessione di rete non sta funzionando bene. Riduci il bitrate video o prova ad usare una connessione più veloce.</string>
|
<string name="no_frame_received_error">La tua connessione di rete non sta funzionando bene. Riduci il bitrate video o prova ad usare una connessione più veloce.</string>
|
||||||
<string name="early_termination_error">Qualcosa è andato storto sul PC sorgente mentre la trasmissione veniva avviata.
|
<string name="early_termination_error">Qualcosa è andato storto sul PC sorgente mentre la trasmissione veniva avviata.
|
||||||
\n
|
\n
|
||||||
\nAssicurati di non avere nessun contenuto protetto da DRM aperto sul PC sorgente. Puoi anche provare a spengere e riaccendere il PC sorgente.
|
\nAssicurati di non avere nessun contenuto protetto da DRM aperto sul PC sorgente. Puoi anche provare a spengere e riaccendere il PC sorgente.</string>
|
||||||
\n
|
|
||||||
\nSe il problema persiste, prova a installare di nuovo i driver della scheda video e GeForce Experience.</string>
|
|
||||||
<string name="summary_unlock_fps">Trasmettere a 90 o 120 FPS potrebbe ridurre il ritardo su dispositivi di fascia alta, ma può provocare ritardi i instabilità sui dispositivi che non lo supportano</string>
|
<string name="summary_unlock_fps">Trasmettere a 90 o 120 FPS potrebbe ridurre il ritardo su dispositivi di fascia alta, ma può provocare ritardi i instabilità sui dispositivi che non lo supportano</string>
|
||||||
<string name="summary_enable_post_stream_toast">Molstra un messaggio con informazioni sulla latenza dopo che la trasmissione è conclusa</string>
|
<string name="summary_enable_post_stream_toast">Molstra un messaggio con informazioni sulla latenza dopo che la trasmissione è conclusa</string>
|
||||||
<string name="text_native_res_dialog">Le impostazioni di risoluzione nativa non sono ufficialmente supportate da GeForce Experience, quindi non cambierà automaticamente la risoluzione del monitor del computer sorgente. Dovrai cambiarla manualmente all\'interno del gioco.
|
<string name="text_native_res_dialog">Le impostazioni di risoluzione nativa e/o di FPS possono non essere supportate dal server per lo streaming. Dovrai aggiungerle manualmente all\'interno delle impostazioni del PC o del server.
|
||||||
\n
|
\n
|
||||||
\nSe scegli di create una risoluzione personalizzata nel Pannello di Controllo NVIDIA per copiare la risoluzione del tuo dispositivo, assicurati di aver letto e capito il messaggio di attenzione di NVIDIA a proposito dei possibili danni al monitor, all\'instabilità del PC e altri potenziali problemi.
|
\nSe scegli di create una risoluzione personalizzata nel Pannello di Controllo NVIDIA per copiare la risoluzione dello schermo, assicurati di aver letto e capito il messaggio di attenzione di NVIDIA a proposito dei possibili danni al monitor, all\'instabilità del PC e altri potenziali problemi.
|
||||||
\n
|
\n
|
||||||
\nNon saremo responsabili per qualsiasi problema risultante dalla creazione di una risoluzione personalizzata sul tuo PC.
|
\nNon saremo responsabili per qualsiasi problema risultante dalla creazione di una risoluzione personalizzata sul tuo PC.
|
||||||
\n
|
\n
|
||||||
\nInfine, il tuo dispositivo o PC sorgente potrebbero non supportare la trasmissione alla risoluzione nativa. Se ciò non funzionasse sul tuo dispositivo, sfortunatamente non ci sono altre soluzioni.</string>
|
\nPuò capitare che il tuo monitor potrebbe non supportare una risoluzione dello schermo richiesta. In questo caso, prova a impostare un monitor virtuale. Infine, se il tuo dispositivo o PC sorgente non supportano la trasmissione ad una specifica risoluzione dello schermo o della frequenza di aggiornamento, sfortunatamente non ci sono altre soluzioni.</string>
|
||||||
<string name="perf_overlay_incomingfps">Frame rate in ingresso dalla rete: %1$.2f FPS</string>
|
<string name="perf_overlay_incomingfps">Frame rate in ingresso dalla rete: %1$.2f FPS</string>
|
||||||
<string name="perf_overlay_renderingfps">Frame rate renderizzato: %1$.2f FPS</string>
|
<string name="perf_overlay_renderingfps">Frame rate renderizzato: %1$.2f FPS</string>
|
||||||
<string name="perf_overlay_netdrops">Frame scartati dalla tua connessione di rete: %1$.2f%%</string>
|
<string name="perf_overlay_netdrops">Frame scartati dalla tua connessione di rete: %1$.2f%%</string>
|
||||||
@ -264,4 +263,20 @@
|
|||||||
<string name="title_checkbox_reduce_refresh_rate">Consenti riduzione della frequenza di aggiornamento</string>
|
<string name="title_checkbox_reduce_refresh_rate">Consenti riduzione della frequenza di aggiornamento</string>
|
||||||
<string name="summary_full_range">Ciò causerà la perdita di dettagli in aree chiare e scure se il dispositivo non visualizza correttamente i contenuti video a gamma completa.</string>
|
<string name="summary_full_range">Ciò causerà la perdita di dettagli in aree chiare e scure se il dispositivo non visualizza correttamente i contenuti video a gamma completa.</string>
|
||||||
<string name="title_full_range">Forza video full range (sperimentale)</string>
|
<string name="title_full_range">Forza video full range (sperimentale)</string>
|
||||||
|
<string name="title_native_fps_dialog">Avviso FPS nativi</string>
|
||||||
|
<string name="videoformat_av1always">Preferisci AV1 (Sperimentale)</string>
|
||||||
|
<string name="pcview_menu_eol">Terminazione del servizio NVIDIA GameStream</string>
|
||||||
|
<string name="title_checkbox_gamepad_motion_sensors">Permetti l\'uso dei sensori giroscopici del gamepad</string>
|
||||||
|
<string name="summary_checkbox_gamepad_touchpad_as_mouse">Forza l\'input del touchpad del gamepad a controllare il mouse dell\'host, anche quando si sta emulando un gamepad col touchpad.</string>
|
||||||
|
<string name="toast_controller_type_changed">Il tipo di gamepad potrebbe cambiare se è attiva l\'emulazione dei sensori giroscopici</string>
|
||||||
|
<string name="summary_checkbox_gamepad_motion_sensors">Abilita per gli host supportati la trasmissione dei dati dai sensori giroscopici quando si simula un gamepad con sensori giroscopici. Disabilitandolo può ridurre il consumo di batteria e la rete richiesta per lo stream se i sensori giroscopici non vengono utilizzati nel gioco.</string>
|
||||||
|
<string name="summary_checkbox_gamepad_motion_fallback">Usa i sensori giroscopici integrati nel tuo dispositivo se il tuo gamepad non possiede i sensori giroscopici o non sono compatibili con la tua versione Android.
|
||||||
|
\nNota: Abilitare questa opzione farà apparire il tuo gamepad come un controller Playstation all\'host.</string>
|
||||||
|
<string name="videoformat_h264always">Preferisci H.264</string>
|
||||||
|
<string name="fps_suffix_fps">FPS</string>
|
||||||
|
<string name="category_gamepad_settings">Impostazioni del gamepad</string>
|
||||||
|
<string name="title_checkbox_gamepad_motion_fallback">Emula il supporto dei sensori giroscopici del gamepad</string>
|
||||||
|
<string name="pair_pairing_help">Se il tuo PC host sta eseguendo Sunshine, vai nella pagina web locale di Sunshine ed inserisci il PIN.</string>
|
||||||
|
<string name="title_checkbox_gamepad_touchpad_as_mouse">Controlla sempre il mouse col touchpad</string>
|
||||||
|
<string name="perf_overlay_hostprocessinglatency">Latenza di codifica da parte dell\'host min/max/average: %1$.1f/%2$.1f/%3$.1f ms</string>
|
||||||
</resources>
|
</resources>
|
@ -221,7 +221,6 @@
|
|||||||
<string name="perf_overlay_netdrops">Frames overgeslagen door uw netwerkverbinding: %1$.2f%%</string>
|
<string name="perf_overlay_netdrops">Frames overgeslagen door uw netwerkverbinding: %1$.2f%%</string>
|
||||||
<string name="perf_overlay_dectime">Gemiddelde decodeertijd: %1$.2f ms</string>
|
<string name="perf_overlay_dectime">Gemiddelde decodeertijd: %1$.2f ms</string>
|
||||||
<string name="applist_menu_tv_channel">Toevoegen aan Kanaal</string>
|
<string name="applist_menu_tv_channel">Toevoegen aan Kanaal</string>
|
||||||
|
|
||||||
<!-- Array strings -->
|
<!-- Array strings -->
|
||||||
<string name="videoformat_hevcalways">Gebruik HEVC altijd (mogelijkheid tot crashes)</string>
|
<string name="videoformat_hevcalways">Gebruik HEVC altijd (mogelijkheid tot crashes)</string>
|
||||||
</resources>
|
</resources>
|
@ -4,4 +4,272 @@
|
|||||||
<string name="scut_pc_not_found">PC nie znaleziony</string>
|
<string name="scut_pc_not_found">PC nie znaleziony</string>
|
||||||
<string name="pcview_menu_header_unknown">Odświeżanie</string>
|
<string name="pcview_menu_header_unknown">Odświeżanie</string>
|
||||||
<string name="scut_not_paired">PC niesparowany</string>
|
<string name="scut_not_paired">PC niesparowany</string>
|
||||||
|
<string name="check_ports_msg">Sprawdź zaporę sieciową i reguły przekierowania portów:</string>
|
||||||
|
<string name="conn_establishing_title">Nawiązywanie połączenia</string>
|
||||||
|
<string name="conn_establishing_msg">Uruchamianie połączenia</string>
|
||||||
|
<string name="title_details">Szczegóły</string>
|
||||||
|
<string name="searching_pc">Wyszukiwanie komputerów-hostów w sieci lokalnej...
|
||||||
|
\n
|
||||||
|
\nUpewnij się, że aplikacja Sunshine jest uruchomiona na komputerze-hoście lub funkcja GameStream jest włączona w ustawieniach aplikacji GeForce Experience SHIELD.</string>
|
||||||
|
<string name="yes">Tak</string>
|
||||||
|
<string name="title_audio_config_list">Konfiguracja dźwięku przestrzennego</string>
|
||||||
|
<string name="summary_audio_config_list">Włączenie dźwięku przestrzennego 5.1 lub 7.1 dla systemów kina domowego</string>
|
||||||
|
<string name="summary_checkbox_mouse_emulation">Długie naciśnięcie przycisku Start spowoduje przełączenie gamepada w tryb myszy</string>
|
||||||
|
<string name="error_code_prefix">Kod błędu:</string>
|
||||||
|
<string name="help">Pomoc</string>
|
||||||
|
<string name="delete_pc_msg">Czy na pewno chcesz usunąć ten komputer?</string>
|
||||||
|
<string name="slow_connection_msg">Wolne połączenie z komputerem
|
||||||
|
\nZmniejsz szybkość transmisji</string>
|
||||||
|
<string name="poor_connection_msg">Słabe połączenie z komputerem</string>
|
||||||
|
<string name="perf_overlay_streamdetails">Strumień wideo: %1$s %2$.2f FPS</string>
|
||||||
|
<string name="perf_overlay_decoder">Dekoder: %1$s</string>
|
||||||
|
<string name="perf_overlay_incomingfps">Przychodząca liczba klatek na sekundę z sieci: %1$.2f FPS</string>
|
||||||
|
<string name="applist_menu_quit_and_start">Zakończ bieżącą grę i uruchom</string>
|
||||||
|
<string name="applist_menu_scut">Utwórz skrót</string>
|
||||||
|
<string name="applist_menu_tv_channel">Dodaj do kanału</string>
|
||||||
|
<string name="applist_refresh_title">Lista aplikacji</string>
|
||||||
|
<string name="applist_refresh_error_msg">Nie udało się pobrać listy aplikacji</string>
|
||||||
|
<string name="applist_quit_app">Rezygnacja</string>
|
||||||
|
<string name="applist_quit_success">Zakończono z powodzeniem</string>
|
||||||
|
<string name="applist_quit_fail">Nie udało się zakończyć</string>
|
||||||
|
<string name="applist_quit_confirmation">Czy na pewno chcesz zamknąć uruchomioną aplikację? Wszystkie niezapisane dane zostaną utracone.</string>
|
||||||
|
<string name="applist_details_id">App ID:</string>
|
||||||
|
<string name="title_add_pc">Dodaj komputer ręcznie</string>
|
||||||
|
<string name="msg_add_pc">Podłączanie do komputera…</string>
|
||||||
|
<string name="addpc_unknown_host">Nie można określić adresu komputera. Upewnij się, że nie popełniłeś literówki w adresie.</string>
|
||||||
|
<string name="addpc_wrong_sitelocal">Ten adres nie wygląda prawidłowo. Do przesyłania strumieniowego przez Internet należy używać publicznego adresu IP routera.</string>
|
||||||
|
<string name="title_resolution_list">Rozdzielczość wideo</string>
|
||||||
|
<string name="summary_resolution_list">Zwiększ, aby poprawić klarowność obrazu. Zmniejsz, aby uzyskać lepszą wydajność na słabszych urządzeniach i wolniejszych połączeniach sieciowych.</string>
|
||||||
|
<string name="title_native_res_dialog">Ostrzeżenie o rozdzielczości natywnej</string>
|
||||||
|
<string name="title_fps_list">Częstotliwość odświeżania wideo</string>
|
||||||
|
<string name="summary_fps_list">Zwiększ, aby uzyskać płynniejszy strumień wideo. Zmniejsz, aby uzyskać lepszą wydajność na słabszych urządzeniach.</string>
|
||||||
|
<string name="summary_seekbar_bitrate">Zwiększ, aby uzyskać lepszą jakość obrazu. Zmniejsz, aby poprawić wydajność na wolniejszych połączeniach.</string>
|
||||||
|
<string name="suffix_seekbar_bitrate_mbps">Mbps</string>
|
||||||
|
<string name="title_checkbox_stretch_video">Rozciągnięcie wideo do pełnego ekranu</string>
|
||||||
|
<string name="resolution_prefix_native">Natywna</string>
|
||||||
|
<string name="title_native_fps_dialog">Ostrzeżenie o natywnym FPS</string>
|
||||||
|
<string name="title_checkbox_enable_audiofx">Włącz obsługę korektora systemowego</string>
|
||||||
|
<string name="category_gamepad_settings">Ustawienia gamepada</string>
|
||||||
|
<string name="title_checkbox_multi_controller">Automatyczne wykrywanie obecności gamepada</string>
|
||||||
|
<string name="summary_checkbox_enable_audiofx">Umożliwia działanie efektów audio podczas przesyłania strumieniowego, ale może zwiększyć opóźnienie dźwięku</string>
|
||||||
|
<string name="title_checkbox_vibrate_fallback">Emuluj wsparcie dudnienia za pomocą wibracji</string>
|
||||||
|
<string name="title_seekbar_vibrate_fallback_strength">Regulacja intensywności emulowanego dudnienia</string>
|
||||||
|
<string name="summary_seekbar_vibrate_fallback_strength">Wzmocnienie lub zmniejszenie intensywności wibracji na urządzeniu</string>
|
||||||
|
<string name="summary_checkbox_multi_controller">Odznaczenie tej opcji wymusza, by gamepad był zawsze obecny</string>
|
||||||
|
<string name="summary_checkbox_vibrate_fallback">Wibruje urządzenie, aby naśladować dudnienie, jeśli gamepad go nie obsługuje</string>
|
||||||
|
<string name="suffix_seekbar_vibrate_fallback_strength">%</string>
|
||||||
|
<string name="title_seekbar_deadzone">Regulacja strefy martwej drążka analogowego</string>
|
||||||
|
<string name="summary_seekbar_deadzone">Uwaga: Niektóre gry mogą wymuszać większą strefę martwą niż ta, do której skonfigurowany jest Moonlight.</string>
|
||||||
|
<string name="suffix_seekbar_deadzone">%</string>
|
||||||
|
<string name="title_checkbox_xb1_driver">Sterownik USB gamepada Xbox 360/One</string>
|
||||||
|
<string name="title_checkbox_usb_bind_all">Zastąpienie natywnej obsługi gamepada Xbox</string>
|
||||||
|
<string name="title_checkbox_mouse_emulation">Emulacja myszy za pomocą gamepada</string>
|
||||||
|
<string name="title_checkbox_flip_face_buttons">Zamiana przycisków akcji A/B/X/Y</string>
|
||||||
|
<string name="summary_checkbox_xb1_driver">Włącza wbudowany sterownik USB dla urządzeń bez natywnej obsługi kontrolera Xbox</string>
|
||||||
|
<string name="summary_checkbox_usb_bind_all">Użyj sterownika USB Moonlight dla wszystkich obsługiwanych gamepadów, nawet jeśli natywna obsługa kontrolera Xbox jest obecna</string>
|
||||||
|
<string name="title_checkbox_gamepad_touchpad_as_mouse">Zawsze kontroluj mysz za pomocą touchpada</string>
|
||||||
|
<string name="summary_checkbox_gamepad_touchpad_as_mouse">Wymusza sterowanie myszą za pomocą touchpada gamepada, nawet w przypadku emulacji gamepada z touchpadem.</string>
|
||||||
|
<string name="title_checkbox_gamepad_motion_sensors">Zezwalaj na korzystanie z czujników ruchu gamepada</string>
|
||||||
|
<string name="summary_checkbox_gamepad_motion_sensors">Umożliwia obsługiwanym hostom żądanie danych z czujników ruchu podczas emulacji gamepada z czujnikami ruchu. Wyłączenie może nieznacznie zmniejszyć zużycie energii i sieci, jeśli czujniki ruchu nie są używane w grze.</string>
|
||||||
|
<string name="title_checkbox_gamepad_motion_fallback">Emulacja obsługi czujnika ruchu gamepada</string>
|
||||||
|
<string name="category_input_settings">Ustawienia wejścia</string>
|
||||||
|
<string name="title_checkbox_touchscreen_trackpad">Używanie ekranu dotykowego jako gładzika</string>
|
||||||
|
<string name="summary_checkbox_touchscreen_trackpad">Jeśli opcja ta jest włączona, ekran dotykowy działa jak gładzik. Jeśli jest wyłączony, ekran dotykowy bezpośrednio steruje kursorem myszy.</string>
|
||||||
|
<string name="title_checkbox_absolute_mouse_mode">Tryb myszy dla pulpitu zdalnego</string>
|
||||||
|
<string name="title_checkbox_mouse_nav_buttons">Włączanie przycisków myszy wstecz i dalej</string>
|
||||||
|
<string name="category_on_screen_controls_settings">Ustawienia sterowania na ekranie</string>
|
||||||
|
<string name="title_checkbox_show_onscreen_controls">Wyświetlanie ustawień sterowania na ekranie</string>
|
||||||
|
<string name="summary_checkbox_show_onscreen_controls">Wyświetlanie nakładki wirtualnego kontrolera na ekranie dotykowym</string>
|
||||||
|
<string name="title_checkbox_vibrate_osc">Włącz wibracje</string>
|
||||||
|
<string name="summary_checkbox_mouse_nav_buttons">Włączenie tej opcji może uniemożliwić kliknięcie prawym przyciskiem myszy na niektórych problematycznych urządzeniach</string>
|
||||||
|
<string name="summary_checkbox_vibrate_osc">Wibruje urządzenie, aby naśladować dudnienie przy ustawieniach sterowania na ekranie</string>
|
||||||
|
<string name="title_only_l3r3">Pokaż tylko L3 i R3</string>
|
||||||
|
<string name="summary_only_l3r3">Ukryj wszystkie przyciski wirtualne z wyjątkiem L3 i R3</string>
|
||||||
|
<string name="title_reset_osc">Wyczyść zapisany układ elementów sterujących na ekranie</string>
|
||||||
|
<string name="toast_reset_osc_success">Przywrócenie domyślnych ustawień elementów sterujących na ekranie</string>
|
||||||
|
<string name="title_osc_opacity">Zmiana krycia elementów sterujących na ekranie</string>
|
||||||
|
<string name="summary_osc_opacity">Zwiększanie/zmniejszanie przezroczystości elementów sterujących na ekranie</string>
|
||||||
|
<string name="dialog_title_osc_opacity">Zmiana krycia</string>
|
||||||
|
<string name="suffix_osc_opacity">%</string>
|
||||||
|
<string name="category_ui_settings">Ustawienia interfejsu użytkownika</string>
|
||||||
|
<string name="title_checkbox_enable_pip">Włącz tryb obserwatora obrazu w obrazie</string>
|
||||||
|
<string name="summary_reset_osc">Przywraca domyślny rozmiar i położenie wszystkich elementów sterujących na ekranie</string>
|
||||||
|
<string name="title_language_list">Język</string>
|
||||||
|
<string name="summary_language_list">Język używany w Moonlight</string>
|
||||||
|
<string name="category_host_settings">Ustawienia hosta</string>
|
||||||
|
<string name="summary_checkbox_small_icon_mode">Mniejsze ramki w siatce aplikacji pozwalają na wyświetlanie większej liczby aplikacji na ekranie</string>
|
||||||
|
<string name="title_checkbox_enable_sops">Optymalizacja ustawień gry</string>
|
||||||
|
<string name="summary_checkbox_enable_sops">Zezwalanie GFE na modyfikowanie ustawień gry w celu optymalnego streamowania</string>
|
||||||
|
<string name="title_checkbox_host_audio">Odtwarzanie dźwięku na komputerze</string>
|
||||||
|
<string name="summary_checkbox_host_audio">Odtwarzanie dźwięku z komputera i tego urządzenia</string>
|
||||||
|
<string name="category_advanced_settings">Ustawienia zaawansowane</string>
|
||||||
|
<string name="title_unlock_fps">Odblokuj wszystkie możliwe liczby klatek na sekundę</string>
|
||||||
|
<string name="title_checkbox_reduce_refresh_rate">Zezwalaj na zmniejszenie częstotliwości odświeżania</string>
|
||||||
|
<string name="summary_checkbox_reduce_refresh_rate">Niższe częstotliwości odświeżania wyświetlacza mogą oszczędzać energię kosztem dodatkowych opóźnień wideo</string>
|
||||||
|
<string name="summary_unlock_fps">Przesyłanie strumieniowe w 90 lub 120 klatkach na sekundę może zmniejszyć opóźnienia na urządzeniach wysokiej klasy, ale może powodować opóźnienia lub niestabilność na urządzeniach, które nie są w stanie tego obsłużyć</string>
|
||||||
|
<string name="title_checkbox_disable_warnings">Wyłączanie komunikatów ostrzegawczych</string>
|
||||||
|
<string name="summary_checkbox_disable_warnings">Wyłączanie wyświetlanych na ekranie komunikatów ostrzegawczych o połączeniu podczas przesyłania strumieniowego</string>
|
||||||
|
<string name="title_disable_frame_drop">Nigdy nie porzucaj klatek</string>
|
||||||
|
<string name="title_video_format">Zmiana ustawień kodeka</string>
|
||||||
|
<string name="summary_video_format">Nowsze kodeki mogą obniżyć wymagania dotyczące przepustowości wideo, jeśli urządzenie je obsługuje. Wybrane kodeki mogą zostać zignorowane, jeśli nie są obsługiwane przez oprogramowanie hosta lub procesor graficzny.</string>
|
||||||
|
<string name="summary_disable_frame_drop">Może zmniejszyć mikroprzycięcia na niektórych urządzeniach, ale może zwiększyć opóźnienia</string>
|
||||||
|
<string name="title_enable_hdr">Włącz HDR (eksperymentalnie)</string>
|
||||||
|
<string name="summary_enable_hdr">Przesyłaj strumieniowo HDR, gdy gra i procesor graficzny komputera obsługują tę funkcję. HDR wymaga GPU z obsługą kodowania HEVC Main 10.</string>
|
||||||
|
<string name="title_full_range">Wymuś pełny zakres wideo (eksperymentalne)</string>
|
||||||
|
<string name="summary_enable_perf_overlay">Wyświetlanie informacji o wydajności strumienia w czasie rzeczywistym podczas strumieniowania</string>
|
||||||
|
<string name="title_enable_post_stream_toast">Wyświetlanie komunikatu o opóźnieniu po przesyłaniu strumieniowym</string>
|
||||||
|
<string name="summary_full_range">Spowoduje to utratę szczegółów w jasnych i ciemnych obszarach, jeśli urządzenie nie wyświetla prawidłowo treści wideo w pełnym zakresie.</string>
|
||||||
|
<string name="summary_enable_post_stream_toast">Wyświetlanie komunikatu informującego o opóźnieniu po zakończeniu strumienia</string>
|
||||||
|
<string name="title_setup_guide">Instrukcja konfiguracji</string>
|
||||||
|
<string name="title_privacy_policy">Polityka prywatności</string>
|
||||||
|
<string name="summary_privacy_policy">Zobacz politykę prywatności Moonlight</string>
|
||||||
|
<string name="resolution_360p">360p</string>
|
||||||
|
<string name="resolution_720p">720p</string>
|
||||||
|
<string name="toast_controller_type_changed">Typ gamepada może zostać zmieniony z powodu emulacji czujnika ruchu</string>
|
||||||
|
<string name="resolution_4k">4K</string>
|
||||||
|
<string name="fps_30">30 FPS</string>
|
||||||
|
<string name="fps_60">60 FPS</string>
|
||||||
|
<string name="fps_90">90 FPS</string>
|
||||||
|
<string name="fps_120">120 FPS</string>
|
||||||
|
<string name="videoformat_h264always">Preferowany H.264</string>
|
||||||
|
<string name="pacing_balanced_alt">Zrównoważone z limitem FPS</string>
|
||||||
|
<string name="pacing_smoothness">Preferowanie najbardziej płynnego wideo (może znacznie zwiększyć opóźnienie)</string>
|
||||||
|
<string name="title_analog_scrolling">Użyj drążka analogowego do przewijania</string>
|
||||||
|
<string name="summary_analog_scrolling">Wybór drążka analogowego do przewijania w trybie emulacji myszy</string>
|
||||||
|
<string name="analogscroll_none">Brak (oba drążki poruszają myszą)</string>
|
||||||
|
<string name="analogscroll_right">Prawy drążek analogowy</string>
|
||||||
|
<string name="analogscroll_left">Lewy drążek analogowy</string>
|
||||||
|
<string name="scut_invalid_app_id">Podana aplikacja jest niepoprawna</string>
|
||||||
|
<string name="scut_invalid_uuid">Podany PC jest niepoprawny</string>
|
||||||
|
<string name="pcview_menu_delete_pc">Usuń PC</string>
|
||||||
|
<string name="pcview_menu_test_network">Test połączenia sieciowego</string>
|
||||||
|
<string name="pcview_menu_details">Wyświetl szczegóły</string>
|
||||||
|
<string name="nettest_title_done">Test sieci zakończony</string>
|
||||||
|
<string name="nettest_text_failure">Bieżące połączenie sieciowe urządzenia wydaje się blokować Moonlight. Przesyłanie strumieniowe przez Internet może nie działać podczas połączenia z tą siecią.
|
||||||
|
\n
|
||||||
|
\nNastępujące porty sieciowe zostały zablokowane:
|
||||||
|
\n</string>
|
||||||
|
<string name="nettest_text_blocked">Bieżące połączenie sieciowe urządzenia blokuje Moonlight. Przesyłanie strumieniowe przez Internet może nie działać podczas połączenia z tą siecią.</string>
|
||||||
|
<string name="pair_pairing_title">Parowanie</string>
|
||||||
|
<string name="pair_pc_offline">Komputer jest offline</string>
|
||||||
|
<string name="pair_incorrect_pin">Nieprawidłowy kod PIN</string>
|
||||||
|
<string name="pair_fail">Parowanie nie powiodło się</string>
|
||||||
|
<string name="pair_already_in_progress">Parowanie jest już w toku</string>
|
||||||
|
<string name="wol_pc_online">Komputer jest online</string>
|
||||||
|
<string name="wol_no_mac">Nie można wybudzić komputera, ponieważ nie ma zapisanego adresu MAC</string>
|
||||||
|
<string name="wol_waking_pc">Uruchamianie PC…</string>
|
||||||
|
<string name="wol_waking_msg">Uruchomienie komputera może potrwać kilka sekund. Jeśli tak się nie stanie, upewnij się, że jest prawidłowo skonfigurowany do Wake-On-LAN.</string>
|
||||||
|
<string name="unpair_fail">Rozparowanie nie powiodło się</string>
|
||||||
|
<string name="unpair_error">Urządzenie nie zostało sparowane</string>
|
||||||
|
<string name="error_pc_offline">Komputer jest offline</string>
|
||||||
|
<string name="error_unknown_host">Nie udało się zlokalizować hosta</string>
|
||||||
|
<string name="message_decoding_error">Moonlight uległ awarii z powodu niezgodności z dekoderem wideo tego urządzenia. Spróbuj dostosować ustawienia przesyłania strumieniowego jeśli awarie będą się powtarzać.</string>
|
||||||
|
<string name="error_404">GFE zwrócił błąd HTTP 404. Upewnij się, że w Twoim komputerze działa obsługiwany procesor graficzny. Używanie oprogramowania pulpitu zdalnego może również powodować ten błąd. Spróbuj ponownie uruchomić komputer lub ponownie zainstalować GFE.</string>
|
||||||
|
<string name="title_decoding_reset">Reset ustawień wideo</string>
|
||||||
|
<string name="error_usb_prohibited">Dostęp USB jest zabroniony przez administratora urządzenia. Sprawdź ustawienia Knox lub MDM.</string>
|
||||||
|
<string name="video_decoder_init_failed">Nie udało się zainicjować dekodera wideo. Urządzenie może nie obsługiwać wybranej rozdzielczości lub liczby klatek na sekundę.</string>
|
||||||
|
<string name="early_termination_error">Coś poszło nie tak na komputerze hosta podczas uruchamiania transmisji.
|
||||||
|
\n
|
||||||
|
\nUpewnij się, że na komputerze hosta nie masz otwartej żadnej zawartości zabezpieczonej DRM. Możesz także spróbować ponownie uruchomić komputer hosta.</string>
|
||||||
|
<string name="conn_error_msg">Nie udało się uruchomić</string>
|
||||||
|
<string name="conn_terminated_msg">Połączenie zostało przerwane.</string>
|
||||||
|
<string name="perf_overlay_renderingfps">Liczba klatek na sekundę renderowania: %1$.2f FPS</string>
|
||||||
|
<string name="applist_refresh_error_title">Błąd</string>
|
||||||
|
<string name="applist_refresh_msg">Odświeżanie aplikacji…</string>
|
||||||
|
<string name="addpc_enter_ip">Należy wprowadzić adres IP</string>
|
||||||
|
<string name="category_audio_settings">Ustawienia audio</string>
|
||||||
|
<string name="title_frame_pacing">Tempo klatek wideo</string>
|
||||||
|
<string name="pacing_balanced">Zrównoważone</string>
|
||||||
|
<string name="no">Nie</string>
|
||||||
|
<string name="applist_menu_quit">Zakończenie sesji</string>
|
||||||
|
<string name="title_seekbar_bitrate">Szybkość transmisji wideo</string>
|
||||||
|
<string name="summary_checkbox_flip_face_buttons">Przełącza przyciski A/B i X/Y dla gamepadów i elementów sterujących na ekranie</string>
|
||||||
|
<string name="category_help">Pomoc</string>
|
||||||
|
<string name="resolution_480p">480p</string>
|
||||||
|
<string name="pair_pairing_msg">Wprowadź następujący kod PIN na komputerze docelowym:</string>
|
||||||
|
<string name="pair_pairing_help">Jeśli na komputerze hosta działa Sunshine, przejdź do interfejsu użytkownika Sunshine aby wprowadzić kod PIN.</string>
|
||||||
|
<string name="unpairing">Rozparowywanie…</string>
|
||||||
|
<string name="unpair_success">Rozparowano z powodzeniem</string>
|
||||||
|
<string name="unable_to_pin_shortcut">Obecny program uruchamiający nie pozwala na tworzenie przypiętych skrótów.</string>
|
||||||
|
<string name="conn_client_latency">Średnie opóźnienie dekodowania ramki:</string>
|
||||||
|
<string name="conn_client_latency_hw">opóźnienie dekodera sprzętowego:</string>
|
||||||
|
<string name="conn_metered">Ostrzeżenie: Aktywne połączenie sieciowe jest taryfowe!</string>
|
||||||
|
<string name="conn_hardware_latency">Średnie opóźnienie dekodowania sprzętowego:</string>
|
||||||
|
<string name="conn_starting">Uruchamianie</string>
|
||||||
|
<string name="conn_error_title">Błąd połączenia</string>
|
||||||
|
<string name="lost_connection">Utrata połączenia z komputerem</string>
|
||||||
|
<string name="dialog_title_reset_osc">Reset układu</string>
|
||||||
|
<string name="dialog_text_reset_osc">Czy na pewno chcesz usunąć zapisany układ kontrolek ekranowych?</string>
|
||||||
|
<string name="summary_checkbox_enable_pip">Umożliwia wyświetlanie strumienia (ale nie sterowanie nim) podczas pracy wielozadaniowej</string>
|
||||||
|
<string name="title_checkbox_small_icon_mode">Używaj małe ramki</string>
|
||||||
|
<string name="title_enable_perf_overlay">Wyświetlanie statystyk wydajności podczas przesyłania strumieniowego</string>
|
||||||
|
<string name="summary_troubleshooting">Zobacz wskazówki dotyczące diagnozowania i naprawiania typowych problemów z transmisją strumieniową</string>
|
||||||
|
<string name="audioconf_51surround">5.1 Surround Sound</string>
|
||||||
|
<string name="audioconf_71surround">7.1 Surround Sound</string>
|
||||||
|
<string name="videoformat_hevcalways">Preferowany HEVC</string>
|
||||||
|
<string name="summary_frame_pacing">Określenie sposobu równoważenia opóźnienia i płynności wideo</string>
|
||||||
|
<string name="pacing_latency">Preferowane najniższe opóźnienia</string>
|
||||||
|
<string name="perf_overlay_hostprocessinglatency">Opóźnienie przetwarzania hosta min/max/średnia: %1$.1f/%2$.1f/%3$.1f ms</string>
|
||||||
|
<string name="perf_overlay_netlatency">Średnie opóźnienie sieci: %1$d ms (wariancja: %2$d ms)</string>
|
||||||
|
<string name="applist_connect_msg">Podłączanie do komputera…</string>
|
||||||
|
<string name="applist_menu_resume">Wznowienie sesji</string>
|
||||||
|
<string name="perf_overlay_netdrops">Ramki porzucone przez połączenie sieciowe: %1$.2f%%</string>
|
||||||
|
<string name="perf_overlay_dectime">Średni czas dekodowania: %1$.2f ms</string>
|
||||||
|
<string name="addpc_success">Dodano komputer z powodzeniem</string>
|
||||||
|
<string name="resolution_prefix_native_landscape">(Panoramiczny)</string>
|
||||||
|
<string name="resolution_prefix_native_fullscreen">Natywny pełny ekran</string>
|
||||||
|
<string name="resolution_prefix_native_portrait">(Portretowy)</string>
|
||||||
|
<string name="resolution_1080p">1080p</string>
|
||||||
|
<string name="help_loading_msg">Ładowanie strony pomocy…</string>
|
||||||
|
<string name="pcview_menu_header_online">Online</string>
|
||||||
|
<string name="pcview_menu_header_offline">Offline</string>
|
||||||
|
<string name="pcview_menu_app_list">Wyświetl wszystkie aplikacje</string>
|
||||||
|
<string name="help_loading_title">Przeglądarka pomocy</string>
|
||||||
|
<string name="pcview_menu_pair_pc">Sparuj z PC</string>
|
||||||
|
<string name="pcview_menu_unpair_pc">Rozparuj</string>
|
||||||
|
<string name="pcview_menu_send_wol">Wyślij żądanie Wake-On-LAN</string>
|
||||||
|
<string name="nettest_text_waiting">Moonlight testuje połączenie sieciowe w celu ustalenia, czy wymagane porty są zablokowane.
|
||||||
|
\n
|
||||||
|
\nMoże to potrwać kilka sekund…</string>
|
||||||
|
<string name="pairing">Parowanie…</string>
|
||||||
|
<string name="pair_pc_ingame">Komputer jest obecnie w trakcie gry. Przed sparowaniem należy zamknąć grę.</string>
|
||||||
|
<string name="nettest_text_success">Wygląda na to, że sieć nie blokuje Moonlight. Jeśli nadal masz problemy z połączeniem, sprawdź ustawienia zapory sieciowej na swoim komputerze.
|
||||||
|
\n
|
||||||
|
\nJeśli próbujesz przesyłać strumieniowo przez Internet, zainstaluj narzędzie Moonlight Internet Hosting Tool na swoim komputerze i uruchom dołączony tester przesyłania strumieniowego przez Internet, aby sprawdzić połączenie internetowe komputera.</string>
|
||||||
|
<string name="pcview_menu_eol">Zakończenie usług NVIDIA GameStream</string>
|
||||||
|
<string name="nettest_text_inconclusive">Nie można było wykonać testu sieci ponieważ żaden z serwerów testujących połączenie Moonlight nie był osiągalny. Sprawdź połączenie internetowe lub spróbuj ponownie później.</string>
|
||||||
|
<string name="nettest_title_waiting">Testowanie połączenia sieciowego</string>
|
||||||
|
<string name="wol_fail">Nie udało się wysłać pakietów Wake-On-LAN</string>
|
||||||
|
<string name="error_manager_not_running">Usługa ComputerManager nie jest uruchomiona. Poczekaj kilka sekund lub uruchom ponownie aplikację.</string>
|
||||||
|
<string name="title_decoding_error">Awaria dekodera wideo</string>
|
||||||
|
<string name="message_decoding_reset">Dekoder wideo urządzenia nadal ulega awarii przy wybranych ustawieniach przesyłania strumieniowego. Ustawienia przesyłania strumieniowego zostały zresetowane do wartości domyślnych.</string>
|
||||||
|
<string name="no_video_received_error">Brak sygnału wideo od hosta.</string>
|
||||||
|
<string name="no_frame_received_error">Połączenie sieciowe nie działa prawidłowo. Zmniejsz ustawienie szybkości transmisji wideo lub wypróbuj szybsze połączenie.</string>
|
||||||
|
<string name="frame_conversion_error">Komputer host zgłosił krytyczny błąd kodowania wideo.
|
||||||
|
\n
|
||||||
|
\nSpróbuj wyłączyć tryb HDR, zmienić rozdzielczość przesyłania strumieniowego lub rozdzielczość wyświetlacza komputera hosta.</string>
|
||||||
|
<string name="conn_terminated_title">Połączenie zakończone</string>
|
||||||
|
<string name="ip_hint">Adres IP komputera hosta</string>
|
||||||
|
<string name="applist_menu_cancel">Anuluj</string>
|
||||||
|
<string name="applist_menu_hide_app">Ukryj aplikację</string>
|
||||||
|
<string name="applist_menu_details">Wyświetl szczegóły</string>
|
||||||
|
<string name="addpc_fail">Nie można połączyć się z określonym komputerem. Upewnij się, że wymagane porty są dozwolone przez zaporę sieciową.</string>
|
||||||
|
<string name="category_basic_settings">Ustawienia podstawowe</string>
|
||||||
|
<string name="text_native_res_dialog">Natywna rozdzielczość i/lub liczba klatek na sekundę mogą nie być obsługiwane przez serwer streamingu. Prawdopodobnie konieczne będzie ręczne skonfigurowanie odpowiedniego niestandardowego trybu wyświetlania dla komputera hosta.
|
||||||
|
\n
|
||||||
|
\nJeśli zdecydujesz się utworzyć niestandardową rozdzielczość w panelu sterowania NVIDIA aby dopasować ustawienia ekranu, upewnij się, że przeczytałeś i zrozumiałeś ostrzeżenie firmy NVIDIA dotyczące możliwego uszkodzenia monitora, niestabilności komputera i innych potencjalnych problemów.
|
||||||
|
\n
|
||||||
|
\nNie ponosimy odpowiedzialności za jakiekolwiek problemy wynikające z utworzenia niestandardowej rozdzielczości na komputerze.
|
||||||
|
\n
|
||||||
|
\nMoże się zdarzyć, że monitor nie obsługuje wymaganej konfiguracji wyświetlania. W takim przypadku można spróbować skonfigurować monitor wirtualny. Jeśli urządzenie lub komputer hosta nie obsługuje przesyłania strumieniowego w określonej rozdzielczości lub częstotliwości odświeżania, niestety nie masz szczęścia.</string>
|
||||||
|
<string name="fps_suffix_fps">FPS</string>
|
||||||
|
<string name="summary_checkbox_gamepad_motion_fallback">Używa wbudowanych czujników ruchu urządzenia, jeśli czujniki gamepada nie są obsługiwane przez podłączony gamepad lub wersję systemu Android.
|
||||||
|
\nUwaga: Włączenie tej opcji może spowodować, że gamepad będzie wyświetlany na hoście jako kontroler PlayStation.</string>
|
||||||
|
<string name="summary_checkbox_absolute_mouse_mode">Może to sprawić, że akceleracja myszy będzie zachowywać się bardziej naturalnie podczas korzystania ze zdalnego pulpitu, ale jest niekompatybilna z wieloma grami.</string>
|
||||||
|
<string name="title_troubleshooting">Przewodnik rozwiązywania problemów</string>
|
||||||
|
<string name="resolution_1440p">1440p</string>
|
||||||
|
<string name="audioconf_stereo">Stereo</string>
|
||||||
|
<string name="videoformat_auto">Automatycznie (zalecane)</string>
|
||||||
|
<string name="videoformat_av1always">Preferowany AV1 (eksperymentalny)</string>
|
||||||
|
<string name="summary_setup_guide">Wyświetl instrukcje, jak skonfigurować komputer do gier do streamowania</string>
|
||||||
</resources>
|
</resources>
|
@ -249,4 +249,9 @@
|
|||||||
\n
|
\n
|
||||||
\nTente desativar o modo HDR, alterar a resolução de streaming ou alterar a resolução do PC host.</string>
|
\nTente desativar o modo HDR, alterar a resolução de streaming ou alterar a resolução do PC host.</string>
|
||||||
<string name="summary_full_range">Isso causará perda de detalhes em áreas claras e escuras se o seu dispositivo não exibir corretamente todo o conteúdo de vídeo em cores.</string>
|
<string name="summary_full_range">Isso causará perda de detalhes em áreas claras e escuras se o seu dispositivo não exibir corretamente todo o conteúdo de vídeo em cores.</string>
|
||||||
|
<string name="analogscroll_none">Nenhum (ambos os sticks movem o rato)</string>
|
||||||
|
<string name="analogscroll_right">Stick analógico direito</string>
|
||||||
|
<string name="analogscroll_left">Stick analógico esquerdo</string>
|
||||||
|
<string name="title_analog_scrolling">Usar um stick analógico para fazer scroll</string>
|
||||||
|
<string name="summary_analog_scrolling">Selecciona um stick analógico para fazer scroll quando a emulação de rato está ativada</string>
|
||||||
</resources>
|
</resources>
|
@ -249,4 +249,9 @@
|
|||||||
<string name="resolution_480p">480p</string>
|
<string name="resolution_480p">480p</string>
|
||||||
<string name="resolution_720p">720p</string>
|
<string name="resolution_720p">720p</string>
|
||||||
<string name="summary_frame_pacing">Especifique o equilíbrio entre latência e suavidade do vídeo</string>
|
<string name="summary_frame_pacing">Especifique o equilíbrio entre latência e suavidade do vídeo</string>
|
||||||
|
<string name="analogscroll_none">Nenhum (ambos os sticks movem o rato)</string>
|
||||||
|
<string name="analogscroll_right">Stick analógico direito</string>
|
||||||
|
<string name="analogscroll_left">Stick analógico esquerdo</string>
|
||||||
|
<string name="title_analog_scrolling">Usar um stick analógico para fazer scroll</string>
|
||||||
|
<string name="summary_analog_scrolling">Selecciona um stick analógico para fazer scroll quando a emulação de rato está ativada</string>
|
||||||
</resources>
|
</resources>
|
@ -6,11 +6,9 @@
|
|||||||
<string name="scut_pc_not_found">PC negăsit</string>
|
<string name="scut_pc_not_found">PC negăsit</string>
|
||||||
<string name="scut_invalid_uuid">PC-ul este invalid</string>
|
<string name="scut_invalid_uuid">PC-ul este invalid</string>
|
||||||
<string name="scut_invalid_app_id">Aplicația este invalidă</string>
|
<string name="scut_invalid_app_id">Aplicația este invalidă</string>
|
||||||
|
|
||||||
<!-- Help strings -->
|
<!-- Help strings -->
|
||||||
<string name="help_loading_title">Ajutor</string>
|
<string name="help_loading_title">Ajutor</string>
|
||||||
<string name="help_loading_msg">Se încarcă pagina de ajutor…</string>
|
<string name="help_loading_msg">Se încarcă pagina de ajutor…</string>
|
||||||
|
|
||||||
<!-- PC view menu entries -->
|
<!-- PC view menu entries -->
|
||||||
<string name="pcview_menu_app_list">Vezi lista de jocuri</string>
|
<string name="pcview_menu_app_list">Vezi lista de jocuri</string>
|
||||||
<string name="pcview_menu_pair_pc">Împerechează PC-ul</string>
|
<string name="pcview_menu_pair_pc">Împerechează PC-ul</string>
|
||||||
@ -18,7 +16,6 @@
|
|||||||
<string name="pcview_menu_send_wol">Trimite o cerere Wake-On-LAN</string>
|
<string name="pcview_menu_send_wol">Trimite o cerere Wake-On-LAN</string>
|
||||||
<string name="pcview_menu_delete_pc">Șterge PC</string>
|
<string name="pcview_menu_delete_pc">Șterge PC</string>
|
||||||
<string name="pcview_menu_details">Vezi detalii</string>
|
<string name="pcview_menu_details">Vezi detalii</string>
|
||||||
|
|
||||||
<!-- Pair messages -->
|
<!-- Pair messages -->
|
||||||
<string name="pairing">Se împerechează…</string>
|
<string name="pairing">Se împerechează…</string>
|
||||||
<string name="pair_pc_offline">PC-ul nu este accesibil</string>
|
<string name="pair_pc_offline">PC-ul nu este accesibil</string>
|
||||||
@ -28,20 +25,17 @@
|
|||||||
<string name="pair_incorrect_pin">PIN-ul este greșit</string>
|
<string name="pair_incorrect_pin">PIN-ul este greșit</string>
|
||||||
<string name="pair_fail">Împerecherea a eșuat</string>
|
<string name="pair_fail">Împerecherea a eșuat</string>
|
||||||
<string name="pair_already_in_progress">Împerecherea este deja în curs</string>
|
<string name="pair_already_in_progress">Împerecherea este deja în curs</string>
|
||||||
|
|
||||||
<!-- WOL messages -->
|
<!-- WOL messages -->
|
||||||
<string name="wol_pc_online">PC-ul este accesibil</string>
|
<string name="wol_pc_online">PC-ul este accesibil</string>
|
||||||
<string name="wol_no_mac">Nu s-a putut porni PC-ul deoarece GFE nu a comunicat o adresa MAC</string>
|
<string name="wol_no_mac">Nu s-a putut porni PC-ul deoarece GFE nu a comunicat o adresa MAC</string>
|
||||||
<string name="wol_waking_pc">Se pornește PC-ul…</string>
|
<string name="wol_waking_pc">Se pornește PC-ul…</string>
|
||||||
<string name="wol_waking_msg">Poate dura puțin până PC-ul pornește. Dacă nu pornește, verifică dacă este configurat corect pentru Wake-On-LAN.</string>
|
<string name="wol_waking_msg">Poate dura puțin până PC-ul pornește. Dacă nu pornește, verifică dacă este configurat corect pentru Wake-On-LAN.</string>
|
||||||
<string name="wol_fail">Nu s-au putut trimite pachetele Wake-On-LAN</string>
|
<string name="wol_fail">Nu s-au putut trimite pachetele Wake-On-LAN</string>
|
||||||
|
|
||||||
<!-- Unpair messages -->
|
<!-- Unpair messages -->
|
||||||
<string name="unpairing">Desperecherechere…</string>
|
<string name="unpairing">Desperecherechere…</string>
|
||||||
<string name="unpair_success">Desperecherechere efectuată cu succes</string>
|
<string name="unpair_success">Desperecherechere efectuată cu succes</string>
|
||||||
<string name="unpair_fail">Desperecherea a eșuat</string>
|
<string name="unpair_fail">Desperecherea a eșuat</string>
|
||||||
<string name="unpair_error">Dispozitivul nu este împerecheat</string>
|
<string name="unpair_error">Dispozitivul nu este împerecheat</string>
|
||||||
|
|
||||||
<!-- Errors -->
|
<!-- Errors -->
|
||||||
<string name="error_pc_offline">PC-ul este inaccesibil</string>
|
<string name="error_pc_offline">PC-ul este inaccesibil</string>
|
||||||
<string name="error_manager_not_running">Serviciul ComputerManager nu este pornit. Te rugăm să aștepți câteva secunde sau să repornești aplicația.</string>
|
<string name="error_manager_not_running">Serviciul ComputerManager nu este pornit. Te rugăm să aștepți câteva secunde sau să repornești aplicația.</string>
|
||||||
@ -56,7 +50,6 @@
|
|||||||
<string name="error_usb_prohibited">Accesul USB este interzis de către administratorul dispozitivului. Verifică setarile Knox sau MDM.</string>
|
<string name="error_usb_prohibited">Accesul USB este interzis de către administratorul dispozitivului. Verifică setarile Knox sau MDM.</string>
|
||||||
<string name="unable_to_pin_shortcut">Launcher-ul tău curent nu permite crearea de scurtături fixate.</string>
|
<string name="unable_to_pin_shortcut">Launcher-ul tău curent nu permite crearea de scurtături fixate.</string>
|
||||||
<string name="video_decoder_init_failed">Inițializarea decodorului video a eșuat. Este posibil ca acest dispozitiv să nu suporte rezoluția sau rata cadrelor selectată.</string>
|
<string name="video_decoder_init_failed">Inițializarea decodorului video a eșuat. Este posibil ca acest dispozitiv să nu suporte rezoluția sau rata cadrelor selectată.</string>
|
||||||
|
|
||||||
<!-- Start application messages -->
|
<!-- Start application messages -->
|
||||||
<string name="conn_establishing_title">Se stabilește conexiunea</string>
|
<string name="conn_establishing_title">Se stabilește conexiunea</string>
|
||||||
<string name="conn_establishing_msg">Se pornește conexiunea</string>
|
<string name="conn_establishing_msg">Se pornește conexiunea</string>
|
||||||
@ -69,7 +62,6 @@
|
|||||||
<string name="conn_error_msg">Pornirea a eșuat</string>
|
<string name="conn_error_msg">Pornirea a eșuat</string>
|
||||||
<string name="conn_terminated_title">Conexiunea închisă</string>
|
<string name="conn_terminated_title">Conexiunea închisă</string>
|
||||||
<string name="conn_terminated_msg">Conexiunea a fost terminată</string>
|
<string name="conn_terminated_msg">Conexiunea a fost terminată</string>
|
||||||
|
|
||||||
<!-- General strings -->
|
<!-- General strings -->
|
||||||
<string name="ip_hint">Adresa IP a PC-ului cu GFE</string>
|
<string name="ip_hint">Adresa IP a PC-ului cu GFE</string>
|
||||||
<string name="searching_pc">Se caută PC-uri cu GameStream activat…\n\n
|
<string name="searching_pc">Se caută PC-uri cu GameStream activat…\n\n
|
||||||
@ -87,7 +79,6 @@
|
|||||||
<string name="perf_overlay_renderingfps">Rata de afisare a cadrelor: %1$.2f FPS</string>
|
<string name="perf_overlay_renderingfps">Rata de afisare a cadrelor: %1$.2f FPS</string>
|
||||||
<string name="perf_overlay_netdrops">Cadre pierdute de rețea: %1$.2f%%</string>
|
<string name="perf_overlay_netdrops">Cadre pierdute de rețea: %1$.2f%%</string>
|
||||||
<string name="perf_overlay_dectime">Timpul mediu de decodare: %1$.2f ms</string>
|
<string name="perf_overlay_dectime">Timpul mediu de decodare: %1$.2f ms</string>
|
||||||
|
|
||||||
<!-- AppList activity -->
|
<!-- AppList activity -->
|
||||||
<string name="applist_connect_msg">Se conectează la PC…</string>
|
<string name="applist_connect_msg">Se conectează la PC…</string>
|
||||||
<string name="applist_menu_resume">Continuă Sesiunea</string>
|
<string name="applist_menu_resume">Continuă Sesiunea</string>
|
||||||
@ -106,7 +97,6 @@
|
|||||||
<string name="applist_quit_fail">Nu s-a putut închide lista</string>
|
<string name="applist_quit_fail">Nu s-a putut închide lista</string>
|
||||||
<string name="applist_quit_confirmation">Sigur dorești să închizi aplicația curentă? Toate datele nesalvate vor fi pierdute.</string>
|
<string name="applist_quit_confirmation">Sigur dorești să închizi aplicația curentă? Toate datele nesalvate vor fi pierdute.</string>
|
||||||
<string name="applist_details_id">ID-ul aplicației:</string>
|
<string name="applist_details_id">ID-ul aplicației:</string>
|
||||||
|
|
||||||
<!-- Add computer manually activity -->
|
<!-- Add computer manually activity -->
|
||||||
<string name="title_add_pc">Adaugă PC manual</string>
|
<string name="title_add_pc">Adaugă PC manual</string>
|
||||||
<string name="msg_add_pc">Conectare în curs…</string>
|
<string name="msg_add_pc">Conectare în curs…</string>
|
||||||
@ -115,7 +105,6 @@
|
|||||||
<string name="addpc_unknown_host">Nu am putut identifica adresa PC-ului. Asigură-te că ai introdus-o corect.</string>
|
<string name="addpc_unknown_host">Nu am putut identifica adresa PC-ului. Asigură-te că ai introdus-o corect.</string>
|
||||||
<string name="addpc_enter_ip">Trebuie să introduci o adresa IP</string>
|
<string name="addpc_enter_ip">Trebuie să introduci o adresa IP</string>
|
||||||
<string name="addpc_wrong_sitelocal">Adresa introdusă nu pare corectă. Pentru conectare prin Internet, este nevoie de adresa publică a routerului.</string>
|
<string name="addpc_wrong_sitelocal">Adresa introdusă nu pare corectă. Pentru conectare prin Internet, este nevoie de adresa publică a routerului.</string>
|
||||||
|
|
||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="category_basic_settings">Setări de bază</string>
|
<string name="category_basic_settings">Setări de bază</string>
|
||||||
<string name="title_resolution_list">Rezolutia video</string>
|
<string name="title_resolution_list">Rezolutia video</string>
|
||||||
@ -131,11 +120,9 @@
|
|||||||
<string name="summary_checkbox_disable_warnings">Dezactivează mesajele de avertizare privind rețeaua în timpul conexiunii</string>
|
<string name="summary_checkbox_disable_warnings">Dezactivează mesajele de avertizare privind rețeaua în timpul conexiunii</string>
|
||||||
<string name="title_checkbox_enable_pip">Activează modul Picture-In-Picture</string>
|
<string name="title_checkbox_enable_pip">Activează modul Picture-In-Picture</string>
|
||||||
<string name="summary_checkbox_enable_pip">Permite vizualizarea (dar nu și controlul) când efectuezi multitasking</string>
|
<string name="summary_checkbox_enable_pip">Permite vizualizarea (dar nu și controlul) când efectuezi multitasking</string>
|
||||||
|
|
||||||
<string name="category_audio_settings">Setări Audio</string>
|
<string name="category_audio_settings">Setări Audio</string>
|
||||||
<string name="title_audio_config_list">Configurarea sunetului surround</string>
|
<string name="title_audio_config_list">Configurarea sunetului surround</string>
|
||||||
<string name="summary_audio_config_list">Activeaza sunetul 5.1 sau 7.1 pentru sisteme home-theater</string>
|
<string name="summary_audio_config_list">Activeaza sunetul 5.1 sau 7.1 pentru sisteme home-theater</string>
|
||||||
|
|
||||||
<string name="category_input_settings">Setări de control</string>
|
<string name="category_input_settings">Setări de control</string>
|
||||||
<string name="title_checkbox_multi_controller">Detectează automat prezența controllerelor.</string>
|
<string name="title_checkbox_multi_controller">Detectează automat prezența controllerelor.</string>
|
||||||
<string name="summary_checkbox_multi_controller">Dezactivarea acestei opțiuni implică prezența constantă a unui controller</string>
|
<string name="summary_checkbox_multi_controller">Dezactivarea acestei opțiuni implică prezența constantă a unui controller</string>
|
||||||
@ -151,7 +138,6 @@
|
|||||||
<string name="summary_checkbox_mouse_emulation">Apăsarea lungă pe butonul Start schimba modul de operare a controllerului în modul mouse.</string>
|
<string name="summary_checkbox_mouse_emulation">Apăsarea lungă pe butonul Start schimba modul de operare a controllerului în modul mouse.</string>
|
||||||
<string name="title_checkbox_mouse_nav_buttons">Activează butoanele de înainte și înapoi ale mousului</string>
|
<string name="title_checkbox_mouse_nav_buttons">Activează butoanele de înainte și înapoi ale mousului</string>
|
||||||
<string name="summary_checkbox_mouse_nav_buttons">Această opțiune poate afecta click dreapta pentru unele dispozitive problematice.</string>
|
<string name="summary_checkbox_mouse_nav_buttons">Această opțiune poate afecta click dreapta pentru unele dispozitive problematice.</string>
|
||||||
|
|
||||||
<string name="category_on_screen_controls_settings">Setări ale controalelor pe ecran</string>
|
<string name="category_on_screen_controls_settings">Setări ale controalelor pe ecran</string>
|
||||||
<string name="title_checkbox_show_onscreen_controls">Afișează controale pe ecran</string>
|
<string name="title_checkbox_show_onscreen_controls">Afișează controale pe ecran</string>
|
||||||
<string name="summary_checkbox_show_onscreen_controls">Afișează un controller virtual pe ecran</string>
|
<string name="summary_checkbox_show_onscreen_controls">Afișează un controller virtual pe ecran</string>
|
||||||
@ -168,19 +154,16 @@
|
|||||||
<string name="summary_osc_opacity">Ajustează gradul de transparență al controalelor de pe ecran</string>
|
<string name="summary_osc_opacity">Ajustează gradul de transparență al controalelor de pe ecran</string>
|
||||||
<string name="dialog_title_osc_opacity">Modifică opacitatea</string>
|
<string name="dialog_title_osc_opacity">Modifică opacitatea</string>
|
||||||
<string name="suffix_osc_opacity">%</string>
|
<string name="suffix_osc_opacity">%</string>
|
||||||
|
|
||||||
<string name="category_ui_settings">Setari UI</string>
|
<string name="category_ui_settings">Setari UI</string>
|
||||||
<string name="title_language_list">Limba (Language)</string>
|
<string name="title_language_list">Limba (Language)</string>
|
||||||
<string name="summary_language_list">Limba folosită de către Moonlight</string>
|
<string name="summary_language_list">Limba folosită de către Moonlight</string>
|
||||||
<string name="title_checkbox_small_icon_mode">Folosește iconițe mici</string>
|
<string name="title_checkbox_small_icon_mode">Folosește iconițe mici</string>
|
||||||
<string name="summary_checkbox_small_icon_mode">Iconițele folosite în grile vor fi mici pentru a încăpea mai multe odata</string>
|
<string name="summary_checkbox_small_icon_mode">Iconițele folosite în grile vor fi mici pentru a încăpea mai multe odata</string>
|
||||||
|
|
||||||
<string name="category_host_settings">Setările PC-ului gazdă</string>
|
<string name="category_host_settings">Setările PC-ului gazdă</string>
|
||||||
<string name="title_checkbox_enable_sops">Optimizarea setărilor de joc</string>
|
<string name="title_checkbox_enable_sops">Optimizarea setărilor de joc</string>
|
||||||
<string name="summary_checkbox_enable_sops">Permite GFE să modifice setările jocurilor pentru experiența optimă</string>
|
<string name="summary_checkbox_enable_sops">Permite GFE să modifice setările jocurilor pentru experiența optimă</string>
|
||||||
<string name="title_checkbox_host_audio">Redă audio si pe PC</string>
|
<string name="title_checkbox_host_audio">Redă audio si pe PC</string>
|
||||||
<string name="summary_checkbox_host_audio">Sunetul se va auzi atat pe acest dispozitiv cât și pe PC</string>
|
<string name="summary_checkbox_host_audio">Sunetul se va auzi atat pe acest dispozitiv cât și pe PC</string>
|
||||||
|
|
||||||
<string name="category_advanced_settings">Setări avansate</string>
|
<string name="category_advanced_settings">Setări avansate</string>
|
||||||
<string name="title_disable_frame_drop">Nu pierde cadre intenționat</string>
|
<string name="title_disable_frame_drop">Nu pierde cadre intenționat</string>
|
||||||
<string name="summary_disable_frame_drop">Poate să reducă micro-stuttering pe anumite device-uri, dar s-ar putea să crească latența</string>
|
<string name="summary_disable_frame_drop">Poate să reducă micro-stuttering pe anumite device-uri, dar s-ar putea să crească latența</string>
|
||||||
@ -190,11 +173,9 @@
|
|||||||
<string name="summary_enable_hdr">Folosește HDR daca aplicația si placa video suportă. Necesită o placa video seria GTX 1000 sau mai nouă.</string>
|
<string name="summary_enable_hdr">Folosește HDR daca aplicația si placa video suportă. Necesită o placa video seria GTX 1000 sau mai nouă.</string>
|
||||||
<string name="title_enable_perf_overlay">Activează statisticile de performanță</string>
|
<string name="title_enable_perf_overlay">Activează statisticile de performanță</string>
|
||||||
<string name="summary_enable_perf_overlay">Afișează în timp real statisticile de performanță ale conexiunii.</string>
|
<string name="summary_enable_perf_overlay">Afișează în timp real statisticile de performanță ale conexiunii.</string>
|
||||||
|
|
||||||
<!-- Array strings -->
|
<!-- Array strings -->
|
||||||
<string name="audioconf_stereo">Stereo</string>
|
<string name="audioconf_stereo">Stereo</string>
|
||||||
<string name="audioconf_51surround">Sunet Surround 5.1</string>
|
<string name="audioconf_51surround">Sunet Surround 5.1</string>
|
||||||
<string name="audioconf_71surround">Sunet Surround 7.1</string>
|
<string name="audioconf_71surround">Sunet Surround 7.1</string>
|
||||||
|
|
||||||
<string name="videoformat_hevcalways">Folosește HEVC mereu (se poate bloca)</string>
|
<string name="videoformat_hevcalways">Folosește HEVC mereu (se poate bloca)</string>
|
||||||
</resources>
|
</resources>
|
@ -59,7 +59,7 @@
|
|||||||
<string name="conn_error_title">Fogningsfel</string>
|
<string name="conn_error_title">Fogningsfel</string>
|
||||||
<string name="conn_error_msg">Misslyckades att börja</string>
|
<string name="conn_error_msg">Misslyckades att börja</string>
|
||||||
<string name="conn_terminated_title">Fogning förstörd</string>
|
<string name="conn_terminated_title">Fogning förstörd</string>
|
||||||
<string name="conn_terminated_msg">Fogningen har förstörts</string>
|
<string name="conn_terminated_msg">Förbindelsen avbröts.</string>
|
||||||
<string name="yes">Ja</string>
|
<string name="yes">Ja</string>
|
||||||
<string name="no">Nej</string>
|
<string name="no">Nej</string>
|
||||||
<string name="lost_connection">Tappade fogning till dator</string>
|
<string name="lost_connection">Tappade fogning till dator</string>
|
||||||
@ -259,4 +259,17 @@
|
|||||||
<string name="title_checkbox_gamepad_touchpad_as_mouse">Styr alltid musen med pekplatta</string>
|
<string name="title_checkbox_gamepad_touchpad_as_mouse">Styr alltid musen med pekplatta</string>
|
||||||
<string name="summary_checkbox_gamepad_touchpad_as_mouse">Tvingar indata från spelkontroll pekplattan att styra värdmusen, även när man emulerar en spelkontroll med en pekplatta.</string>
|
<string name="summary_checkbox_gamepad_touchpad_as_mouse">Tvingar indata från spelkontroll pekplattan att styra värdmusen, även när man emulerar en spelkontroll med en pekplatta.</string>
|
||||||
<string name="summary_checkbox_gamepad_motion_sensors">Aktiverar stöd för värden att begära rörelsesensor data när du emulerar en spelkontroll med rörelsesensorer. Inaktivering kan minska ström och nätverksanvändningen något om rörelsesensorer inte används i spelet.</string>
|
<string name="summary_checkbox_gamepad_motion_sensors">Aktiverar stöd för värden att begära rörelsesensor data när du emulerar en spelkontroll med rörelsesensorer. Inaktivering kan minska ström och nätverksanvändningen något om rörelsesensorer inte används i spelet.</string>
|
||||||
|
<string name="toast_controller_type_changed">Spelkontroll-typ kan ändras på grund av rörelsesensoremulering</string>
|
||||||
|
<string name="summary_checkbox_gamepad_motion_fallback">Använder enhetens inbyggda rörelsesensorer om spelkontrollsensorer inte stöds av din anslutna spelkontroll eller din Android-version.
|
||||||
|
\nObs: Om du aktiverar det här alternativet kan din spelkontroll visas som en PlayStation-kontroller på värden.</string>
|
||||||
|
<string name="title_checkbox_gamepad_motion_fallback">Emulera spelkontroll rörelsesensor stöd</string>
|
||||||
|
<string name="error_code_prefix">Felkod:</string>
|
||||||
|
<string name="summary_analog_scrolling">Välj en analog spak för att scrolla när du är i musemuleringsläge</string>
|
||||||
|
<string name="analogscroll_none">Ingen (båda spakarna flyttar musen)</string>
|
||||||
|
<string name="analogscroll_left">Vänster analogspak</string>
|
||||||
|
<string name="title_seekbar_vibrate_fallback_strength">Justera intensiteten på emulerat skakande</string>
|
||||||
|
<string name="summary_seekbar_vibrate_fallback_strength">Förstärk eller reducera vibrationsintensiteten på din enhet</string>
|
||||||
|
<string name="analogscroll_right">Höger analogspak</string>
|
||||||
|
<string name="suffix_seekbar_vibrate_fallback_strength">%</string>
|
||||||
|
<string name="title_analog_scrolling">Använd en analog spak för att bläddra</string>
|
||||||
</resources>
|
</resources>
|
@ -16,7 +16,7 @@
|
|||||||
<string name="pair_fail">Створення пари не вдалося</string>
|
<string name="pair_fail">Створення пари не вдалося</string>
|
||||||
<!-- WOL messages -->
|
<!-- WOL messages -->
|
||||||
<string name="wol_pc_online">Пристрій у мережі</string>
|
<string name="wol_pc_online">Пристрій у мережі</string>
|
||||||
<string name="wol_no_mac">Неможливо розбудити пристрій бо GFE не відправило MAC адреса</string>
|
<string name="wol_no_mac">Не вдається розбудити ПК, оскільки немає збереженої MAC-адреси</string>
|
||||||
<string name="wol_waking_pc">Пробудження пристрою…</string>
|
<string name="wol_waking_pc">Пробудження пристрою…</string>
|
||||||
<string name="wol_waking_msg">Пробудження пристрою може зайняти кілька секунд. Якщо цього не відбувається, упевніться що Wake-On-LAN налаштований правильно.</string>
|
<string name="wol_waking_msg">Пробудження пристрою може зайняти кілька секунд. Якщо цього не відбувається, упевніться що Wake-On-LAN налаштований правильно.</string>
|
||||||
<string name="wol_fail">Помилка при відправці Wake-On-LAN пакетів</string>
|
<string name="wol_fail">Помилка при відправці Wake-On-LAN пакетів</string>
|
||||||
@ -41,12 +41,12 @@
|
|||||||
<string name="conn_error_title">Помилка з\'єднання</string>
|
<string name="conn_error_title">Помилка з\'єднання</string>
|
||||||
<string name="conn_error_msg">Запуск не вдався</string>
|
<string name="conn_error_msg">Запуск не вдався</string>
|
||||||
<string name="conn_terminated_title">З\'єднання припинено</string>
|
<string name="conn_terminated_title">З\'єднання припинено</string>
|
||||||
<string name="conn_terminated_msg">З\'єднання перервано</string>
|
<string name="conn_terminated_msg">З’єднання було розірване.</string>
|
||||||
<!-- General strings -->
|
<!-- General strings -->
|
||||||
<string name="ip_hint">IP-адреса пристрою з GeForce</string>
|
<string name="ip_hint">IP-адреса головного ПК</string>
|
||||||
<string name="searching_pc">Пошук пристроїв із запущеним GameStream…
|
<string name="searching_pc">Пошук головного ПК у локальній мережі…
|
||||||
\n
|
\n
|
||||||
\n Переконайтеся що GameStream увімкнений в налаштуваннях GeForce Experience в розділі SHIELD.</string>
|
\nПереконайтеся, що Sunshine запущено на вашому головному ПК або GameStream увімкнено в налаштуваннях GeForce Experience SHIELD.</string>
|
||||||
<string name="yes">Так</string>
|
<string name="yes">Так</string>
|
||||||
<string name="no">Ні</string>
|
<string name="no">Ні</string>
|
||||||
<string name="lost_connection">З\'єднання з пристроєм втрачено</string>
|
<string name="lost_connection">З\'єднання з пристроєм втрачено</string>
|
||||||
@ -100,8 +100,8 @@
|
|||||||
<string name="title_checkbox_host_audio">Програвати звук на пристрої хоста</string>
|
<string name="title_checkbox_host_audio">Програвати звук на пристрої хоста</string>
|
||||||
<string name="summary_checkbox_host_audio">Програвати звук на пристроях хоста та клієнта</string>
|
<string name="summary_checkbox_host_audio">Програвати звук на пристроях хоста та клієнта</string>
|
||||||
<string name="category_advanced_settings">Розширені налаштування</string>
|
<string name="category_advanced_settings">Розширені налаштування</string>
|
||||||
<string name="title_video_format">Змінити налаштування HEVC</string>
|
<string name="title_video_format">Змінити налаштування кодека</string>
|
||||||
<string name="summary_video_format">HEVC знижує вимоги мережі, даючи можливість транслювати на повільних мережах але, вимагає нового пристрою з підтримкою цієї системи</string>
|
<string name="summary_video_format">Нові кодеки можуть знизити вимоги до пропускної здатності відео, якщо ваш пристрій їх підтримує. Вибрані кодеки можуть ігноруватися, якщо вони не підтримуються програмним забезпеченням хоста або графічним процесором.</string>
|
||||||
<string name="category_on_screen_controls_settings">Налаштування екранних ґудзиків</string>
|
<string name="category_on_screen_controls_settings">Налаштування екранних ґудзиків</string>
|
||||||
<string name="title_checkbox_show_onscreen_controls">Показувати екранні ґудзики</string>
|
<string name="title_checkbox_show_onscreen_controls">Показувати екранні ґудзики</string>
|
||||||
<string name="summary_checkbox_show_onscreen_controls">Відображати віртуальні ґудзики контролера на екрані</string>
|
<string name="summary_checkbox_show_onscreen_controls">Відображати віртуальні ґудзики контролера на екрані</string>
|
||||||
@ -115,7 +115,7 @@
|
|||||||
<string name="help">Допомога</string>
|
<string name="help">Допомога</string>
|
||||||
<string name="applist_connect_msg">Підключення до пристрою…</string>
|
<string name="applist_connect_msg">Підключення до пристрою…</string>
|
||||||
<string name="title_decoding_error">Збій відео розцифрувача</string>
|
<string name="title_decoding_error">Збій відео розцифрувача</string>
|
||||||
<string name="message_decoding_error">Стався збій Moonlight через несумітність з відео розцифрувачем даного пристрою. Спробуйте змінити налаштування трансляції якщо збої продовжуватимуться.</string>
|
<string name="message_decoding_error">Moonlight аварійно завершив роботу через несумісність із відеодекодером цього пристрою. Спробуйте налаштувати параметри потокового передавання, якщо збої триватимуть.</string>
|
||||||
<string name="title_decoding_reset">Налаштування відео скинуті</string>
|
<string name="title_decoding_reset">Налаштування відео скинуті</string>
|
||||||
<string name="message_decoding_reset">Відео розцифрувач вашого пристрою продовжує давати збої з поточними налаштуваннями трансляції. Налаштування трансляції були скинуті до значень за замовчуванням.</string>
|
<string name="message_decoding_reset">Відео розцифрувач вашого пристрою продовжує давати збої з поточними налаштуваннями трансляції. Налаштування трансляції були скинуті до значень за замовчуванням.</string>
|
||||||
<string name="error_usb_prohibited">USB доступ заборонений адміністратором пристрою. Перевірте налаштування Knox або MDM.</string>
|
<string name="error_usb_prohibited">USB доступ заборонений адміністратором пристрою. Перевірте налаштування Knox або MDM.</string>
|
||||||
@ -134,16 +134,16 @@
|
|||||||
<string name="title_disable_frame_drop">Ніколи не пропускати кадри</string>
|
<string name="title_disable_frame_drop">Ніколи не пропускати кадри</string>
|
||||||
<string name="summary_disable_frame_drop">Може зменшити мікрозависання на деяких пристроях але, також збільшити затримку</string>
|
<string name="summary_disable_frame_drop">Може зменшити мікрозависання на деяких пристроях але, також збільшити затримку</string>
|
||||||
<string name="title_enable_hdr">Увімкнути HDR (Експериментально)</string>
|
<string name="title_enable_hdr">Увімкнути HDR (Експериментально)</string>
|
||||||
<string name="summary_enable_hdr">Транслювати в HDR якщо гра та відео карта на пристрої хоста підтримують це. HDR вимагає відеокарти серії GTX 1000 або новіше.</string>
|
<string name="summary_enable_hdr">Транслювати в HDR, якщо це підтримується грою та графічним процесором ПК. Для HDR потрібен графічний процесор із підтримкою кодування HEVC Main 10.</string>
|
||||||
<string name="title_checkbox_vibrate_osc">Увімкнути вібрацію</string>
|
<string name="title_checkbox_vibrate_osc">Увімкнути вібрацію</string>
|
||||||
<string name="title_fps_list">Частота кадрів</string>
|
<string name="title_fps_list">Частота кадрів</string>
|
||||||
<string name="applist_menu_details">Деталі</string>
|
<string name="applist_menu_details">Переглянути деталі</string>
|
||||||
<string name="applist_menu_scut">Створити ярлик</string>
|
<string name="applist_menu_scut">Створити ярлик</string>
|
||||||
<string name="category_input_settings">Налаштування введення</string>
|
<string name="category_input_settings">Налаштування введення</string>
|
||||||
<string name="title_checkbox_touchscreen_trackpad">Використовувати сенсорний екран як пальцевід</string>
|
<string name="title_checkbox_touchscreen_trackpad">Використовувати сенсорний екран як пальцевід</string>
|
||||||
<string name="summary_checkbox_touchscreen_trackpad">Якщо увімкнено, сенсорний екран працює як ноутбуковий пальцевід. Якщо вимкнено, безпосередньо керує вказівником миші.</string>
|
<string name="summary_checkbox_touchscreen_trackpad">Якщо увімкнено, сенсорний екран працює як ноутбуковий пальцевід. Якщо вимкнено, безпосередньо керує вказівником миші.</string>
|
||||||
<string name="delete_pc_msg">Ви впевнені що хочете видалити цей пристрій\?</string>
|
<string name="delete_pc_msg">Ви впевнені що хочете видалити цей пристрій\?</string>
|
||||||
<string name="pcview_menu_details">Деталі</string>
|
<string name="pcview_menu_details">Переглянути деталі</string>
|
||||||
<string name="poor_connection_msg">Слабке з\'єднання з пристроєм</string>
|
<string name="poor_connection_msg">Слабке з\'єднання з пристроєм</string>
|
||||||
<string name="title_details">Деталі</string>
|
<string name="title_details">Деталі</string>
|
||||||
<string name="title_enable_perf_overlay">Увімкнути відображення статистики</string>
|
<string name="title_enable_perf_overlay">Увімкнути відображення статистики</string>
|
||||||
@ -176,24 +176,22 @@
|
|||||||
<string name="suffix_osc_opacity">%</string>
|
<string name="suffix_osc_opacity">%</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="summary_enable_post_stream_toast">Показувати статистику затримки після закінчення трансляції</string>
|
||||||
<string name="early_termination_error">Щось пішло не так на пристрої хоста при початку трансляції.
|
<string name="early_termination_error">Щось пішло не так на вашому головному ПК під час запуску потоку.
|
||||||
\n
|
\n
|
||||||
\nПереконайтеся, що на головному ПК немає відкритого вмісту, захищеного DRM. Ви також можете спробувати перезавантажити головний ПК.
|
\nПереконайтеся, що на головному ПК немає відкритого вмісту, захищеного DRM. Ви також можете спробувати перезавантажити головний ПК.</string>
|
||||||
\n
|
|
||||||
\nЯкщо проблема не зникає, спробуйте перевстановити драйвери GPU та GeForce Experience.</string>
|
|
||||||
<string name="nettest_text_success">Схоже що ваша мережа не блокує Moonlight. Якщо у вас й надалі проблеми з підключенням, перевірте налаштування брандмауера.
|
<string name="nettest_text_success">Схоже що ваша мережа не блокує Moonlight. Якщо у вас й надалі проблеми з підключенням, перевірте налаштування брандмауера.
|
||||||
\n
|
\n
|
||||||
\nЯкщо ви намагаєтеся транслювати через Інтернет, встановіть на своєму пристрої Moonlight Internet Hosting Tool, та запустіть випробування мережі щоб перевірити ваше з\'єднання до Інтернету.</string>
|
\nЯкщо ви намагаєтеся транслювати через Інтернет, встановіть на своєму пристрої Moonlight Internet Hosting Tool, та запустіть випробування мережі щоб перевірити ваше з\'єднання до Інтернету.</string>
|
||||||
<string name="resolution_prefix_native_fullscreen">Рідний повноекранний</string>
|
<string name="resolution_prefix_native_fullscreen">Рідний повноекранний</string>
|
||||||
<string name="resolution_prefix_native">Рідна</string>
|
<string name="resolution_prefix_native">Рідна</string>
|
||||||
<string name="suffix_seekbar_bitrate_mbps">Мб/с</string>
|
<string name="suffix_seekbar_bitrate_mbps">Мб/с</string>
|
||||||
<string name="text_native_res_dialog">Режими рідної роздільної здатності не підтримуються офіційно через GeForce Experience, і тому не змінять роздільну здатність хоста на ту що в клієнта автоматично. Вам потрібно буде виставити її самостійно у грі.
|
<string name="text_native_res_dialog">Власна роздільна здатність і/або FPS можуть не підтримуватися потоковим сервером. Ймовірно, вам доведеться вручну налаштувати відповідний спеціальний режим відображення для головного ПК.
|
||||||
\n
|
\n
|
||||||
\nЯкщо ви вирішили створити власну роздільну здатність у панелі керування NVIDIA переконайтеся, що ви прочитали та зрозуміли попередження NVIDIA щодо можливих пошкоджень монітора, нестабільності пристрою та інших потенційних проблем.
|
\nЯкщо ви вирішили вказати спеціальну роздільну здатність на панелі керування NVIDIA відповідно до налаштувань екрана, переконайтеся, що ви прочитали та зрозуміли попередження NVIDIA щодо можливого пошкодження монітора, нестабільної роботи ПК та інших потенційних проблем.
|
||||||
\n
|
\n
|
||||||
\nМи не несемо відповідальності за будь-які проблеми, спричинені створенням власних роздільних здатностей на ваших пристроях.
|
\nМи не несемо відповідальності за будь-які проблеми, що виникли в результаті встановлення власної роздільної здатності на вашому ПК.
|
||||||
\n
|
\n
|
||||||
\nЗрештою, пристрої клієнта чи хоста можуть не підтримувати трансляції рідною роздільною здатністю. Якщо це не працює на вашому пристрої, вам на жаль просто не пощастило.</string>
|
\nМожливо, ваш монітор не підтримує необхідну конфігурацію дисплея. Якщо так, ви можете спробувати налаштувати віртуальний монітор. Врешті-решт, якщо ваш пристрій або хост-комп’ютер не підтримує потокове передавання з певною роздільною здатністю чи частотою оновлення, вам, на жаль, не пощастило.</string>
|
||||||
<string name="title_native_res_dialog">Застереження про рідну роздільну здатність</string>
|
<string name="title_native_res_dialog">Застереження про рідну роздільну здатність</string>
|
||||||
<string name="applist_menu_hide_app">Сховати застосунок</string>
|
<string name="applist_menu_hide_app">Сховати застосунок</string>
|
||||||
<string name="perf_overlay_netlatency">Середня затримка мережі: %1$d мс (розбіжність %2$d мс)</string>
|
<string name="perf_overlay_netlatency">Середня затримка мережі: %1$d мс (розбіжність %2$d мс)</string>
|
||||||
@ -209,9 +207,9 @@
|
|||||||
\n</string>
|
\n</string>
|
||||||
<string name="nettest_text_inconclusive">Не вдалося перевірити мережу, тому що усі мережо-перевірочні сервери Moonlight недосяжні. Перевірте ваше з\'єднання з інтернетом та спробуйте знову.</string>
|
<string name="nettest_text_inconclusive">Не вдалося перевірити мережу, тому що усі мережо-перевірочні сервери Moonlight недосяжні. Перевірте ваше з\'єднання з інтернетом та спробуйте знову.</string>
|
||||||
<string name="nettest_title_done">Перевірка мережі завершена</string>
|
<string name="nettest_title_done">Перевірка мережі завершена</string>
|
||||||
<string name="nettest_text_waiting">Moonlight перевіряє мережеве з\'єднання щоб визначити чи заблокований NVIDIA GameStream.
|
<string name="nettest_text_waiting">Moonlight перевіряє ваше мережеве з’єднання, щоб визначити, чи заблоковані необхідні порти.
|
||||||
\n
|
\n
|
||||||
\nЦе займе кілька секунд…</string>
|
\nЦе може зайняти кілька секунд…</string>
|
||||||
<string name="nettest_title_waiting">Перевіряємо з\'єднання</string>
|
<string name="nettest_title_waiting">Перевіряємо з\'єднання</string>
|
||||||
<string name="pcview_menu_test_network">Перевірити мережеве з\'єднання</string>
|
<string name="pcview_menu_test_network">Перевірити мережеве з\'єднання</string>
|
||||||
<string name="pcview_menu_header_unknown">Оновлення</string>
|
<string name="pcview_menu_header_unknown">Оновлення</string>
|
||||||
@ -260,4 +258,29 @@
|
|||||||
\nСпробуйте вимкнути режим HDR, змінити роздільну здатність потокового відео або змінити роздільну здатність дисплея головного комп\'ютера.</string>
|
\nСпробуйте вимкнути режим HDR, змінити роздільну здатність потокового відео або змінити роздільну здатність дисплея головного комп\'ютера.</string>
|
||||||
<string name="title_full_range">Сила повного спектру відео (експериментальна)</string>
|
<string name="title_full_range">Сила повного спектру відео (експериментальна)</string>
|
||||||
<string name="summary_full_range">Це може призвести до втрати деталей у світлих і темних областях, якщо пристрій не відображає належним чином весь діапазон відеоконтенту.</string>
|
<string name="summary_full_range">Це може призвести до втрати деталей у світлих і темних областях, якщо пристрій не відображає належним чином весь діапазон відеоконтенту.</string>
|
||||||
|
<string name="pair_pairing_help">Якщо на вашому комп’ютері встановлений Sunshine, перейдіть до веб-інтерфейсу користувача Sunshine, щоб ввести PIN-код.</string>
|
||||||
|
<string name="error_code_prefix">Код помилки:</string>
|
||||||
|
<string name="title_seekbar_vibrate_fallback_strength">Налаштування інтенсивності вібро</string>
|
||||||
|
<string name="summary_seekbar_vibrate_fallback_strength">Посилюйте або зменшуйте інтенсивність вібрації пристрою</string>
|
||||||
|
<string name="title_checkbox_gamepad_motion_fallback">Емуляція підтримки датчика руху геймпада</string>
|
||||||
|
<string name="videoformat_av1always">Використовувати AV1 (експериментальний)</string>
|
||||||
|
<string name="videoformat_h264always">Використовувати H.264</string>
|
||||||
|
<string name="fps_suffix_fps">FPS</string>
|
||||||
|
<string name="title_native_fps_dialog">Попередження рідного FPS</string>
|
||||||
|
<string name="category_gamepad_settings">Налаштування геймпада</string>
|
||||||
|
<string name="title_analog_scrolling">Використовувати аналоговий стік для прокручування</string>
|
||||||
|
<string name="summary_analog_scrolling">Виберіть аналоговий стік для прокручування під час режиму емуляції миші</string>
|
||||||
|
<string name="analogscroll_none">Немає (обидва стіка пересувають мишу)</string>
|
||||||
|
<string name="analogscroll_right">Аналоговий стік праворуч</string>
|
||||||
|
<string name="analogscroll_left">Аналоговий стік ліворуч</string>
|
||||||
|
<string name="suffix_seekbar_vibrate_fallback_strength">%</string>
|
||||||
|
<string name="title_checkbox_gamepad_touchpad_as_mouse">Завжди керувати мишею за допомогою сенсорної панелі</string>
|
||||||
|
<string name="summary_checkbox_gamepad_touchpad_as_mouse">Примусове використання сенсорної панелі геймпада для керування основною мишею, навіть якщо емулюється геймпад із сенсорною панеллю.</string>
|
||||||
|
<string name="title_checkbox_gamepad_motion_sensors">Дозволити використовувати датчики руху геймпада</string>
|
||||||
|
<string name="summary_checkbox_gamepad_motion_sensors">Дозволяє підтримуваним хостам запитувати дані датчиків руху під час емуляції геймпада з датчиками руху. Якщо в грі не використовуються датчики руху, вимкнення може дещо зменшити енергоспоживання та використання мережі.</string>
|
||||||
|
<string name="summary_checkbox_gamepad_motion_fallback">Використовує вбудовані датчики руху вашого пристрою, якщо датчики геймпада не підтримуються підключеним геймпадом або вашою версією Android.
|
||||||
|
\nПримітка. Якщо ввімкнути цей параметр, ваш геймпад може відображатися як контролер PlayStation на хості.</string>
|
||||||
|
<string name="toast_controller_type_changed">Тип геймпада може бути змінений через емуляцію датчика руху</string>
|
||||||
|
<string name="pcview_menu_eol">Закриття сервісів NVIDIA GameStream</string>
|
||||||
|
<string name="perf_overlay_hostprocessinglatency">Затримка обробки хостом мін./макс./середня: %1$.1f/%2$.1f/%3$.1f мс</string>
|
||||||
</resources>
|
</resources>
|
@ -58,7 +58,7 @@
|
|||||||
<string name="conn_error_title"> 连接错误 </string>
|
<string name="conn_error_title"> 连接错误 </string>
|
||||||
<string name="conn_error_msg"> 启动失败 </string>
|
<string name="conn_error_msg"> 启动失败 </string>
|
||||||
<string name="conn_terminated_title"> 连接终结 </string>
|
<string name="conn_terminated_title"> 连接终结 </string>
|
||||||
<string name="conn_terminated_msg"> 连接已被终结 </string>
|
<string name="conn_terminated_msg">连接已被终结.</string>
|
||||||
<!-- General strings -->
|
<!-- General strings -->
|
||||||
<string name="ip_hint">串流电脑的IP地址</string>
|
<string name="ip_hint">串流电脑的IP地址</string>
|
||||||
<string name="searching_pc">在你的本地网络中搜索串流主机PC...
|
<string name="searching_pc">在你的本地网络中搜索串流主机PC...
|
||||||
@ -275,4 +275,13 @@
|
|||||||
<string name="summary_checkbox_gamepad_motion_fallback">如果你连接的游戏手柄或 Android 版本不支持游戏手柄传感器,请使用设备的内置运动传感器。
|
<string name="summary_checkbox_gamepad_motion_fallback">如果你连接的游戏手柄或 Android 版本不支持游戏手柄传感器,请使用设备的内置运动传感器。
|
||||||
\n注意:启用此选项可能会导致您的游戏手柄在主机上被识别为 PlayStation 4控制器。</string>
|
\n注意:启用此选项可能会导致您的游戏手柄在主机上被识别为 PlayStation 4控制器。</string>
|
||||||
<string name="title_checkbox_gamepad_motion_fallback">模拟游戏手柄运动传感器支持</string>
|
<string name="title_checkbox_gamepad_motion_fallback">模拟游戏手柄运动传感器支持</string>
|
||||||
|
<string name="error_code_prefix">错误代码:</string>
|
||||||
|
<string name="title_seekbar_vibrate_fallback_strength">调整模拟震动强度</string>
|
||||||
|
<string name="suffix_seekbar_vibrate_fallback_strength">%</string>
|
||||||
|
<string name="title_analog_scrolling">使用摇杆控制鼠标移动</string>
|
||||||
|
<string name="analogscroll_left">左摇杆</string>
|
||||||
|
<string name="analogscroll_right">右摇杆</string>
|
||||||
|
<string name="summary_analog_scrolling">在鼠标模式下选择用哪个摇杆控制鼠标移动</string>
|
||||||
|
<string name="summary_seekbar_vibrate_fallback_strength">增强或减弱设备的震动强度</string>
|
||||||
|
<string name="analogscroll_none">默认 (两个摇杆都控制鼠标)</string>
|
||||||
</resources>
|
</resources>
|
@ -120,4 +120,15 @@
|
|||||||
<item>cap-fps</item>
|
<item>cap-fps</item>
|
||||||
<item>smoothness</item>
|
<item>smoothness</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="analog_scrolling_names">
|
||||||
|
<item>@string/analogscroll_none</item>
|
||||||
|
<item>@string/analogscroll_right</item>
|
||||||
|
<item>@string/analogscroll_left</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="analog_scrolling_values" translatable="false">
|
||||||
|
<item>none</item>
|
||||||
|
<item>right</item>
|
||||||
|
<item>left</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -90,7 +90,8 @@
|
|||||||
<string name="conn_error_title">Connection Error</string>
|
<string name="conn_error_title">Connection Error</string>
|
||||||
<string name="conn_error_msg">Failed to start</string>
|
<string name="conn_error_msg">Failed to start</string>
|
||||||
<string name="conn_terminated_title">Connection Terminated</string>
|
<string name="conn_terminated_title">Connection Terminated</string>
|
||||||
<string name="conn_terminated_msg">The connection was terminated</string>
|
<string name="conn_terminated_msg">The connection was terminated.</string>
|
||||||
|
<string name="error_code_prefix">Error code:</string>
|
||||||
|
|
||||||
<!-- General strings -->
|
<!-- General strings -->
|
||||||
<string name="ip_hint">IP address of host PC</string>
|
<string name="ip_hint">IP address of host PC</string>
|
||||||
@ -172,6 +173,9 @@
|
|||||||
<string name="summary_checkbox_multi_controller">Unchecking this option forces a gamepad to always be present</string>
|
<string name="summary_checkbox_multi_controller">Unchecking this option forces a gamepad to always be present</string>
|
||||||
<string name="title_checkbox_vibrate_fallback">Emulate rumble support with vibration</string>
|
<string name="title_checkbox_vibrate_fallback">Emulate rumble support with vibration</string>
|
||||||
<string name="summary_checkbox_vibrate_fallback">Vibrates your device to emulate rumble if your gamepad does not support it</string>
|
<string name="summary_checkbox_vibrate_fallback">Vibrates your device to emulate rumble if your gamepad does not support it</string>
|
||||||
|
<string name="title_seekbar_vibrate_fallback_strength">Adjust emulated rumble intensity</string>
|
||||||
|
<string name="summary_seekbar_vibrate_fallback_strength">Amplify or reduce the vibration intensity on your device</string>
|
||||||
|
<string name="suffix_seekbar_vibrate_fallback_strength">%</string>
|
||||||
<string name="title_seekbar_deadzone">Adjust analog stick deadzone</string>
|
<string name="title_seekbar_deadzone">Adjust analog stick deadzone</string>
|
||||||
<string name="summary_seekbar_deadzone">Note: Some games can enforce a larger deadzone than what Moonlight is configured to use.</string>
|
<string name="summary_seekbar_deadzone">Note: Some games can enforce a larger deadzone than what Moonlight is configured to use.</string>
|
||||||
<string name="suffix_seekbar_deadzone">%</string>
|
<string name="suffix_seekbar_deadzone">%</string>
|
||||||
@ -205,6 +209,8 @@
|
|||||||
<string name="summary_checkbox_vibrate_osc">Vibrates your device to emulate rumble for the on-screen controls</string>
|
<string name="summary_checkbox_vibrate_osc">Vibrates your device to emulate rumble for the on-screen controls</string>
|
||||||
<string name="title_only_l3r3">Only show L3 and R3</string>
|
<string name="title_only_l3r3">Only show L3 and R3</string>
|
||||||
<string name="summary_only_l3r3">Hide all virtual buttons except L3 and R3</string>
|
<string name="summary_only_l3r3">Hide all virtual buttons except L3 and R3</string>
|
||||||
|
<string name="title_show_guide_button">Show Guide Button</string>
|
||||||
|
<string name="summary_show_guide_button">Show the guide button on screen</string>
|
||||||
<string name="title_reset_osc">Clear saved on-screen controls layout</string>
|
<string name="title_reset_osc">Clear saved on-screen controls layout</string>
|
||||||
<string name="summary_reset_osc">Resets all on-screen controls to their default size and position</string>
|
<string name="summary_reset_osc">Resets all on-screen controls to their default size and position</string>
|
||||||
<string name="dialog_title_reset_osc">Reset Layout</string>
|
<string name="dialog_title_reset_osc">Reset Layout</string>
|
||||||
@ -288,4 +294,10 @@
|
|||||||
<string name="pacing_balanced">Balanced</string>
|
<string name="pacing_balanced">Balanced</string>
|
||||||
<string name="pacing_balanced_alt">Balanced with FPS limit</string>
|
<string name="pacing_balanced_alt">Balanced with FPS limit</string>
|
||||||
<string name="pacing_smoothness">Prefer smoothest video (may significantly increase latency)</string>
|
<string name="pacing_smoothness">Prefer smoothest video (may significantly increase latency)</string>
|
||||||
|
|
||||||
|
<string name="title_analog_scrolling">Use an analog stick to scroll</string>
|
||||||
|
<string name="summary_analog_scrolling">Select an analog stick to scroll when in mouse emulation mode</string>
|
||||||
|
<string name="analogscroll_none">None (both sticks move the mouse)</string>
|
||||||
|
<string name="analogscroll_right">Right analog stick</string>
|
||||||
|
<string name="analogscroll_left">Left analog stick</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
8
app/src/main/res/xml/game_mode_config.xml
Normal file
8
app/src/main/res/xml/game_mode_config.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<game-mode-config
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:supportsBatteryGameMode="false"
|
||||||
|
android:supportsPerformanceGameMode="false"
|
||||||
|
android:allowGameDownscaling="false"
|
||||||
|
android:allowGameFpsOverride="false"
|
||||||
|
/>
|
@ -85,11 +85,27 @@
|
|||||||
android:title="@string/title_checkbox_mouse_emulation"
|
android:title="@string/title_checkbox_mouse_emulation"
|
||||||
android:summary="@string/summary_checkbox_mouse_emulation"
|
android:summary="@string/summary_checkbox_mouse_emulation"
|
||||||
android:defaultValue="true" />
|
android:defaultValue="true" />
|
||||||
|
<ListPreference
|
||||||
|
android:key="analog_scrolling"
|
||||||
|
android:dependency="checkbox_mouse_emulation"
|
||||||
|
android:title="@string/title_analog_scrolling"
|
||||||
|
android:summary="@string/summary_analog_scrolling"
|
||||||
|
android:entries="@array/analog_scrolling_names"
|
||||||
|
android:entryValues="@array/analog_scrolling_values"
|
||||||
|
android:defaultValue="right" />
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="checkbox_vibrate_fallback"
|
android:key="checkbox_vibrate_fallback"
|
||||||
android:title="@string/title_checkbox_vibrate_fallback"
|
android:title="@string/title_checkbox_vibrate_fallback"
|
||||||
android:summary="@string/summary_checkbox_vibrate_fallback"
|
android:summary="@string/summary_checkbox_vibrate_fallback"
|
||||||
android:defaultValue="false" />
|
android:defaultValue="false" />
|
||||||
|
<com.limelight.preferences.SeekBarPreference
|
||||||
|
android:key="seekbar_vibrate_fallback_strength"
|
||||||
|
android:dependency="checkbox_vibrate_fallback"
|
||||||
|
android:defaultValue="100"
|
||||||
|
android:max="200"
|
||||||
|
android:summary="@string/summary_seekbar_vibrate_fallback_strength"
|
||||||
|
android:text="@string/suffix_seekbar_vibrate_fallback_strength"
|
||||||
|
android:title="@string/title_seekbar_vibrate_fallback_strength"/>
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="checkbox_flip_face_buttons"
|
android:key="checkbox_flip_face_buttons"
|
||||||
android:title="@string/title_checkbox_flip_face_buttons"
|
android:title="@string/title_checkbox_flip_face_buttons"
|
||||||
@ -148,6 +164,14 @@
|
|||||||
android:key="checkbox_only_show_L3R3"
|
android:key="checkbox_only_show_L3R3"
|
||||||
android:summary="@string/summary_only_l3r3"
|
android:summary="@string/summary_only_l3r3"
|
||||||
android:title="@string/title_only_l3r3" />
|
android:title="@string/title_only_l3r3" />
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:defaultValue="true"
|
||||||
|
android:dependency="checkbox_show_onscreen_controls"
|
||||||
|
android:key="checkbox_show_guide_button"
|
||||||
|
android:summary="@string/summary_show_guide_button"
|
||||||
|
android:title="@string/title_show_guide_button" />
|
||||||
<com.limelight.preferences.SeekBarPreference
|
<com.limelight.preferences.SeekBarPreference
|
||||||
android:key="seekbar_osc_opacity"
|
android:key="seekbar_osc_opacity"
|
||||||
android:dependency="checkbox_show_onscreen_controls"
|
android:dependency="checkbox_show_onscreen_controls"
|
||||||
|
@ -5,7 +5,7 @@ buildscript {
|
|||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:8.1.2'
|
classpath 'com.android.tools.build:gradle:8.5.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
5
fastlane/metadata/android/en-US/changelogs/312.txt
Normal file
5
fastlane/metadata/android/en-US/changelogs/312.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
- Added Select+L1 gamepad button combo to act as the touchpad button when emulating a PS4 controller using built-in device motion sensors
|
||||||
|
- Disabled gamepad motion sensors by default on Android 12 as a workaround for an Android 12 bug that randomly crashes Moonlight
|
||||||
|
- Fixed analog sticks not centering properly in rare cases
|
||||||
|
- Adjusted bitrate handling of AV1 to be consistent with HEVC
|
||||||
|
- Fixed handling of some unusual H.264 and HEVC streams
|
3
fastlane/metadata/android/en-US/changelogs/313.txt
Normal file
3
fastlane/metadata/android/en-US/changelogs/313.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
- Fixed connection issue with some hosts running GeForce Experience and older Sunshine versions
|
||||||
|
- Fixed native frame rate streaming support on older versions of Android
|
||||||
|
- Stability improvements
|
9
fastlane/metadata/android/en-US/changelogs/314.txt
Normal file
9
fastlane/metadata/android/en-US/changelogs/314.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
- Adjusted bitrate calculation logic to provide consistency across codecs, HDR settings, and local/remote streaming
|
||||||
|
- Added support for full end-to-end stream encryption with Sunshine*
|
||||||
|
- Fixed immediate connection termination error when streaming over some Internet connections*
|
||||||
|
- Added option to adjust emulated rumble intensity
|
||||||
|
- Added option to scroll in controller mouse emulation mode
|
||||||
|
- Improved connection reliability during temporary network interruptions
|
||||||
|
- Fixed pass-through of special Sunshine key combos to the host
|
||||||
|
|
||||||
|
* Requires upcoming Sunshine v0.22.0 release or the latest Sunshine nightly build
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
Loading…
x
Reference in New Issue
Block a user